uhhhh
This commit is contained in:
parent
0d2340b7e8
commit
a74be2fc31
11 changed files with 2367 additions and 184 deletions
363
game.py
363
game.py
|
|
@ -1,179 +1,184 @@
|
|||
import pygame
|
||||
import sys
|
||||
import time
|
||||
|
||||
# Initialize Pygame
|
||||
pygame.init()
|
||||
|
||||
# Constants
|
||||
WIDTH, HEIGHT = 700, 500
|
||||
FPS = 30
|
||||
WHITE = (255, 255, 255)
|
||||
BLACK = (0, 0, 0)
|
||||
RED = (255, 0, 0)
|
||||
GREEN = (0, 255, 0)
|
||||
LIGHT_GREY = (200, 200, 200)
|
||||
DARK_GREY = (50, 50, 50)
|
||||
FONT = pygame.font.Font(None, 36)
|
||||
|
||||
# Create screen
|
||||
screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
pygame.display.set_caption('Nim Game')
|
||||
|
||||
# Define piles (number of coins in each pile)
|
||||
piles = [4, 4, 4, 4] # 4 piles with 4 coins each
|
||||
selected_stones = [] # To store selected stones for removal
|
||||
selected_pile = None # Tracks the pile from which coins are selected
|
||||
|
||||
# Players
|
||||
player_turn = 1 # Player 1 starts (alternates between 1 and 2)
|
||||
|
||||
# Game State
|
||||
game_over = False
|
||||
winner = None
|
||||
|
||||
def draw_piles():
|
||||
"""Draws the piles of coins as circles with padding."""
|
||||
x_pos = 130 # Start from left with padding
|
||||
y_start = 250
|
||||
padding = 150 # Increased space between piles for better symmetry
|
||||
radius = 20
|
||||
for idx, pile in enumerate(piles):
|
||||
y_pos = y_start
|
||||
for stone in range(pile):
|
||||
color = RED
|
||||
if (idx, stone) in selected_stones:
|
||||
color = GREEN # Show selected stones as green
|
||||
pygame.draw.circle(screen, color, (x_pos, y_pos), radius)
|
||||
y_pos -= 2 * radius + 10 # Space between circles
|
||||
text = FONT.render(f'Pile {idx + 1}', True, BLACK)
|
||||
screen.blit(text, (x_pos - 30, 320))
|
||||
x_pos += padding # Increase x position and add padding
|
||||
|
||||
def check_game_over():
|
||||
"""Check if the game is over (all piles empty)."""
|
||||
global winner, game_over
|
||||
if all(pile == 0 for pile in piles):
|
||||
winner = 2 if player_turn == 1 else 1 # The other player wins
|
||||
game_over = True
|
||||
|
||||
def draw_game_state():
|
||||
"""Draws the current game state including piles and turn."""
|
||||
screen.fill(LIGHT_GREY) # Background color
|
||||
draw_piles()
|
||||
|
||||
if game_over:
|
||||
if player_turn == 1:
|
||||
text = FONT.render(f'You win, hooray!', True, GREEN)
|
||||
screen.blit(text, (WIDTH // 2 - text.get_width() // 2, 30)) # Adjusted y-position for spacing
|
||||
else:
|
||||
text = FONT.render(f'AI wins!', True, GREEN)
|
||||
screen.blit(text, (WIDTH // 2 - text.get_width() // 2, 30)) # Adjusted y-position for spacing
|
||||
|
||||
# Draw the Restart button
|
||||
pygame.draw.rect(screen, DARK_GREY, (WIDTH // 2 - 60, HEIGHT - 60, 120, 40))
|
||||
restart_text = FONT.render("Restart", True, WHITE)
|
||||
screen.blit(restart_text, (WIDTH // 2 - restart_text.get_width() // 2, HEIGHT - 50))
|
||||
else:
|
||||
if player_turn == 1:
|
||||
text = FONT.render(f'Your turn!', True, BLACK)
|
||||
screen.blit(text, (WIDTH // 2 - text.get_width() // 2, 30)) # Centered player label
|
||||
else:
|
||||
text = FONT.render(f'Computer thinking... ', True, BLACK)
|
||||
screen.blit(text, (WIDTH // 2 - text.get_width() // 2, 30)) # Centered player labe
|
||||
|
||||
|
||||
# Draw the "Remove" button at the bottom
|
||||
pygame.draw.rect(screen, BLACK, (WIDTH // 2 - 60, HEIGHT - 120, 120, 40))
|
||||
remove_text = FONT.render("Remove", True, WHITE)
|
||||
screen.blit(remove_text, (WIDTH // 2 - remove_text.get_width() // 2, HEIGHT - 110))
|
||||
|
||||
def remove_stones():
|
||||
"""Removes the selected stones from the selected pile."""
|
||||
global player_turn, selected_pile
|
||||
for pile_index, stone_index in selected_stones:
|
||||
piles[pile_index] -= 1
|
||||
selected_stones.clear()
|
||||
selected_pile = None # Reset selected pile after removal
|
||||
player_turn = 2 if player_turn == 1 else 1 # Switch turns
|
||||
check_game_over()
|
||||
|
||||
def handle_selection(pile_index, stone_index):
|
||||
"""Handles selecting or deselecting stones, ensuring only one pile can be selected."""
|
||||
global selected_pile
|
||||
if selected_pile is None or selected_pile == pile_index:
|
||||
selected_pile = pile_index # Lock the selection to the current pile
|
||||
if (pile_index, stone_index) in selected_stones:
|
||||
selected_stones.remove((pile_index, stone_index)) # Deselect
|
||||
else:
|
||||
selected_stones.append((pile_index, stone_index)) # Select
|
||||
|
||||
def restart_game():
|
||||
"""Restarts the game."""
|
||||
global piles, player_turn, selected_stones, selected_pile, game_over, winner
|
||||
piles = [4, 4, 4, 4] # Reset piles
|
||||
selected_stones.clear()
|
||||
selected_pile = None
|
||||
player_turn = 1
|
||||
game_over = False
|
||||
winner = None
|
||||
|
||||
def start_game(ai):
|
||||
"""Starts the game and integrates AI for playing against the computer."""
|
||||
global player_turn, game_over
|
||||
|
||||
# Main game loop
|
||||
clock = pygame.time.Clock()
|
||||
while True:
|
||||
clock.tick(FPS)
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
elif event.type == pygame.MOUSEBUTTONDOWN and not game_over and player_turn == 1:
|
||||
mouse_x, mouse_y = event.pos
|
||||
# Check for pile selection (clicking on a coin)
|
||||
x_pos = 130
|
||||
y_start = 250
|
||||
padding = 150
|
||||
radius = 20
|
||||
for pile_index, pile in enumerate(piles):
|
||||
y_pos = y_start
|
||||
for stone_index in range(pile):
|
||||
dist = ((mouse_x - x_pos)**2 + (mouse_y - y_pos)**2)**0.5
|
||||
if dist <= radius:
|
||||
handle_selection(pile_index, stone_index)
|
||||
y_pos -= 2 * radius + 10
|
||||
x_pos += padding
|
||||
# Check for "Remove" button click
|
||||
if WIDTH // 2 - 60 <= mouse_x <= WIDTH // 2 + 60 and HEIGHT - 120 <= mouse_y <= HEIGHT - 80:
|
||||
remove_stones()
|
||||
|
||||
# If game over, check for "Restart" button click
|
||||
elif event.type == pygame.MOUSEBUTTONDOWN and game_over:
|
||||
mouse_x, mouse_y = event.pos
|
||||
if WIDTH // 2 - 60 <= mouse_x <= WIDTH // 2 + 60 and HEIGHT - 60 <= mouse_y <= HEIGHT - 20:
|
||||
restart_game()
|
||||
|
||||
# If it's the AI's turn and the game is not over
|
||||
if player_turn == 2 and not game_over:
|
||||
draw_game_state()
|
||||
pygame.display.flip()
|
||||
# Simulate thinking
|
||||
time.sleep(2)
|
||||
# AI makes its move
|
||||
action = ai.choose_action(piles, epsilon=False)
|
||||
remove_stones_from_ai(action)
|
||||
|
||||
draw_game_state()
|
||||
pygame.display.flip()
|
||||
|
||||
def remove_stones_from_ai(action):
|
||||
"""Handles AI stone removal."""
|
||||
pile, count = action
|
||||
for i in range(count):
|
||||
piles[pile] -= 1
|
||||
global player_turn
|
||||
player_turn = 1 # Switch back to human player
|
||||
check_game_over()
|
||||
import pygame
|
||||
import sys
|
||||
import time
|
||||
|
||||
# Initialize Pygame
|
||||
pygame.init()
|
||||
|
||||
# Constants
|
||||
WIDTH, HEIGHT = 700, 500
|
||||
FPS = 30
|
||||
WHITE = (255, 255, 255)
|
||||
BLACK = (0, 0, 0)
|
||||
RED = (255, 0, 0)
|
||||
GREEN = (0, 255, 0)
|
||||
LIGHT_GREY = (200, 200, 200)
|
||||
DARK_GREY = (50, 50, 50)
|
||||
FONT = pygame.font.Font(None, 36)
|
||||
|
||||
# Create screen
|
||||
screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
pygame.display.set_caption('Nim Game')
|
||||
|
||||
# Define piles (number of coins in each pile)
|
||||
piles = [4, 4, 4, 4] # 4 piles with 4 coins each
|
||||
selected_stones = [] # To store selected stones for removal
|
||||
selected_pile = None # Tracks the pile from which coins are selected
|
||||
|
||||
# Players
|
||||
player_turn = 1 # Player 1 starts (alternates between 1 and 2)
|
||||
|
||||
# Game State
|
||||
game_over = False
|
||||
winner = None
|
||||
|
||||
def draw_piles():
|
||||
"""Draws the piles of coins as circles with padding."""
|
||||
x_pos = 130 # Start from left with padding
|
||||
y_start = 250
|
||||
padding = 150 # Increased space between piles for better symmetry
|
||||
radius = 20
|
||||
for idx, pile in enumerate(piles):
|
||||
y_pos = y_start
|
||||
for stone in range(pile):
|
||||
color = RED
|
||||
if (idx, stone) in selected_stones:
|
||||
color = GREEN # Show selected stones as green
|
||||
pygame.draw.circle(screen, color, (x_pos, y_pos), radius)
|
||||
y_pos -= 2 * radius + 10 # Space between circles
|
||||
text = FONT.render(f'Pile {idx + 1}', True, BLACK)
|
||||
screen.blit(text, (x_pos - 30, 320))
|
||||
x_pos += padding # Increase x position and add padding
|
||||
|
||||
def check_game_over():
|
||||
"""Check if the game is over (all piles empty)."""
|
||||
global winner, game_over
|
||||
if all(pile == 0 for pile in piles):
|
||||
winner = 2 if player_turn == 1 else 1 # The other player wins
|
||||
game_over = True
|
||||
|
||||
def draw_game_state():
|
||||
"""Draws the current game state including piles and turn."""
|
||||
screen.fill(LIGHT_GREY) # Background color
|
||||
draw_piles()
|
||||
|
||||
if game_over:
|
||||
if player_turn == 1:
|
||||
text = FONT.render(f'You win, hooray!', True, GREEN)
|
||||
screen.blit(text, (WIDTH // 2 - text.get_width() // 2, 30)) # Adjusted y-position for spacing
|
||||
else:
|
||||
text = FONT.render(f'AI wins!', True, GREEN)
|
||||
screen.blit(text, (WIDTH // 2 - text.get_width() // 2, 30)) # Adjusted y-position for spacing
|
||||
|
||||
# Draw the Restart button
|
||||
pygame.draw.rect(screen, DARK_GREY, (WIDTH // 2 - 60, HEIGHT - 60, 120, 40))
|
||||
restart_text = FONT.render("Restart", True, WHITE)
|
||||
screen.blit(restart_text, (WIDTH // 2 - restart_text.get_width() // 2, HEIGHT - 50))
|
||||
else:
|
||||
if player_turn == 1:
|
||||
text = FONT.render(f'Your turn!', True, BLACK)
|
||||
screen.blit(text, (WIDTH // 2 - text.get_width() // 2, 30)) # Centered player label
|
||||
else:
|
||||
text = FONT.render(f'Computer thinking... ', True, BLACK)
|
||||
screen.blit(text, (WIDTH // 2 - text.get_width() // 2, 30)) # Centered player labe
|
||||
|
||||
|
||||
# Draw the "Remove" button at the bottom
|
||||
pygame.draw.rect(screen, BLACK, (WIDTH // 2 - 60, HEIGHT - 120, 120, 40))
|
||||
remove_text = FONT.render("Remove", True, WHITE)
|
||||
screen.blit(remove_text, (WIDTH // 2 - remove_text.get_width() // 2, HEIGHT - 110))
|
||||
|
||||
def remove_stones():
|
||||
"""Removes the selected stones from the selected pile."""
|
||||
global player_turn, selected_pile
|
||||
if not selected_stones:
|
||||
return # Do nothing if nothing is selected
|
||||
for pile_index, stone_index in selected_stones:
|
||||
piles[pile_index] -= 1
|
||||
selected_stones.clear()
|
||||
selected_pile = None # Reset selected pile after removal
|
||||
player_turn = 2 if player_turn == 1 else 1 # Switch turns
|
||||
check_game_over()
|
||||
|
||||
def handle_selection(pile_index, stone_index):
|
||||
"""Handles selecting or deselecting stones, ensuring only one pile can be selected."""
|
||||
global selected_pile
|
||||
if selected_pile is None or selected_pile == pile_index:
|
||||
if (pile_index, stone_index) in selected_stones:
|
||||
selected_stones.remove((pile_index, stone_index)) # Deselect
|
||||
# If no stones are selected anymore, allow switching piles
|
||||
if not selected_stones:
|
||||
selected_pile = None
|
||||
else:
|
||||
selected_stones.append((pile_index, stone_index)) # Select
|
||||
selected_pile = pile_index # Lock the selection to the current pile
|
||||
|
||||
def restart_game():
|
||||
"""Restarts the game."""
|
||||
global piles, player_turn, selected_stones, selected_pile, game_over, winner
|
||||
piles = [4, 4, 4, 4] # Reset piles
|
||||
selected_stones.clear()
|
||||
selected_pile = None
|
||||
player_turn = 1
|
||||
game_over = False
|
||||
winner = None
|
||||
|
||||
def start_game(ai):
|
||||
"""Starts the game and integrates AI for playing against the computer."""
|
||||
global player_turn, game_over
|
||||
|
||||
# Main game loop
|
||||
clock = pygame.time.Clock()
|
||||
while True:
|
||||
clock.tick(FPS)
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
elif event.type == pygame.MOUSEBUTTONDOWN and not game_over and player_turn == 1:
|
||||
mouse_x, mouse_y = event.pos
|
||||
# Check for pile selection (clicking on a coin)
|
||||
x_pos = 130
|
||||
y_start = 250
|
||||
padding = 150
|
||||
radius = 20
|
||||
for pile_index, pile in enumerate(piles):
|
||||
y_pos = y_start
|
||||
for stone_index in range(pile):
|
||||
dist = ((mouse_x - x_pos)**2 + (mouse_y - y_pos)**2)**0.5
|
||||
if dist <= radius:
|
||||
handle_selection(pile_index, stone_index)
|
||||
y_pos -= 2 * radius + 10
|
||||
x_pos += padding
|
||||
# Check for "Remove" button click
|
||||
if WIDTH // 2 - 60 <= mouse_x <= WIDTH // 2 + 60 and HEIGHT - 120 <= mouse_y <= HEIGHT - 80:
|
||||
remove_stones()
|
||||
|
||||
# If game over, check for "Restart" button click
|
||||
elif event.type == pygame.MOUSEBUTTONDOWN and game_over:
|
||||
mouse_x, mouse_y = event.pos
|
||||
if WIDTH // 2 - 60 <= mouse_x <= WIDTH // 2 + 60 and HEIGHT - 60 <= mouse_y <= HEIGHT - 20:
|
||||
restart_game()
|
||||
|
||||
# If it's the AI's turn and the game is not over
|
||||
if player_turn == 2 and not game_over:
|
||||
draw_game_state()
|
||||
pygame.display.flip()
|
||||
# Simulate thinking
|
||||
time.sleep(2)
|
||||
# AI makes its move
|
||||
action = ai.choose_action(piles, epsilon=False)
|
||||
remove_stones_from_ai(action)
|
||||
|
||||
draw_game_state()
|
||||
pygame.display.flip()
|
||||
|
||||
def remove_stones_from_ai(action):
|
||||
"""Handles AI stone removal."""
|
||||
pile, count = action
|
||||
for i in range(count):
|
||||
piles[pile] -= 1
|
||||
global player_turn
|
||||
player_turn = 1 # Switch back to human player
|
||||
check_game_over()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue