diff --git a/src/activities/ascending_order/ActivityInfo.qml b/src/activities/ascending_order/ActivityInfo.qml new file mode 100644 --- /dev/null +++ b/src/activities/ascending_order/ActivityInfo.qml @@ -0,0 +1,34 @@ +/* GCompris - ActivityInfo.qml + * + * Copyright (C) 2016 Rudra Nil Basu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +import GCompris 1.0 + +ActivityInfo { + name: "ascending_order/Ascending_order.qml" + difficulty: 2 + icon: "ascending_order/ascending_order.svg" + author: "Rudra Nil Basu <rudra.nil.basu.1996@gmail.com>" + demo: true + title: qsTr("Ascending and Descending Order") + description: qsTr("Arrange the given numbers in ascending or descending order as instructed") +// intro: "arrange the numbers in the correct order by placing a number in it's correct position" + goal: qsTr("arranging numbers in ascending or descending order as instructed") + prerequisite: qsTr("Move, drag and drop using mouse") + manual: qsTr("You are provided with few numbers. Drag and Drop the numbers in its correct position to reorder the numbers in ascending or descending order as instructed") + section: "math" + createdInVersion: 8000 +} diff --git a/src/activities/ascending_order/Ascending_order.qml b/src/activities/ascending_order/Ascending_order.qml new file mode 100644 --- /dev/null +++ b/src/activities/ascending_order/Ascending_order.qml @@ -0,0 +1,260 @@ +/* GCompris - ascending_order.qml + * + * Copyright (C) 2017 Rudra Nil Basu + * + * Authors: + * Rudra Nil Basu (Qt Quick port) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +import QtQuick 2.1 +import GCompris 1.0 + +import "../../core" +import "ascending_order.js" as Activity + +ActivityBase { + id: activity + + property string mode: "number" + + onStart: focus = true + onStop: {} + + pageComponent: Image { + id: background + anchors.fill: parent + fillMode: Image.PreserveAspectCrop + source: "resource/background.svg" + signal start + signal stop + + Component.onCompleted: { + activity.start.connect(start) + activity.stop.connect(stop) + } + + // Add here the QML items you need to access in javascript + QtObject { + id: items + property Item main: activity.main + property alias background: background + property alias bar: bar + property alias bonus: bonus + property alias boxes: boxes + property alias flow: flow + property alias hints: hints + property alias container: container + property alias instruction: instruction + property real ratio: ApplicationInfo.ratio + property alias score: score + } + + onStart: { Activity.start(items, mode) } + onStop: { Activity.stop() } + + GCText { + id: instruction + wrapMode: TextEdit.WordWrap + fontSize: tinySize + horizontalAlignment: Text.Center + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width * 0.9 + color: 'white' + Rectangle { + z: -1 + opacity: 0.8 + gradient: Gradient { + GradientStop { position: 0.0; color: "#000" } + GradientStop { position: 0.9; color: "#666" } + GradientStop { position: 1.0; color: "#AAA" } + } + radius: 10 + border.color: 'black' + border.width: 1 + anchors.centerIn: parent + width: parent.width * 1.1 + height: parent.contentHeight + } + } + + GCText { + id: hints + wrapMode: TextEdit.WordWrap + fontSize: tinySize + horizontalAlignment: Text.Center + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: instruction.height * 1.25 + width: parent.width * 0.5 + color: 'white' + visible: false + text: "" + Rectangle { + z: -1 + opacity: 0.8 + gradient: Gradient { + GradientStop { position: 0.0; color: "#000" } + GradientStop { position: 0.9; color: "#666" } + GradientStop { position: 1.0; color: "#AAA" } + } + radius: 10 + border.color: 'black' + border.width: 1 + anchors.centerIn: parent + width: parent.width * 1.1 + height: parent.contentHeight + } + } + + Rectangle { + id: container + color: "transparent" + width: Math.min(parent.width, ((boxes.itemAt(0)).width*boxes.model)+(boxes.model-1)*flow.spacing) + height: parent.height/2 + + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } + + Flow { + id: flow + spacing: 10 + + /* + * Count number of active animations in the activity + * at this current time + * (No input will be taken at this time) + */ + property int onGoingAnimationCount: 0 + property bool validMousePress + anchors { + fill: parent + } + Repeater { + id: boxes + model: 6 + Rectangle { + id: box + color: "white" + z: mouseArea.drag.active || mouseArea.pressed ? 2 : 1 + property string boxValue + property point beginDragPosition + + width: 65 * ApplicationInfo.ratio + height: 65 * ApplicationInfo.ratio + radius: 10 + border{ + color: "black" + width: 3 * ApplicationInfo.ratio + } + GCText { + id: numText + anchors.centerIn: parent + text: boxValue + font.pointSize: 20 * ApplicationInfo.ratio + } + MouseArea { + id: mouseArea + anchors.fill: parent + drag.target: parent + enabled: (flow.onGoingAnimationCount == 0 && flow.validMousePress == true) ? true : false + onPressed: { + box.beginDragPosition = Qt.point(box.x, box.y) + } + onReleased: { + Activity.placeBlock(box, box.beginDragPosition); + } + } + Behavior on x { + PropertyAnimation { + id: animationX + duration: 500 + easing.type: Easing.InOutBack + onRunningChanged: { + if(animationX.running) { + flow.onGoingAnimationCount++ + } else { + flow.onGoingAnimationCount-- + } + } + } + } + Behavior on y { + PropertyAnimation { + id: animationY + duration: 500 + easing.type: Easing.InOutBack + onRunningChanged: { + if(animationY.running) { + flow.onGoingAnimationCount++ + } else { + flow.onGoingAnimationCount-- + } + } + } + } + } + } + } + } + + DialogHelp { + id: dialogHelp + onClose: home() + } + + BarButton { + id: ok + source: "qrc:/gcompris/src/core/resource/bar_ok.svg"; + sourceSize.width: 75 * ApplicationInfo.ratio + visible: true + anchors { + right: parent.right + bottom: bar.top + bottomMargin: 10 * ApplicationInfo.ratio + rightMargin: 10 * ApplicationInfo.ratio + } + onClicked: Activity.checkOrder() + } + + Score { + id: score + anchors { + right: parent.right + top: instruction.bottom + bottom: undefined + } + } + + Bar { + id: bar + content: BarEnumContent { value: help | home | level | hint } + onHelpClicked: { + displayDialog(dialogHelp) + } + onPreviousLevelClicked: Activity.previousLevel() + onNextLevelClicked: Activity.nextLevel() + onHomeClicked: activity.home() + onHintClicked: hints.visible = !hints.visible + } + + Bonus { + id: bonus + Component.onCompleted: win.connect(Activity.nextSubLevel) + } + } + +} diff --git a/src/activities/ascending_order/CMakeLists.txt b/src/activities/ascending_order/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/src/activities/ascending_order/CMakeLists.txt @@ -0,0 +1 @@ +GCOMPRIS_ADD_RCC(activities/ascending_order *.qml *.svg *.js resource/*) diff --git a/src/activities/ascending_order/README b/src/activities/ascending_order/README new file mode 100644 --- /dev/null +++ b/src/activities/ascending_order/README @@ -0,0 +1,6 @@ +Background: + +Landscape Egypt: https://openclipart.org/detail/175287/landscape-egypt by gnokii (openclipart) + +Colorful Numbers: https://openclipart.org/detail/221916/colorful-numbers by GDJ +(openclipart) diff --git a/src/activities/ascending_order/ascending_order.js b/src/activities/ascending_order/ascending_order.js new file mode 100644 --- /dev/null +++ b/src/activities/ascending_order/ascending_order.js @@ -0,0 +1,288 @@ +/* GCompris - ascending_order.js + * + * Copyright (C) 2016 Rudra Nil Basu + * + * Authors: + * Rudra Nil Basu (Qt Quick port) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +.pragma library +.import QtQuick 2.0 as Quick + +var currentLevel = 0 +var numberOfLevel = 4 + +var items +var mode + +// num[] will contain the random numbers +var num = [] +var originalArrangement = [] +var alphabets = [] + +var ascendingOrder +var thresholdDistance +var noOfTilesInPreviousLevel + +function start(items_, mode_) { + items = items_ + mode = mode_ + currentLevel = 0 + items.flow.validMousePress = false + thresholdDistance = 4000 * items.ratio + items.score.currentSubLevel = 0 + items.score.numberOfSubLevels = 4 + + if (mode == "alphabets") { + //: list containing all the characters separated by a "/" + var letters = qsTr("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z") + items.hints.text = letters + alphabets = letters.split("/") + } + + noOfTilesInPreviousLevel = -1 + initLevel() +} + +function stop() { +} + +function initLevel() { + ascendingOrder = items.score.currentSubLevel % 2 == 0 ? true : false + items.instruction.text = ascendingOrder ? qsTr("Drag and drop the items in correct position in Ascending order") : qsTr("Drag and drop the items in correct position in Descending order") + items.flow.validMousePress = true + items.bar.level = currentLevel + 1 + initGrids() +} + +function initGrids() { + items.boxes.model = 2 * (items.bar.level)+1 + + if(noOfTilesInPreviousLevel != items.boxes.model) { + /* + * When the tiles don't automatically rearrange themself + * manually check the marker off + */ + items.flow.onGoingAnimationCount = 0 + noOfTilesInPreviousLevel = items.boxes.model + } else { + restoreGrids() + } + + generateRandomNumbers() + + for(var i = 0;i < items.boxes.model;i++) { + if (mode == "number") { + items.boxes.itemAt(i).boxValue = num[i].toString() + } else if (mode == "alphabets") { + items.boxes.itemAt(i).boxValue = num[i] + } + } +} + +function generateRandomNumbers() { + var n = items.boxes.model + // generate n random numbers and store it in num[] + num = [] + var upperBound + var lowerBound + if(mode == "number") { + upperBound = (items.bar.level)*100 + lowerBound = 0 + } else if(mode == "alphabets") { + upperBound = alphabets.length -1 + lowerBound = 0 + } + while(num.length < n) { + var randomNumber = Math.ceil(Math.random() * (upperBound - lowerBound) + lowerBound) + if (( mode == "number" && num.indexOf(randomNumber) > -1) || ( mode == "alphabets" && num.indexOf(alphabets[randomNumber]) > -1)) { + continue; + } + if (mode == "number") { + num[num.length] = randomNumber + } else if (mode == "alphabets") { + num[num.length] = alphabets[randomNumber] + } + } + for(var i = 0;i < num.length;i++) { + originalArrangement[i] = num[i] + } +} + +function restoreGrids() { + /* Restore the grid positions */ + /* + * To make sure that the flow is properly indexed + * before moving on to the next sub level. + * This is required since if the previous level and + * current level has the same number of tiles, the + * indices are not automatically rearranged + */ + for(var i = 0;i < items.boxes.model;i++) { + if(num[i] === originalArrangement[i]) { + continue + } + var currentBlock = findBlockWithLabel(originalArrangement[i]) + var finalPosition = findBlockWithLabel(num[i]) + currentBlock.x = finalPosition.x + currentBlock.y = finalPosition.y + } +} + +function nextSubLevel() { + if(items.score.numberOfSubLevels <= ++items.score.currentSubLevel) { + if(numberOfLevel <= ++currentLevel) { + currentLevel = 0 + } + items.score.currentSubLevel = 0 + } + initLevel(); +} + +function nextLevel() { + if(numberOfLevel <= ++currentLevel) { + currentLevel = 0 + } + items.score.currentSubLevel = 0 + initLevel() +} + +function previousLevel() { + if(--currentLevel < 0) { + currentLevel = numberOfLevel - 1 + } + items.score.currentSubLevel = 0 + initLevel() +} + +function checkOrder() { + items.flow.validMousePress = false + for(var i = 0;i < items.boxes.count-1;i++) { + if( ascendingOrder && ( ( mode == "number" && num[i] > num[i+1]) || (mode == "alphabets" && alphabets.indexOf(num[i]) > alphabets.indexOf(num[i+1]))) ) { + items.bonus.bad("lion") + items.flow.validMousePress = true + return + } + if( !ascendingOrder && ( (mode == "number" && num[i] < num[i+1]) || (mode == "alphabets" && alphabets.indexOf(num[i]) < alphabets.indexOf(num[i+1]))) ) { + items.bonus.bad("lion") + items.flow.validMousePress = true + return + } + } + items.bonus.good("lion") +} + +function placeBlock(box, initialPosition) { + /* + * find shortest distance from box to other nodes + * if distance <= threshold distance then put box + * in that block and that block in "initialPosition" + */ + var minDistance = Number.POSITIVE_INFINITY + var closestBlock + for(var i = 0;i < items.boxes.model;i++) { + var currentBlock = items.boxes.itemAt(i) + if(currentBlock.boxValue === box.boxValue) { + continue + } else { + var blockDistance = distance(box, currentBlock) + if( blockDistance < minDistance ) { + minDistance = blockDistance + closestBlock = currentBlock + } + } + } + + if(minDistance < thresholdDistance) { + + var item1Pos = -1 + var item2Pos = num.indexOf(closestBlock.boxValue) + for (var i = 0;i < num.length; i++) { + /* + * var item1Pos = num.indexOf(box.boxValue) + * var item2Pos = num.indexOf(closestBlock.boxValue) + * was NOT used since the boxValue is of string type + * and it will return -1 when strictly compared with + * int + */ + if (box.boxValue == num[i]) { + item1Pos = i + } + if (closestBlock.boxValue == num[i]) { + item2Pos = i + } + } + + var oldPositions = [] + var newPositions = [] + + for(var i = 0;i < num.length;i++) { + oldPositions[i] = num[i] + newPositions[i] = num[i] + } + + if(item1Pos > item2Pos) { + // update new position + var currentBoxValue = newPositions[item1Pos] + for(var i = item1Pos;i > item2Pos;i--) { + newPositions[i] = newPositions[i-1] + } + newPositions[item2Pos] = currentBoxValue + } else { + // update new position + var currentBoxValue = newPositions[item1Pos] + for(var i = item1Pos;i < item2Pos;i++) { + newPositions[i] = newPositions[i+1]; + } + newPositions[item2Pos] = currentBoxValue + } + rearrange(oldPositions, newPositions, box, initialPosition) + for(var i = 0;i < num.length;i++) { + num[i] = newPositions[i] + } + } else { + box.x = initialPosition.x + box.y = initialPosition.y + } +} + +function rearrange(oldPositions, newPositions, movingBlock, initialPosition) { + for(var i = 0;i < newPositions.length;i++) { + if(oldPositions[i] === newPositions[i]) { + continue + } + var currentBlock = findBlockWithLabel(newPositions[i]) + var finalPosition = findBlockWithLabel(oldPositions[i]) + if(finalPosition.boxValue == movingBlock.boxValue) { + currentBlock.x = initialPosition.x + currentBlock.y = initialPosition.y + } else { + currentBlock.x = finalPosition.x + currentBlock.y = finalPosition.y + } + } +} + +function findBlockWithLabel(label) { + for(var i = 0;i < items.boxes.model;i++) { + if(items.boxes.itemAt(i).boxValue == label) { + return items.boxes.itemAt(i) + } + } +} + +function distance(box, currentBlock) { + return Math.pow((box.x-currentBlock.x),2) + Math.pow((box.y-currentBlock.y),2) +} diff --git a/src/activities/ascending_order/ascending_order.svg b/src/activities/ascending_order/ascending_order.svg new file mode 100644 --- /dev/null +++ b/src/activities/ascending_order/ascending_order.svg @@ -0,0 +1,1857 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/activities/ascending_order/resource/background.svg b/src/activities/ascending_order/resource/background.svg new file mode 100644 --- /dev/null +++ b/src/activities/ascending_order/resource/background.svg @@ -0,0 +1,1269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Openclipart + + + Landscape Egypt + 2013-02-23T08:35:01 + + https://openclipart.org/detail/175287/landscape-egypt-by-gnokii-175287 + + + gnokii + + + + + cheops + desert + egypt + gizeh + landmark + landscape + pharao + pyramids + + + + + + + + + + +