npm-noxyai 1.0.10 → 1.0.12
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 +135 -33
- package/package.json +3 -2
- package/index.html +0 -27
- package/reinstall_pip.py +0 -1
- package/script.js +0 -38
- package/server.js +0 -11
- package/snake_game.py +0 -90
- package/style.css +0 -11
- package/tic_tac_toe.py +0 -111
- package/tic_tac_toe_local.py +0 -46
package/index-noxyai.js
CHANGED
|
@@ -9,18 +9,23 @@ const readline = require('readline');
|
|
|
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
|
-
|
|
15
12
|
const args = process.argv.slice(2);
|
|
16
13
|
const command = args[0];
|
|
17
14
|
|
|
18
15
|
// --- CONFIG MANAGEMENT ---
|
|
19
16
|
function loadConfig() {
|
|
20
17
|
if (fs.existsSync(CONFIG_FILE)) {
|
|
21
|
-
try {
|
|
18
|
+
try {
|
|
19
|
+
const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
20
|
+
if (config.agentMode === undefined) config.agentMode = true;
|
|
21
|
+
return config;
|
|
22
|
+
} catch(e) {}
|
|
22
23
|
}
|
|
23
|
-
return {
|
|
24
|
+
return {
|
|
25
|
+
token: null,
|
|
26
|
+
model: 'auto',
|
|
27
|
+
agentMode: true
|
|
28
|
+
};
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
function saveConfig(config) {
|
|
@@ -43,7 +48,7 @@ let spinnerInterval;
|
|
|
43
48
|
function startSpinner(text) {
|
|
44
49
|
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
45
50
|
let i = 0;
|
|
46
|
-
process.stdout.write('\x1b[?25l');
|
|
51
|
+
process.stdout.write('\x1b[?25l');
|
|
47
52
|
spinnerInterval = setInterval(() => {
|
|
48
53
|
process.stdout.write(`\r\x1b[36m${frames[i]} ${text}\x1b[0m`);
|
|
49
54
|
i = (i + 1) % frames.length;
|
|
@@ -52,7 +57,7 @@ function startSpinner(text) {
|
|
|
52
57
|
|
|
53
58
|
function stopSpinner() {
|
|
54
59
|
clearInterval(spinnerInterval);
|
|
55
|
-
process.stdout.write('\r\x1b[K\x1b[?25h');
|
|
60
|
+
process.stdout.write('\r\x1b[K\x1b[?25h');
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
function logout() {
|
|
@@ -70,6 +75,20 @@ function openBrowser(url) {
|
|
|
70
75
|
else spawn('xdg-open', [url], { stdio: 'ignore' });
|
|
71
76
|
}
|
|
72
77
|
|
|
78
|
+
// --- SEARCH FUNCTION ---
|
|
79
|
+
async function searchWeb(query) {
|
|
80
|
+
try {
|
|
81
|
+
const config = loadConfig();
|
|
82
|
+
const res = await fetch(`${BASE_URL}/api/io?action=search&q=${encodeURIComponent(query)}`, {
|
|
83
|
+
headers: { 'Authorization': 'Bearer ' + config.token }
|
|
84
|
+
});
|
|
85
|
+
const data = await res.json();
|
|
86
|
+
return data;
|
|
87
|
+
} catch (err) {
|
|
88
|
+
return { error: err.message };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
73
92
|
// --- CORE FUNCTIONS ---
|
|
74
93
|
async function login() {
|
|
75
94
|
printLogo();
|
|
@@ -132,7 +151,7 @@ function runTerminalCommand(cmd) {
|
|
|
132
151
|
const child = spawn(cmd, { shell: true, stdio: 'inherit' });
|
|
133
152
|
|
|
134
153
|
if (isServer) {
|
|
135
|
-
console.log(`\x1b[36m[i] Server detected. Running in foreground. Press Ctrl+C to stop.\x1b[0m`);
|
|
154
|
+
console.log(`\n\x1b[36m[i] Server detected. Running in foreground. Press Ctrl+C to stop.\x1b[0m`);
|
|
136
155
|
setTimeout(() => resolve(), 2500);
|
|
137
156
|
}
|
|
138
157
|
|
|
@@ -166,38 +185,72 @@ async function chat(prompt, depth = 0) {
|
|
|
166
185
|
const res = await fetch(BASE_URL + '/api/io', {
|
|
167
186
|
method: 'POST',
|
|
168
187
|
headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + config.token },
|
|
169
|
-
body: JSON.stringify({
|
|
188
|
+
body: JSON.stringify({
|
|
189
|
+
prompt: enhancedPrompt,
|
|
190
|
+
model: config.model,
|
|
191
|
+
agentMode: config.agentMode
|
|
192
|
+
})
|
|
170
193
|
});
|
|
171
194
|
|
|
172
195
|
stopSpinner();
|
|
173
196
|
|
|
174
|
-
if (!res.ok)
|
|
197
|
+
if (!res.ok) {
|
|
198
|
+
const errorText = await res.text();
|
|
199
|
+
if (res.status === 402) {
|
|
200
|
+
console.log('\n\x1b[31m' + errorText + '\x1b[0m');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
return console.error('\n❌ API Error: ' + errorText);
|
|
204
|
+
}
|
|
175
205
|
|
|
176
|
-
|
|
206
|
+
const modelDisplay = config.model === 'auto' ? 'Mamba-Codestral 7B' : config.model;
|
|
207
|
+
const agentStatus = config.agentMode ? '🤖 Agent' : '💬 Chat';
|
|
208
|
+
console.log(`\n${agentStatus} \x1b[36mNoxyAI (${modelDisplay}):\x1b[0m\n`);
|
|
177
209
|
|
|
178
210
|
const reader = res.body.getReader();
|
|
179
211
|
const decoder = new TextDecoder('utf-8');
|
|
180
212
|
let fullResponse = "";
|
|
213
|
+
let usage = null;
|
|
214
|
+
let searchSources = [];
|
|
181
215
|
|
|
182
216
|
while (true) {
|
|
183
217
|
const { done, value } = await reader.read();
|
|
184
218
|
if (done) break;
|
|
219
|
+
|
|
185
220
|
const lines = decoder.decode(value, { stream: true }).split('\n');
|
|
186
221
|
for (const line of lines) {
|
|
187
222
|
if (line.startsWith('data: ')) {
|
|
188
223
|
const data = line.slice(6).trim();
|
|
189
224
|
if (data === '[DONE]') break;
|
|
225
|
+
|
|
190
226
|
try {
|
|
191
227
|
const parsed = JSON.parse(data);
|
|
228
|
+
|
|
229
|
+
// Reasoning in GREEN
|
|
230
|
+
if (parsed.reasoning) {
|
|
231
|
+
process.stdout.write('\x1b[32m' + parsed.reasoning + '\x1b[0m');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Normal response
|
|
192
235
|
if (parsed.text) {
|
|
193
236
|
fullResponse += parsed.text;
|
|
194
237
|
process.stdout.write(parsed.text);
|
|
195
238
|
}
|
|
239
|
+
|
|
240
|
+
if (parsed.usage) {
|
|
241
|
+
usage = parsed.usage;
|
|
242
|
+
}
|
|
196
243
|
} catch (e) {}
|
|
197
244
|
}
|
|
198
245
|
}
|
|
199
246
|
}
|
|
200
247
|
|
|
248
|
+
// Only process agent actions if agent mode is ON
|
|
249
|
+
if (!config.agentMode) {
|
|
250
|
+
console.log('\n');
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
201
254
|
console.log('\n\n\x1b[32m[Agent] Processing actions...\x1b[0m');
|
|
202
255
|
let agentFeedback = "";
|
|
203
256
|
|
|
@@ -216,16 +269,31 @@ async function chat(prompt, depth = 0) {
|
|
|
216
269
|
}
|
|
217
270
|
}
|
|
218
271
|
|
|
219
|
-
// Tool: Search Web
|
|
272
|
+
// Tool: Search Web with sources
|
|
220
273
|
const searchRegex = /<search>([\s\S]*?)<\/search>/g;
|
|
221
274
|
while ((match = searchRegex.exec(fullResponse)) !== null) {
|
|
222
275
|
const query = match[1].trim();
|
|
223
276
|
console.log(`\x1b[35m🔍 Searching Web:\x1b[0m ${query}`);
|
|
224
277
|
try {
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
278
|
+
const searchData = await searchWeb(query);
|
|
279
|
+
if (searchData.items) {
|
|
280
|
+
searchSources = searchData.items.slice(0, 5).map(i => ({
|
|
281
|
+
title: i.title,
|
|
282
|
+
link: i.link,
|
|
283
|
+
snippet: i.snippet
|
|
284
|
+
}));
|
|
285
|
+
|
|
286
|
+
console.log(`\x1b[35m📚 Sources found:\x1b[0m`);
|
|
287
|
+
searchSources.forEach((s, i) => {
|
|
288
|
+
console.log(` \x1b[36m${i+1}. ${s.title}\x1b[0m`);
|
|
289
|
+
console.log(` \x1b[90m${s.link}\x1b[0m`);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
const snippets = searchData.items.map(i => `- ${i.title}: ${i.snippet}\n Source: ${i.link}`).join('\n');
|
|
293
|
+
agentFeedback += `\n[SEARCH RESULTS FOR "${query}"]\n${snippets}\n`;
|
|
294
|
+
} else {
|
|
295
|
+
agentFeedback += `\n[SEARCH RESULTS FOR "${query}"]\nNo results found.\n`;
|
|
296
|
+
}
|
|
229
297
|
} catch (err) {
|
|
230
298
|
agentFeedback += `\n[SEARCH FAILED: ${err.message}]\n`;
|
|
231
299
|
}
|
|
@@ -256,7 +324,7 @@ async function chat(prompt, depth = 0) {
|
|
|
256
324
|
}
|
|
257
325
|
|
|
258
326
|
if (agentFeedback) {
|
|
259
|
-
console.log(`\x1b[33m🔄 Sending data back to Agent...\x1b[0m`);
|
|
327
|
+
console.log(`\n\x1b[33m🔄 Sending data back to Agent...\x1b[0m`);
|
|
260
328
|
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
329
|
return;
|
|
262
330
|
}
|
|
@@ -275,42 +343,66 @@ function startInteractiveMode() {
|
|
|
275
343
|
const config = loadConfig();
|
|
276
344
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
277
345
|
printLogo();
|
|
346
|
+
|
|
347
|
+
const agentStatus = config.agentMode ? '\x1b[32mON\x1b[0m' : '\x1b[31mOFF\x1b[0m';
|
|
348
|
+
|
|
278
349
|
console.log(`\x1b[33mWelcome to NoxyAI Interactive Mode!\x1b[0m`);
|
|
279
350
|
console.log(`Current Model: \x1b[32m${config.model}\x1b[0m`);
|
|
280
|
-
console.log(`
|
|
351
|
+
console.log(`Agent Mode: ${agentStatus}`);
|
|
352
|
+
console.log(`\nCommands:`);
|
|
353
|
+
console.log(` \x1b[36m/agent\x1b[0m - Toggle Agent Mode (3-model collaboration)`);
|
|
354
|
+
console.log(` \x1b[36m/model\x1b[0m - Change AI Model`);
|
|
355
|
+
console.log(` \x1b[36m/clear\x1b[0m - Clear screen`);
|
|
356
|
+
console.log(` \x1b[36m/exit\x1b[0m - Exit\n`);
|
|
281
357
|
|
|
282
358
|
function ask() {
|
|
283
|
-
|
|
359
|
+
const prompt = config.agentMode ? '\x1b[36mNoxyAI [Agent] > \x1b[0m' : '\x1b[36mNoxyAI [Chat] > \x1b[0m';
|
|
360
|
+
rl.question(prompt, async (input) => {
|
|
284
361
|
const trimmed = input.trim();
|
|
285
362
|
const lower = trimmed.toLowerCase();
|
|
286
363
|
|
|
287
364
|
if (lower === 'exit' || lower === '/exit') {
|
|
365
|
+
console.log('\n\x1b[36mGoodbye! 👋\x1b[0m\n');
|
|
288
366
|
process.exit(0);
|
|
289
367
|
}
|
|
290
368
|
else if (lower === '/clear') {
|
|
291
369
|
console.clear();
|
|
292
370
|
printLogo();
|
|
293
371
|
ask();
|
|
294
|
-
}
|
|
372
|
+
}
|
|
373
|
+
else if (lower === '/agent' || lower === '/agent on' || lower === '/agent off') {
|
|
374
|
+
config.agentMode = !config.agentMode;
|
|
375
|
+
saveConfig(config);
|
|
376
|
+
const status = config.agentMode ? '\x1b[32mON\x1b[0m' : '\x1b[31mOFF\x1b[0m';
|
|
377
|
+
console.log(`\n\x1b[33m🤖 Agent Mode: ${status}\x1b[0m`);
|
|
378
|
+
if (config.agentMode) {
|
|
379
|
+
console.log('\x1b[36mAgent mode uses 3 models working together:\x1b[0m');
|
|
380
|
+
console.log(' • Mamba-Codestral 7B (Fast Coding)');
|
|
381
|
+
console.log(' • Qwen3 80B (Deep Reasoning)');
|
|
382
|
+
console.log(' • GLM-4 9B (General Purpose)\n');
|
|
383
|
+
}
|
|
384
|
+
ask();
|
|
385
|
+
}
|
|
295
386
|
else if (lower === '/model') {
|
|
296
387
|
console.log('\n\x1b[33mSelect an AI Model:\x1b[0m');
|
|
297
|
-
console.log(' \x1b[36m1)\x1b[0m Auto (
|
|
298
|
-
console.log(' \x1b[36m2)\x1b[0m Qwen3 Next 80B Thinking
|
|
299
|
-
console.log(' \x1b[36m3)\x1b[0m
|
|
388
|
+
console.log(' \x1b[36m1)\x1b[0m Auto (Mamba-Codestral 7B - Fast/Coding)');
|
|
389
|
+
console.log(' \x1b[36m2)\x1b[0m Qwen3 Next 80B Thinking \x1b[32m[Reasoning in Green]\x1b[0m');
|
|
390
|
+
console.log(' \x1b[36m3)\x1b[0m Mistral Mamba-Codestral 7B');
|
|
391
|
+
console.log(' \x1b[36m4)\x1b[0m GLM-4 9B Chat');
|
|
300
392
|
|
|
301
|
-
rl.question('\nEnter number (1-
|
|
393
|
+
rl.question('\nEnter number (1-4): ', (choice) => {
|
|
302
394
|
let selected = 'auto';
|
|
303
395
|
if (choice === '2') selected = 'Qwen3';
|
|
304
|
-
if (choice === '3') selected = '
|
|
396
|
+
if (choice === '3') selected = 'Mamba-Codestral';
|
|
397
|
+
if (choice === '4') selected = 'GLM-4';
|
|
305
398
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
saveConfig(currentConfig);
|
|
399
|
+
config.model = selected;
|
|
400
|
+
saveConfig(config);
|
|
309
401
|
|
|
310
|
-
console.log(`\n\x1b[32m✔ Model
|
|
402
|
+
console.log(`\n\x1b[32m✔ Model changed to: ${selected}\x1b[0m\n`);
|
|
311
403
|
ask();
|
|
312
404
|
});
|
|
313
|
-
return;
|
|
405
|
+
return;
|
|
314
406
|
}
|
|
315
407
|
else if (trimmed) {
|
|
316
408
|
await chat(trimmed);
|
|
@@ -323,12 +415,22 @@ function startInteractiveMode() {
|
|
|
323
415
|
ask();
|
|
324
416
|
}
|
|
325
417
|
|
|
418
|
+
// Command handling
|
|
326
419
|
if (command === 'login') login();
|
|
327
420
|
else if (command === 'logout') logout();
|
|
328
421
|
else if (command === 'help' || command === '--help') {
|
|
329
422
|
printLogo();
|
|
330
|
-
console.log(`\n \x1b[32mnoxyai\x1b[0m Start Interactive Mode
|
|
423
|
+
console.log(`\n \x1b[32mnoxyai\x1b[0m Start Interactive Mode`);
|
|
424
|
+
console.log(` \x1b[32mnoxyai chat "<prompt>"\x1b[0m Run single prompt`);
|
|
425
|
+
console.log(`\n Interactive Commands:`);
|
|
426
|
+
console.log(` \x1b[36m/agent\x1b[0m Toggle Agent Mode (3-model collaboration)`);
|
|
427
|
+
console.log(` \x1b[36m/model\x1b[0m Change AI Model\n`);
|
|
428
|
+
}
|
|
429
|
+
else if (command === 'chat') {
|
|
430
|
+
chat(args.slice(1).join(' ')).then(() => process.exit(0));
|
|
331
431
|
}
|
|
332
|
-
else if (command === 'chat') { chat(args.slice(1).join(' ')).then(() => process.exit(0)); }
|
|
333
432
|
else if (!command) startInteractiveMode();
|
|
334
|
-
else {
|
|
433
|
+
else {
|
|
434
|
+
console.error(`❌ Unknown command. Run "noxyai help"`);
|
|
435
|
+
process.exit(1);
|
|
436
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "npm-noxyai",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"description": "CLI for NoxyAI",
|
|
5
5
|
"main": "index-noxyai.js",
|
|
6
6
|
"bin": {
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"keywords": [],
|
|
16
16
|
"type": "commonjs",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"express": "^5.2.1"
|
|
18
|
+
"express": "^5.2.1",
|
|
19
|
+
"http": "^0.0.1-security"
|
|
19
20
|
}
|
|
20
21
|
}
|
package/index.html
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
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/reinstall_pip.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import pip; pip.uninstall('pip'); import os; os.system('python -m ensurepip')
|
package/script.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
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
DELETED
package/snake_game.py
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
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
DELETED
package/tic_tac_toe.py
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import random
|
|
2
|
-
|
|
3
|
-
class TicTacToe:
|
|
4
|
-
def __init__(self):
|
|
5
|
-
self.board = [' ' for _ in range(9)]
|
|
6
|
-
|
|
7
|
-
def print_board(self):
|
|
8
|
-
row1 = '| {} | {} | {} |'.format(self.board[0], self.board[1], self.board[2])
|
|
9
|
-
row2 = '| {} | {} | {} |'.format(self.board[3], self.board[4], self.board[5])
|
|
10
|
-
row3 = '| {} | {} | {} |'.format(self.board[6], self.board[7], self.board[8])
|
|
11
|
-
|
|
12
|
-
print()
|
|
13
|
-
print(row1)
|
|
14
|
-
print(row2)
|
|
15
|
-
print(row3)
|
|
16
|
-
print()
|
|
17
|
-
|
|
18
|
-
def available_moves(self):
|
|
19
|
-
return [i for i, spot in enumerate(self.board) if spot == ' ']
|
|
20
|
-
|
|
21
|
-
def empty_cells(self):
|
|
22
|
-
return ' ' in self.board
|
|
23
|
-
|
|
24
|
-
def num_empty_cells(self):
|
|
25
|
-
return self.board.count(' ')
|
|
26
|
-
|
|
27
|
-
def make_move(self, letter, move):
|
|
28
|
-
self.board[move] = letter
|
|
29
|
-
|
|
30
|
-
def winner(self):
|
|
31
|
-
winning_combos = [(0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), (0, 4, 8), (2, 4, 6)]
|
|
32
|
-
for combo in winning_combos:
|
|
33
|
-
if self.board[combo[0]] == self.board[combo[1]] == self.board[combo[2]] != ' ':
|
|
34
|
-
return self.board[combo[0]]
|
|
35
|
-
if ' ' not in self.board:
|
|
36
|
-
return 'Tie'
|
|
37
|
-
return False
|
|
38
|
-
|
|
39
|
-
def minimax(board, depth, is_maximizing):
|
|
40
|
-
result = board.winner()
|
|
41
|
-
if result:
|
|
42
|
-
if result == 'X':
|
|
43
|
-
return -10 + depth
|
|
44
|
-
elif result == 'O':
|
|
45
|
-
return 10 - depth
|
|
46
|
-
elif result == 'Tie':
|
|
47
|
-
return 0
|
|
48
|
-
|
|
49
|
-
if is_maximizing:
|
|
50
|
-
best_score = float('-inf')
|
|
51
|
-
for move in board.available_moves():
|
|
52
|
-
board.make_move('O', move)
|
|
53
|
-
score = minimax(board, depth + 1, False)
|
|
54
|
-
board.board[move] = ' '
|
|
55
|
-
best_score = max(score, best_score)
|
|
56
|
-
return best_score
|
|
57
|
-
else:
|
|
58
|
-
best_score = float('inf')
|
|
59
|
-
for move in board.available_moves():
|
|
60
|
-
board.make_move('X', move)
|
|
61
|
-
score = minimax(board, depth + 1, True)
|
|
62
|
-
board.board[move] = ' '
|
|
63
|
-
best_score = min(score, best_score)
|
|
64
|
-
return best_score
|
|
65
|
-
|
|
66
|
-
def ai_move(board):
|
|
67
|
-
best_score = float('-inf')
|
|
68
|
-
best_move = 0
|
|
69
|
-
for move in board.available_moves():
|
|
70
|
-
board.make_move('O', move)
|
|
71
|
-
score = minimax(board, 0, False)
|
|
72
|
-
board.board[move] = ' '
|
|
73
|
-
if score > best_score:
|
|
74
|
-
best_score = score
|
|
75
|
-
best_move = move
|
|
76
|
-
return best_move
|
|
77
|
-
|
|
78
|
-
def main():
|
|
79
|
-
board = TicTacToe()
|
|
80
|
-
while True:
|
|
81
|
-
board.print_board()
|
|
82
|
-
move = input("Enter your move (1-9): ")
|
|
83
|
-
if board.board[int(move) - 1] != ' ':
|
|
84
|
-
print("Invalid move, try again.")
|
|
85
|
-
continue
|
|
86
|
-
board.make_move('X', int(move) - 1)
|
|
87
|
-
result = board.winner()
|
|
88
|
-
if result:
|
|
89
|
-
board.print_board()
|
|
90
|
-
if result == 'X':
|
|
91
|
-
print("You win!")
|
|
92
|
-
elif result == 'O':
|
|
93
|
-
print("AI wins!")
|
|
94
|
-
else:
|
|
95
|
-
print("It's a tie!")
|
|
96
|
-
break
|
|
97
|
-
move = ai_move(board)
|
|
98
|
-
board.make_move('O', move)
|
|
99
|
-
result = board.winner()
|
|
100
|
-
if result:
|
|
101
|
-
board.print_board()
|
|
102
|
-
if result == 'X':
|
|
103
|
-
print("You win!")
|
|
104
|
-
elif result == 'O':
|
|
105
|
-
print("AI wins!")
|
|
106
|
-
else:
|
|
107
|
-
print("It's a tie!")
|
|
108
|
-
break
|
|
109
|
-
|
|
110
|
-
if __name__ == '__main__':
|
|
111
|
-
main()
|
package/tic_tac_toe_local.py
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
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()
|