File indexing completed on 2024-05-05 15:53:10
0001 /* GCompris - hanoi_real.js 0002 * 0003 * Copyright (C) 2015 <Amit Tomar> 0004 * 0005 * Authors: 0006 * Bruno Coudoin <bruno.coudoin@gcompris.net> (GTK+ version) 0007 * Amit Tomar <a.tomar@outlook.com> (Qt Quick hanoi tower port) 0008 * Johnny Jazeix <jazeix@gmail.com> (Qt Quick hanoi simplified port) 0009 * Timothée Giet <animtim@gmail.com> (Graphics refactoring) 0010 * 0011 * SPDX-License-Identifier: GPL-3.0-or-later 0012 */ 0013 .pragma library 0014 .import QtQuick 2.12 as Quick 0015 .import "qrc:/gcompris/src/core/core.js" as Core 0016 0017 var url = "qrc:/gcompris/src/activities/hanoi_real/resource/" 0018 0019 var numberOfLevel 0020 var items 0021 var activityMode 0022 0023 // Specific data for simplified mode 0024 var symbols = [ 0025 "!", "/", "<", 0026 ">", "&", "~", 0027 "#", "{", "%", 0028 "|", "?", "}", 0029 "=", "+", "*" 0030 ] 0031 0032 var colors = [ 0033 "#e41c1c", // red 0 0034 "#79e41c", // green 65 0035 "#1c8fe4", // blue 146 0036 "#e4bb1c", // yellow 34 0037 "#e41c92", // magenta 230 0038 "#1dc0e3", // cyan 135 0039 "#e3711d", // orange 18 0040 "#a91de3", // purple 200 0041 "#e44b1c", // red2 10 0042 "#1ce463", // green2 100 0043 "#1c4ce4", // blue2 160 0044 "#e4e01c", // yellow2 42 0045 "#f20ee5", // magenta2 215 0046 "#1de3da", // cyan2 126 0047 "#e4921c" // orange2 25 0048 ] 0049 0050 var nbTowersLessExpectedAndResultOnes 0051 var nbMaxItemsByTower 0052 0053 function start(items_, activityMode_) { 0054 items = items_ 0055 activityMode = activityMode_ 0056 numberOfLevel = (activityMode == "real") ? 3 : 6 0057 items.currentLevel = Core.getInitialLevel(numberOfLevel) 0058 0059 initLevel() 0060 } 0061 0062 function stop() { 0063 } 0064 0065 function initSpecificInfoForSimplified() { 0066 Core.shuffle(symbols); 0067 switch(items.currentLevel) { 0068 case 0: 0069 nbTowersLessExpectedAndResultOnes = 3; 0070 nbMaxItemsByTower = 5; 0071 break; 0072 case 1: 0073 nbTowersLessExpectedAndResultOnes = 4; 0074 nbMaxItemsByTower = 5; 0075 break; 0076 case 2: 0077 nbTowersLessExpectedAndResultOnes = 5; 0078 nbMaxItemsByTower = 6; 0079 break; 0080 case 3: 0081 nbTowersLessExpectedAndResultOnes = 6; 0082 nbMaxItemsByTower = 7; 0083 break; 0084 case 4: 0085 nbTowersLessExpectedAndResultOnes = 6; 0086 nbMaxItemsByTower = 8; 0087 break; 0088 case 5: 0089 nbTowersLessExpectedAndResultOnes = 5; 0090 nbMaxItemsByTower = 9; 0091 } 0092 } 0093 0094 function initLevel() { 0095 0096 items.hasWon = false 0097 0098 if(activityMode == "real") { 0099 items.numberOfDisc = items.currentLevel + 3 0100 items.discRepeater.model = items.numberOfDisc 0101 items.towerModel.model = 3 0102 } 0103 else { 0104 initSpecificInfoForSimplified(); 0105 items.towerModel.model = nbTowersLessExpectedAndResultOnes + 2 0106 0107 items.numberOfDisc = nbTowersLessExpectedAndResultOnes * (nbMaxItemsByTower-1) + nbMaxItemsByTower 0108 items.discRepeater.model = items.numberOfDisc 0109 } 0110 0111 placeDiscsAtOrigin() 0112 0113 if(activityMode != "real") { 0114 for(var i = 0 ; i < (items.numberOfDisc-nbMaxItemsByTower); ++i) { 0115 var index = Math.floor(Math.random() * symbols.length); 0116 items.discRepeater.itemAt(i).text = symbols[index]; 0117 items.discRepeater.itemAt(i).baseColor = colors[index]; 0118 } 0119 // Fill the text discs avoiding duplicates 0120 var currentAnswerId = items.numberOfDisc-nbMaxItemsByTower; 0121 var goodAnswerIndices = []; 0122 do { 0123 var id = Math.floor(Math.random() * (items.numberOfDisc-nbMaxItemsByTower)); 0124 if(goodAnswerIndices.indexOf(id) == -1) { 0125 items.discRepeater.itemAt(currentAnswerId).text = items.discRepeater.itemAt(id).text; 0126 items.discRepeater.itemAt(currentAnswerId).baseColor = items.discRepeater.itemAt(id).baseColor; 0127 goodAnswerIndices.push(id); 0128 currentAnswerId ++; 0129 } 0130 } 0131 while(currentAnswerId < items.numberOfDisc); 0132 } 0133 0134 disableNonDraggablediscs() 0135 } 0136 0137 function nextLevel() 0138 { 0139 items.currentLevel = Core.getNextLevel(items.currentLevel, numberOfLevel); 0140 initLevel(); 0141 } 0142 0143 function previousLevel() 0144 { 0145 items.currentLevel = Core.getPreviousLevel(items.currentLevel, numberOfLevel); 0146 initLevel(); 0147 } 0148 0149 function placeDisc(disc, towerImage) 0150 { 0151 disc.towerImage = towerImage 0152 disc.position = getNumberOfDiscOnTower(towerImage) 0153 disc.parent = towerImage 0154 setDiscY(disc, towerImage); 0155 } 0156 0157 function setDiscY(disc, towerImage) 0158 { 0159 // -(towerImage.height * 0.12) because we need to remove the base of the tower 0160 // dependent of the image! 0161 disc.y = towerImage.y + towerImage.height - disc.position * disc.height - (towerImage.height * 0.12) 0162 } 0163 0164 function placeDiscsAtOrigin() { 0165 // Reset the model to get the initial animation 0166 if(items.discRepeater.model === items.numberOfDisc) 0167 items.discRepeater.model = 0 0168 items.discRepeater.model = items.numberOfDisc 0169 0170 if(activityMode == "real") { 0171 for(var i = 0 ; i < items.numberOfDisc ; ++i) { 0172 placeDisc(items.discRepeater.itemAt(i), items.towerModel.itemAt(0)) 0173 items.discRepeater.itemAt(i).baseColor = colors[i]; 0174 } 0175 } 0176 else { 0177 // First fill the first towers 0178 for(var i = 0 ; i < (items.numberOfDisc-nbMaxItemsByTower); ++i) { 0179 placeDisc(items.discRepeater.itemAt(i), items.towerModel.itemAt(i%nbTowersLessExpectedAndResultOnes)) 0180 } 0181 // Fill last tower 0182 for(var i = items.numberOfDisc-nbMaxItemsByTower ; i < items.numberOfDisc ; ++i) { 0183 placeDisc(items.discRepeater.itemAt(i), items.towerModel.itemAt(nbTowersLessExpectedAndResultOnes+1)) 0184 } 0185 } 0186 } 0187 0188 function discReleased(index) 0189 { 0190 var disc = items.discRepeater.itemAt(index) 0191 var isCorrect = false; 0192 0193 if(activityMode == "real") { 0194 for(var i = 0 ; i < items.towerModel.model ; ++ i) { 0195 var towerItem = items.towerModel.itemAt(i); 0196 if(checkIfDiscOnTowerImage(disc, towerItem) && 0197 getNumberOfDiscOnTower(towerItem) < items.numberOfDisc && 0198 getHigherfDiscOnTower(towerItem) <= index) { 0199 placeDisc(disc, towerItem) 0200 isCorrect = true 0201 break; 0202 } 0203 } 0204 } 0205 else { 0206 for(var i = 0 ; i < items.towerModel.model ; ++ i) { 0207 var towerItem = items.towerModel.itemAt(i); 0208 if(checkIfDiscOnTowerImage(disc, towerItem) && 0209 getNumberOfDiscOnTower(towerItem) < nbMaxItemsByTower) { 0210 placeDisc(disc, towerItem) 0211 isCorrect = true 0212 break; 0213 } 0214 } 0215 } 0216 0217 if(!isCorrect) { 0218 // Cancel the drop 0219 setDiscY(disc, disc.towerImage) 0220 } 0221 0222 disableNonDraggablediscs() 0223 checkSolved() 0224 } 0225 0226 function sceneSizeChanged() 0227 { 0228 if(!items) 0229 return 0230 0231 for(var i = 0 ; i < items.numberOfDisc ; ++i) { 0232 var disc = items.discRepeater.itemAt(i) 0233 if(!disc || !disc.towerImage) 0234 continue 0235 setDiscY(disc, disc.towerImage) 0236 } 0237 0238 disableNonDraggablediscs() 0239 } 0240 0241 function disableNonDraggablediscs() 0242 { 0243 if(activityMode == "real") { 0244 // Only the highest (index) one is enabled 0245 for(var i = 0 ; i < items.numberOfDisc ; ++i) { 0246 var disc = items.discRepeater.itemAt(i) 0247 if(disc) 0248 disc.mouseEnabled = (getHigherfDiscOnTower(disc.towerImage) <= i) 0249 } 0250 } 0251 else { 0252 // In simplified, all the last tower discs are disabled 0253 // We disable all except the highest (in position) ones of each tower 0254 var highestOnes = []; 0255 for(var i = 0 ; i < items.numberOfDisc ; ++i) { 0256 var disc = items.discRepeater.itemAt(i) 0257 if(!disc) 0258 continue 0259 0260 disc.mouseEnabled = false 0261 if(disc.towerImage == items.towerModel.itemAt(items.towerModel.model-1)) { 0262 continue; 0263 } 0264 else if(highestOnes[disc.towerImage] == undefined) { 0265 highestOnes[disc.towerImage] = {"pos": disc.position, "id": i} 0266 } 0267 else if(highestOnes[disc.towerImage].pos < disc.position) { 0268 highestOnes[disc.towerImage].pos = disc.position 0269 highestOnes[disc.towerImage].id = i 0270 } 0271 } 0272 0273 for(var i in highestOnes) { 0274 items.discRepeater.itemAt(highestOnes[i].id).mouseEnabled = true 0275 } 0276 } 0277 } 0278 0279 function checkIfDiscOnTowerImage(disc, towerImage) 0280 { 0281 var discPosition = items.background.mapFromItem(disc, 0, 0) 0282 var towerPosition = items.background.mapFromItem(towerImage, 0, 0) 0283 return ((discPosition.x + disc.width / 2) > towerPosition.x && 0284 (discPosition.x + disc.width / 2) < towerPosition.x + towerImage.width) 0285 } 0286 0287 function getHigherfDiscOnTower(towerImage) { 0288 var higher = 0 0289 for(var i = 0 ; i < items.numberOfDisc ; ++i) 0290 { 0291 if(items.discRepeater.itemAt(i) && items.discRepeater.itemAt(i).towerImage === towerImage) 0292 higher = i 0293 } 0294 return higher 0295 } 0296 0297 function getNumberOfDiscOnTower(towerImage) { 0298 var count = 0 0299 for(var i = 0 ; i < items.numberOfDisc ; ++i) 0300 { 0301 if(items.discRepeater.itemAt(i).towerImage === towerImage) 0302 count++ 0303 } 0304 return count 0305 } 0306 0307 function checkSolved() { 0308 if(activityMode == "real") { 0309 if(getNumberOfDiscOnTower(items.towerModel.itemAt(items.towerModel.model-1)) === items.numberOfDisc) { 0310 items.hasWon = true 0311 items.bonus.good("flower") 0312 } 0313 } 0314 else { 0315 // Recreate both last towers text 0316 var expectedTower = []; 0317 var actualTower = []; 0318 for(var i = 0 ; i < items.numberOfDisc ; ++i) { 0319 var disc = items.discRepeater.itemAt(i); 0320 if(disc.towerImage == items.towerModel.itemAt(items.towerModel.model-1)) { 0321 actualTower[disc.position] = disc.text 0322 } 0323 else if(disc.towerImage == items.towerModel.itemAt(items.towerModel.model-2)) { 0324 expectedTower[disc.position] = disc.text 0325 } 0326 } 0327 0328 // Don't check if not the same length 0329 var hasWon = (expectedTower.length == actualTower.length) 0330 for (var i = 0; hasWon && i < actualTower.length; ++i) { 0331 if (expectedTower[i] !== actualTower[i]) hasWon = false 0332 } 0333 if(hasWon) { 0334 items.hasWon = true 0335 items.bonus.good("flower") 0336 } 0337 } 0338 } 0339 0340 function getDiscWidth(index) 0341 { 0342 if(activityMode == "real") { 0343 if( 0 === index ) return items.towerModel.itemAt(0).width * 1.6 0344 else if ( 1 === index ) return items.towerModel.itemAt(0).width * 1.3 0345 else if ( 2 === index ) return items.towerModel.itemAt(0).width * 1 0346 else if ( 3 === index ) return items.towerModel.itemAt(0).width * 0.7 0347 else return items.towerModel.itemAt(0).width * 0.5 0348 } 0349 else { 0350 return items.towerModel.itemAt(0).width 0351 } 0352 }