-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
283 lines (250 loc) · 11.7 KB
/
Copy pathscript.js
File metadata and controls
283 lines (250 loc) · 11.7 KB
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
// DOM Elements
const rockBtn = document.getElementById('rock-btn');
const paperBtn = document.getElementById('paper-btn');
const scissorsBtn = document.getElementById('scissors-btn');
const trainModelBtn = document.getElementById('train-model-btn');
const playGameBtn = document.getElementById('play-game-btn');
const resetModelBtn = document.getElementById('reset-model-btn');
const sampleSizeInput = document.getElementById('sample-size-input');
const playerChoiceElem = document.getElementById('player-choice');
const programChoiceElem = document.getElementById('program-choice');
const gameResultElem = document.getElementById('game-result');
const modelStatusElem = document.getElementById('model-status');
const messageBox = document.getElementById('message-box');
const messageText = document.getElementById('message-text');
const messageOkBtn = document.getElementById('message-ok-btn');
// Game state variables
let lastGameData = null; // Stores { playerMove, programMove, result } for the *last played game* (either training or regular)
let isModelTrained = false;
let isTraining = false; // Flag to indicate if training process is active
let currentTrainingSampleIndex = 0;
let totalTrainingSamples = 0;
let prevTrainingGameData = null; // Stores {playerMove, programMove, result} for the *previous game in the current training session*
// Helper function to convert letter to word
function letterToWord(letter) {
switch (letter) {
case 'r': return "Rock";
case 'p': return "Paper";
case 's': return "Scissors";
case 'w': return "You win!";
case 'l': return "The program wins!";
case 't': return "It's a tie!";
default: return "";
}
}
// Function to show a custom message box
function showMessageBox(message) {
messageText.textContent = message;
messageBox.classList.remove('hidden');
}
// Function to hide the custom message box
function hideMessageBox() {
messageBox.classList.add('hidden');
}
// Function to update UI after a game
function updateGameUI(playerMove, programMove, result) {
playerChoiceElem.textContent = `You chose: ${letterToWord(playerMove)}`;
programChoiceElem.textContent = `Program chose: ${letterToWord(programMove)}`;
gameResultElem.textContent = `Result: ${letterToWord(result)}`;
// Apply color based on result
gameResultElem.classList.remove('win', 'loss', 'tie');
if (result === 'w') {
gameResultElem.classList.add('win');
} else if (result === 'l') {
gameResultElem.classList.add('loss');
} else {
gameResultElem.classList.add('tie');
}
}
// Function to update model status display
function updateModelStatus() {
if (isTraining) {
// Display training progress directly in the model status element
modelStatusElem.textContent = `Model Status: Training in progress... (Sample ${currentTrainingSampleIndex}/${totalTrainingSamples})`;
} else {
modelStatusElem.textContent = isModelTrained ? "Model Status: Trained (AI Active)" : "Model Status: Untrained (Random Play)";
}
}
// Function to enable/disable game buttons
function setGameButtonsEnabled(enabled) {
rockBtn.disabled = !enabled;
paperBtn.disabled = !enabled;
scissorsBtn.disabled = !enabled;
}
// Event listener for player move buttons
document.querySelectorAll('.move-btn').forEach(button => {
button.addEventListener('click', async () => {
const playerMove = button.dataset.move;
let programMove;
let result;
if (isTraining) {
// --- Handle interactive training game ---
setGameButtonsEnabled(false); // Disable buttons while processing
updateModelStatus(); // Update status to show "Processing..."
// Program plays randomly during data collection
const programMoveResponse = await fetch('/play');
programMove = await programMoveResponse.json();
// Evaluate the game
const evaluateResponse = await fetch(`/evaluate?player=${playerMove}&program=${programMove}`);
result = await evaluateResponse.json();
updateGameUI(playerMove, programMove, result);
if (prevTrainingGameData) {
// Send datum to add_datum API
const datum = [
prevTrainingGameData.playerMove,
prevTrainingGameData.programMove,
prevTrainingGameData.result,
playerMove // This is the current player's move
];
try {
await fetch('/add_datum', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(datum)
});
} catch (error) {
console.error("Error adding datum:", error);
showMessageBox(`Error collecting data: ${error.message}. Training aborted.`);
// Abort training on error
isTraining = false;
trainModelBtn.disabled = false;
playGameBtn.disabled = false;
resetModelBtn.disabled = false;
setGameButtonsEnabled(true);
updateModelStatus();
return;
}
}
prevTrainingGameData = { playerMove, programMove, result }; // Store for next iteration
currentTrainingSampleIndex++;
updateModelStatus(); // Update counter in status bar
if (currentTrainingSampleIndex < totalTrainingSamples) {
// Continue with next sample
// No showMessageBox here, as status is in modelStatusElem
setGameButtonsEnabled(true); // Re-enable buttons for next sample
} else {
// All samples collected, now train the model
showMessageBox("All samples collected. Training the neural network...");
try {
const trainResponse = await fetch('/train_model', { method: 'POST' });
if (trainResponse.ok) {
isModelTrained = true;
showMessageBox("Model training complete! You can now play against the AI.");
lastGameData = prevTrainingGameData; // Set last game data from the training end
} else {
const errorText = await trainResponse.text();
showMessageBox(`Model training failed: ${errorText}`);
isModelTrained = false;
}
} catch (error) {
console.error("Error during training:", error);
showMessageBox(`An error occurred during training: ${error.message}`);
isModelTrained = false;
} finally {
isTraining = false;
trainModelBtn.disabled = false;
playGameBtn.disabled = false;
resetModelBtn.disabled = false;
setGameButtonsEnabled(true);
updateModelStatus(); // Final status update
}
}
} else {
// --- Handle regular game play ---
setGameButtonsEnabled(false); // Disable buttons while processing
// Determine program's move
if (isModelTrained && lastGameData) {
try {
// Call predict_move API with last game data
const response = await fetch(`/predict_move?last_player_move=${lastGameData.playerMove}&last_program_move=${lastGameData.programMove}&last_result=${lastGameData.result}`);
programMove = await response.json();
console.log("Program uses AI.");
} catch (error) {
console.error("Error predicting move:", error);
showMessageBox("Error with AI prediction. Playing randomly.");
// Fallback to random if AI prediction fails
const randomResponse = await fetch('/play');
programMove = await randomResponse.json();
}
} else {
// Play randomly if model not trained or no previous game data
const response = await fetch('/play');
programMove = await response.json();
console.log("Program plays randomly.");
}
// Evaluate the game
const evaluateResponse = await fetch(`/evaluate?player=${playerMove}&program=${programMove}`);
result = await evaluateResponse.json();
updateGameUI(playerMove, programMove, result);
// Update lastGameData for the next AI prediction
lastGameData = { playerMove, programMove, result };
setGameButtonsEnabled(true); // Re-enable buttons after game
}
});
});
// Event listener for Train New Model button
trainModelBtn.addEventListener('click', async () => {
if (isTraining) {
showMessageBox("Training is already in progress. Please wait.");
return;
}
totalTrainingSamples = parseInt(sampleSizeInput.value);
if (isNaN(totalTrainingSamples) || totalTrainingSamples < 1) {
showMessageBox("Please enter a valid number of samples (minimum 1).");
return;
}
// Reset model first
try {
await fetch('/reset', { method: 'POST' });
isModelTrained = false;
lastGameData = null; // Clear last game data
prevTrainingGameData = null; // Clear training-specific previous data
updateGameUI('-', '-', '-'); // Clear previous game results
} catch (error) {
console.error("Error resetting model before training:", error);
showMessageBox(`Error resetting model: ${error.message}. Training cannot start.`);
return;
}
isTraining = true;
currentTrainingSampleIndex = 0;
// Disable control buttons during interactive training
trainModelBtn.disabled = true;
playGameBtn.disabled = true;
resetModelBtn.disabled = true;
// Enable game buttons for player input
setGameButtonsEnabled(true);
showMessageBox(`Starting interactive training with ${totalTrainingSamples} samples.`);
updateModelStatus(); // Update status to show training is starting
});
// Event listener for Play Game button (just a visual cue, actual play is via move buttons)
playGameBtn.addEventListener('click', () => {
if (isTraining) {
showMessageBox("Please wait for the training process to complete.");
return;
}
showMessageBox("Choose your move (Rock, Paper, or Scissors) to play a game!");
});
// Event listener for Reset Model button
resetModelBtn.addEventListener('click', async () => {
if (isTraining) {
showMessageBox("Please wait for the training process to complete.");
return;
}
try {
await fetch('/reset', { method: 'POST' });
isModelTrained = false;
lastGameData = null; // Clear last game data
prevTrainingGameData = null; // Clear training-specific previous data
updateModelStatus();
updateGameUI('-', '-', '-'); // Clear previous game results
showMessageBox("Model has been reset. Program will now play randomly.");
} catch (error) {
console.error("Error resetting model:", error);
showMessageBox(`An error occurred while resetting the model: ${error.message}`);
}
});
// Event listener for message box OK button
messageOkBtn.addEventListener('click', hideMessageBox);
// Initial status update and enable buttons if not in play mode
updateModelStatus();
setGameButtonsEnabled(true); // Initially enable for first random game or training start