diff --git a/src/activities/oware/Oware.qml b/src/activities/oware/Oware.qml index 86b6616a7..3c6c96627 100644 --- a/src/activities/oware/Oware.qml +++ b/src/activities/oware/Oware.qml @@ -1,530 +1,506 @@ /* GCompris - Oware.qml * * Copyright (C) 2017 Divyam Madaan * * Authors: * Frederic Mazzarol (GTK+ version) * Divyam Madaan (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 . */ import QtQuick 2.6 import GCompris 1.0 import "../../core" import "oware.js" as Activity import "." ActivityBase { id: activity property bool twoPlayer: false property bool horizontalLayout: (background.width > background.height) ? true : false onStart: focus = true onStop: {} pageComponent: Image { id: background anchors.fill: parent source: "qrc:/gcompris/src/activities/guesscount/resource/backgroundW01.svg" signal start signal stop Component.onCompleted: { activity.start.connect(start) activity.stop.connect(stop) } // Add here the QML items you need to access in javascript QtObject { id: items property Item main: activity.main property alias background: background property alias bar: bar property alias bonus: bonus property alias cellGridRepeater: cellGridRepeater property bool playerOneTurn: true property int playerOneScore: 0 property int playerTwoScore: 0 property alias playerOneLevelScore: playerOneLevelScore property alias playerTwoLevelScore: playerTwoLevelScore property alias boardModel: boardModel property bool computerTurn: false - property int indexValue + property int selectedIndexValue property bool gameEnded: false /* The grid starts from top, top houses are occupied by player two so start and end index for player two are 0 and 5 and start and end index for player one are 6 and 11 */ readonly property int playerOneStartIndex: 6 readonly property int playerOneEndIndex: 11 readonly property int playerTwoStartIndex: 0 readonly property int playerTwoEndIndex: 5 readonly property int housesCount: 12 } onStart: { Activity.start(items,twoPlayer) } onStop: { Activity.stop() } // Timer to trigger computer move Timer { id: trigComputerMove repeat: false interval: 2500 onTriggered: { if(items.computerTurn) Activity.computerMove() } } Item { id: boardModel width: parent.width * 0.7 height: width * 0.4 z: 2 anchors.centerIn: parent rotation: horizontalLayout ? 0 : 90 Image { id: board source: Activity.url + "/owareBoard.png" anchors.fill: parent } Rectangle { id: playerOneBorder height: 5 width: parent.width/4 color: "orange" anchors.top: board.bottom anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: 6 } Rectangle { id: playerTwoBorder height: 5 width: parent.width/4 color: "blue" anchors.bottom: board.top anchors.horizontalCenter: parent.horizontalCenter anchors.bottomMargin: 5 } // Grid of houses with 6 houses for each player Grid { id: boardGrid columns: 6 rows: 2 anchors.horizontalCenter: board.horizontalCenter anchors.top: board.top property int currentMove Repeater { id: cellGridRepeater model: 12 Rectangle { id: house color: "transparent" height: board.height/2 width: board.width * (1/6.25) property real circleRadius: width - property int value + property int numberOfSeedsInHouse property string nextMove property real scoreBoardX property int previousIndex property alias grainRepeater: grainRepeater GCText { - text: value + text: numberOfSeedsInHouse color: "white" anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter z: 2 rotation: (background.width > background.height) ? 0 : 270 fontSize: smallSize } MouseArea { id: buttonClick anchors.fill: parent onPressed: { - cellGridRepeater.itemAt(items.indexValue).z = 0 - items.indexValue = index + cellGridRepeater.itemAt(items.selectedIndexValue).z = 0 + items.selectedIndexValue = index boardGrid.currentMove = items.playerOneTurn ? (index - 6) : (11 - index) var nextPlayer = items.playerOneTurn ? 1 : 0 if (!items.computerTurn && Activity.isValidMove(boardGrid.currentMove, nextPlayer, Activity.house)) { - cellGridRepeater.itemAt(items.indexValue).z = 20 + cellGridRepeater.itemAt(items.selectedIndexValue).z = 20 firstMove() items.playerOneTurn = !items.playerOneTurn } } } function scoresAnimation(scoreDirection,seedsCount,currentScoreIndex) { - value = seedsCount - grainRepeater.model = value + numberOfSeedsInHouse = seedsCount + grainRepeater.model = numberOfSeedsInHouse print(grainRepeater.model) previousIndex = currentScoreIndex scoreBoardX = cellGridRepeater.itemAt(currentScoreIndex).x for(var i = 0; i < grainRepeater.count; i++) { - print("hhhh") grainRepeater.itemAt(i).startScoreAnimation(scoreDirection) } } function firstMove() { items.boardModel.enabled = false - /* If the indexValue on which player has clicked is between 6 and 11 then the first move will be towards right. */ - if(items.indexValue >= items.playerOneStartIndex && items.indexValue < items.playerOneEndIndex) + /* If the selectedIndexValue on which player has clicked is between 6 and 11 then the first move will be towards right. */ + if(items.selectedIndexValue >= items.playerOneStartIndex && items.selectedIndexValue < items.playerOneEndIndex) nextMove = "right" - /* Else if the indexValue on which player has clicked is 11 then first move will be up */ - else if(items.indexValue == items.playerOneEndIndex) + /* Else if the selectedIndexValue on which player has clicked is 11 then first move will be up */ + else if(items.selectedIndexValue == items.playerOneEndIndex) nextMove = "up" - /* Similarly if the indexValue on which player has clicked is between 0 and 5 then first move will be left and if equal to 0 then it will be down. */ - else if(items.indexValue > items.playerTwoStartIndex && items.indexValue <= items.playerTwoEndIndex) + /* Similarly if the selectedIndexValue on which player has clicked is between 0 and 5 then first move will be left and if equal to 0 then it will be down. */ + else if(items.selectedIndexValue > items.playerTwoStartIndex && items.selectedIndexValue <= items.playerTwoEndIndex) nextMove = "left" - else if(items.indexValue == items.playerTwoStartIndex) + else if(items.selectedIndexValue == items.playerTwoStartIndex) nextMove = "down" for(var i = 0; i < grainRepeater.count; i++) { grainRepeater.itemAt(i).startAnimation() } } function setScoreValues() { print(Activity.scoreHouse) // for(var i = 0; i < 12; i++) { // print(cellGridRepeater.itemAt(i).value) // } items.playerTwoScore = Activity.scoreHouse[1] items.playerOneScore = Activity.scoreHouse[0] // Activity.setAfterValues(Activity.house) print(items.cellGridRepeater.itemAt(previousIndex).grainRepeater.model) -// Activity.setValues(Activity.house) - value = 0 +// Activity.setHouseAndScoreValues(Activity.house) + numberOfSeedsInHouse = 0 grainRepeater.model = value } Repeater { id: grainRepeater - model: value + model: numberOfSeedsInHouse Image { id: grain source: Activity.url + "grain2.png" height: circleRadius * 0.2 width: circleRadius * 0.2 - x: circleRadius/2 + Activity.getX(circleRadius/6, index,value) - y: circleRadius/2 + Activity.getY(circleRadius/5, index,value) + x: circleRadius/2 + Activity.getX(circleRadius/6, index,numberOfSeedsInHouse) + y: circleRadius/2 + Activity.getY(circleRadius/5, index,numberOfSeedsInHouse) property int currentIndex: index property int currentSeeds: grainRepeater.count property int totalSeeds: grainRepeater.count // moveCount is the current index of the moving seed wrt board. - property int moveCount: items.indexValue + property int moveCount: items.selectedIndexValue property int totalMoves: 0 signal checkAnimation Timer { id: moveSeedsTimer repeat: false interval: 500 onTriggered: { - Activity.setValues(Activity.house) + Activity.setHouseAndScoreValues(Activity.house) } } onCheckAnimation: { if(!currentSeeds && !items.gameEnded) { if(twoPlayer || !items.playerOneTurn) { var nextPlayer = items.playerOneTurn ? 1 : 0 Activity.sowSeeds(boardGrid.currentMove, Activity.house, Activity.scoreHouse, nextPlayer) } moveSeedsTimer.start() if(!twoPlayer && !items.playerOneTurn) { items.computerTurn = true trigComputerMove.start() } } } function startAnimation() { grainRepeater.itemAt(index).source = Activity.url + "grain.png" if(currentIndex >= 0 && currentSeeds > 0) { if(nextMove == "right") xRightAnimation.start() else if(nextMove == "up") yUpAnimation.start() else if(nextMove == "left") xLeftAnimation.start() else if(nextMove == "down") yDownAnimation.start() } checkAnimation() } + function animation(playerEndIndex) { + if(currentIndex >= 0 && currentSeeds > 0) { + if(moveCount == playerEndIndex && totalMoves%items.housesCount == items.housesCount - 1) { + // don't drop seed if it's in the starting house + } + else { + currentSeeds-- + currentIndex-- + } + totalMoves++ + } + } + function startScoreAnimation(scoreDirection) { if(scoreDirection == "left") scoreLeftAnimation.start() else if(scoreDirection == "right") scoreRightAnimation.start() } property var scoreLeftAnimation: SequentialAnimation { NumberAnimation { target: grain properties: "y" from: y; to: y - (board.height)/2 duration: 1000 } NumberAnimation { target: grain properties: "x" from: x ; to: x - (scoreBoardX * 1.3) duration: 2000 } NumberAnimation { target: grain properties: "y" from: y; to: y + (board.height)/2 duration: 2000 } ScriptAction { script: { print("check") setScoreValues() } } } property var scoreRightAnimation: SequentialAnimation { NumberAnimation { target: grain properties: "y" from: y; to: y + (board.height)/2 duration: 400 } NumberAnimation { target: grain properties: "x" from: x ; to: x + (board.width - scoreBoardX) duration: 1000 } NumberAnimation { target: grain properties: "y" from: y; to: y - (board.height)/2 duration: 1000 } ScriptAction { script: { setScoreValues() } } } property var xLeftAnimation: NumberAnimation { target: grain properties: "x" from: x; to: x - (0.162 * board.width) duration: 450 onStopped: { - if(currentIndex >= 0 && currentSeeds > 0) { - if(moveCount == items.indexValue + 1 && totalMoves%items.housesCount == items.housesCount - 1) { - // don't drop seed if it's in the starting house - } - else { - currentSeeds-- - currentIndex-- - } - totalMoves++ + animation(items.selectedIndexValue + 1) moveCount-- nextMove = (moveCount == items.playerTwoStartIndex) ? "down" : "left" startAnimation() - } } } property var xRightAnimation: NumberAnimation { target: grain properties: "x" from: x; to: x + (0.16 * board.width) duration: 450 onStopped: { - if(currentIndex >= 0 && currentSeeds > 0) { - if(moveCount == items.indexValue - 1 && totalMoves%items.housesCount == items.housesCount - 1) { - // don't drop seed if it's in the starting house - } - else { - currentSeeds-- - currentIndex-- - } - totalMoves++ + animation(items.selectedIndexValue - 1) moveCount++ nextMove = (moveCount == items.playerOneEndIndex) ? "up" : "right" startAnimation() - } } } property var yUpAnimation: NumberAnimation { target: grain properties: "y" from: y; to: y - 0.5 * board.height duration: 350 onStopped: { - if(currentIndex >= 0 && currentSeeds > 0) { - // don't drop seed if it's in the starting house - if(moveCount == items.playerOneEndIndex && totalMoves%items.housesCount == items.housesCount - 1) { - } - else { - currentSeeds-- - currentIndex-- - } - totalMoves++ - moveCount = items.playerTwoEndIndex - nextMove = "left" - startAnimation() - } + animation(items.playerOneEndIndex) + moveCount = items.playerTwoEndIndex + nextMove = "left" + startAnimation() } } property var yDownAnimation: NumberAnimation { target: grain properties: "y" loops: 1 from: y; to: y + 0.5 * board.height duration: 350 onStopped: { - if(currentIndex >= 0 && currentSeeds > 0) { - if(moveCount == items.playerTwoStartIndex && totalMoves%items.housesCount == items.housesCount - 1) { - // don't drop seed if it's in the starting house - } - else { - currentSeeds-- - currentIndex-- - } - totalMoves++ - moveCount = items.playerOneStartIndex - nextMove = "right" - startAnimation() - } + animation(items.playerTwoStartIndex) + moveCount = items.playerOneStartIndex + nextMove = "right" + startAnimation() } } } } } } } PlayerScoreBox { id: playerOneScoreBox height: board.height * 0.54 width: height anchors.verticalCenter: parent.verticalCenter anchors.right: boardModel.left playerScore: items.playerOneScore } PlayerScoreBox { id: playerTwoScoreBox height: board.height * 0.54 width: height anchors.verticalCenter: parent.verticalCenter anchors.left: boardModel.right playerScore: items.playerTwoScore } } Image { id: tutorialImage source: "qrc:/gcompris/src/activities/guesscount/resource/backgroundW01.svg" anchors.fill: parent z: 5 visible: twoPlayer ? false : true Tutorial { id:tutorialSection tutorialDetails: Activity.tutorialInstructions onSkipPressed: { Activity.initLevel() tutorialImage.visible = false } } } ScoreItem { id: playerOneLevelScore player: 1 height: Math.min(background.height/7, Math.min(background.width/7, bar.height * 1.05)) width: height * 11/8 playerScore: 0 anchors { top: background.top topMargin: 5 left: background.left leftMargin: 5 } playerImageSource: "qrc:/gcompris/src/activities/align4-2players/resource/player_1.svg" backgroundImageSource: "qrc:/gcompris/src/activities/align4-2players/resource/score_1.svg" } ScoreItem { id: playerTwoLevelScore player: 2 height: Math.min(background.height/7, Math.min(background.width/7, bar.height * 1.05)) width: height * 11/8 playerScore: 0 anchors { top: background.top topMargin: 5 right: background.right rightMargin: 5 } playerImageSource: "qrc:/gcompris/src/activities/align4-2players/resource/player_2.svg" backgroundImageSource: "qrc:/gcompris/src/activities/align4-2players/resource/score_2.svg" playerScaleOriginX: playerTwoLevelScore.width } DialogHelp { id: dialogHelp onClose: home() } Bar { id: bar content: BarEnumContent { value: twoPlayer ? (help | home | reload) : (tutorialSection.visible ? (help | home) : (help | home | level | reload)) } onHelpClicked: { displayDialog(dialogHelp) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() onReloadClicked: Activity.reset() } Bonus { id: bonus } } } diff --git a/src/activities/oware/PlayerScoreBox.qml b/src/activities/oware/PlayerScoreBox.qml index 001cb8564..931c36940 100644 --- a/src/activities/oware/PlayerScoreBox.qml +++ b/src/activities/oware/PlayerScoreBox.qml @@ -1,72 +1,72 @@ -/* GCompris - Oware.qml +/* GCompris - PlayerScoreBox.qml * * Copyright (C) 2017 Divyam Madaan * * Authors: * Frederic Mazzarol (GTK+ version) * Divyam Madaan (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 . */ import QtQuick 2.6 import GCompris 1.0 import "../../core" import "oware.js" as Activity Image { id: playerScoreBox source: Activity.url + "/score.png" property int playerScore Flow { width: parent.width height: parent.height anchors { top: parent.top left: parent.left leftMargin: parent.width * 0.15 topMargin: parent.height * 0.15 right: parent.right rightMargin: parent.width * 0.15 bottom: parent.bottom bottomMargin: parent.height * 0.2 } Repeater { id: playerScoreRepeater model: playerScore Image { id: playerSeedsImage source: Activity.url + "grain2.png" height: board.width * (1 / 7.25) * 0.17 width: board.width * (1 / 7.25) * 0.17 } } } GCText { id: playerScoreText color: "white" anchors.bottom: parent.top anchors.horizontalCenter: parent.horizontalCenter fontSize: smallSize text: playerScore horizontalAlignment: Text.AlignHCenter rotation: (background.width > background.height) ? 0 : 270 wrapMode: TextEdit.WordWrap } } diff --git a/src/activities/oware/oware.js b/src/activities/oware/oware.js index 178ed8594..f2a66794f 100644 --- a/src/activities/oware/oware.js +++ b/src/activities/oware/oware.js @@ -1,364 +1,372 @@ /* GCompris - oware.js * * Copyright (C) 2017 Divyam Madaan * * Authors: * Frederic Mazzarol (GTK+ version) * Divyam Madaan (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.6 as Quick var currentLevel = 0 var numberOfLevel = 5 var items var url = "qrc:/gcompris/src/activities/oware/resource/" // house variable is used for storing the count of all the seeds as we play. var house = [] var scoreHouse = [0, 0] var maxDiff = [20, 15, 10, 5, 0] var depth var heuristicValue var lastMove var finalMove var twoPlayer var capturedHousesIndex var tutorialInstructions = [{ - "instruction": qsTr("
  • - Each player has 6 houses with 4 seeds each.
  • - Lower 6 houses are of player 1.
  • - Upper 6 houses are for player 2.
  • "), + "instruction": qsTr("
    Introduction:
    • Each player has 6 houses with 4 seeds each.
    • Lower 6 houses are for player 1.
    • Upper 6 houses are for player 2.
    "), "instructionImage": "qrc:/gcompris/src/activities/oware/resource/tutorial1.png" }, { - "instruction": qsTr("

    Sowing:

  • - Chose any house from your set of houses.
  • - All seeds from that house will be picked and dropped in each house counter-clockwise.
  • Example: If player 1 choses second house, blue seeds from the second house below are picked and dropped in next houses (yellow seeds represent the dropped seeds)."), + "instruction": qsTr("

    Sowing:

    • Chose any house from your set of houses.
    • All seeds from that house will be picked and dropped in each house counter-clockwise
    "), + "instructionImage": "qrc:/gcompris/src/activities/oware/resource/tutorial2.png" + }, + { + "instruction": qsTr("
    Example:
    If player 1 choses second house, blue seeds from the second house below are picked and dropped in next houses (yellow seeds represent the dropped seeds)."), "instructionImage": "qrc:/gcompris/src/activities/oware/resource/tutorial2.png" }, { "instruction": qsTr("
  • If the number of seeds in the chosen house is >= 12, seed is not dropped in that house while sowing.
  • Example: If player 1 choses second house with 14 seeds, seed will not be dropped in that house.
  • "), "instructionImage": "qrc:/gcompris/src/activities/oware/resource/tutorial3.png" }, { - "instruction": qsTr("

    Capturing:

    The seeds are captured when all below conditions are true:
  • - Last seed is dropped into the opponent's house.
  • - Total number of seeds in that house are now two or three
  • Those seeds will go to your scoring box
  • "), + "instruction": qsTr("
    Capturing:
    The seeds are captured when all below conditions are true:
    • Last seed is dropped into the opponent's house.
    • Total number of seeds in that house are now two or three
    • Those seeds will go to your scoring box.
    "), "instructionImage": "qrc:/gcompris/src/activities/oware/resource/tutorial4.png" }, { - "instruction": qsTr("
  • If all the houses of one player are empty, the other player has to take such a move that it gives one or more seeds to the other player to continue the game.
  • Example: Player 1 has no more seeds left, so player 2 needs to give seeds to player 1 in next move.
  • "), + "instruction": qsTr("If all the houses of one player are empty, the other player has to take such a move that it gives one or more seeds to the other player to continue the game.
  • Example: Player 1 has no more seeds left, so player 2 needs to give seeds to player 1 in next move.
  • "), "instructionImage": "qrc:/gcompris/src/activities/oware/resource/tutorial5.png" }, { - "instruction": qsTr("
  • - The player who gets 25 seeds first wins the game.
  • - If the current player is unable to give any seed to the opponent, then the current player keeps all the seeds in the houses of his side and the game ends.
  • Example: Player 1 has no more seeds, neither player 2 can give any so player 2 will take the seed and game ends."), + "instruction": qsTr("
    • The player who gets 25 seeds first wins the game.
    • If the current player is unable to give any seed then he keeps all the seeds of his houses and the game ends.
    • Example: Player 1 has no seeds, neither player 2 can give any so player 2 will take the seed and game ends.
    "), "instructionImage": "qrc:/gcompris/src/activities/oware/resource/tutorial6.png" } ] function start(items_, twoPlayer_) { items = items_ twoPlayer = twoPlayer_ currentLevel = 0 reset() } function stop() {} // Function to reload the activity. function reset() { for (var i = 0; i < 12; i++) - items.cellGridRepeater.itemAt(i).value = 0 + items.cellGridRepeater.itemAt(i).numberOfSeedsInHouse = 0 items.playerOneLevelScore.endTurn() items.playerTwoLevelScore.endTurn() items.playerOneLevelScore.beginTurn() items.playerOneTurn = true items.computerTurn = false initLevel() } function initLevel() { items.boardModel.enabled = true items.bar.level = currentLevel + 1 var initialSeedsNumber = 4 for (var i = 11; i >= 0; i--) house[i] = initialSeedsNumber items.playerOneScore = 0 items.playerTwoScore = 0 scoreHouse = [0, 0] depth = currentLevel - setValues(house) + setHouseAndScoreValues(house) } function nextLevel() { if (numberOfLevel <= ++currentLevel) { currentLevel = 0 } reset() } function previousLevel() { if (--currentLevel < 0) { currentLevel = numberOfLevel - 1 } initLevel(); reset() } // Function to get the x position of seeds. -function getX(radius, index, value) { - var step = (2 * Math.PI) * index / value; +function getX(radius, index, numberOfSeedsInHouse) { + var step = (2 * Math.PI) * index / numberOfSeedsInHouse; return radius * Math.cos(step); } // Function to get the y position of seeds. -function getY(radius, index, value) { - var step = (2 * Math.PI) * index / value; +function getY(radius, index, numberOfSeedsInHouse) { + var step = (2 * Math.PI) * index / numberOfSeedsInHouse; return radius * Math.sin(step); } function computerMove() { if (items.playerOneScore - items.playerTwoScore >= maxDiff[currentLevel]) { var houseClone = house.slice() var scoreClone = scoreHouse.slice() - var index = alphaBeta(4, -200, 200, houseClone, scoreClone, 0, lastMove) + var heuristicValue + var index = alphaBeta(4, -200, 200, houseClone, scoreClone, 0, lastMove, heuristicValue) finalMove = index[0] } else { randomMove() } sowSeeds(finalMove, house, scoreHouse, 1) - items.cellGridRepeater.itemAt(items.indexValue).z = 0 - items.indexValue = 11 - finalMove + items.cellGridRepeater.itemAt(items.selectedIndexValue).z = 0 + items.selectedIndexValue = 11 - finalMove if(!items.gameEnded) { - items.cellGridRepeater.itemAt(items.indexValue).z = 20 - items.cellGridRepeater.itemAt(items.indexValue).firstMove() + items.cellGridRepeater.itemAt(items.selectedIndexValue).z = 20 + items.cellGridRepeater.itemAt(items.selectedIndexValue).firstMove() items.playerOneTurn = !items.playerOneTurn items.computerTurn = false } } // Random moves are made when the difference between scores is less than maxDiff[levelNumber] function randomMove() { var move = Math.floor(Math.random() * (12 - 6) + 6) do { finalMove = move } while(house[move] == 0 || !isValidMove(move, 0, house)) } function gameOver(board, score) { - if (score[0] > 24 || score[1] > 24) + if (score[0] > 24 || score[1] > 24 || (score[0] == 24 && score[1] == 24)) return true return false } -function alphaBeta(depth, alpha, beta, board, score, nextPlayer, lastMove) { - var heuristicValue +function alphaBeta(depth, alpha, beta, board, score, nextPlayer, lastMove,heuristicValue) { var childHeuristics var bestMove if (depth == 0 || gameOver(board, score)) { heuristicValue = heuristicEvaluation(score) + print("depth over heauristic value,alpha,beta",heuristicValue,alpha,beta); return [-1, heuristicValue] } for (var move = 0; move < 12; move++) { if (!isValidMove(move, nextPlayer, board)) continue board = house.slice() score = scoreHouse.slice() var lastMoveAI = sowSeeds(move, board, score, nextPlayer) - var out = alphaBeta(depth - 1, alpha, beta, lastMoveAI.board, lastMoveAI.scoreHouse, lastMoveAI.nextPlayer, lastMoveAI.lastMove) +// print("lst move", JSON.stringify(lastMoveAI)) + var out = alphaBeta(depth - 1, alpha, beta, lastMoveAI.board, lastMoveAI.scoreHouse, lastMoveAI.nextPlayer, lastMoveAI.lastMove,childHeuristics) +// print(out) childHeuristics = out[1] if (nextPlayer) { if (beta > childHeuristics) { beta = childHeuristics bestMove = lastMoveAI.lastMove } if (alpha >= childHeuristics) break; } else { if (alpha < childHeuristics) { alpha = childHeuristics bestMove = lastMoveAI.lastMove } if (beta <= childHeuristics) break; } } heuristicValue = nextPlayer ? beta : alpha + print("one result bestMove,heuristicValue,alpha,beta",bestMove,depth,heuristicValue,alpha,beta); return [bestMove, heuristicValue] } function heuristicEvaluation(score) { var playerScores = []; for (var i = 0; i < 2; i++) { playerScores[i] = score[i] if (playerScores[i] > 24) playerScores[i] += 100 } - return playerScores[0] - playerScores[1] + return playerScores[1] - playerScores[0] } function isValidMove(move, nextPlayer, board) { if (move < 0 || !board[move]) return false if ((nextPlayer && move > 6) || (!nextPlayer && move < 6)) return false if(board[move] >= 12) return true // if the opponent does not have any seed, the current player has to give him if possible var sum = 0; for (var j = nextPlayer * 6; j < (nextPlayer * 6 + 6); j++) sum += board[j]; if (sum == 0 && ((!nextPlayer && board[move] % 12 < 12 - move) || (nextPlayer && board[move] % 12 < 6 - move))) return false else return true } -function setValues(board) { +function setHouseAndScoreValues(board) { items.gameEnded = false - if(items.playerTwoScore != scoreHouse[1]) { - for(var i = 0; i < capturedHousesIndex.length; i++) { -// print("details",JSON.stringify(capturedHousesIndex[i])) - items.cellGridRepeater.itemAt(capturedHousesIndex[i].index).scoresAnimation("right",capturedHousesIndex[i].seeds,capturedHousesIndex[i].index) - } - } - else if(items.playerOneScore != scoreHouse[0]) { - for(var i = 0; i < capturedHousesIndex.length; i++) { -// print("details",JSON.stringify(capturedHousesIndex[i])) - items.cellGridRepeater.itemAt(capturedHousesIndex[i].index).scoresAnimation("left",capturedHousesIndex[i].seeds,capturedHousesIndex[i].index) - } - } +// if(items.playerTwoScore != scoreHouse[1]) { +// for(var i = 0; i < capturedHousesIndex.length; i++) { +// // print("details",JSON.stringify(capturedHousesIndex[i])) +// items.cellGridRepeater.itemAt(capturedHousesIndex[i].index).scoresAnimation("right",capturedHousesIndex[i].seeds,capturedHousesIndex[i].index) +// } +// } +// else if(items.playerOneScore != scoreHouse[0]) { +// for(var i = 0; i < capturedHousesIndex.length; i++) { +// // print("details",JSON.stringify(capturedHousesIndex[i])) +// items.cellGridRepeater.itemAt(capturedHousesIndex[i].index).scoresAnimation("left",capturedHousesIndex[i].seeds,capturedHousesIndex[i].index) +// } +// } for (var i = 6, j = 0; i < 12, j < 6; j++, i++) - items.cellGridRepeater.itemAt(i).value = board[j] + items.cellGridRepeater.itemAt(i).numberOfSeedsInHouse = board[j] for (var i = 0, j = 11; i < 6, j > 5; j--, i++) - items.cellGridRepeater.itemAt(i).value = board[j] -// for(i = 0; i < 12; i++) { -// print(items.cellGridRepeater.itemAt(i).value) -// } + items.cellGridRepeater.itemAt(i).numberOfSeedsInHouse = board[j] + + items.playerTwoScore = scoreHouse[1] + items.playerOneScore = scoreHouse[0] if(items.playerOneScore == 24 && items.playerTwoScore == 24) items.bonus.good("flower") else if (items.playerTwoScore >= 25) { if(!twoPlayer) items.bonus.bad("flower") else items.bonus.good("flower") items.playerOneLevelScore.endTurn() items.playerTwoLevelScore.endTurn() items.playerTwoLevelScore.win() items.boardModel.enabled = false items.gameEnded = true } else if (items.playerOneScore >= 25) { items.playerOneLevelScore.win() items.playerTwoLevelScore.endTurn() items.boardModel.enabled = false items.gameEnded = true } if (!items.playerOneTurn && !items.gameEnded) { items.playerOneLevelScore.endTurn() items.playerTwoLevelScore.beginTurn() items.boardModel.enabled = true } else if (!items.gameEnded) { items.playerTwoLevelScore.endTurn() items.playerOneLevelScore.beginTurn() items.boardModel.enabled = true } } function sowSeeds(index, board, scoreHouse, nextPlayer) { var currentPlayer = (nextPlayer + 1) % 2 var nextIndex = index lastMove = index capturedHousesIndex = [] // The seeds are sown until the picked seeds are equal to zero while (board[index]) { nextIndex = (nextIndex + 1) % 12 // If there are more than or equal to 12 seeds than we don't sow the in the pit from where we picked the seeds. if (index == nextIndex) { nextIndex = (nextIndex + 1) % 12 } // Decrement the count of seeds and sow it in the nextIndex board[index]--; board[nextIndex]++; } // The nextIndex now contains the seeds in the last pit sown. var capture = []; // The opponent's seeds are captured if they are equal to 2 or 3 if (((board[nextIndex] == 2 || board[nextIndex] == 3)) && ((currentPlayer == 1 && nextIndex > 5 && nextIndex < 12) || (currentPlayer == 0 && nextIndex >= 0 && nextIndex < 6))) { capture[nextIndex % 6] = true; } /* The seeds previous to the captured seeds are checked. If they are equal to 2 or 3 then they are captured until a pit arrives which has more than 3 seeds or 1 seed. */ while (capture[nextIndex % 6] && nextIndex % 6) { nextIndex--; if (board[nextIndex] == 2 || board[nextIndex] == 3) { capture[nextIndex % 6] = true; } } var allSeedsCaptured = true; /* Now we check if all the seeds in opponents houses which were to be captured are captured or not. If any of the house is not yet captured we set allSeedsCaptured as false */ for (var j = currentPlayer * 6; j < (currentPlayer * 6 + 6); j++) { if (!capture[j % 6] && board[j]) allSeedsCaptured = false; } // Now capture the seeds for the houses for which capture[houseIndex] = true if all seeds are not captured if (!allSeedsCaptured) { for (var j = currentPlayer * 6; j < (currentPlayer * 6 + 6); j++) { /* If opponent's houses capture is true we set the no of seeds in that house as 0 and give the seeds to the opponent. */ if (capture[j % 6]) { scoreHouse[nextPlayer] = scoreHouse[nextPlayer] + board[j] // print(nextPlayer,j) if(!nextPlayer) capturedHousesIndex.push({ "index": 11 - j,"seeds": board[j] }) else capturedHousesIndex.push({ "index": 6 + j, "seeds": board[j] }) board[j] = 0; } } } var playerSideEmpty = true for (var j = nextPlayer * 6; j < (nextPlayer * 6 + 6); j++) { if (board[j]) { playerSideEmpty = false; break; - } + } } if (playerSideEmpty) { var canGiveSeeds = false; for (var j = currentPlayer * 6; j < (currentPlayer * 6 + 6); j++) { if ((board[j] >= 6 - j) || (board[j] > 12)) { canGiveSeeds = true; break; } } // If opponent can't give seeds, remaining seeds go to the opponent if (!canGiveSeeds) { for (var j = currentPlayer * 6; j < (currentPlayer * 6 + 6); j++) { scoreHouse[currentPlayer] += board[j]; board[j] = 0; } } } nextPlayer = currentPlayer var obj = { board: board, scoreHouse: scoreHouse, nextPlayer: nextPlayer, lastMove: lastMove } return obj }