Method: Upwords::Player#cpu_move

Defined in:
lib/upwords/player.rb

#cpu_move(board, dict, batch_size = 1000, min_score = 0) ⇒ Object

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



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# 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