zshashz commited on
Commit
4a9fc22
·
1 Parent(s): f75003b
Files changed (2) hide show
  1. .gitignore +1 -0
  2. index.html +176 -80
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ *_s.js
index.html CHANGED
@@ -3,17 +3,23 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Shy Guy Simulator - AI Edition</title>
7
  <style>
8
  body {
9
  font-family: Arial, sans-serif;
10
- max-width: 800px;
11
  margin: 20px auto;
12
  padding: 20px;
13
  background-color: #1a1a1a;
14
  color: #fff;
15
  }
16
 
 
 
 
 
 
 
17
  #game-container {
18
  background-color: #2a2a2a;
19
  padding: 20px;
@@ -21,10 +27,29 @@
21
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
22
  }
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  .chat-container {
25
  height: 400px;
26
  overflow-y: auto;
27
- margin: 20px 0;
28
  padding: 10px;
29
  background-color: #333;
30
  border-radius: 4px;
@@ -37,20 +62,9 @@
37
  word-wrap: break-word;
38
  }
39
 
40
- .wingman {
41
- background-color: #2c5282;
42
- margin-right: 20%;
43
- }
44
-
45
- .shyguy {
46
- background-color: #4a5568;
47
- margin-left: 20%;
48
- }
49
-
50
- .error {
51
- background-color: #c53030;
52
- text-align: center;
53
- }
54
 
55
  #input-container {
56
  display: flex;
@@ -76,22 +90,18 @@
76
  cursor: pointer;
77
  }
78
 
79
- button:hover {
80
- background-color: #3182ce;
 
 
 
81
  }
82
 
83
- #stats {
84
- margin-top: 20px;
85
- padding: 10px;
86
  background-color: #333;
 
87
  border-radius: 4px;
88
- display: flex;
89
- justify-content: space-between;
90
- }
91
-
92
- .typing {
93
- font-style: italic;
94
- color: #718096;
95
  }
96
 
97
  #api-key-container {
@@ -101,7 +111,7 @@
101
  </head>
102
  <body>
103
  <div id="game-container">
104
- <h1>Shy Guy Simulator - AI Edition</h1>
105
 
106
  <div id="api-key-container">
107
  <input type="password" id="api-key" placeholder="Enter your Mistral API key" style="width: 100%; padding: 10px; margin-bottom: 10px;">
@@ -110,51 +120,98 @@
110
 
111
  <div id="game-content" style="display: none;">
112
  <div id="stats">
113
- <span>Confidence: <span id="confidence">0</span>%</span>
114
- <span>Anxiety: <span id="anxiety">100</span>%</span>
115
- <span>Time: <span id="time">8:00 PM</span></span>
116
  </div>
117
- <div class="chat-container" id="chat-container"></div>
118
- <div id="input-container">
119
- <input type="text" id="user-input" placeholder="Type your encouragement as wingman...">
120
- <button onclick="handleUserInput()">Send</button>
 
 
 
 
 
 
121
  </div>
122
  </div>
123
  </div>
124
 
125
  <script>
126
- let game;
127
-
128
  class ShyGuySimulator {
129
  constructor(apiKey) {
130
  this.apiKey = apiKey;
131
  this.state = {
132
  confidence: 0,
133
- anxiety: 100,
134
  time: new Date(2024, 0, 1, 20, 0),
135
- location: 'entrance',
136
- hasSpokenToGirl: false,
137
  isProcessing: false
138
  };
139
 
140
- this.context = [
 
 
 
 
 
 
 
 
141
  {
142
- role: 'system',
143
- content: `You are roleplaying as a shy and anxious guy at a homecoming party.
144
- You're standing near the entrance, and the girl you like is across the room.
145
- Your responses should reflect your social anxiety and reluctance to approach her.
146
- Keep responses concise (max 2-3 sentences) and natural.
147
- Express hesitation, worry, and self-doubt while reacting to the wingman's encouragement.`
148
  }
149
- ];
 
 
 
 
 
 
150
 
151
  this.initialize();
152
  }
153
 
154
  initialize() {
155
- this.addMessage("Hey! I'll be your wingman tonight. I see that girl you like over there - let's help you talk to her!", 'wingman');
 
156
  this.addMessage("I... I don't know about this. Maybe I should just go home...", 'shyguy');
157
  this.updateStats();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  }
159
 
160
  async handleInput(userInput) {
@@ -167,7 +224,11 @@
167
  this.addMessage(userInput, 'wingman');
168
  this.addLoadingMessage();
169
 
170
- const currentState = `Current confidence: ${this.state.confidence}%, anxiety: ${this.state.anxiety}%, location: ${this.state.location}`;
 
 
 
 
171
 
172
  this.context.push({
173
  role: 'user',
@@ -177,9 +238,7 @@
177
  const response = await this.callMistralAPI();
178
 
179
  this.removeLoadingMessage();
180
- this.addMessage(response, 'shyguy');
181
-
182
- this.updateGameState(response);
183
 
184
  this.context.push({
185
  role: 'assistant',
@@ -201,6 +260,59 @@
201
  }
202
  }
203
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  async callMistralAPI() {
205
  try {
206
  const response = await fetch('https://api.mistral.ai/v1/chat/completions', {
@@ -232,31 +344,6 @@
232
  }
233
  }
234
 
235
- updateGameState(response) {
236
- const lowerResponse = response.toLowerCase();
237
-
238
- // Update confidence
239
- if (lowerResponse.includes('okay') || lowerResponse.includes('maybe') || lowerResponse.includes('right')) {
240
- this.state.confidence = Math.min(100, this.state.confidence + 10);
241
- this.state.anxiety = Math.max(0, this.state.anxiety - 5);
242
- } else if (lowerResponse.includes('no') || lowerResponse.includes('can\'t') || lowerResponse.includes('scared')) {
243
- this.state.confidence = Math.max(0, this.state.confidence - 5);
244
- this.state.anxiety = Math.min(100, this.state.anxiety + 10);
245
- }
246
-
247
- // Advance time
248
- this.state.time = new Date(this.state.time.getTime() + 5 * 60000);
249
-
250
- this.updateStats();
251
- }
252
-
253
- updateStats() {
254
- document.getElementById('confidence').textContent = this.state.confidence;
255
- document.getElementById('anxiety').textContent = this.state.anxiety;
256
- document.getElementById('time').textContent =
257
- this.state.time.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' });
258
- }
259
-
260
  addMessage(text, type) {
261
  const chat = document.getElementById('chat-container');
262
  const messageDiv = document.createElement('div');
@@ -282,8 +369,17 @@
282
  loadingMessage.remove();
283
  }
284
  }
 
 
 
 
 
 
 
285
  }
286
 
 
 
287
  function initializeGame() {
288
  const apiKey = document.getElementById('api-key').value.trim();
289
  if (!apiKey) {
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Shy Guy Simulator - Grid Edition</title>
7
  <style>
8
  body {
9
  font-family: Arial, sans-serif;
10
+ max-width: 1200px;
11
  margin: 20px auto;
12
  padding: 20px;
13
  background-color: #1a1a1a;
14
  color: #fff;
15
  }
16
 
17
+ .game-layout {
18
+ display: grid;
19
+ grid-template-columns: 1fr 400px;
20
+ gap: 20px;
21
+ }
22
+
23
  #game-container {
24
  background-color: #2a2a2a;
25
  padding: 20px;
 
27
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
28
  }
29
 
30
+ .grid-container {
31
+ display: grid;
32
+ grid-template-columns: repeat(8, 1fr);
33
+ gap: 2px;
34
+ background-color: #333;
35
+ padding: 10px;
36
+ border-radius: 4px;
37
+ margin-bottom: 20px;
38
+ }
39
+
40
+ .grid-cell {
41
+ aspect-ratio: 1;
42
+ background-color: #4a4a4a;
43
+ border-radius: 2px;
44
+ display: flex;
45
+ align-items: center;
46
+ justify-content: center;
47
+ font-size: 20px;
48
+ }
49
+
50
  .chat-container {
51
  height: 400px;
52
  overflow-y: auto;
 
53
  padding: 10px;
54
  background-color: #333;
55
  border-radius: 4px;
 
62
  word-wrap: break-word;
63
  }
64
 
65
+ .wingman { background-color: #2c5282; margin-right: 20%; }
66
+ .shyguy { background-color: #4a5568; margin-left: 20%; }
67
+ .error { background-color: #c53030; text-align: center; }
 
 
 
 
 
 
 
 
 
 
 
68
 
69
  #input-container {
70
  display: flex;
 
90
  cursor: pointer;
91
  }
92
 
93
+ #stats {
94
+ display: grid;
95
+ grid-template-columns: repeat(3, 1fr);
96
+ gap: 10px;
97
+ margin-bottom: 20px;
98
  }
99
 
100
+ .stat-box {
 
 
101
  background-color: #333;
102
+ padding: 10px;
103
  border-radius: 4px;
104
+ text-align: center;
 
 
 
 
 
 
105
  }
106
 
107
  #api-key-container {
 
111
  </head>
112
  <body>
113
  <div id="game-container">
114
+ <h1>Shy Guy Simulator - Grid Edition</h1>
115
 
116
  <div id="api-key-container">
117
  <input type="password" id="api-key" placeholder="Enter your Mistral API key" style="width: 100%; padding: 10px; margin-bottom: 10px;">
 
120
 
121
  <div id="game-content" style="display: none;">
122
  <div id="stats">
123
+ <div class="stat-box">Confidence: <span id="confidence">0</span>%</div>
124
+ <div class="stat-box">Drinks: <span id="drinks">0</span></div>
125
+ <div class="stat-box">Time: <span id="time">8:00 PM</span></div>
126
  </div>
127
+
128
+ <div class="game-layout">
129
+ <div class="grid-container" id="grid"></div>
130
+ <div class="chat-section">
131
+ <div class="chat-container" id="chat-container"></div>
132
+ <div id="input-container">
133
+ <input type="text" id="user-input" placeholder="Type your encouragement as wingman...">
134
+ <button onclick="handleUserInput()">Send</button>
135
+ </div>
136
+ </div>
137
  </div>
138
  </div>
139
  </div>
140
 
141
  <script>
 
 
142
  class ShyGuySimulator {
143
  constructor(apiKey) {
144
  this.apiKey = apiKey;
145
  this.state = {
146
  confidence: 0,
147
+ drinks: 0,
148
  time: new Date(2024, 0, 1, 20, 0),
149
+ position: { x: 0, y: 0 }, // Start at top-left
 
150
  isProcessing: false
151
  };
152
 
153
+ this.targetPosition = { x: 7, y: 7 }; // Girl's position (bottom-right)
154
+ this.gridSize = 8;
155
+
156
+ // System prompt that instructs the model to return structured responses
157
+ this.context = [{
158
+ role: 'system',
159
+ content: `You are roleplaying as a shy guy at a party, providing both dialogue and movement decisions.
160
+ The party is on an 8x8 grid. You start at (0,0), and the girl you like is at (7,7).
161
+ ALWAYS structure your responses in this exact format:
162
  {
163
+ "dialogue": "Your spoken response here",
164
+ "movement": {
165
+ "x": number (-1, 0, or 1 for movement),
166
+ "y": number (-1, 0, or 1 for movement)
167
+ },
168
+ "emotion": "anxious|nervous|slightly_confident|confident"
169
  }
170
+
171
+ Rules:
172
+ 1. When drinks > 2, be more likely to move toward the girl
173
+ 2. When confidence < 30, prefer to move away or stay still
174
+ 3. Keep dialogue natural and brief (1-2 sentences)
175
+ 4. Movement should reflect emotional state`
176
+ }];
177
 
178
  this.initialize();
179
  }
180
 
181
  initialize() {
182
+ this.setupGrid();
183
+ this.addMessage("Let's help you talk to her! I'll be your wingman tonight.", 'wingman');
184
  this.addMessage("I... I don't know about this. Maybe I should just go home...", 'shyguy');
185
  this.updateStats();
186
+ this.updateGrid();
187
+ }
188
+
189
+ setupGrid() {
190
+ const grid = document.getElementById('grid');
191
+ grid.innerHTML = '';
192
+ for (let y = 0; y < this.gridSize; y++) {
193
+ for (let x = 0; x < this.gridSize; x++) {
194
+ const cell = document.createElement('div');
195
+ cell.className = 'grid-cell';
196
+ cell.id = `cell-${x}-${y}`;
197
+ grid.appendChild(cell);
198
+ }
199
+ }
200
+ }
201
+
202
+ updateGrid() {
203
+ // Clear all cells
204
+ document.querySelectorAll('.grid-cell').forEach(cell => {
205
+ cell.textContent = '';
206
+ });
207
+
208
+ // Place shy guy
209
+ const shyGuyCell = document.getElementById(`cell-${this.state.position.x}-${this.state.position.y}`);
210
+ if (shyGuyCell) shyGuyCell.textContent = '😳';
211
+
212
+ // Place girl
213
+ const girlCell = document.getElementById(`cell-${this.targetPosition.x}-${this.targetPosition.y}`);
214
+ if (girlCell) girlCell.textContent = '👧';
215
  }
216
 
217
  async handleInput(userInput) {
 
224
  this.addMessage(userInput, 'wingman');
225
  this.addLoadingMessage();
226
 
227
+ const currentState = `Current state:
228
+ - Confidence: ${this.state.confidence}%
229
+ - Drinks: ${this.state.drinks}
230
+ - Position: (${this.state.position.x}, ${this.state.position.y})
231
+ - Distance to girl: ${this.calculateDistance()}`;
232
 
233
  this.context.push({
234
  role: 'user',
 
238
  const response = await this.callMistralAPI();
239
 
240
  this.removeLoadingMessage();
241
+ this.processAIResponse(response);
 
 
242
 
243
  this.context.push({
244
  role: 'assistant',
 
260
  }
261
  }
262
 
263
+ calculateDistance() {
264
+ const dx = this.targetPosition.x - this.state.position.x;
265
+ const dy = this.targetPosition.y - this.state.position.y;
266
+ return Math.sqrt(dx * dx + dy * dy);
267
+ }
268
+
269
+ processAIResponse(responseText) {
270
+ try {
271
+ // Extract JSON from response if it's wrapped in text
272
+ const jsonMatch = responseText.match(/\{[\s\S]*\}/);
273
+ const responseData = jsonMatch ? JSON.parse(jsonMatch[0]) : JSON.parse(responseText);
274
+
275
+ // Add the dialogue to chat
276
+ this.addMessage(responseData.dialogue, 'shyguy');
277
+
278
+ // Update position
279
+ const newX = Math.max(0, Math.min(7, this.state.position.x + responseData.movement.x));
280
+ const newY = Math.max(0, Math.min(7, this.state.position.y + responseData.movement.y));
281
+ this.state.position = { x: newX, y: newY };
282
+
283
+ // Update confidence based on emotion
284
+ const emotionConfidenceMap = {
285
+ 'anxious': -5,
286
+ 'nervous': 0,
287
+ 'slightly_confident': 5,
288
+ 'confident': 10
289
+ };
290
+ this.state.confidence = Math.max(0, Math.min(100,
291
+ this.state.confidence + (emotionConfidenceMap[responseData.emotion] || 0)
292
+ ));
293
+
294
+ // Update the grid and stats
295
+ this.updateGrid();
296
+ this.updateStats();
297
+
298
+ // Check win condition
299
+ if (this.state.position.x === this.targetPosition.x &&
300
+ this.state.position.y === this.targetPosition.y) {
301
+ this.handleWin();
302
+ }
303
+ } catch (error) {
304
+ console.error('Error processing AI response:', error);
305
+ this.addMessage("I... uh... *mumbles something incoherent*", 'shyguy');
306
+ }
307
+ }
308
+
309
+ handleWin() {
310
+ this.addMessage("Oh my god, I actually made it! Hi... I've been wanting to talk to you...", 'shyguy');
311
+ this.addMessage("Congratulations! You've helped Shy Guy reach his goal!", 'wingman');
312
+ // Disable input
313
+ document.getElementById('user-input').disabled = true;
314
+ }
315
+
316
  async callMistralAPI() {
317
  try {
318
  const response = await fetch('https://api.mistral.ai/v1/chat/completions', {
 
344
  }
345
  }
346
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
  addMessage(text, type) {
348
  const chat = document.getElementById('chat-container');
349
  const messageDiv = document.createElement('div');
 
369
  loadingMessage.remove();
370
  }
371
  }
372
+
373
+ updateStats() {
374
+ document.getElementById('confidence').textContent = this.state.confidence;
375
+ document.getElementById('drinks').textContent = this.state.drinks;
376
+ document.getElementById('time').textContent =
377
+ this.state.time.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' });
378
+ }
379
  }
380
 
381
+ let game;
382
+
383
  function initializeGame() {
384
  const apiKey = document.getElementById('api-key').value.trim();
385
  if (!apiKey) {