added losing chess
This commit is contained in:
parent
87c59055e3
commit
531d33a56f
|
@ -1188,6 +1188,103 @@ exports.games = (function () {
|
|||
},
|
||||
"viewScripts": config_view_js
|
||||
},
|
||||
{
|
||||
"name": "losing-chess",
|
||||
"modelScripts": [
|
||||
"base-model.js",
|
||||
"grid-geo-model.js",
|
||||
"losing-model.js"
|
||||
],
|
||||
"config": {
|
||||
"status": true,
|
||||
"model": {
|
||||
"title-en": "Losing Chess",
|
||||
"summary": "Also known as Antichess, Suicide Chess, Giveaway Chess, ...",
|
||||
"thumbnail": "knight-inv-thumbnail.png",
|
||||
"module": "chessbase",
|
||||
"plazza": "true",
|
||||
"released": 1495039002,
|
||||
"rules": {
|
||||
"en": "losing-rules.html",
|
||||
},
|
||||
"credits": {
|
||||
"en": "credits.html",
|
||||
"fr": "credits-fr.html"
|
||||
},
|
||||
"gameOptions": config_model_gameOptions,
|
||||
"js": [
|
||||
"base-model.js",
|
||||
"grid-geo-model.js",
|
||||
"losing-model.js"
|
||||
],
|
||||
"levels": config_model_levels_5
|
||||
},
|
||||
"view": {
|
||||
"title-en": "Chessbase view",
|
||||
"visuals": {
|
||||
"600x600": [
|
||||
"res/visuals/classic-chess-600x600-3d.jpg",
|
||||
"res/visuals/classic-chess-600x600-2d.jpg"
|
||||
]
|
||||
},
|
||||
"xdView": true,
|
||||
"css": config_view_css,
|
||||
"preferredRatio": 1,
|
||||
"useShowMoves": true,
|
||||
"useNotation": true,
|
||||
"module": "chessbase",
|
||||
"defaultOptions": config_view_defaultOptions,
|
||||
"skins": [
|
||||
config_view_skins,
|
||||
{
|
||||
"name": "skin3dflat",
|
||||
"title": "3D Flat",
|
||||
"3d": true,
|
||||
"preload": [
|
||||
"smoothedfilegeo|0|/res/ring-target.js",
|
||||
"image|/res/images/cancel.png",
|
||||
"image|/res/images/wikipedia.png",
|
||||
"image|/res/extruded/wood.jpg",
|
||||
"image|/res/extruded/wikipedia-pieces-diffuse-white.jpg",
|
||||
"image|/res/extruded/wikipedia-pieces-diffuse-black.jpg",
|
||||
"smoothedfilegeo|0|/res/extruded/flat3dpieces-king.js",
|
||||
"smoothedfilegeo|0|/res/extruded/flat3dpieces-queen.js",
|
||||
"smoothedfilegeo|0|/res/extruded/flat3dpieces-pawn.js",
|
||||
"smoothedfilegeo|0|/res/extruded/flat3dpieces-rook.js",
|
||||
"smoothedfilegeo|0|/res/extruded/flat3dpieces-knight.js",
|
||||
"smoothedfilegeo|0|/res/extruded/flat3dpieces-bishop.js"
|
||||
],
|
||||
"world": config_view_skins_world,
|
||||
"camera": config_view_skins_camera_2
|
||||
},
|
||||
{
|
||||
"name": "skin2dfull",
|
||||
"title": "2D Classic",
|
||||
"3d": false,
|
||||
"preload": config_view_skins_preload_2
|
||||
},
|
||||
{
|
||||
"name": "skin2dwood",
|
||||
"title": "2D Wood",
|
||||
"3d": false,
|
||||
"preload": [
|
||||
"image|/res/images/cancel.png",
|
||||
"image|/res/images/whitebg.png",
|
||||
"image|/res/images/wikipedia.png",
|
||||
"image|/res/images/woodenpieces2d2.png",
|
||||
"image|/res/images/wood.jpg"
|
||||
]
|
||||
}
|
||||
],
|
||||
"animateSelfMoves": false,
|
||||
"switchable": true,
|
||||
"sounds": config_view_sounds,
|
||||
"js": config_view_js,
|
||||
"useAutoComplete": true
|
||||
}
|
||||
},
|
||||
"viewScripts": config_view_js
|
||||
},
|
||||
{
|
||||
"name": "xiangqi",
|
||||
"modelScripts": modelScripts_2,
|
||||
|
|
BIN
src/games/chessbase/knight-inv-thumbnail.png
Normal file
BIN
src/games/chessbase/knight-inv-thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
340
src/games/chessbase/losing-model.js
Normal file
340
src/games/chessbase/losing-model.js
Normal file
|
@ -0,0 +1,340 @@
|
|||
|
||||
(function() {
|
||||
|
||||
var geometry = Model.Game.cbBoardGeometryGrid(8,8);
|
||||
|
||||
var USE_TYPED_ARRAYS = typeof Int32Array != "undefined";
|
||||
var MASK = 0xffff; // unreachable position
|
||||
var FLAG_MOVE = 0x10000; // move to if target pos empty
|
||||
var FLAG_CAPTURE = 0x20000; // capture if occupied by enemy
|
||||
var FLAG_STOP = 0x40000; // stop if occupied
|
||||
var FLAG_SCREEN_CAPTURE = 0x80000; // capture if occupied by and a piece has been jumped in the path (like cannon in xiangqi)
|
||||
|
||||
Model.Game.cbDefine = function() {
|
||||
|
||||
return {
|
||||
|
||||
geometry: geometry,
|
||||
|
||||
pieceTypes: {
|
||||
|
||||
0: {
|
||||
name: 'pawn-w',
|
||||
aspect: 'pawn',
|
||||
graph: this.cbPawnGraph(geometry,1),
|
||||
value: 1,
|
||||
abbrev: '',
|
||||
fenAbbrev: 'P',
|
||||
epCatch: true,
|
||||
},
|
||||
|
||||
1: {
|
||||
name: 'ipawn-w',
|
||||
aspect: 'pawn',
|
||||
graph: this.cbInitialPawnGraph(geometry,1),
|
||||
value: 1,
|
||||
abbrev: '',
|
||||
fenAbbrev: 'P',
|
||||
initial: [{s:1,p:8},{s:1,p:9},{s:1,p:10},{s:1,p:11},{s:1,p:12},{s:1,p:13},{s:1,p:14},{s:1,p:15}],
|
||||
epTarget: true,
|
||||
},
|
||||
|
||||
2: {
|
||||
name: 'pawn-b',
|
||||
aspect: 'pawn',
|
||||
graph: this.cbPawnGraph(geometry,-1),
|
||||
value: 1,
|
||||
abbrev: '',
|
||||
fenAbbrev: 'P',
|
||||
epCatch: true,
|
||||
},
|
||||
|
||||
3: {
|
||||
name: 'ipawn-b',
|
||||
aspect: 'pawn',
|
||||
graph: this.cbInitialPawnGraph(geometry,-1),
|
||||
value: 1,
|
||||
abbrev: '',
|
||||
fenAbbrev: 'P',
|
||||
initial: [{s:-1,p:48},{s:-1,p:49},{s:-1,p:50},{s:-1,p:51},{s:-1,p:52},{s:-1,p:53},{s:-1,p:54},{s:-1,p:55}],
|
||||
epTarget: true,
|
||||
},
|
||||
|
||||
4: {
|
||||
name: 'knight',
|
||||
graph: this.cbKnightGraph(geometry),
|
||||
value: 2.9,
|
||||
abbrev: 'N',
|
||||
initial: [{s:1,p:1},{s:1,p:6},{s:-1,p:57},{s:-1,p:62}],
|
||||
},
|
||||
|
||||
5: {
|
||||
name: 'bishop',
|
||||
graph: this.cbBishopGraph(geometry),
|
||||
value: 3.1,
|
||||
abbrev: 'B',
|
||||
initial: [{s:1,p:2},{s:1,p:5},{s:-1,p:58},{s:-1,p:61}],
|
||||
},
|
||||
|
||||
6: {
|
||||
name: 'rook',
|
||||
graph: this.cbRookGraph(geometry),
|
||||
value: 5,
|
||||
abbrev: 'R',
|
||||
initial: [{s:1,p:0},{s:1,p:7},{s:-1,p:56},{s:-1,p:63}],
|
||||
},
|
||||
|
||||
7: {
|
||||
name: 'queen',
|
||||
graph: this.cbQueenGraph(geometry),
|
||||
value: 9,
|
||||
abbrev: 'Q',
|
||||
initial: [{s:1,p:3},{s:-1,p:59}],
|
||||
},
|
||||
|
||||
8: {
|
||||
name: 'king',
|
||||
graph: this.cbKingGraph(geometry),
|
||||
abbrev: 'K',
|
||||
initial: [{s:1,p:4},{s:-1,p:60}],
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
promote: function(aGame,piece,move) {
|
||||
if(piece.t==1)
|
||||
return [0];
|
||||
else if(piece.t==3)
|
||||
return [2];
|
||||
else if(piece.t==0 && geometry.R(move.t)==7)
|
||||
return [4,5,6,7,8];
|
||||
else if(piece.t==2 && geometry.R(move.t)==0)
|
||||
return [4,5,6,7,8];
|
||||
return [];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Model.Board.Evaluate = function(aGame) {
|
||||
var debug=arguments[3]=="debug";
|
||||
var $this=this;
|
||||
this.mEvaluation=0;
|
||||
var who=this.mWho;
|
||||
var g=aGame.g;
|
||||
var material;
|
||||
if(USE_TYPED_ARRAYS)
|
||||
material={
|
||||
'1': {
|
||||
count: new Uint8Array(g.pTypes.length),
|
||||
byType: {},
|
||||
},
|
||||
'-1': {
|
||||
count: new Uint8Array(g.pTypes.length),
|
||||
byType: {},
|
||||
}
|
||||
}
|
||||
else {
|
||||
material={
|
||||
'1': {
|
||||
count: [],
|
||||
byType: {},
|
||||
},
|
||||
'-1': {
|
||||
count: [],
|
||||
byType: {},
|
||||
}
|
||||
}
|
||||
for(var i=0;i<g.pTypes.length;i++)
|
||||
material["1"].count[i]=material["-1"].count[i]=0;
|
||||
}
|
||||
|
||||
if(aGame.mOptions.preventRepeat && aGame.GetRepeatOccurence(this)>2) {
|
||||
this.mFinished=true;
|
||||
this.mWinner=aGame.cbOnPerpetual?who*aGame.cbOnPerpetual:JocGame.DRAW;
|
||||
return;
|
||||
}
|
||||
|
||||
var pieceValue={ '1': 0, '-1': 0 };
|
||||
var pieceCount={ '1': 0, '-1': 0 };
|
||||
var posValue={ '1': 0, '-1': 0 };
|
||||
|
||||
var pieces=this.pieces;
|
||||
var piecesLength=pieces.length;
|
||||
for(var i=0;i<piecesLength;i++) {
|
||||
var piece=pieces[i];
|
||||
if(piece.p>=0) {
|
||||
var s=piece.s;
|
||||
var pType=g.pTypes[piece.t];
|
||||
pieceValue[s]+=pType.value;
|
||||
pieceCount[s]++;
|
||||
posValue[s]+=aGame.cbVar.geometry.distEdge[piece.p];
|
||||
var mat=material[s];
|
||||
mat.count[piece.t]++;
|
||||
var byType=mat.byType;
|
||||
if(byType[piece.t]===undefined)
|
||||
byType[piece.t]=[piece];
|
||||
else
|
||||
byType[piece.t].push(piece);
|
||||
}
|
||||
}
|
||||
|
||||
if(pieceCount['1']==0) {
|
||||
this.mFinished = true;
|
||||
this.mWinner = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if(pieceCount['-1']==0) {
|
||||
this.mFinished = true;
|
||||
this.mWinner = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.lastMove && this.lastMove.c!=null) {
|
||||
var piece=this.pieces[this.board[this.lastMove.t]];
|
||||
pieceValue[-piece.s]+=this.cbStaticExchangeEval(aGame,piece.p,piece.s,{piece:piece})
|
||||
}
|
||||
|
||||
var evalValues={
|
||||
"pieceValue": pieceValue['-1']-pieceValue['1'],
|
||||
"pieceValueRatio": (pieceValue['-1']-pieceValue['1'])/(pieceValue['-1']+pieceValue['1']+1),
|
||||
"posValue": posValue['-1']-posValue['1']
|
||||
}
|
||||
|
||||
var evParams=aGame.mOptions.levelOptions;
|
||||
for(var name in evalValues) {
|
||||
var value=evalValues[name];
|
||||
var factor=evParams[name+'Factor'] || 0;
|
||||
var weighted=value*factor;
|
||||
if(debug)
|
||||
console.log(name,"=",value,"*",factor,"=>",weighted);
|
||||
this.mEvaluation+=weighted;
|
||||
}
|
||||
if(debug)
|
||||
console.log("Evaluation",this.mEvaluation);
|
||||
}
|
||||
|
||||
Model.Board.cbGeneratePseudoLegalMoves = function(aGame) {
|
||||
var $this=this;
|
||||
var moves=[];
|
||||
var cbVar=aGame.cbVar;
|
||||
var who=this.mWho;
|
||||
|
||||
function PromotedMoves(piece,move) {
|
||||
var promoFnt=aGame.cbVar.promote;
|
||||
if(!promoFnt) {
|
||||
moves.push(move);
|
||||
return;
|
||||
}
|
||||
var promo=promoFnt.call($this,aGame,piece,move);
|
||||
if(promo==null)
|
||||
return;
|
||||
if(promo.length==0)
|
||||
moves.push(move);
|
||||
else if(promo.length==1) {
|
||||
move.pr=promo[0];
|
||||
moves.push(move);
|
||||
} else {
|
||||
for(var i=0;i<promo.length;i++) {
|
||||
var pr=promo[i];
|
||||
moves.push({
|
||||
f: move.f,
|
||||
t: move.t,
|
||||
c: move.c,
|
||||
pr: pr,
|
||||
ept: move.ept,
|
||||
ep: move.ep,
|
||||
a: move.a,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var piecesLength=this.pieces.length;
|
||||
for(var i=0;i<piecesLength;i++) {
|
||||
var piece=this.pieces[i];
|
||||
if(piece.p<0 || piece.s!=who)
|
||||
continue;
|
||||
var pType=aGame.g.pTypes[piece.t];
|
||||
|
||||
var graph, graphLength;
|
||||
graph=pType.graph[piece.p];
|
||||
graphLength=graph.length;
|
||||
for(var j=0;j<graphLength;j++) {
|
||||
var line=graph[j];
|
||||
var screen=false;
|
||||
var lineLength=line.length;
|
||||
var lastPos=null;
|
||||
for(var k=0;k<lineLength;k++) {
|
||||
var tg1=line[k];
|
||||
var pos1=tg1 & MASK;
|
||||
var index1=this.board[pos1];
|
||||
if(index1<0 && (!pType.epCatch || !this.epTarget || this.epTarget.p!=pos1)) {
|
||||
if((tg1 & FLAG_MOVE) && screen==false)
|
||||
PromotedMoves(piece,{
|
||||
f: piece.p,
|
||||
t: pos1,
|
||||
c: null,
|
||||
a: pType.abbrev,
|
||||
ept: lastPos==null || !pType.epTarget?undefined:lastPos,
|
||||
});
|
||||
} else if(tg1 & FLAG_SCREEN_CAPTURE) {
|
||||
if(screen) {
|
||||
var piece1=this.pieces[index1];
|
||||
if(piece1.s!=piece.s)
|
||||
PromotedMoves(piece,{
|
||||
f: piece.p,
|
||||
t: pos1,
|
||||
c: piece1.i,
|
||||
a: pType.abbrev,
|
||||
});
|
||||
break;
|
||||
} else
|
||||
screen=true;
|
||||
} else {
|
||||
var piece1;
|
||||
if(index1<0)
|
||||
piece1=this.pieces[this.epTarget.i];
|
||||
else
|
||||
piece1=this.pieces[index1];
|
||||
if(piece1.s!=piece.s && (tg1 & FLAG_CAPTURE))
|
||||
PromotedMoves(piece,{
|
||||
f: piece.p,
|
||||
t: pos1,
|
||||
c: piece1.i,
|
||||
a: pType.abbrev,
|
||||
ep: index1<0,
|
||||
});
|
||||
break;
|
||||
}
|
||||
lastPos=pos1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return moves;
|
||||
}
|
||||
|
||||
Model.Board.GenerateMoves = function(aGame) {
|
||||
var moves=this.cbGeneratePseudoLegalMoves(aGame);
|
||||
var captMoves = [];
|
||||
var nonCaptMoves = [];
|
||||
for(var i=0; i<moves.length; i++) {
|
||||
var move = moves[i];
|
||||
if(move.c!=null)
|
||||
captMoves.push(move);
|
||||
else
|
||||
nonCaptMoves.push(move);
|
||||
}
|
||||
if(captMoves.length>0)
|
||||
this.mMoves = captMoves;
|
||||
else
|
||||
this.mMoves = nonCaptMoves;
|
||||
|
||||
if(this.mMoves.length==0) {
|
||||
this.mFinished=true;
|
||||
this.mWinner=this.mWho;
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
49
src/games/chessbase/losing-rules.html
Normal file
49
src/games/chessbase/losing-rules.html
Normal file
|
@ -0,0 +1,49 @@
|
|||
<style>
|
||||
table.psymbs {
|
||||
text-align: center;
|
||||
}
|
||||
.psymb {
|
||||
background-image: url({GAME}/res/images/wikipedia.png);
|
||||
width: 100px;
|
||||
height: 200px;
|
||||
}
|
||||
.psymbs td {
|
||||
padding: 0 10px 0 10px;
|
||||
}
|
||||
.psymb-bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.side {
|
||||
float: right;
|
||||
max-width: 100%;
|
||||
}
|
||||
@media screen and (max-width: 520px) {
|
||||
.side {
|
||||
float: none;
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
h1,h2,h3,h4 {
|
||||
clear: both;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Losing Chess is a game played by two people on a chessboard, with sixteen pieces (of six types) for each player. Each type of piece moves in a distinct way.
|
||||
The goal of the game is be unable to make a move, either by not having any piece left on the board, or
|
||||
by having all remaining pieces blocked.</p>
|
||||
|
||||
<p>Losing Chess follows the normal <a href="http://en.wikipedia.org/wiki/Rules_of_chess" target="_blank">Chess rules</a>,
|
||||
with the following changes:</p>
|
||||
|
||||
<ul>
|
||||
<li>capturing is compulsary: if there is a possible move that captures an opponent's piece, then
|
||||
any move that does not result in a capture is invalid</li>
|
||||
<li>the king has no special status: it can be captured and checks are not considered</li>
|
||||
<li>castling is not possible</li>
|
||||
<li>a pawn reaching the last row can promote to a king (in addition to Knight, Bishop, Rook and Queen)</li>
|
||||
<li>stalemate is a win for the player that cannot make a move</li>
|
||||
</ul>
|
Loading…
Reference in a new issue