From a5ccaa1c34481750c56003de3f294e31b27acae7 Mon Sep 17 00:00:00 2001 From: frederic wagner Date: Fri, 28 Jul 2023 07:46:26 +0200 Subject: [PATCH 1/4] sokoban: initial release --- apps/sokoban/ChangeLog | 1 + apps/sokoban/Microban.txt | 1822 ++++++++++++++++++++++++++++++++++++ apps/sokoban/README.md | 20 + apps/sokoban/TODO | 2 + apps/sokoban/app-icon.js | 1 + apps/sokoban/app.js | 464 +++++++++ apps/sokoban/metadata.json | 21 + apps/sokoban/soko.png | Bin 0 -> 3664 bytes apps/sokoban/sokoban.png | Bin 0 -> 863 bytes 9 files changed, 2331 insertions(+) create mode 100644 apps/sokoban/ChangeLog create mode 100644 apps/sokoban/Microban.txt create mode 100644 apps/sokoban/README.md create mode 100644 apps/sokoban/TODO create mode 100644 apps/sokoban/app-icon.js create mode 100644 apps/sokoban/app.js create mode 100644 apps/sokoban/metadata.json create mode 100644 apps/sokoban/soko.png create mode 100644 apps/sokoban/sokoban.png diff --git a/apps/sokoban/ChangeLog b/apps/sokoban/ChangeLog new file mode 100644 index 0000000000..9fa2c81720 --- /dev/null +++ b/apps/sokoban/ChangeLog @@ -0,0 +1 @@ +0.01: Initial code diff --git a/apps/sokoban/Microban.txt b/apps/sokoban/Microban.txt new file mode 100644 index 0000000000..96146080ce --- /dev/null +++ b/apps/sokoban/Microban.txt @@ -0,0 +1,1822 @@ +; 1 + +#### +# .# +# ### +#*@ # +# $ # +# ### +#### + +; 2 + +###### +# # +# #@ # +# $* # +# .* # +# # +###### + +; 3 + + #### +### #### +# $ # +# # #$ # +# . .#@ # +######### + +; 4 + +######## +# # +# .**$@# +# # +##### # + #### + +; 5 + + ####### + # # + # .$. # +## $@$ # +# .$. # +# # +######## + +; 6 + +###### ##### +# ### # +# $$ #@# +# $ #... # +# ######## +##### + +; 7 + +####### +# # +# .$. # +# $.$ # +# .$. # +# $.$ # +# @ # +####### + +; 8 + + ###### + # ..@# + # $$ # + ## ### + # # + # # +#### # +# ## +# # # +# # # +### # + ##### + +; 9 + +##### +#. ## +#@$$ # +## # + ## # + ##.# + ### + +; 10 + + ##### + #. # + #.# # +#######.# # +# @ $ $ $ # +# # # # ### +# # +######### + +; 11 + + ###### + # # + # ##@## +### # $ # +# ..# $ # +# # +# ###### +#### + +; 12 + +##### +# ## +# $ # +## $ #### + ###@. # + # .# # + # # + ####### + +; 13 + +#### +#. ## +#.@ # +#. $# +##$ ### + # $ # + # # + # ### + #### + +; 14 + +####### +# # +# # # # +#. $*@# +# ### +##### + +; 15 + + ### +######@## +# .* # +# # # +#####$# # + # # + ##### + +; 16 + + #### + # #### + # ## +## ## # +#. .# @$## +# # $$ # +# .# # +########## + +; 17 + +##### +# @ # +#...# +#$$$## +# # +# # +###### + +; 18 + +####### +# # +#. . # +# ## ## +# $ # +###$ # + #@ # + # # + #### + +; 19 + +######## +# .. # +# @$$ # +##### ## + # # + # # + # # + #### + +; 20 + +####### +# ### +# @$$..# +#### ## # + # # + # #### + # # + #### + +; 21 + +#### +# #### +# . . # +# $$#@# +## # + ###### + +; 22 + +##### +# ### +#. . # +# # # +## # # + #@$$ # + # # + # ### + #### + +; 23 + +####### +# * # +# # +## # ## + #$@.# + # # + ##### + +; 24 + +# ##### + # # +###$$@# +# ### +# # +# . . # +####### + +; 25 + + #### + # ### + # $$ # +##... # +# @$ # +# ### +##### + +; 26 + + ##### + # @ # + # # +###$ # +# ...# +# $$ # +### # + #### + +; 27 + +###### +# .# +# ## ## +# $$@# +# # # +#. ### +##### + +; 28 + +##### +# # +# @ # +# $$### +##. . # + # # + ###### + +; 29 + + ##### + # ## + # # + ###### # +## #. # +# $ $ @ ## +# ######.# +# # +########## + +; 30 + +#### +# ### +# $$ # +#... # +# @$ # +# ## +##### + +; 31 + + #### + ## # +##@$.## +# $$ # +# . . # +### # + ##### + +; 32 + + #### +## ### +# # +#.**$@# +# ### +## # + #### + +; 33 + +####### +#. # # +# $ # +#. $#@# +# $ # +#. # # +####### + +; 34 + + #### +### #### +# # +#@$***. # +# # +######### + +; 35 + + #### + ## # + #. $# + #.$ # + #.$ # + #.$ # + #. $## + # @# + ## # + ##### + +; 36 + +#### +# ############ +# $ $ $ $ $ @ # +# ..... # +############### + +; 37 + + ### +##### #.# +# ###.# +# $ #.# +# $ $ # +#####@# # + # # + ##### + +; 38 + +########## +# # +# ##.### # +# # $$ . # +# . @$## # +##### # + ###### + +; 39 + +##### +# #### +# # # .# +# $ ### +### #$. # +# #@ # +# # ###### +# # +##### + +; 40 + + ##### + # # +## ## +# $$$ # +# .+. # +####### + +; 41 + +####### +# # +#@$$$ ## +# #...# +## ## + ###### + +; 42 + + #### + # # + #@ # +####$.# +# $.# +# # $.# +# ## +###### + +; 43 + + #### + # @# + # # +###### .# +# $ .# +# $$# .# +# #### +### # + #### + +; 44 'Duh!' + +##### +#@$.# +##### + +; 45 + +###### +#... # +# $ # +# #$## +# $ # +# @ # +###### + +; 46 + + ###### +## # +# ## # +# # $ # +# * .# +## #@## + # # + ##### + +; 47 + + ####### +### # +# $ $ # +# ### ##### +# @ . . # +# ### # +##### ##### + +; 48 + +###### +# @ # +# # ## +# .# ## +# .$$$ # +# .# # +#### # + ##### + +; 49 + +###### +# @ # +# $# # +# $ # +# $ ## +### #### + # # # + #... # + # # + ####### + +; 50 + + #### +### ##### +# $ @..# +# $ # # +### #### # + # # + ######## + +; 51 + +#### +# ### +# ### +# $*@ # +### .# # + # # + ###### + +; 52 + + #### +### @# +# $ # +# *.# +# *.# +# $ # +### # + #### + +; 53 + + ##### +##. .## +# * * # +# # # +# $ $ # +## @ ## + ##### + +; 54 + + ###### + # # + ##### . # +### ###. # +# $ $ . ## +# @$$ # . # +## ##### + ###### + +; 55 + +######## +# @ # # +# # +#####$ # + # ### + ## #$ ..# + ## # ### + #### + +; 56 + +##### +# ### +# $ # +##* . # + # @# + ###### + +; 57 + + #### + # # + #@ # + # # +### #### +# * # +# $ # +#####. # + #### + +; 58 + +#### +# #### +#.*$ # +# .$# # +## @ # + # ## + ##### + +; 59 + +############ +# # +# ####### @## +# # # +# # $ # # +# $$ ##### # +### # # ...# + #### # # + ###### + +; 60 + + ######### + # # +##@##### # +# # # # +# # $.# +# ##$##.# +##$## #.# +# $ #.# +# # ### +######## + +; 61 + +######## +# # +# #### # +# #...@# +# ###$### +# # # +# $$ $ # +#### ## + #.### + ### + +; 62 + + ########## +#### ## # +# $$$....$@# +# ### # +# #### #### +##### + +; 63 + +##### #### +# ##### .# +# $ ######## +### #### .$ @ # + # # # #### # + #### #### ##### + +; 64 + + ###### +## # +# $ # +# $$ # +### .##### + ##.# @ # + #. $ # + #. #### + #### + +; 65 + + ###### + # # + # $ # + ####$ # +## $ $ # +#....# ## +# @ # +## # # + ######## + +; 66 + + ### + #@# + ###$### +## . ## +# # # # +# # # # +# # # # +# # # # +# # # # +## $ $ ## + ##. .## + # # + # # + ##### + +; 67 + +##### +# ## +# # # +#@$*.## +## . # + # $# # + ## # + ##### + +; 68 + + #### + # ###### +## $ # +# .# $ # +# .#$##### +# .@ # +###### + +; 69 + +#### #### +# #### # +# # # # +# # $## +# . .#$ # +#@ ## # $ # +# . # # +########### + +; 70 + +##### +# @ #### +# # +# $ $$ # +##$## # +# #### +# .. # +##.. # + ### # + #### + +; 71 + +########### +# # ### +# $@$ # . .# +# ## ### ## # +# # # # +# # # # # +# ######### # +# # +############# + +; 72 + + #### + ## ##### + # $ @ # + # $# # +#### ##### +# # # +# $ # +# ..# # +# .#### +# ## +#### + +; 73 + +#### +# ##### +# $$ $ # +# # +## ## ## +#...#@# +# ### ## +# # +# # # +######## + +; 74 + + #### + # ####### + #$ @# .# +## #$$ .# +# $ ##..# +# # ##### +### # + ##### + +; 75 + + ####### +## ....## +# ###### +# $ $ @# +### $ $ # + ### # + ###### + +; 76 + + ##### +## # +# ##### +# #.# # +#@ #.# $ # +# #.# ## +# # # +## ##$$# + ## # + # #### + #### + +; 77 + +########## +# @ .... # +# ####$## +## # $ $ # + # $ # + # ###### + ##### + +; 78 + + ####### +## ## +# $ $ # +# $ $ $ # +## ### #### + #@ .....# + ## ### + ####### + +; 79 + + ######### + # # # +## $#$# # +# .$.@ # +# .# # +########## + +; 80 + +#### +# ####### +# . ## .# +# $# .# +## ## # .# + # # # + #### # # + # @$ ### + # $$ # + # # + ###### + +; 81 + + ##### + # # + # . # +## * # +# *## +# @## +## $ # + # # + ##### + +; 82 + +##### +# ### +# . ## +##*#$ # +# .# $ # +# @## ## +# # +####### + +; 83 + +###### +# ## +# $ $ ## +## $$ # + # # # + # ## ## + # . .# + # @. .# + # #### + #### + +; 84 + +######## +# ... # +# ### ## +# # $ # +## #@$ # + # # $ # + # ### ##### + # # + # ### # + ##### ##### + +; 85 + + #### + ####### # + # $ # + # $ $ # + # ######## +## # . # +# # # # +# @ . ## +## # # # + # . # + ####### + +; 86 + + #### + ### ## + ## $ # +## $ # # +# @#$$ # +# .. ### +# ..### +##### + +; 87 + + #### +###### # +# # +# ... .# +##$###### +# $ # +# $### +## $ # + ## @ # + ###### + +; 88 + + #### + # ### # + # # # + # # # # + # #$ #.# + # # # # # + # #$ #.# # + # # # # +####$ #.# # +# @ # # +# # ## # +######## + +; 89 + +########## +# ## # +# $ $@# # +#### # $ # + #.# ## + # #.# $# + # #. # + # #. # + ###### + +; 90 + + ######## + # @ # + # $ $ # +### ## ### +# $..$ # +# .. # +########## + +; 91 + +########### +# .## # +# $$@..$$ # +# ##. # +########### + +; 92 + + #### + # # ##### + # # # # + # ######.# # +#### $ . # +# $$# ###.# # +# # # # # +######### #@ ## + # # + #### + +; 93 + + ######### +## # ## +# # # +# $ # $ # +# *.* # +####.@.#### +# *.* # +# $ # $ # +# # # +## # ## + ######### + +; 94 + +######### +# @ # # +# $ $ # +##$### ## +# ... # +# # # +###### # + #### + +; 95 + +######## +#@ # +# .$$. # +# $..$ # +# $..$ # +# .$$. # +# # +######## + +; 96 + + ###### + # # + # # +##### # +# #.##### +# $@$ # +#####.# # + ## ## ## + # $.# + # ### + ##### + +; 97 + + #### + # ######## +#### $ $.....# +# $ ###### +#@### ### +# $ # +# $ # # +## # # + # # + ###### + +; 98 + +##### +# ## #### +# $ ### .# +# $ $ .# +## $#####.# #### +# $ # # .### # +# # # .# @ # +### # # # + #### ## ## + ####### + +; 99 + + ##### + # # +####### ####### # # +# # # # # +# @ #### # #### +# # ....## #### # +# ##### ## $$ $ $ # +###### # # + # ########## + #### + +; 100 + +####### +# @# # +#.$ # +#. # $## +#.$# # +#. # $ # +# # # +######## + +; 101 'Lockdown' + + ##### + # # + # # ####### + # * # # + ## ## # # + # #* # +### # # # ### +# *#$+ # +# # ## ## +# # * # +####### # # + # # + ##### + +; 102 + +########### +#....# # +# # $$ # +# @ ## # +# ##$ # +###### $ # + # # + ###### + +; 103 + + ##### + # . ## +### $ # +# . $#@# +# #$ . # +# $ ### +## . # + ##### + +; 104 + + ##### +##### # +# $ # +# $#$#@# +### # # + # ... # + ### ## + # # + #### + +; 105 + + #### #### +## ### ## +# # # # +# *. .* # +###$ $### + # @ # +###$ $### +# *. .* # +# # # # +## ### ## + #### #### + +; 106 + + ######## + # # + #@ $ # +## ###$ # +# .....### +# $ $ $ # +###### # # + # # + ##### + +; 107 + +######## +# # +# $*** # +# * * # +# * * # +# ***. # +# @# +######## + +; 108 + +#### ##### +# ### # ## +# # #$ $ # +#..# ##### # # +# @ # $ $ # +#..# ## +## ######### + ##### + +; 109 + + ####### +# # # +# # # # # + # @ $ # +### ### # +# ### # +# $ ##.# +## $ #.# + ## $ .# +# ## $#.# +## ## #.# +### # # +### ##### + +; 110 + + #### + # # + # $#### +###. . # +# $ # $ # +# . .### +####$ # + # @# + #### + +; 111 + +###### +# #### +# ...# +# ...# +###### # + # # # + # $$ ## + # @$ # + # $$ # + ## $# # + # # + ###### + +; 112 + + ##### +## #### +# $$$ # +# # $ # +# $## ## +### #. # + # # # + ##### ### + # # ## + # @....# + # # + # # # + ######## + +; 113 + + ##### + ## # +### # # +# . # +# ## ##### +# . . # ## +# # @ $ ### +#####. # $ # + #### $ # + ## $ ## + # ## + # # + #### + +; 114 + +###### +# ### +# # $ # +# $ @ # +## ## ##### +# #......# +# $ $ $ $ # +## ###### + ##### + +; 115 + + ##### +##### #### +# # # +# #..... # +## ## # ### + #$$@$$$ # + # ### + ####### + +; 116 + + ##### + ### # +####.....# +# @$$$$$ # +# # ## +##### # + ##### + +; 117 + + #### #### + # ### ## + # @ # +##..### # +# # # +#...#$ # # +# ## $$ $ # +# $ ### +#### ### + #### + +; 118 + + ##### +## ## +# $ ## +# $ $ ## +###$# . ## + # # . # + ## ##. # + # @ . ## + # # # + ######## + +; 119 + + ###### + # ## + ## ## # + # $$ # # + # @$ # # + # # # +#### # # +# ... ## +# ## +####### + +; 120 + + #### +####### # +# $ ## +# $##### # +# @# # # +## ##.. # +# # ..#### +# $ ### +# $### +# # +#### + +; 121 + + ###### + # . # +##$.# # +# * # +# ..### +##$ # ##### +## ## # # +# #### # # +# @ $ $ # +## # # + ########## + +; 122 + +##### +# ### +# #$ # +# $ # +# $ $ # +# $# # +# @### +## ######## +# ...# +# # +########..# + #### + +; 123 + +######## +# # +# $ $$ ######## +##### @##. . # + #$ # . # + # #. . ## + #$# ## # # + # # + # ### ## + # # #### + #### + +; 124 + +############## +# # # +# $@$$ # . ..# +## ## ### ## # + # # # # + # # # # # + # ######### # + # # + ############# + +; 125 + + ##### + # ## + # $ # +######## #@## +# . # $ $ # +# $# # +#...##### # +##### ##### + +; 126 + + ########### +##....... # +# $$$$$$$@ # +# # # # ## +# # # # +# ####### +##### + +; 127 + +## #### +#### #### + # $ $. # +## # .$ # +# ##.### +# $ . # +# @ # # +# ###### +#### + +; 128 + + ######### +### # # +# * $ . . # +# $ ## ## +####*# # + # @ ### + # ### + ##### + +; 129 + + ######### +### @ # # +# * $ *.. # +# $ # # +####*# ### + # ## + # ### + ##### + +; 130 + +##### ##### +# ####.. # +# $$$ # +# $# .. # +### @# ## # + # ## # + ########## + +; 131 + +##### +# # +# . # +#.@.### +##.# # +# $ # +# $ # +##$$ # + # ### + # # + #### + +; 132 + +#### +# @### +#.* ##### +#..#$$ $ # +## # + # # ## # + # ##### + ##### + +; 133 + + ####### + # . .### + # . . . # +### #### # +# @$ $ # +# $$ $ # +#### ### + ##### + +; 134 + + #### +######### # +# ## $ # +# $ ## # +### #. .# ## + # #. .#$## + # # # # + # @ $ # + # ####### + #### + +; 135 + +####### +# ##### +# $$#@##..# +# # # +# $ # # # +#### $ ..# + ######## + +; 136 + + ####### + # # +## ###$## +#.$ @ # +# .. #$ # +#.## $ # +# #### +###### + +; 137 + + #### + ## ### +#### # $ # +# #### $ $ # +# ..# #$ # +# # @ ### +## #..# ### + # ## # # + # # + ######## + +; 138 + + #### +### # +# ### +# # . .# +# @ ...#### +# # # # ## +# # $$ # +##### $ $ # + ##$ # ## + # # + ###### + +; 139 + + #### +## #### +# ...# +# ...# +# # ## +# #@ #### #### +##### $ ### # + # ##$ $ # + ### $$ # + # $ ## ### + # ###### + ###### + +; 140 + +######## ##### +# # ### # +# ## $ # +#.# @ ## $ ## +#.# # $ ## +#.# $ ## +#. ## ##### +## # + ###### + +; 141 + + ######## + # # . # + # .*.# + # # * # +####$##.## +# $ # +# $ ## $ # +# @# # +########## + +; 142 + + #### + # # + # #### +###$.$ # +# .@. # +# $.$### +#### # + # # + #### + +; 143 + +#### +# #### +# $ # +# .# # +# $# ## +# . # +#### # + # # + ### ### + # $ # +## #$# ## +# $ @ $ # +# ..#.. # +### ### + ##### + +; 144 + + #### + ### ##### + # $$ # # + # $ . .$$## + # .. #. $ # +### #** . # +# . **# ### +# $ .# .. # +##$$.@. $ # + # # $$ # + ##### ### + #### + +; 145 + + ##### + # @ # + ## ## +###.$$$.### +# $...$ # +# $.#.$ # +# $...$ # +###.$$$.### + ## ## + # # + ##### + +; 146 + + ####### +## . ## +# .$$$. # +# $. .$ # +#.$ @ $.# +# $. .$ # +# .$$$. # +## . ## + ####### + +; 147 + + ##### +######## # +#. . @#.# +# ### # +## $ # # + # $ ##### + # $# # + ## # # + # ## + ##### + +; 148 'from (Original 18)' + +########### +# . # # +# #. @ # +# #..# ####### +## ## $$ $ $ # + ## # + ############# + +; 149 'from (Boxxle 43)' + + #### +## ### +#@$ # +### $ # + # ###### + # $....# + # # #### + ## # # + # $# # + # # + # ### + #### + +; 150 'from (Original 47)' + + #### + ##### # + # $####### +## ## ..# ...# +# $ $$#$ @ # +# ### # +####### # #### + #### + +; 151 'from (Original 47)' + + #### + # # + ### # +## $ # +# # # +# #$$ ###### +# # # .# +# $ @ .# +### ####..# + #### #### + +; 152 + +###### #### +# # # +#.## #$## # +# # # # +#$ # ### # # +# # # # # +# # #### # # # +#. @ $ * . # +############### + +; 153 + +############# +#.# @# # # +#.#$$ # $ # +#.# # $# # +#.# $# # $## +#.# # $# # +#.# $# # $# +#.. # $ # +#.. # # # +############ + +; 154 'Take the long way home.' + + ############################ + # # + # ######################## # + # # # # + # # #################### # # + # # # # # # + # # # ################ # # # + # # # # # # # # + # # # # ############ # # # # + # # # # # # # # # + # # # # # ############ # # # + # # # # # # # # + # # # # ################ # # + # # # # # # +##$# # #################### # +#. @ # # +############################# + +; 155 'The Dungeon' + + ###### #### +#####*# ################# ## +# ### # +# ######## #### ## # +### #### # #### #### ## +#*# # .# # # # # # # +#*# # # # ## # ## ## # +### ### ### # ## # ## ## + # # #*# # # # # + # # ### ##### #### # # + ##### ##### ####### ###### + # # # #**# # +## # # #**# ####### ## # +# ######### # ##### ### +# # # $ #*# +# ######### ### @##### #*# +##### #### #### ###### diff --git a/apps/sokoban/README.md b/apps/sokoban/README.md new file mode 100644 index 0000000000..36097d66f4 --- /dev/null +++ b/apps/sokoban/README.md @@ -0,0 +1,20 @@ +# Sokoban + +Classic Sokoban game. + +Tap screen at bottom/top/left/right to push boxes into their destinations. +Swipe to undo. + +![Screenshot](soko.png) + +You play the yellow disk (rice hat seen from above). +Each level has a set of crates (brown if incorrectly placed or blue if correctly placed) +and a set of placeholders (empty blue squares). Simply push all crates into their placeholders. +Remember you can push but never pull. + +## Creator + +Levels are the [Microban](http://www.abelmartin.com/rj/sokobanJS/Skinner/David%20W.%20Skinner%20-%20Sokoban.htm) levels +by David W. Skinner. + +frederic.wagner@imag.fr diff --git a/apps/sokoban/TODO b/apps/sokoban/TODO new file mode 100644 index 0000000000..dcad68d38f --- /dev/null +++ b/apps/sokoban/TODO @@ -0,0 +1,2 @@ +- background +- win screen + final win screen diff --git a/apps/sokoban/app-icon.js b/apps/sokoban/app-icon.js new file mode 100644 index 0000000000..e8a1d4b0fe --- /dev/null +++ b/apps/sokoban/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AH4A/ABMN7oXV7vd6AuVAAIXaAwYAEC75fGC6KPFC58BiMQJxAXLiIABDAcBigXRAAIFDC5pGBAAwvOCQYbDiBfOLwgYBO54qER6QXDexIXJRggXRIxIXpb4wXMLwYvTdIinSC4gYFC5xiIC54YDC54SBIQZHRC4gcFC5hyEC4KPPLIrZGC5IWCLwgXPUApeGC5KfGC6DnGIwwXLB4gXQgI/FAwy/MAH4A/ABgA==")) diff --git a/apps/sokoban/app.js b/apps/sokoban/app.js new file mode 100644 index 0000000000..90b24ed114 --- /dev/null +++ b/apps/sokoban/app.js @@ -0,0 +1,464 @@ +// basic shapes +const SPACE = 0; +const WALL = 1; +const PLAYER = 2; +const BOX = 3; +const HOLE = 4; +const FILLED = 5; + +// basic directions +const LEFT = 0; +const UP = 1; +const DOWN = 2; +const RIGHT = 3; + +function go(line, column, direction) { + let destination_line = line; + let destination_column = column; + if (direction == LEFT) { + destination_column -= 1; + } else if (direction == RIGHT) { + destination_column += 1; + } else if (direction == UP) { + destination_line -= 1; + } else { + // direction is down + destination_line += 1; + } + return [destination_line, destination_column]; +} + +Bangle.setOptions({ + lockTimeout: 60000, + backlightTimeout: 60000, +}); + +let s = require("Storage"); + +// parse the levels a bit more to figure offsets delimiting next map. +function next_map_offsets(filename, start_offset) { + let raw_maps = s.readArrayBuffer(filename); + let offsets = []; + // this is a very dumb parser : map starts three chars after the end of a line with a ';' + // and ends two chars before next ';' + let comment_line = true; + for (let i = start_offset; i < raw_maps.length; i++) { + if (raw_maps[i] == 59) { // ';' + if (offsets.length != 0) { + offsets.push(i - 2); + return offsets; + } + comment_line = true; + } else if (raw_maps[i] == 10) { // '\n' + if (comment_line) { + comment_line = false; + offsets.push(i + 3); + } + } + } + return offsets; +} + +let config = s.readJSON("sokoban.json", true); +if (config === undefined) { + let initial_offsets = next_map_offsets("Microban.txt", 0); + config = { + levels_sets: ["Microban.txt"], // all known files containing levels + levels_set: 0, // which set are we using ? + current_maps: [0], // what is current map on each set ? + offsets: [initial_offsets], // known offsets for each levels set (binary positions of maps in each file) + }; + s.writeJSON("sokoban.json", config); +} + +let map = null; +let in_menu = false; +let history = null; // store history to allow undos + + +function load_map(filename, start_offset, end_offset, name) { + console.log("loading map in", filename, "between", start_offset, "and", end_offset); + let raw_map = new Uint8Array(s.readArrayBuffer(filename), start_offset, end_offset - start_offset); + let dimensions = map_dimensions(raw_map); + history = []; + return new Map(dimensions, raw_map, filename, name); +} + +function load_current_map() { + let current_set = config.levels_set; + let offsets = config.offsets[current_set]; + let set_filename = config.levels_sets[current_set]; + let set_name = set_filename.substring(0, set_filename.length - 4); // remove '.txt' + let current_map = config.current_maps[current_set]; + map = load_map(set_filename, offsets[2 * current_map], offsets[2 * current_map + 1], set_name + " " + (current_map + 1)); + map.display(); +} + +function next_map() { + let current_set = config.levels_set; + let current_map = config.current_maps[current_set]; + let offsets = config.offsets[current_set]; + if (2 * (current_map + 1) >= offsets.length) { + // we parse some new offsets + let new_offsets = next_map_offsets(config.levels_sets[current_set], offsets[offsets.length - 1] + 2); // +2 since we need to start at ';' (we did -2 from ';' in previous parser call) + if (new_offsets.length == 0) { + E.showAlert("You Win", "All levels completed").then(function() { + load(); + }); + } else { + config.offsets[current_set].push(new_offsets[0]); + config.offsets[current_set].push(new_offsets[1]); + } + } + config.current_maps[current_set]++; + s.writeJSON("sokoban.json", config); + load_current_map(); +} + +function previous_map() { + let current_set = config.levels_set; + let current_map = config.current_maps[current_set]; + if (current_map > 0) { + current_map--; + config.current_maps[current_set] = current_map; + s.writeJSON("sokoban.json", config); + load_current_map(); + } +} + +function map_dimensions(raw_map) { + let line_start = 0; + let width = 0; + let height = 0; + for (let i = 0; i < raw_map.length; i++) { + if (raw_map[i] == 10) { + height += 1; + let line_width = i - line_start; + if (i > 0 && raw_map[i - 1] == 13) { + line_width -= 1; // remove \r + } + width = Math.max(line_width, width); + line_start = i + 1; + } + } + return [width, height]; +} + +class Map { + constructor(dimensions, raw_map, filename, name) { + this.filename = filename; + this.name = name; + this.width = dimensions[0]; + this.height = dimensions[1]; + this.remaining_holes = 0; + // start by creating an empty map + this.m = []; + for (let i = 0; i < this.height; i++) { + let line = new Uint8Array(this.width); + for (let j = 0; j < this.width; j++) { + line[j] = SPACE; + } + this.m.push(line); + } + // now fill with raw_map's content + let current_line = 0; + let line_start = 0; + for (let i = 0; i < raw_map.length; i++) { + if (raw_map[i] == 32) { + this.m[current_line][i - line_start] = SPACE; + } else if (raw_map[i] == 43) { + // '+' + this.remaining_holes += 1; + this.m[current_line][i - line_start] = HOLE; + this.player_column = i - line_start; + this.player_line = current_line; + } else if (raw_map[i] == 10) { + current_line += 1; + line_start = i + 1; + } else if (raw_map[i] == 35) { + this.m[current_line][i - line_start] = WALL; + } else if (raw_map[i] == 36) { + this.m[current_line][i - line_start] = BOX; + } else if (raw_map[i] == 46) { + this.remaining_holes += 1; + this.m[current_line][i - line_start] = HOLE; + } else if (raw_map[i] == 64) { + this.m[current_line][i - line_start] = SPACE; + this.player_column = i - line_start; + this.player_line = current_line; + } else if (raw_map[i] == 42) { + this.m[current_line][i - line_start] = FILLED; + } else if (raw_map[i] != 13) { + console.log("warning unknown map content", raw_map[i]); + } + } + this.steps = 0; + this.calibrate(); + } + // compute scale + calibrate() { + let r = Bangle.appRect; + let rwidth = 1 + r.x2 - r.x; + let rheight = 1 + r.y2 - r.y; + let cell_width = Math.floor(rwidth / this.width); + let cell_height = Math.floor(rheight / this.height); + let cell_scale = Math.min(cell_width, cell_height); // we want square cells + let real_width = this.width * cell_scale; + let real_height = this.height * cell_scale; + let sx = r.x + Math.ceil((rwidth - real_width) / 2); + let sy = r.y + Math.ceil((rheight - real_height) / 2); + this.sx = sx; + this.sy = sy; + this.cell_scale = cell_scale; + } + undo(direction, pushing) { + this.steps -= 1; + + let previous_position = go(this.player_line, this.player_column, 3 - direction); + let previous_line = previous_position[0]; + let previous_column = previous_position[1]; + + if (pushing) { + // put the box back on current player position + let currently_on = this.m[this.player_line][this.player_column]; + if (currently_on == HOLE) { + this.remaining_holes -= 1; + this.m[this.player_line][this.player_column] = FILLED; + } else { + this.m[this.player_line][this.player_column] = BOX; + } + // now, remove the box from its current position + let current_box_position = go(this.player_line, this.player_column, direction); + let box_line = current_box_position[0]; + let box_column = current_box_position[1]; + let box_on = this.m[box_line][box_column]; + if (box_on == FILLED) { + this.remaining_holes += 1; + this.m[box_line][box_column] = HOLE; + } else { + this.m[box_line][box_column] = SPACE; + } + this.display_cell(box_line, box_column); + } + // cancel player display + this.display_cell(this.player_line, this.player_column); + // re-display player at previous position + this.player_line = previous_line; + this.player_column = previous_column; + this.display_player(); + } + move(direction) { + let destination_position = go(this.player_line, this.player_column, direction); + let destination_line = destination_position[0]; + let destination_column = destination_position[1]; + let destination = this.m[destination_line][destination_column]; + let pushing = false; + if (destination == BOX || destination == SPACE || destination == HOLE || destination == FILLED) { + if (destination == BOX || destination == FILLED) { + pushing = true; + let after_line = 2 * destination_line - this.player_line; + let after_column = 2 * destination_column - this.player_column; + let after = this.m[after_line][after_column]; + let will_remain = SPACE; + if (destination == FILLED) { + will_remain = HOLE; + } + if (after == SPACE) { + if (will_remain == HOLE) { + this.remaining_holes += 1; + } + this.m[destination_line][destination_column] = will_remain; + this.m[after_line][after_column] = BOX; + } else if (after == HOLE) { + this.m[destination_line][destination_column] = will_remain; + this.m[after_line][after_column] = FILLED; + if (will_remain == SPACE) { + this.remaining_holes -= 1; + } + if (this.remaining_holes == 0) { + in_menu = true; + this.steps += 1; + E.showAlert("" + this.steps + "steps", "You Win").then(function() { + in_menu = false; + next_map(); + }); + return; + } + } else { + return; + } + this.display_cell(after_line, after_column); + this.display_cell(destination_line, destination_column); + } + history.push([direction, pushing]); + this.display_cell(this.player_line, this.player_column); + this.steps += 1; + this.player_line = destination_line; + this.player_column = destination_column; + this.display_player(); + // this.display(); + } + } + display_player() { + sx = this.sx; + sy = this.sy; + cell_scale = this.cell_scale; + g.setColor(0.8, 0.8, 0).fillCircle(sx + (0.5 + this.player_column) * cell_scale, sy + (0.5 + this.player_line) * cell_scale, cell_scale / 2 - 1); // -1 because otherwise it overfills + } + display_cell(line, column) { + sx = this.sx; + sy = this.sy; + cell_scale = this.cell_scale; + let shape = this.m[line][column]; + if (shape == WALL) { + if (cell_scale < 10) { + g.setColor(1, 0, 0).fillRect(sx + column * cell_scale, sy + line * cell_scale, sx + (column + 1) * cell_scale, sy + (line + 1) * cell_scale); + } else { + g.setColor(0.5, 0.5, 0.5).fillRect(sx + column * cell_scale, sy + line * cell_scale, sx + (column + 1) * cell_scale, sy + (line + 1) * cell_scale); + g.setColor(1, 0, 0).fillRect(sx + column * cell_scale, sy + (line + 0.15) * cell_scale, sx + (column + 0.35) * cell_scale, sy + (line + 0.45) * cell_scale); + g.fillRect(sx + (column + 0.55) * cell_scale, sy + (line + 0.15) * cell_scale, sx + (column + 1) * cell_scale, sy + (line + 0.45) * cell_scale); + g.fillRect(sx + column * cell_scale, sy + (line + 0.65) * cell_scale, sx + (column + 0.65) * cell_scale, sy + (line + 0.95) * cell_scale); + g.fillRect(sx + (column + 0.85) * cell_scale, sy + (line + 0.65) * cell_scale, sx + (column + 1) * cell_scale, sy + (line + 0.95) * cell_scale); + } + } else if (shape == BOX) { + let border = Math.floor((cell_scale - 2) / 4); + if (border > 0) { + g.setColor(0.6, 0.4, 0.3).fillRect(sx + column * cell_scale + 1, sy + line * cell_scale + 1, sx + (column + 1) * cell_scale - 1, sy + (line + 1) * cell_scale - 1); + g.setColor(0.7, 0.5, 0.5).fillRect(sx + column * cell_scale + 1 + border, sy + line * cell_scale + 1 + border, sx + (column + 1) * cell_scale - 1 - border, sy + (line + 1) * cell_scale - 1 - border); + } else { + g.setColor(0.7, 0.5, 0.5).fillRect(sx + column * cell_scale + 1, sy + line * cell_scale + 1, sx + (column + 1) * cell_scale - 1, sy + (line + 1) * cell_scale - 1); + } + } else if (shape == HOLE) { + g.setColor(1, 1, 1).fillRect(sx + column * cell_scale, sy + line * cell_scale, sx + (column + 1) * cell_scale - 1, sy + (line + 1) * cell_scale - 1); + g.setColor(0, 0, 1).drawRect(sx + column * cell_scale, sy + line * cell_scale, sx + (column + 1) * cell_scale - 1, sy + (line + 1) * cell_scale - 1); + } else if (shape == FILLED) { + let border = Math.floor((cell_scale - 2) / 4); + if (border > 0) { + g.setColor(0.6, 0.4, 0.3).fillRect(sx + column * cell_scale + 1, sy + line * cell_scale + 1, sx + (column + 1) * cell_scale - 1, sy + (line + 1) * cell_scale - 1); + g.setColor(0, 0, 1).fillRect(sx + column * cell_scale + 1 + border, sy + line * cell_scale + 1 + border, sx + (column + 1) * cell_scale - 1 - border, sy + (line + 1) * cell_scale - 1 - border); + } else { + g.setColor(0, 0, 1).fillRect(sx + column * cell_scale + 1 + border, sy + line * cell_scale + 1 + border, sx + (column + 1) * cell_scale - 1 - border, sy + (line + 1) * cell_scale - 1 - border); + + } + } else if (shape == SPACE) { + g.setColor(1, 1, 1).fillRect(sx + column * cell_scale, sy + line * cell_scale, sx + (column + 1) * cell_scale - 1, sy + (line + 1) * cell_scale - 1); + } + + } + display() { + g.clear(); + for (let line = 0; line < this.height; line++) { + for (let column = 0; column < this.width; column++) { + this.display_cell(line, column); + } + } + this.display_player(); + g.setColor(0, 0, 0).setFont("6x8:2") + .setFontAlign(0, -1, 0) + .drawString(map.name, g.getWidth() / 2, 0); + } +} + + +Bangle.on('touch', function(button, xy) { + if (in_menu) { + return; + } + let half_width = g.getWidth() / 2; + let half_height = g.getHeight() / 2; + let directions_amplitudes = [0, 0, 0, 0]; + directions_amplitudes[LEFT] = half_width - xy.x; + directions_amplitudes[RIGHT] = xy.x - half_width; + directions_amplitudes[UP] = half_height - xy.y; + directions_amplitudes[DOWN] = xy.y - half_height; + + let max_direction; + let second_max_direction; + if (directions_amplitudes[0] > directions_amplitudes[1]) { + max_direction = 0; + second_max_direction = 1; + } else { + max_direction = 1; + second_max_direction = 0; + } + for (let direction = 2; direction < 4; direction++) { + if (directions_amplitudes[direction] > directions_amplitudes[max_direction]) { + second_max_direction = max_direction; + max_direction = direction; + } else if (directions_amplitudes[direction] >= directions_amplitudes[second_max_direction]) { + second_max_direction = direction; + } + } + if (directions_amplitudes[max_direction] - directions_amplitudes[second_max_direction] > 10) { + // if there is little possible confusions between two candidate moves let's move. + // basically we forbid diagonals of 10 pixels wide + map.move(max_direction); + } + +}); + +Bangle.on('swipe', function(directionLR, directionUD) { + if (in_menu) { + return; + } + let last_move = history.pop(); + if (last_move !== undefined) { + map.undo(last_move[0], last_move[1]); + } +}); + +setWatch( + function() { + if (in_menu) { + return; + } + in_menu = true; + const menu = { + "": { + title: "choose action" + }, + "restart": function() { + E.showMenu(); + load_current_map(); + in_menu = false; + }, + "current map": { + value: config.current_maps[config.levels_set] + 1, + min: 1, + max: config.offsets[config.levels_set].length / 2, + onchange: (v) => { + config.current_maps[config.levels_set] = v - 1; + load_current_map(); + s.writeJSON("sokoban.json", config); + } + }, + "next map": function() { + E.showMenu(); + next_map(); + in_menu = false; + }, + "previous map": function() { + E.showMenu(); + previous_map(); + in_menu = false; + }, + "back to game": function() { + E.showMenu(); + g.clear(); + map.display(); + in_menu = false; + }, + }; + E.showMenu(menu); + }, + BTN1, { + repeat: true + } +); + + +Bangle.setLocked(false); + +current_map = config.current_map; +offsets = config.offsets; +load_current_map(); \ No newline at end of file diff --git a/apps/sokoban/metadata.json b/apps/sokoban/metadata.json new file mode 100644 index 0000000000..191cea1e09 --- /dev/null +++ b/apps/sokoban/metadata.json @@ -0,0 +1,21 @@ +{ + "id": "sokoban", + "name": "Sokoban", + "shortName": "Sokoban", + "version": "0.01", + "description": "Classic Sokoban game (microban levels).", + "allow_emulator":false, + "icon": "sokoban.png", + "type": "app", + "tags": "game", + "screenshots": [{"url":"soko.png"}], + "supports": ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"sokoban.app.js","url":"app.js"}, + {"name":"Microban.txt", "url":"Microban.txt"}, + {"name":"sokoban.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"sokoban.json"} + ] +} diff --git a/apps/sokoban/soko.png b/apps/sokoban/soko.png new file mode 100644 index 0000000000000000000000000000000000000000..5bf0ae772d6f72cd3ddf6bd15fe812dbd9cb1f13 GIT binary patch literal 3664 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 CS<8?B literal 0 HcmV?d00001 diff --git a/apps/sokoban/sokoban.png b/apps/sokoban/sokoban.png new file mode 100644 index 0000000000000000000000000000000000000000..849b92d0114751cc03d97636e077d4e62c849373 GIT binary patch literal 863 zcmV-l1EBngP)-=LruQHqFqP{czKPwG_>nxyEVo|?W% zD^**9pobFjrXzwhd2d@4z4Xw6;>DukrAbAx6+GCg;0FpGL7&#cK z2I;xTBU^xMbTm{A(sPl#EkG`kcYZIb|LgGd1a$uZ)Q9Z>!gW;v@CPCr9o4guiMgk< z@ty;K>e>WILm+8NAWZ|(OGwh*Qof;k1&~NwSS}>L5|VZ60HiTM5}?!y>w7K9^XuX% zIxdj!2}zUJdlTLO2+3$?yk&eAk_e=>OGs`Ll7@w(Y4e<8r_+@Om~$QeQpD&P7hu0m zihtbj;sgNsR&m3qU!ZmZklqwCS|C3#<}|BJO~qqCNbNw;9hEc{S3O&dc}l58AUO<@ z2aVGL%3CEtl*db_Ux8X5)`1JXpH&u4Bg_-($JeG|xCM$PaAKpeYkEg5IBOf9QE+#w`=C~{@!_5}b)t<{oot`wY*Qp=!|V<72i;XJ!AO~s(l%FxyGGV=(;tAO9=FDq6`=7Hue9s50I9#V zwRdST1B`zq%$K^~4NXM>npLI-ke^umct#*6ofdDx^p4qi^D#0|it%Lw0OS!%uzq!u z1_9|}!Fwrfk0$^E`Mt^C$77OqyII^QRwh?_SgP@5189DIA literal 0 HcmV?d00001 From ebc95fda6920da806064eefea5ea0da782d261c8 Mon Sep 17 00:00:00 2001 From: frederic wagner Date: Thu, 17 Aug 2023 09:11:23 +0200 Subject: [PATCH 2/4] sokoban: renamed level file --- apps/sokoban/{Microban.txt => Microban.sok} | 0 apps/sokoban/app.js | 6 +++--- apps/sokoban/metadata.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename apps/sokoban/{Microban.txt => Microban.sok} (100%) diff --git a/apps/sokoban/Microban.txt b/apps/sokoban/Microban.sok similarity index 100% rename from apps/sokoban/Microban.txt rename to apps/sokoban/Microban.sok diff --git a/apps/sokoban/app.js b/apps/sokoban/app.js index 90b24ed114..b7d89d6ba6 100644 --- a/apps/sokoban/app.js +++ b/apps/sokoban/app.js @@ -61,9 +61,9 @@ function next_map_offsets(filename, start_offset) { let config = s.readJSON("sokoban.json", true); if (config === undefined) { - let initial_offsets = next_map_offsets("Microban.txt", 0); + let initial_offsets = next_map_offsets("Microban.sok", 0); config = { - levels_sets: ["Microban.txt"], // all known files containing levels + levels_sets: ["Microban.sok"], // all known files containing levels levels_set: 0, // which set are we using ? current_maps: [0], // what is current map on each set ? offsets: [initial_offsets], // known offsets for each levels set (binary positions of maps in each file) @@ -461,4 +461,4 @@ Bangle.setLocked(false); current_map = config.current_map; offsets = config.offsets; -load_current_map(); \ No newline at end of file +load_current_map(); diff --git a/apps/sokoban/metadata.json b/apps/sokoban/metadata.json index 191cea1e09..7a4d5bc506 100644 --- a/apps/sokoban/metadata.json +++ b/apps/sokoban/metadata.json @@ -13,7 +13,7 @@ "readme": "README.md", "storage": [ {"name":"sokoban.app.js","url":"app.js"}, - {"name":"Microban.txt", "url":"Microban.txt"}, + {"name":"Microban.sok", "url":"Microban.sok"}, {"name":"sokoban.img","url":"app-icon.js","evaluate":true} ], "data": [{"name":"sokoban.json"} From e379e52dd49ee5a7b25f5a09fc565ad2b230d3fb Mon Sep 17 00:00:00 2001 From: frederic wagner Date: Sun, 20 Aug 2023 17:34:49 +0200 Subject: [PATCH 3/4] sokoban: more renaming --- apps/sokoban/app.js | 4 ++-- apps/sokoban/metadata.json | 2 +- apps/sokoban/{Microban.sok => sokoban.microban.sok} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename apps/sokoban/{Microban.sok => sokoban.microban.sok} (100%) diff --git a/apps/sokoban/app.js b/apps/sokoban/app.js index b7d89d6ba6..890156214b 100644 --- a/apps/sokoban/app.js +++ b/apps/sokoban/app.js @@ -61,9 +61,9 @@ function next_map_offsets(filename, start_offset) { let config = s.readJSON("sokoban.json", true); if (config === undefined) { - let initial_offsets = next_map_offsets("Microban.sok", 0); + let initial_offsets = next_map_offsets("sokoban.microban.sok", 0); config = { - levels_sets: ["Microban.sok"], // all known files containing levels + levels_sets: ["sokoban.microban.sok"], // all known files containing levels levels_set: 0, // which set are we using ? current_maps: [0], // what is current map on each set ? offsets: [initial_offsets], // known offsets for each levels set (binary positions of maps in each file) diff --git a/apps/sokoban/metadata.json b/apps/sokoban/metadata.json index 7a4d5bc506..ef4a45f83d 100644 --- a/apps/sokoban/metadata.json +++ b/apps/sokoban/metadata.json @@ -13,7 +13,7 @@ "readme": "README.md", "storage": [ {"name":"sokoban.app.js","url":"app.js"}, - {"name":"Microban.sok", "url":"Microban.sok"}, + {"name":"sokoban.microban.sok", "url":"sokoban.microban.sok"}, {"name":"sokoban.img","url":"app-icon.js","evaluate":true} ], "data": [{"name":"sokoban.json"} diff --git a/apps/sokoban/Microban.sok b/apps/sokoban/sokoban.microban.sok similarity index 100% rename from apps/sokoban/Microban.sok rename to apps/sokoban/sokoban.microban.sok From 52ee0825c5a7d3d04aa7d3e1c164888d9df095e4 Mon Sep 17 00:00:00 2001 From: frederic wagner Date: Thu, 24 Aug 2023 10:56:59 +0200 Subject: [PATCH 4/4] sokoban: small fixes --- apps/sokoban/ChangeLog | 4 ++++ apps/sokoban/app.js | 17 ++++++++++++----- apps/sokoban/metadata.json | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/apps/sokoban/ChangeLog b/apps/sokoban/ChangeLog index 9fa2c81720..f931ec63e5 100644 --- a/apps/sokoban/ChangeLog +++ b/apps/sokoban/ChangeLog @@ -1 +1,5 @@ 0.01: Initial code +0.02: + * Fix for last level offsets parsing + * Fix for title display + diff --git a/apps/sokoban/app.js b/apps/sokoban/app.js index 890156214b..3915556e3a 100644 --- a/apps/sokoban/app.js +++ b/apps/sokoban/app.js @@ -56,6 +56,9 @@ function next_map_offsets(filename, start_offset) { } } } + if (offsets.length == 1) { + offsets.push(raw_maps.length); + } return offsets; } @@ -88,7 +91,7 @@ function load_current_map() { let current_set = config.levels_set; let offsets = config.offsets[current_set]; let set_filename = config.levels_sets[current_set]; - let set_name = set_filename.substring(0, set_filename.length - 4); // remove '.txt' + let set_name = set_filename.substring(8, set_filename.length - 4); // remove '.txt' and 'sokoban.' let current_map = config.current_maps[current_set]; map = load_map(set_filename, offsets[2 * current_map], offsets[2 * current_map + 1], set_name + " " + (current_map + 1)); map.display(); @@ -98,10 +101,12 @@ function next_map() { let current_set = config.levels_set; let current_map = config.current_maps[current_set]; let offsets = config.offsets[current_set]; + let won = false; if (2 * (current_map + 1) >= offsets.length) { // we parse some new offsets let new_offsets = next_map_offsets(config.levels_sets[current_set], offsets[offsets.length - 1] + 2); // +2 since we need to start at ';' (we did -2 from ';' in previous parser call) - if (new_offsets.length == 0) { + if (new_offsets.length != 2) { + won = true; E.showAlert("You Win", "All levels completed").then(function() { load(); }); @@ -110,9 +115,11 @@ function next_map() { config.offsets[current_set].push(new_offsets[1]); } } - config.current_maps[current_set]++; - s.writeJSON("sokoban.json", config); - load_current_map(); + if (!won) { + config.current_maps[current_set]++; + s.writeJSON("sokoban.json", config); + load_current_map(); + } } function previous_map() { diff --git a/apps/sokoban/metadata.json b/apps/sokoban/metadata.json index ef4a45f83d..752c17e750 100644 --- a/apps/sokoban/metadata.json +++ b/apps/sokoban/metadata.json @@ -2,7 +2,7 @@ "id": "sokoban", "name": "Sokoban", "shortName": "Sokoban", - "version": "0.01", + "version": "0.02", "description": "Classic Sokoban game (microban levels).", "allow_emulator":false, "icon": "sokoban.png",