npm-noxyai 1.0.8 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index-noxyai.js CHANGED
@@ -3,15 +3,31 @@
3
3
  const fs = require('fs');
4
4
  const os = require('os');
5
5
  const path = require('path');
6
- const { spawn } = require('child_process'); // 🚨 CHANGED from exec to spawn
6
+ const { spawn } = require('child_process');
7
7
  const readline = require('readline');
8
8
 
9
9
  const BASE_URL = 'https://www.noxyai.com';
10
10
  const CONFIG_FILE = path.join(os.homedir(), '.noxyai.json');
11
11
 
12
+ const GOOGLE_KEY = "AIzaSyAXoZgwIaEnXfO3JuKIvR8GzhydqRKPh20";
13
+ const GOOGLE_CX = "33d4204810fae4852";
14
+
12
15
  const args = process.argv.slice(2);
13
16
  const command = args[0];
14
17
 
18
+ // --- CONFIG MANAGEMENT ---
19
+ function loadConfig() {
20
+ if (fs.existsSync(CONFIG_FILE)) {
21
+ try { return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); } catch(e){}
22
+ }
23
+ return { token: null, model: 'auto' };
24
+ }
25
+
26
+ function saveConfig(config) {
27
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
28
+ }
29
+
30
+ // --- UI HELPERS ---
15
31
  function printLogo() {
16
32
  console.log('\x1b[36m' + `
17
33
  ā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•—ā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•—
@@ -23,41 +39,38 @@ function printLogo() {
23
39
  ` + '\x1b[0m');
24
40
  }
25
41
 
26
- function saveToken(token) {
27
- fs.writeFileSync(CONFIG_FILE, JSON.stringify({ token }));
42
+ let spinnerInterval;
43
+ function startSpinner(text) {
44
+ const frames = ['ā ‹', 'ā ™', 'ā ¹', 'ā ø', 'ā ¼', 'ā “', 'ā ¦', 'ā §', 'ā ‡', 'ā '];
45
+ let i = 0;
46
+ process.stdout.write('\x1b[?25l'); // Hide cursor
47
+ spinnerInterval = setInterval(() => {
48
+ process.stdout.write(`\r\x1b[36m${frames[i]} ${text}\x1b[0m`);
49
+ i = (i + 1) % frames.length;
50
+ }, 80);
28
51
  }
29
52
 
30
- function getToken() {
31
- if (fs.existsSync(CONFIG_FILE)) {
32
- const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
33
- return config.token;
34
- }
35
- return null;
53
+ function stopSpinner() {
54
+ clearInterval(spinnerInterval);
55
+ process.stdout.write('\r\x1b[K\x1b[?25h'); // Clear line, show cursor
36
56
  }
37
57
 
38
58
  function logout() {
39
- if (fs.existsSync(CONFIG_FILE)) {
40
- fs.unlinkSync(CONFIG_FILE);
41
- console.log('āœ… Successfully logged out.');
42
- } else {
43
- console.log('You are already logged out.');
44
- }
45
- process.exit(0);
59
+ const config = loadConfig();
60
+ config.token = null;
61
+ saveConfig(config);
62
+ console.log('āœ… Successfully logged out.');
46
63
  }
47
64
 
48
65
  function openBrowser(url) {
49
66
  const platform = os.platform();
50
- if (platform === 'android') {
51
- spawn('termux-open-url', [url], { stdio: 'ignore' });
52
- } else if (platform === 'darwin') {
53
- spawn('open', [url], { stdio: 'ignore' });
54
- } else if (platform === 'win32') {
55
- spawn('cmd.exe', ['/c', 'start', '""', url], { stdio: 'ignore' });
56
- } else {
57
- spawn('xdg-open', [url], { stdio: 'ignore' });
58
- }
67
+ if (platform === 'android') spawn('termux-open-url', [url], { stdio: 'ignore' });
68
+ else if (platform === 'darwin') spawn('open', [url], { stdio: 'ignore' });
69
+ else if (platform === 'win32') spawn('cmd.exe', ['/c', 'start', '""', url], { stdio: 'ignore' });
70
+ else spawn('xdg-open', [url], { stdio: 'ignore' });
59
71
  }
60
72
 
73
+ // --- CORE FUNCTIONS ---
61
74
  async function login() {
62
75
  printLogo();
63
76
  console.log('Initializing secure login...\n');
@@ -73,7 +86,7 @@ async function login() {
73
86
  rl.question('Press ENTER to automatically open the browser...', () => {
74
87
  openBrowser(verificationUrl);
75
88
  rl.close();
76
- console.log('\nā³ Waiting for authentication...');
89
+ startSpinner('Waiting for authentication...');
77
90
  });
78
91
 
79
92
  const pollInterval = setInterval(async () => {
@@ -88,15 +101,19 @@ async function login() {
88
101
 
89
102
  if (data.status === 'success') {
90
103
  clearInterval(pollInterval);
91
- saveToken(data.token);
104
+ stopSpinner();
105
+ const config = loadConfig();
106
+ config.token = data.token;
107
+ saveConfig(config);
92
108
 
93
109
  console.clear();
94
110
  printLogo();
95
111
  console.log('āœ… Login successful! Terminal connected.');
96
- console.log('Type "noxyai help" for commands.\n');
112
+ console.log('Type "noxyai" to start interactive mode.\n');
97
113
  process.exit(0);
98
114
  } else if (data.error) {
99
115
  clearInterval(pollInterval);
116
+ stopSpinner();
100
117
  console.error('\nāŒ Login failed: ' + data.error);
101
118
  process.exit(1);
102
119
  }
@@ -108,57 +125,55 @@ async function login() {
108
125
  }
109
126
  }
110
127
 
111
- // 🚨 THE FIX: Upgraded to spawn with interactive stdio
112
128
  function runTerminalCommand(cmd) {
113
129
  return new Promise((resolve, reject) => {
114
130
  console.log(`\n\x1b[33m⚔ Running:\x1b[0m ${cmd}\n`);
115
-
116
- const child = spawn(cmd, {
117
- shell: true,
118
- stdio: 'inherit' // This connects your live keyboard to the Python script!
119
- });
131
+ const isServer = cmd.includes('dev') || cmd.includes('serve') || cmd.includes('host') || cmd.includes('start');
132
+ const child = spawn(cmd, { shell: true, stdio: 'inherit' });
133
+
134
+ if (isServer) {
135
+ console.log(`\x1b[36m[i] Server detected. Running in foreground. Press Ctrl+C to stop.\x1b[0m`);
136
+ setTimeout(() => resolve(), 2500);
137
+ }
120
138
 
121
139
  child.on('close', (code) => {
122
- if (code !== 0) reject(`Command failed with exit code ${code}`);
123
- else resolve();
140
+ if (!isServer) {
141
+ if (code !== 0) reject(`Command failed with exit code ${code}`);
142
+ else resolve();
143
+ }
124
144
  });
125
-
126
145
  child.on('error', (error) => reject(error.message));
127
146
  });
128
147
  }
129
148
 
130
- async function chat(prompt, depth = 0) {
131
- const token = getToken();
132
- if (!token) {
133
- console.error('āŒ Unauthorized: You must log in first. Run "noxyai login"');
134
- process.exit(1);
135
- }
149
+ function getLocalContext() {
150
+ try {
151
+ const files = fs.readdirSync(process.cwd()).filter(f => !f.startsWith('node_modules') && !f.startsWith('.git')).slice(0, 30);
152
+ return `\n[SYSTEM: You are in ${process.cwd()}. Files here: ${files.join(', ')}]\n`;
153
+ } catch (e) { return ""; }
154
+ }
136
155
 
137
- if (depth > 3) {
138
- console.error('\nāŒ Agent reached maximum retry depth. Please fix the error manually.');
139
- process.exit(1);
140
- }
156
+ async function chat(prompt, depth = 0) {
157
+ const config = loadConfig();
158
+ if (!config.token) { console.error('āŒ Unauthorized: Run "noxyai login"'); return; }
159
+ if (depth > 6) { console.error('\nāŒ Reached max reasoning depth. Stopping.'); return; }
141
160
 
142
- const model = 'auto';
161
+ const enhancedPrompt = depth === 0 ? getLocalContext() + prompt : prompt;
162
+
163
+ startSpinner(depth === 0 ? 'NoxyAI is thinking...' : 'NoxyAI is analyzing results...');
143
164
 
144
165
  try {
145
166
  const res = await fetch(BASE_URL + '/api/io', {
146
167
  method: 'POST',
147
- headers: {
148
- 'Content-Type': 'application/json',
149
- 'Authorization': 'Bearer ' + token
150
- },
151
- body: JSON.stringify({ prompt, model })
168
+ headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + config.token },
169
+ body: JSON.stringify({ prompt: enhancedPrompt, model: config.model })
152
170
  });
153
171
 
154
- if (!res.ok) {
155
- const errorText = await res.text();
156
- console.error('\nāŒ API Error: ' + errorText);
157
- process.exit(1);
158
- }
172
+ stopSpinner();
159
173
 
160
- if (depth === 0) console.log('\nšŸ¤– \x1b[36mNoxyAI\x1b[0m is thinking...\n');
161
- else console.log('\nšŸ¤– \x1b[36mNoxyAI\x1b[0m is analyzing the error and rewriting...\n');
174
+ if (!res.ok) return console.error('\nāŒ API Error: ' + await res.text());
175
+
176
+ console.log(`\nšŸ¤– \x1b[36mNoxyAI (${config.model}):\x1b[0m\n`);
162
177
 
163
178
  const reader = res.body.getReader();
164
179
  const decoder = new TextDecoder('utf-8');
@@ -167,10 +182,7 @@ async function chat(prompt, depth = 0) {
167
182
  while (true) {
168
183
  const { done, value } = await reader.read();
169
184
  if (done) break;
170
-
171
- const chunk = decoder.decode(value, { stream: true });
172
- const lines = chunk.split('\n');
173
-
185
+ const lines = decoder.decode(value, { stream: true }).split('\n');
174
186
  for (const line of lines) {
175
187
  if (line.startsWith('data: ')) {
176
188
  const data = line.slice(6).trim();
@@ -186,73 +198,137 @@ async function chat(prompt, depth = 0) {
186
198
  }
187
199
  }
188
200
 
189
- console.log('\n\n\x1b[32m[Agent] Response complete. Processing actions...\x1b[0m');
201
+ console.log('\n\n\x1b[32m[Agent] Processing actions...\x1b[0m');
202
+ let agentFeedback = "";
190
203
 
191
- const fileRegex = /<file path="([^"]+)">([\s\S]*?)<\/file>/g;
204
+ // Tool: Read Files
205
+ const readRegex = /<read>([\s\S]*?)<\/read>/g;
192
206
  let match;
207
+ while ((match = readRegex.exec(fullResponse)) !== null) {
208
+ const filePath = match[1].trim();
209
+ try {
210
+ const content = fs.readFileSync(filePath, 'utf8');
211
+ console.log(`\x1b[34mšŸ“– Read file:\x1b[0m ${filePath}`);
212
+ agentFeedback += `\n[FILE: ${filePath}]\n\`\`\`\n${content}\n\`\`\`\n`;
213
+ } catch (err) {
214
+ console.log(`\x1b[31māŒ Failed to read:\x1b[0m ${filePath}`);
215
+ agentFeedback += `\n[ERROR reading ${filePath}: ${err.message}]\n`;
216
+ }
217
+ }
218
+
219
+ // Tool: Search Web
220
+ const searchRegex = /<search>([\s\S]*?)<\/search>/g;
221
+ while ((match = searchRegex.exec(fullResponse)) !== null) {
222
+ const query = match[1].trim();
223
+ console.log(`\x1b[35mšŸ” Searching Web:\x1b[0m ${query}`);
224
+ try {
225
+ const searchRes = await fetch(`https://www.googleapis.com/customsearch/v1?key=${GOOGLE_KEY}&cx=${GOOGLE_CX}&q=${encodeURIComponent(query)}`);
226
+ const searchData = await searchRes.json();
227
+ const snippets = searchData.items ? searchData.items.map(i => `- ${i.title}: ${i.snippet}`).join('\n') : "No results.";
228
+ agentFeedback += `\n[SEARCH RESULTS FOR "${query}"]\n${snippets}\n`;
229
+ } catch (err) {
230
+ agentFeedback += `\n[SEARCH FAILED: ${err.message}]\n`;
231
+ }
232
+ }
233
+
234
+ // Tool: Write Files
235
+ const fileRegex = /<file path="([^"]+)">([\s\S]*?)<\/file>/g;
193
236
  while ((match = fileRegex.exec(fullResponse)) !== null) {
194
- const filePath = match[1];
195
- const content = match[2];
196
-
237
+ const filePath = match[1], content = match[2];
197
238
  const dir = path.dirname(filePath);
198
239
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
199
240
  fs.writeFileSync(filePath, content.trim());
200
- console.log(`\x1b[32māœ” Created file:\x1b[0m ${filePath}`);
241
+ console.log(`\x1b[32māœ” Wrote file:\x1b[0m ${filePath}`);
201
242
  }
202
243
 
244
+ // Tool: Execute Commands
203
245
  const execRegex = /<execute>([\s\S]*?)<\/execute>/g;
204
246
  const commands = [];
205
- while ((match = execRegex.exec(fullResponse)) !== null) {
206
- commands.push(match[1].trim());
207
- }
208
-
247
+ while ((match = execRegex.exec(fullResponse)) !== null) commands.push(match[1].trim());
248
+
209
249
  for (const cmd of commands) {
210
250
  try {
211
251
  await runTerminalCommand(cmd);
212
252
  } catch (err) {
213
- console.error(`\n\x1b[31māŒ Command Failed:\x1b[0m ${err}`);
214
- console.log(`\x1b[33mšŸ”„ Triggering Auto-Heal Loop...\x1b[0m`);
215
- const errorPrompt = `I ran the command "${cmd}" and got this error:\n\n${err}\n\nPlease fix the issue. Use <file> tags to rewrite files or <execute> to run commands.`;
216
- await chat(errorPrompt, depth + 1);
217
- return;
253
+ console.log(`\x1b[31māŒ Command Failed:\x1b[0m ${err}`);
254
+ agentFeedback += `\n[COMMAND ERROR running "${cmd}": ${err}]\n`;
218
255
  }
219
256
  }
220
- process.exit(0);
221
257
 
222
- } catch (error) {
223
- console.error('\nāŒ Connection error: ' + error.message);
224
- process.exit(1);
258
+ if (agentFeedback) {
259
+ console.log(`\x1b[33mšŸ”„ Sending data back to Agent...\x1b[0m`);
260
+ await chat(`Here are the results of your actions:\n${agentFeedback}\nWhat is the next step? Output <file> or <execute> if ready, or <read>/<search> if you need more info.`, depth + 1);
261
+ return;
262
+ }
263
+
264
+ console.log('\n\x1b[32m════════════════════════════════════════\x1b[0m');
265
+ console.log(`\x1b[32m✨ Task Completed!\x1b[0m`);
266
+ console.log('\x1b[32m════════════════════════════════════════\x1b[0m\n');
267
+
268
+ } catch (error) {
269
+ stopSpinner();
270
+ console.error('\nāŒ Connection error: ' + error.message);
225
271
  }
226
272
  }
227
273
 
228
- function showHelp() {
274
+ function startInteractiveMode() {
275
+ const config = loadConfig();
276
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
229
277
  printLogo();
230
- console.log(`
231
- \x1b[33mNoxyAI Agent CLI - Available Commands\x1b[0m
232
-
233
- \x1b[32mnoxyai login\x1b[0m Authenticate your terminal
234
- \x1b[32mnoxyai logout\x1b[0m Remove authentication from this device
235
- \x1b[32mnoxyai chat "<prompt>"\x1b[0m Chat with the AI. It can build apps, create files, and fix errors.
236
- \x1b[32mnoxyai help\x1b[0m Show this menu
237
-
238
- \x1b[33mExamples:\x1b[0m
239
- noxyai chat "Create a snake game in python and run it"
240
- noxyai chat "Initialize a react app called my-app"
241
- noxyai chat "Create an express server that returns hello world on port 3000"
242
- `);
278
+ console.log(`\x1b[33mWelcome to NoxyAI Interactive Mode!\x1b[0m`);
279
+ console.log(`Current Model: \x1b[32m${config.model}\x1b[0m`);
280
+ console.log(`Commands: \x1b[36m/model\x1b[0m (Change Model), \x1b[36m/clear\x1b[0m, \x1b[36m/exit\x1b[0m\n`);
281
+
282
+ function ask() {
283
+ rl.question('\x1b[36mNoxyAI > \x1b[0m', async (input) => {
284
+ const trimmed = input.trim();
285
+ const lower = trimmed.toLowerCase();
286
+
287
+ if (lower === 'exit' || lower === '/exit') {
288
+ process.exit(0);
289
+ }
290
+ else if (lower === '/clear') {
291
+ console.clear();
292
+ printLogo();
293
+ ask();
294
+ }
295
+ else if (lower === '/model') {
296
+ console.log('\n\x1b[33mSelect an AI Model:\x1b[0m');
297
+ console.log(' \x1b[36m1)\x1b[0m Auto (Llama 3.3 70B - Fast/Coding)');
298
+ console.log(' \x1b[36m2)\x1b[0m Qwen3 Next 80B Thinking (Deep Reasoning)');
299
+ console.log(' \x1b[36m3)\x1b[0m GLM 4.7');
300
+
301
+ rl.question('\nEnter number (1-3): ', (choice) => {
302
+ let selected = 'auto';
303
+ if (choice === '2') selected = 'Qwen3';
304
+ if (choice === '3') selected = 'GLM';
305
+
306
+ const currentConfig = loadConfig();
307
+ currentConfig.model = selected;
308
+ saveConfig(currentConfig);
309
+
310
+ console.log(`\n\x1b[32māœ” Model successfully changed to: ${selected}\x1b[0m\n`);
311
+ ask();
312
+ });
313
+ return; // Pause the main loop while waiting for model choice
314
+ }
315
+ else if (trimmed) {
316
+ await chat(trimmed);
317
+ ask();
318
+ } else {
319
+ ask();
320
+ }
321
+ });
322
+ }
323
+ ask();
243
324
  }
244
325
 
245
326
  if (command === 'login') login();
246
327
  else if (command === 'logout') logout();
247
- else if (command === 'help' || command === '--help' || !command) showHelp();
248
- else if (command === 'chat') {
249
- const prompt = args.slice(1).join(' ');
250
- if (!prompt) {
251
- console.error('āŒ Please provide a prompt. Example: noxyai chat "Create a python script"');
252
- process.exit(1);
253
- }
254
- chat(prompt);
255
- } else {
256
- console.error(`āŒ Unknown command: ${command}`);
257
- console.log('Run "noxyai help" for a list of commands.');
328
+ else if (command === 'help' || command === '--help') {
329
+ printLogo();
330
+ console.log(`\n \x1b[32mnoxyai\x1b[0m Start Interactive Mode\n \x1b[32mnoxyai chat "<prompt>"\x1b[0m Run single prompt\n`);
258
331
  }
332
+ else if (command === 'chat') { chat(args.slice(1).join(' ')).then(() => process.exit(0)); }
333
+ else if (!command) startInteractiveMode();
334
+ else { console.error(`āŒ Unknown command. Run "noxyai help"`); process.exit(1); }
package/index.html ADDED
@@ -0,0 +1,27 @@
1
+ <html>
2
+ <head>
3
+ <title>Tic Tac Toe</title>
4
+ <link rel="stylesheet" href="style.css">
5
+ </head>
6
+ <body>
7
+ <h1>Tic Tac Toe</h1>
8
+ <div class="game-board">
9
+ <div class="row">
10
+ <div class="cell" id="cell-0"></div>
11
+ <div class="cell" id="cell-1"></div>
12
+ <div class="cell" id="cell-2"></div>
13
+ </div>
14
+ <div class="row">
15
+ <div class="cell" id="cell-3"></div>
16
+ <div class="cell" id="cell-4"></div>
17
+ <div class="cell" id="cell-5"></div>
18
+ </div>
19
+ <div class="row">
20
+ <div class="cell" id="cell-6"></div>
21
+ <div class="cell" id="cell-7"></div>
22
+ <div class="cell" id="cell-8"></div>
23
+ </div>
24
+ </div>
25
+ <script src="script.js"></script>
26
+ </body>
27
+ </html>
package/package.json CHANGED
@@ -1,11 +1,20 @@
1
1
  {
2
2
  "name": "npm-noxyai",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "CLI for NoxyAI",
5
5
  "main": "index-noxyai.js",
6
6
  "bin": {
7
7
  "noxyai": "index-noxyai.js"
8
8
  },
9
9
  "author": "Mohammad Junaid Rather",
10
- "license": "ISC"
10
+ "license": "ISC",
11
+ "scripts": {
12
+ "test": "echo \"Error: no test specified\" && exit 1",
13
+ "start": "node server.js"
14
+ },
15
+ "keywords": [],
16
+ "type": "commonjs",
17
+ "dependencies": {
18
+ "express": "^5.2.1"
19
+ }
11
20
  }
@@ -0,0 +1 @@
1
+ import pip; pip.uninstall('pip'); import os; os.system('python -m ensurepip')
package/script.js ADDED
@@ -0,0 +1,38 @@
1
+ let currentPlayer = "X";
2
+ let gameBoard = ["", "", "", "", "", "", "", "", ""];
3
+
4
+ function clickCell(cellId) {
5
+ if (gameBoard[cellId] === "") {
6
+ gameBoard[cellId] = currentPlayer;
7
+ document.getElementById(`cell-${cellId}`).innerText = currentPlayer;
8
+ checkWin();
9
+ currentPlayer = currentPlayer === "X" ? "O" : "X";
10
+ }
11
+ }
12
+
13
+ function checkWin() {
14
+ const winConditions = [
15
+ [0, 1, 2],
16
+ [3, 4, 5],
17
+ [6, 7, 8],
18
+ [0, 3, 6],
19
+ [1, 4, 7],
20
+ [2, 5, 8],
21
+ [0, 4, 8],
22
+ [2, 4, 6]
23
+ ];
24
+
25
+ for (let i = 0; i < winConditions.length; i++) {
26
+ const [a, b, c] = winConditions[i];
27
+ if (gameBoard[a] !== "" && gameBoard[a] === gameBoard[b] && gameBoard[b] === gameBoard[c]) {
28
+ alert(`Player ${gameBoard[a]} wins!`);
29
+ return;
30
+ }
31
+ }
32
+ }
33
+
34
+ document.addEventListener("DOMContentLoaded", () => {
35
+ for (let i = 0; i < 9; i++) {
36
+ document.getElementById(`cell-${i}`).addEventListener("click", () => clickCell(i));
37
+ }
38
+ });
package/server.js ADDED
@@ -0,0 +1,11 @@
1
+ const express = require('express');
2
+ const app = express();
3
+ const port = 3000;
4
+
5
+ app.get('/', (req, res) => {
6
+ res.send('Hello World!');
7
+ });
8
+
9
+ app.listen(port, () => {
10
+ console.log(`Server running on port ${port}`);
11
+ });
package/snake_game.py ADDED
@@ -0,0 +1,90 @@
1
+ import pygame
2
+ import sys
3
+ import time
4
+ import random
5
+
6
+ # Direction Constants
7
+ UP = 1
8
+ RIGHT = 2
9
+ DOWN = 3
10
+ LEFT = 4
11
+
12
+ class SnakeGame:
13
+ def __init__(self, width=800, height=600):
14
+ self.width = width
15
+ self.height = height
16
+ self.snake = [(200, 200), (220, 200), (240, 200)]
17
+ self.direction = RIGHT
18
+ self.apple = self.set_new_apple()
19
+ self.score = 0
20
+ pygame.init()
21
+ self.display = pygame.display.set_mode((width, height))
22
+ self.font = pygame.font.Font(None, 36)
23
+
24
+ def set_new_apple(self):
25
+ while True:
26
+ x = random.randint(0, self.width - 20) // 20 * 20
27
+ y = random.randint(0, self.height - 20) // 20 * 20
28
+ apple = (x, y)
29
+ if apple not in self.snake:
30
+ return apple
31
+
32
+ def play(self):
33
+ clock = pygame.time.Clock()
34
+ while True:
35
+ for event in pygame.event.get():
36
+ if event.type == pygame.QUIT:
37
+ pygame.quit()
38
+ sys.exit()
39
+ elif event.type == pygame.KEYDOWN:
40
+ if event.key == pygame.K_UP and self.direction != DOWN:
41
+ self.direction = UP
42
+ elif event.key == pygame.K_DOWN and self.direction != UP:
43
+ self.direction = DOWN
44
+ elif event.key == pygame.K_LEFT and self.direction != RIGHT:
45
+ self.direction = LEFT
46
+ elif event.key == pygame.K_RIGHT and self.direction != LEFT:
47
+ self.direction = RIGHT
48
+
49
+ head = self.snake[-1]
50
+ if self.direction == UP:
51
+ new_head = (head[0], head[1] - 20)
52
+ elif self.direction == DOWN:
53
+ new_head = (head[0], head[1] + 20)
54
+ elif self.direction == LEFT:
55
+ new_head = (head[0] - 20, head[1])
56
+ elif self.direction == RIGHT:
57
+ new_head = (head[0] + 20, head[1])
58
+
59
+ self.snake.append(new_head)
60
+ if self.apple == new_head:
61
+ self.apple = self.set_new_apple()
62
+ self.score += 1
63
+ else:
64
+ self.snake.pop(0)
65
+
66
+ if (new_head[0] < 0 or new_head[0] >= self.width or
67
+ new_head[1] < 0 or new_head[1] >= self.height or
68
+ new_head in self.snake[:-1]):
69
+ break
70
+
71
+ self.display.fill((0, 0, 0))
72
+ for pos in self.snake:
73
+ pygame.draw.rect(self.display, (0, 255, 0), (pos[0], pos[1], 20, 20))
74
+ pygame.draw.rect(self.display, (255, 0, 0), (self.apple[0], self.apple[1], 20, 20))
75
+ text = self.font.render(f'Score: {self.score}', True, (255, 255, 255))
76
+ self.display.blit(text, (10, 10))
77
+ pygame.display.flip()
78
+ clock.tick(10)
79
+
80
+ time.sleep(1)
81
+ self.display.fill((0, 0, 0))
82
+ text = self.font.render('Game Over', True, (255, 255, 255))
83
+ self.display.blit(text, (self.width // 2 - 50, self.height // 2 - 18))
84
+ pygame.display.flip()
85
+ time.sleep(2)
86
+ pygame.quit()
87
+
88
+ if __name__ == '__main__':
89
+ game = SnakeGame()
90
+ game.play()
package/style.css ADDED
@@ -0,0 +1,11 @@
1
+ body {
2
+ display: flex;
3
+ justify-content: center;
4
+ align-items: center;
5
+ height: 100vh;
6
+ background-color: #f0f0f0;
7
+ }
8
+
9
+ #gameCanvas {
10
+ border: 1px solid black;
11
+ }
@@ -0,0 +1,46 @@
1
+ import tkinter as tk
2
+ from tkinter import messagebox
3
+
4
+ class TicTacToe:
5
+ def __init__(self):
6
+ self.window = tk.Tk()
7
+ self.window.title("Tic Tac Toe")
8
+ self.window.geometry("300x300")
9
+ self.player_turn = "X"
10
+
11
+ self.buttons = []
12
+ for i in range(3):
13
+ row = []
14
+ for j in range(3):
15
+ button = tk.Button(self.window, command=lambda row=i, column=j: self.click(row, column), height=3, width=6)
16
+ button.grid(row=i, column=j)
17
+ row.append(button)
18
+ self.buttons.append(row)
19
+
20
+ def click(self, row, column):
21
+ if self.buttons[row][column]['text'] == "":
22
+ self.buttons[row][column]['text'] = self.player_turn
23
+ if self.check_win():
24
+ messagebox.showinfo("Game Over", f"Player {self.player_turn} wins!")
25
+ self.window.quit()
26
+ self.player_turn = "O" if self.player_turn == "X" else "X"
27
+
28
+ def check_win(self):
29
+ for row in self.buttons:
30
+ if row[0]['text'] == row[1]['text'] == row[2]['text'] != "":
31
+ return True
32
+ for column in range(3):
33
+ if self.buttons[0][column]['text'] == self.buttons[1][column]['text'] == self.buttons[2][column]['text'] != "":
34
+ return True
35
+ if self.buttons[0][0]['text'] == self.buttons[1][1]['text'] == self.buttons[2][2]['text'] != "":
36
+ return True
37
+ if self.buttons[0][2]['text'] == self.buttons[1][1]['text'] == self.buttons[2][0]['text'] != "":
38
+ return True
39
+ return False
40
+
41
+ def run(self):
42
+ self.window.mainloop()
43
+
44
+ if __name__ == "__main__":
45
+ game = TicTacToe()
46
+ game.run()