minesweeprb 0.4.2 → 0.5.0.rc5
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 +4 -4
- data/.github/workflows/ci.yml +36 -0
- data/.github/workflows/release.yml +47 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +59 -4
- data/CHANGELOG.md +4 -0
- data/CODEOWNERS +1 -0
- data/Gemfile +6 -2
- data/Gemfile.lock +91 -119
- data/README.md +0 -1
- data/Rakefile +27 -0
- data/lib/minesweeprb/cli.rb +29 -26
- data/lib/minesweeprb/commands/play.rb +40 -67
- data/lib/minesweeprb/game.rb +63 -47
- data/lib/minesweeprb/game_template.rb +1 -2
- data/lib/minesweeprb/gameboard.rb +92 -73
- data/lib/minesweeprb/menu.rb +265 -0
- data/lib/minesweeprb/splash.rb +46 -0
- data/lib/minesweeprb/theme.rb +36 -0
- data/lib/minesweeprb/themes/classic.rb +46 -0
- data/lib/minesweeprb/themes/modern.rb +47 -0
- data/lib/minesweeprb/version.rb +1 -1
- data/lib/minesweeprb.rb +2 -2
- data/minesweeprb.gemspec +4 -4
- metadata +21 -31
- data/lib/minesweeprb/command.rb +0 -127
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c997529a9b88173318f8789784b99ac9c68440322dee81f00b3a8460e04d3fba
|
|
4
|
+
data.tar.gz: 7ad2f3640a581fc567dcc97a0e047f2daa6377bb1365001a4ff12f90c6b971fa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fffeab53498e2992856ab00f96b91dc9e1d92821e8cfd7f6db763427e8d7767e282f1a9db7d0f9ffe86b87dab096282c21d4d1c758c47b60074c98787371fbf2
|
|
7
|
+
data.tar.gz: '08e7d4939717bbe1b904c59c7aa0f273b612506e6b0200372ef5aea3aa4fc76f6ce6fe9b0f705b345cbc74df76716fddf50fe30b7dbb5d7b8cee5e42b4430289'
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v5
|
|
15
|
+
|
|
16
|
+
- uses: ruby/setup-ruby@v1
|
|
17
|
+
with:
|
|
18
|
+
ruby-version: "4.0"
|
|
19
|
+
bundler-cache: true
|
|
20
|
+
|
|
21
|
+
- name: Run tests
|
|
22
|
+
run: bundle exec rspec
|
|
23
|
+
|
|
24
|
+
lint:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v5
|
|
29
|
+
|
|
30
|
+
- uses: ruby/setup-ruby@v1
|
|
31
|
+
with:
|
|
32
|
+
ruby-version: "4.0"
|
|
33
|
+
bundler-cache: true
|
|
34
|
+
|
|
35
|
+
- name: Run rubocop
|
|
36
|
+
run: bundle exec rubocop
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
release:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
id-token: write
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v5
|
|
17
|
+
|
|
18
|
+
- uses: ruby/setup-ruby@v1
|
|
19
|
+
with:
|
|
20
|
+
ruby-version: "4.0"
|
|
21
|
+
bundler-cache: true
|
|
22
|
+
|
|
23
|
+
- name: Verify version matches tag
|
|
24
|
+
run: |
|
|
25
|
+
tag="${GITHUB_REF#refs/tags/v}"
|
|
26
|
+
gem_version=$(ruby -r ./lib/minesweeprb/version -e "puts Minesweeprb::VERSION")
|
|
27
|
+
if [ "$tag" != "$gem_version" ]; then
|
|
28
|
+
echo "Tag v$tag does not match Minesweeprb::VERSION ($gem_version)"
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
- name: Run tests
|
|
33
|
+
run: bundle exec rake ci
|
|
34
|
+
|
|
35
|
+
- name: Build gem
|
|
36
|
+
run: gem build minesweeprb.gemspec
|
|
37
|
+
|
|
38
|
+
- name: Configure RubyGems trusted publisher
|
|
39
|
+
uses: rubygems/configure-rubygems-credentials@v1.0.0
|
|
40
|
+
|
|
41
|
+
- name: Push to RubyGems
|
|
42
|
+
run: gem push minesweeprb-*.gem
|
|
43
|
+
|
|
44
|
+
- name: Upload gem to GitHub release
|
|
45
|
+
run: gh release upload "${{ github.event.release.tag_name }}" minesweeprb-*.gem
|
|
46
|
+
env:
|
|
47
|
+
GH_TOKEN: ${{ github.token }}
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
|
@@ -1,13 +1,68 @@
|
|
|
1
|
-
|
|
1
|
+
plugins:
|
|
2
|
+
- rubocop-rake
|
|
3
|
+
- rubocop-rspec
|
|
4
|
+
|
|
5
|
+
AllCops:
|
|
6
|
+
NewCops: enable
|
|
7
|
+
TargetRubyVersion: 4.0
|
|
2
8
|
|
|
3
9
|
Style/Documentation:
|
|
4
10
|
Enabled: false
|
|
5
11
|
|
|
6
|
-
Metrics/BlockLength:
|
|
7
|
-
ExcludedMethods: ['describe']
|
|
8
|
-
|
|
9
12
|
Style/TrailingCommaInArrayLiteral:
|
|
10
13
|
EnforcedStyleForMultiline: comma
|
|
11
14
|
|
|
12
15
|
Style/TrailingCommaInHashLiteral:
|
|
13
16
|
EnforcedStyleForMultiline: comma
|
|
17
|
+
|
|
18
|
+
# Game logic has inherently long methods
|
|
19
|
+
Metrics/MethodLength:
|
|
20
|
+
CountAsOne: ['array', 'hash']
|
|
21
|
+
Max: 25
|
|
22
|
+
|
|
23
|
+
Metrics/AbcSize:
|
|
24
|
+
Max: 55
|
|
25
|
+
|
|
26
|
+
Metrics/ClassLength:
|
|
27
|
+
Max: 250
|
|
28
|
+
|
|
29
|
+
Metrics/CyclomaticComplexity:
|
|
30
|
+
Max: 10
|
|
31
|
+
|
|
32
|
+
Metrics/PerceivedComplexity:
|
|
33
|
+
Max: 12
|
|
34
|
+
|
|
35
|
+
Layout/LineLength:
|
|
36
|
+
Max: 150
|
|
37
|
+
|
|
38
|
+
# clue_0..clue_8 naming is intentional
|
|
39
|
+
Naming/VariableNumber:
|
|
40
|
+
Enabled: false
|
|
41
|
+
|
|
42
|
+
# Short param names like x, y are idiomatic for grid code
|
|
43
|
+
Naming/MethodParameterName:
|
|
44
|
+
AllowedNames: ['x', 'y', 'w', 'h']
|
|
45
|
+
|
|
46
|
+
Naming/PredicateMethod:
|
|
47
|
+
Enabled: false
|
|
48
|
+
|
|
49
|
+
RSpec/MultipleExpectations:
|
|
50
|
+
Max: 5
|
|
51
|
+
|
|
52
|
+
RSpec/ExampleLength:
|
|
53
|
+
Max: 20
|
|
54
|
+
|
|
55
|
+
RSpec/AnyInstance:
|
|
56
|
+
Enabled: false
|
|
57
|
+
|
|
58
|
+
RSpec/VerifiedDoubles:
|
|
59
|
+
Enabled: false
|
|
60
|
+
|
|
61
|
+
RSpec/SpecFilePathFormat:
|
|
62
|
+
Enabled: false
|
|
63
|
+
|
|
64
|
+
RSpec/SubjectStub:
|
|
65
|
+
Enabled: false
|
|
66
|
+
|
|
67
|
+
RSpec/DescribeClass:
|
|
68
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
data/CODEOWNERS
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @scudco
|
data/Gemfile
CHANGED
|
@@ -5,5 +5,9 @@ source 'https://rubygems.org'
|
|
|
5
5
|
# Specify your gem's dependencies in minesweeprb.gemspec
|
|
6
6
|
gemspec
|
|
7
7
|
|
|
8
|
-
gem '
|
|
9
|
-
gem '
|
|
8
|
+
gem 'irb'
|
|
9
|
+
gem 'rake'
|
|
10
|
+
gem 'rspec'
|
|
11
|
+
gem 'rubocop', require: false
|
|
12
|
+
gem 'rubocop-rake', require: false
|
|
13
|
+
gem 'rubocop-rspec', require: false
|
data/Gemfile.lock
CHANGED
|
@@ -1,136 +1,108 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
minesweeprb (0.
|
|
5
|
-
curses
|
|
6
|
-
tty (~> 0.10)
|
|
4
|
+
minesweeprb (0.5.0.rc5)
|
|
5
|
+
curses
|
|
7
6
|
|
|
8
7
|
GEM
|
|
9
8
|
remote: https://rubygems.org/
|
|
10
9
|
specs:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
10
|
+
addressable (2.8.9)
|
|
11
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
12
|
+
ast (2.4.3)
|
|
13
|
+
bigdecimal (4.0.1)
|
|
14
|
+
curses (1.6.0)
|
|
15
|
+
date (3.5.1)
|
|
16
|
+
diff-lcs (1.6.2)
|
|
17
|
+
erb (6.0.2)
|
|
18
|
+
io-console (0.8.2)
|
|
19
|
+
irb (1.17.0)
|
|
20
|
+
pp (>= 0.6.0)
|
|
21
|
+
prism (>= 1.3.0)
|
|
22
|
+
rdoc (>= 4.0.0)
|
|
23
|
+
reline (>= 0.4.2)
|
|
24
|
+
json (2.19.1)
|
|
25
|
+
json-schema (6.2.0)
|
|
26
|
+
addressable (~> 2.8)
|
|
27
|
+
bigdecimal (>= 3.1, < 5)
|
|
28
|
+
language_server-protocol (3.17.0.5)
|
|
29
|
+
lint_roller (1.1.0)
|
|
30
|
+
mcp (0.8.0)
|
|
31
|
+
json-schema (>= 4.1)
|
|
32
|
+
parallel (1.27.0)
|
|
33
|
+
parser (3.3.10.2)
|
|
34
|
+
ast (~> 2.4.1)
|
|
35
|
+
racc
|
|
36
|
+
pp (0.6.3)
|
|
37
|
+
prettyprint
|
|
38
|
+
prettyprint (0.2.0)
|
|
39
|
+
prism (1.9.0)
|
|
40
|
+
psych (5.3.1)
|
|
41
|
+
date
|
|
42
|
+
stringio
|
|
43
|
+
public_suffix (7.0.5)
|
|
44
|
+
racc (1.8.1)
|
|
45
|
+
rainbow (3.1.1)
|
|
46
|
+
rake (13.3.1)
|
|
47
|
+
rdoc (7.2.0)
|
|
48
|
+
erb
|
|
49
|
+
psych (>= 4.0.0)
|
|
50
|
+
tsort
|
|
51
|
+
regexp_parser (2.11.3)
|
|
52
|
+
reline (0.6.3)
|
|
53
|
+
io-console (~> 0.5)
|
|
54
|
+
rspec (3.13.2)
|
|
55
|
+
rspec-core (~> 3.13.0)
|
|
56
|
+
rspec-expectations (~> 3.13.0)
|
|
57
|
+
rspec-mocks (~> 3.13.0)
|
|
58
|
+
rspec-core (3.13.6)
|
|
59
|
+
rspec-support (~> 3.13.0)
|
|
60
|
+
rspec-expectations (3.13.5)
|
|
28
61
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
29
|
-
rspec-support (~> 3.
|
|
30
|
-
rspec-mocks (3.
|
|
62
|
+
rspec-support (~> 3.13.0)
|
|
63
|
+
rspec-mocks (3.13.8)
|
|
31
64
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
32
|
-
rspec-support (~> 3.
|
|
33
|
-
rspec-support (3.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
tty-spinner (~> 0.9)
|
|
62
|
-
tty-table (~> 0.11.0)
|
|
63
|
-
tty-tree (~> 0.3)
|
|
64
|
-
tty-which (~> 0.4)
|
|
65
|
-
tty-box (0.4.1)
|
|
66
|
-
pastel (~> 0.7.2)
|
|
67
|
-
strings (~> 0.1.6)
|
|
68
|
-
tty-cursor (~> 0.7)
|
|
69
|
-
tty-color (0.5.1)
|
|
70
|
-
tty-command (0.9.0)
|
|
71
|
-
pastel (~> 0.7.0)
|
|
72
|
-
tty-config (0.3.2)
|
|
73
|
-
tty-cursor (0.7.1)
|
|
74
|
-
tty-editor (0.5.1)
|
|
75
|
-
tty-prompt (~> 0.19)
|
|
76
|
-
tty-which (~> 0.4)
|
|
77
|
-
tty-file (0.8.0)
|
|
78
|
-
diff-lcs (~> 1.3)
|
|
79
|
-
pastel (~> 0.7.2)
|
|
80
|
-
tty-prompt (~> 0.18)
|
|
81
|
-
tty-font (0.4.0)
|
|
82
|
-
tty-logger (0.2.0)
|
|
83
|
-
pastel (~> 0.7.0)
|
|
84
|
-
tty-markdown (0.6.0)
|
|
85
|
-
kramdown (~> 1.16.2)
|
|
86
|
-
pastel (~> 0.7.2)
|
|
87
|
-
rouge (~> 3.3)
|
|
88
|
-
strings (~> 0.1.4)
|
|
89
|
-
tty-color (~> 0.4)
|
|
90
|
-
tty-screen (~> 0.6)
|
|
91
|
-
tty-pager (0.12.1)
|
|
92
|
-
strings (~> 0.1.4)
|
|
93
|
-
tty-screen (~> 0.6)
|
|
94
|
-
tty-which (~> 0.4)
|
|
95
|
-
tty-pie (0.3.0)
|
|
96
|
-
pastel (~> 0.7.3)
|
|
97
|
-
tty-cursor (~> 0.7)
|
|
98
|
-
tty-platform (0.3.0)
|
|
99
|
-
tty-progressbar (0.17.0)
|
|
100
|
-
strings-ansi (~> 0.1.0)
|
|
101
|
-
tty-cursor (~> 0.7)
|
|
102
|
-
tty-screen (~> 0.7)
|
|
103
|
-
unicode-display_width (~> 1.6)
|
|
104
|
-
tty-prompt (0.20.0)
|
|
105
|
-
necromancer (~> 0.5.0)
|
|
106
|
-
pastel (~> 0.7.0)
|
|
107
|
-
tty-reader (~> 0.7.0)
|
|
108
|
-
tty-reader (0.7.0)
|
|
109
|
-
tty-cursor (~> 0.7)
|
|
110
|
-
tty-screen (~> 0.7)
|
|
111
|
-
wisper (~> 2.0.0)
|
|
112
|
-
tty-screen (0.7.1)
|
|
113
|
-
tty-spinner (0.9.3)
|
|
114
|
-
tty-cursor (~> 0.7)
|
|
115
|
-
tty-table (0.11.0)
|
|
116
|
-
equatable (~> 0.6)
|
|
117
|
-
necromancer (~> 0.5)
|
|
118
|
-
pastel (~> 0.7.2)
|
|
119
|
-
strings (~> 0.1.5)
|
|
120
|
-
tty-screen (~> 0.7)
|
|
121
|
-
tty-tree (0.4.0)
|
|
122
|
-
tty-which (0.4.2)
|
|
123
|
-
unicode-display_width (1.6.1)
|
|
124
|
-
unicode_utils (1.4.0)
|
|
125
|
-
wisper (2.0.1)
|
|
65
|
+
rspec-support (~> 3.13.0)
|
|
66
|
+
rspec-support (3.13.7)
|
|
67
|
+
rubocop (1.85.1)
|
|
68
|
+
json (~> 2.3)
|
|
69
|
+
language_server-protocol (~> 3.17.0.2)
|
|
70
|
+
lint_roller (~> 1.1.0)
|
|
71
|
+
mcp (~> 0.6)
|
|
72
|
+
parallel (~> 1.10)
|
|
73
|
+
parser (>= 3.3.0.2)
|
|
74
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
75
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
76
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
77
|
+
ruby-progressbar (~> 1.7)
|
|
78
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
79
|
+
rubocop-ast (1.49.1)
|
|
80
|
+
parser (>= 3.3.7.2)
|
|
81
|
+
prism (~> 1.7)
|
|
82
|
+
rubocop-rake (0.7.1)
|
|
83
|
+
lint_roller (~> 1.1)
|
|
84
|
+
rubocop (>= 1.72.1)
|
|
85
|
+
rubocop-rspec (3.9.0)
|
|
86
|
+
lint_roller (~> 1.1)
|
|
87
|
+
rubocop (~> 1.81)
|
|
88
|
+
ruby-progressbar (1.13.0)
|
|
89
|
+
stringio (3.2.0)
|
|
90
|
+
tsort (0.2.0)
|
|
91
|
+
unicode-display_width (3.2.0)
|
|
92
|
+
unicode-emoji (~> 4.1)
|
|
93
|
+
unicode-emoji (4.2.0)
|
|
126
94
|
|
|
127
95
|
PLATFORMS
|
|
128
96
|
ruby
|
|
129
97
|
|
|
130
98
|
DEPENDENCIES
|
|
99
|
+
irb
|
|
131
100
|
minesweeprb!
|
|
132
|
-
rake
|
|
133
|
-
rspec
|
|
101
|
+
rake
|
|
102
|
+
rspec
|
|
103
|
+
rubocop
|
|
104
|
+
rubocop-rake
|
|
105
|
+
rubocop-rspec
|
|
134
106
|
|
|
135
107
|
BUNDLED WITH
|
|
136
|
-
|
|
108
|
+
4.0.7
|
data/README.md
CHANGED
data/Rakefile
CHANGED
|
@@ -5,4 +5,31 @@ require 'rspec/core/rake_task'
|
|
|
5
5
|
|
|
6
6
|
RSpec::Core::RakeTask.new(:spec)
|
|
7
7
|
|
|
8
|
+
require 'rubocop/rake_task'
|
|
9
|
+
RuboCop::RakeTask.new
|
|
10
|
+
|
|
8
11
|
task default: :spec
|
|
12
|
+
task ci: %w[spec rubocop]
|
|
13
|
+
|
|
14
|
+
desc 'Release a new version (e.g., rake release_gem[0.5.0])'
|
|
15
|
+
task :release_gem, [:version] do |_t, args|
|
|
16
|
+
version = args[:version]
|
|
17
|
+
abort 'Usage: rake release_gem[VERSION]' unless version
|
|
18
|
+
|
|
19
|
+
version_file = 'lib/minesweeprb/version.rb'
|
|
20
|
+
content = File.read(version_file)
|
|
21
|
+
new_content = content.sub(/VERSION = '.*'/, "VERSION = '#{version}'")
|
|
22
|
+
abort 'VERSION not found in version.rb' if content == new_content
|
|
23
|
+
|
|
24
|
+
File.write(version_file, new_content)
|
|
25
|
+
sh 'bundle install'
|
|
26
|
+
sh "git add #{version_file} Gemfile.lock"
|
|
27
|
+
sh "git commit -m 'Bump version to #{version}'"
|
|
28
|
+
sh "git tag v#{version}"
|
|
29
|
+
sh 'git push --tags'
|
|
30
|
+
sh 'git push'
|
|
31
|
+
|
|
32
|
+
prerelease = version.match?(/[a-zA-Z]/)
|
|
33
|
+
flags = prerelease ? '--prerelease' : ''
|
|
34
|
+
sh "gh release create v#{version} --title 'v#{version}' --generate-notes #{flags}"
|
|
35
|
+
end
|
data/lib/minesweeprb/cli.rb
CHANGED
|
@@ -1,35 +1,38 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require '
|
|
3
|
+
require 'optparse'
|
|
4
4
|
|
|
5
5
|
module Minesweeprb
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
# @api public
|
|
10
|
-
class CLI < Thor
|
|
11
|
-
# Error raised by this runner
|
|
12
|
-
Error = Class.new(StandardError)
|
|
13
|
-
|
|
14
|
-
default_command 'play'
|
|
15
|
-
|
|
16
|
-
desc 'version', 'minesweeprb version'
|
|
17
|
-
def version
|
|
18
|
-
require_relative 'version'
|
|
19
|
-
puts "v#{Minesweeprb::VERSION}"
|
|
6
|
+
class CLI
|
|
7
|
+
class Error < StandardError
|
|
20
8
|
end
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
9
|
+
|
|
10
|
+
def self.start(argv = ARGV)
|
|
11
|
+
options = {}
|
|
12
|
+
|
|
13
|
+
parser = OptionParser.new do |opts|
|
|
14
|
+
opts.banner = 'Usage: minesweeprb [options]'
|
|
15
|
+
|
|
16
|
+
opts.on('-v', '--version', 'Print version') do
|
|
17
|
+
require_relative 'version'
|
|
18
|
+
puts "v#{Minesweeprb::VERSION}"
|
|
19
|
+
exit
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
opts.on('-t', '--theme NAME', 'Theme (classic, modern)') do |name|
|
|
23
|
+
options[:theme] = name
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
opts.on('-h', '--help', 'Show this help') do
|
|
27
|
+
puts opts
|
|
28
|
+
exit
|
|
29
|
+
end
|
|
32
30
|
end
|
|
31
|
+
|
|
32
|
+
parser.parse!(argv)
|
|
33
|
+
|
|
34
|
+
require_relative 'commands/play'
|
|
35
|
+
Commands::Play.new(options).execute
|
|
33
36
|
end
|
|
34
37
|
end
|
|
35
38
|
end
|
|
@@ -1,99 +1,72 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require '
|
|
4
|
-
|
|
5
|
-
require_relative '../command'
|
|
3
|
+
require 'io/console'
|
|
4
|
+
require 'curses'
|
|
6
5
|
require_relative '../../minesweeprb'
|
|
6
|
+
require_relative '../menu'
|
|
7
|
+
require_relative '../theme'
|
|
7
8
|
|
|
8
9
|
module Minesweeprb
|
|
9
10
|
module Commands
|
|
10
|
-
class Play
|
|
11
|
+
class Play
|
|
12
|
+
include Curses
|
|
13
|
+
|
|
11
14
|
SIZES = [
|
|
12
15
|
# [ label, width, height, # of mines ]
|
|
13
|
-
['Tiny', 5, 5,
|
|
16
|
+
['Tiny', 5, 5, 3],
|
|
14
17
|
['Small', 9, 9, 10],
|
|
15
18
|
['Medium', 13, 13, 15],
|
|
16
19
|
['Large', 17, 17, 20],
|
|
17
20
|
['Huge', 21, 21, 25],
|
|
18
|
-
].map { |
|
|
21
|
+
].map { |label, width, height, mines| GameTemplate.new(label:, width:, height:, mines:) }.freeze
|
|
19
22
|
|
|
20
23
|
def initialize(options)
|
|
21
24
|
@options = options
|
|
25
|
+
@theme = @options[:theme] ? Theme[@options[:theme]] : Theme.default
|
|
22
26
|
end
|
|
23
27
|
|
|
24
|
-
def execute
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
def execute
|
|
29
|
+
init_screen
|
|
30
|
+
use_default_colors
|
|
31
|
+
start_color
|
|
32
|
+
curs_set(0)
|
|
33
|
+
noecho
|
|
34
|
+
self.ESCDELAY = 1
|
|
35
|
+
mousemask(BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED | BUTTON4_CLICKED)
|
|
27
36
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
loop do
|
|
38
|
+
template = prompt_size
|
|
39
|
+
break if template.nil?
|
|
40
|
+
|
|
41
|
+
game = Game.new(**template.to_h, sprites: @theme.sprites)
|
|
42
|
+
Gameboard.new(game, theme: @theme).draw
|
|
34
43
|
end
|
|
44
|
+
ensure
|
|
45
|
+
close_screen
|
|
35
46
|
end
|
|
36
47
|
|
|
48
|
+
# Gameboard chrome: 1 top margin + 1 header + 1 gap + grid + 1 gap + 1 status + 1 gap + 1 instructions
|
|
49
|
+
BOARD_CHROME_ROWS = 7
|
|
50
|
+
|
|
37
51
|
private
|
|
38
52
|
|
|
39
|
-
def prompt_size
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
53
|
+
def prompt_size
|
|
54
|
+
screen_rows, screen_cols = IO.console.winsize
|
|
55
|
+
|
|
56
|
+
options = SIZES.map do |tmpl|
|
|
57
|
+
too_tall = tmpl.height + BOARD_CHROME_ROWS > screen_rows
|
|
58
|
+
too_wide = (tmpl.width * 2) - 1 > screen_cols
|
|
59
|
+
disabled = '(screen too small)' if too_tall || too_wide
|
|
43
60
|
{
|
|
44
61
|
disabled: disabled,
|
|
45
|
-
name:
|
|
46
|
-
value:
|
|
62
|
+
name: tmpl.label,
|
|
63
|
+
value: tmpl,
|
|
47
64
|
}
|
|
48
65
|
end
|
|
49
66
|
|
|
50
|
-
options << {
|
|
51
|
-
name: 'Custom',
|
|
52
|
-
value: :custom
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
prompt(interrupt: -> { exit 1 }).select('Size:', options, cycle: true)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def prompt_custom(output)
|
|
59
|
-
min_width = 1
|
|
60
|
-
max_width = TTY::Screen.width / 2 - 1
|
|
61
|
-
width = prompt.ask("Width (#{min_width}-#{max_width})") do |q|
|
|
62
|
-
q.required true
|
|
63
|
-
q.convert :int
|
|
64
|
-
q.validate do |val|
|
|
65
|
-
val =~ /\d+/ && (min_width..max_width).include?(val.to_i)
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
min_height = width == 1 ? 2 : 1
|
|
70
|
-
max_height = TTY::Screen.height - 10 # leave room for interface
|
|
71
|
-
height = prompt.ask("Height (#{min_height}-#{max_height})") do |q|
|
|
72
|
-
q.required true
|
|
73
|
-
q.convert :int
|
|
74
|
-
q.validate do |val|
|
|
75
|
-
val =~ /\d+/ && (min_height..max_height).include?(val.to_i)
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
min_mines = 1
|
|
80
|
-
max_mines = width * height - 1
|
|
81
|
-
mines = prompt.ask("Mines (#{min_mines}-#{max_mines})") do |q|
|
|
82
|
-
q.required true
|
|
83
|
-
q.convert :int
|
|
84
|
-
q.validate do |val|
|
|
85
|
-
val =~ /\d+/ && (min_mines..max_mines).include?(val.to_i)
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
GameTemplate.new('Custom', width, height, mines)
|
|
90
|
-
end
|
|
67
|
+
options << { name: 'Quit', value: nil }
|
|
91
68
|
|
|
92
|
-
|
|
93
|
-
output.print cursor.hide
|
|
94
|
-
output.print cursor.up(1)
|
|
95
|
-
output.print cursor.clear_screen_down
|
|
96
|
-
output.puts
|
|
69
|
+
Menu.select('Choose a size:', options)
|
|
97
70
|
end
|
|
98
71
|
end
|
|
99
72
|
end
|