|
import os |
|
import random |
|
import csv |
|
import numpy as np |
|
import tensorflow as tf |
|
import gradio as gr |
|
from tensorflow.keras.models import Sequential, load_model |
|
from tensorflow.keras.layers import LSTM, Dense, Embedding |
|
from tensorflow.keras.preprocessing.sequence import pad_sequences |
|
from tensorflow.keras.preprocessing.text import Tokenizer |
|
|
|
|
|
os.environ["CUDA_VISIBLE_DEVICES"] = "-1" |
|
os.environ["TF_ENABLE_ONEDNN_OPTS"] = "0" |
|
|
|
|
|
csv_filename = "game_moves.csv" |
|
model_filename = "lstm_model.h5" |
|
|
|
|
|
choices = {'rock': 0, 'paper': 1, 'scissors': 2} |
|
rev_choices = {0: 'rock', 1: 'paper', 2: 'scissors'} |
|
|
|
|
|
if not os.path.exists(csv_filename): |
|
with open(csv_filename, mode='w', newline='') as file: |
|
writer = csv.writer(file) |
|
writer.writerow(["Player Choice", "Computer Choice", "Result"]) |
|
|
|
def get_computer_choice(model, past_moves): |
|
""" Predicts player's next move and counteracts it. """ |
|
if len(past_moves) < 5: |
|
return random.choice(["rock", "paper", "scissors"]) |
|
|
|
|
|
sequence = [choices[move] for move in past_moves[-5:]] |
|
sequence = pad_sequences([sequence], maxlen=5) |
|
|
|
prediction = model.predict(sequence, verbose=0) |
|
predicted_choice = rev_choices[np.argmax(prediction)] |
|
|
|
|
|
counter_choices = {'rock': 'paper', 'paper': 'scissors', 'scissors': 'rock'} |
|
return counter_choices[predicted_choice] |
|
|
|
def get_winner(player, computer): |
|
""" Determines the winner of the game. """ |
|
if player == computer: |
|
return "It's a tie!" |
|
elif (player == "rock" and computer == "scissors") or \ |
|
(player == "scissors" and computer == "paper") or \ |
|
(player == "paper" and computer == "rock"): |
|
return "You win!" |
|
else: |
|
return "Computer wins!" |
|
|
|
def save_move(player, computer, result): |
|
""" Saves game move to CSV file. """ |
|
with open(csv_filename, mode="a", newline="") as file: |
|
writer = csv.writer(file) |
|
writer.writerow([player, computer, result]) |
|
|
|
def load_data(): |
|
""" Loads past player moves from CSV file. """ |
|
try: |
|
with open(csv_filename, mode="r") as file: |
|
reader = csv.reader(file) |
|
next(reader) |
|
return [row[0] for row in reader] |
|
except FileNotFoundError: |
|
return [] |
|
|
|
def train_lstm_model(data): |
|
""" Trains an LSTM model to predict the player's next move. """ |
|
if len(data) < 6: |
|
return None |
|
|
|
tokenizer = Tokenizer(num_words=3) |
|
tokenizer.fit_on_texts(data) |
|
sequences = tokenizer.texts_to_sequences(data) |
|
|
|
X = pad_sequences(sequences, maxlen=5) |
|
y = np.array([choices[move] for move in data[1:]]) |
|
|
|
model = Sequential([ |
|
Embedding(input_dim=3, output_dim=10, input_length=5), |
|
LSTM(30, return_sequences=False), |
|
Dense(3, activation="softmax") |
|
]) |
|
model.compile(loss="sparse_categorical_crossentropy", optimizer="adam", metrics=["accuracy"]) |
|
|
|
if len(X) > 1: |
|
model.fit(X[:-1], y, epochs=15, verbose=0) |
|
model.save(model_filename) |
|
|
|
return model |
|
|
|
|
|
past_moves = load_data() |
|
|
|
|
|
if os.path.exists(model_filename): |
|
model = load_model(model_filename) |
|
else: |
|
model = train_lstm_model(past_moves) if len(past_moves) >= 6 else None |
|
|
|
def play_game(player_choice): |
|
""" Handles the game logic and returns the result. """ |
|
global past_moves, model |
|
|
|
if player_choice not in choices: |
|
return "Invalid choice. Choose rock, paper, or scissors." |
|
|
|
|
|
if model is None: |
|
computer_choice = random.choice(["rock", "paper", "scissors"]) |
|
else: |
|
computer_choice = get_computer_choice(model, past_moves) |
|
|
|
result = get_winner(player_choice, computer_choice) |
|
|
|
|
|
save_move(player_choice, computer_choice, result) |
|
past_moves.append(player_choice) |
|
|
|
|
|
if len(past_moves) >= 6: |
|
model = train_lstm_model(past_moves) |
|
|
|
return f"Computer chose: {computer_choice}\n{result}" |
|
|
|
|
|
iface = gr.Interface( |
|
fn=play_game, |
|
inputs=gr.Radio(["rock", "paper", "scissors"], label="Choose your move"), |
|
outputs="text", |
|
title="Rock, Paper, Scissors AI", |
|
description="Play against an AI that learns from your moves and tries to beat you!" |
|
) |
|
|
|
if __name__ == "__main__": |
|
iface.launch() |
|
|