resberry commited on
Commit
13c8825
·
verified ·
1 Parent(s): d7e234f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +113 -61
app.py CHANGED
@@ -13,6 +13,9 @@ from tensorflow.keras.preprocessing.text import Tokenizer
13
  os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
14
  os.environ["TF_ENABLE_ONEDNN_OPTS"] = "0"
15
 
 
 
 
16
  # File paths
17
  csv_filename = "game_moves.csv"
18
  model_filename = "lstm_model.h5"
@@ -27,80 +30,104 @@ if not os.path.exists(csv_filename):
27
  writer = csv.writer(file)
28
  writer.writerow(["Player Choice", "Computer Choice", "Result"])
29
 
30
- def get_computer_choice(model, past_moves):
31
- """ Predicts player's next move and counteracts it. """
32
- if len(past_moves) < 5: # Adjusted sequence length to 5
33
- return random.choice(["rock", "paper", "scissors"])
34
-
35
- # Prepare input data for prediction
36
- sequence = [choices[move] for move in past_moves[-5:]]
37
- sequence = pad_sequences([sequence], maxlen=5)
38
-
39
- prediction = model.predict(sequence, verbose=0)
40
- predicted_choice = rev_choices[np.argmax(prediction)]
41
-
42
- # Counteract the predicted choice
43
- counter_choices = {'rock': 'paper', 'paper': 'scissors', 'scissors': 'rock'}
44
- return counter_choices[predicted_choice]
45
-
46
- def get_winner(player, computer):
47
- """ Determines the winner of the game. """
48
- if player == computer:
49
- return "It's a tie!"
50
- elif (player == "rock" and computer == "scissors") or \
51
- (player == "scissors" and computer == "paper") or \
52
- (player == "paper" and computer == "rock"):
53
- return "You win!"
54
- else:
55
- return "Computer wins!"
56
-
57
- def save_move(player, computer, result):
58
- """ Saves game move to CSV file. """
59
- with open(csv_filename, mode="a", newline="") as file:
60
- writer = csv.writer(file)
61
- writer.writerow([player, computer, result])
62
-
63
  def load_data():
64
  """ Loads past player moves from CSV file. """
65
  try:
66
  with open(csv_filename, mode="r") as file:
67
  reader = csv.reader(file)
68
  next(reader) # Skip header
69
- return [row[0] for row in reader]
70
  except FileNotFoundError:
71
  return []
72
 
73
  def train_lstm_model(data):
74
  """ Trains an LSTM model to predict the player's next move. """
75
- if len(data) < 6: # Adjusted for longer training sequences
76
  return None # Not enough data for meaningful training
77
 
 
78
  tokenizer = Tokenizer(num_words=3)
79
- tokenizer.fit_on_texts(data)
80
  sequences = tokenizer.texts_to_sequences(data)
81
 
82
- X = pad_sequences(sequences, maxlen=5) # Using longer sequences
83
- y = np.array([choices[move] for move in data[1:]])
 
 
 
 
 
 
 
 
 
84
 
85
  model = Sequential([
86
- Embedding(input_dim=3, output_dim=10, input_length=5),
87
- LSTM(30, return_sequences=False), # Increased LSTM units for better learning
88
  Dense(3, activation="softmax")
89
  ])
90
- model.compile(loss="sparse_categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
91
-
92
- if len(X) > 1:
93
- model.fit(X[:-1], y, epochs=15, verbose=0) # Increased epochs for better training
94
- model.save(model_filename) # Save trained model
95
 
 
 
 
96
  return model
97
 
98
- # Load past moves
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  past_moves = load_data()
100
 
101
- # Load existing model if available
102
  if os.path.exists(model_filename):
103
- model = load_model(model_filename)
 
 
 
104
  else:
105
  model = train_lstm_model(past_moves) if len(past_moves) >= 6 else None
106
 
@@ -111,7 +138,7 @@ def play_game(player_choice):
111
  if player_choice not in choices:
112
  return "Invalid choice. Choose rock, paper, or scissors."
113
 
114
- # Ensure model exists before predicting
115
  if model is None:
116
  computer_choice = random.choice(["rock", "paper", "scissors"])
117
  else:
@@ -123,20 +150,45 @@ def play_game(player_choice):
123
  save_move(player_choice, computer_choice, result)
124
  past_moves.append(player_choice)
125
 
126
- # Retrain the model only when enough new data is available
127
- if len(past_moves) >= 6:
128
  model = train_lstm_model(past_moves)
129
 
130
- return f"Computer chose: {computer_choice}\n{result}"
 
 
 
131
 
132
- # Gradio UI
133
- iface = gr.Interface(
134
- fn=play_game,
135
- inputs=gr.Radio(["rock", "paper", "scissors"], label="Choose your move"),
136
- outputs="text",
137
- title="Rock, Paper, Scissors AI",
138
- description="Play against an AI that learns from your moves and tries to beat you!"
139
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
 
141
  if __name__ == "__main__":
142
- iface.launch()
 
13
  os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
14
  os.environ["TF_ENABLE_ONEDNN_OPTS"] = "0"
15
 
16
+ # Reduce TensorFlow verbosity
17
+ tf.get_logger().setLevel('ERROR')
18
+
19
  # File paths
20
  csv_filename = "game_moves.csv"
21
  model_filename = "lstm_model.h5"
 
30
  writer = csv.writer(file)
31
  writer.writerow(["Player Choice", "Computer Choice", "Result"])
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  def load_data():
34
  """ Loads past player moves from CSV file. """
35
  try:
36
  with open(csv_filename, mode="r") as file:
37
  reader = csv.reader(file)
38
  next(reader) # Skip header
39
+ return [row[0] for row in reader if row] # Added check for empty rows
40
  except FileNotFoundError:
41
  return []
42
 
43
  def train_lstm_model(data):
44
  """ Trains an LSTM model to predict the player's next move. """
45
+ if len(data) < 6:
46
  return None # Not enough data for meaningful training
47
 
48
+ # Tokenizer only needs to work with our 3 choices
49
  tokenizer = Tokenizer(num_words=3)
50
+ tokenizer.fit_on_texts(["rock", "paper", "scissors"]) # Fit on all possible choices
51
  sequences = tokenizer.texts_to_sequences(data)
52
 
53
+ # Create sequences for training
54
+ X, y = [], []
55
+ for i in range(len(sequences) - 5):
56
+ X.append(sequences[i:i+5])
57
+ y.append(sequences[i+5][0] if sequences[i+5] else 0)
58
+
59
+ if len(X) == 0:
60
+ return None
61
+
62
+ X = pad_sequences(X, maxlen=5)
63
+ y = np.array(y)
64
 
65
  model = Sequential([
66
+ Embedding(input_dim=4, output_dim=10, input_length=5), # input_dim=4 (0-3)
67
+ LSTM(30, return_sequences=False),
68
  Dense(3, activation="softmax")
69
  ])
70
+
71
+ model.compile(loss="sparse_categorical_crossentropy",
72
+ optimizer="adam",
73
+ metrics=["accuracy"])
 
74
 
75
+ model.fit(X, y, epochs=10, batch_size=1, verbose=0)
76
+ model.save(model_filename)
77
+
78
  return model
79
 
80
+ def get_computer_choice(model, past_moves):
81
+ """ Predicts player's next move and counteracts it. """
82
+ if len(past_moves) < 5 or model is None:
83
+ return random.choice(["rock", "paper", "scissors"])
84
+
85
+ try:
86
+ # Prepare input data for prediction
87
+ tokenizer = Tokenizer(num_words=3)
88
+ tokenizer.fit_on_texts(["rock", "paper", "scissors"])
89
+ sequences = tokenizer.texts_to_sequences(past_moves[-5:])
90
+
91
+ if len(sequences) < 5:
92
+ return random.choice(["rock", "paper", "scissors"])
93
+
94
+ sequence = pad_sequences([sequences], maxlen=5)
95
+
96
+ prediction = model.predict(sequence, verbose=0)
97
+ predicted_choice = rev_choices[np.argmax(prediction)]
98
+
99
+ # Counteract the predicted choice
100
+ counter_choices = {'rock': 'paper', 'paper': 'scissors', 'scissors': 'rock'}
101
+ return counter_choices[predicted_choice]
102
+ except:
103
+ return random.choice(["rock", "paper", "scissors"])
104
+
105
+ def get_winner(player, computer):
106
+ """ Determines the winner of the game. """
107
+ if player == computer:
108
+ return "It's a tie!"
109
+ elif (player == "rock" and computer == "scissors") or \
110
+ (player == "scissors" and computer == "paper") or \
111
+ (player == "paper" and computer == "rock"):
112
+ return "You win!"
113
+ else:
114
+ return "Computer wins!"
115
+
116
+ def save_move(player, computer, result):
117
+ """ Saves game move to CSV file. """
118
+ with open(csv_filename, mode="a", newline="") as file:
119
+ writer = csv.writer(file)
120
+ writer.writerow([player, computer, result])
121
+
122
+ # Initialize data and model
123
  past_moves = load_data()
124
 
125
+ # Try to load existing model, otherwise create new one
126
  if os.path.exists(model_filename):
127
+ try:
128
+ model = load_model(model_filename)
129
+ except:
130
+ model = train_lstm_model(past_moves) if len(past_moves) >= 6 else None
131
  else:
132
  model = train_lstm_model(past_moves) if len(past_moves) >= 6 else None
133
 
 
138
  if player_choice not in choices:
139
  return "Invalid choice. Choose rock, paper, or scissors."
140
 
141
+ # Get computer choice
142
  if model is None:
143
  computer_choice = random.choice(["rock", "paper", "scissors"])
144
  else:
 
150
  save_move(player_choice, computer_choice, result)
151
  past_moves.append(player_choice)
152
 
153
+ # Retrain model every 10 moves for efficiency
154
+ if len(past_moves) >= 6 and len(past_moves) % 10 == 0:
155
  model = train_lstm_model(past_moves)
156
 
157
+ return f"**Your choice:** {player_choice}\n\n" \
158
+ f"**Computer choice:** {computer_choice}\n\n" \
159
+ f"**Result:** {result}\n\n" \
160
+ f"*Total games played: {len(past_moves)}*"
161
 
162
+ # Create Gradio interface
163
+ with gr.Blocks(title="Rock Paper Scissors AI", theme=gr.themes.Soft()) as demo:
164
+ gr.Markdown("# 🪨 📄 ✂️ Rock Paper Scissors AI")
165
+ gr.Markdown("Play against an AI that learns from your moves and tries to beat you!")
166
+
167
+ with gr.Row():
168
+ with gr.Column(scale=1):
169
+ move_input = gr.Radio(
170
+ choices=["rock", "paper", "scissors"],
171
+ label="Choose your move",
172
+ value="rock"
173
+ )
174
+ submit_btn = gr.Button("Play!", variant="primary")
175
+
176
+ with gr.Column(scale=2):
177
+ output = gr.Markdown("## Game will start here...")
178
+
179
+ submit_btn.click(
180
+ fn=play_game,
181
+ inputs=move_input,
182
+ outputs=output
183
+ )
184
+
185
+ gr.Markdown("### How it works:")
186
+ gr.Markdown("""
187
+ 1. The AI uses an LSTM neural network to learn from your move patterns
188
+ 2. It predicts your next move based on your last 5 moves
189
+ 3. It counters your predicted move to try to win
190
+ 4. The model improves as you play more games
191
+ """)
192
 
193
  if __name__ == "__main__":
194
+ demo.launch(debug=False, show_error=True)