Class: TTT::ComputerPlayer

Inherits:
Object
  • Object
show all
Defined in:
lib/ttt/computer_player.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(game) ⇒ ComputerPlayer

Returns a new instance of ComputerPlayer.



8
9
10
# File 'lib/ttt/computer_player.rb', line 8

def initialize(game)
  self.game = game
end

Instance Attribute Details

#gameObject

Returns the value of attribute game.



6
7
8
# File 'lib/ttt/computer_player.rb', line 6

def game
  @game
end

Instance Method Details

#best_moveObject



20
21
22
23
24
# File 'lib/ttt/computer_player.rb', line 20

def best_move
  return imperative_move if imperative_move?  # allow to customize certain situations
  move, rating, game = moves_by_rating.first  # otherwise go by rating
  move
end

#boardObject



66
67
68
# File 'lib/ttt/computer_player.rb', line 66

def board
  game.board
end

#imperative_moveObject

allows us to override ratings in cases where they make the robot look stupid



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/ttt/computer_player.rb', line 42

def imperative_move
  # if we can win *this turn*, then take it because
  # it rates winning next turn the same as winning in 3 turns
  game.available_moves.each do |move|
    new_game = game.pristine_mark move
    return move if new_game.over? && new_game.winner == player_number
  end
  
  # if we can block the opponent from winning *this turn*, then take it, because
  # it rates losing this turn the same as losing in 3 turns
  if moves_by_rating.all? { |move, rating, game| rating == -1 }
    Game.winning_states do |position1, position2, position3|
      a, b, c = board[position1-1, 1].to_i, board[position2-1, 1].to_i, board[position3-1, 1].to_i
      if a + b + c == opponent_number * 2
        return a.zero? ? position1 : b.zero? ? position2 : position3
      end
    end
  end
end

#imperative_move?Boolean

Returns:

  • (Boolean)


62
63
64
# File 'lib/ttt/computer_player.rb', line 62

def imperative_move?
  !!imperative_move
end

#moves_by_ratingObject



26
27
28
29
30
31
32
33
34
35
# File 'lib/ttt/computer_player.rb', line 26

def moves_by_rating
  return to_enum(:moves_by_rating) unless block_given?
  moves = []
  game.available_moves.each do |move|
    new_game = game.pristine_mark move
    moves << [ move, rate(new_game), new_game ]
  end
  moves = moves.sort_by { |move, rating, new_game| -rating } # highest rating first
  moves.each     { |move, rating, new_game| yield move, rating, new_game }
end

#opponent_numberObject



70
71
72
# File 'lib/ttt/computer_player.rb', line 70

def opponent_number
  player_number == 1 ? 2 : 1
end

#player_numberObject



12
13
14
# File 'lib/ttt/computer_player.rb', line 12

def player_number
  game.turn
end

#rate(game) ⇒ Object



37
38
39
# File 'lib/ttt/computer_player.rb', line 37

def rate(game)
  RATINGS[game.board][player_number]
end

#take_turnObject



16
17
18
# File 'lib/ttt/computer_player.rb', line 16

def take_turn
  game.mark best_move
end