From 288f2f47534970603566284500911ac07fde4c29 Mon Sep 17 00:00:00 2001 From: marko Date: Wed, 16 Mar 2022 11:23:16 -0400 Subject: [PATCH] Add "Bordle" app --- apps/bordle/README.md | 17 ++++ apps/bordle/app-icon.js | 1 + apps/bordle/app.png | Bin 0 -> 1918 bytes apps/bordle/bordle.app.js | 159 ++++++++++++++++++++++++++++++++++++++ apps/bordle/metadata.json | 15 ++++ apps/bordle/wordlencr.txt | 1 + 6 files changed, 193 insertions(+) create mode 100644 apps/bordle/README.md create mode 100644 apps/bordle/app-icon.js create mode 100644 apps/bordle/app.png create mode 100644 apps/bordle/bordle.app.js create mode 100644 apps/bordle/metadata.json create mode 100644 apps/bordle/wordlencr.txt diff --git a/apps/bordle/README.md b/apps/bordle/README.md new file mode 100644 index 000000000..f3f628cc0 --- /dev/null +++ b/apps/bordle/README.md @@ -0,0 +1,17 @@ +# Bordle + +The Bangle version of a popular word guessing game. The goal is to guess a 5 letter word in 6 tries or less. After each guess, the letters in the guess are +marked in colors: yellow for a letter that appears in the to-be-guessed word, but in a different location and green for a letter in the correct position. + +Only words contained in the internal dictionary are allowed as valid guesses. On startup, a target word is picked from the dictionary at random. + +On startup, a grid of 6 lines with 5 (empty) letter boxes is displayed. Swiping left or right at any time switches between grid view and keyboard view. +The keyboad was inspired by the 'Scribble' app (it is a simplified version using the layout library). The letter group "Z ..." contains the delete key ("") and +the enter key (""). Hitting enter after the 5th letter will add the guess to the grid view and color mark it. + +The (English language) dictionary was derived from the the Unix ispell word list by filtering out plurals and past particples (and some hand editing) from all 5 letter words. +It is contained in the file 'wordlencr.txt' which contains one long string (no newline characters) of all the words concatenated. It would not be too difficult to swap it +out for a different language version. The keyboard currently only supports the 26 characters of the latin alphabet (no accents or umlauts). + + + diff --git a/apps/bordle/app-icon.js b/apps/bordle/app-icon.js new file mode 100644 index 000000000..64ccbc8a5 --- /dev/null +++ b/apps/bordle/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AA/TADwoIFkYyOF0owIF04wGUSqvVBZQtZGJYJIFzomKF0onIF07EKF0owLF9wNEnwACE6oZILxovbMBov/F/4v/C54uWF/4vKBQQLLF/4YPFwYMLF7AZGF5Y5KF5xJIFwoMJD44vaBhwvcLQpgHF8gGRF6xYNBpQvTXBoNOF65QJBIgvjBywvUV5YOOF64OIB54v/cQwAKB5ov/F84wKADYuIF+AwkFIwwnE45hmExCSlEpTEiERr3KADw+PF0ownUSoseA==")) diff --git a/apps/bordle/app.png b/apps/bordle/app.png new file mode 100644 index 0000000000000000000000000000000000000000..633a83e4e29fc2bbfd16cc98f942a5f183497817 GIT binary patch literal 1918 zcmV-^2Z8vBP)$Q!`j0b)%ld}t6Y1u=_?z*1mA0Q2jjtj#1L zkQz33BJ_OBH*bOC3dhP5iSD~=|2R(QX*EM0x0YTS#=~dZVRo%T)CWbcDYS<3qRj{H* zqD${=7df4nZNgqqZHi2cRvtw7hKD*%II=QKIN1*3NxpK~sc+6cO@D~Qrh%u&N80d6 zqMSrxi&5n90!QUcbm>IL+|ZmE(dFaM0DtjNZ8W47DJRq_9qH`y9i@o08v~R$v zA0KV|4XN2FgWJYM9z}lX4jfW;iP|1f+Y^eI@6G~u08B`BXZi_SzEfZza?B-}XWTaB ziRn{rnTqyipOrPGAnOT{Y-|;J-Rfy8-ENsXfty~7RLJtSqj~=);Wz^tGY{6v+iqob z^~o{dBd5%rfalo06))=}S3pbZ&p!L zk!o_SuW8>?2%hJMy8dko^%nPL`x4U^lvm(4aQ?xr_kqlD&X{;vgP(0ftYb5 z9oX8?vtyH=y-dw(ba1(L{(-K41?3gIhyle>2iEu&vZ(ATkO|-OC1LU=h4X%I%F{Qf zA%Hj%P_dqM&=~7@1mU5KS^5L;g~nLNBVIl#+URHo9zIa)8*t7i5b>L*q zhuxkYDvl{McmYF^37Guly#eja^S}S>_7;>c<${|ZBl5#6Ipnd%*t4y9K~pj6bA1F~ z15$kyfvJk=cgd}U3mSW_=A9*y#ysa}p6PAw`g32?-Zz0WS*g{$U1me<=4x`kMkLaG z1V&K_4BU4p4*WgS7L!~48+vwrUSM;kt*S40JtI81=IoBTECEsHP<%JtM_?3{K#Gi` zkS&h=i`|`xC(wJLdH?S+x(hA)PXgz%rbfS=i|3dOir7MAP;>&~I2$0Tt#x{L`c;Sg zNA9UmL|)81EAq7m&h1>0R%8oUbPf{m+ERo=0fp93{{Fd%%{OdFIs(d{wQF-CmSB@p!ekqy$B-0jjYeUbD29TPp zQOH~rGxD!}-W9ZQ+Gr&5ImuXCe zF-HOtAQ_iKz)h!2t(`G}k&z8mxb6@NY9Jm7t)D5-g{Dtk1g0FKmt)Ocg~P%J{SWV( zRMa`#ruv!}Uz*7;V(bRD%#gZJ%R*GXJR<|?v}m$b#Wbs!=DQM!=L7K0!~8_@2N{1f z*@|@98J!Bb-IlS@w)b2&Gpbfws%lQfiX}Ch7#~^Rg6Lc1-`WfsfdQATV9Wv4reHJD z96H`0@??*q_j(zVI+*_!kz>%A4u1BRE^a=d0 zSqDPp@s`DlPhZO#OpLVEsqhA{C_rETR=85)i|%FQHiaLDYuMz&l{J6(8@MtY8+&}U z*yM4P&y|AMEMQQS&Cb6Xd%3h$Tv*|1&E-HIMOaK4?07*qoM6N<$ Ef~=yiR{#J2 literal 0 HcmV?d00001 diff --git a/apps/bordle/bordle.app.js b/apps/bordle/bordle.app.js new file mode 100644 index 000000000..b1d771877 --- /dev/null +++ b/apps/bordle/bordle.app.js @@ -0,0 +1,159 @@ +var Layout = require("Layout"); + +var gameState = 0; +var keyState = 0; +var keyStateIdx = 0; + +function buttonPushed(b) { + if (keyState==0) { + keyState++; + keyStateIdx = b; + if (b<6) { + for (i=1; i<=5; ++i) { + var c = String.fromCharCode(i+64+(b-1)*5); + layout["bt"+i.toString()].label = c; + layout["bt"+i.toString()].bgCol = wordle.keyColors[c]||g.theme.bg; + } + layout.bt6.label = "<"; + } + else { + layout.bt1.label = "Z"; + layout.bt1.bgCol = wordle.keyColors.Z||g.theme.bg; + layout.bt2.label = ""; + layout.bt4.label = ""; + layout.bt3.label = layout.bt5.label = " "; + layout.bt6.label = "<"; + } + } + else { // actual button pushed + inp = layout.input.label; + if (b!=6) { + if ((keyStateIdx<=5 || b<=1) && inp.length<5) inp += String.fromCharCode(b+(keyStateIdx-1)*5+64); + else if (layout.input.label.length>0 && b==2) inp = inp.slice(0,-1); + layout.input.label = inp; + } + layout = getKeyLayout(inp); + keyState = 0; + if (inp.length==5 && keyStateIdx==6 && b==4) { + rc = wordle.addGuess(inp); + layout.input.label = ""; + layout.update(); + gameState = 0; + if (rc>0) return; + g.clear(); + wordle.render(); + return; + } + } + layout.update(); + g.clear(); + layout.render(); +} + +function getKeyLayout(text) { + return new Layout( { + type: "v", c: [ + {type:"txt", font:"6x8:2", id:"input", label:text, pad: 3}, + {type: "h", c: [ + {type:"btn", font:"6x8:2", id:"bt1", label:"ABCDE", cb: l=>buttonPushed(1), pad:4, filly:1, fillx:1 }, + {type:"btn", font:"6x8:2", id:"bt2", label:"FGHIJ", cb: l=>buttonPushed(2), pad:4, filly:1, fillx:1 }, + ]}, + {type: "h", c: [ + {type:"btn", font:"6x8:2", id:"bt3", label:"KLMNO", cb: l=>buttonPushed(3), pad:4, filly:1, fillx:1 }, + {type:"btn", font:"6x8:2", id:"bt4", label:"PQRST", cb: l=>buttonPushed(4), pad:4, filly:1, fillx:1 }, + ]}, + {type: "h", c: [ + {type:"btn", font:"6x8:2", id:"bt5", label:"UVWXY", cb: l=>buttonPushed(5), pad:4, filly:1, fillx:1 }, + {type:"btn", font:"6x8:2", id:"bt6", label:"Z ...", cb: l=>buttonPushed(6), pad:4, filly:1, fillx:1 }, + ]} + ]}); +} + +class Wordle { + constructor(word) { + this.word = word; + this.guesses = []; + this.guessColors = []; + this.keyColors = []; + this.nGuesses = -1; + if (word == "rnd") { + this.words = require("Storage").read("wordlencr.txt"); + i = Math.floor(Math.floor(this.words.length/5)*Math.random())*5; + this.word = this.words.slice(i, i+5).toUpperCase(); + } + console.log(this.word); + } + render(clear) { + h = g.getHeight(); + bh = Math.floor(h/6); + bbh = Math.floor(0.85*bh); + w = g.getWidth(); + bw = Math.floor(w/5); + bbw = Math.floor(0.85*bw); + if (clear) g.clear(); + g.setFont("Vector", Math.floor(bbh*0.95)).setFontAlign(0,0); + g.setColor(g.theme.fg); + for (i=0; i<6; ++i) { + for (j=0; j<5; ++j) { + if (i<=this.nGuesses) { + g.setColor(this.guessColors[i][j]).fillRect(j*bw+(bw-bbw)/2, i*bh+(bh-bbh)/2, (j+1)*bw-(bw-bbw)/2, (i+1)*bh-(bh-bbh)/2); + g.setColor(g.theme.fg).drawString(this.guesses[i][j], 2+j*bw+bw/2, 2+i*bh+bh/2); + } + g.setColor(g.theme.fg).drawRect(j*bw+(bw-bbw)/2, i*bh+(bh-bbh)/2, (j+1)*bw-(bw-bbw)/2, (i+1)*bh-(bh-bbh)/2); + } + } + } + addGuess(w) { + if ((this.words.indexOf(w.toLowerCase())%5)!=0) { + E.showAlert(w+"\nis not a word", "Invalid word").then(function() { + layout = getKeyLayout(""); + wordle.render(true); + }); + return 3; + } + this.guesses.push(w); + this.nGuesses++; + this.guessColors.push([]); + correct = 0; + var sol = this.word; + for (i=0; i