add spectator

This commit is contained in:
dvorak
2023-12-08 16:14:17 +08:00
parent 8e48c1c47d
commit 5512103ffd
3 changed files with 184 additions and 95 deletions
+3 -2
View File
@@ -12,8 +12,9 @@ ChessServer is just a simple chess server for [Aiursoft](https://www.aiursoft.co
Requirements about how to run
1. [.NET 7 SDK](http://dot.net/)
2. Execute `dotnet run` to run the app
3. Use your browser to view [http://localhost:5000](http://localhost:5000)
2. Run `npm i` at directory `/src/Aiursoft.ChessServer/wwwroot/`
3. Execute `dotnet run` to run the app
4. Use your browser to view [http://localhost:5000](http://localhost:5000)
## Run in Microsoft Visual Studio
@@ -15,19 +15,50 @@
</div>
<div class="col-md-12">
@* Make the following p auto warp *@
<p id="status" class="text-center text-wrap text-primary mt-1"></p>
<p id="fen" class="text-wrap text-muted hidden"></p>
</div>
</div>
<div class="modal fade" id="chooseCharacter" tabindex="-1" aria-labelledby="chooseCharacter" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Choose your character</h5>
</div>
<div class="modal-body">
<button type="button" id="chooseWhite" class="btn">
<img src="/img/chesspieces/wikipedia/wK.png" alt="White">
</button>
<button type="button" id="chooseBlack" class="btn">
<img src="/img/chesspieces/wikipedia/bK.png" alt="Black">
</button>
<button type="button" data-bs-dismiss="modal" id="choosePeek" class="btn btn-primary">Peek~👀</button>
</div>
</div>
</div>
</div>
@section Scripts {
<script type="module" src="~/node_modules/@@chrisoakman/chessboardjs/dist/chessboard-1.0.0.min.js"></script>
<script type="module" src="~/site.js"></script>
<script type="module">
// Ask the user to enter w or b:
import initGameBoard from "/site.js";
const player = prompt("Please enter your color (w or b):");
initGameBoard(player, @Model);
import Game from "/site.js";
let game = new Game(@Model);
game.chooseCharacter();
$("#chooseWhite").on("click", function () {
game.setPlayer('w');
game.startGame();
});
$("#chooseBlack").on("click", function () {
game.setPlayer('b');
game.startGame();
});
$('#choosePeek').on('click', function () {
game.startGame();
});
</script>
}
+146 -89
View File
@@ -1,107 +1,164 @@
import { Chess } from "/node_modules/chess.js/dist/esm/chess.js";
const statusControl = $('#status');
const fenControl = $('#fen');
const WHITE = "w";
const BLACK = "b";
const SPECTATOR = "";
/**
* representing current Game
*
* ## example
* ```
* let gameId = 0;
* let game = new Game(gameId);
* ```
*
* @param {number} gameId current id of game
*/
function Game(gameId) {
this.gameId = gameId;
this.player = "";
this.chooseCharacterModal = new bootstrap.Modal(
document.getElementById("chooseCharacter")
);
this.chooseCharacter = () => {
this.chooseCharacterModal.show();
};
this.setPlayer = (player) => {
if ([WHITE, BLACK].includes(player)) {
this.player = player;
} else {
this.player = SPECTATOR;
}
};
/**
* let's start to play!
* but before, you need to choose a character
*/
this.startGame = () => {
this.chooseCharacterModal.hide();
initGameBoard(this.player, this.gameId);
if (this.player === SPECTATOR) {
document.getElementById("board").style.cursor = "not-allowed";
}
};
}
const statusControl = $("#status");
const fenControl = $("#fen");
const initGameBoard = function (player, gameId) {
$.get("/games/" + gameId + ".fen", function (fen) {
let board = null;
let game = null;
$.get("/games/" + gameId + ".fen", function (fen) {
let board = null;
let game = null;
// Happens when a player picks up a piece.
function onDragStart(source, piece, position, _) {
// only allow moving players own pieces
if ((game.turn() !== player)) {
return false
}
// Happens when a player picks up a piece.
function onDragStart(source, piece, position, _) {
// only allow moving players own pieces
if (game.turn() !== player) {
return false;
}
// do not pick up pieces if the game is over
if (game.isGameOver()) return false
// do not pick up pieces if the game is over
if (game.isGameOver()) return false;
// only pick up pieces for the side to move
if ((game.turn() === 'w' && piece.search(/^b/) !== -1) ||
(game.turn() === 'b' && piece.search(/^w/) !== -1)) {
return false
}
// only pick up pieces for the side to move
if (
(game.turn() === "w" && piece.search(/^b/) !== -1) ||
(game.turn() === "b" && piece.search(/^w/) !== -1)
) {
return false;
}
}
function onDrop(source, target) {
try {
const move = game.move({
from: source,
to: target,
promotion: "q",
});
if (move === null) {
return "snapback";
}
const lastMove = game.history({ verbose: true }).pop().san;
$.post("/games/" + gameId + "/move/" + player + "/" + lastMove);
} catch (e) {
return "snapback";
}
}
function onDrop(source, target) {
try {
const move = game.move({
from: source,
to: target,
promotion: 'q'
})
if (move === null) {
return 'snapback'
}
const lastMove = game.history({verbose: true}).pop().san;
$.post("/games/" + gameId + "/move/" + player + "/" + lastMove);
} catch (e) {
return 'snapback';
}
// Hack to make sure castling\promotion works.
function onSnapEnd() {
board.position(game.fen());
}
function updateStatusText() {
let status;
let moveColor = "White";
if (game.turn() === "b") {
moveColor = "Black";
}
if (game.isCheckmate()) {
status =
"Game over, " +
moveColor +
" is in checkmate, and winner is " +
(game.turn() === "w" ? "Black" : "White");
} else if (game.isDraw()) {
status = "Game over, drawn position";
} else {
status = moveColor + " to move";
if (game.isCheck()) {
status += ", " + moveColor + " is in check";
}
}
statusControl.html(status);
fenControl.html(game.fen());
}
// Hack to make sure castling\promotion works.
function onSnapEnd() {
board.position(game.fen())
}
const config = {
orientation: player === "w" ? "white" : "black",
draggable: true,
dragoffBoard: "snapback",
position: fen,
onDragStart: onDragStart,
onSnapEnd: onSnapEnd,
onDrop: onDrop,
};
board = ChessBoard("board", config);
function updateStatusText() {
let status;
let moveColor = 'White';
if (game.turn() === 'b') {
moveColor = 'Black';
} if (game.isCheckmate()) {
status = 'Game over, ' + moveColor + ' is in checkmate, and winner is ' + (game.turn() === 'w' ? 'Black' : 'White');
} else if (game.isDraw()) {
status = 'Game over, drawn position';
} else {
status = moveColor + ' to move';
if (game.isCheck()) {
status += ', ' + moveColor + ' is in check';
}
}
statusControl.html(status);
fenControl.html(game.fen());
}
function refresh(newFen) {
game = new Chess(newFen);
board.position(newFen);
console.log("Got fen " + newFen + ". refreshing board...");
updateStatusText();
}
const config = {
orientation: player === "w" ? "white" : "black",
draggable: true,
dragoffBoard: 'snapback',
position: fen,
onDragStart: onDragStart,
onSnapEnd: onSnapEnd,
onDrop: onDrop
};
board = ChessBoard('board', config);
refresh(fen);
function refresh(newFen) {
game = new Chess(newFen);
board.position(newFen);
console.log("Got fen " + newFen + ". refreshing board...");
updateStatusText();
}
refresh(fen);
const wsScheme = window.location.protocol === "https:" ? "wss://" : "ws://";
const socket = new WebSocket(wsScheme + window.location.host + "/games/" + gameId + ".ws");
socket.onmessage = function (event) {
refresh(event.data);
};
// Auto reconnect.
socket.onclose = function () {
alert("Socket closed. Reconnecting...");
setTimeout(function () {
initGameBoard(player, gameId);
}, 1000);
};
});
const wsScheme = window.location.protocol === "https:" ? "wss://" : "ws://";
const socket = new WebSocket(
wsScheme + window.location.host + "/games/" + gameId + ".ws"
);
socket.onmessage = function (event) {
refresh(event.data);
};
// Auto reconnect.
socket.onclose = function () {
alert("Socket closed. Reconnecting...");
setTimeout(function () {
initGameBoard(player, gameId);
}, 1000);
};
});
};
// noinspection JSUnusedGlobalSymbols
export default initGameBoard;
export default Game;