diff --git a/2019-setembro/foxalex/README.md b/2019-setembro/foxalex/README.md new file mode 100644 index 0000000..355763f --- /dev/null +++ b/2019-setembro/foxalex/README.md @@ -0,0 +1,9 @@ +# Pense Bem Challenge + +Esse é o código para entrada no desafio promovido pela CollabCodeTech. + +##### Nota + +Enquanto desenvolvia a parte de Javascript para as funcionalidades da aplicação fui procurar por alguma referência sobre os sons originais do aparelho, acabei visualizando o excelente projeto do [Leandro Pereira](https://github.com/lpereira/Pense-Bem) e **Felipe Sanches**, a anos atrás eles já haviam feito todo um trabalho de engenharia reversa do brinquedo, aconselho bastante a dar uma olhada em todo material deles. + +Depois de ler e estudar todo conteúdo deles resolvi utilizar o código deles ao invés de rescrever tudo do zero novamente, modificando e adaptando o código a necessidade da minha aplicação. diff --git a/2019-setembro/foxalex/css/app.css b/2019-setembro/foxalex/css/app.css new file mode 100644 index 0000000..15d1128 --- /dev/null +++ b/2019-setembro/foxalex/css/app.css @@ -0,0 +1,556 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + outline: 0; +} + +body { + font-family: 'Roboto', sans-serif; + background: repeating-linear-gradient( + 90deg, + #f0f0f0 0, + #f0f0f0 5%, + transparent 0, + transparent 50% + ) + 0 / 15px 15px, + repeating-linear-gradient( + 180deg, + #f0f0f0 0, + #f0f0f0 5%, + transparent 0, + transparent 50% + ) + 0 / 15px 15px; +} +button { + font-family: 'Roboto', sans-serif; +} + +.image-ref img { + max-width: 800px; +} + +/** Main Wrap */ +.main-wrap { + max-width: 960px; + margin: 40px auto; + padding: 10px; +} +.main-wrap button { + border: 1px solid #3c302b; + cursor: pointer; + transition: border 0.1s ease-in-out; +} +.main-wrap button:hover { + border: 1px solid #905846; +} +.main-wrap button:active { + border: 2px solid #000; + border-right-width: 0px; + border-bottom-width: 0px; +} +/** End Main Wrap */ + +/** Top Structure */ +.top-structure { + background-color: #cdcac9; + padding: 2.2em; + margin: 10px; + margin-bottom: 0; + border-radius: 10px; + box-shadow: inset 0em 0em 1em -0.3em rgba(0, 0, 0, 0.5); +} +.top-structure .content { + display: flex; + padding: 3px; + border-radius: 5px; + box-shadow: 0em 0em 0.1em 0.1em rgba(0, 0, 0, 0.5), + 0.03em 0.01em 0em 0.2em rgba(255, 255, 255, 0.9), + inset 0em 0em 0.1em 0.03em rgba(255, 255, 255, 0.4), + inset 0.5em 0em 0.2em rgba(0, 0, 0, 0.4); +} +.top-structure .content .fake-disk { + width: 40%; + display: flex; + position: relative; + border-radius: 5px; + border-top-left-radius: 0px; + border-bottom-left-radius: 0px; + justify-content: center; + align-items: center; + box-shadow: inset 0.2em 0 0.2em -0.1em #fff; +} +.top-structure .content .fake-disk .cube, +.top-structure .content .fake-disk .disk { + position: absolute; +} +.top-structure .content .fake-disk .cube { + width: 30%; + height: 30%; + border-radius: 4px; + box-shadow: inset 0.3em 0em 0.4em -0.2em rgba(0, 0, 0, 0.5), + inset -0.2em 0em 0.2em -0.1em rgba(255, 255, 255, 0.9); +} +.top-structure .content .fake-disk .disk { + background-color: #cdcac9; + width: 80%; + height: 4%; + /* border: 1px dashed red; */ + border-radius: 5px; + border: 1px solid #aaa; + box-shadow: inset 0.3em 0em 0.4em -0.2em rgba(0, 0, 0, 0.8), + 0em -0.2em 0.1em 0.05em rgba(0, 0, 0, 0.07), + 0.4em 0em 0.2em -0.05em rgba(255, 255, 255, 1), 0em 0em 0.1em 0.3em #cdcac9; +} +/** End Top Structure */ + +/** Display */ +.screen-wrap { + background-color: #1b2327; + width: 100%; + padding: 1em 3em 0 3em; +} +.screen-wrap .display { + padding: 1em; + margin: 0 auto; +} +.st0 { + fill: #1b2327; +} +.st1 { + fill: #ed2224; +} +.st2 { + /* fill: #585c4c; */ + fill: #352523; +} +.screen-wrap .footer { + display: flex; + color: #fff; +} +.screen-wrap .footer > div { + width: 50%; +} +.screen-wrap .footer .colors { + text-align: left; +} +.screen-wrap .footer .colors span { + display: inline-block; + width: 18%; + height: 10px; + margin: 1%; +} +.screen-wrap .footer .colors span:nth-child(1) { + background-color: #b22514; +} +.screen-wrap .footer .colors span:nth-child(2) { + background-color: #c8a201; +} +.screen-wrap .footer .colors span:nth-child(3) { + background-color: #1451ae; +} +.screen-wrap .footer .colors span:nth-child(4) { + background-color: #0a9923; +} +/** End Display */ + +/** Join Element */ +.join-element { + width: 90%; + margin: 0 auto; + background-color: #cdcac9; + height: 2em; + box-shadow: inset 0.3em 0em 0.2em -0.2em rgba(255, 255, 255, 0.9), + inset 0em 0em 1em 0em rgba(0, 0, 0, 0.4), + inset 0em -0.5em 0.8em -0.5em rgba(0, 0, 0, 0.4); +} +/** End Join Element */ + +/** Bottom Structure */ +.bottom-structure { + margin: 10px; + margin-top: 0; + background-color: #cdcac9; + padding: 2.2em; + padding-top: 0.8em; + border-radius: 5px; + box-shadow: inset 0em 0em 2em -0.5em rgba(0, 0, 0, 0.5), + inset 0.5em 0 0.2em rgba(255, 255, 255, 0.9), + inset 0em 0.3em 0.4em -0.1em rgba(0, 0, 0, 0.3), + inset -0.3em 0em 0.2em -0em rgba(0, 0, 0, 0.2); +} +.bottom-structure .header { + display: flex; + justify-content: flex-end; +} +.bottom-structure .header h2 { + display: inline-block; + padding: 0em 0.9em; + background: #ceccc4; + font-size: 2em; + line-height: 0.9em; + letter-spacing: -0.05em; + margin-bottom: 0.5em; + color: #174588; + border: 1px solid #999; + box-shadow: inset 0.05em 0.01em 0.2em -0.1em rgba(0, 0, 0, 0.2), + 2px 1px 1px -1px rgba(0, 0, 0, 0.8), + -1px -1px 1px -1px rgba(255, 255, 255, 0.8), + 4px 1px 2px -1px rgba(255, 255, 255, 0.8); +} +.bottom-structure .header h2 span { + display: inline-block; + font-size: 0.4em; + vertical-align: super; +} +/** End Bottom Structure */ + +/** KeyBoard Wrap */ +.keyboard-wrap { + font-size: 1.2em; + position: relative; + padding: 20px; + padding-left: 0px; + background-color: #4b423f; + border: 1px solid #4b423f; + border-radius: 5px; + box-shadow: inset 0em 0em 1.2em -0.2em rgba(0, 0, 0, 0.7), + 0.7em 0em 0.15em -0.2em rgba(255, 255, 255, 1), + 0.1em -0.3em 0.5em -0.1em rgba(255, 255, 255, 1), + 0em 0em 0.25em 0.4em rgba(0, 0, 0, 0.3); +} +.keyboard-wrap .row { + display: flex; + align-items: center; + justify-content: center; +} +.keyboard-wrap .col { + display: flex; + flex-flow: column; + justify-content: space-evenly; +} +/** End Keyboard Wrap */ + +/** Main buttons */ +.main-buttons-wrap { + display: flex; + align-items: center; + justify-content: center; +} +.main-button-wrap { + display: inline-block; + transform: skew(-15deg); + /* border: 1px solid #806056; */ + border: 1px solid #4e3f3a; + padding: 3px; + border-radius: 6px; + margin: 0 5px; + box-shadow: inset -1px 1px 1px 0px rgba(0, 0, 0, 0.2), + 1px -1px 1px -1px rgba(255, 255, 255, 0.4); +} +.main-button-wrap button { + font-size: 1.05em; + padding: 2.5em 1.8em; + border-radius: 6px; + box-shadow: 1px -1px 1px -1px rgba(255, 255, 255, 0.5), + -2px -2px 2px -1px rgba(0, 0, 0, 0.4), + inset 2px 2px 1px -2px rgba(255, 255, 255, 0.4), + inset 2px 2px 2px -1px rgba(0, 0, 0, 0.6), + inset 2em 0px 2em rgba(0, 0, 0, 0.1); + background-color: transparent; +} +.main-button-wrap:nth-child(1) button { + background-color: #b22514; +} +.main-button-wrap:nth-child(2) button { + background-color: #c8a201; +} +.main-button-wrap:nth-child(3) button { + background-color: #1451ae; +} +.main-button-wrap:nth-child(4) button { + background-color: #0a9923; +} +.main-button-wrap button span { + display: block; + text-transform: uppercase; + color: #fff; + transform: skew(15deg); + font-weight: bold; +} +/** End Main Buttons */ + +/** Normal Buttons */ +.buttons-wrap { + display: flex; + justify-content: center; + margin: 0.4em; + flex-wrap: wrap; +} +.button-wrap { + width: 3.5em; + height: 3.5em; + border: 1px solid #4e3f3a; + padding: 3px; + margin: 0.1em; + border-radius: 4px; + box-shadow: inset -1px 1px 1px 0px rgba(0, 0, 0, 0.2), + inset 0.03em -0.01em 0 0 rgba(0, 0, 0, 0.6), + 1px -1px 1px -1px rgba(255, 255, 255, 0.4); +} +.button-wrap button { + width: 100%; + height: 100%; + border-radius: 4px; + text-transform: uppercase; + font-size: 0.7em; + font-weight: bold; + box-shadow: 1px -0.03em 1px -1px rgba(255, 255, 255, 0.7), + -2px -2px 2px -1px rgba(0, 0, 0, 0.4), + inset 2px 2px 1px -2px rgba(255, 255, 255, 0.2), + inset 2px 2px 2px -1px rgba(0, 0, 0, 0.6), + inset 1em 0em 0.8em rgba(0, 0, 0, 0.1); +} +/** End Normal Buttons */ + +/** System Buttons */ +.buttons-wrap.system { + transform: translateX(2em); + margin-bottom: 0; +} +.buttons-wrap.system button { + background-color: #fff; + color: #1451ae; +} +.buttons-wrap.system .button-wrap:nth-child(3) button { + background-color: #b22514; + color: #fff; + font-weight: 300; +} +.buttons-wrap.system .button-wrap:nth-child(4) button { + background-color: #0a9923; + color: #fff; +} +/** End System Buttons */ + +/** Math Buttons */ +.buttons-wrap.math { + margin-top: 0; +} +.buttons-wrap.math button { + color: rgba(255, 255, 255, 0.7); + background-color: #1451ae; + font-size: 1.9em; + font-weight: 300; + font-family: Arial, Helvetica, sans-serif; +} +/** End Math Buttons */ + +/** Numbers Buttons */ +.buttons-wrap.numbers { + transform: translateX(2em); +} +.buttons-wrap.numbers button { + background-color: #fff; + color: #1451ae; + display: flex; + align-items: center; + justify-content: space-around; + flex-flow: column; + position: relative; +} +.buttons-wrap.numbers button:before { + content: ' '; + display: block; + width: 100%; + height: 50%; + background-color: #b22514; + bottom: 0px; + left: 0px; + position: absolute; + box-shadow: inset 1em 0em 0.8em rgba(0, 0, 0, 0.1); +} +.buttons-wrap.numbers button span { + display: block; + position: relative; +} +.buttons-wrap.numbers button span:nth-child(1) { + font-size: 1.4em; + font-weight: 700; +} +.buttons-wrap.numbers button span:nth-child(2) { + color: #fff; + font-weight: 300; + font-size: 0.9em; + letter-spacing: 0.1em; +} +/** End Numbers Buttons */ + +/** Games Buttons */ +.buttons-wrap.games button { + background-color: #c8a201; + color: #1a6d29; + font-size: 0.45em; + line-height: 1.5em; +} +/** End Games Buttons */ + +/** Overlay */ +.overlay { + top: 0; + left: 0; + position: absolute; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; +} +.overlay.hidden { + display: none; +} +.overlay .modal { + background-color: #fff; + padding: 2em; + padding-top: 1.5em; + margin: 20px; + max-width: 500px; +} +.overlay .modal .colors { + margin-bottom: 10px; +} +.overlay .modal .colors span { + display: inline-block; + width: 20px; + height: 10px; +} +.overlay .modal .colors span:nth-child(1) { + background-color: #b22514; +} +.overlay .modal .colors span:nth-child(2) { + background-color: #c8a201; +} +.overlay .modal .colors span:nth-child(3) { + background-color: #1451ae; +} +.overlay .modal .colors span:nth-child(4) { + background-color: #0a9923; +} +.overlay .modal h2 { + border-bottom: 2px solid #333; + padding-bottom: 10px; +} +.overlay .modal p { + margin: 20px 0; +} +.overlay .modal .center { + text-align: center; +} +.overlay .modal button { + margin-top: 20px; + border: 1px solid #aaa; + padding: 10px 20px; + background-color: #aaa; + color: #fff; + cursor: pointer; +} +.overlay .modal button:hover { + background-color: #888; +} +/** End Overlay */ + +/** Media Queries for responsible */ +@media only screen and (max-width: 960px) { + .main-wrap { + font-size: 0.8em; + } +} +@media only screen and (max-width: 785px) { + .keyboard-wrap { + padding: 20px 5px 10px 5px; + } + .keyboard-wrap .row { + flex-flow: column; + } + .keyboard-wrap .row .col { + flex-flow: row; + } + .buttons-wrap.system { + transform: none; + } + .buttons-wrap.math { + margin: 0.4em; + } + .buttons-wrap.numbers { + transform: none; + } + .break-line-1 { + width: 100%; + } +} +@media only screen and (max-width: 625px) { + .keyboard-wrap .row .col { + flex-flow: column; + } + .screen-wrap { + padding: 1em 2.5em 0 2.5em; + } +} +@media only screen and (max-width: 525px) { + .break-line-1 { + width: auto; + } + .main-buttons-wrap { + font-size: 0.8em; + } + .main-wrap { + margin: 0; + padding: 0; + } + .top-structure .content { + flex-flow: column; + } + .top-structure .content .fake-disk { + height: 80px; + width: 100%; + order: -1; + box-shadow: none; + } +} +@media only screen and (max-width: 435px) { + .main-buttons-wrap { + font-size: 0.7em; + } + .buttons-wrap { + font-size: 0.9em; + } + .top-structure { + margin: 5px; + margin-bottom: 0; + } + .bottom-structure { + margin: 5px; + margin-top: 0; + } + .screen-wrap { + padding: 1em 1.8em 0 1.8em; + } +} +@media only screen and (max-width: 400px) { + .main-buttons-wrap { + font-size: 0.6em; + margin: 0; + } + .screen-wrap { + padding: 1em 1.3em 0 1.3em; + } +} +@media only screen and (max-width: 370px) { + .main-buttons-wrap { + flex-wrap: wrap; + } +} +/** End Media Queries for responsible */ diff --git a/2019-setembro/foxalex/index.html b/2019-setembro/foxalex/index.html new file mode 100644 index 0000000..6be1227 --- /dev/null +++ b/2019-setembro/foxalex/index.html @@ -0,0 +1,493 @@ + + + + + + + Pense Bem Challenge + + + + + + + + + + + +
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + +
+
+
+
+ +
+ +
+ + + +
+ + + +
+ +
+

Pense Bem ®

+
+ + + +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ + +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/2019-setembro/foxalex/js/app.js b/2019-setembro/foxalex/js/app.js new file mode 100644 index 0000000..964251a --- /dev/null +++ b/2019-setembro/foxalex/js/app.js @@ -0,0 +1,83 @@ +/** + * Buttons + */ + +function initButtons() { + // Main Buttons + const mainButtons = document.querySelectorAll('.main-buttons-wrap button'); + mainButtons.forEach(button => { + button.addEventListener('click', () => + PB_buttonPress(button.innerText.toUpperCase()) + ); + }); + // End Main Buttons + + // System Buttons + const systemButtons = document.querySelectorAll( + '.buttons-wrap.system button' + ); + systemButtons.forEach(button => { + button.addEventListener('click', () => + PB_buttonPress(button.innerText.replace('.', '').toUpperCase()) + ); + }); + // End System Buttons + + // Math Numbers + const mathButtons = document.querySelectorAll('.buttons-wrap.math button'); + mathButtons.forEach(button => { + button.addEventListener('click', () => + PB_buttonPress(button.getAttribute('data-signal')) + ); + }); + + // Numbers Buttons + const numbersButtons = document.querySelectorAll( + '.buttons-wrap.numbers button' + ); + numbersButtons.forEach(button => { + const number = button.querySelector('span').innerText; + button.addEventListener('click', () => PB_buttonPress(number)); + }); + // End Numbers + + // Games Buttons + const gamesButtons = document.querySelectorAll('.buttons-wrap.games button'); + gamesButtons.forEach(button => { + const action = button.getAttribute('data-game'); + button.addEventListener('click', () => PB_buttonPress(action)); + }); + // End Games Buttons +} + +/** + * Overlay Welcome + */ +const overlay = document.querySelector('.overlay'); +const btnWelcome = document.querySelector('.overlay button'); +// Add Event - Click +btnWelcome.addEventListener('click', () => { + overlay.classList.add('hidden'); + window.localStorage.setItem('first', true); +}); +// End Overlay + +/** + * Init + */ +function init() { + // Check and Show Overlay + const check = window.localStorage.getItem('first'); + if (check === null) { + overlay.classList.remove('hidden'); + } + + // Init Buttons + initButtons(); + + // Init Pensebem.js + PB_init(); +} + +// Init App +window.addEventListener('load', init); diff --git a/2019-setembro/foxalex/js/pensebem.js b/2019-setembro/foxalex/js/pensebem.js new file mode 100644 index 0000000..1f7cc20 --- /dev/null +++ b/2019-setembro/foxalex/js/pensebem.js @@ -0,0 +1,1192 @@ +/** + * Pense-Bem Logica desenvolvido por + * e + * + * https://github.com/lpereira/Pense-Bem + */ + +pulseAudioBug = navigator.userAgent.indexOf('Linux') > 0; + +if (typeof Float32Array !== "function") + Float32Array = Array; + +Songs = { + Welcome: 'egage', + GameSelected: 'CgC', + Correct: 'gCC', + Wrong: 'ec', + Fail: 'egec', + Winner: 'gggeCCC', + HighBeep: 'C', + LowBeep: 'c' +}; + +Som = { + SampleRate: 8192, + TickInterval: 20, + currentNote: 0, + isPlayingSong: false, + lowBeep: function() { + Som.playNote(Songs.LowBeep); + }, + highBeep: function() { + Som.playNote(Songs.HighBeep); + }, + songFinishedCallback: function() {}, + toneFinishedPlaying: function() { + if (!Som.isPlayingSong) return; + + if (Som.currentNote >= Som.playQueue.length) { + Som.currentNote = 0; + Som.isPlayingSong = false; + if (Som.shouldClearQueue) + Som.playQueue = []; + Som.songFinishedCallback(); + Som.songFinishedCallback = function() {}; + PB.enableKeyboard(); + } else { + Som.playNote(Som.playQueue[Som.currentNote]); + Som.notePlayCallback(Som.playQueue[Som.currentNote], Som.currentNote >= Som.playQueue.length - 1); + Som.currentNote++; + } + }, + playSoundQueue: function(shouldClearQueue, notePlayCallback) { + Som.isPlayingSong = true; + Som.shouldClearQueue = shouldClearQueue || false; + Som.notePlayCallback = notePlayCallback || function() {}; + PB.disableKeyboard(); + Som.toneFinishedPlaying(); + }, + playSong: function(song, callback) { + Som.songFinishedCallback = callback || function() {}; + Som.playQueue = song; + Som.playSoundQueue(true); + }, + encodeBase64: function(str) { + var out, i, len; + var c1, c2, c3; + const Base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + + len = str.length; + i = 0; + out = ''; + while (i < len) { + c1 = str.charCodeAt(i++) & 0xff; + if (i == len) { + out += Base64EncodeChars[c1 >> 2]; + out += Base64EncodeChars[(c1 & 0x3) << 4]; + out += '=='; + break; + } + c2 = str.charCodeAt(i++); + if (i == len) { + out += Base64EncodeChars[c1 >> 2]; + out += Base64EncodeChars[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)]; + out += Base64EncodeChars[(c2 & 0xF) << 2]; + out += '='; + break; + } + c3 = str.charCodeAt(i++); + out += Base64EncodeChars[c1 >> 2]; + out += Base64EncodeChars[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)]; + out += Base64EncodeChars[((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)]; + out += Base64EncodeChars[c3 & 0x3F]; + } + return out; + }, + encode8BitAudio: function(data) { + var n = data.length; + + // 8-bit mono WAVE header template + var header = 'RIFF<##>WAVEfmt \x10\x00\x00\x00\x01\x00\x01\x00<##><##>\x01\x00\x08\x00data<##>'; + + // Helper to insert a 32-bit little endian int. + function insertLong(value) { + var bytes = ''; + for (var i = 0; i < 4; ++i) { + bytes += String.fromCharCode(value & 255); + value = Math.floor(value / 256); + } + header = header.replace('<##>', bytes); + } + + insertLong(36 + n); // chunk size + insertLong(Som.SampleRate); // sample rate + insertLong(Som.SampleRate); // byte rate + insertLong(n); // subchunk2 size + // Output sound data + for (var i = 0; i < n; ++i) { + header += String.fromCharCode(data[i] * 255); + } + + return 'data:audio/wav;base64,' + Som.encodeBase64(header); + }, + newTone: function(f) { + var audio = new Audio(); + audio.volume = PB.audioVolume; + const numberOfSamples = Math.ceil(Som.SampleRate * Som.TickInterval / 100); + const dt = 1 / Som.SampleRate; + var samples = new Float32Array(numberOfSamples); + for (var i = 0; i < numberOfSamples; ++i) { + const x = f * (i * dt); + const y = x - Math.floor(x); + const envelope = Math.min(1, 5 * (1 - i / numberOfSamples)); + //square wave + samples[i] = envelope * !!(y >= 0.5); + //sawtooth wave + //samples.push(envelope * y); + //sine wawe + //samples.push(envelope * (Math.sin(2*3.1415*x)/2.0 + 0.5)); + } + + audio.setAttribute('src', Som.encode8BitAudio(samples)); + + if (!pulseAudioBug) { + audio.addEventListener('ended', function() { + Som.toneFinishedPlaying(); + }, false); + } + + audio.autoplay = false; + return function() { + audio.load(); + audio.play(); + if (pulseAudioBug) { + window.setTimeout(Som.toneFinishedPlaying, 300); + } + }; + }, + NoteToToneTable: null, + playNote: function(n) { + //real note frequency values: + const FreqC4 = 261.63; + const FreqD4 = 293.66; + const FreqE4 = 329.63; + const FreqF4 = 349.23; + const FreqF4Sharp = 369.994; + const FreqG4 = 392.00; + const FreqA4 = 440.00; + const FreqB4 = 493.88; + const FreqC5 = 523.25; + const FreqC5Sharp = 554.365; + const FreqD5 = 587.33; + const FreqE5 = 659.255; + + if (!Som.NoteToToneTable) { + if (!PB.bugfix) { + Som.NoteToToneTable = { + 'c': Som.newTone(FreqD4), + 'd': Som.newTone(FreqE4), + 'e': Som.newTone(FreqF4Sharp), + 'f': Som.newTone(FreqG4), + 'g': Som.newTone(FreqA4), + 'a': Som.newTone(FreqB4), + 'b': Som.newTone(FreqC5Sharp), + 'C': Som.newTone(FreqD5), + 'D': Som.newTone(FreqE5), + 'p': function() { + PB.delay(3, Som.toneFinishedPlaying); + } + }; + } else { + Som.NoteToToneTable = { + 'c': Som.newTone(FreqC4), + 'd': Som.newTone(FreqD4), + 'e': Som.newTone(FreqE4), + 'f': Som.newTone(FreqF4), + 'g': Som.newTone(FreqG4), + 'a': Som.newTone(FreqA4), + 'b': Som.newTone(FreqB4), + 'C': Som.newTone(FreqC5), + 'D': Som.newTone(FreqD5), + 'p': function() { + PB.delay(3, Som.toneFinishedPlaying); + } + }; + } + } + var tone = Som.NoteToToneTable[n]; + if (tone) + tone(); + } +}; + +//------------------------------------------------------------------------------ +Aritmetica = { + reset: function(possibleOperations) { + Aritmetica.possibleOperations = possibleOperations || '+-/*'; + Aritmetica.showResultFlag = false; + Aritmetica.showOperatorFlag = true; + Aritmetica.numQuestions = 10; + Display.clear(); + Som.playSong(Songs.GameSelected, Aritmetica.newGame); + }, + newGame: function() { + Aritmetica.points = 0; + Aritmetica.currentQuestion = 0; + Aritmetica.advanceQuestion(); + }, + oneLoopIteration: function() { + if (Prompt.done) { + Aritmetica.answerQuestion(parseInt(Prompt.getInput(), 10) == Aritmetica.answer); + } + }, + answerQuestion: function(correct) { + if (correct) { + Aritmetica.correct(); + } else { + Aritmetica.incorrect(); + } + }, + flashResultsAndAdvanceQuestion: function(ticks) { + Aritmetica.showCorrectAnswer(); + Display.blinkAll(); + PB.delay(ticks || 30, function() { + Display.clear(); + PB.delay(4, Aritmetica.advanceQuestion); + }); + }, + incorrect: function() { + Aritmetica.tries++; + if (Aritmetica.tries >= 3) { + Display.clear(); + Som.playSong(Songs.Fail, Aritmetica.flashResultsAndAdvanceQuestion); + } else { + Display.clear(); + Som.playSong(Songs.Wrong, function() { + PB.delay(2, function() { + Aritmetica.redrawScreen(); + if (Aritmetica.showOperatorFlag) PB.prompt(7, 3); + }); + }); + } + }, + correct: function() { + Display.clear(); + Som.playSong(Songs.Correct, function() { + Aritmetica.points += PB.pointsByNumberOfTries(Aritmetica.tries); + Aritmetica.flashResultsAndAdvanceQuestion(10); + }); + }, + showCorrectAnswer: function() { + Aritmetica.redrawScreen(); + if (Aritmetica.showOperatorFlag) { + Display.showNumberAtDigit(Aritmetica.answer, 7); + } else { + Aritmetica.showOperator(true); + } + }, + showOperator: function(force) { + if (force || Aritmetica.showOperatorFlag) { + Display.setSpecialDigit({ + '*': 'x', + '/': '%', + '+': '+', + '-': '-' + }[Aritmetica.operation]); + } else { + Display.blinkSpecialDigit('#'); + } + }, + buttonPress: function(b) {}, + OperatorFunctionTable: { + '+': function(a, b) { + return ~~ (a + b); + }, + '-': function(a, b) { + return ~~ (a - b); + }, + '/': function(a, b) { + return ~~ (a / b); + }, + '*': function(a, b) { + return ~~ (a * b); + } + }, + redrawScreen: function() { + Display.clear(); + Display.showNumberAtDigit(Aritmetica.firstDigit, 2); + Display.showNumberAtDigit(Aritmetica.secondDigit, 4); + if (Aritmetica.showResultFlag) Display.showNumberAtDigit(Aritmetica.answer, 7); + Aritmetica.showOperator(); + Display.setSpecialDigit2('='); + }, + advanceQuestion: function() { + function isDivisionByZero() { + return Aritmetica.operation == '/' && Aritmetica.secondDigit == 0; + } + function isSumOrSubtractionWithZero() { + return (Aritmetica.operation == '+' || Aritmetica.operation == '-') && Aritmetica.secondDigit == 0; + } + function isDivisionOrMultiplication() { + return Aritmetica.operation == '*' || Aritmetica.operation == '/'; + } + function isDivisionOrMultiplicationWithOne() { + return isDivisionOrMultiplication() && Aritmetica.secondDigit == 1; + } + function isZeroDividedOrMultipliedBySomething() { + return isDivisionOrMultiplication() && Aritmetica.firstDigit == 0; + } + function isDivisionOrSubtractionAndResultIsLessThanOne() { + return (Aritmetica.operation == '/' || Aritmetica.operation == '-') && Aritmetica.firstDigit < Aritmetica.secondDigit; + } + function isForbiddenCombination() { + return isDivisionByZero() || + isSumOrSubtractionWithZero() || + isDivisionOrMultiplicationWithOne() || + isDivisionOrSubtractionAndResultIsLessThanOne() || + (Aritmetica.showResultFlag && isZeroDividedOrMultipliedBySomething()); + } + + if (Aritmetica.currentQuestion++ >= Aritmetica.numQuestions) { + PB.delay(10, function() { + Display.showNumberAtDigit(Aritmetica.points, 7); + Display.blinkAll(); + Som.playSong(Songs.Winner, function() { + PB.delay(30, Aritmetica.newGame); + }); + }); + return; + } + Aritmetica.tries = 0; + + do { + Aritmetica.operation = Aritmetica.possibleOperations[~~ (Math.random() * (Aritmetica.possibleOperations.length - 1))]; + Aritmetica.firstDigit = ~~ (Math.random() * 99); + Aritmetica.secondDigit = ~~ (Math.random() * 9); + } while (isForbiddenCombination()); + + if (Aritmetica.secondDigit && isDivisionOrMultiplication()) + Aritmetica.firstDigit -= Aritmetica.firstDigit % Aritmetica.secondDigit; + Aritmetica.answer = Aritmetica.OperatorFunctionTable[Aritmetica.operation](Aritmetica.firstDigit, Aritmetica.secondDigit); + Aritmetica.redrawScreen(); + if (Aritmetica.showOperatorFlag) + PB.prompt(7, 3); + } +}; + +//------------------------------------------------------------------------------ +Adicao = { + reset: function() { + Aritmetica.reset('+'); + }, + oneLoopIteration: Aritmetica.oneLoopIteration, + buttonPress: Aritmetica.buttonPress +}; + +//------------------------------------------------------------------------------ +Subtracao = { + reset: function() { + Aritmetica.reset('-'); + }, + oneLoopIteration: Aritmetica.oneLoopIteration, + buttonPress: Aritmetica.buttonPress +}; + +//------------------------------------------------------------------------------ +Multiplicacao = { + reset: function() { + Aritmetica.reset('*'); + }, + oneLoopIteration: Aritmetica.oneLoopIteration, + buttonPress: Aritmetica.buttonPress +}; + +//------------------------------------------------------------------------------ +Divisao = { + reset: function() { + Aritmetica.reset('/'); + }, + oneLoopIteration: Aritmetica.oneLoopIteration, + buttonPress: Aritmetica.buttonPress +}; + +//------------------------------------------------------------------------------ +Operacao = { + reset: function() { + Aritmetica.reset(); + Aritmetica.showOperatorFlag = false; + Aritmetica.showResultFlag = true; + }, + oneLoopIteration: function() {}, + buttonPress: function(b) { + switch (b) { + case '+': + case '-': + case '*': + case '/': + Display.setSpecialDigit({ + '+': '+', + '-': '-', + '*': 'x', + '/': '%' + }[b]); + Display.stopBlinking(8); + PB.delay(2, function() { + Aritmetica.answerQuestion(b == Aritmetica.operation); + }); + break; + default: + Som.highBeep(); + } + } +}; + +//------------------------------------------------------------------------------ +SigaMe = { + reset: function() { + Display.clear(); + SigaMe.guessIndex = 0; + SigaMe.sequence = []; + Som.playSong(Songs.GameSelected, function() { + PB.delay(5, SigaMe.addRandomNote); + }); + }, + addRandomNote: function() { + SigaMe.sequence.push(~~(Math.random() * 9)); + SigaMe.playSequence(); + }, + oneLoopIteration: function() {}, + playSequence: function() { + var sequenceIndex = 0; + function noteFinishedPlaying() { + if (++sequenceIndex >= SigaMe.sequence.length) + return; + Display.clear(); + PB.delay(2, function() { + Display.setDigit(7, SigaMe.sequence[sequenceIndex]); + Som.playSong('cdefgabCDE'[SigaMe.sequence[sequenceIndex]], noteFinishedPlaying); + }); + } + Display.clear(); + Display.setDigit(7, SigaMe.sequence[0]); + Som.playSong('cdefgabCDE'[SigaMe.sequence[0]], noteFinishedPlaying); + }, + buttonPress: function(b) { + if (b in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']) { + if (b == SigaMe.sequence[SigaMe.guessIndex]) { + Display.clear(); + PB.disableKeyboard(); + PB.delay(2, function() { + Som.playNote('cdefgabCDE'[b]); + Display.setDigit(7, b); + PB.delay(4, function() { + if (SigaMe.sequence.length == 1) { + SigaMe.addRandomNote(); + } else if (SigaMe.sequence.length == 15) { + Som.playSong(Songs.Winner, SigaMe.reset); + } else if (SigaMe.guessIndex < SigaMe.sequence.length - 1) { + SigaMe.guessIndex++; + } else { + SigaMe.guessIndex = 0; + SigaMe.addRandomNote(); + } + PB.enableKeyboard(); + }); + }); + } else { + Som.playSong(Songs.Wrong, function() { + PB.delay(10, function() { + SigaMe.playSequence(); + SigaMe.guessIndex = 0; + }); + }); + } + } + } +}; + +//------------------------------------------------------------------------------ +MemoriaTons = { + reset: function() { + Display.clear(); + Som.playSong(Songs.GameSelected, function() { + MemoriaTons.pressedEnter = false; + MemoriaTons.fakePrompt(); + }); + }, + fakePrompt: function() { + Display.blinkDigit(7, '-'); + }, + oneLoopIteration: function() {}, + buttonPress: function(b) { + if (b == 'ENTER') { + MemoriaTons.pressedEnter = true; + Som.playSoundQueue(false, function(noteCode, lastNote) { + Display.showNumberAtDigit({ + 'p': 0, 'c': 1, 'd': 2, + 'e': 3, 'f': 4, 'g': 5, + 'a': 6, 'b': 7, 'C': 8, + 'D': 9 + }[noteCode], 7); + PB.delay(2, lastNote ? MemoriaTons.fakePrompt : Display.clear); + }); + return; + } + var note = { + '0': 'p', '1': 'c', '2': 'd', + '3': 'e', '4': 'f', '5': 'g', + '6': 'a', '7': 'b', '8': 'C', + '9': 'D' + }[b]; + if (note) { + Display.clear(); + if (MemoriaTons.pressedEnter) { + MemoriaTons.pressedEnter = false; + Som.playQueue = []; + } + Som.playQueue.push(note); + Som.playNote(note); + Display.showNumberAtDigit(b, 7); + } else + Som.lowBeep(); + } +}; + +//------------------------------------------------------------------------------ +AdivinheONumero = { + isMiddleNumber: false, + maxTries: 10, + reset: function(isMiddleNumber) { + Display.clear(); + AdivinheONumero.points = 0; + AdivinheONumero.isMiddleNumber = isMiddleNumber || false; + AdivinheONumero.maxTries = isMiddleNumber ? 3 : 10; + Som.playSong(Songs.GameSelected, AdivinheONumero.advanceQuestion); + }, + advanceQuestion: function() { + Display.clear(); + + if (AdivinheONumero.isMiddleNumber) { + AdivinheONumero.firstDigit = Math.round(Math.random() * 50); + AdivinheONumero.secondDigit = AdivinheONumero.firstDigit + Math.round(Math.random() * 47) + 2; + AdivinheONumero.answer = Math.round((AdivinheONumero.firstDigit + AdivinheONumero.secondDigit) / 2); + } else { + AdivinheONumero.firstDigit = 0; + AdivinheONumero.secondDigit = 99; + AdivinheONumero.answer = AdivinheONumero.firstDigit + Math.round(Math.random() * (AdivinheONumero.secondDigit - AdivinheONumero.firstDigit)); + } + + AdivinheONumero.tries = 0; + Display.showNumberAtDigit(AdivinheONumero.firstDigit, 2); + Display.showNumberAtDigit(AdivinheONumero.secondDigit, 6); + PB.prompt(4, 2, '*'); + }, + showAnswer: function(s) { + Display.clear(); + Som.playSong(s, function() { + Display.setSpecialDigit('~'); + Display.setSpecialDigit2('-'); + Display.showNumberAtDigit(AdivinheONumero.firstDigit, 2); + Display.showNumberAtDigit(AdivinheONumero.secondDigit, 6); + Display.showNumberAtDigit(AdivinheONumero.answer, 4); + PB.delay(20, function() { + Display.clear(); + PB.delay(3, AdivinheONumero.advanceQuestion); + }); + }); + }, + oneLoopIteration: function() { + if (!Prompt.done) return; + var guess = Prompt.getInput(); + if (guess != AdivinheONumero.answer) { + if (!AdivinheONumero.isMiddleNumber) { + if (guess < AdivinheONumero.answer) AdivinheONumero.firstDigit = guess; + else AdivinheONumero.secondDigit = guess; + + Display.showNumberAtDigit(AdivinheONumero.firstDigit, 2); + Display.showNumberAtDigit(AdivinheONumero.secondDigit, 6); + } + + AdivinheONumero.tries++; + if (AdivinheONumero.tries < AdivinheONumero.maxTries) { + Som.playSong(Songs.Wrong, function() { + PB.prompt(4, 2, '*'); + }); + return; + } + AdivinheONumero.showAnswer(Songs.Fail); + } else { + AdivinheONumero.showAnswer(Songs.Correct); + AdivinheONumero.points += PB.pointsByNumberOfTries(AdivinheONumero.tries); + } + }, + buttonPress: function() {} +}; + +//------------------------------------------------------------------------------ +NumeroDoMeio = { + reset: function() { + AdivinheONumero.maxTries = 3; + AdivinheONumero.reset(true); + }, + oneLoopIteration: AdivinheONumero.oneLoopIteration, + buttonPress: AdivinheONumero.buttonPress +}; + +//------------------------------------------------------------------------------ +Livro = { + StateChoosingBook: 0, + StateQuestioning: 1, + reset: function() { + Som.playSong(Songs.GameSelected, function() { + Livro.state = Livro.StateChoosingBook; + PB.prompt(); + }); + }, + oneLoopIteration: function() { + switch (Livro.state) { + case Livro.StateChoosingBook: + if (!Prompt.done) return; + const bookCode = Prompt.getInput(); + const bookNumber = parseInt(bookCode.substring(0, 2)); + const sectionNumber = parseInt(bookCode.substring(2)); + + if (sectionNumber < 1 || sectionNumber > 6 || bookCode < 1) { + Display.clear(); + Som.playSong(Songs.Wrong, PB.prompt); + return; + } + + Livro.bookNumber = bookNumber; + Livro.sectionNumber = sectionNumber; + Livro.isReviewMode = sectionNumber == 6; + if (!Livro.isReviewMode) { + Livro.maxQuestion = sectionNumber * 30; + Livro.currentQuestion = Livro.maxQuestion - 30; + } else { + Livro.maxQuestion = 150; + Livro.chooseRandomQuestion(); + } + Livro.answeredQuestions = 0; + Livro.points = 0; + + Livro.state = Livro.StateQuestioning; + + Display.clear(); + Som.playSong(Songs.Correct, Livro.advanceQuestion); + break; + case Livro.StateQuestioning: + } + }, + chooseRandomQuestion: function() { + Livro.currentQuestion = ~~(Math.random() * (Livro.maxQuestion - 1)) + 1; + }, + highlightAnswer: function(answer, blink) { + Display.clear(); + Display.showNumberAtDigit(Livro.currentQuestion, 3); + const digit = {'A': 4, 'B': 5, 'C': 6, 'D': 7}[answer]; + if (blink) + Display.blinkDigit(digit, '_'); + else + Display.setDigit(digit, '_'); + }, + showCorrectAnswer: function(blink) { + Livro.highlightAnswer(Livro.getCorrectAnswer(), blink); + }, + displayQuestionPrompt: function() { + Display.clear(); + PB.delay(3, function() { + Display.showNumberAtDigit(Livro.currentQuestion, 3); + for (var i = 4; i <= 7; i++) + Display.setDigit(i, '_'); + }); + PB.enableKeyboard(); + }, + advanceQuestion: function() { + if (Livro.currentQuestion >= 0) { + Livro.points += PB.pointsByNumberOfTries(Livro.tries); + } + Livro.tries = 0; + if (Livro.isReviewMode) { + Livro.chooseRandomQuestion(); + } else { + ++Livro.currentQuestion; + } + + if (Livro.answeredQuestions >= 30) { + Display.clear(); + Display.showNumberAtDigit(Livro.points, 7); + Display.blinkAll(); + PB.disableKeyboard(); + Som.playSong(Songs.Winner, function() { + PB.delay(30, function() { + Livro.state = Livro.StateChoosingBook; + PB.enableKeyboard(); + PB.prompt(); + }); + }); + return; + } + Livro.displayQuestionPrompt(); + }, + getCorrectAnswer: function() { + + + const patternList = [ + 'CDDBAADCBDAADCBB', + 'CCBDDDBDABABDACA', + 'DDCBDABABDACACCB', + 'AABBCDCDDDACAABC', + 'CCABADBBBCDCDDDA', + 'ADCBADBADBBDDCCB', + 'ADDBADBBDCCCBADB', + 'DDBBDABBDABDABCC', + 'BDDCCDDAACDBBDDB', + 'CBCDCBBBDABDDDCD' + ]; + + const index = Math.floor((Livro.currentQuestion - 1) / 15); + const question = (Livro.currentQuestion % 15 > 0 ? Livro.currentQuestion % 15 : 15) + + const answers = patternList[index]; + + return answers[(Livro.bookNumber+question)%16] + }, + buttonPress: function(b) { + switch (Livro.state) { + case Livro.StateChoosingBook: + break; + case Livro.StateQuestioning: + switch (b) { + case 'A': + case 'B': + case 'C': + case 'D': + PB.disableKeyboard(); + + if (Livro.getCorrectAnswer(b) == b) { + ++Livro.answeredQuestions; + Livro.showCorrectAnswer(true); + Som.playSong(Songs.Correct, function() { + PB.delay(10, Livro.advanceQuestion); + }); + return; + } + ++Livro.tries; + if (Livro.tries >= 3) { + ++Livro.answeredQuestions; + Livro.showCorrectAnswer(true); + Som.playSong(Songs.Fail, function() { + PB.delay(20, Livro.advanceQuestion); + }); + } else { + Display.clear(); + PB.delay(3, function() { + Livro.highlightAnswer(b, false); + Som.playSong(Songs.Wrong, function() { + PB.delay(10, Livro.displayQuestionPrompt); + }); + }); + } + break; + default: + Som.lowBeep(); + } + break; + } + } +}; + +//------------------------------------------------------------------------------ +Welcome = { + ButtonToActivityTable: { + 'ADIVINHE-O-NÚMERO': AdivinheONumero, + 'ADIÇÃO': Adicao, + 'MULTIPLICAÇÃO': Multiplicacao, + 'DIVISÃO': Divisao, + 'ARITMÉTICA': Aritmetica, + 'OPERAÇÃO': Operacao, + 'SIGA-ME': SigaMe, + 'MEMÓRIA-TONS': MemoriaTons, + 'NÚMERO-DO-MEIO': NumeroDoMeio, + 'SUBTRAÇÃO': Subtracao, + 'LIVRO': Livro + }, + reset: function() { + Display.clear(); + Som.playSong(Songs.Welcome, function() { + Display.blinkSpecialDigit('*'); + }); + }, + oneLoopIteration: function() {}, + buttonPress: function(b) { + const newActivity = Welcome.ButtonToActivityTable[b]; + if (newActivity) + PB.setActivity(newActivity); + else + Som.lowBeep(); + } +}; + +//------------------------------------------------------------------------------ +Standby = { + reset: function() { + Display.clear(); + PB.disableKeyboard(); + }, + oneLoopIteration: function() {}, + buttonPress: function(b) {} +}; + +//------------------------------------------------------------------------------ +Prompt = { + maxDigitSize: 3, + initialDigit: 7, + done: false, + promptCharacter: '-', + reset: function() { + Prompt.done = false; + Prompt.input = ' '; + Display.clear(Prompt.initialDigit - Prompt.maxDigitSize + 1, Prompt.initialDigit); + if (Prompt.initialDigit == 4 && Prompt.maxDigitSize == 2) { + Display.setSpecialDigit(' '); + Display.setSpecialDigit2(' '); + Display.blinkSpecialDigit(Prompt.promptCharacter); + } else + Display.blinkDigit(Prompt.initialDigit, Prompt.promptCharacter); + }, + getInput: function() { + const value = Prompt.input; + Prompt.reset(); + return value; + }, + isEmpty: function() { + return Prompt.input == ' '; + }, + oneLoopIteration: function() {}, + redrawPrompt: function() { + Display.showNumberAtDigit(Prompt.input, Prompt.initialDigit); + }, + buttonPress: function(b) { + if (b == 'ENTER') { + if (Prompt.isEmpty()) { + Som.highBeep(); + return; + } + Prompt.done = true; + PB.activity = PB.previousActivity; + return; + } + if (b in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']) { + Som.lowBeep(); + Display.disableBlink(); + if (Prompt.initialDigit == 4 && Prompt.maxDigitSize == 2) { + Display.setSpecialDigit('~'); + Display.setSpecialDigit2('-'); + } + switch (Prompt.maxDigitSize) { + case 1: + Prompt.input = b; + break; + case 2: + Prompt.input = Prompt.input[1] + b; + break; + default: + Prompt.input = Prompt.input[1] + Prompt.input[2] + b; + break; + } + Prompt.redrawPrompt(); + } else { + //blink and HighBeep + Som.highBeep(); + } + } +}; + +//------------------------------------------------------------------------------ +Display = { + onPhase: true, + blinkTable: 0, + blinkTimer: null, + contents: ['?', '?', '?', '?', '?', '?', '?', '?', '?'], + SpecialFontTable: { + ' ': 0, + '#': 49279, + '%': 49216, + '+': 16420, + '*': 16447, + '-': 16384, + 'x': 27, + '~': 128 + }, + FontTable: { + ' ': 0, + '*': 64, + '-': 64, + '0': 63, + '1': 3, + '2': 109, + '3': 103, + '4': 83, + '5': 118, + '6': 126, + '7': 35, + '8': 127, + '9': 119, + '_': 4 + }, + setSegmentById: function(id, state) { + var s = document.getElementById(id); + s.setAttribute('visibility', state ? 'hidden' : 'visible'); + }, + setSegment: function(i, seg, state) { + Display.setSegmentById('d' + i + '_' + seg, state); + }, + clear: function(begin, end) { + begin = begin || 1; + end = end || 7; + for (var i = begin; i <= end; ++i) + Display.setDigit(i, ' '); + const range = end - begin; + if (range >= 3) Display.setSpecialDigit(' '); + if (range >= 5) Display.setSpecialDigit2(' '); + Display.disableBlink(); + }, + restoreFromStoredContents: function() { + if (!Display.onPhase) return; + for (var d = 0; d < 7; d++) + if (Display.blinkTable & (1 << d)) + Display.setDigit(d + 1, Display.contents[d], true); + if (Display.blinkTable & 1 << 7) Display.setSpecialDigit(Display.contents[7], true); + if (Display.blinkTable & 1 << 8) Display.setSpecialDigit2(Display.contents[8], true); + Display.onPhase = false; + }, + hideBlinkingSegments: function() { + if (Display.onPhase) return; + for (var d = 0; d < 7; d++) + if (Display.blinkTable & (1 << d)) + Display.setDigit(d + 1, ' ', true); + if (Display.blinkTable & 1 << 7) Display.setSpecialDigit(' ', true); + if (Display.blinkTable & 1 << 8) Display.setSpecialDigit2(' ', true); + Display.onPhase = true; + }, + blinkTimerCallback: function() { + if (PB.ticks % 10 < 3) { + Display.hideBlinkingSegments(); + } else { + Display.restoreFromStoredContents(); + } + }, + enableBlinkTimerIfNeeded: function() { + if (!Display.blinkTable) { + if (Display.blinkTimer) { + Display.blinkTimer = clearInterval(Display.blinkTimer); + Display.restoreFromStoredContents(); + } + } else if (!Display.blinkTimer) + Display.blinkTimer = setInterval(Display.blinkTimerCallback, 100); + }, + disableBlink: function() { + Display.blinkTable = 0; + Display.enableBlinkTimerIfNeeded(); + }, + blinkAll: function() { + Display.blinkTable = -1; + Display.enableBlinkTimerIfNeeded(); + }, + blinkDigit: function(which, c) { + if (c) Display.setDigit(which, c); + Display.blinkTable |= 1 << (which - 1); + Display.enableBlinkTimerIfNeeded(); + }, + blinkSpecialDigit: function(c) { + if (c) Display.setSpecialDigit(c); + Display.blinkTable |= 1 << 7; + Display.enableBlinkTimerIfNeeded(); + }, + blinkSpecialDigit2: function(c) { + if (c) Display.setSpecialDigit2(c); + Display.blinkTable |= 1 << 8; + Display.enableBlinkTimerIfNeeded(); + }, + stopBlinking: function(which) { + Display.blinkTable &= ~ (1 << (which - 1)); + Display.enableBlinkTimerIfNeeded(); + }, + setDisplay: function(c) { + for (var i = 1; i <= 7; ++i) { + Display.setDigit(i, c[i - 1]); + } + }, + setDigit: function(i, c, tmp) { + if (tmp === undefined) { + Display.contents[i - 1] = c; + } + var state = Display.FontTable[c] || Display.FontTable[' ']; + for (var segment = 0; segment < 7; segment++) + Display.setSegment(i, 'abcdefg'[segment], state & (1 << segment)); + }, + showNumberAtDigit: function(n, d) { + if (typeof (n) == 'string') { + if (n.length == 1) { + Display.setDigit(d, n[0]); + } else if (n.length == 2) { + Display.setDigit(d, n[1]); + Display.setDigit(d - 1, n[0]); + } else { + Display.setDigit(d, n[2]); + Display.setDigit(d - 1, n[1]); + Display.setDigit(d - 2, n[0]); + } + } else { + Display.setDigit(d, n % 10); + if (n < 100) { + if (n = ~~(n / 10) % 10) + Display.setDigit(d - 1, n); + } else { + Display.setDigit(d - 1, ~~ (n / 10) % 10); + Display.setDigit(d - 2, ~~ (n / 100) % 10); + } + } + }, + setSpecialDigit: function(c, tmp) { + if (tmp === undefined) { + Display.contents[7] = c; + } + if (c in Display.FontTable) + Display.setDigit(3, c); + var state = Display.SpecialFontTable[c] || Display.SpecialFontTable[' ']; + for (var segment = 0; segment < 8; segment++) { + Display.setSegment(8, 'abcdefgh'[segment], state & (1 << segment)); + Display.setSegment(3, 'abcdefgh'[segment], (state >> 8) & (1 << segment)); + } + }, + setSpecialDigit2: function(c, tmp) { + if (tmp === undefined) { + Display.contents[8] = c; + } + + Display.setSegmentById('igual', {'=': true, '-': true}[c] || false); + Display.setSegmentById('igual2', {'=': true, '-': false}[c] || false); + } +}; + +//------------------------------------------------------------------------------ +PB = { + bugfix: false, + /* we are simulating all the bugs from the original machine */ + activity: null, + ticks: 0, + delayTable: {}, + keyboardEnabled: true, + audioVolume: 1, + init: function() { + PB.setActivity(Standby); + PB.reset(); + setInterval(PB.oneLoopIteration, 100); + PB.turnOnReminderTimer = setTimeout(PB.showReminder, 3000); + }, + showReminder: function() { + //document.getElementById('ligue-me-tip').setAttribute('display', 'true'); + PB.turnOnReminderTimer = clearTimeout(PB.turnOnReminderTimer); + }, + resetDefaultVariables: function() { + PB.delayTable = {}; + PB.enableKeyboard(); + PB.ticks = 0; + Display.disableBlink(); + }, + reset: function() { + PB.resetDefaultVariables(); + if (PB.activity) PB.activity.reset(); + }, + delay: function(ticks, callback) { + PB.delayTable[PB.ticks + ticks] = callback; + }, + oneLoopIteration: function() { + ++PB.ticks; + + for (var delay in PB.delayTable) { + if (PB.ticks >= delay) { + PB.delayTable[delay](); + delete PB.delayTable[delay]; + } + } + + if (PB.activity) PB.activity.oneLoopIteration(); + }, + setActivity: function(m, keepScreenContents) { + + if (PB.turnOnReminderTimer) + PB.turnOnReminderTimer = clearTimeout(PB.turnOnReminderTimer); + //document.getElementById('ligue-me-tip').setAttribute('display', 'none'); + if (!keepScreenContents) + Display.clear(); + PB.resetDefaultVariables(); + PB.activity = m; + PB.reset(); + }, + prompt: function(initialDigit, maxDigitSize, promptCharacter) { + Prompt.initialDigit = initialDigit || 7; + Prompt.maxDigitSize = maxDigitSize || 3; + Prompt.promptCharacter = promptCharacter || '-'; + PB.previousActivity = PB.activity; + PB.setActivity(Prompt, true); + }, + buttonPress: function(b) { + switch (b) { + case 'LIGA': + PB.setActivity(Welcome); + return; + case 'DESL': + PB.setActivity(Standby); + return; + default: + if (PB.keyboardEnabled && PB.activity) { + if ((PB.activity != Welcome) && (b in Welcome.ButtonToActivityTable)) { + Som.highBeep(); + return; + } + PB.activity.buttonPress(b); + } + } + }, + enableKeyboard: function() { + PB.keyboardEnabled = true; + }, + disableKeyboard: function() { + PB.keyboardEnabled = false; + }, + pointsByNumberOfTries: function(t) { + switch (t) { + case 0: + return 10; + case 1: + return 6; + case 2: + return 4; + } + return 0; + } +}; + +document.onkeydown = function(event) { + const keyCode = { + 13: 'ENTER', + 19: 'PAUSE', + 80: 'PAUSE', + 27: 'DESL', + 48: '0', + 49: '1', + 50: '2', + 51: '3', + 52: '4', + 53: '5', + 54: '6', + 55: '7', + 56: '8', + 57: '9' + }[event.which]; + if (keyCode) PB.buttonPress(keyCode); +}; + +//If we want to fix bugs found on the original machine +// then uncomment the following line: +//PB.bugfix = true; +//Change the PB Audio Volume; +PB.audioVolume = .05; + +// Add Functions to Window; +window['PB_buttonPress'] = PB.buttonPress; +window['PB_init'] = PB.init; \ No newline at end of file