Created
May 16, 2017 07:33
-
-
Save triestpa/4c006aef041561e1dda2f280e1feab09 to your computer and use it in GitHub Desktop.
Test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ChessGame from './utils/chessgame' | |
/** | |
* Chessboard VueJS Component. | |
* Takes a PGN string and a side (w or b) as props | |
*/ | |
export default { | |
name: 'chessboard', | |
props: { | |
/** Pgn is a string encoded with the current game state */ | |
pgn: { | |
type: String, | |
default: null | |
}, | |
/** side is either 'w' or 'b', and determines which board orientation to display */ | |
side: { | |
type: String, | |
default: 'w' | |
} | |
}, | |
model: { | |
prop: 'pgn', | |
event: 'change' | |
}, | |
data () { | |
return { | |
chessGame: null, // the game logic class | |
availableMoves: {}, // key/value obj of available moves | |
selectedIndex: -1, // the currently selected square | |
squareStyle: { // Square style - values will be reset whenever window is resized | |
height: '100px', | |
width: '100px' | |
} | |
} | |
}, | |
computed: { | |
/** Return the board array to be displayed */ | |
board () { | |
return this.chessGame.getBoard() | |
}, | |
/** Return if it is black or white's turn */ | |
turn () { | |
return this.chessGame.getTurn() | |
} | |
}, | |
watch: { | |
/** Watch the PGN property so that the game can receive new moves from outside the component */ | |
'pgn': function (newVal, oldVal) { | |
this.syncToPgn(newVal) | |
}, | |
/** Watch the side property so that the UI reflects side-swaps */ | |
'side': function (newVal, oldVal) { | |
// Set the board orientation whenever the side changes | |
this.chessGame.setSide(newVal) | |
this.selectedIndex = -1 | |
this.availableMoves = {} | |
} | |
}, | |
created () { | |
// Initialize a new game for the provided pgn and side properties | |
this.chessGame = new ChessGame(this.pgn, this.side) | |
}, | |
mounted () { | |
// On mounted,set the square width and hight | |
this.$nextTick(() => { | |
// Reset sqaure size every time window resizes | |
window.addEventListener('resize', this.getSquareStyle) | |
this.getSquareStyle() | |
}) | |
}, | |
methods: { | |
/** Set the square width/height to 1/8 of the total board width */ | |
getSquareStyle (event) { | |
const board = this.$refs.board | |
if (board) { | |
// Subtract 1 from total width to avoid pixel-wrapping edge-case | |
const squareEdgeLength = (board.offsetWidth - 1) / 8 | |
this.squareStyle = { | |
height: `${squareEdgeLength}px`, | |
width: `${squareEdgeLength}px` | |
} | |
} | |
}, | |
/** Apply a new move to the board */ | |
applyNewMove (newMove) { | |
const srcIndex = this.chessGame.getIndexForPositionString(newMove.from) | |
const targetIndex = this.chessGame.getIndexForPositionString(newMove.to) | |
this.movePiece(srcIndex, targetIndex) | |
}, | |
/** Check if a square index is an available move */ | |
isAvailableMove (index) { | |
return (this.availableMoves[index] === true) | |
}, | |
/** Recieve a new pgn, and sync the displayed board to it */ | |
syncToPgn (newPgn) { | |
// Generate a new game with the new pgn | |
const newGame = new ChessGame(newPgn) | |
// Get the histories for the two games | |
const newHistory = newGame.getHistory() | |
const oldHistory = this.chessGame.getHistory() | |
// If the new pgn is one move ahead of the old, make the connecting move | |
if (newHistory.length === oldHistory.length + 1) { | |
this.applyNewMove(newHistory.pop()) | |
// Else if they are not the same length, reset the whole board to the new pgn | |
} else if (newHistory.length !== oldHistory.length) { | |
this.chessGame = new ChessGame(this.pgn, this.side) | |
} | |
}, | |
/** Get the icon for the piece */ | |
getIcon (square) { | |
if (square.piece) { | |
return require(`../../assets/icons/${square.piece.color}${square.piece.type}.svg`) | |
} | |
}, | |
/** Reset the board to original position */ | |
reset () { | |
this.chessGame.reset() | |
this.syncBoard() | |
}, | |
/** Animate piece from one index to another */ | |
swap (oldIndex = 0, newIndex = 0) { | |
const temp = this.board[newIndex] | |
this.$set(this.board, newIndex, this.board[oldIndex]) | |
this.$set(this.board, oldIndex, temp) | |
}, | |
/** Move a piece to the target index, if move is valid */ | |
movePiece (source, target) { | |
const result = this.chessGame.calculateMove(source, target) | |
// if result is undefined, move is invalid | |
if (result) { | |
this.swap(target, source) // Swap the contents of the squares | |
this.syncBoard() // Sync the piece position with the board model | |
this.availableMoves = {} // Reset available moves | |
// Emit the move to any parent components | |
setTimeout(() => this.$emit('change', this.chessGame.getPGN()), 200) | |
} | |
}, | |
/** Sync the displayed board with the chessgame object. */ | |
syncBoard () { | |
/** | |
* Why not just use "this.board = this.chessGame.getBoard()"? It has to do with | |
* how Vuejs handles reactivity within arrays. Long-story-short, in order to sync | |
* any side-effects from the move, such as castles, promotions, and captures, it is best | |
* for our purposes to manually assign the changed pieces within the array item. | |
*/ | |
const updatedBoard = this.chessGame.getBoard() | |
for (let i = 0; i < updatedBoard.length; i++) { | |
if (this.board[i].piece !== updatedBoard[i].piece) { | |
this.board[i].piece = updatedBoard[i].piece | |
} | |
} | |
}, | |
/** Display all available moves for the selected piece */ | |
getAvailableMoves (index) { | |
this.selectedIndex = index | |
const moves = this.chessGame.getAvailableMoves(index) | |
if (moves.length < 1) { | |
// If no available moves, de-select the square | |
this.selectedIndex = -1 | |
} else { | |
// Set each move to true in the available moves dict | |
for (let move of moves) { | |
// Use $set for the changes to display in the UI | |
this.$set(this.availableMoves, move, true) | |
} | |
} | |
}, | |
/** On-click for square, select square or try move if suqare is selected */ | |
squareSelected (index) { | |
this.availableMoves = {} | |
if (this.selectedIndex > 0) { | |
this.movePiece(this.selectedIndex, index) | |
this.selectedIndex = -1 | |
} else { | |
this.getAvailableMoves(index) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment