module TwentyFortyEight::Screen

Screen

Constants

CELL_HEIGHT
CELL_PADDING
COLOR_MAP
COLOR_MAP_V

create [tile val] => [color] map to color tiles

HIST_WIDTH

Public Class Methods

cell(val, width = CELL_PADDING, fill_count = CELL_HEIGHT, r = 0) click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 156
def self.cell(val, width = CELL_PADDING, fill_count = CELL_HEIGHT, r = 0)
  spacer     = ''.center width
  lines      = [(val > r ? val : '').to_s.center(width)]
  fill_count = fill_count > 1 ? fill_count - 1 : fill_count

  (fill_count / 2).ceil.times { lines.unshift spacer }
  (fill_count / 2).floor.times { lines.push spacer }

  lines
end
color_from_value(v) click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 152
def self.color_from_value(v)
  COLOR_MAP_V[v] || COLOR_MAP.keys.last
end
game_over(game, options = {}) click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 51
def self.game_over(game, options = {})
  hist  = options[:history] || []
  info  = options[:info]    || []

  bw, hw, _hh, sy, sx = render_offsets hist, info, game.board.to_a

  render_game_over game, (sx - hw / 2), (sy + info.size)
end
handle_keypress(allow_moves = true) click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 84
def self.handle_keypress(allow_moves = true)
  case Curses.getch
  when ' ' then sleep 0.2 until Curses.getch == ' '
  when Curses::KEY_DOWN,  's', 'j' then :down  if allow_moves
  when Curses::KEY_UP,    'w', 'k' then :up    if allow_moves
  when Curses::KEY_LEFT,  'a', 'h' then :left  if allow_moves
  when Curses::KEY_RIGHT, 'd', 'l' then :right if allow_moves
  when Curses::KEY_CLOSE, 'q'      then :quit
  when 'r'                         then :restart
  end
end
init!(options = {}) click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 31
def self.init!(options = {})
  Curses.init_screen
  Curses.cbreak
  Curses.noecho
  Curses.nonl
  Curses.curs_set 0
  Curses.timeout = 0
  Curses.stdscr.keypad true

  init_colors! if Curses.has_colors?

  trap('SIGINT') { restore! && exit }
end
init_colors!() click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 172
def self.init_colors!
  Curses.start_color
  Curses.assume_default_colors -1, -1

  Curses.init_pair 250, 0, 7

  COLOR_MAP.each_with_index do |arr, i|
    Curses.init_pair arr[0], *arr[1]
  end
end
justified_str(label, value, length, seperator = ': ') click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 167
def self.justified_str(label, value, length, seperator = ': ')
  label_width = label.to_s.size + seperator.size
  "#{label}#{seperator}#{value.to_s.rjust length - label_width}"
end
render(board, options = {}) click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 60
def self.render(board, options = {})
  hist = options[:history] || []
  info = options[:info]    || []

  bw, hw, hh, sy, sx = render_offsets hist, info, board

  render_history hist, (sx + bw + 2 - hw / 2), sy, hw, hh if hist.any?
  render_info    info, (sx - hw / 2),          sy, bw     if info.any?

  render_board board, (sx - hw / 2), (sy + info.size)
  handle_keypress options[:interactive]

  Curses.refresh
end
render_board(board, start_x, start_y) click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 118
def self.render_board(board, start_x, start_y)
  board.each_with_index do |col, y|
    current_y = start_y + y * CELL_HEIGHT
    col.each_with_index do |val, x|
      current_x = start_x + x * CELL_PADDING
      Curses.attron (Curses.color_pair(color_from_value(val)) | Curses::A_BOLD) do
        cell(val).each_with_index do |line, offset|
          Curses.setpos (current_y + offset), current_x
          Curses.addstr line
        end
      end
    end
  end
end
render_game_over(game, start_x, start_y) click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 133
def self.render_game_over(game, start_x, start_y)
  size   = game.board.to_a.size
  width  = size * CELL_PADDING
  spacer = ''.center width
  lines  = ['Game over!', "score: #{game.score}", '', "[Q]uit", "[R]estart"]
  lines  = lines.map { |text| text.center width }
  rows   = (size * CELL_HEIGHT - lines.count).to_f

  (rows / 2).floor.times { lines.unshift spacer }
  (rows / 2).ceil.times { lines.push spacer }

  Curses.attron (Curses.color_pair(250) | Curses::A_BOLD) do
    lines.each_with_index do |line, offset|
      Curses.setpos (start_y + offset), start_x
      Curses.addstr line
    end
  end
end
render_history(history, start_x, start_y, width = 15, size = 10) click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 96
def self.render_history(history, start_x, start_y, width = 15, size = 10)
  history.last(size).reverse.each_with_index do |game, y|
    Curses.setpos (start_y + y), start_x
    Curses.attron (Curses.color_pair(0)  | Curses::A_BOLD) do
      Curses.addstr justified_str("##{game.id}", game.score, width)
    end
  end
end
render_info(info_rows, start_x, start_y, width) click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 105
def self.render_info(info_rows, start_x, start_y, width)
  info_rows.each_with_index do |h, y|
    part_width = width / h.count
    h.each_with_index do |(label, value), x|
      xx = x > 0 ? 1 : 0
      Curses.setpos (start_y + y), start_x + xx + (x * part_width)
      Curses.attron (Curses.color_pair(0)  | Curses::A_BOLD) do
        Curses.addstr justified_str(label, value, (part_width - xx))
      end
    end
  end
end
render_offsets(history, info, b) click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 75
def self.render_offsets(history, info, b)
  hist_size   = history.any? ? HIST_WIDTH : 0
  board_width = CELL_PADDING * b.size

  [board_width, hist_size, (b.size * CELL_HEIGHT + info.size),
   (Curses.lines / 2) - ((board_width / 2) / CELL_HEIGHT),
   (Curses.cols / 2) - (board_width / 2)]
end
restore!() click to toggle source
# File lib/TwentyFortyEight/screen.rb, line 45
def self.restore!
  Curses.curs_set 1
  Curses.clear
  Curses.close_screen
end