File indexing completed on 2024-04-28 15:07:57

0001 /* GCompris - missing-letter.js
0002  *
0003  * Copyright (C) 2014 "Amit Tomar" <a.tomar@outlook.com>
0004  *
0005  * Authors:
0006  *   "Pascal Georges" <pascal.georgis1.free.fr> (GTK+ version)
0007  *   "Amit Tomar" <a.tomar@outlook.com> (Qt Quick port)
0008  *
0009  *   SPDX-License-Identifier: GPL-3.0-or-later
0010  */
0011 .pragma library
0012 .import QtQuick 2.12 as Quick
0013 .import "qrc:/gcompris/src/core/core.js" as Core
0014 .import GCompris 1.0 as GCompris //for ApplicationInfo
0015 .import "qrc:/gcompris/src/activities/lang/lang_api.js" as Lang
0016 
0017 var url = "qrc:/gcompris/src/activities/missing-letter/resource/"
0018 var langUrl = "qrc:/gcompris/src/activities/lang/resource/";
0019 
0020 var items
0021 var numberOfLevel
0022 
0023 var questions
0024 var dataset
0025 var lessons
0026 var currentQuestion
0027 
0028 // Do not propose these letter in the choices
0029 var ignoreLetters = '[ ,;:\\-\u0027]'
0030 var re = new RegExp(ignoreLetters, 'g')
0031 
0032 function init(items_) {
0033     items = items_
0034 }
0035 
0036 function start() {
0037     var locale = GCompris.ApplicationInfo.getVoicesLocale(items.locale)
0038 
0039     // register the voices for the locale
0040     GCompris.DownloadManager.updateResource(GCompris.GCompris.VOICES, {"locale": locale})
0041 
0042     dataset = Lang.load(items.parser, langUrl,
0043                         GCompris.ApplicationSettings.useExternalWordset() ? "words.json" : "words_sample.json",
0044                         "content-"+ locale +".json")
0045 
0046     // If dataset is empty, we try to load from short locale
0047     // and if not present again, we switch to default one
0048     var localeUnderscoreIndex = locale.indexOf('_')
0049     if(!dataset) {
0050         var localeShort;
0051         // We will first look again for locale xx (without _XX if exist)
0052         if(localeUnderscoreIndex > 0) {
0053             localeShort = locale.substring(0, localeUnderscoreIndex)
0054         } else {
0055             localeShort = locale;
0056         }
0057         dataset = Lang.load(items.parser, langUrl,
0058                             GCompris.ApplicationSettings.useExternalWordset() ? "words.json" : "words_sample.json",
0059                             "content-"+localeShort+ ".json")
0060     }
0061 
0062     // If still dataset is empty then fallback to english
0063     if(!dataset) {
0064         // English fallback
0065         items.background.englishFallback = true
0066         dataset = Lang.load(items.parser, langUrl,
0067                             GCompris.ApplicationSettings.useExternalWordset() ? "words.json" : "words_sample.json",
0068                             "content-en.json")
0069     } else {
0070         items.background.englishFallback = false
0071     }
0072 
0073     lessons = Lang.getAllLessons(dataset)
0074     questions = initDataset()
0075     numberOfLevel = questions.length
0076     items.currentLevel = Core.getInitialLevel(numberOfLevel)
0077     initLevel()
0078 }
0079 
0080 function initDataset() {
0081     var questions = []
0082     for (var lessonIndex = 0; lessonIndex < lessons.length; lessonIndex++) {
0083         var lesson = Lang.getLessonWords(dataset, lessons[lessonIndex])
0084         var guessLetters = getRandomLetters(lesson)
0085         questions[lessonIndex] = []
0086         for (var j in lesson) {
0087             var clearQuestion = lesson[j].translatedTxt
0088             if(GCompris.ApplicationSettings.fontCapitalization === Quick.Font.AllUppercase)
0089                 clearQuestion = clearQuestion.toLocaleUpperCase()
0090             else if(GCompris.ApplicationSettings.fontCapitalization === Quick.Font.AllLowercase)
0091                 clearQuestion = clearQuestion.toLocaleLowerCase()
0092 
0093             var maskedQuestion = getRandomMaskedQuestion(clearQuestion, guessLetters, lessonIndex)
0094 
0095             questions[lessonIndex].push(
0096                         {
0097                             'image': lesson[j].image,
0098                             'clearQuestion': clearQuestion,
0099                             'maskedQuestion': maskedQuestion[0],
0100                             'answer': maskedQuestion[1],
0101                             'choices': maskedQuestion[2],
0102                             'voice': lesson[j].voice,
0103                         })
0104         }
0105     }
0106     return questions
0107 }
0108 
0109 // Get all the letters for all the words in the lesson excluding ignoreLetters
0110 function getRandomLetters(lesson) {
0111     var letters = []
0112     for (var i in lesson) {
0113         var word = lesson[i].translatedTxt.replace(re, '')
0114         var lettersInCurrentWord;
0115         if(GCompris.ApplicationSettings.fontCapitalization === Quick.Font.AllUppercase)
0116             lettersInCurrentWord = word.toLocaleUpperCase().split('')
0117         else if(GCompris.ApplicationSettings.fontCapitalization === Quick.Font.AllLowercase)
0118             lettersInCurrentWord = word.toLocaleLowerCase().split('')
0119         else
0120             lettersInCurrentWord = word.split('')
0121 
0122         for(var l in lettersInCurrentWord) {
0123             if(letters.indexOf(lettersInCurrentWord[l]) === -1) {
0124                 letters.push(lettersInCurrentWord[l]);
0125             }
0126         }
0127     }
0128     return Core.shuffle(GCompris.ApplicationInfo.localeSort(letters, items.locale))
0129 }
0130 
0131 // Get a random letter in the given word excluding ignoreLetters
0132 function getRandomLetter(word) {
0133     var letters = word.replace(re, '').split('')
0134     var letter = letters[Math.floor(Math.random() * letters.length)]
0135     if(GCompris.ApplicationSettings.fontCapitalization === Quick.Font.AllUppercase)
0136         return letter.toLocaleUpperCase()
0137     else if(GCompris.ApplicationSettings.fontCapitalization === Quick.Font.AllLowercase)
0138         return letter.toLocaleLowerCase()
0139 
0140     return letter
0141 }
0142 
0143 function getRandomMaskedQuestion(clearQuestion, guessLetters, level) {
0144     var maskedQuestion = clearQuestion
0145     var goodLetter = getRandomLetter(maskedQuestion)
0146 
0147     // If the word has several occurrences of the letter, choose one at random
0148     var goodLetterPositions = [];
0149     for(var i = 0; i < maskedQuestion.length; i++) {
0150         if (maskedQuestion[i] === goodLetter) {
0151             goodLetterPositions.push(i);
0152         }
0153     }
0154     var index = goodLetterPositions[Math.floor(Math.random() * goodLetterPositions.length)];
0155 
0156     // Replace the char at index with '_'
0157     var repl = maskedQuestion.split('')
0158     repl[index] = '_'
0159     maskedQuestion = repl.join('')
0160 
0161     // Get some other letter to confuse the children
0162     var confusingLetters = []
0163     for(var i = 0; i < Math.min(level + 2, 6); i++) {
0164         var letter = guessLetters.shift()
0165         if(confusingLetters.indexOf(letter) === -1 && letter !== goodLetter) {
0166             confusingLetters.push(letter);
0167         }
0168         guessLetters.push(letter)
0169     }
0170     confusingLetters.push(goodLetter)
0171 
0172     return [maskedQuestion, goodLetter, Core.shuffle(confusingLetters)]
0173 }
0174 
0175 function stop() {
0176     items.questionAnim.stop();
0177     items.audioVoices.clearQueue();
0178 }
0179 
0180 function initLevel() {
0181     items.questionAnim.stop()
0182     items.score.currentSubLevel = 0
0183     items.score.numberOfSubLevels = questions[items.currentLevel].length
0184     showQuestion()
0185 }
0186 
0187 function getCurrentQuestion() {
0188     return questions[items.currentLevel][items.score.currentSubLevel]
0189 }
0190 
0191 function showQuestion() {
0192     currentQuestion = getCurrentQuestion()
0193 
0194     playWord(currentQuestion.voice)
0195     items.answer = currentQuestion.answer
0196     items.answers.model = currentQuestion.choices
0197     items.questionText.text = currentQuestion.maskedQuestion
0198     items.questionImage.source = currentQuestion.image
0199     items.isGoodAnswer = false
0200     items.buttonsBlocked = false
0201 }
0202 
0203 function nextLevel() {
0204     items.score.stopWinAnimation()
0205     items.currentLevel = Core.getNextLevel(items.currentLevel, numberOfLevel);
0206     initLevel();
0207 }
0208 
0209 function nextSubLevel() {
0210     if(items.score.currentSubLevel >= items.score.numberOfSubLevels) {
0211         items.bonus.good('flower')
0212         return
0213     }
0214     showQuestion()
0215 }
0216 
0217 function previousLevel() {
0218     items.score.stopWinAnimation();
0219     items.currentLevel = Core.getPreviousLevel(items.currentLevel, numberOfLevel);
0220     initLevel();
0221 }
0222 
0223 function showAnswer() {
0224     playLetter(currentQuestion.answer)
0225     items.isGoodAnswer = true
0226     items.questionText.text = currentQuestion.clearQuestion
0227 }
0228 
0229 function playLetter(letter) {
0230     var locale = GCompris.ApplicationInfo.getVoicesLocale(items.locale)
0231     items.audioVoices.stop()
0232     items.audioVoices.clearQueue()
0233     items.audioVoices.append(GCompris.ApplicationInfo.getAudioFilePath("voices-$CA/"+locale+"/alphabet/" +
0234                              Core.getSoundFilenamForChar(letter)))
0235 }
0236 
0237 function playCurrentWord() {
0238     var question = getCurrentQuestion()
0239     playWord(question.voice)
0240 }
0241 
0242 function playWord(word) {
0243     var locale = GCompris.ApplicationInfo.getVoicesLocale(items.locale)
0244     var wordLocalized = word.replace("$LOCALE", locale)
0245     items.audioVoices.append(GCompris.ApplicationInfo.getAudioFilePath(wordLocalized))
0246 }
0247 
0248 function focusTextInput() {
0249     if (!GCompris.ApplicationInfo.isMobile && items && items.textinput)
0250         items.textinput.forceActiveFocus();
0251 }