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 }