3 # Library to support a Trap the Cap player that uses potentials to select the
10 # Version 1.1:: 23 April 2008
16 # Play Trap the Cap by using potential fields. For each possible move,
17 # calculate the field strength and pick the move with the lowest potential
18 class Potential_player
20 attr_reader :friend_pull, :enemy_pull, :base_pull,
21 :safe_bonus, :capture_bonus
23 def initialize(args, verbose = false)
24 @friend_pull = args[:friend_pull] || 1
25 @enemy_pull = args[:enemy_pull] || 0.5
26 @base_pull = args[:base_pull] || 2
27 @safe_bonus = args[:safe_bonus] || 8
28 @capture_bonus = args[:capture_bonus] || 10
33 # Find the best move of the possible ones
34 def best_move(game, die_result)
35 me = game.current_player
36 possible_moves = game.possible_moves(die_result, me)
37 scored_moves = possible_moves.collect do |m|
40 score = score_position(game, me)
47 puts "#{m} scores #{score}" if @verbose
50 best_move = (scored_moves.max {|a, b| a[1] <=> b[1]})[0]
53 # Calculate the potential score of a position for a given player
54 def score_position(game, player)
56 game.pieces.each_value do |piece|
58 if piece.colour == player
59 game.pieces.each_value do |other_piece|
60 if other_piece.colour == player
61 score += game.board.distance_between[here.place][other_piece.position.place] * @friend_pull
63 score += game.board.distance_between[here.place][other_piece.position.place] * @enemy_pull
66 score += piece.contains.length * @capture_bonus
67 score += game.board.distance_between[here.place][game.board.positions[player].place] *
68 piece.contains.length * @base_pull
69 elsif here == game.board.positions[player]
77 # Convert a player to a bitstring
79 (@friend_pull * 4).to_i.to_bitstring(4).gray_encode +
80 (@enemy_pull * 4).to_i.to_bitstring(4).gray_encode +
81 (@base_pull * 4).to_i.to_bitstring(4).gray_encode +
82 @safe_bonus.to_bitstring(4).gray_encode +
83 @capture_bonus.to_bitstring(4).gray_encode
86 # Convert a player to a genome
88 Genome.new(self.to_bitstring)
95 # Create a potential player from a genome
96 def to_potential_player
97 friend_pull = @genome[0, 4].gray_decode.to_decimal.to_f / 4
98 enemy_pull = @genome[4, 4].gray_decode.to_decimal.to_f / 4
99 base_pull = @genome[8, 4].gray_decode.to_decimal.to_f / 4
100 safe_bonus = @genome[12, 4].gray_decode.to_decimal
101 capture_bonus = @genome[16, 4].gray_decode.to_decimal
102 Potential_player.new({:friend_pull => friend_pull,
103 :enemy_pull => enemy_pull, :base_pull => base_pull,
104 :safe_bonus => safe_bonus, :capture_bonus => capture_bonus})