File indexing completed on 2024-05-05 15:52:56
0001 /* GCompris - algebra.js 0002 * 0003 * SPDX-FileCopyrightText: 2014 Aruna Sankaranarayanan and Bruno Coudoin 0004 * 0005 * SPDX-License-Identifier: GPL-3.0-or-later 0006 */ 0007 0008 .pragma library 0009 .import QtQuick 2.12 as Quick 0010 .import "qrc:/gcompris/src/core/core.js" as Core 0011 0012 var numberOfLevel 0013 var items 0014 var dataset 0015 var operand 0016 var secondOperandVal 0017 var firstOperandVal 0018 var subLevelData = [] 0019 var speedSetting 0020 var operandText 0021 var OperandsEnum = { 0022 TIMES_SIGN : "\u00D7", 0023 PLUS_SIGN : "\u002B", 0024 MINUS_SIGN : "\u2212", 0025 DIVIDE_SIGN : "\u2215" 0026 } 0027 0028 0029 function start(items_, operand_, speedSetting_) { 0030 operand = operand_ 0031 items = items_ 0032 speedSetting = speedSetting_ 0033 dataset = items.levels 0034 numberOfLevel = dataset.length 0035 items.currentLevel = Core.getInitialLevel(numberOfLevel) 0036 initLevel() 0037 } 0038 0039 function stop() { 0040 items.balloon.stopBalloon() 0041 } 0042 0043 // get appropriate operands depending on operator 0044 function getOperands(min, max) 0045 { 0046 switch(operand.text) 0047 { 0048 case OperandsEnum.TIMES_SIGN: 0049 return [randomInRange(min,max), randomInRange(min,max)] 0050 0051 case OperandsEnum.PLUS_SIGN: 0052 return [randomInRange(min,max), randomInRange(min,max)] 0053 0054 case OperandsEnum.MINUS_SIGN: 0055 // Left operand is always greater than right operand 0056 var minusLeftOperand = randomInRange(min, max) 0057 var minusRightOperand = randomInRange(min, minusLeftOperand) 0058 return [minusLeftOperand, minusRightOperand] 0059 0060 case OperandsEnum.DIVIDE_SIGN: 0061 // Left operand is a multiple of right operand 0062 var divideRightOperand = randomInRange(min, max) 0063 var divideLeftOperand = divideRightOperand * randomInRange(min, max) 0064 return [divideLeftOperand, divideRightOperand] 0065 } 0066 } 0067 0068 function initLevel() { 0069 items.score.visible = false 0070 items.okButton.visible = false 0071 items.score.currentSubLevel = 0 0072 subLevelData = [] 0073 0074 /** 0075 It exists two types of levels: 0076 - the operation table where all operands are defined in the dataset 0077 - the generated question, where the dataset specify constraits 0078 Leveltype is determined by checking what is the inner structure of the dataset 0079 */ 0080 if("operands" in dataset[items.currentLevel]) { 0081 items.score.numberOfSubLevels = dataset[items.currentLevel].operands.length; 0082 for(var i = 0; i < items.score.numberOfSubLevels; i++) 0083 subLevelData.push([dataset[items.currentLevel].operands[i].first, dataset[items.currentLevel].operands[i].second]) 0084 } 0085 else { 0086 // Generate random operations 0087 var minOperandValue = dataset[items.currentLevel].min 0088 var maxOperandValue = dataset[items.currentLevel].max 0089 var limit = dataset[items.currentLevel].limit 0090 items.score.numberOfSubLevels = 10; 0091 for(var i = 0; i < items.score.numberOfSubLevels; i++) 0092 { 0093 var leftOperand = 0; 0094 var rightOperand = 0; 0095 do 0096 { 0097 [leftOperand, rightOperand] = getOperands(minOperandValue, maxOperandValue); 0098 } while(limit !== 0 && getAnswer(leftOperand, rightOperand) > limit); 0099 subLevelData.push([leftOperand, rightOperand]) 0100 } 0101 } 0102 0103 subLevelData = Core.shuffle(subLevelData) 0104 calculateOperands() 0105 items.iAmReady.visible = true 0106 items.firstOp.visible = false 0107 items.secondOp.visible = false 0108 items.balloon.stopMoving() 0109 } 0110 0111 function randomInRange(min, max) { 0112 return Math.floor(min + Math.random() * (max - min + 1)) 0113 } 0114 0115 function circularShiftElements() { 0116 if(!validateAnswer(parseInt(items.numpad.answer))) 0117 subLevelData.push(subLevelData.shift()) 0118 else 0119 subLevelData.shift() 0120 } 0121 0122 function nextLevel() { 0123 items.currentLevel = Core.getNextLevel(items.currentLevel, numberOfLevel); 0124 initLevel(); 0125 } 0126 0127 function previousLevel() { 0128 items.currentLevel = Core.getPreviousLevel(items.currentLevel, numberOfLevel); 0129 initLevel(); 0130 } 0131 0132 function calculateOperands() 0133 { 0134 firstOperandVal = subLevelData[0][0] 0135 secondOperandVal = subLevelData[0][1] 0136 0137 items.firstOp.text = firstOperandVal 0138 items.secondOp.text = secondOperandVal 0139 } 0140 0141 // Return the expected answer 0142 function getAnswer(val1, val2) { 0143 switch(operand.text) 0144 { 0145 case OperandsEnum.TIMES_SIGN: 0146 return (val1 * val2) 0147 0148 case OperandsEnum.PLUS_SIGN: 0149 return (val1 + val2) 0150 0151 case OperandsEnum.MINUS_SIGN: 0152 return (val1 - val2) 0153 0154 case OperandsEnum.DIVIDE_SIGN: 0155 return (val1 / val2) 0156 } 0157 } 0158 0159 function validateAnswer(screenAnswer) 0160 { 0161 return (getAnswer(firstOperandVal, secondOperandVal) === screenAnswer) 0162 } 0163 0164 function run() { 0165 circularShiftElements() 0166 calculateOperands() 0167 items.numpad.resetText() 0168 items.score.visible = true 0169 items.iAmReady.visible = false 0170 items.firstOp.visible = true 0171 items.secondOp.visible = true 0172 items.okButton.visible = true 0173 items.numpad.answerFlag = false 0174 items.result = getAnswer(firstOperandVal, secondOperandVal) 0175 items.balloon.startMoving(100000 / speedSetting) 0176 items.buttonsBlocked = false 0177 } 0178 0179 function checkAnswer() { 0180 items.buttonsBlocked = true 0181 items.balloon.startMoving(100000) 0182 if(validateAnswer(parseInt(items.numpad.answer))) { 0183 items.score.currentSubLevel++ 0184 items.score.playWinAnimation() 0185 items.audioEffects.play("qrc:/gcompris/src/core/resource/sounds/completetask.wav") 0186 } else { 0187 items.errorRectangle.startAnimation() 0188 items.audioEffects.play("qrc:/gcompris/src/core/resource/sounds/crash.wav") 0189 } 0190 } 0191 0192 function questionsLeft() { 0193 if(items.score.currentSubLevel >= items.score.numberOfSubLevels) { 0194 items.bonus.good("smiley") 0195 } else { 0196 run() 0197 } 0198 }