9 def new_game(player1
, player2
):
10 return {'board': empty_board(),
13 'player1_active': True,
17 def game_finished(game
):
18 return (winner(game
['board']) is not None) or (game
['board'].count('.') == 0)
21 def active_player(game
):
22 if game
['player1_active']:
23 return game
['player1']
25 return game
['player2']
29 boxes
= {'human?': False}
30 for b
in non_winning_boards():
31 box
= collections
.Counter()
33 box
[s
] = INITIAL_BEAD_COUNT
38 def menace_move(game
):
39 board
, r
, f
= canonical(game
['board'])
40 player
= active_player(game
)
41 token
= token_for_player(game
['player1_active'])
42 cmove
= random
.choice(list(player
[board
].elements()))
43 cmove_board
= apply_move(empty_board(), cmove
, token
)
44 moved_board
= untransform(cmove_board
, r
, f
)
45 return moved_board
.index(token
)
49 return {'human?': True}
54 print('Opponent moved to', game
['history'][-1]['move'])
56 print('You play first.')
57 print('The board is:')
58 print(show_board(game
['board']))
60 valid_moves
= vacants(game
['board'])
63 while not valid_input
:
64 user_input
= input('Your move ({})? '.format(', '.join(str(m
) for m
in valid_moves
)))
65 if user_input
.isnumeric():
66 move
= int(user_input
)
67 if move
in valid_moves
:
70 print('Number not a valid move.')
72 print('Please enter a number.')
77 if game
['player1_active']:
78 active
= game
['player1']
80 active
= game
['player2']
82 move
= human_move(game
)
84 move
= menace_move(game
)
85 token
= token_for_player(game
['player1_active'])
86 game
['history'] += [{'player1?': game
['player1_active'], 'move': move
, 'board': game
['board']}]
87 game
['board'] = apply_move(game
['board'], move
, token
)
88 game
['player1_active'] = not game
['player1_active']
92 while not game_finished(game
):
96 def winning_player(game
):
97 if winner(game
['board']) is None:
99 elif game
['history'][-1]['player1?']:
100 return game
['player1']
102 return game
['player2']
105 def losing_player(game
):
106 if winner(game
['board']) is None:
108 elif game
['history'][-1]['player1?']:
109 return game
['player2']
111 return game
['player1']
114 def winning_moves(game
):
115 return [h
for h
in game
['history']
116 if h
['player1?'] == game
['history'][-1]['player1?']]
119 def losing_moves(game
):
120 return [h
for h
in game
['history']
121 if h
['player1?'] != game
['history'][-1]['player1?']]
124 def update_players(game
, allow_drop_move
=False):
125 if winner(game
['board']) is not None:
127 update_loser(game
, allow_drop_move
=allow_drop_move
)
130 def update_winner(game
):
131 player
= winning_player(game
)
132 moves
= winning_moves(game
)
134 board
, r
, f
= canonical(m
['board'])
135 move_board
= apply_move(empty_board(), m
['move'], '+')
136 cmove_board
= transform(move_board
, r
, f
)
137 cmove
= cmove_board
.index('+')
138 player
[board
][cmove
] += 1
141 def update_loser(game
, allow_drop_move
=False):
142 player
= losing_player(game
)
143 moves
= losing_moves(game
)
145 board
, r
, f
= canonical(m
['board'])
146 move_board
= apply_move(empty_board(), m
['move'], '+')
147 cmove_board
= transform(move_board
, r
, f
)
148 cmove
= cmove_board
.index('+')
149 # if player[board][cmove] > 1:
150 # player[board][cmove] -= 1
152 if len(list(player
[board
].elements())) > 1:
153 player
[board
][cmove
] -= 1
155 if player
[board
][cmove
] > 1:
156 player
[board
][cmove
] -= 1
159 def count_wins(p1
, p2
, plays
=1000):
162 for _
in range(plays
):
165 if winner(g
['board']) is None:
167 elif winning_player(g
) == p1
:
172 def game_with_players(p1
, p2
, report_result_for
=None):
173 if random
.choice([True, False]):
179 if report_result_for
:
180 print('\nFinal position')
181 print(show_board(g
['board']))
182 if winner(g
['board']) is None:
184 elif winning_player(g
) == ph
:
191 def train_players(p1
, p2
, rounds
=10000, allow_drop_move
=False):
192 for _
in range(rounds
):
193 g
= game_with_players(p1
, p2
)
194 update_players(g
, allow_drop_move
=allow_drop_move
)