Skip to content

Instantly share code, notes, and snippets.

@valex
Created September 18, 2020 11:00
Show Gist options
  • Save valex/c658e953db633abe32473d49e6757db4 to your computer and use it in GitHub Desktop.
Save valex/c658e953db633abe32473d49e6757db4 to your computer and use it in GitHub Desktop.
<template>
<div>
<div class="position-relative">
<div class="blue merida">
<div class="cg-board-wrap" ref="board">
</div>
</div>
<PromotionChoice v-if=" ! _.isNull(promotion)"
@mousedown="onPromotionCancel"
@promote="onPromote"
:left="promotion.left"
:position="promotionMenuPosition"
:color="promotion.color"></PromotionChoice>
</div>
<div v-if="controls" class="controls-row">
<div :class="{'black':turn==='b', 'white':turn==='w'}" class="turn">
<span v-show="turn==='w'">Ход белых</span>
<span v-show="turn==='b'">Ход черных</span>
</div>
<div class="controls">
<button @mousedown="onHistoryBack" :disabled="history_last_index <= -1" type="button" class="btn border-0 btn-light"><font-awesome-icon icon="caret-left" size="2x" /></button>
<button @mousedown="onBoardRotate" type="button" class="btn border-0 btn-light"><font-awesome-icon icon="sync-alt" size="2x" /></button>
<button @mousedown="onHistoryForward" :disabled="_.isEmpty(history) || (_.size(history) - 1 === history_last_index)" type="button" class="btn border-0 btn-light"><font-awesome-icon icon="caret-right" size="2x" /></button>
</div>
</div>
</div>
</template>
<script lang="js">
import PromotionChoice from '../components/PromotionChoice.vue'
import { Chessground } from 'chessground';
import * as util from 'chessground/util';
import Chessjs from 'chess.js'
export default {
name: 'ChessgroundComponent',
cg: null,
backedUpCgConfig: null, // for restore previous move
chess: null,
components: {
PromotionChoice
},
props: {
fen:{
type: String,
},
initialOrientation:{ // 'white', 'black'
type: String,
default: 'white'
},
notation:{
type: Boolean,
default: true
},
controls:{
type: Boolean,
default: true
}
},
mounted() {
this.$options.chess = new Chessjs(this.fen+' 0 1');
this.updateState();
const el = this.$refs.board;
const bounding = el.getBoundingClientRect();
el.setAttribute("style", "width:"+bounding.width+"px; height:"+bounding.width+"px;");
this.$options.cg = Chessground(el, {
fen:this.$options.chess.fen(),
orientation: this.initialOrientation,
turnColor: this.turnColor,
movable: {
color: this.turnColor,
free: false,
dests: this.toDests(),
events: {
after: this.afterMove
}
},
check: this.in_check,
draggable: {
showGhost: true
},
premovable:{
enabled: false
},
drawable:{
enabled: true, // can draw
visible: true, // can view
eraseOnClick: false
}
});
this.backupCgConfig();
// this.$options.cg.set({
// drawable:{
// eraseOnClick: false,
// brushes:{'grey':{
// key:'gr',
// color:'#FF0000',
// opacity: 1,
// lineWidth:10
// }}
// }
// })
},
data() {
return {
promotion: null,
turn: null,
in_check: null,
in_checkmate: null,
in_stalemate: null,
insufficient_material: null,
history: [],
history_last_index: -1,
orientation: this.initialOrientation,
}
},
methods: {
updateState(){
this.turn = this.$options.chess.turn();
this.in_check = this.$options.chess.in_check();
this.in_checkmate = this.$options.chess.in_checkmate();
this.insufficient_material = this.$options.chess.insufficient_material();
this.in_stalemate = this.$options.chess.in_stalemate();
},
updateHistory(){
this.history = this.$options.chess.history({ verbose: true });
this.history_last_index = _.size(this.history) - 1;
console.log(_.last(this.history));
},
updateChessground(){
let cgState = {
fen: this.$options.chess.fen(),
turnColor: this.turnColor,
check: this.in_check,
selected: undefined,
movable: {
color: this.turnColor,
dests: this.toDests(),
},
lastMove: this.lastMoveFromTo(),
selectable: {
enabled : true
},
draggable: {
enabled : true
},
};
if(this.in_checkmate || this.in_stalemate || this.insufficient_material){
cgState = _.assign(cgState, {
movable: {
color: undefined,
dests: undefined,
},
selectable: {
enabled : false
},
draggable: {
enabled : false
},
});
}
this.$options.cg.set(cgState);
this.backupCgConfig();
},
// will not be call on history move
afterMove(orig, dest, meta){
if( ! this.startPromotion(orig, dest, this.makeBoardMove)){
this.makeBoardMove(orig,dest,meta);
}
},
makeBoardMove(orig, dest, meta){
let chessjsMoveObject = {from: orig, to: dest};
if(_.has(meta, 'promotion')){
// const piece = this.$options.cg.state.pieces[dest];
// if (piece && piece.role === 'pawn') {
// const pieces = {};
// pieces[dest] = {
// color: piece.color,
// role: meta.promotion,
// promoted: true
// };
// this.$options.cg.setPieces(pieces);
// }
switch(meta.promotion){
case 'queen':
chessjsMoveObject['promotion'] = 'q';
break;
case 'knight':
chessjsMoveObject['promotion'] = 'n';
break;
case 'rook':
chessjsMoveObject['promotion'] = 'r';
break;
case 'bishop':
chessjsMoveObject['promotion'] = 'b';
break;
}
}
this.makeMove(chessjsMoveObject);
},
makeJSMove(move){
this.makeMove(move);
},
makeMove(moveObject){
const from_fen = this.$options.chess.fen();
this.$options.chess.move(moveObject);
this.updateState();
this.updateHistory();
this.updateChessground();
// let cgState = {
// turnColor: this.turnColor,
// check: this.in_check,
// movable: {
// color: this.turnColor,
// dests: this.toDests(),
// }
// };
// if(orig[0] != dest[0]){ //check for enpassant
// const piece = this.$options.cg.state.pieces[dest];
// if (piece && piece.role === 'pawn') {
// cgState['fen'] = this.$options.chess.fen();
// }
// }
this.$emit('move', from_fen);
},
onHistoryBack(){
if(this.history_last_index <= -1)
return;
this.$options.chess.undo();
this.history_last_index--;
this.updateState();
this.updateChessground();
this.$emit('history-move');
},
onHistoryForward(){
let next_history_index;
next_history_index = 1 + this.history_last_index;
if(_.isNil(this.history[next_history_index]))
return;
this.history_last_index = next_history_index;
const move = this.history[this.history_last_index];
this.$options.chess.move(move);
this.updateState();
this.updateChessground();
this.$emit('history-move');
},
startPromotion(orig, dest, callback){
let s = this.$options.cg.state;
let piece = s.pieces[dest];
if(piece &&
piece.role == 'pawn' &&
((dest[1] == '8' && s.turnColor == 'black') ||
(dest[1] == '1' && s.turnColor == 'white')))
{
let left = (8 - util.key2pos(dest)[0]) * 12.5;
if (this.orientation === 'white') left = 87.5 - left;
this.promotion={
orig,
dest,
callback,
color: piece.color,
left
};
return true;
}
return false;
},
onPromote(role){
if (this.promotion.callback) {
this.promotion.callback(this.promotion.orig, this.promotion.dest, {promotion:role});
}
this.promotion = null;
},
onPromotionCancel(){
this.$options.cg.set(this.$options.backedUpCgConfig);
this.promotion = null;
},
onBoardRotate(){
this.toggleOrientation();
},
toggleOrientation(){
this.orientation = this.orientation === 'white' ? 'black' : 'white';
this.$options.cg.toggleOrientation();
},
toDests(){
const dests = {};
this.$options.chess.SQUARES.forEach(s => {
const ms = this.$options.chess.moves({square: s, verbose: true});
if (ms.length) dests[s] = ms.map(m => m.to);
});
return dests;
},
lastMove() {
let history = this.$options.chess.history({ verbose: true });
if(_.isEmpty(history))
return null;
return _.last(history);
},
lastMoveFromTo() {
const lastMove = this.lastMove();
if(_.isNil(lastMove))
return [];
return [lastMove.from, lastMove.to]
},
backupCgConfig(){
let s = this.$options.cg.state;
this.$options.backedUpCgConfig = {
fen : this.$options.cg.getFen(),
turnColor : s.turnColor,
movable : {
color: s.movable.color,
dests: s.movable.dests
},
check: this.in_check,
lastMove: s.lastMove
};
}
},
computed: {
_(){
return _;
},
turnColor() {
return (this.turn === 'w') ? 'white' : 'black';
},
promotionMenuPosition(){
if(_.isNil(this.promotion))
return;
if(this.promotion.color === 'white' && this.orientation === 'black')
return 'bottom';
if(this.promotion.color === 'black' && this.orientation === 'white')
return 'bottom';
return 'top';
},
},
}
</script>
<style scoped>
.controls-row{
display:flex;
flex: 1 1 200px;
flex-direction: row;
justify-content: space-between;
align-items: stretch;
width: 100%;
height: 40px;
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome and Opera */
}
.controls-row .turn{
text-shadow: 0 1px 1px #000;
overflow: hidden;
display:flex;
flex-direction: row;
align-items:center;
}
.controls-row .turn.white{
background-color: white;
border: 1px solid lightgrey;
}
.controls-row .turn.black{
background-color: #444444;
color: white;
text-shadow: 0 1px 1px #FFFFFF;
}
.controls-row .turn span{
padding: 0 1.5rem;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment