aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/server/toggle_game.py
blob: 0de8f9f0299b43de0560f9d50c7eaf88082cf784 (plain) (blame)
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
from fast_P import P


def safe_int_parse(s):
    try:
        return int(s)
    except ValueError:
        return -1


def display_game(game: dict) -> None:
    for i in range(game['size']):
        if game['board'][i]:
            print(f'{i+1:02d}', end="")
        else:
            print('  ', end="")
        if i + 1 != game['size']:
            print('-', end="")
    print()


def valid_move(game: dict, i: int):
    if i >= game['size'] or i < 0:
        return False
    if game['board'][i]:
        if i > 0:
            if i < game['size']-1:
                return game['board'][i-1] or game['board'][i+1]
            else:
                return game['board'][i-1]
        else:
            if i < game['size']-1:
                return game['board'][i+1]
            else:
                return True


def make_move(game: dict, i: int):
    gs = game['board'].copy()
    gs[i] = False
    if i > 0:
        gs[i-1] = not gs[i-1]
    if i < game['size']-1:
        gs[i+1] = not gs[i+1]
    return gs


def get_nimber(gs: list) -> int:
    n = len(gs)
    nimber_so_far = 0
    path_size = 0
    for i in range(n):
        if gs[i]:
            path_size += 1
        else:
            if path_size == 1 and n != 1:
                path_size = 0
            nimber_so_far = nimber_so_far ^ P(path_size)
            path_size = 0
    if path_size == 1 and n != 1:
        path_size = 0
    nimber_so_far = nimber_so_far ^ P(path_size)
    return nimber_so_far


def i_have_won(game: dict) -> bool:
    for i in range(game['size']):
        if valid_move(game, i):
            return False
    return True


def find_move(game: dict) -> int:
    game_state_orig = game['board'].copy()
    for i in range(game['size']):
        if valid_move(game, i):
            gs = make_move(game, i)
            if get_nimber(gs) == 0:
                return i
    raise Exception("I have been beat!")


def new_game(size: int) -> dict:
    game = {}
    game['board'] = [True] * size
    game['human_turn'] = not P(size) > 0
    game['size'] = size
    game['version'] = '0.0.0'
    game['finished'] = False
    game['winner'] = ""
    game['turn'] = 1
    return game


def main():
    n = int(input("Path size to play on> "))
    game = new_game(n)

    if game['human_turn']:
        print("You can play first!")
    else:
        print("I'll play first!")

    while True:
        display_game(game)
        if game['human_turn']:
            if i_have_won(game):
                print("You're out of moves. I win!")
                game['finished'] = True
                game['winner'] = "Computer"
                break
            game['human_turn'] = False
            i = -1 # placeholder
            while True:
                i = safe_int_parse(input("Make your move> ")) - 1
                if valid_move(game, i):
                    break
                print("Hey! That's not allowed!")
                display_game(game)
            game['turn'] += 1
            game['board'] = make_move(game, i)
        else:
            game['human_turn'] = True
            i = find_move(game)
            print(f"Hmm... I'll toggle {i + 1}")
            game['turn'] += 1
            game['board'] = make_move(game, i)

    print('-'*8)
    for key, val in game.items():
        print(f'{key}: {val}')

if __name__ == "__main__":
    main()