-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnim_game.py
153 lines (130 loc) · 4.19 KB
/
nim_game.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
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
"""
This is the main file for the game of Nim
"""
from GameState import GameState
import bots
def get_move_from_user(game: GameState) -> tuple[int]:
'''
Asks the user for input until they have given a valid move
Returns (m, n)
'''
while True:
try:
s1 = f"Enter pile number (1-{len(game.piles)}): "
pile_idx = int(input(s1)) - 1
if 0 <= pile_idx < len(game.piles) and game.piles[pile_idx] > 0:
break
else:
print("Invalid pile number. Choose a valid pile.")
except ValueError:
print("Invalid input. Please enter a valid pile number.")
while True:
try:
s2 = f"Enter number of stones to take (1-{game.piles[pile_idx]}): "
objects_to_remove = int(input(s2))
if 1 <= objects_to_remove <= game.piles[pile_idx]:
break
else:
print("Invalid number of objects. Choose a valid number.")
except ValueError:
print("Invalid input. Please enter a valid number.")
return (pile_idx, objects_to_remove)
def two_player_nim(game: GameState) -> int:
"""
Runs a single game of nim between two players.
Returns the winning player (in [1, 2])
"""
player = 1
while True:
print(game)
print(f"Player {player}'s turn...")
m, n = get_move_from_user(game)
game.make_move(m, n)
if game.is_empty():
print("It ended!")
break
else:
player = 3 - player
print("Game Over.")
print(f"Player {player} wins!")
return player
def player_vs_bot_nim(game: GameState, user_first=True) -> int:
"""
Runs a single game of nim between the user and computer
User determins whether the user goes first or second
Returns true iff the user wins
"""
user_turn = user_first
while True:
print(game)
if user_turn:
print("Your turn...")
m, n = get_move_from_user(game)
game.make_move(m, n)
else:
# move = bots.random_bot(game)
move = bots.two_pile_bot(game)
m, n = move
game.make_move(m, n)
print(f"Computer takes {n} stones from pile {m+1}")
if game.is_empty():
print("It ended!")
break
else:
user_turn = not user_turn
print("Game Over.")
if user_turn:
print("You win!")
return True
else:
print("You Lose!")
return False
def bot_vs_bot_nim(game: GameState, bot1='random', bot2='random', verbose=True):
"""
Runs a single game of nim betwen two bots
The bot name must be in the list of valid bots
Prints statements if verbose
Returns true iff bot1 wins
"""
# Define the bot functions based on their names
def get_bot_function(bot_name):
if bot_name == 'random':
return bots.random_bot
elif bot_name == 'two_pile':
return bots.two_pile_bot
elif bot_name == 'nim_sum':
return bots.nim_sum_bot
else:
raise ValueError(f"Unknown bot: {bot_name}")
bot1_function = get_bot_function(bot1)
bot2_function = get_bot_function(bot2)
current_bot = bot1_function
next_bot = bot2_function
while True:
if verbose:
print(game)
# Determine the move based on the current bot
move = current_bot(game)
# Make the move
m, n = move
game.make_move(m, n)
if verbose:
print(f"{current_bot.__name__} takes {n} stones from pile {m + 1}")
# Check if the game is over
if game.is_empty():
print("Game Over.")
return current_bot == bot1_function # bot1 wins if it's its turn
# Swap bots for the next turn
current_bot, next_bot = next_bot, current_bot
def main():
# two_player_nim([5, 5])
# player_vs_bot_nim([3, 4, 5])
bot1 = 'nim_sum'
bot2 = 'two_pile'
outcome = bot_vs_bot_nim(GameState([3, 4, 5]), bot1, bot2, True)
if outcome:
print("Bot1:", bot1, "wins!")
else:
print("Bot2:", bot2, "wins!")
if __name__ == "__main__":
main()