minesweeper-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +6 -0
- data/bin/minesweeper +41 -0
- data/lib/minesweeper.rb +2 -0
- data/lib/minesweeper/game.rb +37 -0
- data/lib/minesweeper/playfield.rb +90 -0
- data/lib/minesweeper/square.rb +44 -0
- data/lib/minesweeper/version.rb +3 -0
- data/minesweeper-cli.gemspec +23 -0
- metadata +101 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: d710c1e40315619906f82b3bebbc4f1308f90419
|
|
4
|
+
data.tar.gz: 32cb01b79aac187fc8f87841fd1cc6e490e8dab1
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: cb1541c26f02d2d359f2b3176cf92a65f21df84fdf0af035ab24a02fcc0ab99531a19d796460791d56cbcb2e7c8b845092b1c926c1795c140e3dd38c31413814
|
|
7
|
+
data.tar.gz: ac3e40e003347843b8ee3690a5921b15d0120939d104ae6228505f3bec948f8ff20c88dafb5ec190f5433696cbc4a6fe322020b538c4a80c54fbc97d9f86881d
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 Daniel Cruz Horts
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
A minimalistic Ruby implementation for the classic minesweeper [game](https://en.wikipedia.org/wiki/Minesweeper_(video_game)).
|
|
2
|
+
|
|
3
|
+
In case you don't know, the objective is to reveal the content of all the squares without a mine.
|
|
4
|
+
|
|
5
|
+
# Installation
|
|
6
|
+
|
|
7
|
+
It comes conveniently packaged as a gem:
|
|
8
|
+
|
|
9
|
+
`gem install minesweeper-cli`
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# How to launch the game
|
|
13
|
+
|
|
14
|
+
From the command line:
|
|
15
|
+
|
|
16
|
+
`./minesweeper`
|
|
17
|
+
|
|
18
|
+
To get some help and options:
|
|
19
|
+
|
|
20
|
+
`./minesweeper -h`
|
|
21
|
+
|
|
22
|
+
By default it's a 10x5 grid, with 3 hidden mines.
|
|
23
|
+
|
|
24
|
+
# How to play
|
|
25
|
+
|
|
26
|
+
Enter the position of the square you want to reveal, by typing the coordinates Y and X. Eg:
|
|
27
|
+
|
|
28
|
+
`2,3`
|
|
29
|
+
|
|
30
|
+
…and press enter.
|
|
31
|
+
|
|
32
|
+
The origin `0, 0` is at the leftmost top corner, marked in the diagram below as `O`.
|
|
33
|
+
And `2, 3` would be the square marked as `X`:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
O....
|
|
37
|
+
.....
|
|
38
|
+
...X.
|
|
39
|
+
.....
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The game ends either once you reveal all the squares, or hit a mine.
|
|
43
|
+
In any case, the program ends and you'll be notified in [Engrish](http://knowyourmeme.com/memes/a-winner-is-you).
|
data/Rakefile
ADDED
data/bin/minesweeper
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
require 'minesweeper'
|
|
5
|
+
|
|
6
|
+
options = {
|
|
7
|
+
display_set: :emoji,
|
|
8
|
+
mine_number: 3,
|
|
9
|
+
rows: 5,
|
|
10
|
+
cols: 10,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
opt_parser = OptionParser.new do |opt|
|
|
14
|
+
opt.banner = 'Usage: minesweeper [OPTIONS]'
|
|
15
|
+
opt.separator ''
|
|
16
|
+
opt.separator 'Options'
|
|
17
|
+
|
|
18
|
+
opt.on('-d', '--display_set SET', 'display the playfield using text or emoji (default)') do |display_set|
|
|
19
|
+
options[:display_set] = display_set.to_sym
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
opt.on('-m', '--mine_number NUMBER', 'number of mines') do |mine_number|
|
|
23
|
+
options[:mine_number] = mine_number.to_i
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
opt.on('-r', '--rows NUMBER', 'number of rows') do |rows|
|
|
27
|
+
options[:rows] = rows.to_i
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
opt.on('-c', '--cols NUMBER', 'number of columns') do |cols|
|
|
31
|
+
options[:cols] = cols.to_i
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
opt.on('-h', '--help', 'this message') do |environment|
|
|
35
|
+
puts opt_parser
|
|
36
|
+
exit
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
opt_parser.parse!
|
|
40
|
+
|
|
41
|
+
Minesweeper::Game.new(options).play
|
data/lib/minesweeper.rb
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require_relative 'playfield'
|
|
2
|
+
|
|
3
|
+
module Minesweeper
|
|
4
|
+
class Game
|
|
5
|
+
def initialize(options)
|
|
6
|
+
@playfield = Playfield.new(**options)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def play
|
|
10
|
+
@playfield.display
|
|
11
|
+
|
|
12
|
+
loop do
|
|
13
|
+
puts "Enter position to reveal as: y, x"
|
|
14
|
+
input = STDIN.gets.strip
|
|
15
|
+
|
|
16
|
+
if input.include? ','
|
|
17
|
+
y, x = input.split(',').map &:to_i
|
|
18
|
+
|
|
19
|
+
puts
|
|
20
|
+
if @playfield.has_mine?(y, x)
|
|
21
|
+
@playfield.display_with_mines
|
|
22
|
+
puts "\n\nLose!"
|
|
23
|
+
exit 1
|
|
24
|
+
end
|
|
25
|
+
@playfield.reveal_square(y, x)
|
|
26
|
+
|
|
27
|
+
if @playfield.all_squares_revealed?
|
|
28
|
+
@playfield.display_with_mines
|
|
29
|
+
puts "\n\nThe winner is you!"
|
|
30
|
+
exit
|
|
31
|
+
end
|
|
32
|
+
@playfield.display
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
require_relative 'square'
|
|
3
|
+
|
|
4
|
+
module Minesweeper
|
|
5
|
+
class Playfield
|
|
6
|
+
|
|
7
|
+
def initialize(display_set:, mine_number:, rows:, cols:)
|
|
8
|
+
@display_set = display_set
|
|
9
|
+
@mine_number = mine_number
|
|
10
|
+
@rows = rows
|
|
11
|
+
@cols = cols
|
|
12
|
+
|
|
13
|
+
@revealed_squares = Set.new
|
|
14
|
+
@mines = Set.new
|
|
15
|
+
@playfield = Array.new(rows) { Array.new(cols) }
|
|
16
|
+
|
|
17
|
+
until mine_number.zero?
|
|
18
|
+
mine_position = [rand(rows), rand(cols)]
|
|
19
|
+
unless @mines.include?(mine_position)
|
|
20
|
+
@mines << mine_position
|
|
21
|
+
mine_number -= 1
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def display
|
|
27
|
+
@playfield.each do |row|
|
|
28
|
+
puts row.map { |content| Square.new(@display_set).display(content) }.join
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def display_with_mines
|
|
33
|
+
@mines.each do |mine|
|
|
34
|
+
y, x = mine
|
|
35
|
+
@playfield[y][x] = true
|
|
36
|
+
end
|
|
37
|
+
display
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def has_mine?(y, x)
|
|
41
|
+
@mines.include?([y, x])
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def mines_around(y, x)
|
|
45
|
+
count = 0
|
|
46
|
+
(-1).upto(1).each do |dx|
|
|
47
|
+
(-1).upto(1).each do |dy|
|
|
48
|
+
next if dx.zero? && dy.zero?
|
|
49
|
+
next if x + dx < 0
|
|
50
|
+
next if y + dy < 0
|
|
51
|
+
next if x + dx >= @cols
|
|
52
|
+
next if y + dy >= @rows
|
|
53
|
+
|
|
54
|
+
if has_mine?(y + dy, x + dx)
|
|
55
|
+
count += 1
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
count
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def all_squares_revealed?
|
|
64
|
+
@playfield.flatten.select(&:nil?).size == @mine_number
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def reveal_adjacent(y, x)
|
|
68
|
+
(-1).upto(1).each do |dx|
|
|
69
|
+
(-1).upto(1).each do |dy|
|
|
70
|
+
next if dx.zero? && dy.zero?
|
|
71
|
+
next if x + dx < 0
|
|
72
|
+
next if y + dy < 0
|
|
73
|
+
next if x + dx >= @cols
|
|
74
|
+
next if y + dy >= @rows
|
|
75
|
+
|
|
76
|
+
reveal_square(y + dy, x + dx)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def reveal_square(y, x)
|
|
82
|
+
number_mines_around = mines_around(y, x)
|
|
83
|
+
@playfield[y][x] = number_mines_around
|
|
84
|
+
if number_mines_around.zero? && !@revealed_squares.include?([y, x])
|
|
85
|
+
@revealed_squares << [y, x]
|
|
86
|
+
reveal_adjacent(y, x)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Minesweeper
|
|
2
|
+
class Square
|
|
3
|
+
TEXT_SET = {
|
|
4
|
+
nil => '.',
|
|
5
|
+
0 => '0',
|
|
6
|
+
1 => '1',
|
|
7
|
+
2 => '2',
|
|
8
|
+
3 => '3',
|
|
9
|
+
4 => '4',
|
|
10
|
+
5 => '5',
|
|
11
|
+
6 => '6',
|
|
12
|
+
7 => '7',
|
|
13
|
+
8 => '8',
|
|
14
|
+
true => 'X',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
EMOJI_SET = {
|
|
18
|
+
nil => ' ✴️',
|
|
19
|
+
0 => ' ✅',
|
|
20
|
+
1 => ' 1️⃣',
|
|
21
|
+
2 => ' 2️⃣',
|
|
22
|
+
3 => ' 3️⃣',
|
|
23
|
+
4 => ' 4️⃣',
|
|
24
|
+
5 => ' 5️⃣',
|
|
25
|
+
6 => ' 6️⃣',
|
|
26
|
+
7 => ' 7️⃣',
|
|
27
|
+
8 => ' 8️⃣',
|
|
28
|
+
true => ' 💣',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
CHARACTER_SETS = {
|
|
32
|
+
emoji: EMOJI_SET,
|
|
33
|
+
text: TEXT_SET,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
def initialize(set = :emoji)
|
|
37
|
+
@character_set = CHARACTER_SETS[set]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def display(content)
|
|
41
|
+
@character_set[content]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'minesweeper/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = 'minesweeper-cli'
|
|
8
|
+
spec.version = Minesweeper::VERSION
|
|
9
|
+
spec.authors = ['Daniel Cruz Horts']
|
|
10
|
+
spec.summary = %q{A command line, text/emoji minesweeper implementation in Ruby!}
|
|
11
|
+
spec.homepage = 'https://github.com/dncrht/minesweeper'
|
|
12
|
+
spec.license = 'MIT'
|
|
13
|
+
|
|
14
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
15
|
+
f.match(%r{^(test|spec|features)/})
|
|
16
|
+
end
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.require_paths = ["lib"]
|
|
19
|
+
|
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
22
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
|
23
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: minesweeper-cli
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Daniel Cruz Horts
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2017-02-12 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.13'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.13'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rspec
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.0'
|
|
55
|
+
description:
|
|
56
|
+
email:
|
|
57
|
+
executables:
|
|
58
|
+
- minesweeper
|
|
59
|
+
extensions: []
|
|
60
|
+
extra_rdoc_files: []
|
|
61
|
+
files:
|
|
62
|
+
- ".gitignore"
|
|
63
|
+
- ".rspec"
|
|
64
|
+
- ".travis.yml"
|
|
65
|
+
- Gemfile
|
|
66
|
+
- LICENSE.txt
|
|
67
|
+
- README.md
|
|
68
|
+
- Rakefile
|
|
69
|
+
- bin/minesweeper
|
|
70
|
+
- lib/minesweeper.rb
|
|
71
|
+
- lib/minesweeper/game.rb
|
|
72
|
+
- lib/minesweeper/playfield.rb
|
|
73
|
+
- lib/minesweeper/square.rb
|
|
74
|
+
- lib/minesweeper/version.rb
|
|
75
|
+
- minesweeper-cli.gemspec
|
|
76
|
+
homepage: https://github.com/dncrht/minesweeper
|
|
77
|
+
licenses:
|
|
78
|
+
- MIT
|
|
79
|
+
metadata: {}
|
|
80
|
+
post_install_message:
|
|
81
|
+
rdoc_options: []
|
|
82
|
+
require_paths:
|
|
83
|
+
- lib
|
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
|
+
requirements:
|
|
91
|
+
- - ">="
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: '0'
|
|
94
|
+
requirements: []
|
|
95
|
+
rubyforge_project:
|
|
96
|
+
rubygems_version: 2.2.2
|
|
97
|
+
signing_key:
|
|
98
|
+
specification_version: 4
|
|
99
|
+
summary: A command line, text/emoji minesweeper implementation in Ruby!
|
|
100
|
+
test_files: []
|
|
101
|
+
has_rdoc:
|