-
Notifications
You must be signed in to change notification settings - Fork 0
/
optimal.py
40 lines (32 loc) · 1.25 KB
/
optimal.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import functools
import random
MISERE = 'misere'
NORMAL = 'normal'
def optimal_nim(heaps, possible_actions):
game_type='misere'
is_misere = game_type == MISERE
is_near_endgame = False
count_non_0_1 = sum(1 for x in heaps if x > 1)
is_near_endgame = (count_non_0_1 <= 1)
# nim sum will give the correct end-game move for normal play but
# misere requires the last move be forced onto the opponent
if is_misere and is_near_endgame:
moves_left = sum(1 for x in heaps if x > 0)
is_odd = (moves_left % 2 == 1)
sizeof_max = max(heaps)
index_of_max = heaps.index(sizeof_max)
if sizeof_max == 1 and is_odd:
#return "You will lose :("
return random.choice(list(possible_actions))
# reduce the game to an odd number of 1's
return (index_of_max, sizeof_max - int(is_odd))
nim_sum = functools.reduce(lambda x, y: x ^ y, heaps)
if nim_sum == 0:
#return "You will lose :("
return random.choice(list(possible_actions))
# Calc which move to make
for index, heap in enumerate(heaps):
target_size = heap ^ nim_sum
if target_size < heap:
amount_to_remove = heap - target_size
return (index, amount_to_remove)