Add resign button
This commit is contained in:
parent
10a4bd64d2
commit
3093754bd4
|
@ -18,9 +18,9 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="game-container" hx-ext="ws">
|
<div id="game-container" hx-ext="ws">
|
||||||
<div id="title-box" class="title-box"></div>
|
<div id="title-box"></div>
|
||||||
<div id="game-board" class="game-board-grid"></div>
|
<div id="game-board"></div>
|
||||||
<div id="messages"></div>
|
<div id="button-box"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="game-link-container">
|
<div id="game-link-container">
|
||||||
<button id="copy-link-button" onclick="copyGameLink()">
|
<button id="copy-link-button" onclick="copyGameLink()">
|
||||||
|
|
|
@ -3,11 +3,17 @@ document.addEventListener('htmx:wsConfigSend', function (e) {
|
||||||
const row = parseInt(e.target.dataset.row);
|
const row = parseInt(e.target.dataset.row);
|
||||||
const col = parseInt(e.target.dataset.col);
|
const col = parseInt(e.target.dataset.col);
|
||||||
|
|
||||||
|
console.log(e.target.id);
|
||||||
|
|
||||||
// Set the custom JSON data
|
// Set the custom JSON data
|
||||||
e.detail.parameters = {
|
e.detail.parameters = {
|
||||||
type: 'make_move',
|
type: 'make_move',
|
||||||
row: row,
|
row: row,
|
||||||
col: col,
|
col: col,
|
||||||
};
|
};
|
||||||
|
} else if (e.target.id == 'resign-button') {
|
||||||
|
e.detail.parameters = {
|
||||||
|
type: 'resign'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -102,7 +102,7 @@ body {
|
||||||
padding-bottom: 0.25em;
|
padding-bottom: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-board-grid {
|
#game-board {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: calc(14 * 30px);
|
width: calc(14 * 30px);
|
||||||
height: calc(14 * 30px);
|
height: calc(14 * 30px);
|
||||||
|
@ -110,7 +110,7 @@ body {
|
||||||
border: 2px solid var(--color-neutral-700);
|
border: 2px solid var(--color-neutral-700);
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-board-grid::before {
|
#game-board::before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
@ -221,8 +221,15 @@ body {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#copy-link-button {
|
img.icon {
|
||||||
position: absolute;
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
color: var(--color-on-primary);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -230,27 +237,38 @@ body {
|
||||||
padding: 8px 15px;
|
padding: 8px 15px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
|
||||||
|
|
||||||
#copy-link-button {
|
|
||||||
background-color: var(--color-primary);
|
|
||||||
color: var(--color-on-primary);
|
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#copy-link-button:hover {
|
button:hover {
|
||||||
background-color: var(--color-primary-light);
|
background-color: var(--color-primary-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#button-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#resign-button {
|
||||||
|
background-color: var(--color-error);
|
||||||
|
color: var(--color-on-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
#resign-button:hover {
|
||||||
|
background-color: var(--color-error-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
#copy-link-button {
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
color: var(--color-on-primary);
|
||||||
|
}
|
||||||
|
|
||||||
#copy-link-button.copied-state {
|
#copy-link-button.copied-state {
|
||||||
background-color: var(--color-success);
|
background-color: var(--color-success);
|
||||||
}
|
}
|
||||||
|
|
||||||
img.icon {
|
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
|
@ -76,6 +76,12 @@ export class GomokuGame {
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public resign(resigningPlayerColor: PlayerColor) {
|
||||||
|
this.winnerColor = resigningPlayerColor === 'white' ? 'black' : 'white';
|
||||||
|
this.status = 'finished';
|
||||||
|
this.currentPlayerColor = null;
|
||||||
|
}
|
||||||
|
|
||||||
private checkWin(row: number, col: number, color: PlayerColor): boolean {
|
private checkWin(row: number, col: number, color: PlayerColor): boolean {
|
||||||
const directions = [
|
const directions = [
|
||||||
[1, 0], // vertical
|
[1, 0], // vertical
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
export interface Message {
|
export interface Message {
|
||||||
type: 'make_move' | 'resign';
|
type: 'make_move' | 'resign';
|
||||||
gameId: string;
|
|
||||||
playerId: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MakeMoveMessage extends Message {
|
export interface MakeMoveMessage extends Message {
|
||||||
|
|
|
@ -118,7 +118,11 @@ class GameServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public broadcastButtonsToPlayer(conn: PlayerConnection) {
|
public broadcastButtonsToPlayer(conn: PlayerConnection) {
|
||||||
// TODO
|
let buttonsHtml;
|
||||||
|
if (this.gomoku.status == 'playing' && this.getPlayerColor(conn)) {
|
||||||
|
buttonsHtml = <button id="resign-button" ws-send="click">Resign</button>;
|
||||||
|
}
|
||||||
|
conn.ws.send(<div id="button-box">{buttonsHtml}</div>);
|
||||||
console.log(`Sent buttons for game ${this.id} to player ${conn.id}`);
|
console.log(`Sent buttons for game ${this.id} to player ${conn.id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,6 +140,9 @@ class GameServer {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Handling ${message.type} message in game ${this.id} from player ${conn.id}: ${JSON.stringify(message)}`,
|
||||||
|
);
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case 'make_move': {
|
case 'make_move': {
|
||||||
this.handleMakeMove(conn, message as MakeMoveMessage);
|
this.handleMakeMove(conn, message as MakeMoveMessage);
|
||||||
|
@ -159,9 +166,6 @@ class GameServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleMakeMove(conn: PlayerConnection, message: MakeMoveMessage): void {
|
private handleMakeMove(conn: PlayerConnection, message: MakeMoveMessage): void {
|
||||||
console.log(
|
|
||||||
`Handling make_move message in game ${this.id} from player ${conn.id}: ${{ message }}`,
|
|
||||||
);
|
|
||||||
const { row, col } = message;
|
const { row, col } = message;
|
||||||
|
|
||||||
var playerColor;
|
var playerColor;
|
||||||
|
@ -180,7 +184,6 @@ class GameServer {
|
||||||
|
|
||||||
const stateBeforeMove = this.gomoku.status;
|
const stateBeforeMove = this.gomoku.status;
|
||||||
const result = this.gomoku.makeMove(playerColor, row, col);
|
const result = this.gomoku.makeMove(playerColor, row, col);
|
||||||
console.log(result);
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
this.broadcastBoard();
|
this.broadcastBoard();
|
||||||
this.broadcastTitle();
|
this.broadcastTitle();
|
||||||
|
@ -196,8 +199,28 @@ class GameServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleResignation(conn: PlayerConnection, _message: ResignationMessage): void {
|
private handleResignation(conn: PlayerConnection, message: ResignationMessage): void {
|
||||||
// TODO
|
console.log(
|
||||||
|
`Handling resign message in game ${this.id} from player ${conn.id}: ${{ message }}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.gomoku.status !== 'playing') {
|
||||||
|
conn.sendMessage('error', 'You can only resign from an active game.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resigningPlayerColor = this.getPlayerColor(conn);
|
||||||
|
if (!resigningPlayerColor) {
|
||||||
|
conn.sendMessage('error', 'You are not a player in this game.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.gomoku.resign(resigningPlayerColor);
|
||||||
|
this.broadcastBoard();
|
||||||
|
this.broadcastTitle();
|
||||||
|
this.broadcastButtons();
|
||||||
|
|
||||||
|
console.log(`Player ${conn.id} resigned from game ${this.id}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue