From 604f6f6c476c3bf2cc963a75bfdff1bf9c2b1cb1 Mon Sep 17 00:00:00 2001 From: phil Date: Mon, 27 Dec 2021 14:33:53 -0500 Subject: [PATCH 1/5] Add time and life app --- apps.json | 17 +++ apps/timeandlife/ChangeLog | 1 + apps/timeandlife/README.md | 7 + apps/timeandlife/app-icon.js | 1 + apps/timeandlife/app.js | 278 +++++++++++++++++++++++++++++++++++ apps/timeandlife/app.png | Bin 0 -> 605 bytes 6 files changed, 304 insertions(+) create mode 100644 apps/timeandlife/ChangeLog create mode 100644 apps/timeandlife/README.md create mode 100644 apps/timeandlife/app-icon.js create mode 100644 apps/timeandlife/app.js create mode 100644 apps/timeandlife/app.png diff --git a/apps.json b/apps.json index e5e9f8f02..02ee3d469 100644 --- a/apps.json +++ b/apps.json @@ -5062,5 +5062,22 @@ {"name":"ltherm.app.js","url":"app.js"}, {"name":"ltherm.img","url":"icon.js","evaluate":true} ] + }, + { + "id": "timeandlife", + "name": "Time and Life", + "shortName":"Time and Lfie", + "icon": "app.png", + "version":"0.0.1", + "description": "A simple watchface which displays the time when the screen is tapped and decay according to the rules of Conway's game of life.", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS2"], + "allow_emulator":true, + "readme": "README.md", + "storage": [ + {"name":"timeandlife.app.js","url":"app.js"}, + {"name":"timeandlife.img","url":"app-icon.js","evaluate":true} + ] } ] diff --git a/apps/timeandlife/ChangeLog b/apps/timeandlife/ChangeLog new file mode 100644 index 000000000..115067b80 --- /dev/null +++ b/apps/timeandlife/ChangeLog @@ -0,0 +1 @@ +0.01: New app diff --git a/apps/timeandlife/README.md b/apps/timeandlife/README.md new file mode 100644 index 000000000..af92d8cb8 --- /dev/null +++ b/apps/timeandlife/README.md @@ -0,0 +1,7 @@ +# Time and Life + +A simple watchface which displays the time when the screen is tapped and decay according to the rules of [Conway's game of life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life). + +![](screenshot1.png) +![](screenshot2.png) +![](screenshot3.png) diff --git a/apps/timeandlife/app-icon.js b/apps/timeandlife/app-icon.js new file mode 100644 index 000000000..d7608fca4 --- /dev/null +++ b/apps/timeandlife/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkB/4AGCY4PHC/4X/C/4X/C/4XvJ/4X/C/4X/C/4X3AH4A/AH4A/AH4A/")) diff --git a/apps/timeandlife/app.js b/apps/timeandlife/app.js new file mode 100644 index 000000000..905ec3031 --- /dev/null +++ b/apps/timeandlife/app.js @@ -0,0 +1,278 @@ +// Globals +const X = 176, + Y = 176; // screen resolution of bangle 2 +const STEP_TIMEOUT = 1000; +const PAUSE_TIME = 3000; + +// Each of my pixels is an 8x8 square. +const ON = { + width: 8, + height: 8, + bpp: 1, + transparent: 0, + buffer: new Uint8Array([ + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + ]).buffer, + state: 1, +}; +const OFF = { + width: 8, + height: 8, + bpp: 1, + transparent: 1, + buffer: new Uint8Array([ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ]).buffer, + state: 0, +}; + +const ONE = [ + [0, 1, 0], + [1, 1, 0], + [0, 1, 0], + [0, 1, 0], + [0, 1, 0], + [0, 1, 0], + [1, 1, 1], +]; +const TWO = [ + [0, 1, 0], + [1, 0, 1], + [0, 0, 1], + [0, 1, 0], + [1, 0, 0], + [1, 0, 0], + [1, 1, 1], +]; +const THREE = [ + [0, 1, 0], + [1, 0, 1], + [0, 0, 1], + [0, 1, 0], + [0, 0, 1], + [1, 0, 1], + [0, 1, 0], +]; +const FOUR = [ + [0, 0, 1], + [1, 0, 1], + [1, 0, 1], + [1, 1, 1], + [0, 0, 1], + [0, 0, 1], + [0, 0, 1], +]; +const FIVE = [ + [1, 1, 1], + [1, 0, 0], + [1, 0, 0], + [0, 1, 0], + [0, 0, 1], + [1, 0, 1], + [0, 1, 0], +]; +const SIX = [ + [0, 1, 0], + [1, 0, 1], + [1, 0, 0], + [1, 1, 0], + [1, 0, 1], + [1, 0, 1], + [0, 1, 0], +]; +const SEVEN = [ + [1, 1, 1], + [1, 0, 1], + [0, 0, 1], + [0, 1, 0], + [0, 1, 0], + [0, 1, 0], + [0, 1, 0], +]; +const EIGHT = [ + [0, 1, 0], + [1, 0, 1], + [1, 0, 1], + [0, 1, 0], + [1, 0, 1], + [1, 0, 1], + [0, 1, 0], +]; +const NINE = [ + [0, 1, 0], + [1, 0, 1], + [1, 0, 1], + [0, 1, 1], + [0, 0, 1], + [1, 0, 1], + [0, 1, 0], +]; +const ZERO = [ + [0, 1, 0], + [1, 0, 1], + [1, 0, 1], + [1, 0, 1], + [1, 0, 1], + [1, 0, 1], + [0, 1, 0], +]; +const NUMBERS = [ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE]; + +// Arraybuffers to store game state +// 484 8 bit integers that are either 1 or 0 form the 22 x 22 grid +let emptySeed = []; +for (i = 0; i < 484; i++) { + emptySeed.push(0); +} +let data = E.toUint8Array(emptySeed); +let nextData = E.toUint8Array(emptySeed); +const dataAddr = E.getAddressOf(data, true); +const nextDataAddr = E.getAddressOf(nextData, true); + +let lastPaused = new Date(); + +const forAllElements = fn => { + let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]; + numbers.forEach(i => { + numbers.forEach(j => { + fn(i, j); + }); + }); +}; + +// Conway's game of life +// if < 2 neighbours, set off +// if 2 or 3 neighbours, set on +// if > 3 neighbours, set off +const updateStateC = E.compiledC(` +// void run(int, int) +void run(char* n, char* m){ + // n is a pointer to the first byte in data, m is for nextdata + int count = 0; + for (int i=0;i<484;i++) { + // Add 8 neighbours, wrapping around + count = + *(n+(i+484-23)%484) + + *(n+(i+484-22)%484) + + *(n+(i+484-21)%484) + + *(n+(i+484-1)%484) + + *(n+(i+484+1)%484) + + *(n+(i+484+21)%484) + + *(n+(i+484+22)%484) + + *(n+(i+484+23)%484); + if (count < 2 || count > 3) { + *(m+i) = 0; + } else { + *(m+i) = 1; + } + } +} +`); +const copyStateC = E.compiledC(` +// void run(int, int) +void run(char* n, char* m){ + // n is a pointer to the first byte in data, m is for nextdata + for (int i=0;i<484;i++) { + *(n+i) = *(m+i); + } +} +`); + +const step = () => { + if (new Date() - lastPaused < PAUSE_TIME) { + return; + } + let startTime = new Date(); + updateStateC.run(dataAddr, nextDataAddr); + nextData.forEach((e, i) => { + if (e && !data[i]) { + g.drawImage(ON, Math.floor(i / 22) * 8, i % 22 * 8); + } else if (data[i]) { + g.drawImage(OFF, Math.floor(i / 22) * 8, i % 22 * 8); + } + }); + copyStateC.run(dataAddr, nextDataAddr); +}; + +const drawPixel = (i, j, value) => { + g.drawImage(value, j * 8, i * 8); + data[j * 22 + i] = value.state; + nextData[j * 22 + i] = value.state; +}; + +const drawNum = (character, i, j) => { + const startJ = j; + character.forEach(row => { + j = startJ; + row.forEach(pixel => { + if (pixel) { + drawPixel(i, j, ON); + } + j++; + }); + i++; + }); +}; + +const drawDots = () => { + drawPixel(10, 10, ON); + drawPixel(12, 10, ON); +}; + +const drawTime = () => { + lastPaused = new Date(); + g.clear(); + data.forEach((el, i) => { + data[i] = 0; + }); + const d = new Date(); + const hourTens = Math.floor(d.getHours() / 10); + const hourOnes = d.getHours() % 10; + const minuteTens = Math.floor(d.getMinutes() / 10); + const minuteOnes = d.getMinutes() % 10; + drawNum(NUMBERS[hourTens], 8, 1); + drawNum(NUMBERS[hourOnes], 8, 6); + drawDots(); + drawNum(NUMBERS[minuteTens], 8, 13); + drawNum(NUMBERS[minuteOnes], 8, 18); +}; + +const start = () => { + Bangle.setUI("clock"); // Show launcher when middle button pressed + g.clear(); + Bangle.setLCDTimeout(20); // backlight/lock timeout in seconds + let stepInterval = setInterval(step, STEP_TIMEOUT); + + // Handlers + Bangle.on('touch', drawTime); + + // Sleep mode + Bangle.on('lock', isLocked => { + if (stepInterval) { + clearInterval(stepInterval); + } + stepInterval = undefined; + if (!isLocked) { + drawTime(); + stepInterval = setInterval(step, STEP_TIMEOUT); + } + }); + + drawTime(); +}; + +start(); diff --git a/apps/timeandlife/app.png b/apps/timeandlife/app.png new file mode 100644 index 0000000000000000000000000000000000000000..b1e837d258215458c7427ee87669e9bbac4a6cff GIT binary patch literal 605 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1SD@Hc}*5j~)%+dI0Z`UZ9TaH&0ol7?IxJKYaYEcX0Eb^M5Usybh)`_$$my-IXYqFW{daW%a!F zk%YE4*GJ2bGaSWL>YnU+^GW*oq{DUdB#k%Ctb8P~G2m6w&hE&Y0iDY`9(Sz@+-LuM z)1k`l%~5MNf3y9`eV8>jb>?f6_KAm-rYSfz^jK-FIONn6)+-_`dCR}*2fOTk551W& zq6S4e3)n;_J!b#keE;sOqbE7dHRrH2>2LdM$kbBS7$1N0nDxpV8r5TsRNT2Pd=c+H@LRGrSgzw9Q*Cx${@dC)b_|iP zv}&1UWSADKo{IZkQJ!C(|9@WQ_wUTwQbk=Q7Cfhb(ZX5a5n0T@pr;JNj1^1m%YcIH zC7!;n>`!^5g?X8JOXb~wLXst}5hc#~xw)x%B@E6*sfi`2DGKG8B^e6tp1uL$jeO!j zMed$1jv*0;-(EY&$)Lc);&}dFb)V@ScbByLLhPSB)6z^;SKizH`FoX)0vIf~@0j_1 o>aXTcb(@SJA_|_9RAS#UOgP19!;<*A7ic7dr>mdKI;Vst02rI_VgLXD literal 0 HcmV?d00001 From fb14142593aff4a48411251d593cf26a386a60da Mon Sep 17 00:00:00 2001 From: phil Date: Mon, 27 Dec 2021 14:38:57 -0500 Subject: [PATCH 2/5] fix screenshot --- apps/timeandlife/README.md | 4 +--- apps/timeandlife/screenshot.png | Bin 0 -> 811 bytes 2 files changed, 1 insertion(+), 3 deletions(-) create mode 100644 apps/timeandlife/screenshot.png diff --git a/apps/timeandlife/README.md b/apps/timeandlife/README.md index af92d8cb8..b03cbf2fb 100644 --- a/apps/timeandlife/README.md +++ b/apps/timeandlife/README.md @@ -2,6 +2,4 @@ A simple watchface which displays the time when the screen is tapped and decay according to the rules of [Conway's game of life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life). -![](screenshot1.png) -![](screenshot2.png) -![](screenshot3.png) +![](screenshot.png) diff --git a/apps/timeandlife/screenshot.png b/apps/timeandlife/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..5ffda5bf052b411fab011024b6e8cf9a6b4aedb0 GIT binary patch literal 811 zcmeAS@N?(olHy`uVBq!ia0vp^`+;~L2OE$~*>-O+kYXuz@(kesf*OvL4j^B$#5JNM zI6tkVJh3R1Aw4fYH&wSdxhOR?uQ(&WkRs=z)Wnj^{5*w_%-mE4Um(NC zT)`zZS;5G_$WXz+$jaEl%D_?~z*qO>a-g+L9iA?ZAr*7p-gV46Y#`upan+Z9(?1=& zBE6;C@x+t;+j&*Iew;~4dh^xh{J*9JTfd9hd*0v9&#=8?zRt(Vs&$)=_)q(BQpi5? zk-GPvl+M8`Sm(FzXVmNS*T3IWx34?%^L*XED_{PoVYvHR#`*fHe(Tce^R>6W{J#6I zcG>gUMn5q;=vMvjcJ;08)_dLSfBzTBx1WC!BN$4*?6b}P{_XcEpS%0w{@ZUqpZ*CW zylTJ9tKX$Q?;n3bb^qUQzrWo{!>Z>0w%g}-{{3S6cM2A3zFO}2cExzz_4$UF&b+ox jzxpH==MTb2t79xWAF@BqJ@q&+Av1Wo`njxgN@xNAJLr-e literal 0 HcmV?d00001 From 27be246c82c14f31943567875392469b548cbb2d Mon Sep 17 00:00:00 2001 From: phil Date: Mon, 27 Dec 2021 14:43:37 -0500 Subject: [PATCH 3/5] fix screenshot and description --- apps.json | 2 +- apps/timeandlife/README.md | 2 +- apps/timeandlife/screenshot.png | Bin 811 -> 1634 bytes 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 02ee3d469..62e78b8da 100644 --- a/apps.json +++ b/apps.json @@ -5069,7 +5069,7 @@ "shortName":"Time and Lfie", "icon": "app.png", "version":"0.0.1", - "description": "A simple watchface which displays the time when the screen is tapped and decay according to the rules of Conway's game of life.", + "description": "A simple watchface which displays the time when the screen is tapped and decays according to the rules of Conway's game of life.", "type": "clock", "tags": "clock", "supports": ["BANGLEJS2"], diff --git a/apps/timeandlife/README.md b/apps/timeandlife/README.md index b03cbf2fb..4a638c952 100644 --- a/apps/timeandlife/README.md +++ b/apps/timeandlife/README.md @@ -1,5 +1,5 @@ # Time and Life -A simple watchface which displays the time when the screen is tapped and decay according to the rules of [Conway's game of life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life). +A simple watchface which displays the time when the screen is tapped and decays according to the rules of [Conway's game of life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life). ![](screenshot.png) diff --git a/apps/timeandlife/screenshot.png b/apps/timeandlife/screenshot.png index 5ffda5bf052b411fab011024b6e8cf9a6b4aedb0..3058c9346bbcb23f5348729b81179b6d6b80f37a 100644 GIT binary patch literal 1634 zcmeHIZA@Bc6utsQvBj^}W}*_hR!C)GC#$-1|oh&)E>oL(CuCH=%fOR`#=Rksa|_HeHk9@bbzPZ ze?c(;KS|^x#fxruwmzncRwO-;Pi*%aVP>N^>K0v8ZTW+Js@i*`@P<0;(kb&;PzY=F zTHJw6Q{}*2qH13eHsIHx)_?;II@%Kg9mZ$IF2CU`k3$Z5!8X;DjYckQL6nQe%idiFjU{bm(i(t*KC~zu+1)Tf2 z%XoRakyjPm#s4I8>5RXWc1On@73BAZVGqxLu^S<}&uDP=!laTfO?aHFL}y~#{W?sC zHsqL%{*e&-jX`R4eDt(~EFNS1G;j6OZ6);C3}{->aD!TpiHG!4YE_1-d3pi(Ah*1o))?Yv+!?^jBo{$GA>%jwMfJYA zoX)s@n1tssu=oYouVV^2n9wR@b2_%pU`HfP6Vy7Q^4fz;PX1tk_Txm;GD9F429sWS z93tc`gO2G{;YFp5Qdi<=$YRpBfkW9WZlI@+Sz~k7O17Y{<$%%-#xhWZ+wi+=J1jTC zdnv&poFHE!LIrZBcvbi5sbFtYg$vnVVnMJmVS+$*V){-{V zZ2A1rJ?$#6zH8eH~hTgZsal^9Z5qyfHj{ z#TlB|PpmHvst(?plyxH=S0arH(X)GXxhbixLk;+~(s5!lkQkGDQZ0ZIP^UD-!-t%AJ2YtW;C(BEA(jq N#RVlCRUZGde*iBqFmwO_ literal 811 zcmeAS@N?(olHy`uVBq!ia0vp^`+;~L2OE$~*>-O+kYXuz@(kesf*OvL4j^B$#5JNM zI6tkVJh3R1Aw4fYH&wSdxhOR?uQ(&WkRs=z)Wnj^{5*w_%-mE4Um(NC zT)`zZS;5G_$WXz+$jaEl%D_?~z*qO>a-g+L9iA?ZAr*7p-gV46Y#`upan+Z9(?1=& zBE6;C@x+t;+j&*Iew;~4dh^xh{J*9JTfd9hd*0v9&#=8?zRt(Vs&$)=_)q(BQpi5? zk-GPvl+M8`Sm(FzXVmNS*T3IWx34?%^L*XED_{PoVYvHR#`*fHe(Tce^R>6W{J#6I zcG>gUMn5q;=vMvjcJ;08)_dLSfBzTBx1WC!BN$4*?6b}P{_XcEpS%0w{@ZUqpZ*CW zylTJ9tKX$Q?;n3bb^qUQzrWo{!>Z>0w%g}-{{3S6cM2A3zFO}2cExzz_4$UF&b+ox jzxpH==MTb2t79xWAF@BqJ@q&+Av1Wo`njxgN@xNAJLr-e From b9cda9b829e29a7075d49eaf56e3d8110ae19f9f Mon Sep 17 00:00:00 2001 From: phil Date: Mon, 27 Dec 2021 14:55:22 -0500 Subject: [PATCH 4/5] version number --- apps.json | 2 +- apps/timeandlife/ChangeLog | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 62e78b8da..15d3005c6 100644 --- a/apps.json +++ b/apps.json @@ -5068,7 +5068,7 @@ "name": "Time and Life", "shortName":"Time and Lfie", "icon": "app.png", - "version":"0.0.1", + "version":"0.1", "description": "A simple watchface which displays the time when the screen is tapped and decays according to the rules of Conway's game of life.", "type": "clock", "tags": "clock", diff --git a/apps/timeandlife/ChangeLog b/apps/timeandlife/ChangeLog index 115067b80..c7b309a74 100644 --- a/apps/timeandlife/ChangeLog +++ b/apps/timeandlife/ChangeLog @@ -1 +1 @@ -0.01: New app +0.1: New app From 77d785bb68d3fdc1380110d58a8e6dec9ff0831c Mon Sep 17 00:00:00 2001 From: phil Date: Wed, 29 Dec 2021 22:31:58 -0500 Subject: [PATCH 5/5] remove unused code --- apps/timeandlife/app.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/timeandlife/app.js b/apps/timeandlife/app.js index 905ec3031..7532f9bc8 100644 --- a/apps/timeandlife/app.js +++ b/apps/timeandlife/app.js @@ -145,15 +145,6 @@ const nextDataAddr = E.getAddressOf(nextData, true); let lastPaused = new Date(); -const forAllElements = fn => { - let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]; - numbers.forEach(i => { - numbers.forEach(j => { - fn(i, j); - }); - }); -}; - // Conway's game of life // if < 2 neighbours, set off // if 2 or 3 neighbours, set on