File indexing completed on 2024-05-19 03:43:55

0001 /* GCompris - nine_men_morris.js
0002  *
0003  * SPDX-FileCopyrightText: 2016 Pulkit Gupta <pulkitnsit@gmail.com>
0004  *
0005  * Authors:
0006  *   Pulkit Gupta <pulkitnsit@gmail.com>
0007  *
0008  *   SPDX-License-Identifier: GPL-3.0-or-later
0009  */
0010 .pragma library
0011 .import QtQuick 2.12 as Quick
0012 .import "qrc:/gcompris/src/core/core.js" as Core
0013 
0014 var numberOfLevel = 5
0015 var items
0016 var url = "qrc:/gcompris/src/activities/nine_men_morris/resource/"
0017 var currentPiece
0018 var twoPlayer
0019 var stopper     //For stopping game when doing reset
0020 var currentRepeater
0021 var otherRepeater
0022 var numberOfFirstPieces
0023 var numberOfSecondPieces
0024 var numberOfPieces
0025 var numberOfDragPoints
0026 var depthMax
0027 var tutorialInstructions = [
0028             {
0029                 "instruction": qsTr("You and Tux start with 9 pieces each, and take turns to place your pieces on the empty spots of the board (by clicking on the spots)."),
0030                 "instructionImage" : "qrc:/gcompris/src/activities/nine_men_morris/resource/tutorial1.svg"
0031             },
0032             {
0033                 "instruction": qsTr("If you form a mill (line of 3 pieces), then select one of Tux's pieces to remove it. Pieces of formed mill can not be removed unless no other pieces are left on the board."),
0034                 "instructionImage": "qrc:/gcompris/src/activities/nine_men_morris/resource/tutorial2.svg"
0035             },
0036             {
0037                 "instruction": qsTr("After all the pieces are placed, you and Tux will take turns to move them. Click on one of your pieces, and then on an adjacent empty spot to move it there. Green color spots indicates where you can move."),
0038                 "instructionImage": "qrc:/gcompris/src/activities/nine_men_morris/resource/tutorial3.svg"
0039             },
0040             {
0041                 "instruction":  qsTr("If you are left with 3 pieces, they gain the ability to 'fly' and can be moved to any vacant spot on the board."),
0042                 "instructionImage": "qrc:/gcompris/src/activities/nine_men_morris/resource/tutorial4.svg"
0043             },
0044             {
0045                 "instruction": qsTr("If you immobilize the computer or leave it with less than 3 pieces, then you win the game."),
0046                 "instructionImage": "qrc:/gcompris/src/activities/nine_men_morris/resource/tutorial5.svg"
0047             }
0048         ]
0049 
0050 function start(items_, twoPlayer_) {
0051     items = items_
0052     items.currentLevel = Core.getInitialLevel(numberOfLevel)
0053     twoPlayer = twoPlayer_
0054     numberOfLevel = 6
0055     numberOfPieces = 9
0056     numberOfDragPoints = 24
0057     items.playSecond = false
0058 
0059     // Creating drag points
0060     items.dragPointsModel.append({
0061         "posX": 0.05,
0062         "posY": 0.95,
0063         "myIndex": 0
0064     })
0065     items.dragPointsModel.append({
0066         "posX": 0.5,
0067         "posY": 0.95,
0068         "myIndex": 1
0069     })
0070     items.dragPointsModel.append({
0071         "posX": 0.95,
0072         "posY": 0.95,
0073         "myIndex": 2
0074     })
0075     items.dragPointsModel.append({
0076         "posX": 0.2,
0077         "posY": 0.8,
0078         "myIndex": 3
0079     })
0080     items.dragPointsModel.append({
0081         "posX": 0.5,
0082         "posY": 0.8,
0083         "myIndex": 4
0084     })
0085     items.dragPointsModel.append({
0086         "posX": 0.8,
0087         "posY": 0.8,
0088         "myIndex": 5
0089     })
0090     items.dragPointsModel.append({
0091         "posX": 0.35,
0092         "posY": 0.65,
0093         "myIndex": 6
0094     })
0095     items.dragPointsModel.append({
0096         "posX": 0.5,
0097         "posY": 0.65,
0098         "myIndex": 7
0099     })
0100     items.dragPointsModel.append({
0101         "posX": 0.65,
0102         "posY": 0.65,
0103         "myIndex": 8
0104     })
0105     items.dragPointsModel.append({
0106         "posX": 0.05,
0107         "posY": 0.5,
0108         "myIndex": 9
0109     })
0110     items.dragPointsModel.append({
0111         "posX": 0.2,
0112         "posY": 0.5,
0113         "myIndex": 10
0114     })
0115     items.dragPointsModel.append({
0116         "posX": 0.35,
0117         "posY": 0.5,
0118         "myIndex": 11
0119     })
0120     items.dragPointsModel.append({
0121         "posX": 0.65,
0122         "posY": 0.5,
0123         "myIndex": 12
0124     })
0125     items.dragPointsModel.append({
0126         "posX": 0.8,
0127         "posY": 0.5,
0128         "myIndex": 13
0129     })
0130     items.dragPointsModel.append({
0131         "posX": 0.95,
0132         "posY": 0.5,
0133         "myIndex": 14
0134     })
0135     items.dragPointsModel.append({
0136         "posX": 0.35,
0137         "posY": 0.35,
0138         "myIndex": 15
0139     })
0140     items.dragPointsModel.append({
0141         "posX": 0.5,
0142         "posY": 0.35,
0143         "myIndex": 16
0144     })
0145     items.dragPointsModel.append({
0146         "posX": 0.65,
0147         "posY": 0.35,
0148         "myIndex": 17
0149     })
0150     items.dragPointsModel.append({
0151         "posX": 0.2,
0152         "posY": 0.2,
0153         "myIndex": 18
0154     })
0155     items.dragPointsModel.append({
0156         "posX": 0.500,
0157         "posY": 0.2,
0158         "myIndex": 19
0159     })
0160     items.dragPointsModel.append({
0161         "posX": 0.8,
0162         "posY": 0.2,
0163         "myIndex": 20
0164     })
0165     items.dragPointsModel.append({
0166         "posX": 0.05,
0167         "posY": 0.05,
0168         "myIndex": 21
0169     })
0170     items.dragPointsModel.append({
0171         "posX": 0.5,
0172         "posY": 0.05,
0173         "myIndex": 22
0174     })
0175     items.dragPointsModel.append({
0176         "posX": 0.95,
0177         "posY": 0.05,
0178         "myIndex": 23
0179     })
0180     // For assigning left and right point
0181     for (var i = 0 ; i < numberOfDragPoints ; i++) {
0182         if(i % 3)
0183             items.dragPoints.itemAt(i).leftPoint = items.dragPoints.itemAt(i - 1)
0184         else
0185             items.dragPoints.itemAt(i).leftPoint = null
0186         if((i + 1) % 3)
0187             items.dragPoints.itemAt(i).rightPoint = items.dragPoints.itemAt(i + 1)
0188         else
0189             items.dragPoints.itemAt(i).rightPoint = null
0190     }
0191 
0192     // Start assigning upper and lower point
0193     items.dragPoints.itemAt(0).upperPoint = items.dragPoints.itemAt(9)
0194     items.dragPoints.itemAt(0).lowerPoint = null
0195     items.dragPoints.itemAt(1).upperPoint = items.dragPoints.itemAt(4)
0196     items.dragPoints.itemAt(1).lowerPoint = null
0197     items.dragPoints.itemAt(2).upperPoint = items.dragPoints.itemAt(14)
0198     items.dragPoints.itemAt(2).lowerPoint = null
0199     items.dragPoints.itemAt(3).upperPoint = items.dragPoints.itemAt(10)
0200     items.dragPoints.itemAt(3).lowerPoint = null
0201     items.dragPoints.itemAt(4).upperPoint = items.dragPoints.itemAt(7)
0202     items.dragPoints.itemAt(4).lowerPoint = items.dragPoints.itemAt(1)
0203     items.dragPoints.itemAt(5).upperPoint = items.dragPoints.itemAt(13)
0204     items.dragPoints.itemAt(5).lowerPoint = null
0205     items.dragPoints.itemAt(6).upperPoint = items.dragPoints.itemAt(11)
0206     items.dragPoints.itemAt(6).lowerPoint = null
0207     items.dragPoints.itemAt(7).upperPoint = null
0208     items.dragPoints.itemAt(7).lowerPoint = items.dragPoints.itemAt(4)
0209     items.dragPoints.itemAt(8).upperPoint = items.dragPoints.itemAt(12)
0210     items.dragPoints.itemAt(8).lowerPoint = null
0211     items.dragPoints.itemAt(9).upperPoint = items.dragPoints.itemAt(21)
0212     items.dragPoints.itemAt(9).lowerPoint = items.dragPoints.itemAt(0)
0213     items.dragPoints.itemAt(10).upperPoint = items.dragPoints.itemAt(18)
0214     items.dragPoints.itemAt(10).lowerPoint = items.dragPoints.itemAt(3)
0215     items.dragPoints.itemAt(11).upperPoint = items.dragPoints.itemAt(15)
0216     items.dragPoints.itemAt(11).lowerPoint = items.dragPoints.itemAt(6)
0217     items.dragPoints.itemAt(12).upperPoint = items.dragPoints.itemAt(17)
0218     items.dragPoints.itemAt(12).lowerPoint = items.dragPoints.itemAt(8)
0219     items.dragPoints.itemAt(13).upperPoint = items.dragPoints.itemAt(20)
0220     items.dragPoints.itemAt(13).lowerPoint = items.dragPoints.itemAt(5)
0221     items.dragPoints.itemAt(14).upperPoint = items.dragPoints.itemAt(23)
0222     items.dragPoints.itemAt(14).lowerPoint = items.dragPoints.itemAt(2)
0223     items.dragPoints.itemAt(15).upperPoint = null
0224     items.dragPoints.itemAt(15).lowerPoint = items.dragPoints.itemAt(11)
0225     items.dragPoints.itemAt(16).upperPoint = items.dragPoints.itemAt(19)
0226     items.dragPoints.itemAt(16).lowerPoint = null
0227     items.dragPoints.itemAt(17).upperPoint = null
0228     items.dragPoints.itemAt(17).lowerPoint = items.dragPoints.itemAt(12)
0229     items.dragPoints.itemAt(18).upperPoint = null
0230     items.dragPoints.itemAt(18).lowerPoint = items.dragPoints.itemAt(10)
0231     items.dragPoints.itemAt(19).upperPoint = items.dragPoints.itemAt(22)
0232     items.dragPoints.itemAt(19).lowerPoint = items.dragPoints.itemAt(16)
0233     items.dragPoints.itemAt(20).upperPoint = null
0234     items.dragPoints.itemAt(20).lowerPoint = items.dragPoints.itemAt(13)
0235     items.dragPoints.itemAt(21).upperPoint = null
0236     items.dragPoints.itemAt(21).lowerPoint = items.dragPoints.itemAt(9)
0237     items.dragPoints.itemAt(22).upperPoint = null
0238     items.dragPoints.itemAt(22).lowerPoint = items.dragPoints.itemAt(19)
0239     items.dragPoints.itemAt(23).upperPoint = null
0240     items.dragPoints.itemAt(23).lowerPoint = items.dragPoints.itemAt(14)
0241     // End assigning upper and lower piece
0242 
0243     if(twoPlayer) {
0244         items.tutorialSection.visible = false
0245         initLevel()
0246     }
0247 }
0248 
0249 function stop() {
0250     items.trigTuxMove.stop();
0251 }
0252 
0253 function initLevel() {
0254     items.turn = 0
0255     items.gameDone = false
0256     items.firstPhase = true
0257     items.pieceBeingMoved = false
0258     numberOfFirstPieces = 0
0259     numberOfSecondPieces = 0
0260     items.firstPieceNumberCount = numberOfPieces
0261     items.secondPieceNumberCount = numberOfPieces
0262     items.instructionTxt = qsTr("Place a piece")
0263     depthMax = 2
0264 
0265     // Clear first and second player pieces, and initialize dragPoints
0266     items.firstPlayerPieces.model.clear()
0267     items.secondPlayerPieces.model.clear()
0268     for (var i = 0 ; i < numberOfDragPoints ; ++i)
0269             items.dragPoints.itemAt(i).state = "AVAILABLE"
0270 
0271     // Create first and second player pieces
0272     for (var i = 0 ; i < numberOfPieces ; ++i) {
0273         items.firstPlayerPiecesModel.append({})
0274         items.secondPlayerPiecesModel.append({})
0275     }
0276 
0277     currentRepeater = items.firstPlayerPieces
0278     otherRepeater = items.secondPlayerPieces
0279 
0280     stopper = false
0281 
0282     if(items.playSecond) {
0283         initiatePlayer2()
0284         if(!twoPlayer) {
0285             var rand = Math.floor((Math.random() * numberOfDragPoints))
0286             handleCreate(rand)
0287         }
0288     }
0289     else
0290         initiatePlayer1()
0291 }
0292 
0293 function nextLevel() {
0294     items.currentLevel = Core.getNextLevel(items.currentLevel, numberOfLevel);
0295     reset();
0296 }
0297 
0298 function previousLevel() {
0299     items.currentLevel = Core.getPreviousLevel(items.currentLevel, numberOfLevel);
0300     reset();
0301 }
0302 
0303 function reset() {
0304     items.trigTuxMove.stop();
0305     stopper = true;
0306     shouldComputerPlay();
0307     items.player2score.endTurn();
0308     items.player1score.beginTurn();
0309     items.playSecond = !items.playSecond
0310     initLevel()
0311 }
0312 
0313 //Initial values at the start of game when its player 1 turn
0314 function initiatePlayer1() {
0315     items.player2score.endTurn();
0316     items.player1score.beginTurn();
0317 
0318     items.firstInitial.anchors.right = undefined
0319     items.firstInitial.anchors.top = items.player1score.bottom
0320     items.firstInitial.anchors.left = items.player1score.left
0321 
0322     items.secondInitial.anchors.left = undefined
0323     items.secondInitial.anchors.right = items.player2score.right
0324     items.secondInitial.anchors.top = items.player2score.bottom
0325 }
0326 
0327 //Initial values at the start of game when its player 1 turn
0328 function initiatePlayer2() {
0329 
0330     items.player1score.endTurn();
0331     items.player2score.beginTurn();
0332 
0333     items.secondInitial.anchors.right = undefined
0334     items.secondInitial.anchors.top = items.player1score.bottom
0335     items.secondInitial.anchors.left = items.player1score.left
0336 
0337     items.firstInitial.anchors.left = undefined
0338     items.firstInitial.anchors.right = items.player2score.right
0339     items.firstInitial.anchors.top = items.player2score.bottom
0340 }
0341 
0342 //Change scale of score boxes according to turns
0343 function changeScale() {
0344    if(items.playSecond) {
0345         if(items.turn % 2 == 0) {
0346             items.player2score.beginTurn();
0347             items.player1score.endTurn();
0348         }
0349         else {
0350             items.player1score.beginTurn();
0351             items.player2score.endTurn();
0352         }
0353     }
0354     else {
0355         if(items.turn % 2 == 0) {
0356             items.player1score.beginTurn();
0357             items.player2score.endTurn();
0358         }
0359         else {
0360             items.player2score.beginTurn();
0361             items.player1score.endTurn();
0362         }
0363     }
0364 }
0365 
0366 //Create the piece at given position
0367 function handleCreate(index) {
0368     items.pieceBeingMoved = true
0369     currentPiece = currentRepeater.itemAt(items.turn / 2)
0370     if(currentPiece.state == "2") {
0371         items.secondPieceNumberCount--
0372         numberOfSecondPieces++
0373     }
0374     else {
0375         items.firstPieceNumberCount--
0376         numberOfFirstPieces++
0377     }
0378     currentPiece.move(items.dragPoints.itemAt(index))
0379 }
0380 
0381 function secondPhase() {
0382     items.firstPhase = false
0383     for (var i = 0 ; i < numberOfDragPoints ; ++i) {
0384         if(items.dragPoints.itemAt(i).state != "1" && items.dragPoints.itemAt(i).state != "2")
0385             items.dragPoints.itemAt(i).state = "EMPTY"
0386     }
0387 
0388     items.instructionTxt = qsTr("Move a piece")
0389 }
0390 
0391 function pieceSelected(pieceIndex) {
0392     currentPiece.isSelected = false
0393     currentPiece = currentRepeater.itemAt(pieceIndex)
0394     currentPiece.isSelected = true
0395 
0396     if((currentPiece.state == "1" && numberOfFirstPieces > 3) ||
0397        (currentPiece.state == "2" && numberOfSecondPieces > 3)) {
0398 
0399         for (var i = 0 ; i < numberOfDragPoints ; ++i) {
0400             if(items.dragPoints.itemAt(i).state == "EMPTY" || items.dragPoints.itemAt(i).state == "AVAILABLE")
0401                 items.dragPoints.itemAt(i).state = "UNAVAILABLE"
0402         }
0403 
0404         // Now assign values
0405         var index = currentRepeater.itemAt(pieceIndex).parentIndex // Drag Point index
0406         var dragPoint = items.dragPoints.itemAt(index)
0407 
0408         if(dragPoint.leftPoint) {
0409             if(dragPoint.leftPoint.state == "UNAVAILABLE")
0410                 dragPoint.leftPoint.state = "AVAILABLE"
0411         }
0412         if(dragPoint.upperPoint) {
0413             if(dragPoint.upperPoint.state == "UNAVAILABLE")
0414                 dragPoint.upperPoint.state = "AVAILABLE"
0415         }
0416         if(dragPoint.rightPoint) {
0417             if(dragPoint.rightPoint.state == "UNAVAILABLE")
0418                 dragPoint.rightPoint.state = "AVAILABLE"
0419         }
0420         if(dragPoint.lowerPoint) {
0421             if(dragPoint.lowerPoint.state == "UNAVAILABLE")
0422                 dragPoint.lowerPoint.state = "AVAILABLE"
0423         }
0424     }
0425     else {
0426         for (var i = 0 ; i < numberOfDragPoints ; ++i) {
0427             if(items.dragPoints.itemAt(i).state == "EMPTY" || items.dragPoints.itemAt(i).state == "UNAVAILABLE")
0428                 items.dragPoints.itemAt(i).state = "AVAILABLE"
0429         }
0430     }
0431 }
0432 
0433 function movePiece(index) {
0434     items.pieceBeingMoved = true
0435     currentPiece.pieceParent.state = "EMPTY"
0436     currentPiece.isSelected = false
0437     for (var i = 0 ; i < numberOfDragPoints ; ++i) {
0438         if(items.dragPoints.itemAt(i).state != "1" && items.dragPoints.itemAt(i).state != "2")
0439             items.dragPoints.itemAt(i).state = "EMPTY"
0440     }
0441     currentPiece.move(items.dragPoints.itemAt(index))
0442 }
0443 
0444 function shouldComputerPlay() {
0445     if(!twoPlayer) {
0446         if(items.turn % 2 && items.playSecond == false && stopper == false) {
0447             items.trigTuxMove.start()
0448         }
0449         else if((items.turn % 2 == 0) && items.playSecond && stopper == false) {
0450             items.trigTuxMove.start()
0451         }
0452         else
0453             items.pieceBeingMoved = false
0454     }
0455     else
0456         items.pieceBeingMoved = false
0457 }
0458 
0459 function doMove() {
0460     if(items.firstPhase) {
0461         if(items.currentLevel < 4)
0462             var index = setFirstPhaseMove()
0463         else {
0464             var boardPiecesLeft = items.firstPieceNumberCount + items.secondPieceNumberCount
0465             var board = getBoard()
0466             var index = alphabeta(depthMax, -9000, 9000, 2, board, boardPiecesLeft, false)
0467         }
0468         handleCreate(index)
0469     }
0470     else if(items.currentLevel < 4 && ((currentPiece.state == "2" && numberOfFirstPieces > 3) ||
0471            (currentPiece.state == "1" && numberOfSecondPieces > 3))) {
0472         var index = setSecondPhaseMove()
0473         currentPiece = currentRepeater.itemAt(index[0])
0474         movePiece(index[1])
0475     }
0476     else if(items.currentLevel < 4) {
0477         var index = setThirdPhaseMove()
0478         currentPiece = currentRepeater.itemAt(index[0])
0479         movePiece(index[1])
0480     }
0481     else {
0482         var noOfPlayerPieces = items.playSecond ? numberOfSecondPieces : numberOfFirstPieces
0483         var noOfComputerPieces = items.playSecond ? numberOfFirstPieces : numberOfSecondPieces
0484         var board = getBoard()
0485         var index = alphabeta(depthMax, -9000, 9000, 2, board, 0, false)
0486         currentPiece = currentRepeater.itemAt(items.dragPoints.itemAt(index[0]).pieceIndex)
0487         movePiece(index[1])
0488     }
0489 }
0490 
0491 function setFirstPhaseMove() {
0492     //Assigning States -> State "1" or "2" is used for identifying player and computer
0493     var playerState = items.playSecond ? "2" : "1"
0494     var computerState = items.playSecond ? "1" : "2"
0495 
0496     if(items.currentLevel > 0) {
0497         var value = evaluateBoard(computerState)
0498         if(value != -1)
0499             return value
0500     }
0501 
0502     if(items.currentLevel > 1) {
0503         var value = evaluateBoard(playerState)
0504         if(value != -1)
0505             return value
0506     }
0507 
0508     var found = false
0509     while (!found) {
0510         var randno = Math.floor((Math.random() * numberOfDragPoints))
0511         if(items.dragPoints.itemAt(randno).state == "EMPTY" || items.dragPoints.itemAt(randno).state == "AVAILABLE")
0512             found = true
0513     }
0514     return randno
0515 }
0516 
0517 function evaluateBoard(state) {
0518     for(var i = 0 ; i < numberOfDragPoints ; ++i) {
0519         if(items.dragPoints.itemAt(i).state == "EMPTY" || items.dragPoints.itemAt(i).state == "AVAILABLE") {
0520             if(checkMill(i,state))
0521                 return i
0522         }
0523     }
0524     return -1
0525 }
0526 
0527 function setSecondPhaseMove() {
0528     var index = []
0529     var found = false
0530 
0531     if(items.currentLevel > 0) {
0532         for(var i = 0 ; i < numberOfPieces ; ++i) {
0533             var piece = currentRepeater.itemAt(i)
0534             if(piece.visible) {
0535                 index[0] = i
0536                 if(piece.pieceParent.leftPoint && piece.pieceParent.leftPoint.state == "EMPTY") {
0537                     if(checkMill(piece.pieceParent.leftPoint.index, piece.state, "left")) {
0538                         index[1] = piece.pieceParent.leftPoint.index
0539                         found = true
0540                         break
0541                     }
0542                 }
0543                 if(piece.pieceParent.rightPoint && piece.pieceParent.rightPoint.state == "EMPTY") {
0544                     if(checkMill(piece.pieceParent.rightPoint.index, piece.state, "right")) {
0545                         index[1] = piece.pieceParent.rightPoint.index
0546                         found = true
0547                         break
0548                     }
0549                 }
0550                 if(piece.pieceParent.upperPoint && piece.pieceParent.upperPoint.state == "EMPTY") {
0551                     if(checkMill(piece.pieceParent.upperPoint.index, piece.state, "upper")) {
0552                         index[1] = piece.pieceParent.upperPoint.index
0553                         found = true
0554                         break
0555                     }
0556                 }
0557                 if(piece.pieceParent.lowerPoint && piece.pieceParent.lowerPoint.state == "EMPTY") {
0558                     if(checkMill(piece.pieceParent.lowerPoint.index, piece.state, "lower")) {
0559                         index[1] = piece.pieceParent.lowerPoint.index
0560                         found = true
0561                         break
0562                     }
0563                 }
0564             }
0565         }
0566         if(found)
0567             return index
0568     }
0569 
0570     var playerState = items.playSecond ? "2" : "1"
0571     if(items.currentLevel > 1) {
0572         for(var i = 0 ; i < numberOfPieces ; ++i) {
0573             var piece = currentRepeater.itemAt(i)
0574             if(piece.visible) {
0575                 index[0] = i
0576                 if(piece.pieceParent.leftPoint && piece.pieceParent.leftPoint.state == "EMPTY") {
0577                     if(checkMillPossible(piece.pieceParent.leftPoint.index, playerState)) {
0578                         index[1] = piece.pieceParent.leftPoint.index
0579                         found = true
0580                         break
0581                     }
0582                 }
0583                 if(piece.pieceParent.rightPoint && piece.pieceParent.rightPoint.state == "EMPTY") {
0584                     if(checkMillPossible(piece.pieceParent.rightPoint.index, playerState)) {
0585                         index[1] = piece.pieceParent.rightPoint.index
0586                         found = true
0587                         break
0588                     }
0589                 }
0590                 if(piece.pieceParent.upperPoint && piece.pieceParent.upperPoint.state == "EMPTY") {
0591                     if(checkMillPossible(piece.pieceParent.upperPoint.index, playerState)) {
0592                         index[1] = piece.pieceParent.upperPoint.index
0593                         found = true
0594                         break
0595                     }
0596                 }
0597                 if(piece.pieceParent.lowerPoint && piece.pieceParent.lowerPoint.state == "EMPTY") {
0598                     if(checkMillPossible(piece.pieceParent.lowerPoint.index, playerState)) {
0599                         index[1] = piece.pieceParent.lowerPoint.index
0600                         found = true
0601                         break
0602                     }
0603                 }
0604             }
0605         }
0606         if(found)
0607             return index
0608     }
0609 
0610     var permittedPieceIndex = []
0611     for(var i = 0 ; i < numberOfPieces ; ++i) {
0612         if(currentRepeater.itemAt(i).visible) {
0613             if(checkMovablePieces(currentRepeater.itemAt(i).pieceParent.index))
0614                 permittedPieceIndex.push(i)
0615         }
0616     }
0617 
0618     if(!permittedPieceIndex.length) {
0619         for(var i = 0 ; i < numberOfPieces ; ++i) {
0620             if(currentRepeater.itemAt(i).visible)
0621                 permittedPieceIndex.push(i)
0622         }
0623     }
0624 
0625     var found = false
0626     while (!found) {
0627         var randno = Math.floor((Math.random() * permittedPieceIndex.length))
0628         index[0] = permittedPieceIndex[randno]
0629         var permittedPointIndex = []
0630         var dragPoint = currentRepeater.itemAt(index[0]).pieceParent
0631 
0632         if(dragPoint.leftPoint && dragPoint.leftPoint.state == "EMPTY") {
0633             permittedPointIndex.push(dragPoint.leftPoint.index)
0634         }
0635         if(dragPoint.rightPoint && dragPoint.rightPoint.state == "EMPTY") {
0636             permittedPointIndex.push(dragPoint.rightPoint.index)
0637         }
0638         if(dragPoint.upperPoint && dragPoint.upperPoint.state == "EMPTY") {
0639             permittedPointIndex.push(dragPoint.upperPoint.index)
0640         }
0641         if(dragPoint.lowerPoint && dragPoint.lowerPoint.state == "EMPTY") {
0642             permittedPointIndex.push(dragPoint.lowerPoint.index)
0643         }
0644         if(permittedPointIndex.length) {
0645             var randNo = Math.floor((Math.random() * permittedPointIndex.length))
0646             index[1] = permittedPointIndex[randNo]
0647             found = true
0648         }
0649     }
0650     return index
0651 }
0652 
0653 function checkMillPossible(index, state) {
0654 
0655    // thirdPhase is true if opponent can move its piece anywhere
0656    var thirdPhase = (items.playSecond && numberOfSecondPieces < 4) || (!items.playSecond && numberOfFirstPieces < 4)
0657    var dragPoint = items.dragPoints.itemAt(index)
0658 
0659    if(dragPoint.leftPoint && dragPoint.leftPoint.leftPoint) {
0660         if(state == dragPoint.leftPoint.state && state == dragPoint.leftPoint.leftPoint.state) {
0661             if((dragPoint.upperPoint && state == dragPoint.upperPoint.state) ||
0662                (dragPoint.lowerPoint && state == dragPoint.lowerPoint.state) || thirdPhase)
0663                 return true;
0664         }
0665     }
0666     if(dragPoint.upperPoint && dragPoint.upperPoint.upperPoint) {
0667         if(state == dragPoint.upperPoint.state && state == dragPoint.upperPoint.upperPoint.state) {
0668             if((dragPoint.leftPoint && state == dragPoint.leftPoint.state) ||
0669                (dragPoint.rightPoint && state == dragPoint.rightPoint.state) || thirdPhase)
0670                 return true;
0671         }
0672     }
0673     if(dragPoint.rightPoint && dragPoint.rightPoint.rightPoint) {
0674         if(state == dragPoint.rightPoint.state && state == dragPoint.rightPoint.rightPoint.state) {
0675             if((dragPoint.upperPoint && state == dragPoint.upperPoint.state) ||
0676                (dragPoint.lowerPoint && state == dragPoint.lowerPoint.state) || thirdPhase)
0677                 return true;
0678         }
0679     }
0680     if(dragPoint.lowerPoint && dragPoint.lowerPoint.lowerPoint) {
0681         if(state == dragPoint.lowerPoint.state && state == dragPoint.lowerPoint.lowerPoint.state) {
0682             if((dragPoint.leftPoint && state == dragPoint.leftPoint.state) ||
0683                (dragPoint.rightPoint && state == dragPoint.rightPoint.state) || thirdPhase)
0684                 return true;
0685         }
0686     }
0687     if(dragPoint.lowerPoint && dragPoint.upperPoint) {
0688         if(state == dragPoint.lowerPoint.state && state == dragPoint.upperPoint.state) {
0689             if((dragPoint.leftPoint && state == dragPoint.leftPoint.state) ||
0690                (dragPoint.rightPoint && state == dragPoint.rightPoint.state) || thirdPhase)
0691                 return true;
0692         }
0693     }
0694     if(dragPoint.leftPoint && dragPoint.rightPoint) {
0695         if(state == dragPoint.leftPoint.state && state == dragPoint.rightPoint.state) {
0696             if((dragPoint.upperPoint && state == dragPoint.upperPoint.state) ||
0697                (dragPoint.lowerPoint && state == dragPoint.lowerPoint.state) || thirdPhase)
0698                 return true;
0699         }
0700     }
0701     return false;
0702 }
0703 
0704 function setThirdPhaseMove() {
0705 
0706     //Assigning States -> State "1" or "2" is used for identifying player and computer
0707     var playerState = items.playSecond ? "2" : "1"
0708     var computerState = items.playSecond ? "1" : "2"
0709     var index = []
0710 
0711     if(items.currentLevel > 1) {
0712         for(var i = 0 ; i < numberOfDragPoints ; ++i) {
0713             if(items.dragPoints.itemAt(i).state == "EMPTY") {
0714                 var value = checkMillThirdPhase(i, computerState)
0715                 if(value != -1) {
0716                     index[0] = value
0717                     index[1] = i
0718                     return index
0719                 }
0720             }
0721         }
0722     }
0723 
0724     var permittedPieceIndex = []
0725     for(var i = 0 ; i < numberOfPieces ; ++i) {
0726         if(currentRepeater.itemAt(i).visible) {
0727             if(!checkMillPossible(currentRepeater.itemAt(i).pieceParent.index, playerState)) {
0728                 permittedPieceIndex.push(i)
0729             }
0730         }
0731     }
0732 
0733     if(!permittedPieceIndex.length) {
0734         for(var i = 0 ; i < numberOfPieces ; ++i) {
0735             if(currentRepeater.itemAt(i).visible)
0736                 permittedPieceIndex.push(i)
0737         }
0738     }
0739 
0740     var randno = Math.floor((Math.random() * permittedPieceIndex.length))
0741     index[0] = permittedPieceIndex[randno]
0742 
0743     if(items.currentLevel > 2) {
0744         for(var i = 0 ; i < numberOfDragPoints ; ++i) {
0745             if(items.dragPoints.itemAt(i).state == "EMPTY") {
0746                 if(checkMillPossible(i,playerState)) {
0747                     index[1] = i
0748                     return index
0749                 }
0750             }
0751         }
0752     }
0753 
0754     for(var i = 0 ; i < numberOfDragPoints ; ++i) {
0755         var dragPoint = items.dragPoints.itemAt(i)
0756 
0757         if(dragPoint.state == "EMPTY" &&
0758           ((dragPoint.leftPoint && dragPoint.leftPoint.state == computerState
0759             && dragPoint.leftPoint.pieceIndex != index[0]) ||
0760            (dragPoint.rightPoint && dragPoint.rightPoint.state == computerState
0761             && dragPoint.rightPoint.pieceIndex != index[0]) ||
0762            (dragPoint.upperPoint && dragPoint.upperPoint.state == computerState
0763             && dragPoint.upperPoint.pieceIndex != index[0]) ||
0764            (dragPoint.lowerPoint && dragPoint.lowerPoint.state == computerState
0765             && dragPoint.lowerPoint.pieceIndex != index[0]))) {
0766                 index[1] = i
0767                 return index
0768         }
0769     }
0770 
0771     var permittedPointIndex = []
0772     for(var i = 0 ; i < numberOfDragPoints ; ++i) {
0773         if(items.dragPoints.itemAt(i).state == "EMPTY")
0774             permittedPointIndex.push(i)
0775     }
0776     randno = Math.floor((Math.random() * permittedPointIndex.length))
0777     index[1] = permittedPointIndex[randno]
0778     return index
0779 }
0780 
0781 function checkMillThirdPhase(index, state) {
0782 
0783     var dragPoint = items.dragPoints.itemAt(index)
0784     if(dragPoint.leftPoint && dragPoint.leftPoint.leftPoint) {
0785         if(state == dragPoint.leftPoint.state && state == dragPoint.leftPoint.leftPoint.state) {
0786             for(var i = 0 ; i < numberOfPieces ; ++i) {
0787                 if(currentRepeater.itemAt(i).visible && i != dragPoint.leftPoint.pieceIndex
0788                    && i != dragPoint.leftPoint.leftPoint.pieceIndex) {
0789                     return i
0790                 }
0791             }
0792         }
0793     }
0794 
0795     if(dragPoint.upperPoint && dragPoint.upperPoint.upperPoint) {
0796         if(state == dragPoint.upperPoint.state && state == dragPoint.upperPoint.upperPoint.state) {
0797             for(var i = 0 ; i < numberOfPieces ; ++i) {
0798                 if(currentRepeater.itemAt(i).visible && i != dragPoint.upperPoint.pieceIndex
0799                    && i != dragPoint.upperPoint.upperPoint.pieceIndex) {
0800                        return i
0801                 }
0802             }
0803         }
0804     }
0805     if(dragPoint.rightPoint && dragPoint.rightPoint.rightPoint) {
0806         if(state == dragPoint.rightPoint.state && state == dragPoint.rightPoint.rightPoint.state) {
0807             for(var i = 0 ; i < numberOfPieces ; ++i) {
0808                 if(currentRepeater.itemAt(i).visible && i != dragPoint.rightPoint.pieceIndex
0809                    && i != dragPoint.rightPoint.rightPoint.pieceIndex) {
0810                        return i
0811                 }
0812             }
0813         }
0814     }
0815     if(dragPoint.lowerPoint && dragPoint.lowerPoint.lowerPoint) {
0816         if(state == dragPoint.lowerPoint.state && state == dragPoint.lowerPoint.lowerPoint.state) {
0817             for(var i = 0 ; i < numberOfPieces ; ++i) {
0818                 if(currentRepeater.itemAt(i).visible && i != dragPoint.lowerPoint.pieceIndex
0819                    && i != dragPoint.lowerPoint.lowerPoint.pieceIndex) {
0820                        return i
0821                 }
0822             }
0823         }
0824     }
0825     if(dragPoint.lowerPoint && dragPoint.upperPoint) {
0826         if(state == dragPoint.lowerPoint.state && state == dragPoint.upperPoint.state) {
0827             for(var i = 0 ; i < numberOfPieces ; ++i) {
0828                 if(currentRepeater.itemAt(i).visible && i != dragPoint.lowerPoint.pieceIndex
0829                    && i != dragPoint.upperPoint.pieceIndex) {
0830                        return i
0831                 }
0832             }
0833         }
0834     }
0835     if(dragPoint.leftPoint && dragPoint.rightPoint) {
0836         if(state == dragPoint.leftPoint.state && state == dragPoint.rightPoint.state) {
0837             for(var i = 0 ; i < numberOfPieces ; ++i) {
0838                 if(currentRepeater.itemAt(i).visible && i != dragPoint.leftPoint.pieceIndex
0839                    && i != dragPoint.rightPoint.pieceIndex) {
0840                        return i
0841                 }
0842             }
0843         }
0844     }
0845     return -1
0846 }
0847 
0848 // continueGame() called by Piece when its animation stops and checkMill(piece) is false or
0849 // called after removePiece(index) has removed a piece
0850 function continueGame() {
0851     items.turn ++
0852     if(items.turn == (2 * numberOfPieces) && items.firstPhase) {
0853         secondPhase()
0854         items.turn --
0855         checkGameWon()
0856         return
0857     }
0858     if(items.turn % 2) {
0859         currentRepeater = items.secondPlayerPieces
0860         otherRepeater = items.firstPlayerPieces
0861     }
0862     else {
0863         currentRepeater = items.firstPlayerPieces
0864         otherRepeater = items.secondPlayerPieces
0865     }
0866     changeScale()
0867     shouldComputerPlay();
0868 }
0869 
0870 // position value is only used when checkMill is called by setSecondPhaseMove or getSecondPhaseRemoveIndex function
0871 // Else it is declared as undefined by default
0872 function checkMill(index, state, position) {
0873 
0874     var dragPoint = items.dragPoints.itemAt(index)
0875     if(dragPoint.leftPoint && dragPoint.leftPoint.leftPoint && position != "left" && position != "right") {
0876         if(state == dragPoint.leftPoint.state && state == dragPoint.leftPoint.leftPoint.state)
0877             return true;
0878     }
0879     if(dragPoint.upperPoint && dragPoint.upperPoint.upperPoint && position != "upper" && position != "lower") {
0880         if(state == dragPoint.upperPoint.state && state == dragPoint.upperPoint.upperPoint.state)
0881             return true;
0882     }
0883     if(dragPoint.rightPoint && dragPoint.rightPoint.rightPoint && position != "right" && position != "left") {
0884         if(state == dragPoint.rightPoint.state && state == dragPoint.rightPoint.rightPoint.state)
0885             return true;
0886     }
0887     if(dragPoint.lowerPoint && dragPoint.lowerPoint.lowerPoint && position != "lower" && position != "upper") {
0888         if(state == dragPoint.lowerPoint.state && state == dragPoint.lowerPoint.lowerPoint.state)
0889             return true;
0890     }
0891     if(dragPoint.lowerPoint && dragPoint.upperPoint && position != "lower" && position != "upper") {
0892         if(state == dragPoint.lowerPoint.state && state == dragPoint.upperPoint.state)
0893             return true;
0894     }
0895     if(dragPoint.leftPoint && dragPoint.rightPoint && position != "left" && position != "right") {
0896         if(state == dragPoint.leftPoint.state && state == dragPoint.rightPoint.state)
0897             return true;
0898     }
0899     return false;
0900 }
0901 
0902 //check movable pieces
0903 function checkMovablePieces(index) {
0904     var dragPoint = items.dragPoints.itemAt(index)
0905     if(dragPoint.leftPoint && dragPoint.leftPoint.state == "EMPTY") {
0906         return true;
0907     }
0908     if(dragPoint.rightPoint && dragPoint.rightPoint.state == "EMPTY") {
0909         return true;
0910     }
0911     if(dragPoint.upperPoint && dragPoint.upperPoint.state == "EMPTY") {
0912         return true;
0913     }
0914     if(dragPoint.lowerPoint && dragPoint.lowerPoint.state == "EMPTY") {
0915         return true;
0916     }
0917     return false;
0918 }
0919 
0920 // updateRemovablePiece called by Piece when its animation stops and checkMill(piece) is true
0921 function updateRemovablePiece() {
0922 
0923     if(twoPlayer || ((items.turn % 2) && items.playSecond) || (!(items.turn % 2) && !items.playSecond)) {
0924         var foundOne = false
0925         for(var i = 0 ; i < numberOfPieces ; ++i) {
0926             var piece = otherRepeater.itemAt(i)
0927             if(piece.parentIndex != -1) {
0928                 if(!checkMill(piece.parentIndex, piece.state) && piece.visible) {
0929                     foundOne = true
0930                     piece.canBeRemoved = true // Mark pieces of other player for removal
0931                 }
0932             }
0933         }
0934         if(!foundOne) {
0935             for(var i = 0 ; i < numberOfPieces ; ++i) {
0936                 if(otherRepeater.itemAt(i).parentIndex != -1 && otherRepeater.itemAt(i).visible)
0937                     otherRepeater.itemAt(i).canBeRemoved = true
0938             }
0939         }
0940         items.instructionTxt = qsTr("Remove a piece")
0941     }
0942     else if(items.currentLevel < 4) {
0943         if(items.firstPhase)
0944             otherRepeater.itemAt(getFirstPhaseRemoveIndex()).remove()
0945         else
0946             otherRepeater.itemAt(getSecondPhaseRemoveIndex()).remove()
0947     }
0948     else {
0949         var board = getBoard()
0950         var boardPiecesLeft = items.firstPieceNumberCount + items.secondPieceNumberCount
0951         var index = alphabeta(depthMax, -9000, 9000, 2, board, boardPiecesLeft, true)
0952         var pieceIndex = items.dragPoints.itemAt(index).pieceIndex
0953         otherRepeater.itemAt(pieceIndex).remove()
0954     }
0955 }
0956 
0957 function getFirstPhaseRemoveIndex() {
0958 
0959     var playerState = items.playSecond ? "2" : "1"
0960     var permittedIndex = [];
0961     for(var i = 0 ; i < numberOfPieces ; ++i) {
0962         var piece = otherRepeater.itemAt(i)
0963         if(piece.parentIndex != -1) {
0964             if(!checkMill(piece.parentIndex, piece.state) && piece.visible)
0965                 permittedIndex.push(i)
0966         }
0967     }
0968     if(permittedIndex.length == 0) {
0969         for(var i = 0 ; i < numberOfPieces ; ++i) {
0970             if((otherRepeater.itemAt(i).parentIndex != -1) && (otherRepeater.itemAt(i).visible))
0971                 permittedIndex.push(i)
0972         }
0973     }
0974 
0975     if(items.currentLevel > 3) {
0976         var index = evaluateBoard(playerState)
0977         if(index != -1) {
0978             var value = -1
0979             var dragPoint = items.dragPoints.itemAt(index)
0980             if(dragPoint.leftPoint)
0981                 value = checkRemovedIndex(playerState, dragPoint.leftPoint,
0982                                           dragPoint.leftPoint.leftPoint, permittedIndex)
0983             if(value != -1)
0984                 return value
0985 
0986             if(dragPoint.upperPoint)
0987                 value = checkRemovedIndex(playerState, dragPoint.upperPoint,
0988                                           dragPoint.upperPoint.upperPoint, permittedIndex)
0989             if(value != -1)
0990                 return value
0991 
0992             if(dragPoint.rightPoint)
0993                 value = checkRemovedIndex(playerState, dragPoint.rightPoint,
0994                                           dragPoint.rightPoint.rightPoint, permittedIndex)
0995             if(value != -1)
0996                 return value
0997 
0998             if(dragPoint.lowerPoint)
0999                 value = checkRemovedIndex(playerState, dragPoint.lowerPoint,
1000                                           dragPoint.lowerPoint.lowerPoint, permittedIndex)
1001             if(value != -1)
1002                 return value
1003 
1004             if(dragPoint.lowerPoint)
1005                 value = checkRemovedIndex(playerState, dragPoint.lowerPoint,
1006                                           dragPoint.upperPoint, permittedIndex)
1007             if(value != -1)
1008                 return value
1009 
1010             if(dragPoint.leftPoint)
1011                 value = checkRemovedIndex(playerState, dragPoint.leftPoint,
1012                                           dragPoint.rightPoint, permittedIndex)
1013             if(value != -1)
1014                 return value
1015         }
1016     }
1017 
1018     var randno = Math.floor((Math.random() * permittedIndex.length))
1019     return permittedIndex[randno]
1020 }
1021 
1022 function checkRemovedIndex(state,first,second,permittedIndex) {
1023 
1024     if(second) {
1025         if(state == first.state && state == second.state) {
1026                 if(Math.floor((Math.random() * 2))) {
1027                     for (var i = 0 ; i < permittedIndex.length ; ++ i) {
1028                         if(permittedIndex[i] == first.pieceIndex)
1029                             return first.pieceIndex
1030                     }
1031                     for (var i = 0 ; i < permittedIndex.length ; ++ i) {
1032                         if(permittedIndex[i] == second.pieceIndex)
1033                             return second.pieceIndex
1034                     }
1035                 }
1036                 else {
1037                     for (var i = 0 ; i < permittedIndex.length ; ++ i) {
1038                         if(permittedIndex[i] == second.pieceIndex)
1039                             return second.pieceIndex
1040                     }
1041                     for (var i = 0 ; i < permittedIndex.length ; ++ i) {
1042                         if(permittedIndex[i] == first.pieceIndex)
1043                             return first.pieceIndex
1044                     }
1045                 }
1046         }
1047     }
1048     return -1
1049 }
1050 
1051 function getSecondPhaseRemoveIndex() {
1052     var permittedIndex = [];
1053     for(var i = 0 ; i < numberOfPieces ; ++i) {
1054         var piece = otherRepeater.itemAt(i)
1055         if(piece.parentIndex != -1) {
1056             if(piece.visible && !checkMill(piece.parentIndex, piece.state))
1057                 permittedIndex.push(i)
1058         }
1059     }
1060 
1061     if(permittedIndex.length == 0) {
1062         for(var i = 0 ; i < numberOfPieces ; ++i) {
1063             if((otherRepeater.itemAt(i).parentIndex != -1) && (otherRepeater.itemAt(i).visible))
1064                 permittedIndex.push(i)
1065         }
1066     }
1067 
1068     for(var index = 0 ; index < permittedIndex.length ; ++index) {
1069         var i = permittedIndex[index]
1070         var piece = otherRepeater.itemAt(i)
1071 
1072         if(piece.visible) {
1073             if(piece.pieceParent.leftPoint && piece.pieceParent.leftPoint.state == "EMPTY") {
1074                 if(checkMill(piece.pieceParent.leftPoint.index, piece.state, "left")) {
1075                     return i
1076                 }
1077             }
1078             if(piece.pieceParent.rightPoint && piece.pieceParent.rightPoint.state == "EMPTY") {
1079                 if(checkMill(piece.pieceParent.rightPoint.index, piece.state, "right")) {
1080                     return i
1081                 }
1082             }
1083             if(piece.pieceParent.upperPoint && piece.pieceParent.upperPoint.state == "EMPTY") {
1084                 if(checkMill(piece.pieceParent.upperPoint.index, piece.state, "upper")) {
1085                     return i
1086                 }
1087             }
1088             if(piece.pieceParent.lowerPoint && piece.pieceParent.lowerPoint.state == "EMPTY") {
1089                 if(checkMill(piece.pieceParent.lowerPoint.index, piece.state, "lower")) {
1090                     return i
1091                 }
1092             }
1093         }
1094     }
1095 
1096     return getFirstPhaseRemoveIndex()
1097 }
1098 
1099 // removePiece(index) called by Piece when items.pieceBeingRemoved is true
1100 function removePiece(index) {
1101     otherRepeater.itemAt(index).visible = false
1102     // Decrease number of pieces of other player by 1
1103     if(items.turn % 2)
1104         numberOfFirstPieces --
1105     else
1106         numberOfSecondPieces --
1107     if(items.firstPhase) {
1108         items.instructionTxt = qsTr("Place a piece")
1109         continueGame()
1110     }
1111     else
1112         checkGameWon()
1113 }
1114 
1115 function removePieceSelected(index) {
1116     otherRepeater.itemAt(index).pieceParent.state = items.firstPhase ? "AVAILABLE" : "EMPTY"
1117     for(var i = 0 ; i < numberOfPieces ; ++i)
1118         otherRepeater.itemAt(i).canBeRemoved = false
1119 }
1120 
1121 function checkGameWon() {
1122     // Check if other player can mover or not
1123     var flag = true;
1124     for (var i = 0 ; i < numberOfPieces ; ++i) {
1125         var piece = otherRepeater.itemAt(i)
1126         if(piece.visible) {
1127             if((piece.pieceParent.leftPoint && piece.pieceParent.leftPoint.state == "EMPTY") ||
1128                (piece.pieceParent.rightPoint && piece.pieceParent.rightPoint.state == "EMPTY") ||
1129                (piece.pieceParent.upperPoint && piece.pieceParent.upperPoint.state == "EMPTY") ||
1130                (piece.pieceParent.lowerPoint && piece.pieceParent.lowerPoint.state == "EMPTY")) {
1131                     flag = false
1132                     break
1133             }
1134         }
1135     }
1136 
1137     if(((numberOfSecondPieces < 3 && !items.playSecond) || (numberOfFirstPieces < 3 && items.playSecond)) ||
1138        (flag && ((currentPiece.state == "1" && !items.playSecond && numberOfSecondPieces > 3) ||
1139        (currentPiece.state == "2" && items.playSecond && numberOfFirstPieces > 3)))) {
1140         items.gameDone = true
1141         items.player1score.win();
1142         items.player2score.endTurn();
1143         items.instructionTxt = qsTr("Congratulations")
1144         items.bonus.good("flower")
1145         if(twoPlayer) {
1146             items.instructionTxt = qsTr("Congratulations Player 1")
1147         }
1148     }
1149     else if(((numberOfFirstPieces < 3 && !items.playSecond) || (numberOfSecondPieces < 3 && items.playSecond)) ||
1150             (flag && ((currentPiece.state == "2" && !items.playSecond && numberOfFirstPieces > 3) ||
1151             (currentPiece.state == "1" && items.playSecond && numberOfSecondPieces > 3)))) {
1152         items.gameDone = true
1153         items.player2score.win();
1154         items.player1score.endTurn();
1155         if(twoPlayer) {
1156             items.bonus.good("flower")
1157             items.instructionTxt = qsTr("Congratulations Player 2")
1158         }
1159         else {
1160             items.instructionTxt = qsTr("Try again")
1161             items.bonus.bad("tux")
1162         }
1163     }
1164     else {
1165         // Continue the game
1166         items.instructionTxt = qsTr("Move a piece")
1167         continueGame()
1168     }
1169 }
1170 
1171 function getBoard() {
1172     var board = []
1173     for (var i = 0 ; i < numberOfDragPoints ; ++i) {
1174         if(items.dragPoints.itemAt(i).state == "1") {
1175             if(items.playSecond)
1176                 board.push(2)
1177             else
1178                 board.push(1)
1179         }
1180         else if(items.dragPoints.itemAt(i).state == "2") {
1181             if(items.playSecond)
1182                 board.push(1)
1183             else
1184                 board.push(2)
1185         }
1186         else
1187             board.push(0)
1188     }
1189     return board
1190 }
1191 
1192 function alphabeta(depth, alpha, beta, player, board, boardPiecesLeft, mill) {
1193 
1194     var firstPhase = boardPiecesLeft != 0
1195     var values = getValue(board, firstPhase, player)
1196     var value = values.value
1197     var myToBeMill = 0
1198     var oppToBeMill = 0
1199 
1200     if(value != 9000 && value != -9000 && depth == 0) {
1201         var lost = -8500
1202         var win = 8500
1203         var toBeMill = 1.8
1204         var myMillReachable = false
1205         var oppMillReachable = false
1206         var playerPieces = values.playerPieces
1207         var computerPieces = values.computerPieces
1208 
1209         for (var i = 0 ; i < numberOfDragPoints ; ++i) {
1210             if (board[i] == 0) {
1211                 if(checkMillBoardPossible(board, i, 2, firstPhase, computerPieces)) {
1212                     myToBeMill++
1213                     if(positionReachable(board, i, 1, firstPhase, playerPieces))
1214                         myMillReachable = true
1215                 }
1216                 if(checkMillBoardPossible(board, i, 1, firstPhase, playerPieces)) {
1217                     oppToBeMill++
1218                     if(positionReachable(board, i, 2, firstPhase, computerPieces))
1219                         oppMillReachable = true
1220                 }
1221             }
1222         }
1223 
1224         if(myToBeMill > 2 && playerPieces == 4 && !firstPhase && (mill == false || player == 2)){
1225             value: win - 50
1226         }
1227         else if(oppToBeMill > 2 && computerPieces == 4 && !firstPhase && (mill == false || player == 1)) {
1228             value: lost + 50
1229         }
1230         else {
1231             if(myToBeMill > 0 && myMillReachable && player == 1 && ((playerPieces != 3 &&
1232                !firstPhase) || firstPhase))
1233                 myToBeMill--
1234             if(oppToBeMill > 0 && oppMillReachable && player == 2 && ((computerPieces != 3 &&
1235                !firstPhase) || firstPhase))
1236                 oppToBeMill--
1237 
1238             if(myToBeMill > 0 && playerPieces == 3 && player == 2 && !firstPhase){
1239                 value = win
1240             }
1241             else if(oppToBeMill > 0 && computerPieces == 3 && player == 1 && !firstPhase){
1242                 value = lost
1243             }
1244             else if(myToBeMill > 1 && playerPieces == 3 && player == 1 && !firstPhase &&
1245                     !mill){
1246                 value = win - 25
1247             }
1248             else if(oppToBeMill > 1 && computerPieces == 3 && player == 2 && !firstPhase &&
1249                     !mill){
1250                 value = lost + 25
1251             }
1252             else
1253                 value += toBeMill * (myToBeMill - oppToBeMill)
1254         }
1255 
1256         if(mill && depth == 0){// && value < 8000 && value > -8000) {
1257             if(player == 2 && playerPieces == 3 && !firstPhase)
1258                 value = 9000
1259             else if(player == 1 && computerPieces == 3 && !firstPhase)
1260                 value = -9000
1261             else if(player == 2) {
1262                 if(oppToBeMill == 0)
1263                     value += 1.4
1264                 else if(oppToBeMill == 1)
1265                     value += 3.2
1266                 else
1267                     value += 4.8
1268             }
1269             else {
1270                 if(myToBeMill == 0)
1271                     value -= 1.4
1272                 else if(myToBeMill == 1)
1273                     value -= 3.2
1274                 else
1275                     value -= 4.8
1276             }
1277         }
1278 
1279         if(mill && depth == 1 && !firstPhase && player == 2 && playerPieces == 4
1280            && oppToBeMill > 0)
1281            return value + 3.2
1282 
1283         value = Math.round(value * 1000) / 1000
1284     }
1285 
1286     if(depth == 0 || ((value == 9000 || value < -8000) && depth != depthMax)) {
1287         return value
1288     }
1289 
1290     if(player == 2) {
1291         var scores = []
1292         if(mill) {
1293             var removableIndex = getRemovableIndexFromBoard(board, 1)
1294             var found = false
1295             for(var i = 0 ; i < removableIndex.length ; ++i) {
1296                 board[removableIndex[i]] = 0
1297                 var newAlpha = alphabeta(depth - 1, alpha, beta, 1, board, boardPiecesLeft, false)
1298                 board[removableIndex[i]] = 1
1299                 if(newAlpha >= alpha) {
1300                     found = true
1301                     alpha = newAlpha
1302                     scores[i] = alpha
1303                 }
1304                 if(beta < alpha) break
1305             }
1306             if(depth == depthMax) {
1307                 var max = -9000;
1308                 for(var i = 0; i < scores.length; i++) {
1309                     if(scores[i] != undefined && scores[i] > max)
1310                         max = scores[i]
1311                 }
1312                 var index = []
1313                 for(var i = 0; i < scores.length; i++) {
1314                     if(scores[i] != undefined && scores[i] == max)
1315                         index.push(i)
1316                 }
1317                 var randno = Math.floor((Math.random() * index.length))
1318                 return removableIndex[index[randno]]
1319             }
1320             if(found)
1321                 return alpha
1322             else
1323                 return alpha - 1000
1324         }
1325         else if(firstPhase) {
1326             var scores = []
1327             var moves = generateMove(board, 2, 0, true)
1328             for(var i = 0 ; i < moves.length ; ++i) {
1329                 var move = moves[i]
1330                 board[move] = 2
1331                 boardPiecesLeft--
1332                 var newAlpha
1333                 if(checkMillBoard(board, move) != 0)
1334                     newAlpha = alphabeta(depth - 1, alpha, beta, 2, board, boardPiecesLeft, true)
1335                 else
1336                     newAlpha = alphabeta(depth - 1, alpha, beta, 1, board, boardPiecesLeft, false)
1337                 boardPiecesLeft++
1338                 board[move] = 0
1339                 if(newAlpha >= alpha) {
1340                     alpha = newAlpha
1341                     scores[i] = alpha
1342                 }
1343                 if(beta < alpha) break
1344             }
1345             if(depth == depthMax) {
1346                 var max = -9000;
1347                 for(var i = 0; i < scores.length; i++) {
1348                     if(scores[i] != undefined && scores[i] > max)
1349                         max = scores[i]
1350                 }
1351                 var index = []
1352                 for(var i = 0; i < scores.length; i++) {
1353                     if(scores[i] != undefined && scores[i] == max)
1354                         index.push(i)
1355                 }
1356                 var randno = Math.floor((Math.random() * index.length))
1357                 return moves[index[randno]]
1358             }
1359             return alpha
1360         }
1361         else {
1362             var computerPointsIndex = []
1363             for (var i = 0 ; i < numberOfDragPoints ; ++i) {
1364                 if(board[i] == 2)
1365                     computerPointsIndex.push(i)
1366             }
1367             var scores = []
1368             for (var i = 0 ; i < computerPointsIndex.length ; ++i) {
1369                 var computerPoint = computerPointsIndex[i]
1370                 var moves = generateMove(board, 2, computerPoint, false)
1371                 scores[i] = []
1372                 for(var j = 0 ; j < moves.length ; ++j) {
1373                     var move = moves[j]
1374                     board[computerPoint] = 0
1375                     board[move] = 2
1376                     var newAlpha
1377                     if(checkMillBoard(board, move) != 0)
1378                         newAlpha = alphabeta(depth - 1, alpha, beta, 2, board, boardPiecesLeft, true)
1379                     else
1380                         newAlpha = alphabeta(depth - 1, alpha, beta, 1, board, boardPiecesLeft, false)
1381                     board[computerPoint] = 2
1382                     board[move] = 0
1383                     if(newAlpha >= alpha) {
1384                         alpha = newAlpha
1385                         scores[i][move] = alpha
1386                     }
1387                     if(beta < alpha) break
1388                 }
1389                 if(beta < alpha) break
1390             }
1391             if(depth == depthMax) {
1392                 var max = -9000;
1393                 for(var i = 0; i < scores.length; i++) {
1394                     for(var j = 0 ; j < scores[i].length ; j++) {
1395                         if(scores[i][j] != undefined) {
1396                             if(scores[i][j] > max) {
1397                                 max = scores[i][j]
1398                             }
1399                         }
1400                     }
1401                 }
1402                 var moveIndex = []
1403                 for(var i = 0; i < scores.length; i++) {
1404                     for(var j = 0 ; j < scores[i].length ; j++) {
1405                         if(scores[i][j] != undefined && scores[i][j] == max) {
1406                             var index = []
1407                             index[0] = computerPointsIndex[i]
1408                             index[1] = j
1409                             moveIndex.push(index)
1410                         }
1411                     }
1412                 }
1413                 var randno = Math.floor((Math.random() * moveIndex.length))
1414                 return moveIndex[randno]
1415             }
1416             return alpha
1417         }
1418     }
1419     else {
1420         if(mill) {
1421             var removableIndex = getRemovableIndexFromBoard(board, 2)
1422             for(var i = 0 ; i < removableIndex.length ; ++i) {
1423                 board[removableIndex[i]] = 0
1424                 if(playerPieces == 3 && computerPieces == 4 && !firstPhase)
1425                     beta = Math.min(beta, alphabeta(depth, alpha, beta, 2, board, boardPiecesLeft, false))
1426                 board[removableIndex[i]] = 2
1427                 if(beta < alpha) break
1428             }
1429             return beta
1430         }
1431         else if(boardPiecesLeft != 0) { // First Phase
1432             var moves = generateMove(board, 1, 0, true)
1433             for(var i = 0 ; i < moves.length ; ++i) {
1434                 var move = moves[i]
1435                 board[move] = 1
1436                 boardPiecesLeft--
1437                 if(checkMillBoard(board, move) != 0)
1438                     beta = Math.min(beta, alphabeta(depth - 1, alpha, beta, 1, board, boardPiecesLeft, true))
1439                 else
1440                     beta = Math.min(beta, alphabeta(depth - 1, alpha, beta, 2, board, boardPiecesLeft, false))
1441                 boardPiecesLeft++
1442                 board[move] = 0
1443                 if(beta < alpha) break
1444             }
1445             return beta
1446         }
1447         else {
1448             var playerPointsIndex = []
1449             for (var i = 0 ; i < numberOfDragPoints ; ++i) {
1450                 if(board[i] == 1)
1451                     playerPointsIndex.push(i)
1452             }
1453             for (var i = 0 ; i < playerPointsIndex.length ; ++i) {
1454                 var playerPoint = playerPointsIndex[i]
1455                 var moves = generateMove(board, 1, playerPoint, false)
1456                 for(var j = 0 ; j < moves.length ; ++j) {
1457                     var move = moves[j]
1458                     board[playerPoint] = 0
1459                     board[move] = 1
1460                     if(checkMillBoard(board, move) != 0)
1461                         beta = Math.min(beta, alphabeta(depth - 1, alpha, beta, 1, board, boardPiecesLeft, true))
1462                     else
1463                         beta = Math.min(beta, alphabeta(depth - 1, alpha, beta, 2, board, boardPiecesLeft, false))
1464                     board[playerPoint] = 1
1465                     board[move] = 0
1466                     if(beta < alpha) break
1467                 }
1468                 if(beta < alpha) break
1469             }
1470             return beta
1471         }
1472     }
1473 }
1474 
1475 function getRemovableIndexFromBoard(board, state) {
1476 
1477     var index = []
1478     for (var i = 0 ; i < numberOfDragPoints ; ++i) {
1479         if (board[i] == state && checkMillBoard(board, i) == 0)
1480             index.push(i)
1481     }
1482     if(index.length == 0) {
1483         for (var i = 0 ; i < numberOfDragPoints ; ++i) {
1484             if (board[i] == state)
1485                 index.push(i)
1486         }
1487     }
1488     return index
1489 }
1490 
1491 function getValue(board, firstPhase, player) {
1492 
1493     var value = 0.0
1494     var material = 1.0
1495     var freedom = 0.2
1496     var mills = 0.8
1497     var lost = -8500
1498     var win = 8500
1499     var toBeMill = 1.8
1500 
1501     // ========== material ==========
1502 
1503     var computerPieces = getNumberOfPieces(board, 2)
1504     var playerPieces = getNumberOfPieces(board, 1)
1505 
1506     if (computerPieces < 3 && !firstPhase) {
1507         return {value: lost - 500}
1508     }
1509 
1510     if (playerPieces < 3 && !firstPhase) {
1511         return {value: win + 500}
1512     }
1513 
1514     value += material * (computerPieces - playerPieces)
1515 
1516     // ========== mills ==========
1517 
1518     var computerMills = 0
1519     var playerMills = 0
1520     var computerMillsIndex = []
1521     var playerMillsIndex = []
1522 
1523     for (var i = 0 ; i < numberOfDragPoints ; ++i) {
1524         if(computerMillsIndex.indexOf(i) == -1 && board[i] == 2) {
1525             computerMills += checkMillBoard(board, i, computerMillsIndex)
1526         }
1527         else if(playerMillsIndex.indexOf(i) == -1 && board[i] == 1) {
1528             playerMills += checkMillBoard(board, i, playerMillsIndex)
1529         }
1530     }
1531     value += mills * (computerMills - playerMills)
1532 
1533     // ========== freedom ==========
1534     if(playerPieces != 3 || computerPieces != 3 || firstPhase) {
1535         var myFreedom = 0
1536         var oppFreedom = 0
1537         for (var i = 0 ; i < numberOfDragPoints ; ++i) {
1538             if (board[i] == 2)
1539                 myFreedom += positionAchievable(board, i, computerPieces, firstPhase)
1540             else if (board[i] == 1)
1541                 oppFreedom += positionAchievable(board, i, playerPieces, firstPhase)
1542         }
1543 
1544         if (myFreedom == 0 && !firstPhase){
1545             return {value: lost, computerPieces: computerPieces, playerPieces: playerPieces}
1546         }
1547         if (oppFreedom == 0 && !firstPhase){
1548             return {value: win + 500, computerPieces: computerPieces, playerPieces: playerPieces}
1549         }
1550 
1551         if(((computerPieces > 3 && playerPieces == 3 && computerPieces < 6) ||
1552            (playerMills > 0 && playerPieces == 4)) && !firstPhase)
1553             freedom = 0
1554         value += freedom * (myFreedom - oppFreedom)
1555     }
1556     value = Math.round(value * 1000) / 1000
1557 
1558     return {value: value, computerPieces: computerPieces, playerPieces: playerPieces}
1559 }
1560 
1561 function getNumberOfPieces(board, state) {
1562     var no = 0
1563     for (var i = 0 ; i < numberOfDragPoints ; ++ i) {
1564             if (board[i] == state)
1565                 no ++
1566     }
1567     return no
1568 }
1569 
1570 function positionAchievable(board, index, noOfBoardPieces, firstPhase) {
1571     var positions = 0
1572     if(noOfBoardPieces == 3 && !firstPhase) {
1573         for (var i = 0 ; i < numberOfDragPoints ; ++ i) {
1574             if (board[i] == 0)
1575                 positions ++
1576         }
1577     }
1578     else {
1579         var point = items.dragPoints.itemAt(index)
1580         if(point.leftPoint && board[point.leftPoint.index] == 0)
1581             positions ++
1582         if(point.rightPoint && board[point.rightPoint.index] == 0)
1583             positions ++
1584         if(point.upperPoint && board[point.upperPoint.index] == 0)
1585             positions ++
1586         if(point.lowerPoint && board[point.lowerPoint.index] == 0)
1587             positions ++
1588     }
1589     return positions
1590 }
1591 
1592 function positionReachable(board, index, state, firstPhase, noOfBoardPieces) {
1593     if(noOfBoardPieces == 3 || firstPhase)
1594         return true
1595     else {
1596         var point = items.dragPoints.itemAt(index)
1597         if(point.leftPoint && board[point.leftPoint.index] == state)
1598             return true
1599         if(point.rightPoint && board[point.rightPoint.index] == state)
1600             return true
1601         if(point.upperPoint && board[point.upperPoint.index] == state)
1602             return true
1603         if(point.lowerPoint && board[point.lowerPoint.index] == state)
1604             return true
1605         return false
1606     }
1607 }
1608 
1609 function checkMillBoard(board, index, millsIndex) {
1610     var point = items.dragPoints.itemAt(index)
1611     var state = board[index]
1612     var mills = 0
1613     if (millsIndex == undefined)
1614         millsIndex = []
1615 
1616     if(point.leftPoint && point.leftPoint.leftPoint && state == board[point.leftPoint.index]
1617        && state == board[point.leftPoint.leftPoint.index]) {
1618         mills ++
1619         millsIndex.push(point.leftPoint.index)
1620         millsIndex.push(point.leftPoint.leftPoint.index)
1621     }
1622     if(point.upperPoint && point.upperPoint.upperPoint && state == board[point.upperPoint.index]
1623        && state == board[point.upperPoint.upperPoint.index]) {
1624         mills ++
1625         millsIndex.push(point.upperPoint.index)
1626         millsIndex.push(point.upperPoint.upperPoint.index)
1627     }
1628     if(point.rightPoint && point.rightPoint.rightPoint && state == board[point.rightPoint.index]
1629        && state == board[point.rightPoint.rightPoint.index]) {
1630         mills ++
1631         millsIndex.push(point.rightPoint.index)
1632         millsIndex.push(point.rightPoint.rightPoint.index)
1633     }
1634     if(point.lowerPoint && point.lowerPoint.lowerPoint && state == board[point.lowerPoint.index]
1635        && state == board[point.lowerPoint.lowerPoint.index]) {
1636         mills ++
1637         millsIndex.push(point.lowerPoint.index)
1638         millsIndex.push(point.lowerPoint.lowerPoint.index)
1639     }
1640     if(point.lowerPoint && point.upperPoint && state == board[point.lowerPoint.index]
1641        && state == board[point.upperPoint.index]) {
1642         mills ++
1643         millsIndex.push(point.lowerPoint.index)
1644         millsIndex.push(point.upperPoint.index)
1645     }
1646     if(point.leftPoint && point.rightPoint && state == board[point.leftPoint.index]
1647        && state == board[point.rightPoint.index]) {
1648         mills ++
1649         millsIndex.push(point.rightPoint.index)
1650         millsIndex.push(point.leftPoint.index)
1651     }
1652     return mills
1653 }
1654 
1655 function checkMillBoardPossible(board, index, state, firstPhase, pieces) {
1656 
1657    var freeMove = pieces == 3 || firstPhase
1658    var point = items.dragPoints.itemAt(index)
1659 
1660    if(point.leftPoint && point.leftPoint.leftPoint) {
1661         if(state == board[point.leftPoint.index] && state == board[point.leftPoint.leftPoint.index]) {
1662             if((point.upperPoint && state == board[point.upperPoint.index]) ||
1663                (point.lowerPoint && state == board[point.lowerPoint.index]) || freeMove)
1664                 return true;
1665         }
1666     }
1667     if(point.upperPoint && point.upperPoint.upperPoint) {
1668         if(state == board[point.upperPoint.index] && state == board[point.upperPoint.upperPoint.index]) {
1669             if((point.leftPoint && state == board[point.leftPoint.index]) ||
1670                (point.rightPoint && state == board[point.rightPoint.index]) || freeMove)
1671                 return true;
1672         }
1673     }
1674     if(point.rightPoint && point.rightPoint.rightPoint) {
1675         if(state == board[point.rightPoint.index] && state == board[point.rightPoint.rightPoint.index]) {
1676             if((point.upperPoint && state == board[point.upperPoint.index]) ||
1677                (point.lowerPoint && state == board[point.lowerPoint.index]) || freeMove)
1678                 return true;
1679         }
1680     }
1681     if(point.lowerPoint && point.lowerPoint.lowerPoint) {
1682         if(state == board[point.lowerPoint.index] && state == board[point.lowerPoint.lowerPoint.index]) {
1683             if((point.leftPoint && state == board[point.leftPoint.index]) ||
1684                (point.rightPoint && state == board[point.rightPoint.index]) || freeMove)
1685                 return true;
1686         }
1687     }
1688     if(point.lowerPoint && point.upperPoint) {
1689         if(state == board[point.lowerPoint.index] && state == board[point.upperPoint.index]) {
1690             if((point.leftPoint && state == board[point.leftPoint.index]) ||
1691                (point.rightPoint && state == board[point.rightPoint.index]) || freeMove)
1692                 return true;
1693         }
1694     }
1695     if(point.leftPoint && point.rightPoint) {
1696         if(state == board[point.leftPoint.index] && state == board[point.rightPoint.index]) {
1697             if((point.upperPoint && state == board[point.upperPoint.index]) ||
1698                (point.lowerPoint && state == board[point.lowerPoint.index]) || freeMove)
1699                 return true;
1700         }
1701     }
1702     return false;
1703 }
1704 
1705 function generateMove(board, state, index, firstPhase) {
1706     var moves = []
1707     if(firstPhase || getNumberOfPieces(board, state) == 3) {
1708         for (var i = 0 ; i < numberOfDragPoints ; ++i) {
1709             if (board[i] == 0)
1710                 moves.push(i)
1711         }
1712     }
1713     else {
1714         var point = items.dragPoints.itemAt(index)
1715         if(point.leftPoint && board[point.leftPoint.index] == 0)
1716             moves.push(point.leftPoint.index)
1717         if(point.rightPoint && board[point.rightPoint.index] == 0)
1718             moves.push(point.rightPoint.index)
1719         if(point.upperPoint && board[point.upperPoint.index] == 0)
1720             moves.push(point.upperPoint.index)
1721         if(point.lowerPoint && board[point.lowerPoint.index] == 0)
1722             moves.push(point.lowerPoint.index)
1723     }
1724     return moves
1725 }
1726 
1727