crazyhouse wip

pull/1472/merge
Thibault Duplessis 2016-01-18 14:21:52 +07:00
parent 4769602481
commit f8c8b5af58
6 changed files with 94 additions and 53 deletions

@ -1 +1 @@
Subproject commit 4491a857ac163f2c987edabce9f7b0e7e42f540a
Subproject commit b11e59479d41a316502e6b5fe111f3946867f58d

View File

@ -30,8 +30,40 @@ object Event {
def typ = "start"
}
private def withCrazyData(data: Option[Crazyhouse.Data])(js: JsObject): JsObject =
data.fold(js) { d => js + ("crazyhouse" -> crazyhouseDataWriter.writes(d)) }
private def withCrazyData(
data: Option[Crazyhouse.Data],
drops: Option[List[Pos]])(js: JsObject): JsObject =
data.fold(js) { d =>
val js1 = js + ("crazyhouse" -> crazyhouseDataWriter.writes(d))
drops.fold(js1) { squares =>
js1 + ("drops" -> JsString(squares.map(_.key).mkString))
}
}
object MoveOrDrop {
def data(
fen: String,
check: Boolean,
threefold: Boolean,
state: State,
clock: Option[Event],
possibleMoves: Map[Pos, List[Pos]],
possibleDrops: Option[List[Pos]],
crazyData: Option[Crazyhouse.Data])(extra: JsObject) = {
extra ++ Json.obj(
"fen" -> fen,
"check" -> check.option(true),
"threefold" -> threefold.option(true),
"ply" -> state.turns,
"status" -> state.status,
"winner" -> state.winner,
"wDraw" -> state.whiteOffersDraw.option(true),
"bDraw" -> state.blackOffersDraw.option(true),
"clock" -> clock.map(_.data),
"dests" -> PossibleMoves.json(possibleMoves))
}.noNull |> withCrazyData(crazyData, possibleDrops)
}
case class Move(
orig: Pos,
@ -46,25 +78,17 @@ object Event {
state: State,
clock: Option[Event],
possibleMoves: Map[Pos, List[Pos]],
possibleDrops: Option[List[Pos]],
crazyData: Option[Crazyhouse.Data]) extends Event {
def typ = "move"
def data = Json.obj(
"uci" -> s"${orig.key}${dest.key}",
"san" -> san,
"fen" -> fen,
"check" -> check.option(true),
"threefold" -> threefold.option(true),
"promotion" -> promotion.map(_.data),
"enpassant" -> enpassant.map(_.data),
"castle" -> castle.map(_.data),
"ply" -> state.turns,
"status" -> state.status,
"winner" -> state.winner,
"wDraw" -> state.whiteOffersDraw.option(true),
"bDraw" -> state.blackOffersDraw.option(true),
"clock" -> clock.map(_.data),
"dests" -> PossibleMoves.json(possibleMoves)
).noNull |> withCrazyData(crazyData)
def data = MoveOrDrop.data(fen, check, threefold, state, clock, possibleMoves, possibleDrops, crazyData) {
Json.obj(
"uci" -> s"${orig.key}${dest.key}",
"san" -> san,
"promotion" -> promotion.map(_.data),
"enpassant" -> enpassant.map(_.data),
"castle" -> castle.map(_.data))
}
}
object Move {
def apply(move: ChessMove, situation: Situation, state: State, clock: Option[Event], crazyData: Option[Crazyhouse.Data]): Move = Move(
@ -84,6 +108,7 @@ object Event {
state = state,
clock = clock,
possibleMoves = situation.destinations,
possibleDrops = situation.drops,
crazyData = crazyData)
}
@ -97,23 +122,15 @@ object Event {
state: State,
clock: Option[Event],
possibleMoves: Map[Pos, List[Pos]],
crazyData: Option[Crazyhouse.Data]) extends Event {
crazyData: Option[Crazyhouse.Data],
possibleDrops: Option[List[Pos]]) extends Event {
def typ = "drop"
def data = Json.obj(
"role" -> role.name,
"uci" -> s"${role.pgn}@${pos.key}",
"san" -> san,
"fen" -> fen,
"check" -> check.option(true),
"threefold" -> threefold.option(true),
"ply" -> state.turns,
"status" -> state.status,
"winner" -> state.winner,
"wDraw" -> state.whiteOffersDraw.option(true),
"bDraw" -> state.blackOffersDraw.option(true),
"clock" -> clock.map(_.data),
"dests" -> PossibleMoves.json(possibleMoves)
).noNull |> withCrazyData(crazyData)
def data = MoveOrDrop.data(fen, check, threefold, state, clock, possibleMoves, possibleDrops, crazyData) {
Json.obj(
"role" -> role.name,
"uci" -> s"${role.pgn}@${pos.key}",
"san" -> san)
}
}
object Drop {
def apply(drop: ChessDrop, situation: Situation, state: State, clock: Option[Event], crazyData: Option[Crazyhouse.Data]): Drop = Drop(
@ -126,17 +143,10 @@ object Event {
state = state,
clock = clock,
possibleMoves = situation.destinations,
possibleDrops = situation.drops,
crazyData = crazyData)
}
case class PossibleMoves(
color: Color,
moves: Map[Pos, List[Pos]]) extends Event {
def typ = "possibleMoves"
def data = PossibleMoves json moves
override def only = Some(color)
}
object PossibleMoves {
def json(moves: Map[Pos, List[Pos]]) =
if (moves.isEmpty) JsNull

View File

@ -5,10 +5,11 @@ import scala.math
import play.api.libs.json._
import chess.variant.Crazyhouse
import lila.common.Maths.truncateAt
import lila.common.PimpedJson._
import lila.game.{ Pov, Game, PerfPicker, Source, GameRepo, CorrespondenceClock }
import lila.game.JsonView._
import lila.game.{ Pov, Game, PerfPicker, Source, GameRepo, CorrespondenceClock }
import lila.pref.Pref
import lila.user.{ User, UserRepo }
@ -120,6 +121,7 @@ final class JsonView(
})
},
"possibleMoves" -> possibleMoves(pov),
"possibleDrops" -> possibleDrops(pov),
"takebackable" -> takebackable,
"crazyhouse" -> pov.game.crazyData).noNull
}
@ -301,6 +303,12 @@ final class JsonView(
}
}
private def possibleDrops(pov: Pov) = (pov.game playableBy pov.player) ?? {
pov.game.toChess.situation.drops map { drops =>
JsString(drops.map(_.key).mkString)
}
}
private def animationFactor(pref: Pref): Float = pref.animation match {
case 0 => 0
case 1 => 0.5f

View File

@ -29,7 +29,7 @@
"watchify": "~3.1.1"
},
"dependencies": {
"chessground": "github:ornicar/chessground#v3.3.0",
"chessground": "github:ornicar/chessground#v3.3.1",
"game": "file:../game",
"mithril": "github:ornicar/mithril.js#v1.0.0"
}

View File

@ -0,0 +1,15 @@
var util = require('./util');
module.exports = {
validateDrop: function(chessground, dropStr, piece, pos) {
if (piece.role === 'pawn' && (pos[1] === '1' || pos[1] === '8')) return false;
if (typeof dropStr === 'undefined' || dropStr === null) return true;
var drops = dropStr.match(/.{2}/g) || [];
return drops.indexOf(pos) !== -1;
}
};

View File

@ -18,6 +18,7 @@ var moveOn = require('./moveOn');
var atomic = require('./atomic');
var sound = require('./sound');
var util = require('./util');
var crazyhouse = require('./crazyhouse');
module.exports = function(opts) {
@ -58,7 +59,9 @@ module.exports = function(opts) {
}.bind(this);
var onUserNewPiece = function(piece, pos) {
this.sendNewPiece(piece.role, pos);
if (crazyhouse.validateDrop(this.chessground, this.data.possibleDrops, piece, pos))
this.sendNewPiece(piece.role, pos);
else this.jump(this.vm.ply);
}.bind(this);
var onMove = function(orig, dest, captured) {
@ -151,7 +154,7 @@ module.exports = function(opts) {
role: role,
pos: pos
};
if (this.clock) move.lag = Math.round(lichess.socket.averageLag);
if (this.clock) drop.lag = Math.round(lichess.socket.averageLag);
this.resign(false);
this.socket.send('drop', drop, {
ackable: true
@ -165,7 +168,8 @@ module.exports = function(opts) {
this.apiMove = function(o) {
m.startComputation();
var d = this.data;
var d = this.data,
playing = game.isPlayerPlaying(d);
d.game.turns = o.ply;
d.game.player = o.ply % 2 === 0 ? 'white' : 'black';
var playedColor = o.ply % 2 === 0 ? 'black' : 'white';
@ -174,12 +178,16 @@ module.exports = function(opts) {
d[d.player.color === 'white' ? 'player' : 'opponent'].offeringDraw = o.wDraw;
d[d.player.color === 'black' ? 'player' : 'opponent'].offeringDraw = o.bDraw;
d.possibleMoves = d.player.color === d.game.player ? o.dests : null;
d.possibleDrops = d.player.color === d.game.player ? o.drops : null;
d.crazyhouse = o.crazyhouse;
this.setTitle();
if (!this.replaying()) {
this.vm.ply++;
if (o.isMove) this.chessground.apiMove(o.uci.substr(0, 2), o.uci.substr(2, 2));
else this.chessground.apiNewPiece({role: o.role, color: playedColor}, o.uci.substr(2, 2));
else this.chessground.apiNewPiece({
role: o.role,
color: playedColor
}, o.uci.substr(2, 2));
if (o.enpassant) {
var p = o.enpassant,
pieces = {};
@ -209,7 +217,7 @@ module.exports = function(opts) {
this.chessground.set({
turnColor: d.game.player,
movable: {
dests: game.isPlayerPlaying(d) ? util.parsePossibleMoves(d.possibleMoves) : {}
dests: playing ? util.parsePossibleMoves(d.possibleMoves) : {}
},
check: o.check
});
@ -227,13 +235,13 @@ module.exports = function(opts) {
san: o.san,
uci: o.uci,
check: o.check,
crazyhouse: o.crazyhouse
crazy: o.crazyhouse
});
game.setOnGame(d, playedColor, true);
delete this.data.forecastCount;
m.endComputation();
if (d.blind) blind.reload(this);
if (game.isPlayerPlaying(d) && playedColor === d.player.color) this.moveOn.next();
if (playing && playedColor === d.player.color) this.moveOn.next();
if (!this.replaying() && playedColor !== d.player.color) {
// atrocious hack to prevent race condition