Skip to content

Commit f27e8a4

Browse files
committed
feat: Add WebSocket server CLI and enhance AI-vs-AI test script with board state management
1 parent 6c7eb7c commit f27e8a4

File tree

7 files changed

+76
-11
lines changed

7 files changed

+76
-11
lines changed
41.9 MB
Binary file not shown.

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,18 @@
88
"liku": "dist/index.js",
99
"liku-agent": "dist/agent/cli.js",
1010
"liku-autoplay": "dist/autoplayer/cli.js",
11-
"liku-learn": "dist/learn/cli.js"
11+
"liku-learn": "dist/learn/cli.js",
12+
"liku-server": "dist/websocket/cli.js"
1213
},
1314
"scripts": {
1415
"build": "tsc",
1516
"start": "node dist/index.js",
1617
"dev": "tsc --watch",
1718
"test": "vitest",
1819
"test:run": "vitest run",
20+
"server": "node dist/websocket/cli.js",
21+
"server:verbose": "node dist/websocket/cli.js --verbose",
22+
"ai-vs-ai": "node dist/websocket/cli.js & sleep 2 && node scripts/test-ai-vs-ai.js",
1923
"agent": "node dist/agent/cli.js",
2024
"agent:info": "node dist/agent/cli.js info",
2125
"agent:read": "node dist/agent/cli.js read",

scripts/test-ai-vs-ai.js

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ class SimpleAI {
1919
this.sessionId = null;
2020
this.isMyTurn = false;
2121
this.gameOver = false;
22+
this.board = [
23+
[null, null, null],
24+
[null, null, null],
25+
[null, null, null]
26+
];
2227
}
2328

2429
connect() {
@@ -91,7 +96,12 @@ class SimpleAI {
9196

9297
switch (eventType) {
9398
case 'session:created':
94-
console.log(`[${this.name}] Session created: ${event.sessionId?.slice(0, 8)}`);
99+
// Session ID is in event.id (not event.sessionId)
100+
const createdId = event.id || event.sessionId;
101+
if (createdId) {
102+
this.sessionId = createdId;
103+
}
104+
console.log(`[${this.name}] Session created: ${createdId?.slice(0, 12) || 'unknown'}`);
95105
break;
96106

97107
case 'session:playerJoined':
@@ -117,10 +127,13 @@ class SimpleAI {
117127

118128
case 'session:moveMade':
119129
console.log(`[${this.name}] Move made by ${event.agentId?.slice(0, 8) || 'player'} at (${event.move?.row ?? event.row},${event.move?.col ?? event.col})`);
120-
if (event.board) {
121-
this.printBoard(event.board);
122-
} else if (event.state?.board) {
130+
// Update local board state
131+
if (event.state?.board) {
132+
this.board = event.state.board;
123133
this.printBoard(event.state.board);
134+
} else if (event.board) {
135+
this.board = event.board;
136+
this.printBoard(event.board);
124137
}
125138
break;
126139

@@ -162,17 +175,48 @@ class SimpleAI {
162175
makeMove() {
163176
if (!this.isMyTurn || this.gameOver) return;
164177

165-
// Simple strategy: try center first, then corners, then edges
166-
const moves = [
178+
// Find empty cells from current board state
179+
const emptyCells = [];
180+
for (let row = 0; row < 3; row++) {
181+
for (let col = 0; col < 3; col++) {
182+
if (!this.board[row][col]) {
183+
emptyCells.push([row, col]);
184+
}
185+
}
186+
}
187+
188+
if (emptyCells.length === 0) {
189+
console.log(`[${this.name}] No empty cells!`);
190+
return;
191+
}
192+
193+
// Simple strategy: prefer center, then corners, then edges
194+
const priorities = [
167195
[1, 1], // center
168196
[0, 0], [0, 2], [2, 0], [2, 2], // corners
169197
[0, 1], [1, 0], [1, 2], [2, 1] // edges
170198
];
171199

172-
// For testing, just try moves in order
173-
// The server will tell us if a move is invalid
174-
const [row, col] = moves[Math.floor(Math.random() * moves.length)];
175-
console.log(`[${this.name}] Attempting move at (${row}, ${col})`);
200+
let move = null;
201+
for (const [r, c] of priorities) {
202+
if (emptyCells.some(([er, ec]) => er === r && ec === c)) {
203+
move = [r, c];
204+
break;
205+
}
206+
}
207+
208+
// Fallback to first empty cell
209+
if (!move && emptyCells.length > 0) {
210+
move = emptyCells[0];
211+
}
212+
213+
if (!move) {
214+
console.log(`[${this.name}] No valid move found!`);
215+
return;
216+
}
217+
218+
const [row, col] = move;
219+
console.log(`[${this.name}] Making move at (${row}, ${col})`);
176220

177221
this.send({
178222
type: 'action',

server-output.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Starting Liku-AI WebSocket server...
2+
[Security] No JWT secret provided - using random key (tokens will be invalid after restart)
3+
[WS] Liku-AI WebSocket server v1.0.0 listening on ws://localhost:3847
4+
[WS] Security: {"tls":{"enabled":false,"minVersion":"TLSv1.2","requestCert":false},"jwt":{"enabled":false,"algorithm":"HS256","issuer":"liku-ai","expiresIn":3600,"allowRefresh":true}}
5+
[WS] Health endpoint listening on port 3848
6+
Server is running on port 3847
7+
Health endpoint on port 3848
8+
Press Ctrl+C to stop

server.log

828 Bytes
Binary file not shown.

test-error.txt

Whitespace-only changes.

test-output.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
═══════════════════════════════════════════════════════════════
2+
Cross-Chat AI Game - BEST OF 5 SERIES
3+
Simulating two chat windows finding each other
4+
FAIR PLAY: Both agents use SMART strategy
5+
═══════════════════════════════════════════════════════════════
6+
7+
Step 1: Both agents connect to server...
8+
9+
[ChatWindow-1] Disconnected

0 commit comments

Comments
 (0)