Commit 6c5ac051 authored by Bruno Coudoin's avatar Bruno Coudoin
Browse files

roman_numerals: new activity to learn roman numerals

Everything should be workinng fine but the level tuning, question and instructions
should be reviewed.
parent 9d088444
......@@ -108,6 +108,7 @@ redraw
redraw_symmetrical
renewable_energy
reversecount
roman_numerals
scalesboard
scalesboard_weight
scalesboard_weight_avoirdupois
......
/* GCompris - ActivityInfo.qml
*
* Copyright (C) 2016 Your Name <yy@zz.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
import GCompris 1.0
ActivityInfo {
name: "roman_numerals/RomanNumerals.qml"
difficulty: 4
icon: "roman_numerals/roman_numerals.svg"
author: "Bruno Coudoin &lt;bruno.coudoin@gcompris.net&gt;"
demo: true
title: "Roman numerals"
description: ""
//intro: "Learn and practice roman to arabic numerals conversion"
goal: ""
prerequisite: ""
manual: "A Roman numeral is the name for a number when it is written in the way the Romans used to write numbers. Roman numerals are not used very often today in the west. They are used to write the names of kings and queens, or popes. For example: Queen Elizabeth II. They may be used to write the year a book or movie was made."
credit: ""
section: "math"
createdInVersion: 7000
}
GCOMPRIS_ADD_RCC(activities/roman_numerals *.qml *.svg *.js resource/*)
/* GCompris - roman_numerals.qml
*
* Copyright (C) 2016 Bruno Coudoin <bruno.coudoin@gcompris.net>
*
* Authors:
* Bruno Coudoin <bruno.coudoin@gcompris.net>
*
* 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 <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.1
import GCompris 1.0
import "../../core"
ActivityBase {
id: activity
onStart: focus = true
onStop: {}
pageComponent: Image {
id: background
source: items.toArabic ?
"qrc:/gcompris/src/activities/roman_numerals/resource/arcs.svg" :
"qrc:/gcompris/src/activities/roman_numerals/resource/torrazzo-crema.svg"
fillMode: Image.PreserveAspectCrop
sourceSize.width: Math.max(parent.width, parent.height)
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 score: score
property alias textInput: textInput
property bool toArabic: dataset[currentLevel].toArabic
property string questionText: dataset[currentLevel].question
property string instruction: dataset[currentLevel].instruction
property string questionValue
property int currentLevel: 0
property int numberOfLevel: dataset.length
property var dataset: [
{
values: ['I', 'V', 'X', 'L', 'C', 'D', 'M'],
instruction: qsTr("Roman numerals, are based on seven symbols: I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000."),
question: qsTr("Convert the roman number %1 in arabic."),
toArabic: true
},
{
values: [1, 5, 10, 50, 100, 500, 1000],
instruction: qsTr("Roman numerals, are based on seven symbols: I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000."),
question: qsTr("Convert the arabic number %1 in roman."),
toArabic: false
},
{
values: ['II', 'III', 'VI', 'XX', 'XXII', 'XXX', 'LX', 'CC', 'CCL', 'MM', 'CLX', 'DCCLI', 'CCCLXVI'],
instruction: qsTr("Several symbols create a larger number like II = 2, XX = 20, XI = 11."),
question: qsTr("Convert the roman number %1 in arabic."),
toArabic: true
},
{
values: [2, 3, 6, 20, 22, 30, 60, 200, 250, 2000, 160, 651, 361],
instruction: qsTr("Several symbols create a larger number like II = 2, XX = 20, XI = 11."),
question: qsTr("Convert the arabic number %1 in roman."),
toArabic: false
},
{
values: ['IV', 'IX', 'XL', 'XC', 'CD', 'CM'],
instruction: qsTr("If a lower value symbol is before a higher value one, it is subtracted. Otherwise it is added. So 'IV' is '4', 'VI' is '6', 'IX' is 9."),
question: qsTr("Convert the roman number %1 in arabic."),
toArabic: true
},
{
values: [4, 9, 40, 90, 400, 900],
instruction: qsTr("If a lower value symbol is before a higher value one, it is subtracted. Otherwise it is added. So 'IV' is '4', 'VI' is '6', 'IX' is 9."),
question: qsTr("Convert the arabic number %1 in roman."),
toArabic: false
},
{
values: ['VIII', 'LXXX', 'CCCCLXXX', 'DCCC', 'MCCC'],
instruction: qsTr("Only one number is subtracted, not two. So 8 is always VIII and never IIX."),
question: qsTr("Convert the roman number %1 in arabic."),
toArabic: true
},
{
values: [8, 70, 480, 800, 1300],
instruction: qsTr("Only one number is subtracted, not two. So 8 is always VIII and never IIX."),
question: qsTr("Convert the arabic number %1 in roman."),
toArabic: false
},
{
values: ['XLIX', 'CMXC', 'XCV', 'XLVIII', 'CMXCIX', 'XLVI', 'CXCII', 'CDLXXV'],
instruction: qsTr("Proper form is to subtract only a value with the next lower power of 10. Thus, 900 is written CM, but 990 would not be XM - properly, it is CM for the 900 portion and XC for the 90 portion, or CMXC. Similarly, 999 would not be IM but rather CMXCIX - CM for the 900 portion, XC for the 90 portion, and IX for the 9 portion. Only values starting in 1's are ever used to subtract; 45 is properly XLV, not VL."),
question: qsTr("Convert the roman number %1 in arabic."),
toArabic: true
},
{
values: [48, 991, 96, 49, 998, 47, 193, 472, 1092],
instruction: qsTr("Proper form is to subtract only a value with the next lower power of 10. Thus, 900 is written CM, but 990 would not be XM - properly, it is CM for the 900 portion and XC for the 90 portion, or CMXC. Similarly, 999 would not be IM but rather CMXCIX - CM for the 900 portion, XC for the 90 portion, and IX for the 9 portion. Only values starting in 1's are ever used to subtract; 45 is properly XLV, not VL."),
question: qsTr("Convert the arabic number %1 in roman."),
toArabic: false
},
{
values: ['_random_', 50 /* up to this number */ , 10 /* sublevels */],
instruction: qsTr("Now you know the rules, You can read and write any numbers in roman numerals."),
question: qsTr("Convert the arabic number %1 in roman."),
toArabic: false
},
{
values: ['_random_', 100, 10],
instruction: '',
question: qsTr("Convert the arabic number %1 in roman."),
toArabic: false
},
{
values: ['_random_', 500, 10],
instruction: '',
question: qsTr("Convert the arabic number %1 in roman."),
toArabic: false
},
{
values: ['_random_', 1000, 10],
instruction: '',
question: qsTr("Convert the arabic number %1 in roman."),
toArabic: false
}
]
onQuestionValueChanged: {
textInput.text = ''
romanConverter.arabic = 0
if(toArabic)
keyboard.populateArabic()
else
keyboard.populateRoman()
}
function start() {
if (!ApplicationInfo.isMobile)
textInput.forceActiveFocus();
items.currentLevel = 0
initLevel()
}
function initLevel() {
score.currentSubLevel = 1
initSubLevel()
}
function initSubLevel() {
if(dataset[currentLevel].values[0] == '_random_') {
questionValue = Math.round(Math.random() * dataset[currentLevel].values[1] + 1)
score.numberOfSubLevels = dataset[currentLevel].values[2]
} else {
questionValue = dataset[currentLevel].values[score.currentSubLevel - 1]
score.numberOfSubLevels = dataset[currentLevel].values.length
}
}
function nextLevel() {
if(numberOfLevel - 1 == currentLevel ) {
currentLevel = 0
} else {
currentLevel++
}
initLevel();
}
function previousLevel() {
if(currentLevel == 0) {
currentLevel = numberOfLevel - 1
} else {
currentLevel--
}
initLevel();
}
function nextSubLevel() {
if(++score.currentSubLevel > score.numberOfSubLevels) {
nextLevel()
} else {
initSubLevel();
}
}
}
onStart: {
items.start()
}
onStop: { }
QtObject {
id: romanConverter
property int arabic
property string roman
// conversion code copied from:
// http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter
function arabic2Roman(num) {
if (!+num)
return '';
var digits = String(+num).split(""),
key = ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM",
"","X","XX","XXX","XL","L","LX","LXX","LXXX","XC",
"","I","II","III","IV","V","VI","VII","VIII","IX"],
roman = "",
i = 3;
while (i--)
roman = (key[+digits.pop() + (i * 10)] || "") + roman;
return new Array(+digits.join("") + 1).join("M") + roman;
}
function roman2Arabic(str) {
var str = str.toUpperCase(),
validator = /^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/,
token = /[MDLV]|C[MD]?|X[CL]?|I[XV]?/g,
key = {M:1000,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1},
num = 0, m;
if (!(str && validator.test(str)))
return false;
while (m = token.exec(str))
num += key[m[0]];
return num;
}
onArabicChanged: roman = arabic2Roman(arabic)
onRomanChanged: arabic = roman2Arabic(roman)
}
Column {
id: column
anchors.fill: parent
GCText {
id: questionLabel
anchors.horizontalCenter: parent.horizontalCenter
text: items.questionValue ? items.questionText.arg(items.questionValue) : ''
color: 'white'
Rectangle {
z: -1
color: '#AA333333'
border.color: 'black'
border.width: 1
anchors.centerIn: parent
width: parent.width * 1.1
height: parent.height
}
}
Item { // Just a margin
width: 1
height: 5 * ApplicationInfo.ratio
}
TextInput {
id: textInput
x: parent.width / 2
width: 60 * ApplicationInfo.ratio
color: 'white'
text: ''
maximumLength: items.toArabic ?
('' + romanConverter.roman2Arabic(items.questionValue)).length + 1 :
romanConverter.arabic2Roman(items.questionValue).length + 1
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.pointSize: questionLabel.pointSize
font.weight: Font.DemiBold
font.family: GCSingletonFontLoader.fontLoader.name
font.capitalization: ApplicationSettings.fontCapitalization
font.letterSpacing: ApplicationSettings.fontLetterSpacing
cursorVisible: true
validator: RegExpValidator{regExp: items.toArabic ?
/[0-9]+/ :
/[ivxlcdmIVXLCDM]*/}
onTextChanged: if(text) {
text = text.toUpperCase();
if(items.toArabic)
romanConverter.arabic = parseInt(text)
else
romanConverter.roman = text
}
Rectangle {
z: -1
color: '#AA333333'
border.color: 'black'
border.width: 1
anchors.centerIn: parent
width: column.width * 0.7
height: parent.height
}
function appendText(car) {
if(car === keyboard.backspace) {
if(text && cursorPosition > 0) {
var oldPos = cursorPosition
text = text.substring(0, cursorPosition - 1) + text.substring(cursorPosition)
cursorPosition = oldPos - 1
}
return
}
var oldPos = cursorPosition
text = text.substring(0, cursorPosition) + car + text.substring(cursorPosition)
cursorPosition = oldPos + 1
}
}
Item { // Just a margin
width: 1
height: 5 * ApplicationInfo.ratio
}
GCText {
id: feedback
anchors.horizontalCenter: parent.horizontalCenter
text: items.toArabic ?
qsTr("Roman value: %1").arg(value) :
qsTr('Arabic value: %1'.arg(value))
onTextChanged: timer.start()
color: 'white'
Rectangle {
z: -1
color: '#AA333333'
border.color: 'black'
border.width: 1
anchors.centerIn: parent
width: parent.width * 1.1
height: parent.height
}
property string value: items.toArabic ?
romanConverter.roman :
romanConverter.arabic ? romanConverter.arabic : ''
}
// We want the entry to be checked after a little timer to make sure we don't trig a
// transient children answer
Timer {
id: timer
interval: 500
onTriggered: {
if( feedback.value == items.questionValue )
bonus.good('tux')
}
}
Item { // Just a margin
width: 1
height: 20 * ApplicationInfo.ratio
}
GCText {
id: instruction
visible: items.instruction != ''
wrapMode: TextEdit.WordWrap
fontSize: tinySize
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width * 0.9
text: items.instruction
color: 'white'
Rectangle {
z: -1
color: '#AA333333'
border.color: 'black'
border.width: 1
anchors.centerIn: parent
width: parent.width * 1.1
height: parent.contentHeight
}
}
}
Score {
id: score
anchors.bottom: keyboard.top
currentSubLevel: 0
numberOfSubLevels: 1
}
DialogHelp {
id: dialogHelp
onClose: home()
}
VirtualKeyboard {
id: keyboard
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
function populateArabic() {
layout = [ [
{ label: "0" },
{ label: "1" },
{ label: "2" },
{ label: "3" },
{ label: "4" },
{ label: "5" },
{ label: "6" },
{ label: "7" },
{ label: "8" },
{ label: "9" },
{ label: keyboard.backspace }
] ]
}
function populateRoman() {
layout = [ [
{ label: "I" },
{ label: "V" },
{ label: "X" },
{ label: "L" },
{ label: "C" },
{ label: "D" },
{ label: "M" },
{ label: keyboard.backspace }
] ]
}
onKeypress: textInput.appendText(text)
onError: console.log("VirtualKeyboard error: " + msg);
}
Bar {
id: bar
anchors.bottom: keyboard.top
content: BarEnumContent { value: help | home | level }
onHelpClicked: {
displayDialog(dialogHelp)
}
onPreviousLevelClicked: items.previousLevel()
onNextLevelClicked: items.nextLevel()
onHomeClicked: activity.home()
level: items.currentLevel + 1
}
Bonus {
id: bonus
Component.onCompleted: win.connect(items.nextSubLevel)
}
}
}
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
License: public-domain
Files: terrazzo-crema.svg
Source: https://openclipart.org/download/139573/torrazzo-crema.svg
License: public-domain
Files: arcs.svg
Source: https://openclipart.org/download/171578/arcs.svg
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment