mirror of
				https://github.com/thib8956/tic-tac-toe-ws.git
				synced 2025-10-31 09:09:21 +00:00 
			
		
		
		
	implement the game, more or less
This commit is contained in:
		
							
								
								
									
										15
									
								
								client.mts
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								client.mts
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| import { Request, Response, Message, Hello } from "common.mjs"; | ||||
| import { Request, Response, Message, Hello, EndGame } from "common.mjs"; | ||||
|  | ||||
| const ws = new WebSocket("ws://localhost:1234"); | ||||
| const grid = [0, 0, 0, 0, 0, 0, 0, 0, 0] | ||||
| @@ -44,6 +44,19 @@ ws.onmessage = (evt) => { | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| 	case "endgame": { | ||||
|             const h1 = document.getElementById("title") as HTMLHeadingElement | null; | ||||
|             if (h1) { | ||||
| 		const issue = (msg.data as EndGame).issue; | ||||
| 		switch (issue){ | ||||
| 	            case "win": h1.innerText = "you won"; break; | ||||
| 		    case "lose": h1.innerText = "you lose"; break; | ||||
| 		    case "draw": h1.innerText = "it's a draw!"; break; | ||||
| 		    default: throw new Error(`unexpected ${issue}`); | ||||
| 		} | ||||
| 	    } | ||||
| 	    break; | ||||
| 	} | ||||
|         default: { | ||||
|             console.log(msg); | ||||
|             break; | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| export type MessageKind = "hello" | "update"; | ||||
| export type MessageKind = "hello" | "update" | "endgame"; | ||||
|  | ||||
| export interface Message { | ||||
| 	kind: MessageKind, | ||||
| 	data: Response | Hello, | ||||
| 	data: Response | Hello | EndGame, | ||||
| } | ||||
|  | ||||
| export interface Request { | ||||
| @@ -18,3 +18,6 @@ export interface Hello { | ||||
|     id: number | ||||
| } | ||||
|  | ||||
| export interface EndGame { | ||||
|     issue: "win" | "lose" | "draw" | ||||
| } | ||||
|   | ||||
							
								
								
									
										122
									
								
								server.mts
									
									
									
									
									
								
							
							
						
						
									
										122
									
								
								server.mts
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| import { Message, Response, Hello } from "common.mjs" | ||||
| import { Message, Response, Hello, EndGame } from "common.mjs" | ||||
| import { WebSocket, WebSocketServer } from "ws"; | ||||
|  | ||||
| const port = 1234 | ||||
| @@ -15,6 +15,7 @@ interface Client { | ||||
|  | ||||
| let id = 1; | ||||
| let clients: Client[] = []; | ||||
| let currentPlayerId: number | undefined = undefined; | ||||
|  | ||||
| wss.on("connection", (ws) => { | ||||
|     id += 1; | ||||
| @@ -24,6 +25,11 @@ wss.on("connection", (ws) => { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (!currentPlayerId) { | ||||
| 	currentPlayerId = id; | ||||
| 	console.log(`current player is #${currentPlayerId}`); | ||||
|     } | ||||
|  | ||||
|     clients.push({id, ws}); | ||||
|     ws.send(JSON.stringify({kind: "hello", data: { id } as Hello})); | ||||
|     console.log(`player #${id} connected`); | ||||
| @@ -33,16 +39,51 @@ wss.on("connection", (ws) => { | ||||
|         const {x, y} = message; | ||||
|         const playerId = clients.find(x => x.ws === ws)?.id; | ||||
|         console.assert(playerId); | ||||
| 	console.log(message, playerId, currentPlayerId); | ||||
|  | ||||
| 	if (playerId != currentPlayerId) { | ||||
| 	    return; | ||||
| 	} | ||||
|  | ||||
|         if (grid[y*3+x] === 0) { | ||||
|             grid[y*3+x] = playerId as number; | ||||
|             for (const c of clients) { | ||||
|                 const msg: Message = { | ||||
|                     kind: "update", | ||||
|                     data: { grid } as Response, | ||||
|                 } | ||||
|                 c.ws.send(JSON.stringify(msg)); | ||||
|             } | ||||
|         } | ||||
| 		    data: { grid } as Response, | ||||
| 		} | ||||
| 		c.ws.send(JSON.stringify(msg)); | ||||
| 	    } | ||||
|  | ||||
| 	    const winnerId = checkWin(grid); | ||||
| 	    if (winnerId == -1) { | ||||
| 	        currentPlayerId = clients.find(x => x.id !== currentPlayerId)?.id; // change player | ||||
| 		console.assert(currentPlayerId); | ||||
| 		console.log(`current player is #${currentPlayerId}`); | ||||
| 	    } else if (winnerId == 0) { | ||||
| 		for (const c of clients) { | ||||
|                      const msg: Message = { | ||||
| 		         kind: "endgame", | ||||
| 			 data: { issue: "draw" } as EndGame | ||||
| 		     }; | ||||
| 		     c.ws.send(JSON.stringify(msg)); | ||||
| 		} | ||||
| 	    } else { | ||||
| 	        console.log(`player ${winnerId} won !`); | ||||
|  | ||||
| 		const winner = clients.find(x => x.id === winnerId); | ||||
| 	        winner?.ws?.send(JSON.stringify({ | ||||
| 		    kind: "endgame", | ||||
| 		    data: { issue: "win" } as EndGame | ||||
| 		} as Message));	 | ||||
|  | ||||
| 		const loser = clients.find(x => x.id !== winnerId); | ||||
| 	        loser?.ws?.send(JSON.stringify({ | ||||
| 		    kind: "endgame", | ||||
| 		    data: { issue: "lose" } as EndGame | ||||
| 		} as Message));	 | ||||
| 	    } | ||||
| 	} | ||||
|     }); | ||||
|  | ||||
|     ws.on("close", () => { | ||||
| @@ -50,3 +91,72 @@ wss.on("connection", (ws) => { | ||||
|         clients = clients.filter(x => x.id !== id); | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| function checkWin(grid: number[]): number { | ||||
| 	const clone = [...grid]; | ||||
| 	const grid2d = []; | ||||
| 	while(clone.length) grid2d.push(clone.splice(0,3)); | ||||
|  | ||||
| 	if ( | ||||
| 		grid2d[0][0] !== 0 && | ||||
| 		grid2d[0][0] === grid2d[0][1] && | ||||
| 		grid2d[0][1] === grid2d[0][2] | ||||
| 	) { | ||||
| 		return grid2d[0][0]; | ||||
| 	} | ||||
| 	if ( | ||||
| 		grid2d[1][0] !== 0 && | ||||
| 		grid2d[1][0] === grid2d[1][1] && | ||||
| 	grid2d[1][1] === grid2d[1][2] | ||||
| 	) { | ||||
| 		return grid2d[1][0]; | ||||
| 	} | ||||
| 	if ( | ||||
| 		grid2d[2][0] !== 0 && | ||||
| 		grid2d[2][0] === grid2d[2][1] && | ||||
| 	grid2d[2][1] === grid2d[2][2] | ||||
| 	) { | ||||
| 		return grid2d[2][0]; | ||||
| 	} | ||||
| 	if ( | ||||
| 		grid2d[0][0] !== 0 && | ||||
| 		grid2d[0][0] === grid2d[1][0] && | ||||
| 	grid2d[1][0] === grid2d[2][0] | ||||
| 	) { | ||||
| 		return grid2d[0][0]; | ||||
| 	} | ||||
| 	if ( | ||||
| 		grid2d[0][1] !== 0 && | ||||
| 		grid2d[0][1] === grid2d[1][1] && | ||||
| 	grid2d[1][1] === grid2d[2][1] | ||||
| 	) { | ||||
| 		return grid2d[0][1]; | ||||
| 	} | ||||
| 	if ( | ||||
| 		grid2d[0][2] !== 0 && | ||||
| 		grid2d[0][2] === grid2d[1][2] && | ||||
| 	grid2d[1][2] === grid2d[2][2] | ||||
| 	) { | ||||
| 		return grid2d[0][2]; | ||||
| 	} | ||||
| 	if ( | ||||
| 		grid2d[0][0] !== 0 && | ||||
| 		grid2d[0][0] === grid2d[1][1] && | ||||
| 	grid2d[1][1] === grid2d[2][2] | ||||
| 	) { | ||||
| 		return grid2d[0][0]; | ||||
| 	} | ||||
| 	if ( | ||||
| 		grid2d[0][2] !== 0 && | ||||
| 		grid2d[0][2] === grid2d[1][1] && | ||||
| 	grid2d[1][1] === grid2d[2][0] | ||||
| 	) { | ||||
| 		return grid2d[0][2]; | ||||
| 	} | ||||
| 	for (const row of grid2d) { | ||||
| 		if (row[0] === 0 || row[1] === 0 || row[2] === 0) { | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user