11 def new_game(player1
, player2
):
12 return {'board': empty_board(),
15 'player1_active': True,
18 def game_finished(game
):
19 return (winner(game
['board']) is not None) or (game
['board'].count('.') == 0)
22 def active_player(game
):
23 if game
['player1_active']:
24 return game
['player1']
26 return game
['player2']
30 boxes
= {'human?': False}
31 for b
in non_winning_boards():
32 box
= collections
.Counter()
34 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
)
48 return {'human?': True}
53 print('Opponent moved to', game
['history'][-1]['move'])
55 print('You play first.')
56 print('The board is:')
57 print(show_board(game
['board']))
59 valid_moves
= vacants(game
['board'])
62 while not valid_input
:
63 user_input
= input('Your move ({})? '.format(', '.join(str(m
) for m
in valid_moves
)))
64 if user_input
.isnumeric():
65 move
= int(user_input
)
66 if move
in valid_moves
:
69 print('Number not a valid move.')
71 print('Please enter a number.')
75 if game
['player1_active']:
76 active
= game
['player1']
78 active
= game
['player2']
80 move
= human_move(game
)
82 move
= menace_move(game
)
83 token
= token_for_player(game
['player1_active'])
84 game
['history'] += [{'player1?': game
['player1_active'], 'move': move
, 'board': game
['board']}]
85 game
['board'] = apply_move(game
['board'], move
, token
)
86 game
['player1_active'] = not game
['player1_active']
90 while not game_finished(game
):
93 def winning_player(game
):
94 if winner(game
['board']) is None:
96 elif game
['history'][-1]['player1?']:
97 return game
['player1']
99 return game
['player2']
101 def losing_player(game
):
102 if winner(game
['board']) is None:
104 elif game
['history'][-1]['player1?']:
105 return game
['player2']
107 return game
['player1']
110 def winning_moves(game
):
111 return [h
for h
in game
['history']
112 if h
['player1?'] == game
['history'][-1]['player1?']]
114 def losing_moves(game
):
115 return [h
for h
in game
['history']
116 if h
['player1?'] != game
['history'][-1]['player1?']]
119 def update_players(game
, allow_drop_move
=False):
120 if winner(game
['board']) is not None:
122 update_loser(game
, allow_drop_move
=allow_drop_move
)
125 def update_winner(game
):
126 player
= winning_player(game
)
127 moves
= winning_moves(game
)
129 board
, r
, f
= canonical(m
['board'])
130 move_board
= apply_move(empty_board(), m
['move'], '+')
131 cmove_board
= transform(move_board
, r
, f
)
132 cmove
= cmove_board
.index('+')
133 player
[board
][cmove
] += 1
135 def update_loser(game
, allow_drop_move
=False):
136 player
= losing_player(game
)
137 moves
= losing_moves(game
)
139 board
, r
, f
= canonical(m
['board'])
140 move_board
= apply_move(empty_board(), m
['move'], '+')
141 cmove_board
= transform(move_board
, r
, f
)
142 cmove
= cmove_board
.index('+')
143 # if player[board][cmove] > 1:
144 # player[board][cmove] -= 1
146 if len(list(player
[board
].elements())) > 1:
147 player
[board
][cmove
] -= 1
149 if player
[board
][cmove
] > 1:
150 player
[board
][cmove
] -= 1
154 def count_wins(p1
, p2
, plays
=1000):
157 for _
in range(plays
):
160 if winner(g
['board']) is None:
162 elif winning_player(g
) == p1
:
167 def game_with_players(p1
, p2
, report_result_for
=None):
168 if random
.choice([True, False]):
174 if report_result_for
:
175 print('\nFinal position')
176 print(show_board(g
['board']))
177 if winner(g
['board']) is None:
179 elif winning_player(g
) == ph
:
186 def train_players(p1
, p2
, rounds
=10000, allow_drop_move
=False):
187 for _
in range(rounds
):
188 g
= game_with_players(p1
, p2
)
189 update_players(g
, allow_drop_move
=allow_drop_move
)