class Minesweeprb::Gameboard

Constants

COLORS
ESCDELAY
FLAG
MOVE
QUIT
RESTART
REVEAL

Attributes

game[R]
game_x[R]
game_y[R]
windows[R]

Public Class Methods

new(game) click to toggle source
# File lib/minesweeprb/gameboard.rb, line 49
def initialize(game)
  @game = game
  setup_curses
end

Public Instance Methods

clear() click to toggle source
# File lib/minesweeprb/gameboard.rb, line 87
def clear
  close_screen
end
draw() click to toggle source
# File lib/minesweeprb/gameboard.rb, line 74
def draw
  # paint_debug
  Thread.new do
    loop do
      paint_header
      sleep(0.5)
    end
  end

  paint_grid
  paint_grid while process_input(w_grid.getch)
end
w_debug() click to toggle source
# File lib/minesweeprb/gameboard.rb, line 70
def w_debug
  windows[:debug]
end
w_grid() click to toggle source
# File lib/minesweeprb/gameboard.rb, line 58
def w_grid
  windows[:grid]
end
w_header() click to toggle source
# File lib/minesweeprb/gameboard.rb, line 54
def w_header
  windows[:header]
end
w_instructions() click to toggle source
# File lib/minesweeprb/gameboard.rb, line 66
def w_instructions
  windows[:instructions]
end
w_status() click to toggle source
# File lib/minesweeprb/gameboard.rb, line 62
def w_status
  windows[:status]
end

Private Instance Methods

build_window(rows:, cols:, top:, left:) click to toggle source
# File lib/minesweeprb/gameboard.rb, line 147
def build_window(rows:, cols:, top:, left:)
  Window.new(rows, cols, top, left)
end
color_for(char) click to toggle source
# File lib/minesweeprb/gameboard.rb, line 254
def color_for(char)
  pair = COLORS.keys.index(char)

  if pair
    color_pair(pair + 1)
  else
    0
  end
end
paint_debug() click to toggle source
# File lib/minesweeprb/gameboard.rb, line 193
def paint_debug
  COLORS.keys.each do |char|
    w_debug.attron(color_for(char)) { w_debug << char.to_s }
  end
  w_debug.refresh
end
paint_grid() click to toggle source
# File lib/minesweeprb/gameboard.rb, line 200
def paint_grid
  w_grid.setpos(0,0)

  game.play_grid.each.with_index do |line, row|
    line.each.with_index do |char, col|
      w_grid.setpos(row, col * 2) if col < line.length

      if game.active_square == [col, row]
        w_grid.attron(color_for(char) | A_REVERSE) { w_grid << char }
      else
        w_grid.attron(color_for(char)) { w_grid << char }
      end
    end
  end

  paint_status
  paint_instructions

  w_grid.refresh
  w_status.refresh
  w_instructions.refresh
end
paint_header() click to toggle source
# File lib/minesweeprb/gameboard.rb, line 183
def paint_header
  w_header.setpos(0,0)

  game.header.chars.each do |char|
    w_header.attron(color_for(char)) { w_header << char }
  end

  w_header.refresh
end
paint_instructions() click to toggle source
# File lib/minesweeprb/gameboard.rb, line 242
def paint_instructions
  instructions = []
  instructions << '(←↓↑→ or hjkl)Move' unless game.over?
  instructions << '(f or ␣)Flag/Mark' if game.started?
  instructions << '(↵)Reveal' unless game.over?
  instructions << '(r)Restart'
  instructions << '(q or ⎋)Quit'

  w_instructions.setpos(0,0)
  w_instructions << instructions.join(' ').center(w_instructions.maxx - 1)
end
paint_status() click to toggle source
# File lib/minesweeprb/gameboard.rb, line 223
def paint_status
  if game.over?
    w_status.setpos(0,0)
    outcome = game.won? ? :win : :lose
    message = game.game_over_message.center(w_status.maxx - 1)
    message.chars.each do |char|
      char_color = color_for(char)

      if char_color.zero?
        w_status.attron(color_for(outcome)) { w_status << char }
      else
        w_status.attron(char_color) { w_status << char }
      end
    end
  else
    w_status.clear
  end
end
process_input(key) click to toggle source
# File lib/minesweeprb/gameboard.rb, line 151
def process_input(key)
  case key
  when KEY_MOUSE then process_mouse(getmouse)
  when *MOVE.keys then game.move(MOVE[key])
  when *REVEAL then game.reveal_active_square
  when *FLAG then game.cycle_flag
  when *RESTART then game.restart
  when *QUIT then return false
  end

  true
end
process_mouse(m) click to toggle source
# File lib/minesweeprb/gameboard.rb, line 164
def process_mouse(m)
  top = w_grid.begy
  left = w_grid.begx
  bottom = top + game.height
  right = left + game.width * 2 - 1
  on_board = (top..bottom).include?(m.y) &&
    (left..right).include?(m.x) &&
    (m.x - w_grid.begx).even?

  return if !on_board && !game.over?

  game.active_square = [(m.x - w_grid.begx) / 2, m.y - w_grid.begy]

  case m.bstate
    when BUTTON1_CLICKED then game.reveal_active_square
    when BUTTON2_CLICKED, (BUTTON_CTRL | BUTTON1_CLICKED) then game.cycle_flag
  end
end
setup_curses() click to toggle source
# File lib/minesweeprb/gameboard.rb, line 93
def setup_curses
  screen = init_screen
  use_default_colors
  start_color
  curs_set(0)
  noecho
  self.ESCDELAY = 1;
  mousemask(BUTTON1_CLICKED|BUTTON2_CLICKED|BUTTON3_CLICKED|BUTTON4_CLICKED)

  header = {
    top: 1,
    left: (screen.maxx - game.header.length) / 2,
    cols: game.header.length,
    rows: 1,
  }
  grid = {
    left: (screen.maxx - (game.width * 2 - 1)) / 2,
    top: header[:top] + header[:rows] + 1,
    cols: game.width * 2 - 1, # leave room for spaces between squares
    rows: game.height,  # leave room for win/lose status and instructions
  }
  status = {
    left: 0,
    top: grid[:top] + grid[:rows] + 1,
    cols: 0,
    rows: 1,
  }
  instructions = {
    left: 0,
    top: status[:top] + status[:rows] + 1,
    cols: 0,
    rows: 1,
  }
  debug = {
    left: 0,
    top: screen.maxy - 1,
    cols: 0,
    rows: 1,
  }

  @windows = {}
  @windows[:header] = build_window(**header)
  @windows[:grid] = build_window(**grid)
  @windows[:status] = build_window(**status)
  @windows[:instructions] = build_window(**instructions)
  @windows[:debug] = build_window(**debug)
  @windows[:grid].keypad(true)

  COLORS.keys.each.with_index do |char, index|
    fg, bg = COLORS[char]
    init_pair(index + 1, fg, bg || -1)
  end
end