File indexing completed on 2024-04-28 15:07:58
0001 /* GCompris - oware.js 0002 * 0003 * SPDX-FileCopyrightText: 2021 Harsh Kumar <hadron43@yahoo.com> 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 * 0006 */ 0007 .pragma library 0008 .import QtQuick 2.12 as Quick 0009 0010 var items 0011 var url = "qrc:/gcompris/src/activities/oware/resource/"; 0012 0013 // true if two players mode enabled 0014 var twoPlayers 0015 0016 // Player.PLAYER1, Player.PLAYER2 0017 var turn 0018 0019 // Enum for player 0020 var Player = { 0021 PLAYER1: 1, 0022 PLAYER2: 2 0023 } 0024 0025 // properties: player, index 0026 var lastPos, basePos 0027 0028 function start(items_, twoPlayers_) { 0029 items = items_ 0030 twoPlayers = twoPlayers_ 0031 initLevel() 0032 } 0033 0034 function stop() { 0035 } 0036 0037 function initLevel() { 0038 items.board.init() 0039 items.player1score.playerScore = 0 0040 items.player2score.playerScore = 0 0041 items.hand1.seeds = items.hand2.seeds = 0 0042 items.isDistributionAnimationPlaying = false 0043 0044 if (items.playerWithFirstMove === Player.PLAYER1) { 0045 items.player2score.beginTurn() 0046 items.player1score.endTurn() 0047 items.playerWithFirstMove = Player.PLAYER2 0048 } 0049 else { 0050 items.player1score.beginTurn() 0051 items.player2score.endTurn() 0052 items.playerWithFirstMove = Player.PLAYER1 0053 } 0054 0055 turn = items.playerWithFirstMove 0056 items.gameOver = false 0057 0058 if(!twoPlayers) { 0059 for(var i = 0; i < items.board.numberOfPitsInOneRow; ++i) 0060 items.board.pitRepeater2.itemAt(i).responsive = false 0061 0062 if(turn === Player.PLAYER2) { 0063 playRandomMove() 0064 return 0065 } 0066 } 0067 } 0068 0069 function countSeedsInRow(pitRepeater) { 0070 var count = 0 0071 for(var i = 0; i < items.board.numberOfPitsInOneRow; ++i) 0072 count += pitRepeater.itemAt(i).seeds 0073 return count 0074 } 0075 0076 function isValidMove(pit) { 0077 if(pit.seeds === 0) 0078 return false 0079 0080 var opponentSeeds 0081 var seedsTransferrable 0082 0083 if(pit.player === 1) { 0084 opponentSeeds = countSeedsInRow(items.board.pitRepeater2) 0085 seedsTransferrable = Math.max(pit.seeds - pit.index, 0) 0086 } 0087 else { 0088 opponentSeeds = countSeedsInRow(items.board.pitRepeater1) 0089 seedsTransferrable = Math.max(pit.seeds - (5 - pit.index), 0) 0090 } 0091 0092 if(opponentSeeds > 0) 0093 return true 0094 0095 return seedsTransferrable > 0 0096 } 0097 0098 function processMove(player, ind) { 0099 if(turn !== player || items.isDistributionAnimationPlaying || items.gameOver) 0100 return 0101 0102 var pit = (turn === Player.PLAYER1) ? items.board.pitRepeater1.itemAt(ind) : 0103 items.board.pitRepeater2.itemAt(ind) 0104 0105 if(!isValidMove(pit)) { 0106 items.invalidMoveAnimation.start(pit) 0107 items.instructionArea.start(qsTr("Invalid Move!")) 0108 return 0109 } 0110 0111 lastPos = { 0112 player: turn, 0113 index: ind 0114 } 0115 basePos = { 0116 player: turn, 0117 index: ind 0118 } 0119 0120 items.isDistributionAnimationPlaying = true 0121 items.teleportAnimation.start(pit, (turn === Player.PLAYER1 ? items.hand1 : items.hand2)) 0122 } 0123 0124 function checkWin() { 0125 if(items.player1score.playerScore >= 25) { 0126 items.gameOver = true 0127 // to counter extra score by win() method 0128 items.player1score.playerScore-- 0129 items.player1score.win() 0130 items.bonus.good("smiley") 0131 return true 0132 } 0133 else if(items.player2score.playerScore >= 25) { 0134 items.gameOver = true 0135 // to counter extra score by win() method 0136 items.player2score.playerScore-- 0137 items.player2score.win() 0138 items.bonus.good("tux") 0139 return true 0140 } 0141 else if(items.player1score.playerScore === 24 && items.player2score.playerScore === 24) { 0142 items.gameOver = true 0143 items.bonus.good("lion") 0144 return true 0145 } 0146 } 0147 0148 function captureAll() { 0149 for(var i = 0; i < items.board.numberOfPitsInOneRow; ++i) { 0150 items.player1score.playerScore += items.board.pitRepeater1.itemAt(i).seeds 0151 items.board.pitRepeater1.itemAt(i).seeds = 0 0152 items.player2score.playerScore += items.board.pitRepeater2.itemAt(i).seeds 0153 items.board.pitRepeater2.itemAt(i).seeds = 0 0154 } 0155 checkWin() 0156 } 0157 0158 function switchTurn() { 0159 items.selectedPit.selected = false 0160 if(checkWin()) 0161 return 0162 if(turn === Player.PLAYER1) { 0163 turn = Player.PLAYER2 0164 0165 items.player1score.endTurn() 0166 items.player2score.beginTurn() 0167 0168 if(!twoPlayers) { 0169 playRandomMove() 0170 return 0171 } 0172 0173 var valid = false 0174 for(var i = 0; i < items.board.numberOfPitsInOneRow; ++i) 0175 valid = valid | isValidMove(items.board.pitRepeater2.itemAt(i)) 0176 if(!valid) 0177 captureAll() 0178 } 0179 else { 0180 turn = Player.PLAYER1 0181 items.player2score.endTurn() 0182 items.player1score.beginTurn() 0183 0184 var valid = false 0185 for(var i = 0; i < items.board.numberOfPitsInOneRow; ++i) 0186 valid = valid | isValidMove(items.board.pitRepeater1.itemAt(i)) 0187 if(!valid) 0188 captureAll() 0189 } 0190 } 0191 0192 function nextAntiClockwise(lastPos) { 0193 // lastPos.player, lastPos.index 0194 if(lastPos.player === 1) { 0195 if(lastPos.index === 0) 0196 lastPos.player++ 0197 else 0198 lastPos.index-- 0199 } 0200 else { 0201 if(lastPos.index === 5) 0202 lastPos.player-- 0203 else 0204 lastPos.index++ 0205 } 0206 } 0207 0208 function nextClockwise(lastPos) { 0209 // lastPos.player, lastPos.index 0210 if(lastPos.player === 1) { 0211 if(lastPos.index === 5) 0212 lastPos.player++ 0213 else 0214 lastPos.index++ 0215 } 0216 else { 0217 if(lastPos.index === 0) 0218 lastPos.player-- 0219 else 0220 lastPos.index-- 0221 } 0222 } 0223 0224 function getGlobalPos(component) { 0225 if(!component || component.id === "background") 0226 return [0, 0] 0227 0228 var pos = getGlobalPos(component.parent) 0229 return [pos[0] + component.x, pos[1] + component.y] 0230 } 0231 0232 function getPit(player, index) { 0233 return (player === Player.PLAYER1 ? items.board.pitRepeater1.itemAt(index) : items.board.pitRepeater2.itemAt(index)) 0234 } 0235 0236 function isCaptureAllowed() { 0237 if(lastPos.player === turn) 0238 return false 0239 var pos = { 0240 player: lastPos.player, 0241 index: lastPos.index 0242 } 0243 var pit = getPit(pos.player, pos.index) 0244 var remaining = 0 0245 0246 while((pit.seeds === 2 || pit.seeds === 3) && pit.player !== turn) { 0247 nextClockwise(pos); 0248 pit = getPit(pos.player, pos.index) 0249 } 0250 0251 while(pit.player !== turn) { 0252 remaining += pit.seeds 0253 nextClockwise(pos); 0254 pit = getPit(pos.player, pos.index) 0255 } 0256 0257 pos = { 0258 player: lastPos.player, 0259 index: lastPos.index 0260 } 0261 nextAntiClockwise(pos) 0262 pit = getPit(pos.player, pos.index) 0263 0264 while(pit.player !== turn) { 0265 remaining += pit.seeds 0266 nextAntiClockwise(pos); 0267 pit = getPit(pos.player, pos.index) 0268 } 0269 return remaining > 0; 0270 } 0271 0272 function checkCapture() { 0273 var pit = getPit(lastPos.player, lastPos.index) 0274 0275 // end if back to original pit 0276 if((pit.seeds !== 2 && pit.seeds !== 3) || pit.player === turn) { 0277 // base case, end recursion 0278 switchTurn() 0279 items.isDistributionAnimationPlaying = false 0280 return 0281 } 0282 0283 if(turn === Player.PLAYER1) 0284 items.captureAnimation.start(pit, items.player1score) 0285 else 0286 items.captureAnimation.start(pit, items.player2score) 0287 0288 nextClockwise(lastPos) 0289 } 0290 0291 function redistribute() { 0292 if(!items.hand1.seeds && !items.hand2.seeds) { 0293 if(isCaptureAllowed()) 0294 checkCapture() 0295 else { 0296 // base case, end recursion 0297 // this base is otherwise handled by checkCapture function 0298 switchTurn() 0299 items.isDistributionAnimationPlaying = false 0300 } 0301 return 0302 } 0303 0304 nextAntiClockwise(lastPos) 0305 0306 // skip if back to original pit 0307 if(lastPos.player === basePos.player && lastPos.index === basePos.index) 0308 nextAntiClockwise(lastPos) 0309 0310 // incremement count of seeds in corresponding pit 0311 var fromPit = (items.hand1.seeds ? items.hand1 : items.hand2) 0312 var toPit = (lastPos.player == 1 ? items.board.pitRepeater1.itemAt(lastPos.index) : items.board.pitRepeater2.itemAt(lastPos.index)) 0313 0314 items.animationSeed.startAnimation(fromPit, toPit) 0315 } 0316 0317 function playRandomMove() { 0318 var validMoves = [] 0319 for(var i = 0; i < items.board.numberOfPitsInOneRow; ++i) { 0320 if(isValidMove(items.board.pitRepeater2.itemAt(i))) 0321 validMoves.push([turn, i]) 0322 } 0323 if(validMoves.length === 0) { 0324 captureAll() 0325 return 0326 } 0327 var randomIndex = Math.floor(Math.random() * validMoves.length) 0328 0329 items.delayAnimation.start(validMoves[randomIndex][0], validMoves[randomIndex][1]) 0330 }