diff --git a/src/activities/chess/chess.js b/src/activities/chess/chess.js index 7d84da4bc..8bd3e6445 100644 --- a/src/activities/chess/chess.js +++ b/src/activities/chess/chess.js @@ -1,280 +1,281 @@ /* GCompris - chess.js * * Copyright (C) 2015 Bruno Coudoin * * Authors: * Bruno Coudoin (GTK+ version) * Bruno Coudoin (Qt Quick port) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ .pragma library .import QtQuick 2.0 as Quick .import "qrc:/gcompris/src/core/core.js" as Core .import "engine.js" as Engine var url = "qrc:/gcompris/src/activities/chess/resource/" var currentLevel var numberOfLevel var items var state function start(items_) { items = items_ currentLevel = 0 numberOfLevel = items.fen.length initLevel() } function stop() { } function initLevel() { items.bar.level = currentLevel + 1 state = Engine.p4_fen2state(items.fen[currentLevel][1]) items.from = -1 items.gameOver = false refresh() Engine.p4_prepare(state) items.positions = 0 // Force a model reload items.positions = simplifiedState(state['board']) clearAcceptMove() } function nextLevel() { if(numberOfLevel <= ++currentLevel ) { currentLevel = 0 } initLevel(); } function previousLevel() { if(--currentLevel < 0) { currentLevel = numberOfLevel - 1 } initLevel(); } function isWhite(piece) { if(piece.length != 2) return -1 if(piece[0] == 'w') return true return false } function simplifiedState(state) { var newState = new Array() for(var i = state.length - 1; i >= 0; --i) { if(state[i] != 16) { var img = "" switch(state[i]) { case 2: img = "wp" break case 3: img = "bp" break case 4: img = "wr" break case 5: img = "br" break case 6: img = "wn" break case 7: img = "bn" break case 8: img = "wb" break case 9: img = "bb" break case 10: img = "wk" break case 11: img = "bk" break case 12: img = "wq" break case 13: img = "bq" break default: break } newState.push( { 'pos': engineToViewPos(i), 'img': img, 'isWhite': isWhite(img) }) } } return newState } function updateMessage(move) { items.gameOver = false items.message = items.blackTurn ? qsTr("Black's turn") : qsTr("White's turn") if(!move) return if((move.flags & (Engine.P4_MOVE_FLAG_CHECK | Engine.P4_MOVE_FLAG_MATE)) == (Engine.P4_MOVE_FLAG_CHECK | Engine.P4_MOVE_FLAG_MATE)) { items.message = items.blackTurn ? qsTr("Black mates") : qsTr("White mates") items.gameOver = true } else if((move.flags & Engine.P4_MOVE_FLAG_MATE) == Engine.P4_MOVE_FLAG_MATE) { items.message = qsTr("Drawn game") items.gameOver = true } else if((move.flags & Engine.P4_MOVE_FLAG_CHECK) == Engine.P4_MOVE_FLAG_CHECK) { items.message = items.blackTurn ? qsTr("Black checks") : qsTr("White checks") } else if(move.flags == Engine.P4_MOVE_ILLEGAL) { items.message = qsTr("Invalid, your king may be in check") } } function refresh(move) { items.blackTurn = state.to_play // 0=w 1=b items.history = state.history updateMessage(move) } // Convert view position (QML) to the chess engine coordinate // // The engine manages coordinate into a 120 element array, which is conceptually // a 10x12 board, with the 8x8 board placed at the centre, thus: // + 0123456789 // 0 ########## // 10 ########## // 20 #RNBQKBNR# // 30 #PPPPPPPP# // 40 #........# // 50 #........# // 60 #........# // 70 #........# // 80 #pppppppp# // 90 #rnbqkbnr# //100 ########## //110 ########## // // In QML each cell is in the regular range [0-63] // function viewPosToEngine(pos) { return (Math.floor(pos / 8) + 2) * 10 + pos % 8 + 1 } // Convert chess engine coordinate to view position (QML) function engineToViewPos(pos) { var newpos = pos - 21 - (Math.floor((pos - 20) / 10) * 2) return newpos } // move is the result from the engine move function visibleMove(move, from, to) { items.pieces.moveTo(from, to) // Castle move if(move.flags & Engine.P4_MOVE_FLAG_CASTLE_KING) items.pieces.moveTo(from + 3, to - 1) else if(move.flags & Engine.P4_MOVE_FLAG_CASTLE_QUEEN) items.pieces.moveTo(from - 4, to + 1) } function computerMove() { var computer = state.findmove(3) var move = state.move(computer[0], computer[1]) if(move.ok) { visibleMove(move, engineToViewPos(computer[0]), engineToViewPos(computer[1])) refresh(move) } return move } function moveTo(from, to) { var move = state.move(viewPosToEngine(from), viewPosToEngine(to)) if(move.ok) { visibleMove(move, from, to) refresh(move) clearAcceptMove() if(!items.twoPlayer) items.trigComputerMove.start() items.from = -1; } else { // Probably a check makes the move is invalid updateMessage(move) } } function undo() { state.jump_to_moveno(state.moveno - 1) // In computer mode, the white always starts, take care // of undo after a mate which requires us to revert on // a white play if(!items.twoPlayer && state.to_play != 0) { state.jump_to_moveno(state.moveno - 1) } refresh() + items.positions = 0 // Force a model reload items.positions = simplifiedState(state['board']) } // Random move depending on the level function randomMove() { if(!items.difficultyByLevel) { computerMove() return } // At level 2 we let the computer play 20% of the time // and 80% of the time we make a random move. if(Math.random() < currentLevel / (numberOfLevel - 1)) { computerMove() return } // Get all possible moves var moves = Engine.p4_parse(state, state.to_play, 0, 0) moves = Core.shuffle(moves) var move = state.move(moves[0][1], moves[0][2]) if(move.ok) { visibleMove(move, engineToViewPos(moves[0][1]), engineToViewPos(moves[0][2])) refresh(move) } else { // Bad move, should not happens computerMove() } } // Clear all accept move marker from the chessboard function clearAcceptMove() { for(var i=0; i < items.positions.length; ++i) items.pieces.getPieceAt(i)['acceptMove'] = false } // Highlight the possible moves for the piece at position 'from' function showPossibleMoves(from) { var result = Engine.p4_parse(state, state.to_play, 0, 0) clearAcceptMove() for(var i=0; i < result.length; ++i) { if(viewPosToEngine(from) == result[i][1]) { var pos = engineToViewPos(result[i][2]) items.pieces.getPieceAt(pos)['acceptMove'] = true } } }