Class: Minehunter::Game

Inherits:
Object
  • Object
show all
Defined in:
lib/minehunter/game.rb

Overview

Responsible for playing mine hunting game

Constant Summary collapse

EXIT_KEYS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

The keys to exit game

[?\C-x, "q", "\e"].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input: $stdin, output: $stdout, env: {}, width: nil, height: nil, mines_limit: nil, screen_width: nil, screen_height: nil, decorator: DEFAULT_DECORATOR, randomiser: DEFAULT_RANDOMISER) ⇒ Game

Create a Game instance

Parameters:

  • input (IO) (defaults to: $stdin)

    the input stream, defaults to stdin

  • output (IO) (defaults to: $stdout)

    the output stream, defaults to stdout

  • env (Hash) (defaults to: {})

    the environment variables

  • width (Integer) (defaults to: nil)

    the number of columns

  • height (Integer) (defaults to: nil)

    the number of rows

  • mines_limit (Integer) (defaults to: nil)

    the total number of mines

  • screen_width (Integer) (defaults to: nil)

    the terminal screen width

  • screen_height (Integer) (defaults to: nil)

    the terminal screen height

  • decorator (Pastel) (defaults to: DEFAULT_DECORATOR)

    the decorator for styling

  • randomiser (Proc) (defaults to: DEFAULT_RANDOMISER)

    the random number generator



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/minehunter/game.rb', line 49

def initialize(input: $stdin, output: $stdout, env: {},
               width: nil, height: nil, mines_limit: nil,
               screen_width: nil, screen_height: nil,
               decorator: DEFAULT_DECORATOR, randomiser: DEFAULT_RANDOMISER)
  @output = output
  @width = width
  @top = (screen_height - height - 4) / 2
  @left = (screen_width - width - 4) / 2
  @pos_x = (width - 1) / 2
  @pos_y = (height - 1) / 2
  @decorator = decorator
  @randomiser = randomiser
  @box = TTY::Box
  @cursor = TTY::Cursor
  @reader = TTY::Reader.new(input: input, output: output, env: env,
                            interrupt: :exit)
  @grid = Grid.new(width: width, height: height, mines_limit: mines_limit)
  @intro = Intro
  @intro_top = (screen_height - @intro.height - 2) / 2
  @intro_left = (screen_width - @intro.width - 4) / 2

  reset
end

Instance Attribute Details

#cursorObject (readonly)

The terminal cursor clearing and positioning



23
24
25
# File 'lib/minehunter/game.rb', line 23

def cursor
  @cursor
end

Instance Method Details

#finished?Boolean

Check whether or not the game is finished

Returns:

  • (Boolean)


90
91
92
# File 'lib/minehunter/game.rb', line 90

def finished?
  @lost || @grid.cleared?
end

#flagObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Place a flag



205
206
207
208
209
# File 'lib/minehunter/game.rb', line 205

def flag
  return if finished?

  @grid.flag(@curr_x, @curr_y) unless finished?
end

#keyctrl_xObject Also known as: keyescape

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Quit game



214
215
216
217
218
# File 'lib/minehunter/game.rb', line 214

def keyctrl_x(*)
  @output.print cursor.clear_screen
  @output.print cursor.move_to(0, 0)
  @stop = true
end

#keydownObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Move cursor down



248
249
250
251
252
# File 'lib/minehunter/game.rb', line 248

def keydown(*)
  return if finished?

  @curr_y = @grid.move_down(@curr_y)
end

#keyleftObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Move cursor left



257
258
259
260
261
# File 'lib/minehunter/game.rb', line 257

def keyleft(*)
  return if finished?

  @curr_x = @grid.move_left(@curr_x)
end

#keypress(event) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Control game movement and actions

Parameters:

  • event (TTY::Reader::KeyEvent)

    the keypress event



190
191
192
193
194
195
196
197
198
199
200
# File 'lib/minehunter/game.rb', line 190

def keypress(event)
  case event.value.to_sym
  when :h, :a then keyleft
  when :l, :d then keyright
  when :j, :s then keydown
  when :k, :w then keyup
  when :f, :g then flag
  when :r then reset
  when :q then keyctrl_x
  end
end

#keyrightObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Move cursor right



266
267
268
269
270
# File 'lib/minehunter/game.rb', line 266

def keyright(*)
  return if finished?

  @curr_x = @grid.move_right(@curr_x)
end

#keyspaceObject Also known as: keyenter, keyreturn

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Uncover a field



224
225
226
227
228
229
230
231
232
# File 'lib/minehunter/game.rb', line 224

def keyspace(*)
  return if @grid.flag?(@curr_x, @curr_y)

  if @first_uncover
    @grid.fill_with_mines(@curr_x, @curr_y, randomiser: @randomiser)
    @first_uncover = false
  end
  @lost = @grid.uncover(@curr_x, @curr_y)
end

#keyupObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Move cursor up



239
240
241
242
243
# File 'lib/minehunter/game.rb', line 239

def keyup(*)
  return if finished?

  @curr_y = @grid.move_up(@curr_y)
end

#render_gridObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Render grid with current position marker



180
181
182
# File 'lib/minehunter/game.rb', line 180

def render_grid
  @grid.render(@curr_x, @curr_y, decorator: @decorator)
end

#render_grid_boxString

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Render box with grid

Returns:

  • (String)


149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/minehunter/game.rb', line 149

def render_grid_box
  @box.frame(
    render_grid,
    top: @top + 2,
    left: @left,
    padding: [0, 1],
    border: {
      top_left: :divider_right,
      top_right: :divider_left
    }
  )
end

#render_intro_boxString

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Render box with intro

Returns:

  • (String)


118
119
120
121
122
123
124
125
# File 'lib/minehunter/game.rb', line 118

def render_intro_box
  @box.frame(
    @intro.render,
    top: @intro_top,
    left: @intro_left,
    padding: [0, 1]
  )
end

#render_status_boxString

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Render box with status message

Returns:

  • (String)


132
133
134
135
136
137
138
139
140
141
142
# File 'lib/minehunter/game.rb', line 132

def render_status_box
  @box.frame(
    status,
    top: @top,
    left: @left,
    width: @width + 4,
    padding: [0, 1],
    border: {bottom: false},
    align: :center
  )
end

#resetObject

Reset game



76
77
78
79
80
81
82
83
# File 'lib/minehunter/game.rb', line 76

def reset
  @curr_x = @pos_x
  @curr_y = @pos_y
  @first_uncover = true
  @lost = false
  @stop = false
  @grid.reset
end

#runObject

Start the game



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/minehunter/game.rb', line 97

def run
  @output.print cursor.hide + cursor.clear_screen + render_intro_box
  pressed_key = @reader.read_keypress
  keyctrl_x if EXIT_KEYS.include?(pressed_key)

  @output.print cursor.clear_screen
  @reader.subscribe(self)

  until @stop
    @output.print render_status_box + render_grid_box
    @reader.read_keypress
  end
ensure
  @output.print cursor.show
end

#statusString

Status message

Returns:

  • (String)


167
168
169
170
171
172
173
174
175
# File 'lib/minehunter/game.rb', line 167

def status
  if @lost
    "GAME OVER"
  elsif @grid.cleared?
    "YOU WIN"
  else
    "Flags #{@grid.flags_remaining}"
  end
end