class TwentyFortyEight::Game

Game

Constants

ACTIONS
DEFAULTS
MOVES

Attributes

board[R]
current_dir[R]
id[R]
log[R]
moves[R]
prev_available[R]
prev_score[R]
score[R]
settings[R]

Public Class Methods

new(id = 1, opts = {}, **rest_opts) click to toggle source
# File lib/TwentyFortyEight/game.rb, line 12
def initialize(id = 1, opts = {}, **rest_opts)
  @id             = id
  @score          = 0
  @prev_score     = 0
  @moves          = 0
  @settings       = Options.new DEFAULTS.merge(opts.merge(rest_opts))
  @board          = Board.new(settings)
  @prev_available = available
  @current_dir    = nil
  @force_quit     = false
  @log            = Logger.new if settings.log?
  2.times { insert! } unless settings.board?
end

Public Instance Methods

action(action, **opts) click to toggle source
# File lib/TwentyFortyEight/game.rb, line 65
def action(action, **opts)
  action == :quit && quit! || move(action, opts)
  self
end
available() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 61
def available
  board.empty_cells
end
changed?() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 33
def changed?
  score > prev_score || (prev_available - available).any?
end
directions() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 57
def directions
  MOVES
end
down() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 93
def down
  board.transpose! && right && board.transpose!
end
dup() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 105
def dup
  Game.new settings.merge(board: board.to_a)
end
end?() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 49
def end?
  true if @force_quit || !mergeable? && board.full?
end
insert!() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 26
def insert!
  value = Random.rand(1..10) == 10 ? 4 : 2
  pos   = available.sample

  board.set! value, pos if pos
end
left() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 97
def left
  board.replace! board.to_a.map { |col| merge(col) }
end
lost?() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 41
def lost?
  true if end? && !won?
end
mergeable?() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 53
def mergeable?
  directions.select { |dir| dup.move(dir, insert: false).changed? }.any?
end
move(dir, **opts) click to toggle source
# File lib/TwentyFortyEight/game.rb, line 70
def move(dir, **opts)
  return self unless directions.include? dir.to_sym

  @prev_score     = score
  @prev_available = available
  @current_dir    = dir

  send dir

  if changed?
    @moves += 1

    log << { move: moves, score: score, direction: dir } if log
    insert! unless opts[:insert] == false
  end

  self
end
quit!() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 45
def quit!
  @force_quit = true
end
right() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 101
def right
  board.replace! board.to_a.map { |col| merge(col.reverse).reverse }
end
up() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 89
def up
  board.transpose! && left && board.transpose!
end
won?() click to toggle source
# File lib/TwentyFortyEight/game.rb, line 37
def won?
  board.board.flatten.max >= 2048
end

Private Instance Methods

merge(unmerged) click to toggle source
# File lib/TwentyFortyEight/game.rb, line 111
def merge(unmerged)
  input  = unmerged.reject { |v| settings.empty? v }
  output = []

  while (current = input.shift)
    compare = input.shift

    if current == compare
      merged  = current << 1
      @score += merged
      output << merged
    else
      output << current
      break unless compare
      input.unshift compare if compare
    end

  end

  output.concat(Array.new(unmerged.size - output.size) { settings.empty })
end