From 2cb4dbcd1e377affa1ee6ee3f5535d64d108a33a Mon Sep 17 00:00:00 2001 From: Samuel Vilz Date: Tue, 19 Jan 2021 21:16:16 +0100 Subject: [PATCH 1/4] Added a Game of Life Clock --- apps.json | 13 ++ apps/lifeclk/ChangeLog | 5 + apps/lifeclk/app-icon.js | 1 + apps/lifeclk/app.js | 473 +++++++++++++++++++++++++++++++++++++++ apps/lifeclk/app.png | Bin 0 -> 1566 bytes 5 files changed, 492 insertions(+) create mode 100644 apps/lifeclk/ChangeLog create mode 100644 apps/lifeclk/app-icon.js create mode 100644 apps/lifeclk/app.js create mode 100644 apps/lifeclk/app.png diff --git a/apps.json b/apps.json index 50a628676..931cfc2e5 100644 --- a/apps.json +++ b/apps.json @@ -2591,5 +2591,18 @@ {"name":"astral.app.js","url":"app.js"}, {"name":"astral.img","url":"app-icon.js","evaluate":true} ] +}, +{ "id": "lifeclk", + "name": "Game of Life Clock", + "shortName":"Conway's Clock", + "icon": "app.png", + "version":"0.05", + "description": "Modification and clockification of Conway's Game of Life", + "tags": "clock", + "type" : "clock", + "storage": [ + {"name":"lifeclk.app.js","url":"app.js"}, + {"name":"lifeclk.img","url":"app-icon.js","evaluate":true} + ] } ] diff --git a/apps/lifeclk/ChangeLog b/apps/lifeclk/ChangeLog new file mode 100644 index 000000000..dfd8b8775 --- /dev/null +++ b/apps/lifeclk/ChangeLog @@ -0,0 +1,5 @@ +0.01: New App! 2021-01-07 +0.02: Faster algorithm, hours and minutes are now displayable whenever, using the upper button 2021-01-14 +0.03: Ah yes. Some people prefer the 12 hour system 2021-01-14 +0.04: Fixed a bug, doesn't run while display's on now 2021-01-18 +0.05: Fixed a bug, doesn't count the time it was asleep when calculating the update time 2021-01-19 \ No newline at end of file diff --git a/apps/lifeclk/app-icon.js b/apps/lifeclk/app-icon.js new file mode 100644 index 000000000..8127abd79 --- /dev/null +++ b/apps/lifeclk/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AFkLC6+wC6u73YuVC7JIUCwIZBLywwTIwYwTC4QwUC4OwGCgXCCoQwRXwYwTO4wwQO4wwQO44wPO44wPO5G7olACY9EAAVLO44LCCosECwYXDGAm0BQIvFCwoABCwIcCCoQuHCwwXEAAguFBQgFBoEEC451GIwQVDAgIXBIhQwECoYEBYAS5NCogEBC6BGFVAQXPGAoXRGAoXSO6owGC6Z3VGAoXUd4gWRGAYXVIwQXUIwReSC7gWUgELFyoXBCyoA/ACwA==")) \ No newline at end of file diff --git a/apps/lifeclk/app.js b/apps/lifeclk/app.js new file mode 100644 index 000000000..ec30b6973 --- /dev/null +++ b/apps/lifeclk/app.js @@ -0,0 +1,473 @@ +Bangle.setLCDTimeout(30); + +const is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; + +const squaresize = 5; +const padding = 2; +const bigSquareSize = squaresize+padding; +const noOfSquX = 27; +const noOfSquY = 23; +const screenWidth = noOfSquX * bigSquareSize - padding; +const screenHeight = noOfSquY * bigSquareSize - padding; +const ulCornerX = parseInt((220-screenWidth)/2); +const ulCornerY = parseInt(40 + (160-screenHeight)/2); +const textWidth = 27; +const textHeight = 7; +const sectextWidth = 9; +const textWidthScreen = textWidth*bigSquareSize; +const textHeightScreen = textHeight*bigSquareSize; +const textWidthScreenMin = (textWidth-sectextWidth)*bigSquareSize; +const textWidthScreenSec = sectextWidth*bigSquareSize; +const ulCornerTextX = parseInt((noOfSquX-textWidth)/2); +const ulCornerTextY = parseInt((noOfSquY-textHeight)/2); +const ulCornerTextXScreen = ulCornerX+parseInt((noOfSquX-textWidth) + *bigSquareSize/2); +const ulCornerTextYScreen = ulCornerY+parseInt((noOfSquY-textHeight) + *bigSquareSize/2); +const seculCornerTextX = ulCornerTextX+textWidth-sectextWidth; + +let buf = Graphics.createArrayBuffer(screenWidth,screenHeight,1,{msb:true}); +let textbufMin = Graphics.createArrayBuffer((textWidth-sectextWidth)*bigSquareSize, + textHeight*bigSquareSize, + 1,{msb:true}); +let textPreBufMin = Graphics.createArrayBuffer(textWidth-sectextWidth, + textHeight, + 8,{msb:true}); +let textbufSec = Graphics.createArrayBuffer(sectextWidth*bigSquareSize, + textHeight*bigSquareSize, + 1,{msb:true}); +let textPreBufSec = Graphics.createArrayBuffer(sectextWidth, + textHeight, + 8,{msb:true}); + +let genNow = new Uint8Array((noOfSquX+2)*(noOfSquY+2)); +let genFut = new Uint8Array((noOfSquX+2)*(noOfSquY+2)); +let generation=0; +const minuteGens = 10; +let genEnd = minuteGens; +let lastupdatetime=null; + +function fillLinesFirstFewGens(){ + let fade = (genEnd-generation)/minuteGens; + g.setColor(fade,fade,fade); + // vertical lines + g.fillRect(ulCornerTextXScreen, + ulCornerTextYScreen, + ulCornerTextXScreen, + ulCornerTextYScreen+textHeightScreen-padding); + // horizontal lines + g.fillRect(ulCornerTextXScreen, + ulCornerTextYScreen, + ulCornerTextXScreen+textWidthScreenMin, + ulCornerTextYScreen); + g.fillRect(ulCornerTextXScreen, + ulCornerTextYScreen+textHeightScreen-padding, + ulCornerTextXScreen+textWidthScreenMin, + ulCornerTextYScreen+textHeightScreen-padding); + g.setColor(1,1,1); +} + +function clearLinesFirstFewGens(){ + // vertical lines + g.clearRect(ulCornerTextXScreen, + ulCornerTextYScreen, + ulCornerTextXScreen, + ulCornerTextYScreen+textHeightScreen-padding); + // horizontal lines + g.clearRect(ulCornerTextXScreen, + ulCornerTextYScreen, + ulCornerTextXScreen+textWidthScreenMin, + ulCornerTextYScreen); + g.clearRect(ulCornerTextXScreen, + ulCornerTextYScreen+textHeightScreen-padding, + ulCornerTextXScreen+textWidthScreenMin, + ulCornerTextYScreen+textHeightScreen-padding); +} + +function fillLinesLaterGens(){ + g.setColor(1,1,1); + // horizontal lines + g.fillRect(ulCornerTextXScreen+textWidthScreenMin, + ulCornerTextYScreen, + ulCornerTextXScreen+textWidthScreenMin+textWidthScreenSec, + ulCornerTextYScreen); + g.fillRect(ulCornerTextXScreen+textWidthScreenMin, + ulCornerTextYScreen+textHeightScreen-padding, + ulCornerTextXScreen+textWidthScreenMin+textWidthScreenSec, + ulCornerTextYScreen+textHeightScreen-padding); + // vertical lines + g.fillRect(ulCornerTextXScreen+textWidthScreenMin, + ulCornerTextYScreen, + ulCornerTextXScreen+textWidthScreenMin, + ulCornerTextYScreen+textHeightScreen-padding); + g.fillRect(ulCornerTextXScreen+textWidthScreenMin+textWidthScreenSec, + ulCornerTextYScreen, + ulCornerTextXScreen+textWidthScreenMin+textWidthScreenSec, + ulCornerTextYScreen+textHeightScreen-padding); +} + +function renderSecText(){ + g.clearRect(ulCornerTextXScreen+18*bigSquareSize+padding, + ulCornerTextYScreen, + ulCornerTextXScreen+textWidthScreen, + ulCornerTextYScreen+textHeightScreen-1); + fillLinesLaterGens(); + g.drawImage({width:textWidthScreenSec, + height:textHeightScreen, + bpp:1,transparent:0,buffer:textbufSec.buffer}, + ulCornerTextXScreen+textWidthScreenMin,ulCornerTextYScreen); +} + +function flip(dontclear) { + g.setColor(1,1,1); + g.drawImage({width:screenWidth,height:screenHeight,bpp:1,buffer:buf.buffer}, + ulCornerX,ulCornerY); + if(generation=seculCornerTextX && x=ulCornerTextY && y=ulCornerTextX && x=ulCornerTextY && y4 && genNow[ind]<8){ + genFut[ind]+=1; + addNeighbors(ind); + let Xr=bigSquareSize*(x-1); + let Yr=bigSquareSize*(y-1); + buf.fillRect(Xr,Yr, Xr+squaresize,Yr+squaresize); + } + } + if(y == noOfSquY){ + if(generation == genEnd-1){writeMinuteText();} + flip(); + let tmp = genFut; genFut = genNow; genNow = tmp; // reference swapping + genFut.fill(0); + howlong(); + currentY = 1; + } + else{ + currentY++; + } + if(runOn){setTimeout(nextLineComp, 50);} +} + +function stopdraw() { + runOn = false; +} + +function startdraw(init) { + if (init===undefined) init=false; + Bangle.drawWidgets(); + g.reset(); + g.setColor(1,1,1); + g.setFont("6x8",1); + g.setFontAlign(0,0,3); + g.drawString("RESET",230,200); + g.drawString("LAUNCH",230,130); + g.drawString("CLOCK",230,60); + if(!init){ + updateSecondText(); + // stopdraw(); + runOn = true; + nextLineComp(); + } +} + +function regen(){ + g.setColor(1,1,1); + generation = 0; + genEnd = minuteGens; + currentY=1; + g.setFont("6x8",2); + g.setFontAlign(-1,-1,0); + g.clearRect(20,220,220,240); + g.drawString('Gen:'+generation+' 0ms ',20,220,true); + lastupdatetime=Date.now(); + updateSecondText(); + genNow.fill(0); + genFut.fill(0); + initDraw(); + // stopdraw(); + runOn = true; + nextLineComp(); +} + +function showMinAgain(){ + if(genEnd != generation+minuteGens){ + genEnd = generation+minuteGens; + lastDate = null; + } +} + +function setButtons(){ + setWatch(showMinAgain, BTN1, {repeat:true,edge:"falling"}); + setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); + setWatch(regen, BTN3, {repeat:true,edge:"falling"}); +} + +let wentToSleepAt; + +var SCREENACCESS = { + withApp:true, + request:function(){ + this.withApp=false; + stopdraw(); + wentToSleepAt = Date.now(); + }, + release:function(){ + this.withApp=true; + sleeptime = Date.now()-wentToSleepAt; + startdraw(); + } +}; + +Bangle.on('lcdPower',function(on) { + if (!SCREENACCESS.withApp) return; + if (on) { + startdraw(); + sleeptime = Date.now()-wentToSleepAt; + } else { + stopdraw(); + wentToSleepAt = Date.now(); + } +}); + +g.clear(); +Bangle.loadWidgets(); +setButtons(); +regen(); +startdraw(true); diff --git a/apps/lifeclk/app.png b/apps/lifeclk/app.png new file mode 100644 index 0000000000000000000000000000000000000000..a88157f5cb1a32cb5caa0011832a6dd15491769e GIT binary patch literal 1566 zcmV+(2I2XMP)n}Yi2PQS{n=DzP1yP+Y=uFLq%-S44+QLd;~3}0#K~R9!m`n_9r*aV-l$^# zNbN_OD9Sg(VcKaKfhA)dzY%0bb*!iYm&RoAQ%YZGc3Vb3kb7$ki9Q76Rdic6J^ZwW z6uvDXP)XKnrUgPSG4$6zh_W8Y13R+mZO?>3q9p{Z=q)t@C6P;Ib|r>WM}S`eW5AAF zDzj_8;nWfW0xN@Kt%Oc4_2sk46REd>TY#~uY(6Afl>^rWo=2QY=v3oBd7}RpY=xyKW~ZN2yDWAsEh5n>0!IUbxG|ou*8CD7Cva=$ zWZ@slg!^9oNmO$>K_;92^3Q`m*nIu|#HOv^D*-`*1n^w5pR)N}jaiG3L)g$vVi(n1 zB`$|WrGFr?>5;~^n#2o<-W!ZM>l|dIqCZsV5?BOSU;^-fv%srYN28s~y=ZTpiZ^w# zw4R82rMT{EC<&CoWYXP|%bL|HyadF7o$nM24@Z#4Cak%O+K>Fi#?$-mtNA!HIlYtZ zk)=z%y$4~3RemIZqK%j@s{HK$w&i@o@_^=o>PcVK_dM^ZFDA!-e{C$jR$TWrnA(YC z(%mwWGq)SHPv(5{V^wo}LZze5owBO_yWYnO?!e$Bcdb*$J_%eq6Ujz!MObxF8&Xj} zW-T8T3)N{K7+EAvuFZ9fLi?C8p09d2;9fxGh()&ao__9)`ib*)KtTqUZhlCyeO!p3 z${7{D71b*c1Qm;@t?DzX$TV1c6r~5jLDVa_(bes)-=mZEAfg^HR`McuME%lDs63FjCerRqg|7p| z#bsR0Yz|jZ0uBIu8&B{1V5WuV5paY-tK1E=1;mBC8@=hA!z_-Q(y?)(J?%07=Bg~} zm;ae}V?A*@d2rm?SC$1@ie+x(@8i}Kf$KrLK$1YTGCcu&3VbZ+VZWpUn?|2M+YHl& zA@ahK-k(^kr!X3EoSqVTm1FE7WM)~np-9<(rX&onlGBF0|S?AUWM=` zLPV6&HYu;j+sI|J$$r+>K8ny?vGne;q5f526KJXuZ#=v29h9G=lvU^~XyjGKw zrRu?xwhdh$JoETx_PrsS&OCl9z4e~|wI2&u!2bjO3ry|)!9vCF Qf&c&j07*qoM6N<$g6$U&9smFU literal 0 HcmV?d00001 From 5374abebd9fbdff5678b18e368021fc12b64d91e Mon Sep 17 00:00:00 2001 From: Samuel Vilz Date: Tue, 19 Jan 2021 21:24:12 +0100 Subject: [PATCH 2/4] Fixed initial update time --- apps/lifeclk/app.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/lifeclk/app.js b/apps/lifeclk/app.js index ec30b6973..d0288ad2f 100644 --- a/apps/lifeclk/app.js +++ b/apps/lifeclk/app.js @@ -403,6 +403,7 @@ function startdraw(init) { updateSecondText(); // stopdraw(); runOn = true; + sleeptime = 0; nextLineComp(); } } @@ -423,6 +424,7 @@ function regen(){ initDraw(); // stopdraw(); runOn = true; + sleeptime = 0; nextLineComp(); } From 79ef57147489b8f8692d08f80d6cfca910afccd3 Mon Sep 17 00:00:00 2001 From: Samuel Vilz <56087559+SamuelVilz@users.noreply.github.com> Date: Tue, 19 Jan 2021 21:35:48 +0100 Subject: [PATCH 3/4] Added README.md for lifeclk --- apps/lifeclk/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 apps/lifeclk/README.md diff --git a/apps/lifeclk/README.md b/apps/lifeclk/README.md new file mode 100644 index 000000000..e799cf72c --- /dev/null +++ b/apps/lifeclk/README.md @@ -0,0 +1,12 @@ +# Game of Life Clock + +Modification of the "Game of Life" ("life") app that also displays the current time, including seconds. + +## Usage + +Upon launch, the clock loads a randomly generated 27x23 grid of "cells", with a block in the middle showing the time. +Hours and minute are only displayed for 10 generations after launch, reset or after pressing the top button. After 10 generations, the cells that showed the hours and minutes become part of the game of life. + +* Top button: Immediately displays hours and minutes, killing any cells underneath the time block. +* Middle button: Shows the launcher. The state of the game is not saved. +* Lower button: Resets the cells, randomly generates new ones. From 1e41e6ead0352ebf7a5273e1146c99874b4a911c Mon Sep 17 00:00:00 2001 From: Samuel Vilz <56087559+SamuelVilz@users.noreply.github.com> Date: Tue, 19 Jan 2021 21:40:46 +0100 Subject: [PATCH 4/4] Added lifeclk's readme in apps.json --- apps.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps.json b/apps.json index 931cfc2e5..f5c751ccc 100644 --- a/apps.json +++ b/apps.json @@ -2600,6 +2600,7 @@ "description": "Modification and clockification of Conway's Game of Life", "tags": "clock", "type" : "clock", + "readme": "README.md", "storage": [ {"name":"lifeclk.app.js","url":"app.js"}, {"name":"lifeclk.img","url":"app-icon.js","evaluate":true}