add chess example
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-macos (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
3
examples/chess/Makefile
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
def:
|
||||||
|
cd _prosperon && make && cp build_dbg/prosperon ..
|
||||||
|
./prosperon
|
||||||
BIN
examples/chess/black_bishop.png
Normal file
|
After Width: | Height: | Size: 390 B |
BIN
examples/chess/black_king.png
Normal file
|
After Width: | Height: | Size: 438 B |
BIN
examples/chess/black_knight.png
Normal file
|
After Width: | Height: | Size: 398 B |
BIN
examples/chess/black_pawn.png
Normal file
|
After Width: | Height: | Size: 337 B |
BIN
examples/chess/black_queen.png
Normal file
|
After Width: | Height: | Size: 390 B |
BIN
examples/chess/black_rook.png
Normal file
|
After Width: | Height: | Size: 379 B |
57
examples/chess/grid.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
var CELLS = Symbol()
|
||||||
|
|
||||||
|
var key = function key(x,y) { return `${x},${y}` }
|
||||||
|
|
||||||
|
function grid(w, h)
|
||||||
|
{
|
||||||
|
this[CELLS] = new Map()
|
||||||
|
this.width = w;
|
||||||
|
this.height = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.prototype = {
|
||||||
|
cell(x,y) {
|
||||||
|
var k = key(x,y)
|
||||||
|
if (!this[CELLS].has(k)) this[CELLS].set(k,[])
|
||||||
|
return this[CELLS].get(k)
|
||||||
|
},
|
||||||
|
|
||||||
|
add(entity, pos) {
|
||||||
|
this.cell(pos.x, pos.y).push(entity);
|
||||||
|
entity.coord = pos.slice();
|
||||||
|
},
|
||||||
|
|
||||||
|
remove(entity, pos) {
|
||||||
|
var c = this.cell(pos.x, pos.y);
|
||||||
|
c.splice(c.indexOf(entity), 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
at(pos) {
|
||||||
|
return this.cell(pos.x, pos.y);
|
||||||
|
},
|
||||||
|
|
||||||
|
inBounds(pos) {
|
||||||
|
return pos.x >= 0 && pos.x < this.width && pos.y >= 0 && pos.y < this.height;
|
||||||
|
},
|
||||||
|
|
||||||
|
each(fn) {
|
||||||
|
for (var [k, list] of this[CELLS])
|
||||||
|
for (var p of list) fn(p, p.coord);
|
||||||
|
},
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
var out = `grid [${this.width}x${this.height}]
|
||||||
|
`
|
||||||
|
for (var y = 0; y < this.height; y++) {
|
||||||
|
for (var x = 0; x < this.width; x++) {
|
||||||
|
var cell = this.at([x,y]);
|
||||||
|
out += cell.length
|
||||||
|
}
|
||||||
|
if (y !== this.height - 1) out += "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return grid
|
||||||
117
examples/chess/main.js
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/* main.js – runs the demo with your prototype-based grid */
|
||||||
|
var res = 160
|
||||||
|
var internal_res = 480
|
||||||
|
var render = use('render');
|
||||||
|
render.initialize({ width:res, height:res, resolution_x:internal_res, resolution_y:internal_res, mode:'letterbox' });
|
||||||
|
|
||||||
|
var os = use('os');
|
||||||
|
var draw2d = use('draw2d');
|
||||||
|
var gfx = use('graphics');
|
||||||
|
|
||||||
|
/* camera – unchanged */
|
||||||
|
var camera = { size:[internal_res,internal_res], transform:os.make_transform(), fov:50, near_z:0,
|
||||||
|
far_z:1000, surface:undefined, viewport:{x:0,y:0,width:1,height:1},
|
||||||
|
ortho:true, anchor:[0,0] };
|
||||||
|
|
||||||
|
/*──── import our pieces + systems ───────────────────────────────────*/
|
||||||
|
var Grid = use('grid'); // your new ctor
|
||||||
|
var MovementSystem = use('movement').MovementSystem;
|
||||||
|
var startingPos = use('pieces').startingPosition;
|
||||||
|
var rules = use('rules');
|
||||||
|
|
||||||
|
/*──── build board ───────────────────────────────────────────────────*/
|
||||||
|
var grid = new Grid(8, 8);
|
||||||
|
grid.width = 8; // (the ctor didn’t store them)
|
||||||
|
grid.height = 8;
|
||||||
|
|
||||||
|
var mover = new MovementSystem(grid, rules);
|
||||||
|
startingPos(grid);
|
||||||
|
|
||||||
|
/*──── mouse → click-to-move ─────────────────────────────────────────*/
|
||||||
|
var selectPos = null;
|
||||||
|
prosperon.window.on_mousedown = function (btn, mx, my) {
|
||||||
|
if (btn !== 0) return;
|
||||||
|
var c = [Math.floor(mx / 60), Math.floor(my / 60)];
|
||||||
|
if (!grid.inBounds(c)) return;
|
||||||
|
|
||||||
|
var cell = grid.at(c);
|
||||||
|
if (selectPos && mover.tryMove(grid.at(selectPos)[0], c)) {
|
||||||
|
selectPos = null; // made a move
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cell.length && cell[0].colour === mover.turn) {
|
||||||
|
selectPos = c; // pick up piece
|
||||||
|
} else {
|
||||||
|
selectPos = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*──── drawing helpers ───────────────────────────────────────────────*/
|
||||||
|
/* ── constants ─────────────────────────────────────────────────── */
|
||||||
|
var S = 60; // square size in px
|
||||||
|
var light = [0.93,0.93,0.93,1];
|
||||||
|
var dark = [0.25,0.25,0.25,1];
|
||||||
|
|
||||||
|
/* ── draw one 8×8 chess board ──────────────────────────────────── */
|
||||||
|
function drawBoard() {
|
||||||
|
for (var y = 0; y < 8; ++y)
|
||||||
|
for (var x = 0; x < 8; ++x) {
|
||||||
|
draw2d.rectangle(
|
||||||
|
{ x: x*S, y: y*S, width: S, height: S },
|
||||||
|
{ thickness: 0, color: ((x+y)&1) ? dark : light }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── draw every live piece ─────────────────────────────────────── */
|
||||||
|
function drawPieces() {
|
||||||
|
grid.each(function (piece) {
|
||||||
|
if (piece.captured) return;
|
||||||
|
|
||||||
|
var r = { x: piece.coord[0]*S, y: piece.coord[1]*S,
|
||||||
|
width:S, height:S };
|
||||||
|
|
||||||
|
draw2d.image(piece.sprite, r, 0, [0,0], [0,0], {mode:"nearest"});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*──── main loop ─────────────────────────────────────────────────────*/
|
||||||
|
var last = os.now(), fpsTimer = 0, fpsCount = 0;
|
||||||
|
|
||||||
|
function loop() {
|
||||||
|
var now = os.now(), dt = now - last; last = now;
|
||||||
|
|
||||||
|
render.clear([22/255, 120/255, 194/255, 1]);
|
||||||
|
render.camera(camera);
|
||||||
|
drawBoard();
|
||||||
|
drawPieces();
|
||||||
|
render.present();
|
||||||
|
|
||||||
|
fpsTimer += dt; fpsCount++;
|
||||||
|
if (fpsTimer >= 0.5) {
|
||||||
|
prosperon.window.title =
|
||||||
|
'Chess demo – ' + mover.turn + '\'s move – FPS ' + (fpsCount / fpsTimer).toFixed(1);
|
||||||
|
fpsTimer = fpsCount = 0;
|
||||||
|
}
|
||||||
|
$_.delay(loop, Math.max(0, (1 / 60) - (os.now() - now)));
|
||||||
|
}
|
||||||
|
loop();
|
||||||
|
|
||||||
|
var os = use('os')
|
||||||
|
var ioguy = {
|
||||||
|
__ACTORDATA__: {
|
||||||
|
id: os.ioactor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$_.send(ioguy, {
|
||||||
|
type: "subscribe",
|
||||||
|
actor: $_
|
||||||
|
})
|
||||||
|
|
||||||
|
$_.receiver(e => {
|
||||||
|
if (e.type === 'quit')
|
||||||
|
os.exit()
|
||||||
|
else
|
||||||
|
console.log(json.encode(e))
|
||||||
|
})
|
||||||
32
examples/chess/movement.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
var MovementSystem = function(grid, rules) {
|
||||||
|
this.grid = grid;
|
||||||
|
this.rules = rules || {}; // expects { canMove: fn }
|
||||||
|
this.turn = 'white';
|
||||||
|
}
|
||||||
|
|
||||||
|
MovementSystem.prototype.tryMove = function (piece, to) {
|
||||||
|
if (piece.colour !== this.turn) return false;
|
||||||
|
|
||||||
|
// normalise ‘to’ into our hybrid coord
|
||||||
|
var dest = [to.x !== undefined ? to.x : to[0],
|
||||||
|
to.y !== undefined ? to.y : to[1]];
|
||||||
|
|
||||||
|
if (!this.grid.inBounds(dest)) return false;
|
||||||
|
if (!this.rules.canMove(piece, piece.coord, dest, this.grid)) return false;
|
||||||
|
|
||||||
|
var victims = this.grid.at(dest);
|
||||||
|
if (victims.length && victims[0].colour === piece.colour) return false;
|
||||||
|
if (victims.length) victims[0].captured = true;
|
||||||
|
|
||||||
|
this.grid.remove(piece, piece.coord);
|
||||||
|
this.grid.add (piece, dest);
|
||||||
|
|
||||||
|
// grid.add() re-creates coord; re-add .x/.y fields:
|
||||||
|
piece.coord.x = dest.x;
|
||||||
|
piece.coord.y = dest.y;
|
||||||
|
|
||||||
|
this.turn = (this.turn === 'white') ? 'black' : 'white';
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
return { MovementSystem: MovementSystem };
|
||||||
29
examples/chess/pieces.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/* pieces.js – simple data holders + starting layout */
|
||||||
|
function Piece(kind, colour) {
|
||||||
|
this.kind = kind; // "pawn" etc.
|
||||||
|
this.colour = colour; // "white"/"black"
|
||||||
|
this.sprite = colour + '_' + kind; // for draw2d.image
|
||||||
|
this.captured = false;
|
||||||
|
this.coord = [0,0];
|
||||||
|
}
|
||||||
|
Piece.prototype.toString = function () {
|
||||||
|
return this.colour.charAt(0) + this.kind.charAt(0).toUpperCase();
|
||||||
|
};
|
||||||
|
|
||||||
|
function startingPosition(grid) {
|
||||||
|
var W = 'white', B = 'black', x;
|
||||||
|
|
||||||
|
// pawns
|
||||||
|
for (x = 0; x < 8; x++) {
|
||||||
|
grid.add(new Piece('pawn', W), [x, 6]);
|
||||||
|
grid.add(new Piece('pawn', B), [x, 1]);
|
||||||
|
}
|
||||||
|
// major pieces
|
||||||
|
var back = ['rook','knight','bishop','queen','king','bishop','knight','rook'];
|
||||||
|
for (x = 0; x < 8; x++) {
|
||||||
|
grid.add(new Piece(back[x], W), [x, 7]);
|
||||||
|
grid.add(new Piece(back[x], B), [x, 0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { Piece, startingPosition };
|
||||||
BIN
examples/chess/prosperon
Executable file
45
examples/chess/rules.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/* helper – robust coord access */
|
||||||
|
function cx(c) { return (c.x !== undefined) ? c.x : c[0]; }
|
||||||
|
function cy(c) { return (c.y !== undefined) ? c.y : c[1]; }
|
||||||
|
|
||||||
|
/* simple move-shape checks */
|
||||||
|
var deltas = {
|
||||||
|
pawn: function (pc, dx, dy, grid, to) {
|
||||||
|
var dir = (pc.colour === 'white') ? -1 : 1;
|
||||||
|
var base = (pc.colour === 'white') ? 6 : 1;
|
||||||
|
var one = (dy === dir && dx === 0 && grid.at(to).length === 0);
|
||||||
|
var two = (dy === 2 * dir && dx === 0 && cy(pc.coord) === base &&
|
||||||
|
grid.at({ x: cx(pc.coord), y: cy(pc.coord)+dir }).length === 0 &&
|
||||||
|
grid.at(to).length === 0);
|
||||||
|
var cap = (dy === dir && Math.abs(dx) === 1 && grid.at(to).length);
|
||||||
|
return one || two || cap;
|
||||||
|
},
|
||||||
|
rook : function (pc, dx, dy) { return (dx === 0 || dy === 0); },
|
||||||
|
bishop: function (pc, dx, dy) { return Math.abs(dx) === Math.abs(dy); },
|
||||||
|
queen : function (pc, dx, dy) { return (dx === 0 || dy === 0 || Math.abs(dx) === Math.abs(dy)); },
|
||||||
|
knight: function (pc, dx, dy) { return (Math.abs(dx) === 1 && Math.abs(dy) === 2) ||
|
||||||
|
(Math.abs(dx) === 2 && Math.abs(dy) === 1); },
|
||||||
|
king : function (pc, dx, dy) { return Math.max(Math.abs(dx), Math.abs(dy)) === 1; }
|
||||||
|
};
|
||||||
|
|
||||||
|
function clearLine(from, to, grid) {
|
||||||
|
var dx = Math.sign(cx(to) - cx(from));
|
||||||
|
var dy = Math.sign(cy(to) - cy(from));
|
||||||
|
var x = cx(from) + dx, y = cy(from) + dy;
|
||||||
|
while (x !== cx(to) || y !== cy(to)) {
|
||||||
|
if (grid.at({ x: x, y: y }).length) return false;
|
||||||
|
x += dx; y += dy;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function canMove(piece, from, to, grid) {
|
||||||
|
var dx = cx(to) - cx(from);
|
||||||
|
var dy = cy(to) - cy(from);
|
||||||
|
var f = deltas[piece.kind];
|
||||||
|
if (!f || !f(piece, dx, dy, grid, to)) return false;
|
||||||
|
if (piece.kind === 'knight') return true;
|
||||||
|
return clearLine(from, to, grid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { canMove };
|
||||||
BIN
examples/chess/white_bishop.png
Normal file
|
After Width: | Height: | Size: 376 B |
BIN
examples/chess/white_king.png
Normal file
|
After Width: | Height: | Size: 403 B |
BIN
examples/chess/white_knight.png
Normal file
|
After Width: | Height: | Size: 381 B |
BIN
examples/chess/white_pawn.png
Normal file
|
After Width: | Height: | Size: 313 B |
BIN
examples/chess/white_queen.png
Normal file
|
After Width: | Height: | Size: 378 B |
BIN
examples/chess/white_rook.png
Normal file
|
After Width: | Height: | Size: 378 B |