minehunt 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +1 -0
  3. data/bin/minehunt +114 -0
  4. data/lib/minehunt.rb +121 -0
  5. metadata +61 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 322e0063d5bfff9584242e7394d523f296b09fb63f8ad60eb4171bf7c140276d
4
+ data.tar.gz: 8474fcafea89310fe07dc776dc71243d68e16b805249a9f9111c988caba821d3
5
+ SHA512:
6
+ metadata.gz: 7c93386b2e102cd6df6f3330172e6a408141daeb885d77152ff3afe7581d5090a22d2c0d69c88c42c33d903c217658d98bee488f5954cd4b35579ddd87c2730f
7
+ data.tar.gz: 4fda1ac747d01670cc76f5aef87c64e88c2b8940d19d15b6002cb263a54ee83622ba30555def267ff42258fe97f355bbbf2f1064ce3251c03d533ffb7e9f2029
data/README.md ADDED
@@ -0,0 +1 @@
1
+ Implementing HP {48,49,50} minehunt game
data/bin/minehunt ADDED
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'curses'
5
+
6
+ require 'minehunt'
7
+
8
+ def display_curses( field,
9
+ state = { dead: false, victory: false },
10
+ theme = { explorer: '()',
11
+ dead_explorer: '☠ ',
12
+ door: '=>',
13
+ mine: '<>',
14
+ cell: '██',
15
+ visited_cell: ' ' } )
16
+ Curses.setpos 0, 0
17
+
18
+ if state[:dead]
19
+ Curses.addstr "You died! :(, score #{field.score} "
20
+ elsif state[:victory]
21
+ Curses.addstr "You won!! :), score #{field.score} "
22
+ else
23
+ Curses.addstr "#{field.number_of_mines} mines, #{field.count_nearby_mines} nearby, score #{field.score}"
24
+ end
25
+
26
+ field.height.times do |y|
27
+ Curses.setpos y + 2, 0
28
+ field.width.times do |x|
29
+ if [field.explorer_x, field.explorer_y] == [x, y]
30
+ Curses.addstr state[:dead] ? theme[:dead_explorer] : theme[:explorer]
31
+ elsif [field.width, field.height] == [x + 1, y + 1]
32
+ Curses.addstr theme[:door]
33
+ elsif field.field[[x, y]].open
34
+ Curses.addstr theme[:visited_cell]
35
+ elsif field.field[[x, y]].mine && ( state[:dead] || state[:victory] )
36
+ Curses.addstr theme[:mine]
37
+ else
38
+ Curses.addstr theme[:cell]
39
+ end
40
+ end
41
+ end
42
+
43
+ Curses.refresh
44
+ end
45
+
46
+ def ncurses_main( number_of_mines )
47
+ field = MineHunt::Board.new( number_of_mines )
48
+ finished = false
49
+
50
+ Curses.init_screen
51
+ Curses.cbreak
52
+ Curses.noecho
53
+ Curses.stdscr.keypad = true
54
+
55
+ at_exit do
56
+ Curses.close_screen
57
+ end
58
+
59
+ display_curses( field )
60
+
61
+ loop do
62
+ direction = ''
63
+ ch = Curses.getch
64
+ if finished
65
+ begin
66
+ case ch
67
+ when 'r'
68
+ field = MineHunt::Board.new( number_of_mines )
69
+ finished = false
70
+ else
71
+ break
72
+ end
73
+ rescue Curses::RequestDeniedError
74
+ 'prout'
75
+ end
76
+ else
77
+ begin
78
+ case ch
79
+ when '1'
80
+ direction = 'down-left'
81
+ when '2', Curses::KEY_DOWN
82
+ direction = 'down'
83
+ when '3'
84
+ direction = 'down-right'
85
+ when '4', Curses::KEY_LEFT
86
+ direction = 'left'
87
+ when '6', Curses::KEY_RIGHT
88
+ direction = 'right'
89
+ when '7'
90
+ direction = 'up-left'
91
+ when '8', Curses::KEY_UP
92
+ direction = 'up'
93
+ when '9'
94
+ direction = 'up-right'
95
+ when 'q'
96
+ break
97
+ end
98
+ rescue Curses::RequestDeniedError
99
+ 'prout'
100
+ end
101
+ end
102
+
103
+ state = field.move( direction )
104
+ finished = state[:dead] || state[:victory]
105
+ display_curses( field, state )
106
+ end
107
+
108
+ exit!
109
+ end
110
+
111
+ number_of_mines = 20
112
+ number_of_mines = ARGV.first.to_i if ARGV.length == 1
113
+
114
+ ncurses_main( number_of_mines )
data/lib/minehunt.rb ADDED
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ module MineHunt
5
+ VERSION = '1.0.0'
6
+
7
+ class Cell
8
+ attr_accessor :mine,
9
+ :open
10
+
11
+ def initialize( mine: false, open: false )
12
+ @mine = mine
13
+ @open = open
14
+ end
15
+
16
+ def explore
17
+ @open = true
18
+
19
+ @mine
20
+ end
21
+ end
22
+
23
+ class Board
24
+ attr_reader :width,
25
+ :height,
26
+ :field,
27
+ :number_of_mines,
28
+ :explorer_x,
29
+ :explorer_y,
30
+ :score
31
+
32
+ def initialize( number_of_mines = 20, height = 8, width = 16 )
33
+ @height = height
34
+ @width = width
35
+ @explorer_x = 0
36
+ @explorer_y = 0
37
+ @score = 1
38
+ @field = {}
39
+ @number_of_mines = if number_of_mines.negative? && number_of_mines > ((@height * @width) - 2)
40
+ 20
41
+ else
42
+ number_of_mines
43
+ end
44
+
45
+ @width.times do |x|
46
+ @height.times do |y|
47
+ @field[[x, y]] = Cell.new( open: x.zero? && y.zero? )
48
+ end
49
+ end
50
+
51
+ placed_mines = 0
52
+ while placed_mines < @number_of_mines
53
+ coordinates = [rand( @width ), rand( @height )]
54
+ next if coordinates == [0, 0]
55
+ next if @field[ coordinates ].mine
56
+
57
+ @field[ coordinates ].mine = true
58
+ placed_mines += 1
59
+ end
60
+ end
61
+
62
+ def update_explorer_location( direction )
63
+ case direction
64
+ when 'up'
65
+ @explorer_y -= 1 if @explorer_y.positive?
66
+ when 'right'
67
+ @explorer_x += 1 if @explorer_x < (@width - 1)
68
+ when 'down'
69
+ @explorer_y += 1 if @explorer_y < (@height - 1)
70
+ when 'left'
71
+ @explorer_x -= 1 if @explorer_x.positive?
72
+ when 'up-right'
73
+ if @explorer_x < (@width - 1) && @explorer_y.positive?
74
+ @explorer_x += 1
75
+ @explorer_y -= 1
76
+ end
77
+ when 'down-right'
78
+ if @explorer_x < (@width - 1) && @explorer_y < (@height - 1)
79
+ @explorer_x += 1
80
+ @explorer_y += 1
81
+ end
82
+ when 'down-left'
83
+ if @explorer_x.positive? && @explorer_y < (@height - 1)
84
+ @explorer_x -= 1
85
+ @explorer_y += 1
86
+ end
87
+ when 'up-left'
88
+ if @explorer_x.positive? && @explorer_y.positive?
89
+ @explorer_x -= 1
90
+ @explorer_y -= 1
91
+ end
92
+ end
93
+ end
94
+
95
+ def move( direction )
96
+ update_explorer_location( direction )
97
+ @score += 1 unless @field[[@explorer_x, @explorer_y]].open
98
+
99
+ { dead: @field[[@explorer_x, @explorer_y]].explore,
100
+ victory: @explorer_x == (@width - 1) && @explorer_y == (@height - 1) }
101
+ end
102
+
103
+ def count_nearby_mines
104
+ counter = 0
105
+
106
+ [@explorer_x - 1, @explorer_x, @explorer_x + 1].each do |x|
107
+ [@explorer_y - 1, @explorer_y, @explorer_y + 1].each do |y|
108
+ next if x.negative?
109
+ next if y.negative?
110
+ next if x == @width
111
+ next if y == @height
112
+ next if x == @explorer_x && y == @explorer_y
113
+
114
+ counter += 1 if @field[[x, y]].mine
115
+ end
116
+ end
117
+
118
+ counter
119
+ end
120
+ end
121
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: minehunt
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Gwenhael Le Moine
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-11-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: curses
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.4.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.4.4
27
+ description: Mine hunting game inspired by the HP 48
28
+ email: gwenhael@le-moine.org
29
+ executables:
30
+ - minehunt
31
+ extensions: []
32
+ extra_rdoc_files:
33
+ - README.md
34
+ files:
35
+ - README.md
36
+ - bin/minehunt
37
+ - lib/minehunt.rb
38
+ homepage: https://src.le-moine.org/gwh/myhunt/src/branch/main/ruby
39
+ licenses:
40
+ - GPL-3.0
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">"
49
+ - !ruby/object:Gem::Version
50
+ version: '3'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.3.7
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: Mine hunting game
61
+ test_files: []