class Upwords::Player

Attributes

last_turn[RW]
name[R]
score[RW]

Public Class Methods

new(name, rack_capacity=7, cpu=false) click to toggle source
# File lib/upwords/player.rb, line 10
def initialize(name, rack_capacity=7, cpu=false)
  @name = name
  @rack = LetterRack.new(rack_capacity)
  @score = 0
  @last_turn = nil
  @cpu = cpu
end

Public Instance Methods

cpu?() click to toggle source

AI move methods


# File lib/upwords/player.rb, line 84
def cpu?
  @cpu
end
cpu_move(board, dict, batch_size = 1000, min_score = 0) click to toggle source

Execute a legal move based on a predefined strategy

Basic strategy:

  • Find all legal move shapes and all possible letter permutations across those shapes (this computation is relatively quick)

  • Retun the highest score from permutation that do not produce in any illegal new words (this computation is slow…)

  • To speed up the above computation: + Only check a batch of permutations at a time (specified in 'batch_size' argument) + After each batch, terminate the subroutine if it finds a score that is at least as high as the given 'min_score' + Decrement the 'min_score' after each batch that does not terminate the subroutine to prevent endless searches

TODO: refactor the the 'strategy' component out of this method, so different strategies can be swapped in and out

# File lib/upwords/player.rb, line 135
def cpu_move(board, dict, batch_size = 1000, min_score = 0)
  possible_moves = self.legal_move_shapes_letter_permutations(board)      
  possible_moves.shuffle!
  
  top_score = 0
  top_score_move = nil
  
  while top_score_move.nil? || (top_score < min_score) do
    
    # Check if next batch contains any legal moves and save the top score
    ([batch_size, possible_moves.size].min).times do
      move_arr = possible_moves.pop
      move = Move.new(move_arr)

      if move.legal_words?(board, dict)
        move_score = move.score(board, self)
        if move_score >= top_score
          top_score = move_score
          top_score_move = move_arr
        end
      end
    end
    
    # Decrement minimum required score after each cycle to help prevent long searches
    min_score = [(min_score - 1), 0].max
  end
  
  top_score_move
end
letters() click to toggle source
# File lib/upwords/player.rb, line 18
def letters
  @rack.letters.dup
end
play_letter(board, letter, row, col) click to toggle source
# File lib/upwords/player.rb, line 54
def play_letter(board, letter, row, col)
  rack_letter = @rack.remove(letter)
  begin
    board.play_letter(rack_letter, row, col)
  rescue IllegalMove => exn
    take_letter(rack_letter)
    raise IllegalMove, exn
  end
end
rack_capacity() click to toggle source
# File lib/upwords/player.rb, line 34
def rack_capacity
  @rack.capacity
end
rack_empty?() click to toggle source
# File lib/upwords/player.rb, line 30
def rack_empty?
  @rack.empty?
end
rack_full?() click to toggle source
# File lib/upwords/player.rb, line 26
def rack_full?
  @rack.full?
end
refill_rack(letter_bank) click to toggle source
# File lib/upwords/player.rb, line 74
def refill_rack(letter_bank)
  until rack_full? || letter_bank.empty? do
    take_letter(letter_bank.draw)
  end
end
show_rack(masked = false) click to toggle source
# File lib/upwords/player.rb, line 22
def show_rack(masked = false)
  masked ? @rack.show_masked : @rack.show
end
swap_letter(letter, letter_bank) click to toggle source
# File lib/upwords/player.rb, line 64
def swap_letter(letter, letter_bank)
  if letter_bank.empty?
    raise IllegalMove, "Letter bank is empty!"
  else
    trade_letter = @rack.remove(letter)
    take_letter(letter_bank.draw)
    letter_bank.deposit(trade_letter)
  end
end
take_from(board, row, col) click to toggle source

Game object interaction methods


# File lib/upwords/player.rb, line 46
def take_from(board, row, col)
  if board.stack_height(row, col) == 0
    raise IllegalMove, "No letters in #{row}, #{col}!"
  else
    take_letter(board.remove_top_letter(row, col))
  end
end
take_letter(letter) click to toggle source
# File lib/upwords/player.rb, line 38
def take_letter(letter)
  @rack.add(letter)
end