summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/plugins/CATEGORIES1
-rw-r--r--apps/plugins/puzzles/SOURCES4
-rw-r--r--apps/plugins/puzzles/SOURCES.games4
-rwxr-xr-xapps/plugins/puzzles/genhelp.sh23
-rw-r--r--apps/plugins/puzzles/help/blackbox.c653
-rw-r--r--apps/plugins/puzzles/help/bridges.c672
-rw-r--r--apps/plugins/puzzles/help/cube.c307
-rw-r--r--apps/plugins/puzzles/help/dominosa.c328
-rw-r--r--apps/plugins/puzzles/help/fifteen.c240
-rw-r--r--apps/plugins/puzzles/help/filling.c260
-rw-r--r--apps/plugins/puzzles/help/flip.c236
-rw-r--r--apps/plugins/puzzles/help/flood.c338
-rw-r--r--apps/plugins/puzzles/help/galaxies.c390
-rw-r--r--apps/plugins/puzzles/help/guess.c419
-rw-r--r--apps/plugins/puzzles/help/inertia.c331
-rw-r--r--apps/plugins/puzzles/help/keen.c495
-rw-r--r--apps/plugins/puzzles/help/lightup.c345
-rw-r--r--apps/plugins/puzzles/help/loopy.c424
-rw-r--r--apps/plugins/puzzles/help/magnets.c353
-rw-r--r--apps/plugins/puzzles/help/map.c502
-rw-r--r--apps/plugins/puzzles/help/mines.c494
-rw-r--r--apps/plugins/puzzles/help/mosaic.c150
-rw-r--r--apps/plugins/puzzles/help/net.c543
-rw-r--r--apps/plugins/puzzles/help/netslide.c91
-rw-r--r--apps/plugins/puzzles/help/nullgame.c1
-rw-r--r--apps/plugins/puzzles/help/palisade.c145
-rw-r--r--apps/plugins/puzzles/help/pattern.c182
-rw-r--r--apps/plugins/puzzles/help/pearl.c407
-rw-r--r--apps/plugins/puzzles/help/pegs.c267
-rw-r--r--apps/plugins/puzzles/help/range.c303
-rw-r--r--apps/plugins/puzzles/help/rect.c493
-rw-r--r--apps/plugins/puzzles/help/samegame.c347
-rw-r--r--apps/plugins/puzzles/help/signpost.c406
-rw-r--r--apps/plugins/puzzles/help/singles.c251
-rw-r--r--apps/plugins/puzzles/help/sixteen.c369
-rw-r--r--apps/plugins/puzzles/help/slant.c319
-rw-r--r--apps/plugins/puzzles/help/solo.c743
-rw-r--r--apps/plugins/puzzles/help/tents.c299
-rw-r--r--apps/plugins/puzzles/help/towers.c480
-rw-r--r--apps/plugins/puzzles/help/tracks.c233
-rw-r--r--apps/plugins/puzzles/help/twiddle.c385
-rw-r--r--apps/plugins/puzzles/help/undead.c456
-rw-r--r--apps/plugins/puzzles/help/unequal.c490
-rw-r--r--apps/plugins/puzzles/help/unruly.c263
-rw-r--r--apps/plugins/puzzles/help/untangle.c150
-rw-r--r--apps/plugins/puzzles/rbcompat.h2
-rwxr-xr-xapps/plugins/puzzles/resync.sh5
-rw-r--r--apps/plugins/puzzles/rockbox.c75
-rw-r--r--apps/plugins/puzzles/src/CMakeLists.txt287
-rw-r--r--apps/plugins/puzzles/src/LICENCE4
-rw-r--r--apps/plugins/puzzles/src/README46
-rw-r--r--apps/plugins/puzzles/src/blackbox.R19
-rw-r--r--apps/plugins/puzzles/src/blackbox.c115
-rw-r--r--apps/plugins/puzzles/src/bridges.R21
-rw-r--r--apps/plugins/puzzles/src/bridges.c210
-rw-r--r--apps/plugins/puzzles/src/combi.c37
-rw-r--r--apps/plugins/puzzles/src/cube.R19
-rw-r--r--apps/plugins/puzzles/src/cube.c110
-rw-r--r--apps/plugins/puzzles/src/devel.but1607
-rw-r--r--apps/plugins/puzzles/src/divvy.c141
-rw-r--r--apps/plugins/puzzles/src/dominosa.R24
-rw-r--r--apps/plugins/puzzles/src/dominosa.c136
-rw-r--r--apps/plugins/puzzles/src/drawing.c16
-rw-r--r--apps/plugins/puzzles/src/dsf.c411
-rw-r--r--apps/plugins/puzzles/src/emcc.c483
-rw-r--r--apps/plugins/puzzles/src/emcccopy.but128
-rw-r--r--apps/plugins/puzzles/src/fifteen.R22
-rw-r--r--apps/plugins/puzzles/src/fifteen.c259
-rw-r--r--apps/plugins/puzzles/src/filling.R24
-rw-r--r--apps/plugins/puzzles/src/filling.c198
-rw-r--r--apps/plugins/puzzles/src/flip.R21
-rw-r--r--apps/plugins/puzzles/src/flip.c89
-rw-r--r--apps/plugins/puzzles/src/flood.R19
-rw-r--r--apps/plugins/puzzles/src/flood.c184
-rw-r--r--apps/plugins/puzzles/src/fuzzpuzz.c250
-rw-r--r--apps/plugins/puzzles/src/galaxies.R28
-rw-r--r--apps/plugins/puzzles/src/galaxies.c734
-rw-r--r--apps/plugins/puzzles/src/grid.c1357
-rw-r--r--apps/plugins/puzzles/src/grid.h23
-rw-r--r--apps/plugins/puzzles/src/gtk.c550
-rw-r--r--apps/plugins/puzzles/src/gtk.h7
-rw-r--r--apps/plugins/puzzles/src/guess.R19
-rw-r--r--apps/plugins/puzzles/src/guess.c221
-rw-r--r--apps/plugins/puzzles/src/hat-internal.h271
-rw-r--r--apps/plugins/puzzles/src/hat-tables.h2120
-rw-r--r--apps/plugins/puzzles/src/hat.c891
-rw-r--r--apps/plugins/puzzles/src/hat.h67
-rw-r--r--apps/plugins/puzzles/src/inertia.R19
-rw-r--r--apps/plugins/puzzles/src/inertia.c76
-rw-r--r--apps/plugins/puzzles/src/keen.R25
-rw-r--r--apps/plugins/puzzles/src/keen.c250
-rw-r--r--apps/plugins/puzzles/src/latin.c164
-rw-r--r--apps/plugins/puzzles/src/latin.h9
-rw-r--r--apps/plugins/puzzles/src/lightup.R24
-rw-r--r--apps/plugins/puzzles/src/lightup.c137
-rw-r--r--apps/plugins/puzzles/src/list.c17
-rw-r--r--apps/plugins/puzzles/src/loopgen.c16
-rw-r--r--apps/plugins/puzzles/src/loopgen.h6
-rw-r--r--apps/plugins/puzzles/src/loopy.R31
-rw-r--r--apps/plugins/puzzles/src/loopy.c576
-rw-r--r--apps/plugins/puzzles/src/magnets.R24
-rw-r--r--apps/plugins/puzzles/src/magnets.c125
-rw-r--r--apps/plugins/puzzles/src/malloc.c13
-rw-r--r--apps/plugins/puzzles/src/map.R24
-rw-r--r--apps/plugins/puzzles/src/map.c259
-rw-r--r--apps/plugins/puzzles/src/matching.c424
-rw-r--r--apps/plugins/puzzles/src/matching.h28
-rw-r--r--apps/plugins/puzzles/src/midend.c797
-rw-r--r--apps/plugins/puzzles/src/mines.R24
-rw-r--r--apps/plugins/puzzles/src/mines.c218
-rw-r--r--apps/plugins/puzzles/src/misc.c278
-rw-r--r--apps/plugins/puzzles/src/mosaic.c1626
-rw-r--r--apps/plugins/puzzles/src/nestedvm.c14
-rw-r--r--apps/plugins/puzzles/src/net.R23
-rw-r--r--apps/plugins/puzzles/src/net.c231
-rw-r--r--apps/plugins/puzzles/src/netslide.R21
-rw-r--r--apps/plugins/puzzles/src/netslide.c105
-rw-r--r--apps/plugins/puzzles/src/no-icon.c2
-rw-r--r--apps/plugins/puzzles/src/nullfe.c24
-rw-r--r--apps/plugins/puzzles/src/nullgame.R12
-rw-r--r--apps/plugins/puzzles/src/nullgame.c80
-rw-r--r--apps/plugins/puzzles/src/obfusc.c130
-rw-r--r--apps/plugins/puzzles/src/palisade.R21
-rw-r--r--apps/plugins/puzzles/src/palisade.c172
-rw-r--r--apps/plugins/puzzles/src/pattern.R25
-rw-r--r--apps/plugins/puzzles/src/pattern.c224
-rw-r--r--apps/plugins/puzzles/src/pearl.R23
-rw-r--r--apps/plugins/puzzles/src/pearl.c499
-rw-r--r--apps/plugins/puzzles/src/pegs.R21
-rw-r--r--apps/plugins/puzzles/src/pegs.c172
-rw-r--r--apps/plugins/puzzles/src/penrose-internal.h289
-rw-r--r--apps/plugins/puzzles/src/penrose-legacy.c506
-rw-r--r--apps/plugins/puzzles/src/penrose-legacy.h63
-rw-r--r--apps/plugins/puzzles/src/penrose.c1271
-rw-r--r--apps/plugins/puzzles/src/penrose.h119
-rw-r--r--apps/plugins/puzzles/src/printing.c15
-rw-r--r--apps/plugins/puzzles/src/ps.c2
-rw-r--r--apps/plugins/puzzles/src/puzzles.but341
-rw-r--r--apps/plugins/puzzles/src/puzzles.h165
-rw-r--r--apps/plugins/puzzles/src/random.c6
-rw-r--r--apps/plugins/puzzles/src/range.R21
-rw-r--r--apps/plugins/puzzles/src/range.c182
-rw-r--r--apps/plugins/puzzles/src/rect.R19
-rw-r--r--apps/plugins/puzzles/src/rect.c82
-rw-r--r--apps/plugins/puzzles/src/resource.h20
-rw-r--r--apps/plugins/puzzles/src/samegame.R19
-rw-r--r--apps/plugins/puzzles/src/samegame.c182
-rw-r--r--apps/plugins/puzzles/src/signpost.R23
-rw-r--r--apps/plugins/puzzles/src/signpost.c185
-rw-r--r--apps/plugins/puzzles/src/singles.R23
-rw-r--r--apps/plugins/puzzles/src/singles.c111
-rw-r--r--apps/plugins/puzzles/src/sixteen.R19
-rw-r--r--apps/plugins/puzzles/src/sixteen.c87
-rw-r--r--apps/plugins/puzzles/src/slant.R24
-rw-r--r--apps/plugins/puzzles/src/slant.c180
-rw-r--r--apps/plugins/puzzles/src/solo.R24
-rw-r--r--apps/plugins/puzzles/src/solo.c197
-rw-r--r--apps/plugins/puzzles/src/sort.c91
-rw-r--r--apps/plugins/puzzles/src/spectre-internal.h327
-rw-r--r--apps/plugins/puzzles/src/spectre-tables-auto.h1220
-rw-r--r--apps/plugins/puzzles/src/spectre-tables-manual.h160
-rw-r--r--apps/plugins/puzzles/src/spectre.c599
-rw-r--r--apps/plugins/puzzles/src/spectre.h72
-rw-r--r--apps/plugins/puzzles/src/tents.R24
-rw-r--r--apps/plugins/puzzles/src/tents.c121
-rw-r--r--apps/plugins/puzzles/src/towers.R25
-rw-r--r--apps/plugins/puzzles/src/towers.c199
-rw-r--r--apps/plugins/puzzles/src/tracks.R24
-rw-r--r--apps/plugins/puzzles/src/tracks.c351
-rw-r--r--apps/plugins/puzzles/src/tree234.c782
-rw-r--r--apps/plugins/puzzles/src/tree234.h24
-rw-r--r--apps/plugins/puzzles/src/twiddle.R19
-rw-r--r--apps/plugins/puzzles/src/twiddle.c94
-rw-r--r--apps/plugins/puzzles/src/undead.R18
-rw-r--r--apps/plugins/puzzles/src/undead.c210
-rw-r--r--apps/plugins/puzzles/src/unequal.R25
-rw-r--r--apps/plugins/puzzles/src/unequal.c193
-rw-r--r--apps/plugins/puzzles/src/unruly.R21
-rw-r--r--apps/plugins/puzzles/src/unruly.c189
-rw-r--r--apps/plugins/puzzles/src/untangle.R21
-rw-r--r--apps/plugins/puzzles/src/untangle.c512
-rw-r--r--apps/plugins/puzzles/src/version.c1
-rw-r--r--apps/plugins/puzzles/src/version.h2
-rw-r--r--apps/plugins/puzzles/src/windows.c807
184 files changed, 27699 insertions, 15438 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
index 366c42c75b..814fb2f130 100644
--- a/apps/plugins/CATEGORIES
+++ b/apps/plugins/CATEGORIES
@@ -128,6 +128,7 @@ sgt-loopy,games
128sgt-magnets,games 128sgt-magnets,games
129sgt-map,games 129sgt-map,games
130sgt-mines,games 130sgt-mines,games
131sgt-mosaic,games
131sgt-net,games 132sgt-net,games
132sgt-netslide,games 133sgt-netslide,games
133sgt-palisade,games 134sgt-palisade,games
diff --git a/apps/plugins/puzzles/SOURCES b/apps/plugins/puzzles/SOURCES
index 5301ceef3d..58a16bc9b9 100644
--- a/apps/plugins/puzzles/SOURCES
+++ b/apps/plugins/puzzles/SOURCES
@@ -17,6 +17,7 @@ src/matching.c
17src/midend.c 17src/midend.c
18src/misc.c 18src/misc.c
19src/penrose.c 19src/penrose.c
20src/penrose-legacy.c
20src/printing.c 21src/printing.c
21src/random.c 22src/random.c
22src/sort.c 23src/sort.c
@@ -24,6 +25,9 @@ src/tdq.c
24src/tree234.c 25src/tree234.c
25src/version.c 26src/version.c
26 27
28src/hat.c
29src/spectre.c
30
27#ifdef COMBINED 31#ifdef COMBINED
28src/list.c 32src/list.c
29#endif 33#endif
diff --git a/apps/plugins/puzzles/SOURCES.games b/apps/plugins/puzzles/SOURCES.games
index 2b80ea3300..29af18e7b8 100644
--- a/apps/plugins/puzzles/SOURCES.games
+++ b/apps/plugins/puzzles/SOURCES.games
@@ -16,6 +16,7 @@ src/lightup.c
16src/magnets.c 16src/magnets.c
17src/map.c 17src/map.c
18src/mines.c 18src/mines.c
19src/mosaic.c
19src/net.c 20src/net.c
20src/netslide.c 21src/netslide.c
21src/palisade.c 22src/palisade.c
@@ -37,7 +38,8 @@ src/unequal.c
37src/unruly.c 38src/unruly.c
38src/untangle.c 39src/untangle.c
39 40
40/* disabled for now (fix puzzles.make and CATEGORIES to accomodate these) */ 41/* Disabled for now. Fix puzzles.make and CATEGORIES to accomodate these. */
42/* The help system would also need to be patched to compile these. */
41/*src/unfinished/group.c*/ 43/*src/unfinished/group.c*/
42/*src/unfinished/separate.c*/ 44/*src/unfinished/separate.c*/
43/*src/unfinished/slide.c*/ 45/*src/unfinished/slide.c*/
diff --git a/apps/plugins/puzzles/genhelp.sh b/apps/plugins/puzzles/genhelp.sh
index 3df7706b5d..f515bb25dc 100755
--- a/apps/plugins/puzzles/genhelp.sh
+++ b/apps/plugins/puzzles/genhelp.sh
@@ -36,6 +36,9 @@ BEGIN {
36 if($3 ~ "Rectangles") 36 if($3 ~ "Rectangles")
37 file = "help/rect.c"; 37 file = "help/rect.c";
38 38
39 if($3 ~ "Train")
40 file = "help/tracks.c";
41
39 print "/* auto-generated by genhelp.sh (intermediate file) */" > file; 42 print "/* auto-generated by genhelp.sh (intermediate file) */" > file;
40 print "/* DO NOT EDIT! */" > file; 43 print "/* DO NOT EDIT! */" > file;
41 print "const char help_text[] = " > file; 44 print "const char help_text[] = " > file;
@@ -87,8 +90,24 @@ do
87 mv $f.tmp $f 90 mv $f.tmp $f
88done 91done
89 92
90# generate quick help from all the .R files 93# Generate quick help by parsing the CMakeLists.txt file to isolate
91cat src/*.R | awk 'print_next { print_next = 0; print; } /!begin/ && />/ && /gamedesc.txt/ { print_next = 1; }' | awk -F ":" '{print "const char quick_help_text[] = \""$5"\";" >> "help/"$1".c" }' 94# the "Objective" text for each puzzle.
95cat <<EOF > parsed_cmakelists.txt
96function(puzzle NAME)
97 cmake_parse_arguments(OPT
98 "" "DISPLAYNAME;DESCRIPTION;OBJECTIVE;WINDOWS_EXE_NAME" "" \${ARGN})
99
100 message("\${NAME}:\${OPT_OBJECTIVE}")
101endfunction()
102EOF
103
104# This parses out the puzzle(...) definitions from CMakeLists.
105
106# TODO: Perhaps ask Simon to include special header/footer comments to
107# make this less brittle?
108cat src/CMakeLists.txt | awk '/puzzle\(/{p=1} p{print} /\)/{p=0}' >> parsed_cmakelists.txt
109cmake -P parsed_cmakelists.txt 2>&1 | awk -F ":" '{print "const char quick_help_text[] = \""$2"\";" >> "help/"$1".c" }'
92 110
111rm parsed_cmakelists.txt
93rm puzzles.txt 112rm puzzles.txt
94rm compress 113rm compress
diff --git a/apps/plugins/puzzles/help/blackbox.c b/apps/plugins/puzzles/help/blackbox.c
index 0121ee3f93..f01852becf 100644
--- a/apps/plugins/puzzles/help/blackbox.c
+++ b/apps/plugins/puzzles/help/blackbox.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,337 +6,338 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 450, TEXT_UNDERLINE }, 9 { 451, TEXT_UNDERLINE },
10 { 476, TEXT_UNDERLINE }, 10 { 477, TEXT_UNDERLINE },
11 { 503, TEXT_CENTER | C_RED }, 11 { 504, TEXT_CENTER | C_RED },
12 { 869, TEXT_UNDERLINE }, 12 { 870, TEXT_UNDERLINE },
13 { 897, TEXT_CENTER | C_RED }, 13 { 898, TEXT_CENTER | C_RED },
14 { 914, TEXT_UNDERLINE },
15 { 915, TEXT_UNDERLINE }, 14 { 915, TEXT_UNDERLINE },
16 { 927, TEXT_UNDERLINE }, 15 { 916, TEXT_UNDERLINE },
17 { 929, TEXT_UNDERLINE }, 16 { 928, TEXT_UNDERLINE },
18 { 942, TEXT_UNDERLINE }, 17 { 930, TEXT_UNDERLINE },
18 { 943, TEXT_UNDERLINE },
19 LAST_STYLE_ITEM 19 LAST_STYLE_ITEM
20}; 20};
21 21
22/* orig 5458 comp 3139 ratio 0.575119 level 10 saved 2319 */ 22/* orig 5480 comp 3142 ratio 0.573358 level 10 saved 2338 */
23const char help_text[] = { 23const char help_text[] = {
240xf0, 0x37, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 240xff, 0x09, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
250x31, 0x39, 0x3a, 0x20, 0x42, 0x6c, 0x61, 0x63, 0x6b, 0x20, 250x31, 0x39, 0x3a, 0x20, 0x42, 0x6c, 0x61, 0x63, 0x6b, 0x20,
260x42, 0x6f, 0x78, 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x6e, 260x42, 0x6f, 0x78, 0x20, 0x00, 0x2d, 0x01, 0x00, 0x01, 0xf0,
270x75, 0x6d, 0x62, 0x65, 0x72, 0x00, 0x6f, 0x66, 0x00, 0x62, 270x21, 0x00, 0x00, 0x00, 0x41, 0x00, 0x6e, 0x75, 0x6d, 0x62,
280x61, 0x6c, 0x6c, 0x73, 0x00, 0x61, 0x72, 0x65, 0x00, 0x68, 280x65, 0x72, 0x00, 0x6f, 0x66, 0x00, 0x62, 0x61, 0x6c, 0x6c,
290x69, 0x64, 0x64, 0x65, 0x6e, 0x00, 0x69, 0x6e, 0x00, 0x61, 290x73, 0x00, 0x61, 0x72, 0x65, 0x00, 0x68, 0x69, 0x64, 0x64,
300x00, 0x72, 0x65, 0x63, 0x74, 0x61, 0x6e, 0x67, 0x75, 0x6c, 300x65, 0x6e, 0x00, 0x69, 0x6e, 0x00, 0x61, 0x00, 0x72, 0x65,
310x61, 0x72, 0x1c, 0x00, 0xf0, 0x15, 0x6e, 0x61, 0x2e, 0x00, 310x63, 0x74, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x1c,
320x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x74, 320x00, 0xf0, 0x15, 0x6e, 0x61, 0x2e, 0x00, 0x59, 0x6f, 0x75,
330x6f, 0x00, 0x64, 0x65, 0x64, 0x75, 0x63, 0x65, 0x00, 0x74, 330x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x74, 0x6f, 0x00, 0x64,
340x68, 0x65, 0x00, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 340x65, 0x64, 0x75, 0x63, 0x65, 0x00, 0x74, 0x68, 0x65, 0x00,
350x6e, 0x73, 0x4d, 0x00, 0x00, 0x11, 0x00, 0x02, 0x51, 0x00, 350x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d,
360xf5, 0x01, 0x62, 0x79, 0x00, 0x66, 0x69, 0x72, 0x69, 0x6e, 360x00, 0x00, 0x11, 0x00, 0x02, 0x51, 0x00, 0xf5, 0x01, 0x62,
370x67, 0x00, 0x6c, 0x61, 0x73, 0x65, 0x72, 0x73, 0x28, 0x00, 370x79, 0x00, 0x66, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x00, 0x6c,
380x51, 0x65, 0x64, 0x00, 0x61, 0x74, 0x29, 0x00, 0x45, 0x65, 380x61, 0x73, 0x65, 0x72, 0x73, 0x28, 0x00, 0x51, 0x65, 0x64,
390x64, 0x67, 0x65, 0x36, 0x00, 0x01, 0x65, 0x00, 0xb0, 0x00, 390x00, 0x61, 0x74, 0x29, 0x00, 0x45, 0x65, 0x64, 0x67, 0x65,
400x61, 0x6e, 0x64, 0x00, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 400x36, 0x00, 0x01, 0x65, 0x00, 0xb0, 0x00, 0x61, 0x6e, 0x64,
410x3a, 0x00, 0x30, 0x68, 0x6f, 0x77, 0x1c, 0x00, 0x72, 0x69, 410x00, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x3a, 0x00, 0x30,
420x72, 0x00, 0x62, 0x65, 0x61, 0x6d, 0xa5, 0x00, 0xe1, 0x64, 420x68, 0x6f, 0x77, 0x1c, 0x00, 0x72, 0x69, 0x72, 0x00, 0x62,
430x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x2e, 0x00, 430x65, 0x61, 0x6d, 0xa5, 0x00, 0xe1, 0x64, 0x65, 0x66, 0x6c,
440x00, 0x00, 0x42, 0x17, 0x00, 0xf3, 0x0a, 0x77, 0x69, 0x6c, 440x65, 0x63, 0x74, 0x65, 0x64, 0x2e, 0x00, 0x00, 0x00, 0x42,
450x6c, 0x00, 0x74, 0x72, 0x61, 0x76, 0x65, 0x6c, 0x00, 0x73, 450x17, 0x00, 0xf3, 0x0a, 0x77, 0x69, 0x6c, 0x6c, 0x00, 0x74,
460x74, 0x72, 0x61, 0x69, 0x67, 0x68, 0x74, 0x00, 0x66, 0x72, 460x72, 0x61, 0x76, 0x65, 0x6c, 0x00, 0x73, 0x74, 0x72, 0x61,
470x6f, 0x6d, 0x3d, 0x00, 0xc0, 0x6f, 0x72, 0x69, 0x67, 0x69, 470x69, 0x67, 0x68, 0x74, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x3d,
480x6e, 0x00, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x13, 0x00, 0x42, 480x00, 0xc0, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x00, 0x75,
490x79, 0x00, 0x68, 0x69, 0x82, 0x00, 0x21, 0x6f, 0x70, 0x96, 490x6e, 0x74, 0x69, 0x6c, 0x13, 0x00, 0x42, 0x79, 0x00, 0x68,
500x00, 0x6a, 0x65, 0x00, 0x73, 0x69, 0x64, 0x65, 0x8a, 0x00, 500x69, 0x82, 0x00, 0x21, 0x6f, 0x70, 0x96, 0x00, 0x6a, 0x65,
510xf2, 0x00, 0x28, 0x61, 0x74, 0x00, 0x77, 0x68, 0x69, 0x63, 510x00, 0x73, 0x69, 0x64, 0x65, 0x8a, 0x00, 0xf2, 0x00, 0x28,
520x68, 0x00, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x38, 0x00, 0xf1, 520x61, 0x74, 0x00, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x70,
530x04, 0x65, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x29, 0x2c, 0x00, 530x6f, 0x69, 0x6e, 0x74, 0x38, 0x00, 0xf1, 0x04, 0x65, 0x6d,
540x75, 0x6e, 0x6c, 0x65, 0x73, 0x73, 0x00, 0x61, 0x66, 0x66, 540x65, 0x72, 0x67, 0x65, 0x29, 0x2c, 0x00, 0x75, 0x6e, 0x6c,
550x8c, 0x00, 0x00, 0xee, 0x00, 0x02, 0xf7, 0x00, 0x55, 0x69, 550x65, 0x73, 0x73, 0x00, 0x61, 0x66, 0x66, 0x8c, 0x00, 0x00,
560x6e, 0x00, 0x6f, 0x6e, 0x4b, 0x00, 0x60, 0x66, 0x6f, 0x6c, 560xee, 0x00, 0x02, 0xf7, 0x00, 0x55, 0x69, 0x6e, 0x00, 0x6f,
570x6c, 0x6f, 0x77, 0xcb, 0x00, 0xb1, 0x77, 0x61, 0x79, 0x73, 570x6e, 0x4b, 0x00, 0x60, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77,
580x3a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x41, 0xcd, 0x00, 0x50, 580xcb, 0x00, 0xb1, 0x77, 0x61, 0x79, 0x73, 0x3a, 0x00, 0x00,
590x00, 0x74, 0x68, 0x61, 0x74, 0x88, 0x00, 0x31, 0x73, 0x00, 590x00, 0x2d, 0x00, 0x41, 0xcd, 0x00, 0x50, 0x00, 0x74, 0x68,
600x61, 0x3b, 0x00, 0xf1, 0x05, 0x00, 0x68, 0x65, 0x61, 0x64, 600x61, 0x74, 0x88, 0x00, 0x31, 0x73, 0x00, 0x61, 0x3b, 0x00,
610x2d, 0x6f, 0x6e, 0x00, 0x69, 0x73, 0x00, 0x61, 0x62, 0x73, 610xf1, 0x05, 0x00, 0x68, 0x65, 0x61, 0x64, 0x2d, 0x6f, 0x6e,
620x6f, 0x72, 0x62, 0x65, 0x64, 0x0f, 0x01, 0x01, 0xde, 0x00, 620x00, 0x69, 0x73, 0x00, 0x61, 0x62, 0x73, 0x6f, 0x72, 0x62,
630x93, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x00, 0x72, 0x65, 0x2d, 630x65, 0x64, 0x0f, 0x01, 0x01, 0xde, 0x00, 0x93, 0x6e, 0x65,
640x83, 0x00, 0x50, 0x2e, 0x00, 0x54, 0x68, 0x69, 0x6e, 0x00, 640x76, 0x65, 0x72, 0x00, 0x72, 0x65, 0x2d, 0x83, 0x00, 0x50,
650x63, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x20, 0x01, 0x01, 650x2e, 0x00, 0x54, 0x68, 0x69, 0x6e, 0x00, 0x63, 0x63, 0x6c,
660x54, 0x00, 0x44, 0x6d, 0x65, 0x65, 0x74, 0x54, 0x00, 0x22, 660x75, 0x64, 0x65, 0x73, 0x20, 0x01, 0x01, 0x54, 0x00, 0x44,
670x6f, 0x6e, 0x87, 0x00, 0x99, 0x69, 0x72, 0x73, 0x74, 0x00, 670x6d, 0x65, 0x65, 0x74, 0x54, 0x00, 0x22, 0x6f, 0x6e, 0x87,
680x72, 0x61, 0x6e, 0x6b, 0xe4, 0x00, 0x18, 0x2e, 0x90, 0x00, 680x00, 0x99, 0x69, 0x72, 0x73, 0x74, 0x00, 0x72, 0x61, 0x6e,
690x44, 0x77, 0x69, 0x74, 0x68, 0x37, 0x00, 0x30, 0x69, 0x6e, 690x6b, 0xe4, 0x00, 0x18, 0x2e, 0x90, 0x00, 0x44, 0x77, 0x69,
700x00, 0x99, 0x00, 0xe0, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x2d, 700x74, 0x68, 0x37, 0x00, 0x30, 0x69, 0x6e, 0x00, 0x99, 0x00,
710x6c, 0x65, 0x66, 0x74, 0x00, 0x73, 0x71, 0x75, 0x7d, 0x01, 710xe0, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x66,
720x00, 0x90, 0x00, 0x22, 0x6e, 0x6f, 0x25, 0x00, 0x10, 0x61, 720x74, 0x00, 0x73, 0x71, 0x75, 0x7d, 0x01, 0x00, 0x90, 0x00,
730xb1, 0x00, 0x00, 0x50, 0x00, 0x76, 0x69, 0x74, 0x00, 0x67, 730x22, 0x6e, 0x6f, 0x25, 0x00, 0x10, 0x61, 0xb1, 0x00, 0x00,
740x65, 0x74, 0x73, 0x9a, 0x01, 0xb0, 0x00, 0x39, 0x30, 0x00, 740x50, 0x00, 0x76, 0x69, 0x74, 0x00, 0x67, 0x65, 0x74, 0x73,
750x64, 0x65, 0x67, 0x72, 0x65, 0x65, 0x73, 0x2c, 0x02, 0x00, 750x9a, 0x01, 0xb0, 0x00, 0x39, 0x30, 0x00, 0x64, 0x65, 0x67,
760x70, 0x00, 0x10, 0x72, 0x94, 0x01, 0x0f, 0x70, 0x00, 0x13, 760x72, 0x65, 0x65, 0x73, 0x2c, 0x02, 0x00, 0x70, 0x00, 0x10,
770x01, 0x2b, 0x00, 0x0f, 0x71, 0x00, 0x12, 0x97, 0x73, 0x69, 770x72, 0x94, 0x01, 0x0f, 0x70, 0x00, 0x13, 0x01, 0x2b, 0x00,
780x6d, 0x69, 0x6c, 0x61, 0x72, 0x6c, 0x79, 0x7b, 0x00, 0x03, 780x0f, 0x71, 0x00, 0x12, 0x97, 0x73, 0x69, 0x6d, 0x69, 0x6c,
790x70, 0x00, 0x00, 0xb5, 0x00, 0x1d, 0x2e, 0x6f, 0x01, 0x50, 790x61, 0x72, 0x6c, 0x79, 0x7b, 0x00, 0x03, 0x70, 0x00, 0x00,
800x77, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x01, 0x02, 0x45, 0x01, 800xb5, 0x00, 0x1d, 0x2e, 0x6f, 0x01, 0x50, 0x77, 0x6f, 0x75,
810x02, 0x24, 0x02, 0x00, 0x7a, 0x00, 0xc2, 0x65, 0x6e, 0x74, 810x6c, 0x64, 0x46, 0x01, 0x02, 0x45, 0x01, 0x02, 0x24, 0x02,
820x72, 0x79, 0x00, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x83, 820x00, 0x7a, 0x00, 0xc2, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x00,
830x01, 0x30, 0x63, 0x6f, 0x6e, 0x14, 0x02, 0x12, 0x72, 0x53, 830x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x83, 0x01, 0x30, 0x63,
840x00, 0x54, 0x62, 0x65, 0x00, 0x60, 0x72, 0x64, 0x00, 0x1a, 840x6f, 0x6e, 0x14, 0x02, 0x12, 0x72, 0x53, 0x00, 0x54, 0x62,
850x27, 0xc8, 0x00, 0x01, 0x24, 0x02, 0x02, 0x5a, 0x00, 0x37, 850x65, 0x00, 0x60, 0x72, 0x64, 0x00, 0x1a, 0x27, 0xc8, 0x00,
860x67, 0x65, 0x74, 0x8b, 0x00, 0x60, 0x62, 0x65, 0x66, 0x6f, 860x01, 0x24, 0x02, 0x02, 0x5a, 0x00, 0x37, 0x67, 0x65, 0x74,
870x72, 0x65, 0x5c, 0x00, 0x11, 0x65, 0x08, 0x03, 0x06, 0x5c, 870x8b, 0x00, 0x60, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x5c,
880x02, 0x24, 0x62, 0x79, 0xfa, 0x00, 0x03, 0xaf, 0x00, 0x07, 880x00, 0x11, 0x65, 0x08, 0x03, 0x06, 0x5c, 0x02, 0x24, 0x62,
890x6a, 0x01, 0x29, 0x6f, 0x72, 0x08, 0x01, 0x27, 0x6f, 0x66, 890x79, 0xfa, 0x00, 0x03, 0xaf, 0x00, 0x07, 0x6a, 0x01, 0x29,
900xa1, 0x00, 0x02, 0x8a, 0x02, 0x00, 0x21, 0x02, 0x3f, 0x6c, 900x6f, 0x72, 0x08, 0x01, 0x27, 0x6f, 0x66, 0xa1, 0x00, 0x02,
910x73, 0x6f, 0xa3, 0x00, 0x0e, 0x16, 0x42, 0x14, 0x02, 0x00, 910x8a, 0x02, 0x00, 0x21, 0x02, 0x3f, 0x6c, 0x73, 0x6f, 0xa3,
920x4b, 0x01, 0x15, 0x72, 0x99, 0x00, 0x40, 0x61, 0x70, 0x70, 920x00, 0x0e, 0x16, 0x42, 0x14, 0x02, 0x00, 0x4b, 0x01, 0x15,
930x65, 0xd7, 0x03, 0x00, 0x7b, 0x02, 0x48, 0x60, 0x52, 0x27, 930x72, 0x99, 0x00, 0x40, 0x61, 0x70, 0x70, 0x65, 0xd7, 0x03,
940x3b, 0x3e, 0x02, 0x00, 0x1a, 0x03, 0x02, 0xca, 0x02, 0x01, 940x00, 0x7b, 0x02, 0x48, 0x60, 0x52, 0x27, 0x3b, 0x3e, 0x02,
950x90, 0x02, 0x00, 0x42, 0x02, 0x06, 0x2f, 0x00, 0xf4, 0x02, 950x00, 0x1a, 0x03, 0x02, 0xca, 0x02, 0x01, 0x90, 0x02, 0x00,
960x60, 0x48, 0x27, 0x2e, 0x00, 0x4f, 0x74, 0x68, 0x65, 0x72, 960x42, 0x02, 0x06, 0x2f, 0x00, 0xf4, 0x02, 0x60, 0x48, 0x27,
970x77, 0x69, 0x73, 0x65, 0x2c, 0x00, 0x61, 0x47, 0x04, 0x02, 970x2e, 0x00, 0x4f, 0x74, 0x68, 0x65, 0x72, 0x77, 0x69, 0x73,
980x23, 0x00, 0x14, 0x73, 0xd9, 0x03, 0x03, 0xf9, 0x03, 0x02, 980x65, 0x2c, 0x00, 0x61, 0x47, 0x04, 0x02, 0x23, 0x00, 0x14,
990xaf, 0x00, 0x00, 0xc3, 0x01, 0x01, 0x93, 0x01, 0x04, 0x5e, 990x73, 0xd9, 0x03, 0x03, 0xf9, 0x03, 0x02, 0xaf, 0x00, 0x00,
1000x01, 0x42, 0x77, 0x68, 0x65, 0x72, 0x3b, 0x04, 0x01, 0x41, 1000xc3, 0x01, 0x01, 0x93, 0x01, 0x04, 0x5e, 0x01, 0x42, 0x77,
1010x01, 0x02, 0x8c, 0x01, 0x40, 0x73, 0x00, 0x28, 0x74, 0xd2, 1010x68, 0x65, 0x72, 0x3b, 0x04, 0x01, 0x41, 0x01, 0x02, 0x8c,
1020x02, 0x03, 0x51, 0x00, 0x81, 0x69, 0x73, 0x00, 0x75, 0x6e, 1020x01, 0x40, 0x73, 0x00, 0x28, 0x74, 0xd2, 0x02, 0x03, 0x51,
1030x69, 0x71, 0x75, 0x6d, 0x04, 0x01, 0x99, 0x00, 0x50, 0x73, 1030x00, 0x81, 0x69, 0x73, 0x00, 0x75, 0x6e, 0x69, 0x71, 0x75,
1040x68, 0x6f, 0x74, 0x29, 0xd7, 0x00, 0x00, 0x87, 0x04, 0xf5, 1040x6d, 0x04, 0x01, 0x99, 0x00, 0x50, 0x73, 0x68, 0x6f, 0x74,
1050x04, 0x63, 0x61, 0x6e, 0x00, 0x70, 0x6c, 0x61, 0x63, 0x65, 1050x29, 0xd7, 0x00, 0x00, 0x87, 0x04, 0xf5, 0x04, 0x63, 0x61,
1060x00, 0x67, 0x75, 0x65, 0x73, 0x73, 0x65, 0x73, 0x00, 0x61, 1060x6e, 0x00, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x00, 0x67, 0x75,
1070x6b, 0x02, 0x05, 0x68, 0x00, 0x08, 0x8f, 0x04, 0x74, 0x2c, 1070x65, 0x73, 0x73, 0x65, 0x73, 0x00, 0x61, 0x6b, 0x02, 0x05,
1080x00, 0x62, 0x61, 0x73, 0x65, 0x64, 0x11, 0x03, 0x02, 0x4f, 1080x68, 0x00, 0x08, 0x8f, 0x04, 0x74, 0x2c, 0x00, 0x62, 0x61,
1090x01, 0x00, 0x9a, 0x00, 0xb7, 0x65, 0x78, 0x69, 0x74, 0x00, 1090x73, 0x65, 0x64, 0x11, 0x03, 0x02, 0x4f, 0x01, 0x00, 0x9a,
1100x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0xc2, 0x04, 0x00, 0x10, 1100x00, 0xb7, 0x65, 0x78, 0x69, 0x74, 0x00, 0x70, 0x61, 0x74,
1110x01, 0x84, 0x3b, 0x00, 0x6f, 0x6e, 0x63, 0x65, 0x00, 0x79, 1110x74, 0x65, 0x72, 0xc2, 0x04, 0x00, 0x10, 0x01, 0x84, 0x3b,
1120xf6, 0x04, 0x01, 0x70, 0x00, 0x84, 0x64, 0x00, 0x65, 0x6e, 1120x00, 0x6f, 0x6e, 0x63, 0x65, 0x00, 0x79, 0xf6, 0x04, 0x01,
1130x6f, 0x75, 0x67, 0x68, 0x36, 0x05, 0x55, 0x00, 0x62, 0x75, 1130x70, 0x00, 0x84, 0x64, 0x00, 0x65, 0x6e, 0x6f, 0x75, 0x67,
1140x74, 0x74, 0x24, 0x01, 0x00, 0xa8, 0x01, 0x30, 0x61, 0x62, 1140x68, 0x36, 0x05, 0x55, 0x00, 0x62, 0x75, 0x74, 0x74, 0x24,
1150x6c, 0xfc, 0x00, 0x00, 0x37, 0x00, 0x22, 0x74, 0x6f, 0x3a, 1150x01, 0x00, 0xa8, 0x01, 0x30, 0x61, 0x62, 0x6c, 0xfc, 0x00,
1160x00, 0x45, 0x79, 0x6f, 0x75, 0x72, 0xa9, 0x00, 0x52, 0x63, 1160x00, 0x37, 0x00, 0x22, 0x74, 0x6f, 0x3a, 0x00, 0x45, 0x79,
1170x68, 0x65, 0x63, 0x6b, 0xbe, 0x04, 0x10, 0x48, 0x08, 0x01, 1170x6f, 0x75, 0x72, 0xa9, 0x00, 0x52, 0x63, 0x68, 0x65, 0x63,
1180x10, 0x69, 0x46, 0x00, 0x70, 0x64, 0x69, 0x61, 0x67, 0x72, 1180x6b, 0xbe, 0x04, 0x10, 0x48, 0x08, 0x01, 0x10, 0x69, 0x46,
1190x61, 0x6d, 0xe5, 0x00, 0x17, 0x77, 0xf9, 0x04, 0x0a, 0x5c, 1190x00, 0x70, 0x64, 0x69, 0x61, 0x67, 0x72, 0x61, 0x6d, 0xe5,
1200x05, 0x02, 0x73, 0x00, 0x00, 0xfb, 0x00, 0xb8, 0x63, 0x72, 1200x00, 0x17, 0x77, 0xf9, 0x04, 0x0a, 0x5c, 0x05, 0x02, 0x73,
1210x65, 0x61, 0x74, 0x65, 0x00, 0x65, 0x61, 0x63, 0x68, 0xb3, 1210x00, 0x00, 0xfb, 0x00, 0xb8, 0x63, 0x72, 0x65, 0x61, 0x74,
1220x00, 0xb1, 0x00, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 1220x65, 0x00, 0x65, 0x61, 0x63, 0x68, 0xb3, 0x00, 0xb1, 0x00,
1230x75, 0x72, 0x73, 0x4a, 0x00, 0x70, 0x6e, 0x00, 0x61, 0x62, 1230x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x75, 0x72, 0x73,
1240x6f, 0x76, 0x65, 0x77, 0x04, 0xf3, 0x09, 0x31, 0x52, 0x48, 1240x4a, 0x00, 0x70, 0x6e, 0x00, 0x61, 0x62, 0x6f, 0x76, 0x65,
1250x52, 0x2d, 0x2d, 0x2d, 0x2d, 0x00, 0x00, 0x7c, 0x2e, 0x2e, 1250x77, 0x04, 0x42, 0x31, 0x52, 0x48, 0x52, 0xfc, 0x05, 0xe3,
1260x4f, 0x2e, 0x4f, 0x2e, 0x2e, 0x2e, 0x7c, 0x00, 0x00, 0x32, 1260x7c, 0x2e, 0x2e, 0x4f, 0x2e, 0x4f, 0x2e, 0x2e, 0x2e, 0x7c,
1270x2e, 0x01, 0x00, 0x11, 0x33, 0x18, 0x00, 0x02, 0x01, 0x00, 1270x00, 0x00, 0x32, 0x2e, 0x01, 0x00, 0x11, 0x33, 0x18, 0x00,
1280x1a, 0x7c, 0x0c, 0x00, 0x1e, 0x33, 0x18, 0x00, 0x10, 0x4f, 1280x02, 0x01, 0x00, 0x1a, 0x7c, 0x0c, 0x00, 0x1e, 0x33, 0x18,
1290x0c, 0x00, 0x1d, 0x48, 0x18, 0x00, 0x11, 0x4f, 0x0c, 0x00, 1290x00, 0x10, 0x4f, 0x0c, 0x00, 0x1d, 0x48, 0x18, 0x00, 0x11,
1300x51, 0x31, 0x32, 0x2d, 0x52, 0x52, 0x6a, 0x00, 0x33, 0x00, 1300x4f, 0x0c, 0x00, 0x52, 0x31, 0x32, 0x2d, 0x52, 0x52, 0x66,
1310x00, 0x41, 0x88, 0x00, 0x10, 0x2c, 0xb3, 0x03, 0x11, 0x69, 1310x06, 0x23, 0x00, 0x41, 0x88, 0x00, 0x10, 0x2c, 0xb3, 0x03,
1320x03, 0x06, 0x40, 0x73, 0x69, 0x62, 0x6c, 0x18, 0x05, 0x33, 1320x11, 0x69, 0x03, 0x06, 0x40, 0x73, 0x69, 0x62, 0x6c, 0x18,
1330x72, 0x00, 0x61, 0x99, 0x03, 0x10, 0x6f, 0x6c, 0x06, 0xc5, 1330x05, 0x33, 0x72, 0x00, 0x61, 0x99, 0x03, 0x10, 0x6f, 0x6c,
1340x65, 0x69, 0x76, 0x65, 0x00, 0x6d, 0x75, 0x6c, 0x74, 0x69, 1340x06, 0xc5, 0x65, 0x69, 0x76, 0x65, 0x00, 0x6d, 0x75, 0x6c,
1350x70, 0x6c, 0xab, 0x02, 0x01, 0xf9, 0x00, 0x03, 0x46, 0x03, 1350x74, 0x69, 0x70, 0x6c, 0xab, 0x02, 0x01, 0xf9, 0x00, 0x03,
1360x04, 0xb5, 0x03, 0x00, 0x1e, 0x01, 0xf4, 0x00, 0x28, 0x73, 1360x46, 0x03, 0x04, 0xb5, 0x03, 0x00, 0x1e, 0x01, 0xf4, 0x00,
1370x65, 0x65, 0x00, 0x74, 0x75, 0x72, 0x6e, 0x00, 0x33, 0x29, 1370x28, 0x73, 0x65, 0x65, 0x00, 0x74, 0x75, 0x72, 0x6e, 0x00,
1380x2e, 0x00, 0x53, 0x06, 0x04, 0x14, 0x2c, 0x53, 0x00, 0x58, 1380x33, 0x29, 0x2e, 0x00, 0x53, 0x06, 0x04, 0x14, 0x2c, 0x53,
1390x6d, 0x61, 0x79, 0x00, 0x62, 0xf1, 0x02, 0x13, 0x28, 0x79, 1390x00, 0x58, 0x6d, 0x61, 0x79, 0x00, 0x62, 0xf1, 0x02, 0x13,
1400x00, 0x41, 0x79, 0x00, 0x6d, 0x6f, 0x7b, 0x02, 0x21, 0x61, 1400x28, 0x79, 0x00, 0x41, 0x79, 0x00, 0x6d, 0x6f, 0x7b, 0x02,
1410x6e, 0xdd, 0x01, 0x16, 0x29, 0x5e, 0x00, 0x00, 0x82, 0x00, 1410x21, 0x61, 0x6e, 0xdd, 0x01, 0x16, 0x29, 0x5e, 0x00, 0x00,
1420x00, 0x5c, 0x00, 0x11, 0x61, 0x02, 0x03, 0x10, 0x28, 0x53, 1420x82, 0x00, 0x00, 0x5c, 0x00, 0x11, 0x61, 0x02, 0x03, 0x10,
1430x01, 0x34, 0x60, 0x48, 0x27, 0x30, 0x02, 0x02, 0x04, 0x05, 1430x28, 0x53, 0x01, 0x34, 0x60, 0x48, 0x27, 0x30, 0x02, 0x02,
1440x07, 0x24, 0x06, 0x71, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 1440x04, 0x05, 0x07, 0x24, 0x06, 0x71, 0x65, 0x78, 0x61, 0x6d,
1450x65, 0x91, 0x02, 0x43, 0x4e, 0x6f, 0x74, 0x65, 0x67, 0x03, 1450x70, 0x6c, 0x65, 0x91, 0x02, 0x43, 0x4e, 0x6f, 0x74, 0x65,
1460x92, 0x6e, 0x79, 0x00, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 1460x67, 0x03, 0x92, 0x6e, 0x79, 0x00, 0x6c, 0x61, 0x79, 0x6f,
1470xdf, 0x04, 0x06, 0x6e, 0x00, 0x13, 0x34, 0xbe, 0x01, 0x00, 1470x75, 0x74, 0xdf, 0x04, 0x06, 0x6e, 0x00, 0x13, 0x34, 0xbe,
1480x9b, 0x00, 0x01, 0x14, 0x02, 0x63, 0x61, 0x00, 0x6e, 0x6f, 1480x01, 0x00, 0x9b, 0x00, 0x01, 0x14, 0x02, 0x63, 0x61, 0x00,
1490x6e, 0x2d, 0xe4, 0x02, 0x40, 0x73, 0x6f, 0x6c, 0x75, 0xee, 1490x6e, 0x6f, 0x6e, 0x2d, 0xe4, 0x02, 0x40, 0x73, 0x6f, 0x6c,
1500x00, 0x00, 0xd6, 0x05, 0x08, 0x35, 0x06, 0x04, 0x17, 0x02, 1500x75, 0xee, 0x00, 0x00, 0xd6, 0x05, 0x08, 0x35, 0x06, 0x04,
1510x40, 0x69, 0x6c, 0x6c, 0x75, 0xd9, 0x06, 0x20, 0x74, 0x65, 1510x17, 0x02, 0x40, 0x69, 0x6c, 0x6c, 0x75, 0xd9, 0x06, 0x20,
1520xa6, 0x03, 0x61, 0x69, 0x73, 0x3b, 0x00, 0x69, 0x66, 0x62, 1520x74, 0x65, 0xa6, 0x03, 0x61, 0x69, 0x73, 0x3b, 0x00, 0x69,
1530x02, 0x23, 0x6b, 0x6e, 0x29, 0x02, 0x50, 0x62, 0x6f, 0x61, 1530x66, 0x62, 0x02, 0x23, 0x6b, 0x6e, 0x29, 0x02, 0x50, 0x62,
1540x72, 0x64, 0x12, 0x04, 0x74, 0x74, 0x61, 0x69, 0x6e, 0x73, 1540x6f, 0x61, 0x72, 0x64, 0x12, 0x04, 0x74, 0x74, 0x61, 0x69,
1550x00, 0x35, 0xf6, 0x02, 0x02, 0x78, 0x01, 0x25, 0x69, 0x6d, 1550x6e, 0x73, 0x00, 0x35, 0xf6, 0x02, 0x02, 0x78, 0x01, 0x25,
1560x7a, 0x01, 0x01, 0xbc, 0x07, 0x77, 0x74, 0x65, 0x72, 0x6d, 1560x69, 0x6d, 0x7a, 0x01, 0x01, 0xbc, 0x07, 0x77, 0x74, 0x65,
1570x69, 0x6e, 0x65, 0x8a, 0x03, 0x53, 0x66, 0x69, 0x66, 0x74, 1570x72, 0x6d, 0x69, 0x6e, 0x65, 0x8a, 0x03, 0x53, 0x66, 0x69,
1580x68, 0x8d, 0x05, 0x15, 0x73, 0x30, 0x01, 0x08, 0x81, 0x02, 1580x66, 0x74, 0x68, 0x8d, 0x05, 0x15, 0x73, 0x30, 0x01, 0x08,
1590x63, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0xb7, 0x05, 0x41, 1590x81, 0x02, 0x63, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0xb7,
1600x6e, 0x00, 0x78, 0x29, 0xce, 0x06, 0x03, 0x01, 0x00, 0x0f, 1600x05, 0x41, 0x6e, 0x00, 0x78, 0x29, 0xce, 0x06, 0x05, 0x53,
1610x3f, 0x02, 0x07, 0x11, 0x7c, 0x18, 0x02, 0x15, 0x4f, 0x18, 1610x08, 0x0f, 0x3f, 0x02, 0x05, 0x11, 0x7c, 0x18, 0x02, 0x15,
1620x00, 0x3e, 0x78, 0x78, 0x2e, 0x0c, 0x00, 0x0b, 0x24, 0x00, 1620x4f, 0x18, 0x00, 0x3e, 0x78, 0x78, 0x2e, 0x0c, 0x00, 0x0b,
1630x0e, 0x48, 0x00, 0x08, 0x6a, 0x00, 0x61, 0x00, 0x00, 0x46, 1630x24, 0x00, 0x0f, 0x48, 0x00, 0x01, 0x07, 0xbd, 0x08, 0x51,
1640x6f, 0x72, 0x00, 0x2d, 0x04, 0x70, 0x72, 0x65, 0x61, 0x73, 1640x00, 0x46, 0x6f, 0x72, 0x00, 0x2d, 0x04, 0x70, 0x72, 0x65,
1650x6f, 0x6e, 0x2c, 0xc8, 0x00, 0x16, 0x6e, 0xa9, 0x03, 0x0f, 1650x61, 0x73, 0x6f, 0x6e, 0x2c, 0xc8, 0x00, 0x16, 0x6e, 0xa9,
1660x6f, 0x03, 0x01, 0x11, 0x2c, 0xe6, 0x00, 0x42, 0x67, 0x61, 1660x03, 0x0f, 0x6f, 0x03, 0x01, 0x11, 0x2c, 0xe6, 0x00, 0x42,
1670x6d, 0x65, 0x50, 0x07, 0x01, 0x17, 0x00, 0x02, 0xb5, 0x01, 1670x67, 0x61, 0x6d, 0x65, 0x50, 0x07, 0x01, 0x17, 0x00, 0x02,
1680x01, 0x2f, 0x00, 0x04, 0x82, 0x01, 0x40, 0x00, 0x70, 0x72, 1680xb5, 0x01, 0x01, 0x2f, 0x00, 0x04, 0x82, 0x01, 0x40, 0x00,
1690x6f, 0xda, 0x08, 0xf2, 0x02, 0x73, 0x20, 0x74, 0x68, 0x65, 1690x70, 0x72, 0x6f, 0xda, 0x08, 0xf2, 0x02, 0x73, 0x20, 0x74,
1700x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x72, 0x65, 0x73, 0x75, 1700x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x72, 0x65,
1710x6c, 0x74, 0x62, 0x04, 0xf0, 0x02, 0x68, 0x65, 0x00, 0x63, 1710x73, 0x75, 0x6c, 0x74, 0x62, 0x04, 0xf0, 0x02, 0x68, 0x65,
1720x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x27, 0x73, 0x2c, 1720x00, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x27,
1730x00, 0x72, 0x61, 0x0c, 0x05, 0x02, 0xe2, 0x01, 0x0e, 0x4c, 1730x73, 0x2c, 0x00, 0x72, 0x61, 0x0c, 0x05, 0x02, 0xe2, 0x01,
1740x00, 0x01, 0x7a, 0x01, 0x75, 0x64, 0x65, 0x6e, 0x74, 0x69, 1740x0e, 0x4c, 0x00, 0x01, 0x7a, 0x01, 0x75, 0x64, 0x65, 0x6e,
1750x63, 0x61, 0xea, 0x05, 0x06, 0x3f, 0x00, 0x62, 0x2e, 0x00, 1750x74, 0x69, 0x63, 0x61, 0xea, 0x05, 0x06, 0x3f, 0x00, 0x62,
1760x53, 0x6f, 0x00, 0x69, 0x60, 0x02, 0x01, 0xa8, 0x03, 0x04, 1760x2e, 0x00, 0x53, 0x6f, 0x00, 0x69, 0x60, 0x02, 0x01, 0xa8,
1770x55, 0x02, 0x11, 0x2c, 0xcb, 0x00, 0x11, 0x63, 0x52, 0x06, 1770x03, 0x04, 0x55, 0x02, 0x11, 0x2c, 0xcb, 0x00, 0x11, 0x63,
1780x3c, 0x70, 0x75, 0x74, 0xa0, 0x01, 0x03, 0x68, 0x02, 0x29, 1780x52, 0x06, 0x3c, 0x70, 0x75, 0x74, 0xa0, 0x01, 0x03, 0x68,
1790x6f, 0x66, 0xee, 0x04, 0x0e, 0xa1, 0x01, 0x11, 0x2c, 0xe0, 1790x02, 0x29, 0x6f, 0x66, 0xee, 0x04, 0x0e, 0xa1, 0x01, 0x11,
1800x04, 0x00, 0x4b, 0x00, 0x02, 0x9d, 0x06, 0x20, 0x73, 0x74, 1800x2c, 0xe0, 0x04, 0x00, 0x4b, 0x00, 0x02, 0x9d, 0x06, 0x20,
1810xf9, 0x00, 0x31, 0x77, 0x69, 0x6e, 0x1c, 0x06, 0x00, 0x0e, 1810x73, 0x74, 0xf9, 0x00, 0x31, 0x77, 0x69, 0x6e, 0x1c, 0x06,
1820x0a, 0x81, 0x00, 0x42, 0x6f, 0x78, 0x00, 0x77, 0x61, 0x73, 1820x00, 0x24, 0x0a, 0x81, 0x00, 0x42, 0x6f, 0x78, 0x00, 0x77,
1830x38, 0x02, 0x45, 0x72, 0x69, 0x62, 0x75, 0x41, 0x07, 0x01, 1830x61, 0x73, 0x38, 0x02, 0x45, 0x72, 0x69, 0x62, 0x75, 0x41,
1840x01, 0x07, 0x13, 0x6c, 0x84, 0x03, 0x00, 0xaf, 0x06, 0xd0, 1840x07, 0x01, 0x01, 0x07, 0x13, 0x6c, 0x84, 0x03, 0x00, 0xaf,
1850x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61, 0x72, 0x76, 1850x06, 0xd0, 0x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61,
1860x65, 0x79, 0x2e, 0x50, 0x04, 0x37, 0x39, 0x2e, 0x31, 0x53, 1860x72, 0x76, 0x65, 0x79, 0x2e, 0x50, 0x04, 0x37, 0x39, 0x2e,
1870x0a, 0x01, 0x41, 0x00, 0x30, 0x6f, 0x6c, 0x73, 0x5c, 0x0a, 1870x31, 0x69, 0x0a, 0x01, 0x41, 0x00, 0x90, 0x6f, 0x6c, 0x73,
1880x20, 0x54, 0x6f, 0x00, 0x06, 0x00, 0xe2, 0x02, 0x01, 0xf9, 1880x20, 0x00, 0x00, 0x00, 0x54, 0x6f, 0x00, 0x06, 0x00, 0xe2,
1890x09, 0x01, 0x93, 0x03, 0x11, 0x2c, 0x42, 0x03, 0x62, 0x2d, 1890x02, 0x01, 0xf9, 0x09, 0x01, 0x93, 0x03, 0x11, 0x2c, 0x42,
1900x63, 0x6c, 0x69, 0x63, 0x6b, 0x60, 0x0a, 0x04, 0xe0, 0x07, 1900x03, 0x62, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x60, 0x0a,
1910x55, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x0e, 0x0a, 0x0b, 0x9f, 1910x04, 0xe0, 0x07, 0x55, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x0e,
1920x08, 0x00, 0x0e, 0x03, 0x04, 0x7f, 0x01, 0x01, 0xb7, 0x01, 1920x0a, 0x0b, 0x9f, 0x08, 0x00, 0x0e, 0x03, 0x04, 0x7f, 0x01,
1930xf0, 0x0c, 0x62, 0x65, 0x00, 0x64, 0x69, 0x73, 0x70, 0x6c, 1930x01, 0xb7, 0x01, 0xf0, 0x0c, 0x62, 0x65, 0x00, 0x64, 0x69,
1940x61, 0x79, 0x65, 0x64, 0x00, 0x69, 0x6d, 0x6d, 0x65, 0x64, 1940x73, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x00, 0x69, 0x6d,
1950x69, 0x61, 0x74, 0x65, 0x6c, 0x79, 0x2e, 0x00, 0x43, 0x5b, 1950x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x6c, 0x79, 0x2e,
1960x00, 0x00, 0x34, 0x03, 0x74, 0x6f, 0x72, 0x00, 0x68, 0x6f, 1960x00, 0x43, 0x5b, 0x00, 0x00, 0x34, 0x03, 0x74, 0x6f, 0x72,
1970x6c, 0x64, 0x71, 0x07, 0x01, 0xba, 0x03, 0x03, 0xa5, 0x05, 1970x00, 0x68, 0x6f, 0x6c, 0x64, 0x71, 0x07, 0x01, 0xba, 0x03,
1980x18, 0x6f, 0x9c, 0x09, 0x23, 0x73, 0x65, 0x84, 0x00, 0x03, 1980x03, 0xa5, 0x05, 0x18, 0x6f, 0x9c, 0x09, 0x23, 0x73, 0x65,
1990x5b, 0x00, 0x51, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x73, 0x07, 1990x84, 0x00, 0x03, 0x5b, 0x00, 0x51, 0x68, 0x69, 0x67, 0x68,
2000x01, 0xa7, 0x01, 0xb1, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 2000x6c, 0x73, 0x07, 0x01, 0xa7, 0x01, 0xb1, 0x75, 0x72, 0x72,
2010x00, 0x67, 0x6f, 0x00, 0x28, 0xac, 0x04, 0x30, 0x70, 0x72, 2010x65, 0x6e, 0x74, 0x00, 0x67, 0x6f, 0x00, 0x28, 0xac, 0x04,
2020x65, 0x5a, 0x05, 0x71, 0x73, 0x00, 0x67, 0x6f, 0x29, 0x00, 2020x30, 0x70, 0x72, 0x65, 0x5a, 0x05, 0x71, 0x73, 0x00, 0x67,
2030x74, 0x7d, 0x07, 0x31, 0x66, 0x69, 0x72, 0x62, 0x0a, 0x03, 2030x6f, 0x29, 0x00, 0x74, 0x7d, 0x07, 0x31, 0x66, 0x69, 0x72,
2040x44, 0x06, 0x01, 0xed, 0x06, 0x00, 0xd9, 0x04, 0x01, 0x0a, 2040x62, 0x0a, 0x03, 0x44, 0x06, 0x01, 0xed, 0x06, 0x00, 0xd9,
2050x02, 0x01, 0xfc, 0x00, 0x10, 0x2c, 0xa8, 0x03, 0xb2, 0x61, 2050x04, 0x01, 0x0a, 0x02, 0x01, 0xfc, 0x00, 0x10, 0x2c, 0xa8,
2060x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x62, 0x6c, 0x65, 0x2e, 2060x03, 0xb2, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x62,
2070x1e, 0x01, 0x01, 0x9b, 0x02, 0x0d, 0xab, 0x06, 0x02, 0x11, 2070x6c, 0x65, 0x2e, 0x1e, 0x01, 0x01, 0x9b, 0x02, 0x0d, 0xab,
2080x08, 0x09, 0x29, 0x01, 0x00, 0xcb, 0x01, 0x2b, 0x69, 0x6e, 2080x06, 0x02, 0x11, 0x08, 0x09, 0x29, 0x01, 0x00, 0xcb, 0x01,
2090x1e, 0x0b, 0x31, 0x61, 0x00, 0x62, 0xbc, 0x01, 0x53, 0x63, 2090x2b, 0x69, 0x6e, 0x1e, 0x0b, 0x31, 0x61, 0x00, 0x62, 0xbc,
2100x69, 0x72, 0x63, 0x6c, 0xce, 0x02, 0x03, 0xa2, 0x07, 0x00, 2100x01, 0x53, 0x63, 0x69, 0x72, 0x63, 0x6c, 0xce, 0x02, 0x03,
2110x02, 0x02, 0x04, 0xf8, 0x00, 0x01, 0x65, 0x00, 0x22, 0x3b, 2110xa2, 0x07, 0x00, 0x02, 0x02, 0x04, 0xf8, 0x00, 0x01, 0x65,
2120x00, 0x49, 0x00, 0x52, 0x61, 0x67, 0x61, 0x69, 0x6e, 0x6a, 2120x00, 0x22, 0x3b, 0x00, 0x49, 0x00, 0x52, 0x61, 0x67, 0x61,
2130x05, 0x10, 0x6d, 0x69, 0x02, 0x05, 0x21, 0x00, 0x21, 0x65, 2130x69, 0x6e, 0x6a, 0x05, 0x10, 0x6d, 0x69, 0x02, 0x05, 0x21,
2140x64, 0x76, 0x00, 0x00, 0x99, 0x00, 0x15, 0x4c, 0x49, 0x02, 2140x00, 0x21, 0x65, 0x64, 0x76, 0x00, 0x00, 0x99, 0x00, 0x15,
2150x09, 0x73, 0x00, 0x03, 0x4c, 0x05, 0x20, 0x6c, 0x6f, 0x46, 2150x4c, 0x49, 0x02, 0x09, 0x73, 0x00, 0x03, 0x4c, 0x05, 0x20,
2160x03, 0x02, 0x49, 0x00, 0xb4, 0x73, 0x74, 0x00, 0x6d, 0x6f, 2160x6c, 0x6f, 0x46, 0x03, 0x02, 0x49, 0x00, 0xb4, 0x73, 0x74,
2170x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x1f, 0x02, 0x01, 0xac, 2170x00, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x1f,
2180x08, 0x33, 0x2d, 0x00, 0x63, 0x85, 0x01, 0x50, 0x3b, 0x00, 2180x02, 0x01, 0xac, 0x08, 0x33, 0x2d, 0x00, 0x63, 0x85, 0x01,
2190x77, 0x68, 0x6f, 0xc8, 0x05, 0x31, 0x6f, 0x77, 0x73, 0xb5, 2190x50, 0x3b, 0x00, 0x77, 0x68, 0x6f, 0xc8, 0x05, 0x31, 0x6f,
2200x00, 0x74, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x4e, 2200x77, 0x73, 0xb5, 0x00, 0x74, 0x63, 0x6f, 0x6c, 0x75, 0x6d,
2210x00, 0x06, 0xb9, 0x09, 0x03, 0x58, 0x00, 0x0e, 0x43, 0x00, 2210x6e, 0x73, 0x4e, 0x00, 0x06, 0xb9, 0x09, 0x03, 0x58, 0x00,
2220x04, 0x86, 0x00, 0x02, 0x44, 0x02, 0x04, 0x2e, 0x02, 0x00, 2220x0e, 0x43, 0x00, 0x04, 0x86, 0x00, 0x02, 0x44, 0x02, 0x04,
2230x27, 0x03, 0x62, 0x2f, 0x62, 0x65, 0x6c, 0x6f, 0x77, 0x66, 2230x2e, 0x02, 0x00, 0x27, 0x03, 0x62, 0x2f, 0x62, 0x65, 0x6c,
2240x01, 0x02, 0x58, 0x00, 0x10, 0x2c, 0xf5, 0x01, 0x07, 0xf9, 2240x6f, 0x77, 0x66, 0x01, 0x02, 0x58, 0x00, 0x10, 0x2c, 0xf5,
2250x09, 0x15, 0x2f, 0x3b, 0x09, 0x01, 0x25, 0x00, 0x31, 0x72, 2250x01, 0x07, 0xf9, 0x09, 0x15, 0x2f, 0x3b, 0x09, 0x01, 0x25,
2260x6f, 0x77, 0x7a, 0x01, 0x02, 0xd7, 0x01, 0x72, 0x73, 0x6f, 2260x00, 0x31, 0x72, 0x6f, 0x77, 0x7a, 0x01, 0x02, 0xd7, 0x01,
2270x72, 0x00, 0x6b, 0x65, 0x79, 0x8c, 0x00, 0x01, 0x48, 0x09, 2270x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x8c, 0x00,
2280x52, 0x62, 0x65, 0x00, 0x75, 0x73, 0xfa, 0x02, 0x01, 0x1e, 2280x01, 0x48, 0x09, 0x52, 0x62, 0x65, 0x00, 0x75, 0x73, 0xfa,
2290x01, 0x07, 0x94, 0x02, 0xb4, 0x67, 0x72, 0x69, 0x64, 0x2e, 2290x02, 0x01, 0x1e, 0x01, 0x07, 0x94, 0x02, 0xb4, 0x67, 0x72,
2300x00, 0x50, 0x72, 0x65, 0x73, 0x73, 0x59, 0x01, 0x10, 0x45, 2300x69, 0x64, 0x2e, 0x00, 0x50, 0x72, 0x65, 0x73, 0x73, 0x59,
2310xcf, 0x09, 0x00, 0x42, 0x00, 0x02, 0x7b, 0x01, 0x09, 0xeb, 2310x01, 0x10, 0x45, 0xcf, 0x09, 0x00, 0x42, 0x00, 0x02, 0x7b,
2320x02, 0x00, 0x2a, 0x02, 0x20, 0x64, 0x64, 0xdc, 0x05, 0x21, 2320x01, 0x09, 0xeb, 0x02, 0x00, 0x2a, 0x02, 0x20, 0x64, 0x64,
2330x65, 0x77, 0x59, 0x01, 0x15, 0x2d, 0xe2, 0x01, 0x01, 0x6f, 2330xdc, 0x05, 0x21, 0x65, 0x77, 0x59, 0x01, 0x15, 0x2d, 0xe2,
2340x01, 0x02, 0x93, 0x03, 0x14, 0x70, 0x4f, 0x00, 0x43, 0x53, 2340x01, 0x01, 0x6f, 0x01, 0x02, 0x93, 0x03, 0x14, 0x70, 0x4f,
2350x70, 0x61, 0x63, 0xc2, 0x01, 0x20, 0x6c, 0x6f, 0xa7, 0x01, 2350x00, 0x43, 0x53, 0x70, 0x61, 0x63, 0xc2, 0x01, 0x20, 0x6c,
2360x30, 0x00, 0x63, 0x65, 0x03, 0x02, 0x31, 0x72, 0x6f, 0x77, 2360x6f, 0xa7, 0x01, 0x30, 0x00, 0x63, 0x65, 0x03, 0x02, 0x31,
2370xd3, 0x00, 0x02, 0xde, 0x00, 0x00, 0xbc, 0x00, 0x10, 0x57, 2370x72, 0x6f, 0x77, 0xd3, 0x00, 0x02, 0xde, 0x00, 0x00, 0xbc,
2380xe1, 0x04, 0x11, 0x61, 0x67, 0x08, 0x40, 0x72, 0x6f, 0x70, 2380x00, 0x10, 0x57, 0xe1, 0x04, 0x11, 0x61, 0x67, 0x08, 0x40,
2390x72, 0xf5, 0x02, 0x0d, 0xc2, 0x0d, 0x01, 0xfc, 0x04, 0x44, 2390x72, 0x6f, 0x70, 0x72, 0xf5, 0x02, 0x0d, 0xc2, 0x0d, 0x01,
2400x62, 0x65, 0x65, 0x6e, 0xdb, 0x01, 0x16, 0x2c, 0x9f, 0x08, 2400xfc, 0x04, 0x44, 0x62, 0x65, 0x65, 0x6e, 0xdb, 0x01, 0x16,
2410x08, 0x26, 0x02, 0x03, 0xa4, 0x09, 0x32, 0x74, 0x6f, 0x70, 2410x2c, 0x9f, 0x08, 0x08, 0x26, 0x02, 0x03, 0xa4, 0x09, 0x32,
2420x71, 0x0a, 0x42, 0x63, 0x6f, 0x72, 0x6e, 0x48, 0x00, 0x04, 2420x74, 0x6f, 0x70, 0x71, 0x0a, 0x42, 0x63, 0x6f, 0x72, 0x6e,
2430xf2, 0x00, 0x16, 0x3b, 0x86, 0x01, 0x01, 0x41, 0x01, 0x13, 2430x48, 0x00, 0x04, 0xf2, 0x00, 0x16, 0x3b, 0x86, 0x01, 0x01,
2440x28, 0xcd, 0x06, 0x31, 0x75, 0x73, 0x65, 0x97, 0x00, 0x01, 2440x41, 0x01, 0x13, 0x28, 0xcd, 0x06, 0x31, 0x75, 0x73, 0x65,
2450x45, 0x01, 0x18, 0x29, 0x49, 0x05, 0x08, 0x73, 0x05, 0x00, 2450x97, 0x00, 0x01, 0x45, 0x01, 0x18, 0x29, 0x49, 0x05, 0x08,
2460xb0, 0x00, 0x12, 0x49, 0x9f, 0x06, 0x02, 0x7e, 0x02, 0x01, 2460x73, 0x05, 0x00, 0xb0, 0x00, 0x12, 0x49, 0x9f, 0x06, 0x02,
2470x4c, 0x07, 0x01, 0x28, 0x00, 0x15, 0x27, 0x2f, 0x09, 0x2a, 2470x7e, 0x02, 0x01, 0x4c, 0x07, 0x01, 0x28, 0x00, 0x15, 0x27,
2480x6e, 0x64, 0xa7, 0x05, 0x00, 0xde, 0x01, 0x21, 0x6e, 0x6f, 2480x2f, 0x09, 0x2a, 0x6e, 0x64, 0xa7, 0x05, 0x00, 0xde, 0x01,
2490x8d, 0x00, 0x00, 0x7a, 0x0e, 0x0c, 0xaf, 0x05, 0x00, 0x46, 2490x21, 0x6e, 0x6f, 0x8d, 0x00, 0x00, 0x7a, 0x0e, 0x0c, 0xaf,
2500x08, 0x02, 0x53, 0x09, 0xf2, 0x02, 0x68, 0x65, 0x00, 0x6d, 2500x05, 0x00, 0x46, 0x08, 0x02, 0x53, 0x09, 0xf2, 0x02, 0x68,
2510x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x00, 0x69, 0x6e, 0x66, 2510x65, 0x00, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x00,
2520x6f, 0x72, 0x6d, 0x5f, 0x01, 0x92, 0x6e, 0x65, 0x63, 0x65, 2520x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x01, 0x92, 0x6e,
2530x73, 0x73, 0x61, 0x72, 0x79, 0xe1, 0x06, 0x32, 0x6d, 0x6f, 2530x65, 0x63, 0x65, 0x73, 0x73, 0x61, 0x72, 0x79, 0xe1, 0x06,
2540x6e, 0x30, 0x07, 0x02, 0xcc, 0x04, 0x20, 0x74, 0x6f, 0x3d, 2540x32, 0x6d, 0x6f, 0x6e, 0x30, 0x07, 0x02, 0xcc, 0x04, 0x20,
2550x00, 0x31, 0x2c, 0x00, 0x73, 0x08, 0x00, 0x01, 0x43, 0x09, 2550x74, 0x6f, 0x3d, 0x00, 0x31, 0x2c, 0x00, 0x73, 0x08, 0x00,
2560x01, 0x00, 0x0a, 0x00, 0xce, 0x02, 0x13, 0x2e, 0xad, 0x00, 2560x01, 0x43, 0x09, 0x01, 0x00, 0x0a, 0x00, 0xce, 0x02, 0x13,
2570x12, 0x72, 0x5e, 0x05, 0x06, 0xf1, 0x06, 0x06, 0x93, 0x00, 2570x2e, 0xad, 0x00, 0x12, 0x72, 0x5e, 0x05, 0x06, 0xf1, 0x06,
2580x73, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0xd5, 0x07, 2580x06, 0x93, 0x00, 0x73, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65,
2590x05, 0x6e, 0x09, 0x51, 0x70, 0x61, 0x74, 0x68, 0x73, 0x51, 2590x6e, 0xd5, 0x07, 0x05, 0x6e, 0x09, 0x51, 0x70, 0x61, 0x74,
2600x00, 0x72, 0x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x8f, 2600x68, 0x73, 0x51, 0x00, 0x72, 0x61, 0x6c, 0x72, 0x65, 0x61,
2610x07, 0x61, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x2c, 0x6a, 0x04, 2610x64, 0x79, 0x8f, 0x07, 0x61, 0x61, 0x62, 0x6f, 0x75, 0x74,
2620x05, 0x27, 0x00, 0x05, 0xbe, 0x04, 0x02, 0xb6, 0x03, 0x01, 2620x2c, 0x6a, 0x04, 0x05, 0x27, 0x00, 0x05, 0xbe, 0x04, 0x02,
2630x6c, 0x02, 0x30, 0x69, 0x6e, 0x64, 0x42, 0x03, 0x03, 0x3b, 2630xb6, 0x03, 0x01, 0x6c, 0x02, 0x30, 0x69, 0x6e, 0x64, 0x42,
2640x08, 0x20, 0x69, 0x74, 0x7b, 0x06, 0x32, 0x76, 0x65, 0x73, 2640x03, 0x03, 0x3b, 0x08, 0x20, 0x69, 0x74, 0x7b, 0x06, 0x32,
2650xb2, 0x05, 0x46, 0x72, 0x6f, 0x6e, 0x67, 0x9a, 0x00, 0x08, 2650x76, 0x65, 0x73, 0xb2, 0x05, 0x46, 0x72, 0x6f, 0x6e, 0x67,
2660x86, 0x07, 0x41, 0x74, 0x63, 0x68, 0x00, 0x3a, 0x0c, 0x02, 2660x9a, 0x00, 0x08, 0x86, 0x07, 0x41, 0x74, 0x63, 0x68, 0x00,
2670x79, 0x04, 0x20, 0x73, 0x74, 0xa7, 0x01, 0x07, 0x90, 0x00, 2670x3a, 0x0c, 0x02, 0x79, 0x04, 0x20, 0x73, 0x74, 0xa7, 0x01,
2680x22, 0x62, 0x75, 0xef, 0x0b, 0x03, 0xef, 0x05, 0x00, 0x49, 2680x07, 0x90, 0x00, 0x22, 0x62, 0x75, 0xef, 0x0b, 0x03, 0xef,
2690x00, 0x02, 0x8d, 0x00, 0x01, 0x94, 0x02, 0x0d, 0x91, 0x00, 2690x05, 0x00, 0x49, 0x00, 0x02, 0x8d, 0x00, 0x01, 0x94, 0x02,
2700x60, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x24, 0x09, 0x52, 2700x0d, 0x91, 0x00, 0x60, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c,
2710x77, 0x72, 0x69, 0x74, 0x74, 0xff, 0x0f, 0x43, 0x72, 0x65, 2710x24, 0x09, 0x52, 0x77, 0x72, 0x69, 0x74, 0x74, 0xff, 0x0f,
2720x64, 0x29, 0xd9, 0x0c, 0x2f, 0x69, 0x73, 0x05, 0x01, 0x02, 2720x43, 0x72, 0x65, 0x64, 0x29, 0xd9, 0x0c, 0x2f, 0x69, 0x73,
2730x01, 0x97, 0x00, 0x05, 0x25, 0x05, 0x0d, 0xf9, 0x01, 0x51, 2730x05, 0x01, 0x02, 0x01, 0x97, 0x00, 0x05, 0x25, 0x05, 0x0d,
2740x64, 0x65, 0x63, 0x69, 0x64, 0x6d, 0x08, 0x10, 0x67, 0xd9, 2740xf9, 0x01, 0x51, 0x64, 0x65, 0x63, 0x69, 0x64, 0x6d, 0x08,
2750x09, 0x21, 0x75, 0x70, 0xf8, 0x06, 0x20, 0x6c, 0x65, 0xac, 2750x10, 0x67, 0xd9, 0x09, 0x21, 0x75, 0x70, 0xf8, 0x06, 0x20,
2760x05, 0x15, 0x2c, 0x84, 0x01, 0x20, 0x73, 0x65, 0x62, 0x06, 2760x6c, 0x65, 0xac, 0x05, 0x15, 0x2c, 0x84, 0x01, 0x20, 0x73,
2770x42, 0x00, 0x53, 0x6f, 0x6c, 0x55, 0x10, 0x02, 0x8c, 0x00, 2770x65, 0x62, 0x06, 0x42, 0x00, 0x53, 0x6f, 0x6c, 0x55, 0x10,
2780x02, 0x7d, 0x04, 0x5b, 0x63, 0x74, 0x75, 0x61, 0x6c, 0x93, 2780x02, 0x8c, 0x00, 0x02, 0x7d, 0x04, 0x5b, 0x63, 0x74, 0x75,
2790x01, 0x42, 0x2e, 0x00, 0x41, 0x74, 0xd1, 0x01, 0x01, 0x6d, 2790x61, 0x6c, 0x93, 0x01, 0x42, 0x2e, 0x00, 0x41, 0x74, 0xd1,
2800x05, 0x14, 0x2c, 0x2e, 0x02, 0x33, 0x6c, 0x79, 0x2d, 0x9d, 2800x01, 0x01, 0x6d, 0x05, 0x14, 0x2c, 0x2e, 0x02, 0x33, 0x6c,
2810x0b, 0x02, 0x0a, 0x03, 0x0e, 0x2b, 0x06, 0x60, 0x61, 0x73, 2810x79, 0x2d, 0x9d, 0x0b, 0x02, 0x0a, 0x03, 0x0e, 0x2b, 0x06,
2820x00, 0x66, 0x69, 0x6c, 0xe7, 0x00, 0x08, 0x3d, 0x05, 0x00, 2820x60, 0x61, 0x73, 0x00, 0x66, 0x69, 0x6c, 0xe7, 0x00, 0x08,
2830x20, 0x09, 0x1f, 0x6e, 0x44, 0x00, 0x04, 0x0f, 0x32, 0x00, 2830x3d, 0x05, 0x00, 0x20, 0x09, 0x1f, 0x6e, 0x44, 0x00, 0x04,
2840x04, 0x02, 0xfe, 0x00, 0x00, 0x73, 0x0d, 0x30, 0x63, 0x72, 2840x0f, 0x32, 0x00, 0x04, 0x02, 0xfe, 0x00, 0x00, 0x73, 0x0d,
2850x6f, 0xf5, 0x00, 0x02, 0xd3, 0x03, 0x22, 0x6d, 0x69, 0xd2, 2850x30, 0x63, 0x72, 0x6f, 0xf5, 0x00, 0x02, 0xd3, 0x03, 0x22,
2860x03, 0x0c, 0x3c, 0x00, 0x01, 0x29, 0x00, 0x02, 0x3a, 0x00, 2860x6d, 0x69, 0xd2, 0x03, 0x0c, 0x3c, 0x00, 0x01, 0x29, 0x00,
2870x40, 0x2e, 0x00, 0x49, 0x6e, 0x1e, 0x04, 0x01, 0xcb, 0x00, 2870x02, 0x3a, 0x00, 0x40, 0x2e, 0x00, 0x49, 0x6e, 0x1e, 0x04,
2880x00, 0x9b, 0x03, 0x06, 0x1c, 0x00, 0x01, 0xb9, 0x05, 0x13, 2880x01, 0xcb, 0x00, 0x00, 0x9b, 0x03, 0x06, 0x1c, 0x00, 0x01,
2890x73, 0x3e, 0x0a, 0x00, 0x48, 0x04, 0x02, 0xcb, 0x08, 0x15, 2890xb9, 0x05, 0x13, 0x73, 0x3e, 0x0a, 0x00, 0x48, 0x04, 0x02,
2900x64, 0x58, 0x02, 0x00, 0x65, 0x04, 0x1f, 0x64, 0x91, 0x01, 2900xcb, 0x08, 0x15, 0x64, 0x58, 0x02, 0x00, 0x65, 0x04, 0x1f,
2910x10, 0x01, 0x2f, 0x01, 0x03, 0x81, 0x0a, 0x50, 0x28, 0x6a, 2910x64, 0x91, 0x01, 0x10, 0x01, 0x2f, 0x01, 0x03, 0x81, 0x0a,
2920x75, 0x73, 0x74, 0x8b, 0x00, 0x05, 0x1d, 0x09, 0x01, 0x78, 2920x50, 0x28, 0x6a, 0x75, 0x73, 0x74, 0x8b, 0x00, 0x05, 0x1d,
2930x04, 0x0f, 0x8e, 0x03, 0x00, 0x12, 0x29, 0xc4, 0x00, 0x01, 2930x09, 0x01, 0x78, 0x04, 0x0f, 0x8e, 0x03, 0x00, 0x12, 0x29,
2940x48, 0x0e, 0x3e, 0x65, 0x78, 0x74, 0x8e, 0x00, 0x05, 0x8e, 2940xc4, 0x00, 0x01, 0x48, 0x0e, 0x3e, 0x65, 0x78, 0x74, 0x8e,
2950x08, 0x01, 0x63, 0x04, 0x02, 0x8d, 0x00, 0x00, 0xe8, 0x10, 2950x00, 0x05, 0x8e, 0x08, 0x01, 0x63, 0x04, 0x02, 0x8d, 0x00,
2960x41, 0x72, 0x64, 0x65, 0x72, 0x70, 0x03, 0x02, 0x86, 0x02, 2960x00, 0xe8, 0x10, 0x41, 0x72, 0x64, 0x65, 0x72, 0x70, 0x03,
2970x3e, 0x75, 0x69, 0x73, 0x88, 0x00, 0x05, 0x88, 0x11, 0x04, 2970x02, 0x86, 0x02, 0x3e, 0x75, 0x69, 0x73, 0x88, 0x00, 0x05,
2980xad, 0x01, 0x00, 0x8c, 0x02, 0x00, 0x2a, 0x02, 0x35, 0x28, 2980x88, 0x11, 0x04, 0xad, 0x01, 0x00, 0x8c, 0x02, 0x00, 0x2a,
2990x41, 0x6c, 0xeb, 0x01, 0x01, 0xdb, 0x02, 0x72, 0x64, 0x65, 2990x02, 0x35, 0x28, 0x41, 0x6c, 0xeb, 0x01, 0x01, 0xdb, 0x02,
3000x73, 0x63, 0x72, 0x69, 0x62, 0x5c, 0x00, 0x13, 0x73, 0x7b, 3000x72, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x5c, 0x00,
3010x08, 0x31, 0x32, 0x2e, 0x31, 0xce, 0x02, 0x01, 0xa9, 0x05, 3010x13, 0x73, 0x7b, 0x08, 0x31, 0x32, 0x2e, 0x31, 0xce, 0x02,
3020x51, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x49, 0x07, 0x12, 0x29, 3020x01, 0xa9, 0x05, 0x51, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x49,
3030x83, 0x08, 0x17, 0x32, 0x83, 0x08, 0x50, 0x70, 0x61, 0x72, 3030x07, 0x12, 0x29, 0x83, 0x08, 0x17, 0x32, 0x83, 0x08, 0x50,
3040x61, 0x6d, 0xda, 0x0a, 0x02, 0x85, 0x08, 0x01, 0xe1, 0x07, 3040x70, 0x61, 0x72, 0x61, 0x6d, 0xda, 0x0a, 0x02, 0x85, 0x08,
3050x06, 0x14, 0x00, 0x02, 0x45, 0x00, 0x04, 0x40, 0x00, 0x06, 3050x01, 0xe1, 0x07, 0x06, 0x14, 0x00, 0x02, 0x45, 0x00, 0x04,
3060x95, 0x00, 0xe2, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 3060x40, 0x00, 0x06, 0x95, 0x00, 0xe2, 0x60, 0x43, 0x75, 0x73,
3070x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x8c, 0x07, 0x12, 3070x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70,
3080x6e, 0x1a, 0x00, 0xa1, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 3080x8c, 0x07, 0x12, 0x6e, 0x1a, 0x00, 0xa1, 0x54, 0x79, 0x70,
3090x6d, 0x65, 0x6e, 0x75, 0x82, 0x05, 0x81, 0x69, 0x64, 0x74, 3090x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0x82, 0x05, 0x81,
3100x68, 0x2c, 0x00, 0x48, 0x65, 0x5b, 0x06, 0x51, 0x00, 0x00, 3100x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x5b, 0x06,
3110x53, 0x69, 0x7a, 0x4a, 0x08, 0x00, 0x30, 0x05, 0x01, 0xb1, 3110x51, 0x00, 0x00, 0x53, 0x69, 0x7a, 0x4a, 0x08, 0x00, 0x30,
3120x00, 0x02, 0x4c, 0x08, 0x01, 0xb4, 0x08, 0x21, 0x72, 0x65, 3120x05, 0x01, 0xb1, 0x00, 0x02, 0x4c, 0x08, 0x01, 0xb4, 0x08,
3130x6f, 0x00, 0x32, 0x32, 0x00, 0x78, 0x37, 0x00, 0x24, 0x00, 3130x21, 0x72, 0x65, 0x6f, 0x00, 0x32, 0x32, 0x00, 0x78, 0x37,
3140x78, 0x38, 0x00, 0x04, 0x0b, 0x13, 0x21, 0x65, 0x72, 0x39, 3140x00, 0x24, 0x00, 0x78, 0x38, 0x00, 0x04, 0x0b, 0x13, 0x21,
3150x00, 0x51, 0x2c, 0x00, 0x74, 0x77, 0x6f, 0x0e, 0x00, 0x32, 3150x65, 0x72, 0x39, 0x00, 0x51, 0x2c, 0x00, 0x74, 0x77, 0x6f,
3160x72, 0x6f, 0x77, 0x29, 0x0f, 0x03, 0x10, 0x00, 0x06, 0xfb, 3160x0e, 0x00, 0x32, 0x72, 0x6f, 0x77, 0x29, 0x0f, 0x03, 0x10,
3170x05, 0x72, 0x4e, 0x6f, 0x2e, 0x20, 0x6f, 0x66, 0x20, 0x5a, 3170x00, 0x06, 0xfb, 0x05, 0x72, 0x4e, 0x6f, 0x2e, 0x20, 0x6f,
3180x02, 0x3b, 0x00, 0x00, 0x4e, 0xf6, 0x05, 0x23, 0x74, 0x6f, 3180x66, 0x20, 0x5a, 0x02, 0x3b, 0x00, 0x00, 0x4e, 0xf6, 0x05,
3190x09, 0x0f, 0x27, 0x69, 0x6e, 0xb2, 0x06, 0x01, 0x1d, 0x12, 3190x23, 0x74, 0x6f, 0x09, 0x0f, 0x27, 0x69, 0x6e, 0xb2, 0x06,
3200x00, 0x63, 0x03, 0x10, 0x62, 0x9d, 0x06, 0x00, 0x9b, 0x02, 3200x01, 0x1d, 0x12, 0x00, 0x63, 0x03, 0x10, 0x62, 0x9d, 0x06,
3210x14, 0x6c, 0x31, 0x06, 0x11, 0x2c, 0xa6, 0x06, 0x00, 0x0d, 3210x00, 0x9b, 0x02, 0x14, 0x6c, 0x31, 0x06, 0x11, 0x2c, 0xa6,
3220x12, 0x20, 0x67, 0x65, 0x4a, 0x0d, 0x00, 0x24, 0x01, 0x15, 3220x06, 0x00, 0x0d, 0x12, 0x20, 0x67, 0x65, 0x4a, 0x0d, 0x00,
3230x74, 0x38, 0x0a, 0xf3, 0x04, 0x00, 0x68, 0x79, 0x70, 0x68, 3230x24, 0x01, 0x15, 0x74, 0x38, 0x0a, 0xf3, 0x04, 0x00, 0x68,
3240x65, 0x6e, 0x2c, 0x00, 0x6c, 0x69, 0x6b, 0x65, 0x00, 0x60, 3240x79, 0x70, 0x68, 0x65, 0x6e, 0x2c, 0x00, 0x6c, 0x69, 0x6b,
3250x32, 0x2d, 0x36, 0x27, 0x1f, 0x02, 0x05, 0x36, 0x0c, 0x02, 3250x65, 0x00, 0x60, 0x32, 0x2d, 0x36, 0x27, 0x1f, 0x02, 0x05,
3260x43, 0x02, 0x1f, 0x6e, 0x88, 0x00, 0x05, 0x1a, 0x6f, 0x88, 3260x36, 0x0c, 0x02, 0x43, 0x02, 0x1f, 0x6e, 0x88, 0x00, 0x05,
3270x00, 0x01, 0x96, 0x10, 0x00, 0xd7, 0x03, 0x05, 0xfc, 0x05, 3270x1a, 0x6f, 0x88, 0x00, 0x01, 0x96, 0x10, 0x00, 0xd7, 0x03,
3280x72, 0x69, 0x73, 0x00, 0x6f, 0x6e, 0x6c, 0x79, 0x2b, 0x0f, 3280x05, 0xfc, 0x05, 0x72, 0x69, 0x73, 0x00, 0x6f, 0x6e, 0x6c,
3290x00, 0xee, 0x01, 0x16, 0x66, 0xbb, 0x0b, 0x04, 0x95, 0x08, 3290x79, 0x2b, 0x0f, 0x00, 0xee, 0x01, 0x16, 0x66, 0xbb, 0x0b,
3300x0f, 0xeb, 0x06, 0x0b, 0x33, 0x3b, 0x00, 0x61, 0x45, 0x09, 3300x04, 0x95, 0x08, 0x0f, 0xeb, 0x06, 0x0b, 0x33, 0x3b, 0x00,
3310x11, 0x75, 0x76, 0x03, 0x00, 0x40, 0x0f, 0x31, 0x66, 0x66, 3310x61, 0x45, 0x09, 0x11, 0x75, 0x76, 0x03, 0x00, 0x40, 0x0f,
3320x65, 0x8c, 0x04, 0x03, 0x2b, 0x00, 0x03, 0x0e, 0x08, 0x02, 3320x31, 0x66, 0x66, 0x65, 0x8c, 0x04, 0x03, 0x2b, 0x00, 0x03,
3330xfa, 0x13, 0x29, 0x61, 0x6c, 0x94, 0x0b, 0x02, 0x1a, 0x05, 3330x0e, 0x08, 0x02, 0xfa, 0x13, 0x29, 0x61, 0x6c, 0x94, 0x0b,
3340x60, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x83, 0x00, 0x02, 3340x02, 0x1a, 0x05, 0x60, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74,
3350xa6, 0x09, 0x26, 0x6c, 0x6c, 0xda, 0x05, 0x62, 0x69, 0x6e, 3350x83, 0x00, 0x02, 0xa6, 0x09, 0x26, 0x6c, 0x6c, 0xda, 0x05,
3360x70, 0x75, 0x74, 0x73, 0x8d, 0x14, 0x21, 0x75, 0x74, 0x0c, 3360x62, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x8d, 0x14, 0x21,
3370x00, 0x70, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x2e, 0x00, 3370x75, 0x74, 0x0c, 0x00, 0x70, 0x6d, 0x61, 0x74, 0x63, 0x68,
3380x2e, 0x00,
338}; 339};
339 340
340const unsigned short help_text_len = 5458; 341const unsigned short help_text_len = 5480;
341const unsigned short help_text_words = 1015; 342const unsigned short help_text_words = 1016;
342const char quick_help_text[] = "Find the hidden balls in the box by bouncing laser beams off them."; 343const char quick_help_text[] = "Find the hidden balls in the box by bouncing laser beams off them.";
diff --git a/apps/plugins/puzzles/help/bridges.c b/apps/plugins/puzzles/help/bridges.c
index be4469b5ac..bd01c53426 100644
--- a/apps/plugins/puzzles/help/bridges.c
+++ b/apps/plugins/puzzles/help/bridges.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,336 +6,356 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 180, TEXT_CENTER | C_RED }, 9 { 178, TEXT_CENTER | C_RED },
10 { 312, TEXT_UNDERLINE }, 10 { 310, TEXT_UNDERLINE },
11 { 737, TEXT_CENTER | C_RED }, 11 { 763, TEXT_CENTER | C_RED },
12 { 754, TEXT_UNDERLINE }, 12 { 780, TEXT_UNDERLINE },
13 { 755, TEXT_UNDERLINE }, 13 { 781, TEXT_UNDERLINE },
14 { 765, TEXT_UNDERLINE }, 14 { 791, TEXT_UNDERLINE },
15 { 774, TEXT_UNDERLINE }, 15 { 800, TEXT_UNDERLINE },
16 { 813, TEXT_UNDERLINE }, 16 { 839, TEXT_UNDERLINE },
17 { 845, TEXT_UNDERLINE }, 17 { 871, TEXT_UNDERLINE },
18 { 880, TEXT_UNDERLINE }, 18 { 906, TEXT_UNDERLINE },
19 { 991, TEXT_CENTER | C_RED },
19 LAST_STYLE_ITEM 20 LAST_STYLE_ITEM
20}; 21};
21 22
22/* orig 5230 comp 3126 ratio 0.597706 level 10 saved 2104 */ 23/* orig 5613 comp 3312 ratio 0.590059 level 10 saved 2301 */
23const char help_text[] = { 24const char help_text[] = {
240xf3, 0x4b, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 250xfe, 0x07, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
250x32, 0x36, 0x3a, 0x20, 0x42, 0x72, 0x69, 0x64, 0x67, 0x65, 260x32, 0x36, 0x3a, 0x20, 0x42, 0x72, 0x69, 0x64, 0x67, 0x65,
260x73, 0x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 270x73, 0x20, 0x00, 0x2d, 0x01, 0x00, 0xf3, 0x37, 0x00, 0x00,
270x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x73, 0x65, 0x74, 0x00, 280x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00,
280x6f, 0x66, 0x00, 0x69, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 290x61, 0x00, 0x73, 0x65, 0x74, 0x00, 0x6f, 0x66, 0x00, 0x69,
290x00, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 300x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x00, 0x64, 0x69, 0x73,
300x65, 0x64, 0x00, 0x61, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x00, 310x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x00, 0x61,
310x74, 0x68, 0x65, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x69, 0x6e, 320x63, 0x72, 0x6f, 0x73, 0x73, 0x00, 0x74, 0x68, 0x65, 0x00,
320x67, 0x00, 0x61, 0x72, 0x65, 0x61, 0x2e, 0x00, 0x45, 0x61, 330x70, 0x6c, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x00, 0x61, 0x72,
330x63, 0x68, 0x32, 0x00, 0xf0, 0x04, 0x00, 0x63, 0x6f, 0x6e, 340x65, 0x61, 0x2e, 0x00, 0x45, 0x61, 0x63, 0x68, 0x32, 0x00,
340x74, 0x61, 0x69, 0x6e, 0x73, 0x00, 0x61, 0x00, 0x6e, 0x75, 350xf0, 0x04, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
350x6d, 0x62, 0x65, 0x72, 0x2e, 0x5e, 0x00, 0xb0, 0x72, 0x00, 360x73, 0x00, 0x61, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
360x61, 0x69, 0x6d, 0x00, 0x69, 0x73, 0x00, 0x74, 0x6f, 0x22, 370x2e, 0x5e, 0x00, 0xb0, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00,
370x00, 0x41, 0x6e, 0x65, 0x63, 0x74, 0x48, 0x00, 0x04, 0x67, 380x69, 0x73, 0x00, 0x74, 0x6f, 0x22, 0x00, 0x41, 0x6e, 0x65,
380x00, 0xf2, 0x00, 0x74, 0x6f, 0x67, 0x65, 0x74, 0x68, 0x65, 390x63, 0x74, 0x48, 0x00, 0x04, 0x67, 0x00, 0xf2, 0x00, 0x74,
390x72, 0x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x62, 0x9a, 0x00, 400x6f, 0x67, 0x65, 0x74, 0x68, 0x65, 0x72, 0x00, 0x77, 0x69,
400xf3, 0x0b, 0x2c, 0x00, 0x69, 0x6e, 0x00, 0x73, 0x75, 0x63, 410x74, 0x68, 0x00, 0x62, 0xae, 0x00, 0xf3, 0x0b, 0x2c, 0x00,
410x68, 0x00, 0x61, 0x00, 0x77, 0x61, 0x79, 0x00, 0x74, 0x68, 420x69, 0x6e, 0x00, 0x73, 0x75, 0x63, 0x68, 0x00, 0x61, 0x00,
420x61, 0x74, 0x3a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0xbb, 0x00, 430x77, 0x61, 0x79, 0x00, 0x74, 0x68, 0x61, 0x74, 0x3a, 0x00,
430xa0, 0x00, 0x72, 0x75, 0x6e, 0x00, 0x68, 0x6f, 0x72, 0x69, 440x00, 0x00, 0x2d, 0x00, 0xcf, 0x00, 0xa0, 0x00, 0x72, 0x75,
440x7a, 0x75, 0x00, 0xd0, 0x6c, 0x6c, 0x79, 0x00, 0x6f, 0x72, 450x6e, 0x00, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x75, 0x00, 0xd0,
450x00, 0x76, 0x65, 0x72, 0x74, 0x69, 0x63, 0x0e, 0x00, 0x11, 460x6c, 0x6c, 0x79, 0x00, 0x6f, 0x72, 0x00, 0x76, 0x65, 0x72,
460x2e, 0x2c, 0x00, 0x33, 0x54, 0x68, 0x65, 0x8a, 0x00, 0x00, 470x74, 0x69, 0x63, 0x0e, 0x00, 0x11, 0x2e, 0x2c, 0x00, 0x33,
470xd8, 0x00, 0x13, 0x62, 0x3a, 0x00, 0x81, 0x74, 0x65, 0x72, 480x54, 0x68, 0x65, 0x8a, 0x00, 0x00, 0xd8, 0x00, 0x13, 0x62,
480x6d, 0x69, 0x6e, 0x61, 0x74, 0xc5, 0x00, 0x54, 0x74, 0x00, 490x3a, 0x00, 0x81, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61,
490x61, 0x6e, 0x79, 0xc1, 0x00, 0x80, 0x69, 0x73, 0x00, 0x65, 500x74, 0xc5, 0x00, 0x54, 0x74, 0x00, 0x61, 0x6e, 0x79, 0xc1,
500x71, 0x75, 0x61, 0x6c, 0xab, 0x00, 0x16, 0x74, 0x3c, 0x00, 510x00, 0x80, 0x69, 0x73, 0x00, 0x65, 0x71, 0x75, 0x61, 0x6c,
510x70, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x93, 0x00, 520xab, 0x00, 0x16, 0x74, 0x3c, 0x00, 0x70, 0x77, 0x72, 0x69,
520x00, 0x88, 0x00, 0x03, 0x2e, 0x00, 0x03, 0x63, 0x00, 0x25, 530x74, 0x74, 0x65, 0x6e, 0x93, 0x00, 0x00, 0x88, 0x00, 0x03,
530x77, 0x6f, 0x59, 0x00, 0x31, 0x6d, 0x61, 0x79, 0x97, 0x00, 540x2e, 0x00, 0x03, 0x63, 0x00, 0x25, 0x77, 0x6f, 0x59, 0x00,
540xf1, 0x04, 0x69, 0x6e, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6c, 550x31, 0x6d, 0x61, 0x79, 0x97, 0x00, 0xf1, 0x04, 0x69, 0x6e,
550x6c, 0x65, 0x6c, 0x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 560x00, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x00,
560x6e, 0x4f, 0x00, 0x84, 0x73, 0x61, 0x6d, 0x65, 0x00, 0x74, 570x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x4f, 0x00, 0x84,
570x77, 0x6f, 0xfb, 0x00, 0xd0, 0x2c, 0x00, 0x62, 0x75, 0x74, 580x73, 0x61, 0x6d, 0x65, 0x00, 0x74, 0x77, 0x6f, 0xfb, 0x00,
580x00, 0x6e, 0x6f, 0x00, 0x6d, 0x6f, 0x72, 0x65, 0x5b, 0x00, 590xd0, 0x2c, 0x00, 0x62, 0x75, 0x74, 0x00, 0x6e, 0x6f, 0x00,
590x11, 0x6e, 0x1e, 0x00, 0x00, 0x47, 0x00, 0x52, 0x64, 0x6f, 600x6d, 0x6f, 0x72, 0x65, 0x5b, 0x00, 0x11, 0x6e, 0x1e, 0x00,
600x00, 0x73, 0x6f, 0x62, 0x00, 0x14, 0x4e, 0x61, 0x00, 0x11, 610x00, 0x47, 0x00, 0x52, 0x64, 0x6f, 0x00, 0x73, 0x6f, 0x62,
610x00, 0x84, 0x01, 0x61, 0x65, 0x73, 0x00, 0x61, 0x6e, 0x6f, 620x00, 0x14, 0x4e, 0x61, 0x00, 0x11, 0x00, 0x84, 0x01, 0x61,
620x31, 0x01, 0x02, 0x17, 0x00, 0x02, 0x26, 0x00, 0x39, 0x41, 630x65, 0x73, 0x00, 0x61, 0x6e, 0x6f, 0x31, 0x01, 0x02, 0x17,
630x6c, 0x6c, 0x56, 0x01, 0x34, 0x61, 0x72, 0x65, 0x6e, 0x01, 640x00, 0x02, 0x26, 0x00, 0x39, 0x41, 0x6c, 0x6c, 0x56, 0x01,
640x25, 0x65, 0x64, 0x64, 0x01, 0x00, 0x2c, 0x00, 0x51, 0x54, 650x34, 0x61, 0x72, 0x65, 0x6e, 0x01, 0x25, 0x65, 0x64, 0x64,
650x68, 0x65, 0x72, 0x65, 0x20, 0x00, 0x31, 0x73, 0x6f, 0x6d, 660x01, 0x00, 0x2c, 0x00, 0x51, 0x54, 0x68, 0x65, 0x72, 0x65,
660x25, 0x00, 0xf0, 0x00, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 670x20, 0x00, 0x31, 0x73, 0x6f, 0x6d, 0x25, 0x00, 0xf0, 0x00,
670x62, 0x6c, 0x65, 0x00, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x1b, 680x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x00,
680x01, 0x60, 0x76, 0x65, 0x00, 0x6d, 0x6f, 0x64, 0x88, 0x01, 690x61, 0x6c, 0x74, 0x65, 0x72, 0x1b, 0x01, 0x60, 0x76, 0x65,
690x30, 0x77, 0x68, 0x69, 0xe2, 0x01, 0xc0, 0x6e, 0x76, 0x6f, 700x00, 0x6d, 0x6f, 0x64, 0x88, 0x01, 0x30, 0x77, 0x68, 0x69,
700x6c, 0x76, 0x65, 0x00, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x39, 710xe2, 0x01, 0xc0, 0x6e, 0x76, 0x6f, 0x6c, 0x76, 0x65, 0x00,
710x01, 0x01, 0x0a, 0x02, 0x03, 0xe5, 0x00, 0x13, 0x2d, 0xa0, 720x63, 0x68, 0x61, 0x6e, 0x67, 0x39, 0x01, 0x01, 0x0a, 0x02,
720x00, 0x50, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x3c, 0x01, 0x00, 730x03, 0xe5, 0x00, 0x13, 0x2d, 0xa0, 0x00, 0x50, 0x6c, 0x69,
730x59, 0x00, 0x20, 0x74, 0x68, 0x27, 0x00, 0x02, 0xa9, 0x00, 740x6d, 0x69, 0x74, 0x3c, 0x01, 0x00, 0x59, 0x00, 0x20, 0x74,
740x01, 0xdb, 0x00, 0x31, 0x32, 0x2c, 0x00, 0x64, 0x01, 0x74, 750x68, 0x27, 0x00, 0x02, 0xa9, 0x00, 0x01, 0xdb, 0x00, 0x31,
750x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x45, 0x00, 0xa0, 760x32, 0x2c, 0x00, 0x64, 0x01, 0x74, 0x6e, 0x74, 0x72, 0x6f,
760x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 770x64, 0x75, 0x63, 0x45, 0x00, 0xa0, 0x61, 0x64, 0x64, 0x69,
770x8b, 0x00, 0x72, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 780x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x8b, 0x00, 0x72, 0x73,
780x68, 0x01, 0xb8, 0x6e, 0x6f, 0x00, 0x73, 0x65, 0x71, 0x75, 790x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x68, 0x01, 0xb8, 0x6e,
790x65, 0x6e, 0x63, 0x65, 0xc0, 0x01, 0x00, 0x20, 0x01, 0xf4, 800x6f, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65,
800x05, 0x66, 0x6f, 0x72, 0x6d, 0x00, 0x61, 0x00, 0x6c, 0x6f, 810xc0, 0x01, 0x00, 0x20, 0x01, 0xf4, 0x05, 0x66, 0x6f, 0x72,
810x6f, 0x70, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x00, 0x6f, 0x6e, 820x6d, 0x00, 0x61, 0x00, 0x6c, 0x6f, 0x6f, 0x70, 0x00, 0x66,
820x65, 0xc6, 0x01, 0x44, 0x62, 0x61, 0x63, 0x6b, 0xc2, 0x01, 830x72, 0x6f, 0x6d, 0x00, 0x6f, 0x6e, 0x65, 0xc6, 0x01, 0x44,
830x01, 0x73, 0x01, 0x04, 0xb0, 0x01, 0x00, 0x0f, 0x02, 0x91, 840x62, 0x61, 0x63, 0x6b, 0xc2, 0x01, 0x01, 0x73, 0x01, 0x04,
840x72, 0x75, 0x6c, 0x65, 0x73, 0x00, 0x73, 0x74, 0x61, 0xd6, 850xb0, 0x01, 0x00, 0x0f, 0x02, 0x91, 0x72, 0x75, 0x6c, 0x65,
850x02, 0x32, 0x62, 0x6f, 0x76, 0x0b, 0x01, 0x00, 0x2c, 0x00, 860x73, 0x00, 0x73, 0x74, 0x61, 0xd6, 0x02, 0x32, 0x62, 0x6f,
860x70, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4b, 0x00, 870x76, 0x0b, 0x01, 0x00, 0x2c, 0x00, 0x70, 0x64, 0x65, 0x66,
870x10, 0x73, 0x29, 0x01, 0x60, 0x43, 0x72, 0x65, 0x64, 0x69, 880x61, 0x75, 0x6c, 0x74, 0x4b, 0x00, 0x10, 0x73, 0x29, 0x01,
880x74, 0x6b, 0x00, 0xf1, 0x01, 0x00, 0x74, 0x68, 0x69, 0x73, 890x60, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x6b, 0x00, 0xf1,
890x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x67, 0x6f, 900x01, 0x00, 0x74, 0x68, 0x69, 0x73, 0x00, 0x70, 0x75, 0x7a,
900x65, 0xcc, 0x02, 0xb0, 0x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69, 910x7a, 0x6c, 0x65, 0x00, 0x67, 0x6f, 0x65, 0xcc, 0x02, 0xb0,
910x00, 0x5b, 0x31, 0x32, 0x5d, 0x2e, 0x00, 0x04, 0x98, 0x02, 920x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69, 0x00, 0x5b, 0x31, 0x32,
920x31, 0x77, 0x61, 0x73, 0x09, 0x03, 0x04, 0x3a, 0x03, 0x01, 930x5d, 0x2e, 0x00, 0x04, 0x98, 0x02, 0x31, 0x77, 0x61, 0x73,
930x89, 0x00, 0x10, 0x69, 0x14, 0x00, 0x40, 0x6c, 0x6c, 0x65, 940x09, 0x03, 0x04, 0x3a, 0x03, 0x01, 0x89, 0x00, 0x10, 0x69,
940x63, 0xea, 0x00, 0xf1, 0x00, 0x00, 0x62, 0x79, 0x00, 0x4a, 950x14, 0x00, 0x40, 0x6c, 0x6c, 0x65, 0x63, 0xea, 0x00, 0xf1,
950x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61, 0x72, 0x76, 0x65, 960x00, 0x00, 0x62, 0x79, 0x00, 0x4a, 0x61, 0x6d, 0x65, 0x73,
960xac, 0x02, 0x00, 0x46, 0x00, 0xd1, 0x00, 0x68, 0x74, 0x74, 970x00, 0x48, 0x61, 0x72, 0x76, 0x65, 0xac, 0x02, 0x00, 0x46,
970x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 0x5d, 980x00, 0xe1, 0x00, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f,
980x00, 0xa2, 0x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f, 0x65, 990x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 0x5e, 0x00, 0xa2, 0x2e,
990x6e, 0x2f, 0x7c, 0x00, 0xf1, 0x0c, 0x73, 0x2f, 0x68, 0x61, 1000x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f, 0x65, 0x6e, 0x2f, 0x7d,
1000x73, 0x68, 0x69, 0x77, 0x6f, 0x6b, 0x61, 0x6b, 0x65, 0x72, 1010x00, 0xf5, 0x08, 0x73, 0x2f, 0x48, 0x61, 0x73, 0x68, 0x69,
1010x6f, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x00, 0x28, 0x62, 0x65, 1020x77, 0x6f, 0x6b, 0x61, 0x6b, 0x65, 0x72, 0x6f, 0x2f, 0x00,
1020x77, 0x61, 0x72, 0x22, 0x01, 0xd5, 0x46, 0x6c, 0x61, 0x73, 1030x00, 0x00, 0x32, 0x36, 0x2e, 0x31, 0xe4, 0x03, 0x01, 0x79,
1030x68, 0x29, 0x00, 0x00, 0x00, 0x32, 0x36, 0x2e, 0x31, 0xe5, 1040x00, 0x40, 0x6f, 0x6c, 0x73, 0x20, 0xe8, 0x01, 0x10, 0x6f,
1040x03, 0x01, 0x8e, 0x00, 0x21, 0x6f, 0x6c, 0xee, 0x03, 0x20, 1050xab, 0x03, 0x10, 0x63, 0xd9, 0x03, 0x03, 0xa0, 0x01, 0x05,
1050x54, 0x6f, 0xc0, 0x03, 0x10, 0x63, 0xee, 0x03, 0x03, 0xb5, 1060x8c, 0x02, 0x08, 0x83, 0x02, 0x30, 0x63, 0x6c, 0x69, 0x2f,
1060x01, 0x05, 0xa1, 0x02, 0x08, 0x98, 0x02, 0x30, 0x63, 0x6c, 1070x01, 0x10, 0x68, 0xf1, 0x01, 0xb8, 0x75, 0x73, 0x65, 0x00,
1070x69, 0x44, 0x01, 0x10, 0x68, 0x06, 0x02, 0xb8, 0x75, 0x73, 1080x64, 0x6f, 0x77, 0x6e, 0x00, 0x6f, 0x6e, 0x51, 0x01, 0x00,
1080x65, 0x00, 0x64, 0x6f, 0x77, 0x6e, 0x00, 0x6f, 0x6e, 0x66, 1090x04, 0x00, 0x51, 0x64, 0x72, 0x61, 0x67, 0x00, 0xde, 0x01,
1090x01, 0x00, 0x04, 0x00, 0x51, 0x64, 0x72, 0x61, 0x67, 0x00, 1100x42, 0x77, 0x61, 0x72, 0x64, 0x0a, 0x04, 0x01, 0xdd, 0x01,
1100xf3, 0x01, 0x42, 0x77, 0x61, 0x72, 0x64, 0x1f, 0x04, 0x01, 1110x01, 0xe4, 0x03, 0x00, 0xb0, 0x02, 0x62, 0x6e, 0x6f, 0x74,
1110xf2, 0x01, 0x01, 0xf9, 0x03, 0x00, 0xc5, 0x02, 0x62, 0x6e, 1120x00, 0x6e, 0x65, 0xf2, 0x00, 0x01, 0x2e, 0x00, 0x13, 0x61,
1120x6f, 0x74, 0x00, 0x6e, 0x65, 0x07, 0x01, 0x01, 0x2e, 0x00, 1130x93, 0x02, 0x01, 0xc0, 0x03, 0x16, 0x6f, 0x32, 0x00, 0x03,
1130x13, 0x61, 0xa8, 0x02, 0x01, 0xd5, 0x03, 0x16, 0x6f, 0x32, 1140x57, 0x00, 0xa5, 0x3b, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x6f,
1140x00, 0x03, 0x57, 0x00, 0xa5, 0x3b, 0x00, 0x79, 0x6f, 0x75, 1150x6e, 0x6c, 0x79, 0x37, 0x00, 0x10, 0x6d, 0x8f, 0x01, 0x06,
1150x00, 0x6f, 0x6e, 0x6c, 0x79, 0x37, 0x00, 0x10, 0x6d, 0xa4, 1160x8b, 0x00, 0xa3, 0x66, 0x61, 0x72, 0x00, 0x65, 0x6e, 0x6f,
1160x01, 0x06, 0x8b, 0x00, 0xa3, 0x66, 0x61, 0x72, 0x00, 0x65, 1170x75, 0x67, 0x68, 0x85, 0x01, 0x10, 0x65, 0x3e, 0x02, 0x54,
1170x6e, 0x6f, 0x75, 0x67, 0x68, 0x9a, 0x01, 0x10, 0x65, 0x53, 1180x65, 0x6e, 0x64, 0x65, 0x64, 0xd3, 0x00, 0x33, 0x64, 0x69,
1180x02, 0x54, 0x65, 0x6e, 0x64, 0x65, 0x64, 0xd3, 0x00, 0x33, 1190x72, 0x55, 0x01, 0xf1, 0x07, 0x74, 0x6f, 0x00, 0x62, 0x65,
1190x64, 0x69, 0x72, 0x6a, 0x01, 0xf1, 0x07, 0x74, 0x6f, 0x00, 1200x00, 0x75, 0x6e, 0x61, 0x6d, 0x62, 0x69, 0x67, 0x75, 0x6f,
1200x62, 0x65, 0x00, 0x75, 0x6e, 0x61, 0x6d, 0x62, 0x69, 0x67, 1210x75, 0x73, 0x2e, 0x00, 0x28, 0x53, 0x6f, 0x64, 0x00, 0x87,
1210x75, 0x6f, 0x75, 0x73, 0x2e, 0x00, 0x28, 0x53, 0x6f, 0x64, 1220x63, 0x61, 0x6e, 0x00, 0x6b, 0x65, 0x65, 0x70, 0x5b, 0x00,
1220x00, 0x87, 0x63, 0x61, 0x6e, 0x00, 0x6b, 0x65, 0x65, 0x70, 1230x42, 0x6e, 0x65, 0x61, 0x72, 0x21, 0x02, 0x31, 0x74, 0x61,
1230x5b, 0x00, 0x42, 0x6e, 0x65, 0x61, 0x72, 0x36, 0x02, 0x31, 1240x72, 0x0a, 0x04, 0x07, 0xec, 0x00, 0xb0, 0x63, 0x6f, 0x6e,
1240x74, 0x61, 0x72, 0x1f, 0x04, 0x07, 0xec, 0x00, 0xb0, 0x63, 1250x76, 0x65, 0x6e, 0x69, 0x65, 0x6e, 0x74, 0x6c, 0x7a, 0x04,
1250x6f, 0x6e, 0x76, 0x65, 0x6e, 0x69, 0x65, 0x6e, 0x74, 0x6c, 1260x35, 0x72, 0x6f, 0x77, 0x7c, 0x02, 0x32, 0x6f, 0x75, 0x74,
1260x8f, 0x04, 0x35, 0x72, 0x6f, 0x77, 0x91, 0x02, 0x32, 0x6f, 1270x70, 0x02, 0x20, 0x69, 0x74, 0xe7, 0x03, 0x10, 0x6d, 0x3d,
1270x75, 0x74, 0x85, 0x02, 0x20, 0x69, 0x74, 0xfc, 0x03, 0x10, 1280x04, 0x05, 0x84, 0x00, 0x82, 0x73, 0x2e, 0x29, 0x00, 0x00,
1280x6d, 0x52, 0x04, 0x05, 0x84, 0x00, 0x20, 0x73, 0x2e, 0x91, 1290x00, 0x44, 0x6f, 0xdb, 0x02, 0xd6, 0x69, 0x73, 0x00, 0x61,
1290x01, 0x22, 0x44, 0x6f, 0xf0, 0x02, 0xd6, 0x69, 0x73, 0x00, 1300x67, 0x61, 0x69, 0x6e, 0x00, 0x77, 0x68, 0x65, 0x6e, 0x85,
1300x61, 0x67, 0x61, 0x69, 0x6e, 0x00, 0x77, 0x68, 0x65, 0x6e, 1310x01, 0x00, 0x17, 0x00, 0xf0, 0x04, 0x6c, 0x72, 0x65, 0x61,
1310x85, 0x01, 0x00, 0x17, 0x00, 0xf0, 0x04, 0x6c, 0x72, 0x65, 1320x64, 0x79, 0x00, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74,
1320x61, 0x64, 0x79, 0x00, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 1330x00, 0x77, 0x69, 0x6c, 0x6c, 0x08, 0x03, 0x05, 0xd9, 0x03,
1330x74, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0x1d, 0x03, 0x05, 0xee, 1340x06, 0x3e, 0x04, 0x03, 0xe2, 0x03, 0x45, 0x49, 0x66, 0x00,
1340x03, 0x06, 0x53, 0x04, 0x03, 0xf7, 0x03, 0x45, 0x49, 0x66, 1350x74, 0xb7, 0x03, 0x04, 0x3f, 0x00, 0x22, 0x61, 0x73, 0x80,
1350x00, 0x74, 0xcc, 0x03, 0x04, 0x3f, 0x00, 0x22, 0x61, 0x73, 1360x00, 0x04, 0x9c, 0x00, 0x08, 0x6b, 0x04, 0x07, 0xe3, 0x01,
1360x80, 0x00, 0x04, 0x9c, 0x00, 0x08, 0x80, 0x04, 0x07, 0xe3, 1370x00, 0x28, 0x00, 0x10, 0x70, 0xf3, 0x04, 0x20, 0x74, 0x74,
1370x01, 0x00, 0x28, 0x00, 0x10, 0x70, 0x08, 0x05, 0x20, 0x74, 1380x38, 0x01, 0x11, 0x79, 0x20, 0x00, 0x40, 0x63, 0x75, 0x72,
1380x74, 0x38, 0x01, 0x11, 0x79, 0x20, 0x00, 0x40, 0x63, 0x75, 1390x72, 0x7b, 0x00, 0x34, 0x67, 0x61, 0x6d, 0x14, 0x03, 0x51,
1390x72, 0x72, 0x7b, 0x00, 0x34, 0x67, 0x61, 0x6d, 0x29, 0x03, 1400x28, 0x69, 0x2e, 0x65, 0x2e, 0x39, 0x00, 0x24, 0x62, 0x79,
1400x51, 0x28, 0x69, 0x2e, 0x65, 0x2e, 0x39, 0x00, 0x24, 0x62, 1410x0c, 0x03, 0x26, 0x29, 0x2c, 0x46, 0x03, 0x00, 0xd4, 0x01,
1410x79, 0x21, 0x03, 0x26, 0x29, 0x2c, 0x5b, 0x03, 0x00, 0xd4, 1420x11, 0x67, 0x34, 0x05, 0x02, 0x71, 0x01, 0x01, 0xb6, 0x00,
1420x01, 0x11, 0x67, 0x49, 0x05, 0x02, 0x71, 0x01, 0x01, 0xb6, 1430x21, 0x72, 0x65, 0xb4, 0x01, 0x00, 0xeb, 0x01, 0x11, 0x6f,
1430x00, 0x21, 0x72, 0x65, 0xb4, 0x01, 0x00, 0xeb, 0x01, 0x11, 1440xa4, 0x00, 0x10, 0x6d, 0xce, 0x02, 0x21, 0x49, 0x66, 0x78,
1440x6f, 0xa4, 0x00, 0x10, 0x6d, 0xe3, 0x02, 0x21, 0x49, 0x66, 1450x01, 0x31, 0x77, 0x61, 0x6e, 0x0f, 0x04, 0x60, 0x72, 0x65,
1450x78, 0x01, 0x31, 0x77, 0x61, 0x6e, 0x24, 0x04, 0x60, 0x72, 1460x6d, 0x69, 0x6e, 0x64, 0x13, 0x00, 0x52, 0x72, 0x73, 0x65,
1460x65, 0x6d, 0x69, 0x6e, 0x64, 0x13, 0x00, 0x52, 0x72, 0x73, 1470x6c, 0x66, 0xdd, 0x03, 0x08, 0xa2, 0x00, 0x90, 0x64, 0x65,
1470x65, 0x6c, 0x66, 0xf2, 0x03, 0x08, 0xa2, 0x00, 0x90, 0x64, 1480x66, 0x69, 0x6e, 0x69, 0x74, 0x65, 0x6c, 0xf9, 0x04, 0x10,
1480x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x65, 0x6c, 0x0e, 0x05, 1490x20, 0x49, 0x02, 0x03, 0x92, 0x06, 0x0c, 0xb9, 0x02, 0x45,
1490x10, 0x20, 0x49, 0x02, 0x03, 0xa7, 0x06, 0x0c, 0xb9, 0x02, 1500x68, 0x65, 0x6d, 0x2c, 0xd3, 0x01, 0x61, 0x72, 0x69, 0x67,
1500x45, 0x68, 0x65, 0x6d, 0x2c, 0xd3, 0x01, 0x61, 0x72, 0x69, 1510x68, 0x74, 0x2d, 0x6b, 0x02, 0x08, 0x21, 0x00, 0x27, 0x00,
1510x67, 0x68, 0x74, 0x2d, 0x6b, 0x02, 0x08, 0x21, 0x00, 0x27, 1520x69, 0x6e, 0x05, 0x03, 0x7c, 0x02, 0xb3, 0x64, 0x72, 0x61,
1520x00, 0x69, 0x83, 0x05, 0x03, 0x7c, 0x02, 0xb3, 0x64, 0x72, 1530x77, 0x00, 0x61, 0x00, 0x60, 0x6e, 0x6f, 0x6e, 0xad, 0x04,
1530x61, 0x77, 0x00, 0x61, 0x00, 0x60, 0x6e, 0x6f, 0x6e, 0xc2, 1540x87, 0x27, 0x00, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x72, 0xaf,
1540x04, 0x87, 0x27, 0x00, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x72, 1550x00, 0x00, 0xb2, 0x04, 0x34, 0x6b, 0x00, 0x79, 0x10, 0x07,
1550xaf, 0x00, 0x00, 0xc7, 0x04, 0x34, 0x6b, 0x00, 0x79, 0x25, 1560x00, 0x93, 0x00, 0x42, 0x73, 0x68, 0x65, 0x64, 0x98, 0x06,
1560x07, 0x00, 0x93, 0x00, 0x42, 0x73, 0x68, 0x65, 0x64, 0xad, 1570x24, 0x61, 0x6e, 0x22, 0x02, 0x02, 0x28, 0x01, 0x05, 0x27,
1570x06, 0x24, 0x61, 0x6e, 0x22, 0x02, 0x02, 0x28, 0x01, 0x05, 1580x00, 0x01, 0x64, 0x03, 0x11, 0x64, 0x02, 0x01, 0x35, 0x69,
1580x27, 0x00, 0x01, 0x64, 0x03, 0x11, 0x64, 0x02, 0x01, 0x35, 1590x74, 0x73, 0x8d, 0x01, 0x01, 0x4c, 0x02, 0x13, 0x72, 0x5f,
1590x69, 0x74, 0x73, 0x8d, 0x01, 0x01, 0x4c, 0x02, 0x13, 0x72, 1600x05, 0x24, 0x64, 0x65, 0xd3, 0x04, 0x41, 0x74, 0x68, 0x65,
1600x74, 0x05, 0x24, 0x64, 0x65, 0xe8, 0x04, 0x41, 0x74, 0x68, 1610x79, 0x18, 0x00, 0x03, 0xa5, 0x00, 0x01, 0xc4, 0x00, 0x02,
1610x65, 0x79, 0x18, 0x00, 0x03, 0xa5, 0x00, 0x01, 0xc4, 0x00, 1620x44, 0x00, 0x26, 0x73, 0x29, 0xdb, 0x00, 0x00, 0x9c, 0x00,
1620x02, 0x44, 0x00, 0x26, 0x73, 0x29, 0xdb, 0x00, 0x00, 0x9c, 1630x07, 0xcf, 0x05, 0x00, 0xc3, 0x01, 0x05, 0x8f, 0x00, 0x81,
1630x00, 0x07, 0xe4, 0x05, 0x00, 0xc3, 0x01, 0x05, 0x8f, 0x00, 1640x62, 0x79, 0x00, 0x6c, 0x65, 0x66, 0x74, 0x2d, 0xb9, 0x03,
1640x81, 0x62, 0x79, 0x00, 0x6c, 0x65, 0x66, 0x74, 0x2d, 0xb9, 1650x01, 0x64, 0x05, 0x40, 0x6e, 0x00, 0x69, 0x74, 0xde, 0x04,
1650x03, 0x01, 0x79, 0x05, 0x40, 0x6e, 0x00, 0x69, 0x74, 0xf3, 1660x22, 0x69, 0x73, 0x95, 0x01, 0x51, 0x68, 0x69, 0x67, 0x68,
1660x04, 0x22, 0x69, 0x73, 0x95, 0x01, 0x51, 0x68, 0x69, 0x67, 1670x6c, 0x59, 0x00, 0x22, 0x69, 0x74, 0x89, 0x00, 0x03, 0x8a,
1670x68, 0x6c, 0x59, 0x00, 0x22, 0x69, 0x74, 0x89, 0x00, 0x03, 1680x03, 0x04, 0x9d, 0x00, 0x08, 0x19, 0x06, 0x32, 0x00, 0x69,
1680x8a, 0x03, 0x04, 0x9d, 0x00, 0x08, 0x2e, 0x06, 0x32, 0x00, 1690x74, 0x99, 0x05, 0x01, 0xb2, 0x01, 0x20, 0x69, 0x6c, 0xb3,
1690x69, 0x74, 0xae, 0x05, 0x01, 0xb2, 0x01, 0x20, 0x69, 0x6c, 1700x06, 0x00, 0x9a, 0x02, 0x30, 0x76, 0x65, 0x6e, 0x21, 0x00,
1700xc8, 0x06, 0x00, 0x9a, 0x02, 0x30, 0x76, 0x65, 0x6e, 0x21, 1710x01, 0xed, 0x02, 0x31, 0x61, 0x63, 0x63, 0xc4, 0x00, 0x01,
1710x00, 0x01, 0xed, 0x02, 0x31, 0x61, 0x63, 0x63, 0xc4, 0x00, 1720x68, 0x07, 0x52, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x02, 0x08,
1720x01, 0x7d, 0x07, 0x52, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x17, 1730x22, 0x6e, 0x79, 0xf6, 0x01, 0x26, 0x6f, 0x73, 0x5c, 0x00,
1730x08, 0x22, 0x6e, 0x79, 0xf6, 0x01, 0x26, 0x6f, 0x73, 0x5c, 1740xc9, 0x69, 0x6e, 0x00, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65,
1740x00, 0xc9, 0x69, 0x6e, 0x00, 0x66, 0x75, 0x74, 0x75, 0x72, 1750x2e, 0x00, 0x4c, 0xa7, 0x00, 0x02, 0x0d, 0x03, 0x10, 0x6f,
1750x65, 0x2e, 0x00, 0x4c, 0xa7, 0x00, 0x02, 0x0d, 0x03, 0x10, 1760x0b, 0x03, 0x05, 0xa1, 0x00, 0x24, 0x65, 0x64, 0xe2, 0x00,
1760x6f, 0x0b, 0x03, 0x05, 0xa1, 0x00, 0x24, 0x65, 0x64, 0xe2, 1770x01, 0x7a, 0x00, 0x21, 0x75, 0x6e, 0xf9, 0x00, 0x03, 0xb6,
1770x00, 0x01, 0x7a, 0x00, 0x21, 0x75, 0x6e, 0xf9, 0x00, 0x03, 1780x00, 0x40, 0x72, 0x65, 0x73, 0x74, 0x19, 0x07, 0x11, 0x79,
1780xb6, 0x00, 0x40, 0x72, 0x65, 0x73, 0x74, 0x2e, 0x07, 0x11, 1790x44, 0x08, 0x51, 0x62, 0x69, 0x6c, 0x69, 0x74, 0xcd, 0x01,
1790x79, 0x59, 0x08, 0x51, 0x62, 0x69, 0x6c, 0x69, 0x74, 0xcd, 1800x02, 0x81, 0x00, 0x01, 0xf4, 0x00, 0x02, 0xbf, 0x08, 0x00,
1800x01, 0x02, 0x81, 0x00, 0x01, 0xf4, 0x00, 0x02, 0xd4, 0x08, 1810x32, 0x01, 0x50, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0xda, 0x03,
1810x00, 0x32, 0x01, 0x50, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0xda, 1820x03, 0xde, 0x02, 0x85, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65,
1820x03, 0x03, 0xde, 0x02, 0x85, 0x73, 0x6f, 0x72, 0x00, 0x6b, 1830x79, 0x73, 0x57, 0x04, 0x61, 0x61, 0x72, 0x6f, 0x75, 0x6e,
1830x65, 0x79, 0x73, 0x57, 0x04, 0x61, 0x61, 0x72, 0x6f, 0x75, 1840x64, 0x1f, 0x00, 0xf9, 0x01, 0x67, 0x72, 0x69, 0x64, 0x3a,
1840x6e, 0x64, 0x1f, 0x00, 0xf9, 0x01, 0x67, 0x72, 0x69, 0x64, 1850x00, 0x69, 0x66, 0x00, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62,
1850x3a, 0x00, 0x69, 0x66, 0x00, 0x70, 0x6f, 0x73, 0x73, 0x69, 1860x6c, 0x35, 0x00, 0x02, 0x8d, 0x03, 0x52, 0x6c, 0x77, 0x61,
1860x62, 0x6c, 0x35, 0x00, 0x02, 0x8d, 0x03, 0x52, 0x6c, 0x77, 1870x79, 0x73, 0x39, 0x00, 0x80, 0x6f, 0x72, 0x74, 0x68, 0x6f,
1870x61, 0x79, 0x73, 0x39, 0x00, 0x80, 0x6f, 0x72, 0x74, 0x68, 1880x67, 0x6f, 0x6e, 0xfd, 0x00, 0x12, 0x2c, 0xc2, 0x04, 0x63,
1880x6f, 0x67, 0x6f, 0x6e, 0xfd, 0x00, 0x12, 0x2c, 0xc2, 0x04, 1890x77, 0x69, 0x73, 0x65, 0x00, 0x69, 0xb9, 0x03, 0x02, 0xb5,
1890x63, 0x77, 0x69, 0x73, 0x65, 0x00, 0x69, 0xb9, 0x03, 0x02, 1900x04, 0x07, 0x17, 0x05, 0x00, 0x5c, 0x04, 0x24, 0x65, 0x73,
1900xb5, 0x04, 0x07, 0x17, 0x05, 0x00, 0x5c, 0x04, 0x24, 0x65, 1910x27, 0x08, 0x04, 0xfb, 0x04, 0x51, 0x69, 0x6e, 0x64, 0x69,
1910x73, 0x3c, 0x08, 0x04, 0xfb, 0x04, 0x51, 0x69, 0x6e, 0x64, 1920x63, 0x76, 0x06, 0x05, 0x30, 0x04, 0x60, 0x2e, 0x00, 0x48,
1920x69, 0x63, 0x8b, 0x06, 0x05, 0x30, 0x04, 0x60, 0x2e, 0x00, 1930x6f, 0x6c, 0x64, 0x1c, 0x01, 0x12, 0x43, 0xb8, 0x05, 0x01,
1930x48, 0x6f, 0x6c, 0x64, 0x1c, 0x01, 0x12, 0x43, 0xb8, 0x05, 1940xf7, 0x00, 0x00, 0x16, 0x04, 0x11, 0x73, 0x31, 0x01, 0x07,
1940x01, 0xf7, 0x00, 0x00, 0x16, 0x04, 0x11, 0x73, 0x31, 0x01, 1950xc8, 0x00, 0x02, 0x6b, 0x00, 0x37, 0x6c, 0x61, 0x79, 0x49,
1950x07, 0xc8, 0x00, 0x02, 0x6b, 0x00, 0x37, 0x6c, 0x61, 0x79, 1960x04, 0x03, 0x8e, 0x08, 0x06, 0x03, 0x05, 0x90, 0x28, 0x69,
1960x49, 0x04, 0x03, 0xa3, 0x08, 0x06, 0x03, 0x05, 0x90, 0x28, 1970x66, 0x00, 0x61, 0x76, 0x61, 0x69, 0x6c, 0xcc, 0x07, 0x73,
1970x69, 0x66, 0x00, 0x61, 0x76, 0x61, 0x69, 0x6c, 0xe1, 0x07, 1980x29, 0x3b, 0x00, 0x53, 0x68, 0x69, 0x66, 0x01, 0x02, 0x0f,
1980x73, 0x29, 0x3b, 0x00, 0x53, 0x68, 0x69, 0x66, 0x01, 0x02, 1990x4b, 0x00, 0x04, 0x01, 0x11, 0x03, 0x1c, 0x00, 0x12, 0x03,
1990x0f, 0x4b, 0x00, 0x04, 0x01, 0x11, 0x03, 0x1c, 0x00, 0x12, 2000x14, 0x50, 0x82, 0x00, 0x01, 0xa2, 0x02, 0x40, 0x65, 0x74,
2000x03, 0x14, 0x50, 0x82, 0x00, 0x01, 0xa2, 0x02, 0x40, 0x65, 2010x75, 0x72, 0x40, 0x05, 0x00, 0x75, 0x07, 0x42, 0x6c, 0x6c,
2010x74, 0x75, 0x72, 0x40, 0x05, 0x00, 0x8a, 0x07, 0x42, 0x6c, 2020x6f, 0x77, 0x83, 0x02, 0x0e, 0x52, 0x00, 0x01, 0x82, 0x01,
2020x6c, 0x6f, 0x77, 0x83, 0x02, 0x0e, 0x52, 0x00, 0x01, 0x82, 2030x0f, 0xa2, 0x00, 0x0b, 0x08, 0xb1, 0x01, 0x01, 0xea, 0x01,
2030x01, 0x0f, 0xa2, 0x00, 0x0b, 0x08, 0xb1, 0x01, 0x01, 0xea, 2040x2f, 0x61, 0x6e, 0xe2, 0x02, 0x04, 0x18, 0x70, 0x83, 0x00,
2040x01, 0x2f, 0x61, 0x6e, 0xe2, 0x02, 0x04, 0x18, 0x70, 0x83, 2050x20, 0x73, 0x70, 0xc7, 0x06, 0x30, 0x62, 0x61, 0x72, 0xe4,
2050x00, 0x20, 0x73, 0x70, 0xc7, 0x06, 0x30, 0x62, 0x61, 0x72, 2060x09, 0x0c, 0x1d, 0x00, 0x07, 0xa0, 0x00, 0x51, 0x74, 0x77,
2060xf9, 0x09, 0x0c, 0x1d, 0x00, 0x07, 0xa0, 0x00, 0x51, 0x74, 2070x69, 0x63, 0x65, 0x8c, 0x07, 0x07, 0x24, 0x00, 0x04, 0x8c,
2070x77, 0x69, 0x63, 0x65, 0xa1, 0x07, 0x07, 0x24, 0x00, 0x04, 2080x0a, 0x00, 0x22, 0x00, 0x06, 0x61, 0x03, 0x45, 0x6a, 0x75,
2080xa1, 0x0a, 0x00, 0x22, 0x00, 0x06, 0x61, 0x03, 0x45, 0x6a, 2090x6d, 0x70, 0xe6, 0x09, 0x0a, 0xb0, 0x01, 0x01, 0xef, 0x03,
2090x75, 0x6d, 0x70, 0xfb, 0x09, 0x0a, 0xb0, 0x01, 0x01, 0xef, 2100x02, 0x80, 0x08, 0x03, 0xc5, 0x0a, 0xf0, 0x0c, 0x4c, 0x65,
2100x03, 0x02, 0x95, 0x08, 0x03, 0xda, 0x0a, 0xf0, 0x0c, 0x4c, 2110x74, 0x74, 0x65, 0x72, 0x73, 0x00, 0x60, 0x61, 0x27, 0x2c,
2110x65, 0x74, 0x74, 0x65, 0x72, 0x73, 0x00, 0x60, 0x61, 0x27, 2120x00, 0x2e, 0x2e, 0x2e, 0x2c, 0x00, 0x60, 0x66, 0x27, 0x00,
2120x2c, 0x00, 0x2e, 0x2e, 0x2e, 0x2c, 0x00, 0x60, 0x66, 0x27, 2130x63, 0x6f, 0x75, 0x6e, 0x74, 0xb8, 0x00, 0x23, 0x31, 0x30,
2130x00, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0xb8, 0x00, 0x23, 0x31, 2140x16, 0x00, 0x21, 0x31, 0x35, 0x6d, 0x01, 0x31, 0x60, 0x30,
2140x30, 0x16, 0x00, 0x21, 0x31, 0x35, 0x6d, 0x01, 0x31, 0x60, 2150x27, 0x17, 0x00, 0x13, 0x36, 0x6e, 0x09, 0x46, 0x00, 0x60,
2150x30, 0x27, 0x17, 0x00, 0x10, 0x36, 0x8b, 0x00, 0x51, 0x56, 2160x47, 0x27, 0x27, 0x01, 0x03, 0x8b, 0x04, 0x86, 0x67, 0x72,
2160x69, 0x6f, 0x6c, 0x61, 0x1d, 0x06, 0x03, 0x21, 0x05, 0x04, 2170x65, 0x79, 0x00, 0x6c, 0x69, 0x6e, 0xdd, 0x04, 0x10, 0x65,
2170x5c, 0x08, 0x02, 0x75, 0x05, 0x04, 0x71, 0x03, 0x01, 0x7b, 2180x4a, 0x0b, 0x48, 0x70, 0x61, 0x69, 0x72, 0x84, 0x0b, 0x01,
2180x01, 0x10, 0x64, 0x32, 0x01, 0x42, 0x72, 0x65, 0x64, 0x3a, 2190x88, 0x00, 0x78, 0x63, 0x6f, 0x75, 0x6c, 0x64, 0x00, 0x62,
2190xe7, 0x09, 0x1a, 0x6e, 0x92, 0x00, 0x2a, 0x6f, 0x6f, 0xef, 2200xd1, 0x09, 0x02, 0x94, 0x04, 0x04, 0x69, 0x01, 0x36, 0x6f,
2200x05, 0x04, 0x3b, 0x00, 0x09, 0x4d, 0x03, 0x01, 0x40, 0x00, 2210x72, 0x00, 0xda, 0x04, 0x01, 0x55, 0x0a, 0x25, 0x61, 0x72,
2210x1f, 0x2e, 0x40, 0x00, 0x05, 0x3f, 0x66, 0x65, 0x77, 0x3f, 2220xe4, 0x05, 0x00, 0x60, 0x07, 0x11, 0x6f, 0x2c, 0x03, 0x51,
2220x00, 0x10, 0x00, 0x1a, 0x03, 0x00, 0xdf, 0x06, 0x09, 0x98, 2230x56, 0x69, 0x6f, 0x6c, 0x61, 0xa9, 0x06, 0x03, 0xad, 0x05,
2230x05, 0xf3, 0x03, 0x61, 0x6e, 0x00, 0x65, 0x72, 0x72, 0x6f, 2240x04, 0xd3, 0x08, 0x02, 0x01, 0x06, 0x04, 0xfd, 0x03, 0x01,
2240x72, 0x00, 0x28, 0x61, 0x73, 0x00, 0x6f, 0x70, 0x70, 0x6f, 2250x07, 0x02, 0x10, 0x64, 0xbe, 0x01, 0x42, 0x72, 0x65, 0x64,
2250x73, 0xb3, 0x07, 0x20, 0x65, 0x72, 0x1f, 0x00, 0x00, 0xb4, 2260x3a, 0x5e, 0x0a, 0x1a, 0x6e, 0x1e, 0x01, 0x2a, 0x6f, 0x6f,
2260x05, 0x20, 0x62, 0x65, 0x70, 0x01, 0x05, 0xc6, 0x01, 0x41, 2270x7b, 0x06, 0x04, 0x3b, 0x00, 0x09, 0xd9, 0x03, 0x01, 0x40,
2270x79, 0x65, 0x74, 0x29, 0x66, 0x03, 0x21, 0x61, 0x64, 0xe4, 2280x00, 0x1f, 0x2e, 0x40, 0x00, 0x05, 0x3f, 0x66, 0x65, 0x77,
2280x02, 0x03, 0xca, 0x07, 0x05, 0x80, 0x00, 0x45, 0x6f, 0x75, 2290x3f, 0x00, 0x10, 0x00, 0xa6, 0x03, 0x00, 0x6b, 0x07, 0x09,
2290x6c, 0x64, 0x6d, 0x0a, 0x31, 0x68, 0x61, 0x76, 0xd1, 0x01, 2300x24, 0x06, 0xf3, 0x03, 0x61, 0x6e, 0x00, 0x65, 0x72, 0x72,
2300x12, 0x6f, 0xfa, 0x0a, 0x0b, 0xf8, 0x0a, 0x00, 0xf8, 0x01, 2310x6f, 0x72, 0x00, 0x28, 0x61, 0x73, 0x00, 0x6f, 0x70, 0x70,
2310x04, 0x6a, 0x06, 0x16, 0x00, 0xc4, 0x05, 0x03, 0xb1, 0x02, 2320x6f, 0x73, 0x3f, 0x08, 0x32, 0x65, 0x72, 0x65, 0xee, 0x00,
2320x10, 0x2c, 0x1f, 0x00, 0x28, 0x69, 0x66, 0x30, 0x05, 0x20, 2330x30, 0x00, 0x62, 0x65, 0xfc, 0x01, 0x05, 0x52, 0x02, 0x41,
2330x68, 0x61, 0x0f, 0x07, 0x29, 0x65, 0x6e, 0xde, 0x00, 0x01, 2340x79, 0x65, 0x74, 0x29, 0xf2, 0x03, 0x21, 0x61, 0x64, 0x70,
2340xae, 0x09, 0x54, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x49, 0x0b, 2350x03, 0x03, 0x56, 0x08, 0x05, 0x80, 0x00, 0x01, 0x61, 0x01,
2350x68, 0x00, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x09, 0x0d, 0x01, 2360x04, 0xe4, 0x0a, 0x31, 0x68, 0x61, 0x76, 0x5d, 0x02, 0x12,
2360x55, 0x0a, 0x07, 0x7d, 0x0a, 0x0f, 0x21, 0x01, 0x0c, 0x41, 2370x6f, 0x71, 0x0b, 0x0b, 0x6f, 0x0b, 0x00, 0x6d, 0x01, 0x04,
2370x61, 0x00, 0x63, 0x6c, 0x0a, 0x01, 0x33, 0x73, 0x75, 0x62, 2380xf6, 0x06, 0x08, 0x76, 0x01, 0x02, 0x3d, 0x03, 0x10, 0x2c,
2380x53, 0x0d, 0x07, 0xe3, 0x01, 0x01, 0x78, 0x01, 0x24, 0x6e, 2390x1f, 0x00, 0x28, 0x69, 0x66, 0xbc, 0x05, 0x20, 0x68, 0x61,
2390x6f, 0x85, 0x06, 0x04, 0x12, 0x0d, 0x02, 0x39, 0x0b, 0x02, 2400x9b, 0x07, 0x29, 0x65, 0x6e, 0xde, 0x00, 0x01, 0x25, 0x0a,
2400xbc, 0x02, 0x15, 0x73, 0x34, 0x00, 0x03, 0x82, 0x00, 0x90, 2410x54, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0xc0, 0x0b, 0x68, 0x00,
2410x2e, 0x00, 0x46, 0x6f, 0x72, 0x00, 0x65, 0x78, 0x61, 0xa9, 2420x67, 0x72, 0x6f, 0x75, 0x70, 0xfc, 0x01, 0x01, 0xcc, 0x0a,
2420x00, 0x32, 0x2c, 0x00, 0x69, 0x9b, 0x06, 0x02, 0x42, 0x03, 2430x07, 0xf4, 0x0a, 0x0f, 0x21, 0x01, 0x0c, 0x41, 0x61, 0x00,
2430x26, 0x6c, 0x79, 0x56, 0x0d, 0x4c, 0x77, 0x6f, 0x00, 0x31, 2440x63, 0x6c, 0x0a, 0x01, 0x33, 0x73, 0x75, 0x62, 0xca, 0x0d,
2440x51, 0x0d, 0x05, 0x79, 0x03, 0x01, 0x77, 0x04, 0x04, 0x6a, 2450x07, 0xe3, 0x01, 0x01, 0x78, 0x01, 0x24, 0x6e, 0x6f, 0x11,
2450x06, 0x22, 0x6e, 0x6f, 0x85, 0x0d, 0x01, 0x6a, 0x09, 0x08, 2460x07, 0x04, 0x89, 0x0d, 0x02, 0xb0, 0x0b, 0x02, 0x48, 0x03,
2460x76, 0x07, 0x25, 0x6f, 0x6e, 0x0e, 0x05, 0x01, 0xe7, 0x07, 2470x15, 0x73, 0x34, 0x00, 0x03, 0x82, 0x00, 0x90, 0x2e, 0x00,
2470x04, 0x1a, 0x04, 0x01, 0x3a, 0x06, 0x43, 0x75, 0x70, 0x00, 2480x46, 0x6f, 0x72, 0x00, 0x65, 0x78, 0x61, 0xa9, 0x00, 0x32,
2480x72, 0x20, 0x06, 0x03, 0xb9, 0x04, 0x02, 0x14, 0x03, 0x03, 2490x2c, 0x00, 0x69, 0x27, 0x07, 0x02, 0xce, 0x03, 0x26, 0x6c,
2490xa9, 0x0d, 0x02, 0x39, 0x01, 0x32, 0x63, 0x61, 0x6e, 0xf9, 2500x79, 0xcd, 0x0d, 0x4c, 0x77, 0x6f, 0x00, 0x31, 0xc8, 0x0d,
2500x01, 0x04, 0x10, 0x0e, 0x02, 0x23, 0x01, 0x00, 0xa6, 0x02, 2510x05, 0x9c, 0x02, 0x01, 0x03, 0x05, 0x04, 0xf6, 0x06, 0x22,
2510xa4, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x00, 0x73, 0x6f, 0x6c, 2520x6e, 0x6f, 0xfc, 0x0d, 0x01, 0xf6, 0x09, 0x08, 0x02, 0x08,
2520x75, 0xf9, 0x03, 0x14, 0x2d, 0x68, 0x07, 0x01, 0x37, 0x07, 2530x25, 0x6f, 0x6e, 0x9a, 0x05, 0x01, 0x73, 0x08, 0x04, 0xa6,
2530x33, 0x73, 0x65, 0x6c, 0x82, 0x06, 0x40, 0x68, 0x65, 0x00, 2540x04, 0x01, 0xc6, 0x06, 0x43, 0x75, 0x70, 0x00, 0x72, 0xac,
2540x28, 0xd4, 0x01, 0x04, 0x73, 0x08, 0x34, 0x00, 0x6f, 0x70, 2550x06, 0x03, 0x45, 0x05, 0x02, 0x18, 0x03, 0x03, 0x20, 0x0e,
2550xd1, 0x09, 0x40, 0x64, 0x69, 0x73, 0x61, 0x73, 0x04, 0x01, 2560x02, 0x39, 0x01, 0x32, 0x63, 0x61, 0x6e, 0xf9, 0x01, 0x04,
2560xfd, 0x0b, 0x15, 0x73, 0xd9, 0x07, 0x03, 0x55, 0x00, 0x15, 2570x87, 0x0e, 0x02, 0x23, 0x01, 0x00, 0xa6, 0x02, 0xa4, 0x76,
2570x2c, 0x88, 0x00, 0x07, 0x32, 0x0c, 0x02, 0xc4, 0x0c, 0x00, 2580x61, 0x6c, 0x69, 0x64, 0x00, 0x73, 0x6f, 0x6c, 0x75, 0x85,
2580x34, 0x0c, 0x14, 0x73, 0x35, 0x0c, 0x0e, 0xea, 0x02, 0x01, 2590x04, 0x14, 0x2d, 0xf4, 0x07, 0x01, 0xc3, 0x07, 0x33, 0x73,
2590x22, 0x03, 0x14, 0x28, 0x48, 0x0d, 0x02, 0xd0, 0x08, 0x00, 2600x65, 0x6c, 0x0e, 0x07, 0x40, 0x68, 0x65, 0x00, 0x28, 0xd4,
2600xee, 0x02, 0x52, 0x73, 0x63, 0x72, 0x69, 0x62, 0xc4, 0x00, 2610x01, 0x04, 0xff, 0x08, 0x34, 0x00, 0x6f, 0x70, 0x5d, 0x0a,
2610x13, 0x73, 0x54, 0x05, 0x33, 0x32, 0x2e, 0x31, 0x75, 0x09, 2620x40, 0x64, 0x69, 0x73, 0x61, 0xff, 0x04, 0x01, 0x74, 0x0c,
2620x26, 0x73, 0x6f, 0x5d, 0x05, 0x13, 0x2e, 0x7a, 0x0b, 0x15, 2630x15, 0x73, 0x65, 0x08, 0x03, 0x55, 0x00, 0x15, 0x2c, 0x88,
2630x32, 0x7a, 0x0b, 0x00, 0xb3, 0x09, 0x20, 0x6d, 0x65, 0x27, 2640x00, 0x07, 0xa9, 0x0c, 0x02, 0x3b, 0x0d, 0x00, 0xab, 0x0c,
2640x04, 0x12, 0x20, 0x79, 0x0d, 0x36, 0x73, 0x65, 0x00, 0x14, 2650x14, 0x73, 0xac, 0x0c, 0x0e, 0xea, 0x02, 0x01, 0x22, 0x03,
2650x00, 0x02, 0x43, 0x00, 0x04, 0x3e, 0x00, 0x02, 0x55, 0x07, 2660x14, 0x28, 0xbf, 0x0d, 0x02, 0x5c, 0x09, 0x00, 0xee, 0x02,
2660x00, 0x7b, 0x00, 0xb4, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 2670x52, 0x73, 0x63, 0x72, 0x69, 0x62, 0xc4, 0x00, 0x13, 0x73,
2670x6d, 0x2e, 0x2e, 0x2e, 0x27, 0xf7, 0x00, 0x03, 0x96, 0x01, 2680xe0, 0x05, 0x33, 0x32, 0x2e, 0x31, 0x01, 0x0a, 0x26, 0x73,
2680x40, 0x60, 0x54, 0x79, 0x70, 0x93, 0x05, 0x30, 0x65, 0x6e, 2690x6f, 0xe9, 0x05, 0x22, 0x2e, 0x29, 0x06, 0x0c, 0x15, 0x32,
2690x75, 0xad, 0x00, 0x91, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 2700x06, 0x0c, 0x00, 0x3f, 0x0a, 0x20, 0x6d, 0x65, 0xb3, 0x04,
2700x00, 0x48, 0x65, 0x9d, 0x01, 0x51, 0x00, 0x00, 0x53, 0x69, 2710x12, 0x20, 0x82, 0x04, 0x36, 0x73, 0x65, 0x00, 0x14, 0x00,
2710x7a, 0x07, 0x0c, 0x00, 0xbd, 0x01, 0x01, 0xaf, 0x00, 0x42, 2720x02, 0x43, 0x00, 0x04, 0x3e, 0x00, 0x02, 0xe1, 0x07, 0x10,
2720x71, 0x75, 0x61, 0x72, 0xcc, 0x0c, 0xaa, 0x44, 0x69, 0x66, 2730x74, 0xa6, 0x04, 0xa4, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d,
2730x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x0d, 0x00, 0x41, 2740x2e, 0x2e, 0x2e, 0x27, 0xf7, 0x00, 0x03, 0x96, 0x01, 0x40,
2740x6c, 0x65, 0x76, 0x65, 0xa6, 0x09, 0x02, 0x9e, 0x02, 0x00, 2750x60, 0x54, 0x79, 0x70, 0x1f, 0x06, 0x30, 0x65, 0x6e, 0x75,
2750x2b, 0x00, 0x10, 0x41, 0x5d, 0x01, 0x12, 0x20, 0x5d, 0x01, 2760xad, 0x00, 0x91, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00,
2760x12, 0x00, 0x41, 0x08, 0x21, 0x69, 0x73, 0x1c, 0x10, 0x06, 2770x48, 0x65, 0x9d, 0x01, 0x51, 0x00, 0x00, 0x53, 0x69, 0x7a,
2770x03, 0x0a, 0x01, 0x7d, 0x0a, 0x20, 0x63, 0x6c, 0x24, 0x05, 2780xa0, 0x0d, 0x00, 0xbd, 0x01, 0x01, 0xaf, 0x00, 0x42, 0x71,
2780x23, 0x64, 0x2c, 0x3c, 0x00, 0x06, 0x3e, 0x04, 0x51, 0x67, 2790x75, 0x61, 0x72, 0x43, 0x0d, 0xaa, 0x44, 0x69, 0x66, 0x66,
2790x65, 0x6e, 0x65, 0x72, 0xd6, 0x06, 0x0e, 0xc5, 0x0f, 0x06, 2800x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x0d, 0x00, 0x41, 0x6c,
2800x83, 0x02, 0x03, 0x4f, 0x07, 0x00, 0xb9, 0x01, 0x13, 0x62, 2810x65, 0x76, 0x65, 0x32, 0x0a, 0x02, 0x9e, 0x02, 0x00, 0x2b,
2810x18, 0x03, 0x00, 0x49, 0x0b, 0x33, 0x63, 0x72, 0x65, 0x9b, 2820x00, 0x10, 0x41, 0x5d, 0x01, 0x12, 0x20, 0x5d, 0x01, 0x12,
2820x0f, 0x01, 0xa9, 0x01, 0x02, 0x87, 0x08, 0x04, 0xde, 0x01, 2830x00, 0xcd, 0x08, 0x21, 0x69, 0x73, 0x93, 0x10, 0x06, 0x8f,
2830x04, 0xcb, 0x01, 0x25, 0x64, 0x6f, 0x25, 0x04, 0x0b, 0xd0, 2840x0a, 0x01, 0x09, 0x0b, 0x20, 0x63, 0x6c, 0xb0, 0x05, 0x23,
2840x01, 0x04, 0x1e, 0x02, 0x02, 0xcf, 0x01, 0x64, 0x4d, 0x61, 2850x64, 0x2c, 0x3c, 0x00, 0x06, 0x3e, 0x04, 0x51, 0x67, 0x65,
2850x78, 0x2e, 0x20, 0x62, 0x8e, 0x01, 0x36, 0x65, 0x72, 0x20, 2860x6e, 0x65, 0x72, 0x62, 0x07, 0x0e, 0x3c, 0x10, 0x06, 0x83,
2860x18, 0x07, 0x01, 0x1d, 0x00, 0x4e, 0x69, 0x6d, 0x75, 0x6d, 2870x02, 0x03, 0xdb, 0x07, 0x00, 0xb9, 0x01, 0x13, 0x62, 0x18,
2870x22, 0x10, 0x04, 0xaf, 0x02, 0x20, 0x70, 0x61, 0x4f, 0x10, 2880x03, 0x00, 0xd5, 0x0b, 0x33, 0x63, 0x72, 0x65, 0x12, 0x10,
2880x48, 0x75, 0x6c, 0x61, 0x72, 0xae, 0x06, 0x17, 0x54, 0x2b, 2890x01, 0xa9, 0x01, 0x02, 0x13, 0x09, 0x04, 0xde, 0x01, 0x04,
2890x0e, 0x42, 0x69, 0x73, 0x00, 0x32, 0xc6, 0x0f, 0x04, 0x44, 2900xcb, 0x01, 0x25, 0x64, 0x6f, 0x25, 0x04, 0x0b, 0xd0, 0x01,
2900x06, 0x01, 0x21, 0x0f, 0x13, 0x65, 0xcf, 0x03, 0x40, 0x31, 2910x04, 0x1e, 0x02, 0x02, 0xcf, 0x01, 0x64, 0x4d, 0x61, 0x78,
2910x2c, 0x00, 0x33, 0x88, 0x04, 0x53, 0x34, 0x2e, 0x00, 0x49, 2920x2e, 0x20, 0x62, 0x8e, 0x01, 0x36, 0x65, 0x72, 0x20, 0xa4,
2920x6e, 0x17, 0x01, 0x20, 0x6c, 0x2c, 0x72, 0x05, 0x21, 0x65, 2930x07, 0x01, 0x1d, 0x00, 0x4e, 0x69, 0x6d, 0x75, 0x6d, 0x99,
2930x72, 0x6d, 0x10, 0x32, 0x61, 0x73, 0x69, 0x6e, 0x0a, 0x82, 2940x10, 0x04, 0xaf, 0x02, 0x20, 0x70, 0x61, 0xc6, 0x10, 0x48,
2940x25, 0x61, 0x67, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x87, 0x03, 2950x75, 0x6c, 0x61, 0x72, 0x3a, 0x07, 0x17, 0x54, 0xa2, 0x0e,
2950x13, 0x20, 0xba, 0x01, 0x70, 0x00, 0x00, 0x00, 0x47, 0x69, 2960x42, 0x69, 0x73, 0x00, 0x32, 0x3d, 0x10, 0x04, 0xd0, 0x06,
2960x76, 0x65, 0xb5, 0x02, 0x11, 0x72, 0x28, 0x05, 0x40, 0x70, 2970x01, 0x98, 0x0f, 0x13, 0x65, 0xcf, 0x03, 0x40, 0x31, 0x2c,
2970x65, 0x72, 0x63, 0x73, 0x09, 0x28, 0x67, 0x65, 0xa0, 0x04, 2980x00, 0x33, 0x88, 0x04, 0x53, 0x34, 0x2e, 0x00, 0x49, 0x6e,
2980x25, 0x74, 0x68, 0x74, 0x01, 0x04, 0xac, 0x08, 0x31, 0x74, 2990x17, 0x01, 0x20, 0x6c, 0x2c, 0x72, 0x05, 0x21, 0x65, 0x72,
2990x72, 0x79, 0x39, 0x01, 0x11, 0x6c, 0xaf, 0x04, 0x34, 0x66, 3000xe4, 0x10, 0x32, 0x61, 0x73, 0x69, 0xfa, 0x0a, 0x82, 0x25,
3000x6f, 0x72, 0xbb, 0x0a, 0x05, 0xbc, 0x0f, 0x03, 0xf0, 0x01, 3010x61, 0x67, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x87, 0x03, 0x13,
3010x30, 0x43, 0x65, 0x72, 0xa4, 0x03, 0x00, 0x29, 0x00, 0x33, 3020x20, 0xba, 0x01, 0x70, 0x00, 0x00, 0x00, 0x47, 0x69, 0x76,
3020x6f, 0x75, 0x74, 0xc4, 0x01, 0x00, 0xc0, 0x03, 0x30, 0x6d, 3030x65, 0xb5, 0x02, 0x11, 0x72, 0x28, 0x05, 0x40, 0x70, 0x65,
3030x61, 0x6e, 0x67, 0x00, 0x12, 0x74, 0xbf, 0x07, 0x03, 0xa8, 3040x72, 0x63, 0xff, 0x09, 0x2a, 0x67, 0x65, 0x9c, 0x06, 0x05,
3040x05, 0x03, 0x72, 0x00, 0x12, 0x3b, 0xca, 0x0c, 0x10, 0x69, 3050x74, 0x01, 0x04, 0x38, 0x09, 0x31, 0x74, 0x72, 0x79, 0x39,
3050x1b, 0x05, 0x40, 0x00, 0x75, 0x70, 0x70, 0x94, 0x05, 0x22, 3060x01, 0x11, 0x6c, 0xaf, 0x04, 0x34, 0x66, 0x6f, 0x72, 0x47,
3060x6f, 0x75, 0x13, 0x11, 0xf0, 0x03, 0x45, 0x78, 0x70, 0x61, 3070x0b, 0x05, 0x33, 0x10, 0x03, 0xf0, 0x01, 0x30, 0x43, 0x65,
3070x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x61, 0x63, 0x74, 3080x72, 0xa4, 0x03, 0x00, 0x29, 0x00, 0x33, 0x6f, 0x75, 0x74,
3080x6f, 0x72, 0x20, 0x28, 0xdc, 0x00, 0x12, 0x29, 0x00, 0x03, 3090xc4, 0x01, 0x00, 0xc0, 0x03, 0x30, 0x6d, 0x61, 0x6e, 0x67,
3090x02, 0x9b, 0x02, 0x07, 0xac, 0x00, 0x41, 0x6f, 0x72, 0x6b, 3100x00, 0x12, 0x74, 0x4b, 0x08, 0x03, 0xa8, 0x05, 0x03, 0x72,
3100x73, 0xbe, 0x07, 0x04, 0x10, 0x0a, 0x69, 0x6e, 0x00, 0x65, 3110x00, 0x12, 0x3b, 0x56, 0x0d, 0x10, 0x69, 0x1b, 0x05, 0x40,
3110x78, 0x69, 0x73, 0x7d, 0x0d, 0xf8, 0x05, 0x74, 0x00, 0x72, 3120x00, 0x75, 0x70, 0x70, 0x94, 0x05, 0x22, 0x6f, 0x75, 0x8a,
3120x61, 0x6e, 0x64, 0x6f, 0x6d, 0x00, 0x28, 0x61, 0x66, 0x74, 3130x11, 0xf0, 0x03, 0x45, 0x78, 0x70, 0x61, 0x6e, 0x73, 0x69,
3130x65, 0x72, 0x00, 0x66, 0x69, 0x72, 0x73, 0x28, 0x02, 0x20, 3140x6f, 0x6e, 0x20, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x20,
3140x6e, 0x00, 0x90, 0x06, 0x34, 0x69, 0x61, 0x6c, 0x32, 0x00, 3150x28, 0xdc, 0x00, 0x13, 0x29, 0x82, 0x07, 0x01, 0x9b, 0x02,
3150x00, 0x7f, 0x10, 0x10, 0x77, 0x1a, 0x0d, 0x41, 0x29, 0x2e, 3160x07, 0xac, 0x00, 0x41, 0x6f, 0x72, 0x6b, 0x73, 0x4a, 0x08,
3160x00, 0x49, 0x72, 0x02, 0x40, 0x6e, 0x00, 0x64, 0x65, 0xae, 3170x04, 0x9c, 0x0a, 0x69, 0x6e, 0x00, 0x65, 0x78, 0x69, 0x73,
3170x0a, 0x12, 0x73, 0x6b, 0x0a, 0x07, 0x1e, 0x09, 0x05, 0x5e, 3180x09, 0x0e, 0xf8, 0x05, 0x74, 0x00, 0x72, 0x61, 0x6e, 0x64,
3180x00, 0x24, 0x29, 0x2c, 0x22, 0x05, 0x13, 0x6e, 0x97, 0x00, 3190x6f, 0x6d, 0x00, 0x28, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00,
3190x00, 0x8e, 0x02, 0x31, 0x68, 0x6f, 0x77, 0x72, 0x0e, 0x41, 3200x66, 0x69, 0x72, 0x73, 0x28, 0x02, 0x20, 0x6e, 0x00, 0x90,
3200x69, 0x74, 0x00, 0x63, 0x9c, 0x06, 0x20, 0x65, 0x78, 0x6c, 3210x06, 0x34, 0x69, 0x61, 0x6c, 0x32, 0x00, 0x00, 0xf6, 0x10,
3210x0e, 0x04, 0x54, 0x01, 0x07, 0x85, 0x00, 0x08, 0xc6, 0x0e, 3220x10, 0x77, 0xa6, 0x0d, 0x41, 0x29, 0x2e, 0x00, 0x49, 0x72,
3220x03, 0x78, 0x0b, 0x05, 0xeb, 0x03, 0x32, 0x00, 0x64, 0x65, 3230x02, 0x40, 0x6e, 0x00, 0x64, 0x65, 0x3a, 0x0b, 0x12, 0x73,
3230x75, 0x12, 0x21, 0x65, 0x73, 0x52, 0x00, 0x50, 0x6c, 0x69, 3240xf7, 0x0a, 0x07, 0xaa, 0x09, 0x05, 0x5e, 0x00, 0x24, 0x29,
3240x6b, 0x65, 0x6c, 0xad, 0x0a, 0x03, 0x17, 0x13, 0x03, 0x55, 3250x2c, 0x22, 0x05, 0x13, 0x6e, 0x97, 0x00, 0x00, 0x8e, 0x02,
3250x00, 0x21, 0x61, 0x73, 0x6c, 0x00, 0x21, 0x61, 0x73, 0x6f, 3260x31, 0x68, 0x6f, 0x77, 0xfe, 0x0e, 0x14, 0x69, 0xfd, 0x07,
3260x00, 0x66, 0x61, 0x6e, 0x2c, 0x00, 0x72, 0x61, 0x40, 0x11, 3270x20, 0x65, 0x78, 0xf8, 0x0e, 0x04, 0x54, 0x01, 0x07, 0x85,
3270x41, 0x63, 0x68, 0x6f, 0x6f, 0xbd, 0x08, 0x05, 0xdf, 0x00, 3280x00, 0x08, 0x52, 0x0f, 0x03, 0x04, 0x0c, 0x05, 0xeb, 0x03,
3280x02, 0x68, 0x06, 0x01, 0x40, 0x02, 0x64, 0x48, 0x69, 0x67, 3290x32, 0x00, 0x64, 0x65, 0xec, 0x12, 0x21, 0x65, 0x73, 0x52,
3290x68, 0x00, 0x65, 0x7b, 0x01, 0x12, 0x00, 0x7b, 0x01, 0x52, 3300x00, 0x50, 0x6c, 0x69, 0x6b, 0x65, 0x6c, 0x39, 0x0b, 0x03,
3300x73, 0x00, 0x75, 0x73, 0x75, 0x9f, 0x0b, 0x33, 0x65, 0x61, 3310x8e, 0x13, 0x03, 0x55, 0x00, 0x21, 0x61, 0x73, 0x6c, 0x00,
3310x6e, 0x6e, 0x02, 0x07, 0xae, 0x03, 0x23, 0x74, 0x68, 0x8b, 3320x21, 0x61, 0x73, 0x6f, 0x00, 0x66, 0x61, 0x6e, 0x2c, 0x00,
3320x02, 0x05, 0xf3, 0x0a, 0x05, 0xe0, 0x01, 0x00, 0x60, 0x05, 3330x72, 0x61, 0xb7, 0x11, 0x41, 0x63, 0x68, 0x6f, 0x6f, 0x49,
3330x0e, 0x4f, 0x00, 0x01, 0xe1, 0x02, 0x20, 0x72, 0x65, 0xf8, 3340x09, 0x05, 0xdf, 0x00, 0x02, 0x68, 0x06, 0x01, 0x40, 0x02,
3340x05, 0x32, 0x6c, 0x6f, 0x74, 0xbd, 0x08, 0x00, 0x7c, 0x04, 3350x64, 0x48, 0x69, 0x67, 0x68, 0x00, 0x65, 0x7b, 0x01, 0x12,
3350x73, 0x6c, 0x79, 0x2d, 0x70, 0x61, 0x63, 0x6b, 0xb9, 0x0b, 3360x00, 0x7b, 0x01, 0x52, 0x73, 0x00, 0x75, 0x73, 0x75, 0x2b,
3360x50, 0x6e, 0x64, 0x73, 0x2e, 0x00, 3370x0c, 0x33, 0x65, 0x61, 0x6e, 0x6e, 0x02, 0x07, 0xae, 0x03,
3380x23, 0x74, 0x68, 0x8b, 0x02, 0x05, 0x7f, 0x0b, 0x05, 0xe0,
3390x01, 0x00, 0x60, 0x05, 0x0e, 0x4f, 0x00, 0x01, 0xe1, 0x02,
3400x20, 0x72, 0x65, 0xf8, 0x05, 0x32, 0x6c, 0x6f, 0x74, 0xbd,
3410x08, 0x00, 0x7c, 0x04, 0x61, 0x6c, 0x79, 0x2d, 0x70, 0x61,
3420x63, 0xac, 0x08, 0x04, 0xb1, 0x06, 0x01, 0x0a, 0x05, 0x15,
3430x33, 0x0a, 0x05, 0xb0, 0x75, 0x73, 0x65, 0x72, 0x20, 0x70,
3440x72, 0x65, 0x66, 0x65, 0x72, 0x46, 0x12, 0x01, 0x10, 0x05,
3450x20, 0x4f, 0x6e, 0x70, 0x0d, 0x12, 0x74, 0x97, 0x05, 0x03,
3460x48, 0x06, 0x60, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x00, 0x2e,
3470x00, 0x17, 0x00, 0x2e, 0x00, 0x12, 0x2c, 0xfe, 0x04, 0x16,
3480x50, 0x12, 0x00, 0x0d, 0x1a, 0x05, 0x33, 0x47, 0x61, 0x6d,
3490x1a, 0x05, 0x03, 0xb1, 0x06, 0x13, 0x65, 0x94, 0x03, 0x03,
3500x56, 0x13, 0x10, 0x65, 0xfe, 0x0f, 0x28, 0x74, 0x68, 0xed,
3510x00, 0x04, 0x2d, 0x13, 0x23, 0x6f, 0x63, 0x8c, 0x09, 0x01,
3520x8b, 0x13, 0x80, 0x68, 0x6f, 0x77, 0x6e, 0x2e, 0x00, 0x55,
3530x6e, 0xa4, 0x01, 0x26, 0x00, 0x74, 0x35, 0x0a, 0x00, 0x84,
3540x00, 0x04, 0xd8, 0x0d, 0x75, 0x70, 0x65, 0x72, 0x73, 0x69,
3550x73, 0x74, 0x32, 0x0a, 0x70, 0x67, 0x61, 0x6d, 0x65, 0x73,
3560x2e, 0x00,
337}; 357};
338 358
339const unsigned short help_text_len = 5230; 359const unsigned short help_text_len = 5613;
340const unsigned short help_text_words = 963; 360const unsigned short help_text_words = 1026;
341const char quick_help_text[] = "Connect all the islands with a network of bridges."; 361const char quick_help_text[] = "Connect all the islands with a network of bridges.";
diff --git a/apps/plugins/puzzles/help/cube.c b/apps/plugins/puzzles/help/cube.c
index 6857cbf733..21c3eb7cc3 100644
--- a/apps/plugins/puzzles/help/cube.c
+++ b/apps/plugins/puzzles/help/cube.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,163 +6,164 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 207, TEXT_CENTER | C_RED }, 9 { 208, TEXT_CENTER | C_RED },
10 { 319, TEXT_CENTER | C_RED }, 10 { 320, TEXT_CENTER | C_RED },
11 { 336, TEXT_UNDERLINE }, 11 { 337, TEXT_UNDERLINE },
12 { 358, TEXT_UNDERLINE },
13 { 359, TEXT_UNDERLINE }, 12 { 359, TEXT_UNDERLINE },
13 { 360, TEXT_UNDERLINE },
14 LAST_STYLE_ITEM 14 LAST_STYLE_ITEM
15}; 15};
16 16
17/* orig 2055 comp 1444 ratio 0.702676 level 10 saved 611 */ 17/* orig 2071 comp 1451 ratio 0.700628 level 10 saved 620 */
18const char help_text[] = { 18const char help_text[] = {
190xf2, 0x37, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 190xfa, 0x03, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
200x34, 0x3a, 0x20, 0x43, 0x75, 0x62, 0x65, 0x20, 0x00, 0x00, 200x34, 0x3a, 0x20, 0x43, 0x75, 0x62, 0x65, 0x20, 0x00, 0x2d,
210x00, 0x54, 0x68, 0x69, 0x73, 0x00, 0x69, 0x73, 0x00, 0x61, 210x01, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69,
220x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x00, 0x6f, 0x6e, 0x65, 220x73, 0x00, 0x69, 0x73, 0x00, 0x61, 0x6e, 0x6f, 0x74, 0x68,
230x00, 0x49, 0x00, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 230x65, 0x72, 0x00, 0x6f, 0x6e, 0x65, 0x00, 0x49, 0x00, 0x6f,
240x6c, 0x6c, 0x79, 0x00, 0x73, 0x61, 0x77, 0x00, 0x61, 0x73, 240x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0x00,
250x00, 0x61, 0x00, 0x77, 0x65, 0x62, 0x00, 0x67, 0x61, 0x6d, 250x73, 0x61, 0x77, 0x00, 0x61, 0x73, 0x00, 0x61, 0x00, 0x77,
260x65, 0x2e, 0x34, 0x00, 0x00, 0x29, 0x00, 0x11, 0x77, 0x19, 260x65, 0x62, 0x00, 0x67, 0x61, 0x6d, 0x65, 0x2e, 0x34, 0x00,
270x00, 0x41, 0x4a, 0x61, 0x76, 0x61, 0x1a, 0x00, 0xf0, 0x28, 270x00, 0x29, 0x00, 0x11, 0x77, 0x19, 0x00, 0x41, 0x4a, 0x61,
280x00, 0x5b, 0x32, 0x5d, 0x2c, 0x00, 0x62, 0x79, 0x00, 0x50, 280x76, 0x61, 0x1a, 0x00, 0xf0, 0x28, 0x00, 0x5b, 0x32, 0x5d,
290x61, 0x75, 0x6c, 0x00, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x2e, 290x2c, 0x00, 0x62, 0x79, 0x00, 0x50, 0x61, 0x75, 0x6c, 0x00,
300x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 300x53, 0x63, 0x6f, 0x74, 0x74, 0x2e, 0x00, 0x59, 0x6f, 0x75,
310x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 310x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x67, 0x72,
320x31, 0x36, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 320x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x31, 0x36, 0x00, 0x73,
330x2c, 0x00, 0x73, 0x69, 0x78, 0x13, 0x00, 0xf1, 0x03, 0x77, 330x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x73, 0x69,
340x68, 0x69, 0x63, 0x68, 0x00, 0x61, 0x72, 0x65, 0x00, 0x62, 340x78, 0x13, 0x00, 0xf1, 0x03, 0x77, 0x68, 0x69, 0x63, 0x68,
350x6c, 0x75, 0x65, 0x3b, 0x00, 0x6f, 0x6e, 0x61, 0x00, 0x02, 350x00, 0x61, 0x72, 0x65, 0x00, 0x62, 0x6c, 0x75, 0x65, 0x3b,
360x27, 0x00, 0x50, 0x00, 0x72, 0x65, 0x73, 0x74, 0x6a, 0x00, 360x00, 0x6f, 0x6e, 0x61, 0x00, 0x02, 0x27, 0x00, 0x50, 0x00,
370x41, 0x63, 0x75, 0x62, 0x65, 0x52, 0x00, 0x60, 0x72, 0x00, 370x72, 0x65, 0x73, 0x74, 0x6a, 0x00, 0x41, 0x63, 0x75, 0x62,
380x6d, 0x6f, 0x76, 0x65, 0xb8, 0x00, 0xf1, 0x05, 0x74, 0x6f, 380x65, 0x52, 0x00, 0x60, 0x72, 0x00, 0x6d, 0x6f, 0x76, 0x65,
390x00, 0x75, 0x73, 0x65, 0x00, 0x74, 0x68, 0x65, 0x00, 0x61, 390xb8, 0x00, 0xf1, 0x05, 0x74, 0x6f, 0x00, 0x75, 0x73, 0x65,
400x72, 0x72, 0x6f, 0x77, 0x00, 0x6b, 0x65, 0x79, 0x16, 0x00, 400x00, 0x74, 0x68, 0x65, 0x00, 0x61, 0x72, 0x72, 0x6f, 0x77,
410x41, 0x72, 0x6f, 0x6c, 0x6c, 0x17, 0x00, 0x00, 0x35, 0x00, 410x00, 0x6b, 0x65, 0x79, 0x16, 0x00, 0x41, 0x72, 0x6f, 0x6c,
420xf1, 0x0f, 0x00, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 420x6c, 0x17, 0x00, 0x00, 0x35, 0x00, 0xf1, 0x0f, 0x00, 0x74,
430x00, 0x39, 0x30, 0x00, 0x64, 0x65, 0x67, 0x72, 0x65, 0x65, 430x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x00, 0x39, 0x30, 0x00,
440x73, 0x00, 0x73, 0x6f, 0x00, 0x74, 0x68, 0x61, 0x74, 0x00, 440x64, 0x65, 0x67, 0x72, 0x65, 0x65, 0x73, 0x00, 0x73, 0x6f,
450x69, 0x74, 0x4d, 0x00, 0x01, 0x35, 0x00, 0xb3, 0x61, 0x6e, 450x00, 0x74, 0x68, 0x61, 0x74, 0x00, 0x69, 0x74, 0x4d, 0x00,
460x00, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x7c, 460x01, 0x35, 0x00, 0xb3, 0x61, 0x6e, 0x00, 0x61, 0x64, 0x6a,
470x00, 0x8b, 0x2e, 0x00, 0x49, 0x66, 0x00, 0x79, 0x6f, 0x75, 470x61, 0x63, 0x65, 0x6e, 0x74, 0x7c, 0x00, 0x8b, 0x2e, 0x00,
480x50, 0x00, 0x21, 0x6f, 0x6e, 0x2f, 0x00, 0x01, 0xae, 0x00, 480x49, 0x66, 0x00, 0x79, 0x6f, 0x75, 0x50, 0x00, 0x21, 0x6f,
490x03, 0x2a, 0x00, 0x11, 0x2c, 0x1e, 0x00, 0x07, 0x11, 0x00, 490x6e, 0x2f, 0x00, 0x01, 0xae, 0x00, 0x03, 0x2a, 0x00, 0x11,
500x00, 0x9f, 0x00, 0x94, 0x70, 0x69, 0x63, 0x6b, 0x65, 0x64, 500x2c, 0x1e, 0x00, 0x07, 0x11, 0x00, 0x00, 0x9f, 0x00, 0x94,
510x00, 0x75, 0x70, 0xd2, 0x00, 0x40, 0x66, 0x61, 0x63, 0x65, 510x70, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x00, 0x75, 0x70, 0xd2,
520xf1, 0x00, 0x04, 0x4a, 0x00, 0x37, 0x3b, 0x00, 0x69, 0x60, 520x00, 0x40, 0x66, 0x61, 0x63, 0x65, 0xf1, 0x00, 0x04, 0x4a,
530x00, 0x03, 0x51, 0x00, 0x0c, 0x25, 0x00, 0x05, 0x6f, 0x00, 530x00, 0x37, 0x3b, 0x00, 0x69, 0x60, 0x00, 0x03, 0x51, 0x00,
540x4f, 0x6e, 0x6f, 0x6e, 0x2d, 0x73, 0x00, 0x02, 0x41, 0x6e, 540x0c, 0x25, 0x00, 0x05, 0x6f, 0x00, 0x4f, 0x6e, 0x6f, 0x6e,
550x65, 0x73, 0x73, 0x70, 0x00, 0xfe, 0x15, 0x75, 0x74, 0x00, 550x2d, 0x73, 0x00, 0x02, 0x41, 0x6e, 0x65, 0x73, 0x73, 0x70,
560x64, 0x6f, 0x77, 0x6e, 0x00, 0x61, 0x67, 0x61, 0x69, 0x6e, 560x00, 0xfe, 0x15, 0x75, 0x74, 0x00, 0x64, 0x6f, 0x77, 0x6e,
570x2e, 0x00, 0x28, 0x49, 0x6e, 0x00, 0x67, 0x65, 0x6e, 0x65, 570x00, 0x61, 0x67, 0x61, 0x69, 0x6e, 0x2e, 0x00, 0x28, 0x49,
580x72, 0x61, 0x6c, 0x2c, 0x00, 0x77, 0x68, 0x65, 0x6e, 0x65, 580x6e, 0x00, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x2c,
590x76, 0x65, 0x72, 0xd0, 0x00, 0x02, 0x49, 0x00, 0x31, 0x74, 590x00, 0x77, 0x68, 0x65, 0x6e, 0x65, 0x76, 0x65, 0x72, 0xd0,
600x77, 0x6f, 0x7b, 0x00, 0x12, 0x73, 0x19, 0x01, 0xf2, 0x11, 600x00, 0x02, 0x49, 0x00, 0x31, 0x74, 0x77, 0x6f, 0x7b, 0x00,
610x63, 0x6f, 0x6d, 0x65, 0x00, 0x69, 0x6e, 0x74, 0x6f, 0x00, 610x12, 0x73, 0x19, 0x01, 0xf2, 0x11, 0x63, 0x6f, 0x6d, 0x65,
620x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x00, 0x73, 0x77, 620x00, 0x69, 0x6e, 0x74, 0x6f, 0x00, 0x63, 0x6f, 0x6e, 0x74,
630x61, 0x70, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x73, 630x61, 0x63, 0x74, 0x00, 0x73, 0x77, 0x61, 0x70, 0x00, 0x63,
640x2e, 0x29, 0x89, 0x01, 0x33, 0x6a, 0x6f, 0x62, 0x88, 0x01, 640x6f, 0x6c, 0x6f, 0x75, 0x72, 0x73, 0x2e, 0x29, 0x89, 0x01,
650x71, 0x67, 0x65, 0x74, 0x00, 0x61, 0x6c, 0x6c, 0xd3, 0x01, 650x33, 0x6a, 0x6f, 0x62, 0x88, 0x01, 0x71, 0x67, 0x65, 0x74,
660x07, 0xa5, 0x00, 0x13, 0x73, 0xbe, 0x00, 0x00, 0x62, 0x00, 660x00, 0x61, 0x6c, 0x6c, 0xd3, 0x01, 0x07, 0xa5, 0x00, 0x13,
670x00, 0x1b, 0x00, 0x02, 0x62, 0x00, 0x08, 0xde, 0x00, 0x22, 670x73, 0xbe, 0x00, 0x00, 0x62, 0x00, 0x00, 0x1b, 0x00, 0x02,
680x61, 0x74, 0x1d, 0x00, 0x00, 0x43, 0x02, 0x20, 0x74, 0x69, 680x62, 0x00, 0x08, 0xde, 0x00, 0x22, 0x61, 0x74, 0x1d, 0x00,
690x62, 0x02, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x79, 690x00, 0x43, 0x02, 0x20, 0x74, 0x69, 0x62, 0x02, 0x74, 0x43,
700xe9, 0x01, 0x00, 0x9f, 0x02, 0x50, 0x64, 0x00, 0x74, 0x72, 700x6f, 0x75, 0x6e, 0x74, 0x00, 0x79, 0xe9, 0x01, 0x00, 0x9f,
710x79, 0x48, 0x00, 0x20, 0x64, 0x6f, 0xb3, 0x01, 0x20, 0x69, 710x02, 0x50, 0x64, 0x00, 0x74, 0x72, 0x79, 0x48, 0x00, 0x20,
720x6e, 0x96, 0x02, 0x21, 0x66, 0x65, 0x9d, 0x02, 0xf2, 0x02, 720x64, 0x6f, 0xb3, 0x01, 0x20, 0x69, 0x6e, 0x96, 0x02, 0x21,
730x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x2e, 0x00, 730x66, 0x65, 0x9d, 0x02, 0xf2, 0x02, 0x70, 0x6f, 0x73, 0x73,
740x00, 0x00, 0x55, 0x6e, 0x6c, 0x69, 0x6b, 0x11, 0x02, 0x04, 740x69, 0x62, 0x6c, 0x65, 0x2e, 0x00, 0x00, 0x00, 0x55, 0x6e,
750xc6, 0x02, 0x06, 0xa2, 0x02, 0xf2, 0x01, 0x2c, 0x00, 0x6d, 750x6c, 0x69, 0x6b, 0x11, 0x02, 0x04, 0xc6, 0x02, 0x06, 0xa2,
760x79, 0x00, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 760x02, 0xf2, 0x01, 0x2c, 0x00, 0x6d, 0x79, 0x00, 0x76, 0x65,
770x68, 0x61, 0x73, 0xf1, 0x01, 0x50, 0x64, 0x69, 0x74, 0x69, 770x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x68, 0x61, 0x73, 0xf1,
780x6f, 0x28, 0x00, 0xd0, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 780x01, 0x50, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x28, 0x00, 0xd0,
790x65, 0x3a, 0x00, 0x6f, 0x6e, 0x63, 0x65, 0x7f, 0x00, 0xc1, 790x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x3a, 0x00, 0x6f,
800x27, 0x76, 0x65, 0x00, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 800x6e, 0x63, 0x65, 0x7f, 0x00, 0xc1, 0x27, 0x76, 0x65, 0x00,
810x65, 0x64, 0x53, 0x00, 0x01, 0xe7, 0x02, 0x43, 0x77, 0x69, 810x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x53, 0x00,
820x74, 0x68, 0x8e, 0x02, 0x01, 0x47, 0x01, 0x30, 0x69, 0x6e, 820x01, 0xe7, 0x02, 0x43, 0x77, 0x69, 0x74, 0x68, 0x8e, 0x02,
830x67, 0xe4, 0x00, 0x14, 0x61, 0xf8, 0x01, 0x00, 0xe8, 0x02, 830x01, 0x47, 0x01, 0x30, 0x69, 0x6e, 0x67, 0xe4, 0x00, 0x14,
840x11, 0x2c, 0x65, 0x01, 0xa2, 0x63, 0x61, 0x6e, 0x00, 0x63, 840x61, 0xf8, 0x01, 0x00, 0xe8, 0x02, 0x11, 0x2c, 0x65, 0x01,
850x68, 0x61, 0x6e, 0x67, 0x65, 0xc0, 0x01, 0xa2, 0x74, 0x72, 850xa2, 0x63, 0x61, 0x6e, 0x00, 0x63, 0x68, 0x61, 0x6e, 0x67,
860x69, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x0d, 0x03, 860x65, 0xc0, 0x01, 0xa2, 0x74, 0x72, 0x69, 0x61, 0x6e, 0x67,
870x00, 0xd7, 0x00, 0x02, 0xf9, 0x01, 0x20, 0x6e, 0x79, 0x13, 870x75, 0x6c, 0x61, 0x72, 0x0d, 0x03, 0x00, 0xd7, 0x00, 0x02,
880x01, 0xe0, 0x61, 0x00, 0x74, 0x65, 0x74, 0x72, 0x61, 0x68, 880xf9, 0x01, 0x20, 0x6e, 0x79, 0x13, 0x01, 0xe0, 0x61, 0x00,
890x65, 0x64, 0x72, 0x6f, 0x6e, 0x2c, 0x9e, 0x00, 0x33, 0x6f, 890x74, 0x65, 0x74, 0x72, 0x61, 0x68, 0x65, 0x64, 0x72, 0x6f,
900x63, 0x74, 0x0f, 0x00, 0x30, 0x00, 0x6f, 0x72, 0x11, 0x00, 900x6e, 0x2c, 0x9e, 0x00, 0x33, 0x6f, 0x63, 0x74, 0x0f, 0x00,
910x43, 0x69, 0x63, 0x6f, 0x73, 0x12, 0x00, 0x00, 0xef, 0x00, 910x30, 0x00, 0x6f, 0x72, 0x11, 0x00, 0x43, 0x69, 0x63, 0x6f,
920xf0, 0x13, 0x5b, 0x32, 0x5d, 0x00, 0x68, 0x74, 0x74, 0x70, 920x73, 0x12, 0x00, 0x00, 0xef, 0x00, 0xf0, 0x13, 0x5b, 0x32,
930x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x33, 0x2e, 0x73, 0x79, 930x5d, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
940x6d, 0x70, 0x61, 0x74, 0x69, 0x63, 0x6f, 0x2e, 0x63, 0x61, 940x77, 0x77, 0x33, 0x2e, 0x73, 0x79, 0x6d, 0x70, 0x61, 0x74,
950x2f, 0x70, 0x61, 0x75, 0x6c, 0x73, 0x87, 0x03, 0x10, 0x2f, 950x69, 0x63, 0x6f, 0x2e, 0x63, 0x61, 0x2f, 0x70, 0x61, 0x75,
960xac, 0x00, 0x11, 0x2f, 0x3f, 0x03, 0x92, 0x68, 0x74, 0x6d, 960x6c, 0x73, 0x87, 0x03, 0x10, 0x2f, 0xac, 0x00, 0x11, 0x2f,
970x00, 0x00, 0x00, 0x34, 0x2e, 0x31, 0x03, 0x04, 0x00, 0xdb, 970x3f, 0x03, 0x92, 0x68, 0x74, 0x6d, 0x00, 0x00, 0x00, 0x34,
980x01, 0x45, 0x72, 0x6f, 0x6c, 0x73, 0x0c, 0x04, 0x01, 0xe2, 980x2e, 0x31, 0x13, 0x04, 0x00, 0xdb, 0x01, 0x54, 0x72, 0x6f,
990x00, 0x00, 0xb8, 0x00, 0x92, 0x62, 0x65, 0x00, 0x70, 0x6c, 990x6c, 0x73, 0x20, 0x0c, 0x04, 0x01, 0xe2, 0x00, 0x00, 0xb8,
1000x61, 0x79, 0x65, 0x64, 0xf0, 0x00, 0x21, 0x65, 0x69, 0x20, 1000x00, 0x92, 0x62, 0x65, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x65,
1010x04, 0x00, 0x05, 0x01, 0xa2, 0x6b, 0x65, 0x79, 0x62, 0x6f, 1010x64, 0xf0, 0x00, 0x21, 0x65, 0x69, 0x20, 0x04, 0x00, 0x05,
1020x61, 0x72, 0x64, 0x00, 0x6f, 0x10, 0x00, 0x41, 0x6d, 0x6f, 1020x01, 0xa2, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64,
1030x75, 0x73, 0x7c, 0x01, 0xa0, 0x4c, 0x65, 0x66, 0x74, 0x2d, 1030x00, 0x6f, 0x10, 0x00, 0x41, 0x6d, 0x6f, 0x75, 0x73, 0x7c,
1040x63, 0x6c, 0x69, 0x63, 0x6b, 0x13, 0x01, 0x72, 0x61, 0x6e, 1040x01, 0xa0, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69,
1050x79, 0x77, 0x68, 0x65, 0x72, 0xbe, 0x02, 0x10, 0x68, 0x37, 1050x63, 0x6b, 0x13, 0x01, 0x72, 0x61, 0x6e, 0x79, 0x77, 0x68,
1060x01, 0x92, 0x6e, 0x64, 0x6f, 0x77, 0x00, 0x77, 0x69, 0x6c, 1060x65, 0x72, 0xbe, 0x02, 0x10, 0x68, 0x37, 0x01, 0x92, 0x6e,
1070x6c, 0xbf, 0x03, 0x05, 0x01, 0x02, 0x42, 0x28, 0x6f, 0x72, 1070x64, 0x6f, 0x77, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0xbf, 0x03,
1080x00, 0x7f, 0x04, 0xe6, 0x73, 0x6f, 0x6c, 0x69, 0x64, 0x29, 1080x05, 0x01, 0x02, 0x42, 0x28, 0x6f, 0x72, 0x00, 0x7f, 0x04,
1090x00, 0x74, 0x6f, 0x77, 0x61, 0x72, 0x64, 0x73, 0x5e, 0x00, 1090xe6, 0x73, 0x6f, 0x6c, 0x69, 0x64, 0x29, 0x00, 0x74, 0x6f,
1100x91, 0x00, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2e, 1100x77, 0x61, 0x72, 0x64, 0x73, 0x5e, 0x00, 0x91, 0x00, 0x70,
1110xa7, 0x00, 0x09, 0xec, 0x03, 0x10, 0x63, 0xc4, 0x01, 0x21, 1110x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2e, 0xa7, 0x00, 0x09,
1120x6c, 0x73, 0x08, 0x04, 0x1e, 0x64, 0xfa, 0x03, 0x68, 0x6f, 1120xec, 0x03, 0x10, 0x63, 0xc4, 0x01, 0x21, 0x6c, 0x73, 0x08,
1130x6e, 0x00, 0x69, 0x74, 0x73, 0x9b, 0x01, 0x22, 0x00, 0x69, 1130x04, 0x1e, 0x64, 0xfa, 0x03, 0x68, 0x6f, 0x6e, 0x00, 0x69,
1140x90, 0x00, 0x10, 0x66, 0x5f, 0x02, 0x41, 0x63, 0x61, 0x72, 1140x74, 0x73, 0x9b, 0x01, 0x22, 0x00, 0x69, 0x90, 0x00, 0x10,
1150x64, 0x24, 0x02, 0x50, 0x64, 0x69, 0x72, 0x65, 0x63, 0x08, 1150x66, 0x5f, 0x02, 0x41, 0x63, 0x61, 0x72, 0x64, 0x24, 0x02,
1160x02, 0x42, 0x73, 0x2e, 0x00, 0x4f, 0x21, 0x00, 0x0b, 0xae, 1160x50, 0x64, 0x69, 0x72, 0x65, 0x63, 0x08, 0x02, 0x42, 0x73,
1170x01, 0x22, 0x73, 0x2c, 0x90, 0x00, 0x31, 0x61, 0x70, 0x70, 1170x2e, 0x00, 0x4f, 0x21, 0x00, 0x0b, 0xae, 0x01, 0x22, 0x73,
1180xf2, 0x01, 0x1b, 0x66, 0x72, 0x04, 0x06, 0x42, 0x00, 0x00, 1180x2c, 0x90, 0x00, 0x31, 0x61, 0x70, 0x70, 0xf2, 0x01, 0x1b,
1190x11, 0x03, 0xf2, 0x0a, 0x6d, 0x6f, 0x72, 0x65, 0x00, 0x61, 1190x66, 0x72, 0x04, 0x06, 0x42, 0x00, 0x00, 0x11, 0x03, 0xf2,
1200x70, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x6d, 0x61, 0x74, 0x65, 1200x0a, 0x6d, 0x6f, 0x72, 0x65, 0x00, 0x61, 0x70, 0x70, 0x72,
1210x2e, 0x00, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0xfd, 1210x6f, 0x78, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x2e, 0x00, 0x56,
1220x00, 0x10, 0x6d, 0x63, 0x04, 0xb0, 0x69, 0x73, 0x00, 0x64, 1220x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0xfd, 0x00, 0x10, 0x6d,
1230x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x67, 0x01, 0x01, 1230x63, 0x04, 0xb0, 0x69, 0x73, 0x00, 0x64, 0x69, 0x73, 0x61,
1240x2d, 0x01, 0x10, 0x69, 0xc1, 0x03, 0xe0, 0x65, 0x73, 0x6e, 1240x6c, 0x6c, 0x6f, 0x77, 0x67, 0x01, 0x01, 0x2d, 0x01, 0x10,
1250x27, 0x74, 0x00, 0x6d, 0x61, 0x6b, 0x65, 0x00, 0x73, 0x65, 1250x69, 0xc1, 0x03, 0xe0, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x00,
1260x6e, 0x5d, 0x01, 0x14, 0x54, 0xb1, 0x00, 0x01, 0x6e, 0x00, 1260x6d, 0x61, 0x6b, 0x65, 0x00, 0x73, 0x65, 0x6e, 0x5d, 0x01,
1270x80, 0x73, 0x75, 0x72, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x88, 1270x14, 0x54, 0xb1, 0x00, 0x01, 0x6e, 0x00, 0x80, 0x73, 0x75,
1280x00, 0x0b, 0xfb, 0x04, 0x03, 0x6d, 0x01, 0x70, 0x6e, 0x75, 1280x72, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x88, 0x00, 0x0b, 0xfb,
1290x6d, 0x65, 0x72, 0x69, 0x63, 0x14, 0x00, 0xc0, 0x70, 0x61, 1290x04, 0x03, 0x6d, 0x01, 0x70, 0x6e, 0x75, 0x6d, 0x65, 0x72,
1300x64, 0x00, 0x28, 0x60, 0x37, 0x27, 0x2c, 0x00, 0x60, 0x39, 1300x69, 0x63, 0x14, 0x00, 0xc0, 0x70, 0x61, 0x64, 0x00, 0x28,
1310x05, 0x00, 0x10, 0x31, 0x05, 0x00, 0x34, 0x33, 0x27, 0x29, 1310x60, 0x37, 0x27, 0x2c, 0x00, 0x60, 0x39, 0x05, 0x00, 0x10,
1320xe6, 0x01, 0x01, 0x38, 0x01, 0xa7, 0x66, 0x6f, 0x72, 0x00, 1320x31, 0x05, 0x00, 0x34, 0x33, 0x27, 0x29, 0xe6, 0x01, 0x01,
1330x64, 0x69, 0x61, 0x67, 0x6f, 0x6e, 0xa1, 0x00, 0x00, 0x6e, 1330x38, 0x01, 0xa7, 0x66, 0x6f, 0x72, 0x00, 0x64, 0x69, 0x61,
1340x01, 0x23, 0x28, 0x41, 0x4e, 0x01, 0x13, 0x61, 0xdc, 0x00, 1340x67, 0x6f, 0x6e, 0xa1, 0x00, 0x00, 0x6e, 0x01, 0x23, 0x28,
1350x81, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x48, 1350x41, 0x4e, 0x01, 0x13, 0x61, 0xdc, 0x00, 0x81, 0x64, 0x65,
1360x01, 0x12, 0x73, 0xf2, 0x00, 0x41, 0x00, 0x32, 0x2e, 0x31, 1360x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x48, 0x01, 0x12, 0x73,
1370xbe, 0x05, 0x01, 0x89, 0x01, 0x60, 0x61, 0x76, 0x61, 0x69, 1370xf2, 0x00, 0x41, 0x00, 0x32, 0x2e, 0x31, 0xbe, 0x05, 0x01,
1380x6c, 0x61, 0x90, 0x03, 0x11, 0x29, 0x6b, 0x02, 0x12, 0x32, 1380x89, 0x01, 0x60, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x90,
1390x6b, 0x02, 0x93, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 1390x03, 0x11, 0x29, 0x6b, 0x02, 0x12, 0x32, 0x6b, 0x02, 0x93,
1400x65, 0x72, 0x6d, 0x02, 0x10, 0x65, 0xd7, 0x01, 0x05, 0x14, 1400x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x6d,
1410x00, 0x02, 0x3f, 0x00, 0x04, 0x3a, 0x00, 0x51, 0x00, 0x66, 1410x02, 0x10, 0x65, 0xd7, 0x01, 0x05, 0x14, 0x00, 0x02, 0x3f,
1420x72, 0x6f, 0x6d, 0x77, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 1420x00, 0x04, 0x3a, 0x00, 0x51, 0x00, 0x66, 0x72, 0x6f, 0x6d,
1430x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 1430x77, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d,
1440x6d, 0x00, 0x03, 0xe3, 0x00, 0xb1, 0x60, 0x54, 0x79, 0x70, 1440x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x6d, 0x00, 0x03,
1450x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0x17, 0x02, 0x71, 1450xe3, 0x00, 0xb1, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00,
1460x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x43, 0x02, 0x92, 1460x6d, 0x65, 0x6e, 0x75, 0x17, 0x02, 0x71, 0x79, 0x70, 0x65,
1470x00, 0x00, 0x00, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x44, 1470x20, 0x6f, 0x66, 0x20, 0x43, 0x02, 0x92, 0x00, 0x00, 0x00,
1480x02, 0x02, 0x14, 0x00, 0x04, 0x1c, 0x02, 0x10, 0x28, 0x77, 1480x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x44, 0x02, 0x02, 0x14,
1490x03, 0x20, 0x68, 0x65, 0xe4, 0x03, 0x01, 0x1d, 0x00, 0x35, 1490x00, 0x04, 0x1c, 0x02, 0x10, 0x28, 0x77, 0x03, 0x20, 0x68,
1500x68, 0x61, 0x70, 0x6f, 0x05, 0x00, 0xe9, 0x01, 0x2a, 0x29, 1500x65, 0xe4, 0x03, 0x01, 0x1d, 0x00, 0x35, 0x68, 0x61, 0x70,
1510x3a, 0x87, 0x03, 0x02, 0x22, 0x05, 0x06, 0x8a, 0x03, 0x10, 1510x6f, 0x05, 0x00, 0xe9, 0x01, 0x2a, 0x29, 0x3a, 0x87, 0x03,
1520x2c, 0xf9, 0x02, 0x0b, 0x88, 0x03, 0xf0, 0x0c, 0x57, 0x69, 1520x02, 0x22, 0x05, 0x06, 0x8a, 0x03, 0x10, 0x2c, 0xf9, 0x02,
1530x64, 0x74, 0x68, 0x20, 0x2f, 0x20, 0x74, 0x6f, 0x70, 0x2c, 1530x0b, 0x88, 0x03, 0xf0, 0x0c, 0x57, 0x69, 0x64, 0x74, 0x68,
1540x00, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x2f, 0x20, 1540x20, 0x2f, 0x20, 0x74, 0x6f, 0x70, 0x2c, 0x00, 0x48, 0x65,
1550x62, 0x6f, 0x74, 0x74, 0x6f, 0x70, 0x03, 0x1d, 0x4f, 0x1f, 1550x69, 0x67, 0x68, 0x74, 0x20, 0x2f, 0x20, 0x62, 0x6f, 0x74,
1560x04, 0x50, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x58, 0x05, 0x11, 1560x74, 0x6f, 0x70, 0x03, 0x1d, 0x4f, 0x1f, 0x04, 0x50, 0x68,
1570x6c, 0x06, 0x04, 0x14, 0x76, 0x1d, 0x02, 0x65, 0x64, 0x69, 1570x6f, 0x72, 0x69, 0x7a, 0x58, 0x05, 0x11, 0x6c, 0x06, 0x04,
1580x6d, 0x65, 0x6e, 0x73, 0x88, 0x02, 0x0d, 0x34, 0x04, 0x14, 1580x14, 0x76, 0x1d, 0x02, 0x65, 0x64, 0x69, 0x6d, 0x65, 0x6e,
1590x2c, 0xdf, 0x01, 0x10, 0x62, 0xae, 0x07, 0x13, 0x66, 0x1f, 1590x73, 0x88, 0x02, 0x0d, 0x34, 0x04, 0x14, 0x2c, 0xdf, 0x01,
1600x00, 0x25, 0x6c, 0x65, 0xfa, 0x01, 0x31, 0x74, 0x6f, 0x70, 1600x10, 0x62, 0xae, 0x07, 0x13, 0x66, 0x1f, 0x00, 0x25, 0x6c,
1610x52, 0x00, 0x03, 0x7c, 0x00, 0x40, 0x72, 0x6f, 0x77, 0x73, 1610x65, 0xfa, 0x01, 0x31, 0x74, 0x6f, 0x70, 0x52, 0x00, 0x03,
1620x41, 0x07, 0xb0, 0x70, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 1620x7c, 0x00, 0x40, 0x72, 0x6f, 0x77, 0x73, 0x41, 0x07, 0xb0,
1630x6c, 0x79, 0x2e, 0x00, 1630x70, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x6c, 0x79, 0x2e,
1640x00,
164}; 165};
165 166
166const unsigned short help_text_len = 2055; 167const unsigned short help_text_len = 2071;
167const unsigned short help_text_words = 385; 168const unsigned short help_text_words = 386;
168const char quick_help_text[] = "Pick up all the blue squares by rolling the cube over them."; 169const char quick_help_text[] = "Pick up all the blue squares by rolling the cube over them.";
diff --git a/apps/plugins/puzzles/help/dominosa.c b/apps/plugins/puzzles/help/dominosa.c
index 388abb16d4..34958feb22 100644
--- a/apps/plugins/puzzles/help/dominosa.c
+++ b/apps/plugins/puzzles/help/dominosa.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,174 +6,174 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 88, TEXT_CENTER | C_RED }, 9 { 89, TEXT_CENTER | C_RED },
10 { 151, TEXT_UNDERLINE }, 10 { 152, TEXT_UNDERLINE },
11 { 267, TEXT_CENTER | C_RED }, 11 { 268, TEXT_CENTER | C_RED },
12 { 284, TEXT_UNDERLINE }, 12 { 285, TEXT_UNDERLINE },
13 { 336, TEXT_UNDERLINE }, 13 { 337, TEXT_UNDERLINE },
14 { 377, TEXT_UNDERLINE }, 14 { 378, TEXT_UNDERLINE },
15 LAST_STYLE_ITEM 15 LAST_STYLE_ITEM
16}; 16};
17 17
18/* orig 2278 comp 1541 ratio 0.676471 level 10 saved 737 */ 18/* orig 2299 comp 1550 ratio 0.674206 level 10 saved 749 */
19const char help_text[] = { 19const char help_text[] = {
200xf1, 0x1a, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 200xff, 0x08, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
210x31, 0x37, 0x3a, 0x20, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x6f, 210x31, 0x37, 0x3a, 0x20, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x6f,
220x73, 0x61, 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x6e, 0x6f, 220x73, 0x61, 0x20, 0x00, 0x2d, 0x01, 0x00, 0x00, 0xf1, 0x05,
230x72, 0x6d, 0x61, 0x6c, 0x00, 0x73, 0x65, 0x74, 0x00, 0x6f, 230x00, 0x00, 0x00, 0x41, 0x00, 0x6e, 0x6f, 0x72, 0x6d, 0x61,
240x66, 0x00, 0x64, 0x1c, 0x00, 0xf0, 0x0b, 0x65, 0x73, 0x00, 240x6c, 0x00, 0x73, 0x65, 0x74, 0x00, 0x6f, 0x66, 0x00, 0x64,
250x2d, 0x00, 0x74, 0x68, 0x61, 0x74, 0x00, 0x69, 0x73, 0x2c, 250x31, 0x00, 0xf0, 0x0b, 0x65, 0x73, 0x00, 0x2d, 0x00, 0x74,
260x00, 0x6f, 0x6e, 0x65, 0x00, 0x69, 0x6e, 0x73, 0x74, 0x61, 260x68, 0x61, 0x74, 0x00, 0x69, 0x73, 0x2c, 0x00, 0x6f, 0x6e,
270x6e, 0x63, 0x65, 0x24, 0x00, 0xf0, 0x07, 0x65, 0x76, 0x65, 270x65, 0x00, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
280x72, 0x79, 0x00, 0x28, 0x75, 0x6e, 0x6f, 0x72, 0x64, 0x65, 280x24, 0x00, 0xf0, 0x07, 0x65, 0x76, 0x65, 0x72, 0x79, 0x00,
290x72, 0x65, 0x64, 0x29, 0x00, 0x70, 0x61, 0x69, 0x72, 0x1a, 290x28, 0x75, 0x6e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64,
300x00, 0xf0, 0x3b, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 300x29, 0x00, 0x70, 0x61, 0x69, 0x72, 0x1a, 0x00, 0xf0, 0x3b,
310x00, 0x66, 0x72, 0x6f, 0x6d, 0x00, 0x30, 0x00, 0x74, 0x6f, 310x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x00, 0x66, 0x72,
320x00, 0x36, 0x00, 0x2d, 0x00, 0x68, 0x61, 0x73, 0x00, 0x62, 320x6f, 0x6d, 0x00, 0x30, 0x00, 0x74, 0x6f, 0x00, 0x36, 0x00,
330x65, 0x65, 0x6e, 0x00, 0x61, 0x72, 0x72, 0x61, 0x6e, 0x67, 330x2d, 0x00, 0x68, 0x61, 0x73, 0x00, 0x62, 0x65, 0x65, 0x6e,
340x65, 0x64, 0x00, 0x69, 0x72, 0x72, 0x65, 0x67, 0x75, 0x6c, 340x00, 0x61, 0x72, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x00,
350x61, 0x72, 0x6c, 0x79, 0x00, 0x69, 0x6e, 0x74, 0x6f, 0x00, 350x69, 0x72, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x6c,
360x61, 0x00, 0x72, 0x65, 0x63, 0x74, 0x61, 0x6e, 0x67, 0x6c, 360x79, 0x00, 0x69, 0x6e, 0x74, 0x6f, 0x00, 0x61, 0x00, 0x72,
370x65, 0x3b, 0x00, 0x74, 0x68, 0x65, 0x6e, 0x05, 0x00, 0x03, 370x65, 0x63, 0x74, 0x61, 0x6e, 0x67, 0x6c, 0x65, 0x3b, 0x00,
380x4f, 0x00, 0xf6, 0x00, 0x00, 0x69, 0x6e, 0x00, 0x65, 0x61, 380x74, 0x68, 0x65, 0x6e, 0x05, 0x00, 0x03, 0x4f, 0x00, 0xf6,
390x63, 0x68, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x4f, 390x00, 0x00, 0x69, 0x6e, 0x00, 0x65, 0x61, 0x63, 0x68, 0x00,
400x00, 0xf1, 0x01, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 400x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x4f, 0x00, 0xf1, 0x01,
410x00, 0x64, 0x6f, 0x77, 0x6e, 0x00, 0x61, 0x6e, 0x64, 0x34, 410x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x00, 0x64, 0x6f,
420x00, 0x05, 0xc1, 0x00, 0xf0, 0x11, 0x74, 0x68, 0x65, 0x6d, 420x77, 0x6e, 0x00, 0x61, 0x6e, 0x64, 0x34, 0x00, 0x05, 0xc1,
430x73, 0x65, 0x6c, 0x76, 0x65, 0x73, 0x00, 0x72, 0x65, 0x6d, 430x00, 0xf0, 0x11, 0x74, 0x68, 0x65, 0x6d, 0x73, 0x65, 0x6c,
440x6f, 0x76, 0x65, 0x64, 0x2e, 0x00, 0x59, 0x6f, 0x75, 0x72, 440x76, 0x65, 0x73, 0x00, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65,
450x00, 0x74, 0x61, 0x73, 0x6b, 0x00, 0x69, 0x73, 0x9e, 0x00, 450x64, 0x2e, 0x00, 0x59, 0x6f, 0x75, 0x72, 0x00, 0x74, 0x61,
460xb1, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x75, 460x73, 0x6b, 0x00, 0x69, 0x73, 0x9e, 0x00, 0xb1, 0x72, 0x65,
470x63, 0x74, 0x3d, 0x00, 0xa3, 0x70, 0x61, 0x74, 0x74, 0x65, 470x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x3d,
480x72, 0x6e, 0x00, 0x62, 0x79, 0xac, 0x00, 0x31, 0x69, 0x6e, 480x00, 0xa3, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x00,
490x67, 0x19, 0x00, 0x0c, 0x1e, 0x01, 0x82, 0x74, 0x6f, 0x00, 490x62, 0x79, 0xac, 0x00, 0x31, 0x69, 0x6e, 0x67, 0x19, 0x00,
500x6d, 0x61, 0x74, 0x63, 0x68, 0x36, 0x00, 0x71, 0x72, 0x6f, 500x0c, 0x1e, 0x01, 0x82, 0x74, 0x6f, 0x00, 0x6d, 0x61, 0x74,
510x76, 0x69, 0x64, 0x65, 0x64, 0x34, 0x00, 0x17, 0x79, 0x08, 510x63, 0x68, 0x36, 0x00, 0x71, 0x72, 0x6f, 0x76, 0x69, 0x64,
520x01, 0xf0, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 520x65, 0x64, 0x34, 0x00, 0x17, 0x79, 0x08, 0x01, 0xf0, 0x00,
530x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x75, 0x00, 530x2e, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x73, 0x00, 0x70,
540xf0, 0x00, 0x77, 0x69, 0x64, 0x65, 0x6c, 0x79, 0x00, 0x63, 540x75, 0x7a, 0x7a, 0x6c, 0x65, 0x75, 0x00, 0xf0, 0x00, 0x77,
550x72, 0x65, 0x64, 0x69, 0x74, 0x65, 0x64, 0x49, 0x00, 0xc2, 550x69, 0x64, 0x65, 0x6c, 0x79, 0x00, 0x63, 0x72, 0x65, 0x64,
560x4f, 0x2e, 0x00, 0x53, 0x2e, 0x00, 0x41, 0x64, 0x6c, 0x65, 560x69, 0x74, 0x65, 0x64, 0x49, 0x00, 0xc2, 0x4f, 0x2e, 0x00,
570x72, 0x2c, 0xc7, 0x00, 0x81, 0x61, 0x6b, 0x65, 0x73, 0x00, 570x53, 0x2e, 0x00, 0x41, 0x64, 0x6c, 0x65, 0x72, 0x2c, 0xc7,
580x70, 0x61, 0x72, 0x74, 0x00, 0x82, 0x69, 0x74, 0x73, 0x00, 580x00, 0x81, 0x61, 0x6b, 0x65, 0x73, 0x00, 0x70, 0x61, 0x72,
590x6e, 0x61, 0x6d, 0x65, 0x55, 0x01, 0x40, 0x74, 0x68, 0x6f, 590x74, 0x00, 0x82, 0x69, 0x74, 0x73, 0x00, 0x6e, 0x61, 0x6d,
600x73, 0x8e, 0x01, 0x51, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x61, 600x65, 0x55, 0x01, 0x40, 0x74, 0x68, 0x6f, 0x73, 0x8e, 0x01,
610x00, 0x46, 0x31, 0x37, 0x2e, 0x31, 0xd3, 0x01, 0x80, 0x63, 610x51, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x61, 0x00, 0x46, 0x31,
620x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0xdc, 0x01, 0xa0, 620x37, 0x2e, 0x31, 0xe8, 0x01, 0xf0, 0x07, 0x63, 0x6f, 0x6e,
630x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 630x74, 0x72, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00, 0x00, 0x4c,
640xc7, 0x00, 0x41, 0x62, 0x65, 0x74, 0x77, 0x85, 0x01, 0xf5, 640x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0xc7,
650x00, 0x6e, 0x79, 0x00, 0x74, 0x77, 0x6f, 0x00, 0x61, 0x64, 650x00, 0x41, 0x62, 0x65, 0x74, 0x77, 0x85, 0x01, 0xf5, 0x00,
660x6a, 0x61, 0x63, 0x65, 0x6e, 0x74, 0xb5, 0x01, 0x83, 0x70, 660x6e, 0x79, 0x00, 0x74, 0x77, 0x6f, 0x00, 0x61, 0x64, 0x6a,
670x6c, 0x61, 0x63, 0x65, 0x73, 0x00, 0x61, 0xe6, 0x00, 0x63, 670x61, 0x63, 0x65, 0x6e, 0x74, 0xb5, 0x01, 0x83, 0x70, 0x6c,
680x00, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x01, 0x01, 0x53, 0x6d, 680x61, 0x63, 0x65, 0x73, 0x00, 0x61, 0xe6, 0x00, 0x63, 0x00,
690x2c, 0x00, 0x6f, 0x72, 0x48, 0x01, 0x12, 0x73, 0x11, 0x02, 690x63, 0x6f, 0x76, 0x65, 0x72, 0x01, 0x01, 0x53, 0x6d, 0x2c,
700x00, 0x9a, 0x00, 0x00, 0xd2, 0x00, 0xf1, 0x05, 0x61, 0x6c, 700x00, 0x6f, 0x72, 0x48, 0x01, 0x12, 0x73, 0x11, 0x02, 0x00,
710x72, 0x65, 0x61, 0x64, 0x79, 0x00, 0x70, 0x72, 0x65, 0x73, 710x9a, 0x00, 0x00, 0xd2, 0x00, 0xf1, 0x05, 0x61, 0x6c, 0x72,
720x65, 0x6e, 0x74, 0x2e, 0x00, 0x54, 0x72, 0x79, 0x36, 0x00, 720x65, 0x61, 0x64, 0x79, 0x00, 0x70, 0x72, 0x65, 0x73, 0x65,
730x12, 0x6f, 0x52, 0x00, 0x06, 0x51, 0x00, 0x60, 0x77, 0x68, 730x6e, 0x74, 0x2e, 0x00, 0x54, 0x72, 0x79, 0x36, 0x00, 0x12,
740x69, 0x63, 0x68, 0x00, 0x56, 0x00, 0xa0, 0x6c, 0x61, 0x70, 740x6f, 0x52, 0x00, 0x06, 0x51, 0x00, 0x60, 0x77, 0x68, 0x69,
750x73, 0x00, 0x65, 0x78, 0x69, 0x73, 0x74, 0x2a, 0x00, 0x05, 750x63, 0x68, 0x00, 0x56, 0x00, 0xa0, 0x6c, 0x61, 0x70, 0x73,
760x56, 0x01, 0x43, 0x77, 0x69, 0x6c, 0x6c, 0x65, 0x00, 0x01, 760x00, 0x65, 0x78, 0x69, 0x73, 0x74, 0x2a, 0x00, 0x05, 0x56,
770x59, 0x01, 0x40, 0x6f, 0x6e, 0x65, 0x73, 0x66, 0x00, 0x04, 770x01, 0x43, 0x77, 0x69, 0x6c, 0x6c, 0x65, 0x00, 0x01, 0x59,
780x33, 0x00, 0x00, 0xef, 0x00, 0x4e, 0x52, 0x69, 0x67, 0x68, 780x01, 0x40, 0x6f, 0x6e, 0x65, 0x73, 0x66, 0x00, 0x04, 0x33,
790xd6, 0x00, 0x0f, 0xd2, 0x00, 0x03, 0x40, 0x64, 0x72, 0x61, 790x00, 0x00, 0xef, 0x00, 0x4e, 0x52, 0x69, 0x67, 0x68, 0xd6,
800x77, 0xd1, 0x00, 0x46, 0x6c, 0x69, 0x6e, 0x65, 0x2a, 0x00, 800x00, 0x0f, 0xd2, 0x00, 0x03, 0x40, 0x64, 0x72, 0x61, 0x77,
810x01, 0xce, 0x00, 0x02, 0x8c, 0x00, 0xb2, 0x79, 0x6f, 0x75, 810xd1, 0x00, 0x46, 0x6c, 0x69, 0x6e, 0x65, 0x2a, 0x00, 0x01,
820x00, 0x63, 0x61, 0x6e, 0x00, 0x75, 0x73, 0x65, 0x0f, 0x02, 820xce, 0x00, 0x02, 0x8c, 0x00, 0xb2, 0x79, 0x6f, 0x75, 0x00,
830x40, 0x6d, 0x69, 0x6e, 0x64, 0x16, 0x00, 0x52, 0x72, 0x73, 830x63, 0x61, 0x6e, 0x00, 0x75, 0x73, 0x65, 0x0f, 0x02, 0x40,
840x65, 0x6c, 0x66, 0x02, 0x03, 0x00, 0x24, 0x00, 0x43, 0x6b, 840x6d, 0x69, 0x6e, 0x64, 0x16, 0x00, 0x52, 0x72, 0x73, 0x65,
850x6e, 0x6f, 0x77, 0x7b, 0x01, 0x00, 0x69, 0x00, 0x04, 0x60, 850x6c, 0x66, 0x02, 0x03, 0x00, 0x24, 0x00, 0x43, 0x6b, 0x6e,
860x00, 0x00, 0x8e, 0x02, 0x32, 0x6e, 0x6f, 0x74, 0x2a, 0x01, 860x6f, 0x77, 0x7b, 0x01, 0x00, 0x69, 0x00, 0x04, 0x60, 0x00,
870x21, 0x65, 0x64, 0x37, 0x02, 0x30, 0x00, 0x73, 0x69, 0xc6, 870x00, 0x8e, 0x02, 0x32, 0x6e, 0x6f, 0x74, 0x2a, 0x01, 0x21,
880x02, 0x03, 0xd5, 0x00, 0x1c, 0x2e, 0xb0, 0x00, 0x55, 0x61, 880x65, 0x64, 0x37, 0x02, 0x30, 0x00, 0x73, 0x69, 0xc6, 0x02,
890x67, 0x61, 0x69, 0x6e, 0x49, 0x01, 0x00, 0xe5, 0x00, 0x00, 890x03, 0xd5, 0x00, 0x1c, 0x2e, 0xb0, 0x00, 0x55, 0x61, 0x67,
900x9d, 0x00, 0x00, 0xd9, 0x00, 0x13, 0x59, 0x8c, 0x00, 0x42, 900x61, 0x69, 0x6e, 0x49, 0x01, 0x00, 0xe5, 0x00, 0x00, 0x9d,
910x61, 0x6c, 0x73, 0x6f, 0x91, 0x00, 0xd2, 0x68, 0x65, 0x00, 910x00, 0x00, 0xd9, 0x00, 0x13, 0x59, 0x8c, 0x00, 0x42, 0x61,
920x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 920x6c, 0x73, 0x6f, 0x91, 0x00, 0xd2, 0x68, 0x65, 0x00, 0x63,
930x74, 0x02, 0x00, 0x1a, 0x01, 0x14, 0x61, 0x16, 0x00, 0x43, 930x75, 0x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x74,
940x61, 0x72, 0x6f, 0x75, 0xf6, 0x02, 0x74, 0x67, 0x72, 0x69, 940x02, 0x00, 0x1a, 0x01, 0x14, 0x61, 0x16, 0x00, 0x43, 0x61,
950x64, 0x2e, 0x00, 0x57, 0x39, 0x03, 0x03, 0x21, 0x00, 0xbf, 950x72, 0x6f, 0x75, 0xf6, 0x02, 0x74, 0x67, 0x72, 0x69, 0x64,
960x69, 0x73, 0x00, 0x68, 0x61, 0x6c, 0x66, 0x00, 0x77, 0x61, 960x2e, 0x00, 0x57, 0x39, 0x03, 0x03, 0x21, 0x00, 0xbf, 0x69,
970x79, 0x29, 0x01, 0x0a, 0x11, 0x2c, 0xbd, 0x01, 0x14, 0x73, 970x73, 0x00, 0x68, 0x61, 0x6c, 0x66, 0x00, 0x77, 0x61, 0x79,
980xed, 0x02, 0x60, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x75, 980x29, 0x01, 0x0a, 0x11, 0x2c, 0xbd, 0x01, 0x14, 0x73, 0xed,
990x00, 0x02, 0x92, 0x01, 0x0b, 0xc7, 0x01, 0x07, 0x18, 0x02, 990x02, 0x60, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x75, 0x00,
1000x00, 0x11, 0x01, 0x05, 0x44, 0x00, 0x2a, 0x6f, 0x72, 0x47, 1000x02, 0x92, 0x01, 0x0b, 0xc7, 0x01, 0x07, 0x18, 0x02, 0x00,
1010x00, 0x20, 0x73, 0x70, 0x37, 0x00, 0x32, 0x62, 0x61, 0x72, 1010x11, 0x01, 0x05, 0x44, 0x00, 0x2a, 0x6f, 0x72, 0x47, 0x00,
1020x46, 0x00, 0x3e, 0x6c, 0x61, 0x79, 0x8b, 0x01, 0x02, 0x50, 1020x20, 0x73, 0x70, 0x37, 0x00, 0x32, 0x62, 0x61, 0x72, 0x46,
1030x01, 0x02, 0xd9, 0x03, 0x81, 0x73, 0x2e, 0x00, 0x52, 0x65, 1030x00, 0x3e, 0x6c, 0x61, 0x79, 0x8b, 0x01, 0x02, 0x50, 0x01,
1040x70, 0x65, 0x61, 0x14, 0x02, 0xca, 0x65, 0x69, 0x74, 0x68, 1040x02, 0xd9, 0x03, 0x81, 0x73, 0x2e, 0x00, 0x52, 0x65, 0x70,
1050x65, 0x72, 0x00, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x30, 0x01, 1050x65, 0x61, 0x14, 0x02, 0xca, 0x65, 0x69, 0x74, 0x68, 0x65,
1060x03, 0x86, 0x00, 0x25, 0x6f, 0x72, 0x3a, 0x01, 0x14, 0x50, 1060x72, 0x00, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x30, 0x01, 0x03,
1070x76, 0x00, 0x14, 0x61, 0x32, 0x04, 0x05, 0xbb, 0x00, 0x50, 1070x86, 0x00, 0x25, 0x6f, 0x72, 0x3a, 0x01, 0x14, 0x50, 0x76,
1080x68, 0x69, 0x67, 0x68, 0x6c, 0x82, 0x01, 0xe0, 0x00, 0x61, 1080x00, 0x14, 0x61, 0x32, 0x04, 0x05, 0xbb, 0x00, 0x50, 0x68,
1090x6c, 0x6c, 0x00, 0x6f, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 1090x69, 0x67, 0x68, 0x6c, 0x82, 0x01, 0xe0, 0x00, 0x61, 0x6c,
1100x6e, 0x63, 0xc4, 0x02, 0x03, 0xdf, 0x01, 0x02, 0x32, 0x00, 1100x6c, 0x00, 0x6f, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
1110x16, 0x2e, 0x45, 0x00, 0x07, 0x16, 0x00, 0x03, 0xae, 0x01, 1110x63, 0xc4, 0x02, 0x03, 0xdf, 0x01, 0x02, 0x32, 0x00, 0x16,
1120x01, 0x4a, 0x00, 0x51, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x81, 1120x2e, 0x45, 0x00, 0x07, 0x16, 0x00, 0x03, 0xae, 0x01, 0x01,
1130x00, 0x05, 0x54, 0x00, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x00, 1130x4a, 0x00, 0x51, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x81, 0x00,
1140x55, 0x70, 0x99, 0x01, 0x00, 0xc6, 0x00, 0x68, 0x64, 0x69, 1140x05, 0x54, 0x00, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x00, 0x55,
1150x66, 0x66, 0x65, 0x72, 0x80, 0x02, 0x00, 0xcf, 0x01, 0x17, 1150x70, 0x99, 0x01, 0x00, 0xc6, 0x00, 0x68, 0x64, 0x69, 0x66,
1160x62, 0x31, 0x00, 0x00, 0x23, 0x04, 0x11, 0x74, 0x81, 0x03, 1160x66, 0x65, 0x72, 0x80, 0x02, 0x00, 0xcf, 0x01, 0x17, 0x62,
1170x30, 0x67, 0x69, 0x76, 0x00, 0x01, 0x21, 0x69, 0x6d, 0xc1, 1170x31, 0x00, 0x00, 0x23, 0x04, 0x11, 0x74, 0x81, 0x03, 0x30,
1180x00, 0x41, 0x28, 0x41, 0x6c, 0x6c, 0x5b, 0x00, 0x02, 0xef, 1180x67, 0x69, 0x76, 0x00, 0x01, 0x21, 0x69, 0x6d, 0xc1, 0x00,
1190x00, 0xb0, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 1190x41, 0x28, 0x41, 0x6c, 0x6c, 0x5b, 0x00, 0x02, 0xef, 0x00,
1200x62, 0x65, 0x64, 0xfc, 0x04, 0x22, 0x73, 0x65, 0x05, 0x01, 1200xb0, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62,
1210x31, 0x32, 0x2e, 0x31, 0x72, 0x02, 0x01, 0x21, 0x02, 0xb2, 1210x65, 0x64, 0xfc, 0x04, 0x22, 0x73, 0x65, 0x05, 0x01, 0x31,
1220x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 1220x32, 0x2e, 0x31, 0x72, 0x02, 0x01, 0x21, 0x02, 0xb2, 0x61,
1230x29, 0x04, 0x04, 0x16, 0x32, 0x04, 0x04, 0xb1, 0x70, 0x61, 1230x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29,
1240x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x81, 1240x04, 0x04, 0x16, 0x32, 0x04, 0x04, 0xb1, 0x70, 0x61, 0x72,
1250x04, 0x46, 0x65, 0x73, 0x65, 0x00, 0x14, 0x00, 0x02, 0x44, 1250x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x81, 0x04,
1260x00, 0x04, 0x3f, 0x00, 0x04, 0x56, 0x04, 0xf1, 0x01, 0x65, 1260x46, 0x65, 0x73, 0x65, 0x00, 0x14, 0x00, 0x02, 0x44, 0x00,
1270x00, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 1270x04, 0x3f, 0x00, 0x04, 0x56, 0x04, 0xf1, 0x01, 0x65, 0x00,
1280x2e, 0x27, 0x00, 0x6f, 0x70, 0x72, 0x00, 0x22, 0x6f, 0x6e, 1280x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e,
1290x1a, 0x00, 0xa0, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 1290x27, 0x00, 0x6f, 0x70, 0x72, 0x00, 0x22, 0x6f, 0x6e, 0x1a,
1300x65, 0x6e, 0x75, 0xae, 0x00, 0x82, 0x4d, 0x61, 0x78, 0x69, 1300x00, 0xa0, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65,
1310x6d, 0x75, 0x6d, 0x20, 0xe6, 0x00, 0x45, 0x20, 0x6f, 0x6e, 1310x6e, 0x75, 0xae, 0x00, 0x82, 0x4d, 0x61, 0x78, 0x69, 0x6d,
1320x20, 0xc1, 0x03, 0x33, 0x00, 0x00, 0x43, 0x80, 0x04, 0x02, 1320x75, 0x6d, 0x20, 0xe6, 0x00, 0x45, 0x20, 0x6f, 0x6e, 0x20,
1330x02, 0x02, 0x32, 0x69, 0x7a, 0x65, 0x69, 0x01, 0x13, 0x65, 1330xc1, 0x03, 0x33, 0x00, 0x00, 0x43, 0x80, 0x04, 0x02, 0x02,
1340x03, 0x05, 0x10, 0x2c, 0x24, 0x03, 0x03, 0xa4, 0x04, 0x15, 1340x02, 0x32, 0x69, 0x7a, 0x65, 0x69, 0x01, 0x13, 0x65, 0x03,
1350x6c, 0x29, 0x02, 0x07, 0x27, 0x00, 0x0c, 0x69, 0x05, 0x42, 1350x05, 0x10, 0x2c, 0x24, 0x03, 0x03, 0xa4, 0x04, 0x15, 0x6c,
1360x75, 0x73, 0x65, 0x64, 0x6e, 0x05, 0x86, 0x6b, 0x65, 0x00, 1360x29, 0x02, 0x07, 0x27, 0x00, 0x0c, 0x69, 0x05, 0x42, 0x75,
1370x69, 0x74, 0x2e, 0x00, 0x44, 0x2d, 0x04, 0x25, 0x74, 0x68, 1370x73, 0x65, 0x64, 0x6e, 0x05, 0x86, 0x6b, 0x65, 0x00, 0x69,
1380x6a, 0x01, 0x20, 0x67, 0x6f, 0x4d, 0x00, 0x11, 0x75, 0x8c, 1380x74, 0x2e, 0x00, 0x44, 0x2d, 0x04, 0x25, 0x74, 0x68, 0x6a,
1390x01, 0x12, 0x4e, 0xb1, 0x01, 0x00, 0x63, 0x01, 0x32, 0x00, 1390x01, 0x20, 0x67, 0x6f, 0x4d, 0x00, 0x11, 0x75, 0x8c, 0x01,
1400x72, 0x69, 0xda, 0x03, 0xa0, 0x61, 0x6e, 0x00, 0x28, 0x4e, 1400x12, 0x4e, 0xb1, 0x01, 0x00, 0x63, 0x01, 0x32, 0x00, 0x72,
1410x2b, 0x32, 0x29, 0x00, 0x78, 0x08, 0x00, 0x28, 0x31, 0x29, 1410x69, 0xda, 0x03, 0xa0, 0x61, 0x6e, 0x00, 0x28, 0x4e, 0x2b,
1420x6f, 0x06, 0x30, 0x73, 0x6f, 0x2c, 0x67, 0x01, 0x00, 0x70, 1420x32, 0x29, 0x00, 0x78, 0x08, 0x00, 0x28, 0x31, 0x29, 0x6f,
1430x05, 0x20, 0x69, 0x63, 0x95, 0x06, 0x12, 0x2c, 0x68, 0x02, 1430x06, 0x30, 0x73, 0x6f, 0x2c, 0x67, 0x01, 0x00, 0x70, 0x05,
1440xb1, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x76, 0x61, 1440x20, 0x69, 0x63, 0x95, 0x06, 0x12, 0x2c, 0x68, 0x02, 0xb1,
1450x6c, 0x75, 0x9f, 0x00, 0x11, 0x36, 0x53, 0x00, 0x10, 0x73, 1450x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x76, 0x61, 0x6c,
1460x4c, 0x00, 0x33, 0x38, 0x78, 0x37, 0x73, 0x03, 0xf1, 0x05, 1460x75, 0x9f, 0x00, 0x11, 0x36, 0x53, 0x00, 0x10, 0x73, 0x4c,
1470x00, 0x00, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x20, 0x75, 1470x00, 0x33, 0x38, 0x78, 0x37, 0x73, 0x03, 0xf1, 0x05, 0x00,
1480x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x73, 0x6f, 0x6c, 0x75, 1480x00, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x20, 0x75, 0x6e,
1490x3c, 0x01, 0x31, 0x00, 0x00, 0x4e, 0x59, 0x07, 0x44, 0x6c, 1490x69, 0x71, 0x75, 0x65, 0x20, 0x73, 0x6f, 0x6c, 0x75, 0x3c,
1500x79, 0x2c, 0x00, 0x9a, 0x01, 0x02, 0x99, 0x00, 0x01, 0xcb, 1500x01, 0x31, 0x00, 0x00, 0x4e, 0x59, 0x07, 0x44, 0x6c, 0x79,
1510x00, 0x00, 0x34, 0x00, 0x02, 0x6b, 0x02, 0x06, 0x1d, 0x01, 1510x2c, 0x00, 0x9a, 0x01, 0x02, 0x99, 0x00, 0x01, 0xcb, 0x00,
1520x01, 0xec, 0x04, 0x03, 0x47, 0x05, 0x00, 0xba, 0x03, 0x10, 1520x00, 0x34, 0x00, 0x02, 0x6b, 0x02, 0x06, 0x1d, 0x01, 0x01,
1530x76, 0x02, 0x05, 0x21, 0x6c, 0x79, 0x6f, 0x05, 0x04, 0x58, 1530xec, 0x04, 0x03, 0x47, 0x05, 0x00, 0xba, 0x03, 0x10, 0x76,
1540x00, 0x33, 0x2e, 0x00, 0x50, 0x2c, 0x00, 0x01, 0x00, 0x01, 1540x02, 0x05, 0x21, 0x6c, 0x79, 0x6f, 0x05, 0x04, 0x58, 0x00,
1550x94, 0x61, 0x6d, 0x62, 0x69, 0x67, 0x75, 0x6f, 0x75, 0x73, 1550x33, 0x2e, 0x00, 0x50, 0x2c, 0x00, 0x01, 0x00, 0x01, 0x94,
1560x26, 0x02, 0x05, 0x75, 0x02, 0x41, 0x6d, 0x6f, 0x72, 0x65, 1560x61, 0x6d, 0x62, 0x69, 0x67, 0x75, 0x6f, 0x75, 0x73, 0x26,
1570x93, 0x02, 0x00, 0xd4, 0x00, 0x11, 0x74, 0x58, 0x06, 0x40, 1570x02, 0x05, 0x75, 0x02, 0x41, 0x6d, 0x6f, 0x72, 0x65, 0x93,
1580x73, 0x6f, 0x6d, 0x65, 0x73, 0x02, 0x12, 0x73, 0x1d, 0x00, 1580x02, 0x00, 0xd4, 0x00, 0x11, 0x74, 0x58, 0x06, 0x40, 0x73,
1590x40, 0x73, 0x75, 0x62, 0x74, 0x92, 0x01, 0x20, 0x73, 0x6f, 1590x6f, 0x6d, 0x65, 0x73, 0x02, 0x12, 0x73, 0x1d, 0x00, 0x40,
1600xcd, 0x05, 0x00, 0xe7, 0x04, 0x45, 0x6c, 0x69, 0x6b, 0x65, 1600x73, 0x75, 0x62, 0x74, 0x92, 0x01, 0x20, 0x73, 0x6f, 0xcd,
1610x14, 0x05, 0x01, 0x04, 0x04, 0x20, 0x6f, 0x66, 0x97, 0x01, 1610x05, 0x00, 0xe7, 0x04, 0x45, 0x6c, 0x69, 0x6b, 0x65, 0x14,
1620xe0, 0x69, 0x73, 0x00, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 1620x05, 0x01, 0x04, 0x04, 0x20, 0x6f, 0x66, 0x97, 0x01, 0xe0,
1630x65, 0x2e, 0x00, 0x41, 0x6c, 0x30, 0x01, 0x41, 0x66, 0x69, 1630x69, 0x73, 0x00, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65,
1640x6e, 0x64, 0x72, 0x03, 0x03, 0xb9, 0x02, 0x76, 0x70, 0x6f, 1640x2e, 0x00, 0x41, 0x6c, 0x30, 0x01, 0x41, 0x66, 0x69, 0x6e,
1650x73, 0x73, 0x69, 0x62, 0x6c, 0xa8, 0x00, 0x05, 0x88, 0x00, 1650x64, 0x72, 0x03, 0x03, 0xb9, 0x02, 0x76, 0x70, 0x6f, 0x73,
1660x00, 0xd2, 0x04, 0x30, 0x64, 0x64, 0x69, 0x14, 0x00, 0xf2, 1660x73, 0x69, 0x62, 0x6c, 0xa8, 0x00, 0x05, 0x88, 0x00, 0x00,
1670x01, 0x61, 0x6c, 0x00, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 1670xd2, 0x04, 0x30, 0x64, 0x64, 0x69, 0x14, 0x00, 0xf2, 0x01,
1680x6e, 0x67, 0x65, 0x00, 0x66, 0x6f, 0x72, 0x1c, 0x00, 0x10, 1680x61, 0x6c, 0x00, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e,
1690x76, 0x57, 0x08, 0x10, 0x64, 0x65, 0x04, 0x10, 0x79, 0x88, 1690x67, 0x65, 0x00, 0x66, 0x6f, 0x72, 0x1c, 0x00, 0x10, 0x76,
1700x03, 0x40, 0x54, 0x75, 0x72, 0x6e, 0x5a, 0x00, 0x05, 0x7a, 1700x57, 0x08, 0x10, 0x64, 0x65, 0x04, 0x10, 0x79, 0x88, 0x03,
1710x00, 0x03, 0x8c, 0x02, 0x05, 0x1b, 0x05, 0x50, 0x73, 0x70, 1710x40, 0x54, 0x75, 0x72, 0x6e, 0x5a, 0x00, 0x05, 0x7a, 0x00,
1720x65, 0x65, 0x64, 0xeb, 0x01, 0x03, 0x55, 0x07, 0xc0, 0x67, 1720x03, 0x8c, 0x02, 0x05, 0x1b, 0x05, 0x50, 0x73, 0x70, 0x65,
1730x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 1730x65, 0x64, 0xeb, 0x01, 0x03, 0x55, 0x07, 0xc0, 0x67, 0x65,
1740x00, 1740x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x00,
175}; 175};
176 176
177const unsigned short help_text_len = 2278; 177const unsigned short help_text_len = 2299;
178const unsigned short help_text_words = 400; 178const unsigned short help_text_words = 401;
179const char quick_help_text[] = "Tile the rectangle with a full set of dominoes."; 179const char quick_help_text[] = "Tile the rectangle with a full set of dominoes.";
diff --git a/apps/plugins/puzzles/help/fifteen.c b/apps/plugins/puzzles/help/fifteen.c
index 467118b7d5..7c0b4c8063 100644
--- a/apps/plugins/puzzles/help/fifteen.c
+++ b/apps/plugins/puzzles/help/fifteen.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,112 +6,150 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 83, TEXT_UNDERLINE }, 9 { 89, TEXT_UNDERLINE },
10 { 86, TEXT_CENTER | C_RED }, 10 { 92, TEXT_CENTER | C_RED },
11 { 153, TEXT_UNDERLINE }, 11 { 161, TEXT_UNDERLINE },
12 { 195, TEXT_CENTER | C_RED }, 12 { 203, TEXT_CENTER | C_RED },
13 { 211, TEXT_UNDERLINE }, 13 { 219, TEXT_UNDERLINE },
14 { 213, TEXT_UNDERLINE }, 14 { 221, TEXT_UNDERLINE },
15 { 239, TEXT_CENTER | C_RED },
16 { 343, TEXT_UNDERLINE },
15 LAST_STYLE_ITEM 17 LAST_STYLE_ITEM
16}; 18};
17 19
18/* orig 1245 comp 925 ratio 0.742972 level 5 saved 320 */ 20/* orig 1927 comp 1285 ratio 0.66684 level 10 saved 642 */
19const char help_text[] = { 21const char help_text[] = {
200xf1, 0x29, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 220xfd, 0x06, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
210x35, 0x3a, 0x20, 0x46, 0x69, 0x66, 0x74, 0x65, 0x65, 0x6e, 230x35, 0x3a, 0x20, 0x46, 0x69, 0x66, 0x74, 0x65, 0x65, 0x6e,
220x20, 0x00, 0x00, 0x00, 0x54, 0x68, 0x65, 0x00, 0x6f, 0x6c, 240x20, 0x00, 0x2d, 0x01, 0x00, 0xf1, 0x16, 0x00, 0x00, 0x00,
230x64, 0x00, 0x6f, 0x6e, 0x65, 0x73, 0x00, 0x61, 0x72, 0x65, 250x54, 0x68, 0x65, 0x00, 0x6f, 0x6c, 0x64, 0x00, 0x6f, 0x6e,
240x00, 0x74, 0x68, 0x65, 0x00, 0x62, 0x65, 0x73, 0x74, 0x3a, 260x65, 0x73, 0x00, 0x61, 0x72, 0x65, 0x00, 0x74, 0x68, 0x65,
250x00, 0x74, 0x68, 0x69, 0x73, 0x00, 0x69, 0x73, 0x12, 0x00, 270x00, 0x62, 0x65, 0x73, 0x74, 0x3a, 0x00, 0x74, 0x68, 0x69,
260x41, 0x67, 0x6f, 0x6f, 0x64, 0x28, 0x00, 0xf0, 0x23, 0x60, 280x73, 0x00, 0x69, 0x73, 0x12, 0x00, 0x41, 0x67, 0x6f, 0x6f,
270x31, 0x35, 0x2d, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x27, 290x64, 0x28, 0x00, 0xf1, 0x21, 0x60, 0x31, 0x35, 0x2d, 0x70,
280x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x73, 0x6c, 0x69, 0x64, 300x75, 0x7a, 0x7a, 0x6c, 0x65, 0x27, 0x00, 0x77, 0x69, 0x74,
290x69, 0x6e, 0x67, 0x00, 0x74, 0x69, 0x6c, 0x65, 0x73, 0x2e, 310x68, 0x00, 0x73, 0x6c, 0x69, 0x64, 0x69, 0x6e, 0x67, 0x00,
300x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 320x74, 0x69, 0x6c, 0x65, 0x73, 0x2c, 0x00, 0x77, 0x68, 0x69,
310x61, 0x00, 0x34, 0x78, 0x34, 0x00, 0x73, 0x71, 0x75, 0x55, 330x63, 0x68, 0x00, 0x64, 0x61, 0x74, 0x65, 0x73, 0x00, 0x66,
320x00, 0x83, 0x67, 0x72, 0x69, 0x64, 0x3b, 0x00, 0x31, 0x35, 340x72, 0x6f, 0x6d, 0x3e, 0x00, 0xf0, 0x0a, 0x31, 0x38, 0x37,
330x10, 0x00, 0xf2, 0x03, 0x73, 0x00, 0x63, 0x6f, 0x6e, 0x74, 350x30, 0x73, 0x2e, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61,
340x61, 0x69, 0x6e, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 360x76, 0x65, 0x00, 0x61, 0x00, 0x34, 0x78, 0x34, 0x00, 0x73,
350x65, 0x64, 0x3f, 0x00, 0x51, 0x2c, 0x00, 0x61, 0x6e, 0x64, 370x71, 0x75, 0x71, 0x00, 0x83, 0x67, 0x72, 0x69, 0x64, 0x3b,
360x70, 0x00, 0x30, 0x73, 0x69, 0x78, 0xa2, 0x00, 0x20, 0x74, 380x00, 0x31, 0x35, 0x10, 0x00, 0xf4, 0x03, 0x73, 0x00, 0x63,
370x68, 0x81, 0x00, 0x51, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5b, 390x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x00, 0x6e, 0x75, 0x6d,
380x00, 0x61, 0x72, 0x00, 0x6d, 0x6f, 0x76, 0x65, 0x95, 0x00, 400x62, 0x65, 0x72, 0x65, 0x64, 0x5b, 0x00, 0x31, 0x61, 0x6e,
390x70, 0x6f, 0x00, 0x63, 0x68, 0x6f, 0x6f, 0x73, 0x69, 0x00, 410x64, 0x4e, 0x00, 0x30, 0x73, 0x69, 0x78, 0xd1, 0x00, 0x20,
400x00, 0x3c, 0x00, 0x50, 0x00, 0x6e, 0x65, 0x78, 0x74, 0x16, 420x74, 0x68, 0x9d, 0x00, 0x51, 0x65, 0x6d, 0x70, 0x74, 0x79,
410x00, 0x00, 0x3e, 0x00, 0x01, 0x31, 0x00, 0x62, 0x00, 0x73, 430x5b, 0x00, 0x61, 0x72, 0x00, 0x6d, 0x6f, 0x76, 0x65, 0xb1,
420x70, 0x61, 0x63, 0x65, 0x53, 0x00, 0x00, 0xa5, 0x00, 0x73, 440x00, 0x70, 0x6f, 0x00, 0x63, 0x68, 0x6f, 0x6f, 0x73, 0x69,
430x65, 0x00, 0x69, 0x74, 0x00, 0x69, 0x6e, 0x23, 0x00, 0x01, 450x00, 0x00, 0x3c, 0x00, 0x50, 0x00, 0x6e, 0x65, 0x78, 0x74,
440x1d, 0x00, 0x11, 0x2e, 0xff, 0x00, 0x33, 0x61, 0x69, 0x6d, 460x16, 0x00, 0x00, 0x3e, 0x00, 0x01, 0x31, 0x00, 0x62, 0x00,
450x52, 0x00, 0x62, 0x65, 0x6e, 0x64, 0x00, 0x75, 0x70, 0xd8, 470x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x00, 0x00, 0xc1, 0x00,
460x00, 0x00, 0x25, 0x00, 0x01, 0x95, 0x00, 0x12, 0x00, 0xa7, 480x73, 0x65, 0x00, 0x69, 0x74, 0x00, 0x69, 0x6e, 0x23, 0x00,
470x00, 0xd6, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x00, 0x6f, 490x01, 0x1d, 0x00, 0x11, 0x2e, 0x1b, 0x01, 0x33, 0x61, 0x69,
480x72, 0x64, 0x65, 0x72, 0x2c, 0x23, 0x00, 0x01, 0x48, 0x00, 500x6d, 0x52, 0x00, 0x62, 0x65, 0x6e, 0x64, 0x00, 0x75, 0x70,
490x00, 0x23, 0x00, 0x01, 0x38, 0x01, 0xe0, 0x6f, 0x74, 0x74, 510xf4, 0x00, 0x00, 0x25, 0x00, 0x01, 0x95, 0x00, 0x12, 0x00,
500x6f, 0x6d, 0x00, 0x72, 0x69, 0x67, 0x68, 0x74, 0x00, 0x28, 520xa7, 0x00, 0xd6, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x00,
510x73, 0x6a, 0x00, 0x22, 0x61, 0x74, 0x4a, 0x00, 0xf5, 0x05, 530x6f, 0x72, 0x64, 0x65, 0x72, 0x2c, 0x23, 0x00, 0x01, 0x48,
520x6f, 0x70, 0x00, 0x72, 0x6f, 0x77, 0x00, 0x72, 0x65, 0x61, 540x00, 0x00, 0x23, 0x00, 0x01, 0x54, 0x01, 0xe0, 0x6f, 0x74,
530x64, 0x73, 0x00, 0x31, 0x2c, 0x32, 0x2c, 0x33, 0x2c, 0x34, 550x74, 0x6f, 0x6d, 0x00, 0x72, 0x69, 0x67, 0x68, 0x74, 0x00,
540xee, 0x00, 0x04, 0x38, 0x00, 0x06, 0x21, 0x00, 0x81, 0x33, 560x28, 0x73, 0x6a, 0x00, 0x22, 0x61, 0x74, 0x4a, 0x00, 0xf5,
550x2c, 0x31, 0x34, 0x2c, 0x31, 0x35, 0x2c, 0x5f, 0x00, 0x85, 570x05, 0x6f, 0x70, 0x00, 0x72, 0x6f, 0x77, 0x00, 0x72, 0x65,
560x29, 0x2e, 0x00, 0x00, 0x00, 0x35, 0x2e, 0x31, 0xb8, 0x01, 580x61, 0x64, 0x73, 0x00, 0x31, 0x2c, 0x32, 0x2c, 0x33, 0x2c,
570x00, 0x3e, 0x01, 0x42, 0x72, 0x6f, 0x6c, 0x73, 0xc1, 0x01, 590x34, 0xee, 0x00, 0x04, 0x38, 0x00, 0x06, 0x21, 0x00, 0x81,
580xf3, 0x00, 0x69, 0x73, 0x00, 0x67, 0x61, 0x6d, 0x65, 0x00, 600x33, 0x2c, 0x31, 0x34, 0x2c, 0x31, 0x35, 0x2c, 0x5f, 0x00,
590x63, 0x61, 0x6e, 0x00, 0x62, 0x65, 0x00, 0x1d, 0x00, 0x36, 610x85, 0x29, 0x2e, 0x00, 0x00, 0x00, 0x35, 0x2e, 0x31, 0xe7,
600x6c, 0x65, 0x64, 0xa6, 0x00, 0x81, 0x6d, 0x6f, 0x75, 0x73, 620x01, 0x00, 0x3e, 0x01, 0x51, 0x72, 0x6f, 0x6c, 0x73, 0x20,
610x65, 0x00, 0x6f, 0x72, 0x0d, 0x00, 0x80, 0x6b, 0x65, 0x79, 630xdd, 0x01, 0xf3, 0x00, 0x69, 0x73, 0x00, 0x67, 0x61, 0x6d,
620x62, 0x6f, 0x61, 0x72, 0x64, 0x56, 0x00, 0xcc, 0x41, 0x00, 640x65, 0x00, 0x63, 0x61, 0x6e, 0x00, 0x62, 0x65, 0x00, 0x1d,
630x6c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 650x00, 0x36, 0x6c, 0x65, 0x64, 0xa6, 0x00, 0x81, 0x6d, 0x6f,
640x2f, 0x00, 0x03, 0xd5, 0x00, 0x00, 0x96, 0x00, 0x94, 0x6f, 660x75, 0x73, 0x65, 0x00, 0x6f, 0x72, 0x0d, 0x00, 0x80, 0x6b,
650x72, 0x00, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0xb9, 0x01, 670x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x56, 0x00, 0xcc,
660x01, 0xf2, 0x01, 0x0a, 0x6a, 0x01, 0x52, 0x00, 0x77, 0x69, 680x41, 0x00, 0x6c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69,
670x6c, 0x6c, 0xa0, 0x01, 0x73, 0x61, 0x73, 0x00, 0x6d, 0x61, 690x63, 0x6b, 0x2f, 0x00, 0x03, 0xd5, 0x00, 0x00, 0x96, 0x00,
680x6e, 0x79, 0x40, 0x01, 0xc0, 0x61, 0x73, 0x00, 0x6e, 0x65, 700x94, 0x6f, 0x72, 0x00, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e,
690x63, 0x65, 0x73, 0x73, 0x61, 0x72, 0x79, 0x66, 0x01, 0x01, 710xb9, 0x01, 0x01, 0x0e, 0x02, 0x0a, 0x6a, 0x01, 0x52, 0x00,
700x23, 0x00, 0x06, 0x3c, 0x01, 0x27, 0x74, 0x6f, 0x74, 0x00, 720x77, 0x69, 0x6c, 0x6c, 0xa0, 0x01, 0x73, 0x61, 0x73, 0x00,
710x83, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2e, 0x9a, 730x6d, 0x61, 0x6e, 0x79, 0x40, 0x01, 0xc0, 0x61, 0x73, 0x00,
720x02, 0x20, 0x61, 0x72, 0x7e, 0x00, 0x48, 0x6b, 0x65, 0x79, 740x6e, 0x65, 0x63, 0x65, 0x73, 0x73, 0x61, 0x72, 0x79, 0x66,
730x73, 0x5e, 0x00, 0x02, 0xf1, 0x01, 0x75, 0x61, 0x64, 0x6a, 750x01, 0x01, 0x23, 0x00, 0x06, 0x3c, 0x01, 0x27, 0x74, 0x6f,
740x61, 0x63, 0x65, 0x6e, 0xf5, 0x01, 0x09, 0x8a, 0x01, 0xf4, 760x74, 0x00, 0x70, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72,
750x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 770x9b, 0x00, 0xb1, 0x42, 0x79, 0x00, 0x64, 0x65, 0x66, 0x61,
760x00, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 780x75, 0x6c, 0x74, 0x2c, 0x21, 0x00, 0x20, 0x61, 0x72, 0x8a,
770x00, 0x28, 0x6d, 0x6f, 0x76, 0xb8, 0x00, 0x09, 0x2d, 0x00, 790x00, 0x48, 0x6b, 0x65, 0x79, 0x73, 0x6a, 0x00, 0x02, 0xfd,
780x77, 0x6f, 0x70, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x36, 0x00, 800x01, 0x75, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x65, 0x6e, 0x01,
790x01, 0x72, 0x01, 0x50, 0x50, 0x72, 0x65, 0x73, 0x73, 0x31, 810x02, 0x09, 0x96, 0x01, 0xf4, 0x09, 0x64, 0x69, 0x72, 0x65,
800x00, 0x33, 0x60, 0x68, 0x27, 0x7f, 0x00, 0x20, 0x61, 0x6b, 820x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x69, 0x6e, 0x64, 0x69,
810x7f, 0x00, 0x60, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x53, 830x63, 0x61, 0x74, 0x65, 0x64, 0x00, 0x28, 0x6d, 0x6f, 0x76,
820x00, 0x00, 0x90, 0x00, 0x1a, 0x2e, 0x29, 0x00, 0xb3, 0x65, 840xc4, 0x00, 0x09, 0x2d, 0x00, 0x77, 0x6f, 0x70, 0x70, 0x6f,
830x6e, 0x6f, 0x75, 0x67, 0x68, 0x00, 0x74, 0x69, 0x6d, 0x65, 850x73, 0x69, 0x74, 0x36, 0x00, 0x01, 0x7e, 0x01, 0x50, 0x50,
840xb5, 0x00, 0x33, 0x73, 0x6f, 0x6c, 0xf1, 0x00, 0x00, 0xa7, 860x72, 0x65, 0x73, 0x73, 0x31, 0x00, 0x33, 0x60, 0x68, 0x27,
850x01, 0x50, 0x2c, 0x00, 0x62, 0x75, 0x74, 0x8b, 0x02, 0xe0, 870x7f, 0x00, 0x20, 0x61, 0x6b, 0x7f, 0x00, 0x60, 0x73, 0x75,
860x6d, 0x61, 0x79, 0x00, 0x73, 0x63, 0x72, 0x61, 0x6d, 0x62, 880x67, 0x67, 0x65, 0x73, 0x53, 0x00, 0x00, 0x90, 0x00, 0x1a,
870x6c, 0x65, 0x00, 0x79, 0xdc, 0x02, 0x40, 0x70, 0x72, 0x6f, 890x2e, 0x29, 0x00, 0xb3, 0x65, 0x6e, 0x6f, 0x75, 0x67, 0x68,
880x67, 0x4b, 0x00, 0x30, 0x00, 0x77, 0x68, 0xe1, 0x00, 0x20, 900x00, 0x74, 0x69, 0x6d, 0x65, 0xb5, 0x00, 0x33, 0x73, 0x6f,
890x64, 0x6f, 0x54, 0x00, 0x20, 0x73, 0x6f, 0x8c, 0x00, 0x41, 910x6c, 0xfd, 0x00, 0x00, 0xb3, 0x01, 0x50, 0x2c, 0x00, 0x62,
900x28, 0x41, 0x6c, 0x6c, 0x43, 0x00, 0x11, 0x61, 0xa0, 0x00, 920x75, 0x74, 0x97, 0x02, 0xe0, 0x6d, 0x61, 0x79, 0x00, 0x73,
910xb0, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 930x63, 0x72, 0x61, 0x6d, 0x62, 0x6c, 0x65, 0x00, 0x79, 0xe8,
920x65, 0x64, 0xc5, 0x00, 0x13, 0x73, 0xec, 0x00, 0x31, 0x32, 940x02, 0x40, 0x70, 0x72, 0x6f, 0x67, 0x4b, 0x00, 0x00, 0x6d,
930x2e, 0x31, 0xc4, 0x03, 0xf1, 0x01, 0x61, 0x6c, 0x73, 0x6f, 950x03, 0x50, 0x6c, 0x65, 0x00, 0x64, 0x6f, 0x54, 0x00, 0x20,
940x00, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 960x73, 0x6f, 0x8c, 0x00, 0x42, 0x28, 0x41, 0x6c, 0x6c, 0x12,
950x2e, 0x29, 0x3f, 0x02, 0x15, 0x32, 0x3f, 0x02, 0xa5, 0x70, 970x01, 0x01, 0xa0, 0x00, 0xb0, 0x73, 0x00, 0x64, 0x65, 0x73,
960x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x02, 980x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0xc5, 0x00, 0x13, 0x73,
970x04, 0x62, 0x6e, 0x6c, 0x79, 0x00, 0x6f, 0x70, 0x5b, 0x00, 990xec, 0x00, 0x31, 0x32, 0x2e, 0x31, 0xec, 0x03, 0xf1, 0x01,
980x05, 0x39, 0x00, 0x51, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x76, 1000x61, 0x6c, 0x73, 0x6f, 0x00, 0x61, 0x76, 0x61, 0x69, 0x6c,
990x00, 0xb3, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 1010x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0x4b, 0x02, 0x15, 0x32,
1000x2e, 0x2e, 0x27, 0x27, 0x00, 0x22, 0x00, 0x6f, 0x3c, 0x01, 1020x4b, 0x02, 0xb4, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74,
1010xb1, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 1030x65, 0x72, 0x73, 0x20, 0x2a, 0x04, 0x62, 0x6e, 0x6c, 0x79,
1040x00, 0x6f, 0x70, 0x5b, 0x00, 0x05, 0x39, 0x00, 0x06, 0xe9,
1050x03, 0xb3, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e,
1060x2e, 0x2e, 0x27, 0x27, 0x00, 0x32, 0x00, 0x6f, 0x6e, 0x1a,
1070x00, 0xa1, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65,
1020x6e, 0x75, 0x7b, 0x00, 0x51, 0x57, 0x69, 0x64, 0x74, 0x68, 1080x6e, 0x75, 0x7b, 0x00, 0x51, 0x57, 0x69, 0x64, 0x74, 0x68,
1030xd9, 0x02, 0x20, 0x48, 0x65, 0x07, 0x03, 0x10, 0x2c, 0xcd, 1090xe5, 0x02, 0x20, 0x48, 0x65, 0x13, 0x03, 0x04, 0x3a, 0x04,
1040x00, 0x21, 0x63, 0x68, 0x1c, 0x00, 0xf1, 0x07, 0x73, 0x65, 1100x00, 0x1c, 0x00, 0xf1, 0x07, 0x73, 0x65, 0x6c, 0x66, 0x2d,
1050x6c, 0x66, 0x2d, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x6e, 0x61, 1110x65, 0x78, 0x70, 0x6c, 0x61, 0x6e, 0x61, 0x74, 0x6f, 0x72,
1060x74, 0x6f, 0x72, 0x79, 0x2e, 0x00, 0x28, 0x4f, 0x6e, 0x63, 1120x79, 0x2e, 0x00, 0x28, 0x4f, 0x6e, 0x63, 0xfd, 0x00, 0xa1,
1070xfd, 0x00, 0xa1, 0x27, 0x76, 0x65, 0x00, 0x63, 0x68, 0x61, 1130x27, 0x76, 0x65, 0x00, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
1080x6e, 0x67, 0x65, 0x12, 0x03, 0xe9, 0x73, 0x65, 0x2c, 0x00, 1140x1e, 0x03, 0xe9, 0x73, 0x65, 0x2c, 0x00, 0x69, 0x74, 0x27,
1090x69, 0x74, 0x27, 0x73, 0x00, 0x6e, 0x6f, 0x74, 0x00, 0x61, 1150x73, 0x00, 0x6e, 0x6f, 0x74, 0x00, 0x61, 0x9d, 0x04, 0x00,
1100x75, 0x04, 0x00, 0x58, 0x02, 0xf0, 0x03, 0x6d, 0x6f, 0x72, 1160x64, 0x02, 0xf2, 0x01, 0x6d, 0x6f, 0x72, 0x65, 0x2c, 0x00,
1110x65, 0x2c, 0x00, 0x6f, 0x66, 0x00, 0x63, 0x6f, 0x75, 0x72, 1170x6f, 0x66, 0x00, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x21,
1120x73, 0x65, 0x21, 0x29, 0x00, 1180xe1, 0x00, 0x15, 0x33, 0xe1, 0x00, 0xf1, 0x00, 0x75, 0x73,
1190x65, 0x72, 0x20, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65,
1200x6e, 0x63, 0x65, 0xe7, 0x00, 0xc2, 0x4f, 0x6e, 0x00, 0x70,
1210x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0xa4, 0x03,
1220x80, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x00, 0x2e,
1230x00, 0x17, 0x00, 0x2e, 0x00, 0x12, 0x2c, 0xd9, 0x00, 0x16,
1240x50, 0x12, 0x00, 0x0d, 0xf5, 0x00, 0x34, 0x47, 0x61, 0x6d,
1250xf5, 0x00, 0x01, 0xe3, 0x01, 0x30, 0x6c, 0x65, 0x74, 0xc6,
1260x00, 0x00, 0x2a, 0x03, 0x53, 0x66, 0x69, 0x67, 0x75, 0x72,
1270xec, 0x02, 0x20, 0x65, 0x6e, 0x82, 0x03, 0x1b, 0x66, 0xcb,
1280x02, 0x34, 0x2e, 0x00, 0x57, 0x75, 0x03, 0x03, 0xed, 0x02,
1290xc4, 0x00, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x2c,
1300x00, 0x60, 0x4d, 0x29, 0x03, 0x00, 0xe4, 0x02, 0x1b, 0x27,
1310x06, 0x03, 0x01, 0x64, 0x00, 0x11, 0x70, 0x23, 0x02, 0x04,
1320xd7, 0x02, 0x1b, 0x73, 0xef, 0x02, 0x01, 0xda, 0x00, 0x00,
1330x27, 0x00, 0x44, 0x77, 0x61, 0x6e, 0x74, 0x2b, 0x03, 0x03,
1340x81, 0x03, 0x24, 0x2c, 0x00, 0x9f, 0x04, 0xf6, 0x01, 0x28,
1350x66, 0x6f, 0x72, 0x00, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c,
1360x65, 0x29, 0x00, 0x69, 0x66, 0x32, 0x00, 0x08, 0xac, 0x03,
1370x01, 0x3c, 0x00, 0x00, 0x2c, 0x04, 0x04, 0xc4, 0x00, 0x32,
1380x67, 0x61, 0x70, 0xe9, 0x04, 0x56, 0x77, 0x61, 0x72, 0x64,
1390x73, 0x59, 0x05, 0x41, 0x67, 0x61, 0x70, 0x2c, 0xc6, 0x01,
1400x13, 0x64, 0x9e, 0x00, 0x10, 0x52, 0x25, 0x00, 0x07, 0xe8,
1410x00, 0x05, 0x62, 0x03, 0x0e, 0xe9, 0x00, 0x00, 0x3d, 0x00,
1420x23, 0x27, 0x2c, 0x9f, 0x06, 0x40, 0x68, 0x61, 0x76, 0x69,
1430x0a, 0x03, 0x0d, 0x34, 0x01, 0x00, 0xad, 0x05, 0x82, 0x72,
1440x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x64, 0xdf, 0x05, 0x01,
1450xb2, 0x00, 0x34, 0x6f, 0x75, 0x6c, 0x73, 0x00, 0x3f, 0x4c,
1460x65, 0x66, 0xbe, 0x00, 0x10, 0x0a, 0xb3, 0x00, 0x08, 0xae,
1470x05, 0x00, 0x1e, 0x00, 0x40, 0x65, 0x6e, 0x64, 0x73, 0x0d,
1480x06, 0x34, 0x6f, 0x6e, 0x65, 0xc6, 0x06, 0x04, 0x41, 0x00,
1490xe0, 0x77, 0x68, 0x65, 0x72, 0x65, 0x00, 0x69, 0x74, 0x00,
1500x77, 0x61, 0x73, 0x2e, 0x00,
113}; 151};
114 152
115const unsigned short help_text_len = 1245; 153const unsigned short help_text_len = 1927;
116const unsigned short help_text_words = 229; 154const unsigned short help_text_words = 353;
117const char quick_help_text[] = "Slide the tiles around to arrange them into order."; 155const char quick_help_text[] = "Slide the tiles around to arrange them into order.";
diff --git a/apps/plugins/puzzles/help/filling.c b/apps/plugins/puzzles/help/filling.c
index 19ffb97dee..a5ccd6d1fb 100644
--- a/apps/plugins/puzzles/help/filling.c
+++ b/apps/plugins/puzzles/help/filling.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,140 +6,140 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 141, TEXT_CENTER | C_RED }, 9 { 142, TEXT_CENTER | C_RED },
10 { 306, TEXT_CENTER | C_RED }, 10 { 307, TEXT_CENTER | C_RED },
11 LAST_STYLE_ITEM 11 LAST_STYLE_ITEM
12}; 12};
13 13
14/* orig 1804 comp 1242 ratio 0.68847 level 10 saved 562 */ 14/* orig 1821 comp 1245 ratio 0.68369 level 10 saved 576 */
15const char help_text[] = { 15const char help_text[] = {
160xf0, 0x28, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 160xfe, 0x07, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
170x32, 0x39, 0x3a, 0x20, 0x46, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 170x32, 0x39, 0x3a, 0x20, 0x46, 0x69, 0x6c, 0x6c, 0x69, 0x6e,
180x67, 0x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 180x67, 0x20, 0x00, 0x2d, 0x01, 0x00, 0xf0, 0x14, 0x00, 0x00,
190x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 190x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00,
200x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 200x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00,
210x73, 0x2c, 0x00, 0x73, 0x6f, 0x6d, 0x65, 0x11, 0x00, 0xf6, 210x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x73,
220x13, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x63, 0x6f, 0x6e, 220x6f, 0x6d, 0x65, 0x11, 0x00, 0xf6, 0x13, 0x77, 0x68, 0x69,
230x74, 0x61, 0x69, 0x6e, 0x00, 0x64, 0x69, 0x67, 0x69, 0x74, 230x63, 0x68, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
240x73, 0x2c, 0x00, 0x61, 0x6e, 0x64, 0x00, 0x74, 0x68, 0x65, 240x00, 0x64, 0x69, 0x67, 0x69, 0x74, 0x73, 0x2c, 0x00, 0x61,
250x00, 0x72, 0x65, 0x73, 0x74, 0x26, 0x00, 0xa0, 0x61, 0x72, 250x6e, 0x64, 0x00, 0x74, 0x68, 0x65, 0x00, 0x72, 0x65, 0x73,
260x65, 0x00, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x5b, 0x00, 260x74, 0x26, 0x00, 0xa0, 0x61, 0x72, 0x65, 0x00, 0x65, 0x6d,
270xf5, 0x02, 0x72, 0x00, 0x6a, 0x6f, 0x62, 0x00, 0x69, 0x73, 270x70, 0x74, 0x79, 0x2e, 0x5b, 0x00, 0xf5, 0x02, 0x72, 0x00,
280x00, 0x74, 0x6f, 0x00, 0x66, 0x69, 0x6c, 0x6c, 0x00, 0x40, 280x6a, 0x6f, 0x62, 0x00, 0x69, 0x73, 0x00, 0x74, 0x6f, 0x00,
290x00, 0x00, 0x0a, 0x00, 0x23, 0x74, 0x68, 0x2c, 0x00, 0x06, 290x66, 0x69, 0x6c, 0x6c, 0x00, 0x40, 0x00, 0x00, 0x0a, 0x00,
300x73, 0x00, 0x50, 0x69, 0x6e, 0x00, 0x73, 0x75, 0x47, 0x00, 300x23, 0x74, 0x68, 0x2c, 0x00, 0x06, 0x73, 0x00, 0x50, 0x69,
310xc2, 0x00, 0x77, 0x61, 0x79, 0x00, 0x74, 0x68, 0x61, 0x74, 310x6e, 0x00, 0x73, 0x75, 0x47, 0x00, 0xc2, 0x00, 0x77, 0x61,
320x00, 0x65, 0x61, 0x7d, 0x00, 0xd7, 0x6e, 0x65, 0x63, 0x74, 320x79, 0x00, 0x74, 0x68, 0x61, 0x74, 0x00, 0x65, 0x61, 0x7d,
330x65, 0x64, 0x00, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0xa8, 330x00, 0xd7, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x00, 0x72,
340x00, 0x44, 0x00, 0x61, 0x6c, 0x6c, 0x9d, 0x00, 0x31, 0x69, 340x65, 0x67, 0x69, 0x6f, 0x6e, 0xa8, 0x00, 0x44, 0x00, 0x61,
350x6e, 0x67, 0x56, 0x00, 0x42, 0x73, 0x61, 0x6d, 0x65, 0x69, 350x6c, 0x6c, 0x9d, 0x00, 0x31, 0x69, 0x6e, 0x67, 0x56, 0x00,
360x00, 0x70, 0x00, 0x68, 0x61, 0x73, 0x00, 0x61, 0x6e, 0x98, 360x42, 0x73, 0x61, 0x6d, 0x65, 0x69, 0x00, 0x70, 0x00, 0x68,
370x00, 0x70, 0x61, 0x00, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x8c, 370x61, 0x73, 0x00, 0x61, 0x6e, 0x98, 0x00, 0x70, 0x61, 0x00,
380x00, 0x01, 0x59, 0x00, 0x01, 0x20, 0x00, 0x7b, 0x2e, 0x00, 380x65, 0x71, 0x75, 0x61, 0x6c, 0x8c, 0x00, 0x01, 0x59, 0x00,
390x00, 0x00, 0x28, 0x60, 0x43, 0x5f, 0x00, 0x61, 0x27, 0x2c, 390x01, 0x20, 0x00, 0x7b, 0x2e, 0x00, 0x00, 0x00, 0x28, 0x60,
400x00, 0x66, 0x6f, 0x72, 0x4b, 0x00, 0x80, 0x70, 0x75, 0x72, 400x43, 0x5f, 0x00, 0x61, 0x27, 0x2c, 0x00, 0x66, 0x6f, 0x72,
410x70, 0x6f, 0x73, 0x65, 0x73, 0x72, 0x00, 0xf0, 0x09, 0x74, 410x4b, 0x00, 0x80, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65,
420x68, 0x69, 0x73, 0x00, 0x67, 0x61, 0x6d, 0x65, 0x2c, 0x00, 420x73, 0x72, 0x00, 0xf0, 0x09, 0x74, 0x68, 0x69, 0x73, 0x00,
430x64, 0x6f, 0x65, 0x73, 0x00, 0x6e, 0x6f, 0x74, 0x00, 0x63, 430x67, 0x61, 0x6d, 0x65, 0x2c, 0x00, 0x64, 0x6f, 0x65, 0x73,
440x6f, 0x75, 0x6e, 0x4c, 0x00, 0xf0, 0x00, 0x61, 0x67, 0x6f, 440x00, 0x6e, 0x6f, 0x74, 0x00, 0x63, 0x6f, 0x75, 0x6e, 0x4c,
450x6e, 0x61, 0x6c, 0x6c, 0x79, 0x00, 0x73, 0x65, 0x70, 0x61, 450x00, 0xf0, 0x00, 0x61, 0x67, 0x6f, 0x6e, 0x61, 0x6c, 0x6c,
460x72, 0x61, 0x4c, 0x00, 0x05, 0xa1, 0x00, 0xf2, 0x17, 0x73, 460x79, 0x00, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x4c, 0x00,
470x00, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x2e, 470x05, 0xa1, 0x00, 0xf2, 0x17, 0x73, 0x00, 0x61, 0x64, 0x6a,
480x29, 0x00, 0x00, 0x00, 0x46, 0x6f, 0x72, 0x00, 0x65, 0x78, 480x61, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x29, 0x00, 0x00, 0x00,
490x61, 0x6d, 0x70, 0x6c, 0x65, 0x2c, 0x00, 0x69, 0x74, 0x00, 490x46, 0x6f, 0x72, 0x00, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c,
500x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x96, 0x00, 0x23, 500x65, 0x2c, 0x00, 0x69, 0x74, 0x00, 0x66, 0x6f, 0x6c, 0x6c,
510x6e, 0x6f, 0x38, 0x00, 0x45, 0x00, 0x63, 0x61, 0x6e, 0x75, 510x6f, 0x77, 0x73, 0x96, 0x00, 0x23, 0x6e, 0x6f, 0x38, 0x00,
520x01, 0x64, 0x61, 0x00, 0x7a, 0x65, 0x72, 0x6f, 0x75, 0x01, 520x45, 0x00, 0x63, 0x61, 0x6e, 0x75, 0x01, 0x64, 0x61, 0x00,
530x65, 0x61, 0x74, 0x00, 0x74, 0x77, 0x6f, 0x55, 0x00, 0x05, 530x7a, 0x65, 0x72, 0x6f, 0x75, 0x01, 0x65, 0x61, 0x74, 0x00,
540x69, 0x00, 0x00, 0x32, 0x00, 0x00, 0x94, 0x00, 0x47, 0x62, 540x74, 0x77, 0x6f, 0x55, 0x00, 0x05, 0x69, 0x00, 0x00, 0x32,
550x6f, 0x74, 0x68, 0x3b, 0x00, 0x74, 0x6f, 0x6e, 0x65, 0x2e, 550x00, 0x00, 0x94, 0x00, 0x47, 0x62, 0x6f, 0x74, 0x68, 0x3b,
560x00, 0x4e, 0x6f, 0x3b, 0x01, 0x08, 0x12, 0x01, 0x70, 0x67, 560x00, 0x74, 0x6f, 0x6e, 0x65, 0x2e, 0x00, 0x4e, 0x6f, 0x3b,
570x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x54, 0x00, 0xc0, 0x6e, 570x01, 0x08, 0x12, 0x01, 0x70, 0x67, 0x72, 0x65, 0x61, 0x74,
580x00, 0x39, 0x00, 0x28, 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 580x65, 0x72, 0x54, 0x00, 0xc0, 0x6e, 0x00, 0x39, 0x00, 0x28,
590x65, 0xfa, 0x00, 0x20, 0x6e, 0x00, 0xa7, 0x01, 0x01, 0x26, 590x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0xfa, 0x00, 0x20,
600x00, 0x52, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x5a, 0x00, 0x00, 600x6e, 0x00, 0xa7, 0x01, 0x01, 0x26, 0x00, 0x52, 0x77, 0x6f,
610x29, 0x02, 0x53, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x60, 0x01, 610x75, 0x6c, 0x64, 0x5a, 0x00, 0x00, 0x29, 0x02, 0x53, 0x73,
620x10, 0x29, 0x41, 0x01, 0x41, 0x43, 0x72, 0x65, 0x64, 0xc8, 620x69, 0x6e, 0x67, 0x6c, 0x60, 0x01, 0x10, 0x29, 0x41, 0x01,
630x00, 0x12, 0x72, 0x23, 0x01, 0xa1, 0x70, 0x75, 0x7a, 0x7a, 630x41, 0x43, 0x72, 0x65, 0x64, 0xc8, 0x00, 0x12, 0x72, 0x23,
640x6c, 0x65, 0x00, 0x67, 0x6f, 0x65, 0xfa, 0x01, 0xb0, 0x4e, 640x01, 0xa1, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x67,
650x69, 0x6b, 0x6f, 0x6c, 0x69, 0x00, 0x5b, 0x31, 0x34, 0x5d, 650x6f, 0x65, 0xfa, 0x01, 0xb0, 0x4e, 0x69, 0x6b, 0x6f, 0x6c,
660x2e, 0x00, 0x03, 0x7e, 0x02, 0x41, 0x00, 0x77, 0x61, 0x73, 660x69, 0x00, 0x5b, 0x31, 0x34, 0x5d, 0x2e, 0x00, 0x03, 0x92,
670xa5, 0x00, 0x40, 0x72, 0x69, 0x62, 0x75, 0x2f, 0x01, 0x01, 670x02, 0x41, 0x00, 0x77, 0x61, 0x73, 0xa5, 0x00, 0x40, 0x72,
680x98, 0x01, 0x10, 0x69, 0x14, 0x00, 0x50, 0x6c, 0x6c, 0x65, 680x69, 0x62, 0x75, 0x2f, 0x01, 0x01, 0x98, 0x01, 0x10, 0x69,
690x63, 0x74, 0xab, 0x00, 0xf0, 0x01, 0x62, 0x79, 0x00, 0x4a, 690x14, 0x00, 0x50, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0xab, 0x00,
700x6f, 0x6e, 0x61, 0x73, 0x00, 0x4b, 0x6f, 0x65, 0x6c, 0x6b, 700xf0, 0x01, 0x62, 0x79, 0x00, 0x4a, 0x6f, 0x6e, 0x61, 0x73,
710x65, 0x72, 0x3f, 0x00, 0x00, 0x47, 0x00, 0xd1, 0x00, 0x68, 710x00, 0x4b, 0x6f, 0x65, 0x6c, 0x6b, 0x65, 0x72, 0x3f, 0x00,
720x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 720x00, 0x47, 0x00, 0xe1, 0x00, 0x68, 0x74, 0x74, 0x70, 0x73,
730x6e, 0x5e, 0x00, 0xa2, 0x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70, 730x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 0x5f, 0x00,
740x2f, 0x65, 0x6e, 0x2f, 0x7d, 0x00, 0x20, 0x73, 0x2f, 0x70, 740xa2, 0x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f, 0x65, 0x6e,
750x02, 0xf5, 0x02, 0x6f, 0x6d, 0x69, 0x6e, 0x6f, 0x2e, 0x68, 750x2f, 0x7e, 0x00, 0x20, 0x73, 0x2f, 0x71, 0x02, 0xd5, 0x6f,
760x74, 0x6d, 0x6c, 0x00, 0x00, 0x00, 0x32, 0x39, 0x2e, 0x31, 760x6d, 0x69, 0x6e, 0x6f, 0x2f, 0x00, 0x00, 0x00, 0x32, 0x39,
770xfb, 0x02, 0x01, 0x79, 0x00, 0x30, 0x6f, 0x6c, 0x73, 0x04, 770x2e, 0x31, 0x0c, 0x03, 0x01, 0x76, 0x00, 0xe4, 0x6f, 0x6c,
780x03, 0x74, 0x54, 0x6f, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x99, 780x73, 0x20, 0x00, 0x00, 0x00, 0x54, 0x6f, 0x00, 0x70, 0x6c,
790x00, 0xe1, 0x2c, 0x00, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x79, 790x61, 0x79, 0x96, 0x00, 0xe1, 0x2c, 0x00, 0x73, 0x69, 0x6d,
800x00, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x05, 0x02, 0x20, 0x6d, 800x70, 0x6c, 0x79, 0x00, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x02,
810x6f, 0x15, 0x01, 0x00, 0x4d, 0x01, 0x29, 0x6e, 0x79, 0xb3, 810x02, 0x20, 0x6d, 0x6f, 0x12, 0x01, 0x00, 0x4a, 0x01, 0x29,
820x02, 0x04, 0x06, 0x03, 0x50, 0x6e, 0x00, 0x74, 0x79, 0x70, 820x6e, 0x79, 0xb0, 0x02, 0x04, 0x03, 0x03, 0x50, 0x6e, 0x00,
830x1c, 0x01, 0x02, 0x75, 0x02, 0x12, 0x6f, 0xdd, 0x02, 0x85, 830x74, 0x79, 0x70, 0x19, 0x01, 0x02, 0x72, 0x02, 0x12, 0x6f,
840x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0xff, 0x02, 840xda, 0x02, 0x85, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72,
850x01, 0xbb, 0x01, 0x02, 0x3a, 0x00, 0xa4, 0x2e, 0x00, 0x42, 850x64, 0xfc, 0x02, 0x01, 0xb8, 0x01, 0x02, 0x3a, 0x00, 0xa4,
860x79, 0x00, 0x64, 0x72, 0x61, 0x67, 0x67, 0xb5, 0x02, 0x01, 860x2e, 0x00, 0x42, 0x79, 0x00, 0x64, 0x72, 0x61, 0x67, 0x67,
870x65, 0x00, 0x51, 0x2c, 0x00, 0x79, 0x6f, 0x75, 0xc9, 0x01, 870xb2, 0x02, 0x01, 0x65, 0x00, 0x51, 0x2c, 0x00, 0x79, 0x6f,
880x20, 0x73, 0x65, 0x06, 0x01, 0x95, 0x00, 0x6d, 0x75, 0x6c, 880x75, 0xc6, 0x01, 0x20, 0x73, 0x65, 0x03, 0x01, 0x95, 0x00,
890x74, 0x69, 0x70, 0x6c, 0x65, 0xe5, 0x01, 0x04, 0x4c, 0x00, 890x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0xe2, 0x01,
900x46, 0x77, 0x69, 0x74, 0x68, 0x8d, 0x01, 0xc1, 0x6b, 0x65, 900x04, 0x4c, 0x00, 0x46, 0x77, 0x69, 0x74, 0x68, 0x8a, 0x01,
910x79, 0x70, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x00, 0x49, 0x66, 910xc1, 0x6b, 0x65, 0x79, 0x70, 0x72, 0x65, 0x73, 0x73, 0x2e,
920x43, 0x00, 0x30, 0x6d, 0x61, 0x6b, 0x90, 0x00, 0x8e, 0x6d, 920x00, 0x49, 0x66, 0x43, 0x00, 0x30, 0x6d, 0x61, 0x6b, 0x90,
930x69, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x2c, 0xcd, 0x00, 0x02, 930x00, 0x8e, 0x6d, 0x69, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x2c,
940xa3, 0x00, 0x60, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x72, 0x69, 940xcd, 0x00, 0x02, 0xa3, 0x00, 0x60, 0x69, 0x6e, 0x63, 0x6f,
950x00, 0x07, 0xd1, 0x00, 0x01, 0x4a, 0x00, 0xf0, 0x01, 0x00, 950x72, 0x72, 0x69, 0x00, 0x07, 0xd1, 0x00, 0x01, 0x4a, 0x00,
960x30, 0x2c, 0x00, 0x53, 0x70, 0x61, 0x63, 0x65, 0x2c, 0x00, 960xf0, 0x01, 0x00, 0x30, 0x2c, 0x00, 0x53, 0x70, 0x61, 0x63,
970x42, 0x61, 0x63, 0x6b, 0x73, 0x0b, 0x00, 0x61, 0x00, 0x6f, 970x65, 0x2c, 0x00, 0x42, 0x61, 0x63, 0x6b, 0x73, 0x0b, 0x00,
980x72, 0x00, 0x45, 0x6e, 0x31, 0x02, 0x70, 0x6f, 0x00, 0x63, 980x61, 0x00, 0x6f, 0x72, 0x00, 0x45, 0x6e, 0x2e, 0x02, 0x70,
990x6c, 0x65, 0x61, 0x72, 0xc0, 0x02, 0x20, 0x61, 0x67, 0x68, 990x6f, 0x00, 0x63, 0x6c, 0x65, 0x61, 0x72, 0xbd, 0x02, 0x20,
1000x02, 0x43, 0x28, 0x6f, 0x72, 0x00, 0x3b, 0x02, 0xd1, 0x00, 1000x61, 0x67, 0x65, 0x02, 0x43, 0x28, 0x6f, 0x72, 0x00, 0x38,
1010x55, 0x6e, 0x64, 0x6f, 0x00, 0x66, 0x65, 0x61, 0x74, 0x75, 1010x02, 0xd1, 0x00, 0x55, 0x6e, 0x64, 0x6f, 0x00, 0x66, 0x65,
1020x72, 0x65, 0x22, 0x02, 0x13, 0x59, 0xd5, 0x00, 0x70, 0x61, 1020x61, 0x74, 0x75, 0x72, 0x65, 0x1f, 0x02, 0x13, 0x59, 0xd5,
1030x6c, 0x73, 0x6f, 0x00, 0x6d, 0x6f, 0x70, 0x04, 0x33, 0x72, 1030x00, 0x70, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0x6d, 0x6f, 0x6d,
1040x6f, 0x75, 0x42, 0x04, 0x01, 0x79, 0x04, 0x01, 0xcf, 0x00, 1040x04, 0x33, 0x72, 0x6f, 0x75, 0x3f, 0x04, 0x01, 0x76, 0x04,
1050x00, 0x0e, 0x00, 0x60, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 1050x01, 0xcf, 0x00, 0x00, 0x0e, 0x00, 0x60, 0x63, 0x75, 0x72,
1060xd1, 0x00, 0x20, 0x73, 0x3b, 0x56, 0x01, 0x00, 0x1f, 0x01, 1060x73, 0x6f, 0x72, 0xd1, 0x00, 0x20, 0x73, 0x3b, 0x56, 0x01,
1070x04, 0x58, 0x01, 0x10, 0x77, 0xf9, 0x00, 0x03, 0x4a, 0x01, 1070x00, 0x1f, 0x01, 0x04, 0x58, 0x01, 0x10, 0x77, 0xf9, 0x00,
1080x04, 0x12, 0x01, 0x0c, 0xfc, 0x03, 0x03, 0x40, 0x00, 0x03, 1080x03, 0x4a, 0x01, 0x04, 0x12, 0x01, 0x0c, 0xf9, 0x03, 0x03,
1090x50, 0x00, 0x00, 0x52, 0x03, 0x55, 0x75, 0x6d, 0x62, 0x65, 1090x40, 0x00, 0x03, 0x50, 0x00, 0x00, 0x4f, 0x03, 0x55, 0x75,
1100x72, 0x4c, 0x00, 0x12, 0x30, 0x46, 0x00, 0x04, 0xbe, 0x00, 1100x6d, 0x62, 0x65, 0x72, 0x4c, 0x00, 0x12, 0x30, 0x46, 0x00,
1110x1a, 0x2e, 0x9c, 0x00, 0x0f, 0x76, 0x01, 0x05, 0x00, 0xdc, 1110x04, 0xbe, 0x00, 0x1a, 0x2e, 0x9c, 0x00, 0x0f, 0x76, 0x01,
1120x02, 0x02, 0x49, 0x00, 0x00, 0x44, 0x00, 0x22, 0x6f, 0x72, 1120x05, 0x00, 0xd9, 0x02, 0x02, 0x49, 0x00, 0x00, 0x44, 0x00,
1130x40, 0x00, 0x01, 0xc7, 0x02, 0x04, 0xb9, 0x00, 0x61, 0x72, 1130x22, 0x6f, 0x72, 0x40, 0x00, 0x01, 0xc4, 0x02, 0x04, 0xb9,
1140x65, 0x74, 0x75, 0x72, 0x6e, 0x41, 0x01, 0x51, 0x61, 0x72, 1140x00, 0x61, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x41, 0x01,
1150x72, 0x6f, 0x77, 0xc3, 0x00, 0x8c, 0x2c, 0x00, 0x62, 0x65, 1150x51, 0x61, 0x72, 0x72, 0x6f, 0x77, 0xc3, 0x00, 0x8c, 0x2c,
1160x66, 0x6f, 0x72, 0x65, 0xca, 0x00, 0x04, 0xc6, 0x01, 0x04, 1160x00, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0xca, 0x00, 0x04,
1170x4a, 0x00, 0x01, 0x42, 0x00, 0x88, 0x68, 0x69, 0x67, 0x68, 1170xc6, 0x01, 0x04, 0x4a, 0x00, 0x01, 0x42, 0x00, 0x88, 0x68,
1180x6c, 0x69, 0x67, 0x68, 0x3d, 0x04, 0x10, 0x28, 0xae, 0x03, 1180x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x3a, 0x04, 0x10,
1190x30, 0x62, 0x6f, 0x76, 0x48, 0x01, 0x10, 0x54, 0xf5, 0x00, 1190x28, 0xab, 0x03, 0x30, 0x62, 0x6f, 0x76, 0x48, 0x01, 0x10,
1200x01, 0x88, 0x01, 0x70, 0x62, 0x61, 0x72, 0x00, 0x61, 0x64, 1200x54, 0xf5, 0x00, 0x01, 0x88, 0x01, 0x70, 0x62, 0x61, 0x72,
1210x64, 0xc9, 0x03, 0x00, 0xb4, 0x04, 0x00, 0x52, 0x01, 0x14, 1210x00, 0x61, 0x64, 0x64, 0xc6, 0x03, 0x00, 0xb1, 0x04, 0x00,
1220x73, 0x0b, 0x02, 0x07, 0x29, 0x02, 0x00, 0x1e, 0x00, 0x42, 1220x52, 0x01, 0x14, 0x73, 0x0b, 0x02, 0x07, 0x29, 0x02, 0x00,
1230x66, 0x72, 0x6f, 0x6d, 0x2f, 0x01, 0x13, 0x65, 0x57, 0x03, 1230x1e, 0x00, 0x42, 0x66, 0x72, 0x6f, 0x6d, 0x2f, 0x01, 0x13,
1240x17, 0x2e, 0xd1, 0x01, 0x00, 0x22, 0x00, 0x63, 0x65, 0x73, 1240x65, 0x54, 0x03, 0x17, 0x2e, 0xd1, 0x01, 0x00, 0x22, 0x00,
1250x63, 0x61, 0x70, 0x65, 0x47, 0x00, 0x01, 0x4f, 0x05, 0x05, 1250x63, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x47, 0x00, 0x01,
1260xf6, 0x00, 0x0e, 0x3c, 0x00, 0x00, 0x30, 0x05, 0x13, 0x41, 1260x4c, 0x05, 0x05, 0xf6, 0x00, 0x0e, 0x3c, 0x00, 0x00, 0x2d,
1270x81, 0x01, 0x11, 0x61, 0x13, 0x00, 0xb1, 0x73, 0x00, 0x64, 1270x05, 0x13, 0x41, 0x81, 0x01, 0x11, 0x61, 0x13, 0x00, 0xb1,
1280x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0xc0, 0x05, 1280x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
1290x03, 0xbc, 0x03, 0x31, 0x32, 0x2e, 0x31, 0x0e, 0x06, 0x01, 1290x64, 0xbd, 0x05, 0x03, 0xb9, 0x03, 0x31, 0x32, 0x2e, 0x31,
1300x57, 0x01, 0xb2, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 1300x0b, 0x06, 0x01, 0x57, 0x01, 0xb2, 0x61, 0x76, 0x61, 0x69,
1310x6c, 0x65, 0x2e, 0x29, 0x8a, 0x03, 0x15, 0x32, 0x8a, 0x03, 1310x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0x8a, 0x03, 0x15,
1320x00, 0x2e, 0x05, 0x77, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 1320x32, 0x8a, 0x03, 0x00, 0x2b, 0x05, 0x77, 0x6d, 0x65, 0x74,
1330x20, 0x1d, 0x04, 0x12, 0x61, 0x13, 0x05, 0x00, 0xca, 0x02, 1330x65, 0x72, 0x73, 0x20, 0x1a, 0x04, 0x12, 0x61, 0x10, 0x05,
1340x20, 0x74, 0x6f, 0xe3, 0x01, 0x52, 0x66, 0x69, 0x67, 0x75, 1340x00, 0xca, 0x02, 0x20, 0x74, 0x6f, 0xe3, 0x01, 0x52, 0x66,
1350x72, 0x5e, 0x02, 0x02, 0x88, 0x01, 0x00, 0x91, 0x05, 0x32, 1350x69, 0x67, 0x75, 0x72, 0x5e, 0x02, 0x02, 0x88, 0x01, 0x00,
1360x72, 0x6f, 0x77, 0x03, 0x01, 0x63, 0x63, 0x6f, 0x6c, 0x75, 1360x8e, 0x05, 0x32, 0x72, 0x6f, 0x77, 0x03, 0x01, 0x63, 0x63,
1370x6d, 0x6e, 0xa5, 0x05, 0x02, 0x52, 0x02, 0x82, 0x2c, 0x00, 1370x6f, 0x6c, 0x75, 0x6d, 0x6e, 0xa2, 0x05, 0x02, 0x52, 0x02,
1380x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x9d, 0x01, 0xd0, 0x60, 1380x82, 0x2c, 0x00, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x9d,
1390x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 1390x01, 0xd0, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d,
1400x2e, 0x00, 1400x65, 0x6e, 0x75, 0x2e, 0x00,
141}; 141};
142 142
143const unsigned short help_text_len = 1804; 143const unsigned short help_text_len = 1821;
144const unsigned short help_text_words = 327; 144const unsigned short help_text_words = 328;
145const char quick_help_text[] = "Mark every square with the area of its containing region."; 145const char quick_help_text[] = "Mark every square with the area of its containing region.";
diff --git a/apps/plugins/puzzles/help/flip.c b/apps/plugins/puzzles/help/flip.c
index e5ec994fdb..91a0886b66 100644
--- a/apps/plugins/puzzles/help/flip.c
+++ b/apps/plugins/puzzles/help/flip.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,129 +6,129 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 76, TEXT_CENTER | C_RED }, 9 { 77, TEXT_CENTER | C_RED },
10 { 164, TEXT_UNDERLINE }, 10 { 165, TEXT_UNDERLINE },
11 { 203, TEXT_CENTER | C_RED }, 11 { 204, TEXT_CENTER | C_RED },
12 { 220, TEXT_UNDERLINE },
13 { 221, TEXT_UNDERLINE }, 12 { 221, TEXT_UNDERLINE },
14 { 231, TEXT_UNDERLINE }, 13 { 222, TEXT_UNDERLINE },
14 { 232, TEXT_UNDERLINE },
15 LAST_STYLE_ITEM 15 LAST_STYLE_ITEM
16}; 16};
17 17
18/* orig 1522 comp 1092 ratio 0.717477 level 10 saved 430 */ 18/* orig 1539 comp 1099 ratio 0.7141 level 10 saved 440 */
19const char help_text[] = { 19const char help_text[] = {
200xf2, 0x2f, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 200xfb, 0x04, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
210x31, 0x34, 0x3a, 0x20, 0x46, 0x6c, 0x69, 0x70, 0x20, 0x00, 210x31, 0x34, 0x3a, 0x20, 0x46, 0x6c, 0x69, 0x70, 0x20, 0x00,
220x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 220x2d, 0x01, 0x00, 0xf2, 0x1e, 0x00, 0x00, 0x00, 0x59, 0x6f,
230x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 230x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x67,
240x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 240x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75,
250x73, 0x6f, 0x6d, 0x65, 0x00, 0x6c, 0x69, 0x67, 0x68, 0x74, 250x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x73, 0x6f, 0x6d, 0x65,
260x00, 0x61, 0x6e, 0x64, 0x0f, 0x00, 0x50, 0x64, 0x61, 0x72, 260x00, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x00, 0x61, 0x6e, 0x64,
270x6b, 0x2e, 0x36, 0x00, 0xb4, 0x72, 0x00, 0x61, 0x69, 0x6d, 270x0f, 0x00, 0x50, 0x64, 0x61, 0x72, 0x6b, 0x2e, 0x36, 0x00,
280x00, 0x69, 0x73, 0x00, 0x74, 0x6f, 0x24, 0x00, 0x64, 0x6c, 280xb4, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 0x69, 0x73, 0x00,
290x6c, 0x00, 0x74, 0x68, 0x65, 0x40, 0x00, 0x62, 0x00, 0x75, 290x74, 0x6f, 0x24, 0x00, 0x64, 0x6c, 0x6c, 0x00, 0x74, 0x68,
300x70, 0x00, 0x61, 0x74, 0x12, 0x00, 0x91, 0x61, 0x6d, 0x65, 300x65, 0x40, 0x00, 0x62, 0x00, 0x75, 0x70, 0x00, 0x61, 0x74,
310x00, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x70, 0x00, 0xe3, 0x63, 310x12, 0x00, 0x91, 0x61, 0x6d, 0x65, 0x00, 0x74, 0x69, 0x6d,
320x61, 0x6e, 0x00, 0x63, 0x68, 0x6f, 0x6f, 0x73, 0x65, 0x00, 320x65, 0x2e, 0x70, 0x00, 0xe3, 0x63, 0x61, 0x6e, 0x00, 0x63,
330x61, 0x6e, 0x79, 0x30, 0x00, 0x01, 0x63, 0x00, 0xf3, 0x04, 330x68, 0x6f, 0x6f, 0x73, 0x65, 0x00, 0x61, 0x6e, 0x79, 0x30,
340x66, 0x6c, 0x69, 0x70, 0x00, 0x69, 0x74, 0x73, 0x00, 0x73, 340x00, 0x01, 0x63, 0x00, 0xf3, 0x04, 0x66, 0x6c, 0x69, 0x70,
350x74, 0x61, 0x74, 0x65, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x5d, 350x00, 0x69, 0x74, 0x73, 0x00, 0x73, 0x74, 0x61, 0x74, 0x65,
360x00, 0x21, 0x74, 0x6f, 0x7b, 0x00, 0x32, 0x00, 0x6f, 0x72, 360x00, 0x66, 0x72, 0x6f, 0x6d, 0x5d, 0x00, 0x21, 0x74, 0x6f,
370x08, 0x00, 0x04, 0x76, 0x00, 0xf5, 0x0c, 0x2c, 0x00, 0x62, 370x7b, 0x00, 0x32, 0x00, 0x6f, 0x72, 0x08, 0x00, 0x04, 0x76,
380x75, 0x74, 0x00, 0x77, 0x68, 0x65, 0x6e, 0x00, 0x79, 0x6f, 380x00, 0xf5, 0x0c, 0x2c, 0x00, 0x62, 0x75, 0x74, 0x00, 0x77,
390x75, 0x00, 0x64, 0x6f, 0x00, 0x73, 0x6f, 0x2c, 0x00, 0x6f, 390x68, 0x65, 0x6e, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x64, 0x6f,
400x74, 0x68, 0x65, 0x72, 0x89, 0x00, 0xf3, 0x01, 0x61, 0x72, 400x00, 0x73, 0x6f, 0x2c, 0x00, 0x6f, 0x74, 0x68, 0x65, 0x72,
410x6f, 0x75, 0x6e, 0x64, 0x00, 0x69, 0x74, 0x00, 0x63, 0x68, 410x89, 0x00, 0xf3, 0x01, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64,
420x61, 0x6e, 0x67, 0x65, 0x5e, 0x00, 0xf4, 0x00, 0x61, 0x73, 420x00, 0x69, 0x74, 0x00, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
430x00, 0x77, 0x65, 0x6c, 0x6c, 0x2e, 0x00, 0x00, 0x00, 0x45, 430x5e, 0x00, 0xf4, 0x00, 0x61, 0x73, 0x00, 0x77, 0x65, 0x6c,
440x61, 0x63, 0x68, 0x88, 0x00, 0xd0, 0x63, 0x6f, 0x6e, 0x74, 440x6c, 0x2e, 0x00, 0x00, 0x00, 0x45, 0x61, 0x63, 0x68, 0x88,
450x61, 0x69, 0x6e, 0x73, 0x00, 0x61, 0x00, 0x73, 0x6d, 0xd4, 450x00, 0xd0, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73,
460x00, 0xfb, 0x06, 0x64, 0x69, 0x61, 0x67, 0x72, 0x61, 0x6d, 460x00, 0x61, 0x00, 0x73, 0x6d, 0xd4, 0x00, 0xfb, 0x06, 0x64,
470x00, 0x73, 0x68, 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x00, 0x77, 470x69, 0x61, 0x67, 0x72, 0x61, 0x6d, 0x00, 0x73, 0x68, 0x6f,
480x68, 0x69, 0x63, 0x68, 0x63, 0x00, 0x03, 0x59, 0x00, 0x05, 480x77, 0x69, 0x6e, 0x67, 0x00, 0x77, 0x68, 0x69, 0x63, 0x68,
490x88, 0x00, 0x03, 0xc9, 0x00, 0x00, 0x5c, 0x00, 0x42, 0x31, 490x63, 0x00, 0x03, 0x59, 0x00, 0x05, 0x88, 0x00, 0x03, 0xc9,
500x34, 0x2e, 0x31, 0x6f, 0x01, 0x00, 0x5a, 0x00, 0x40, 0x72, 500x00, 0x00, 0x5c, 0x00, 0x42, 0x31, 0x34, 0x2e, 0x31, 0x80,
510x6f, 0x6c, 0x73, 0x78, 0x01, 0x60, 0x54, 0x68, 0x69, 0x73, 510x01, 0x00, 0x5a, 0x00, 0xe0, 0x72, 0x6f, 0x6c, 0x73, 0x20,
520x00, 0x67, 0x18, 0x01, 0x00, 0x0e, 0x01, 0xf1, 0x02, 0x62, 520x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x73, 0x00, 0x67, 0x18,
530x65, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x00, 0x77, 530x01, 0x00, 0x0e, 0x01, 0xf1, 0x02, 0x62, 0x65, 0x00, 0x70,
540x69, 0x74, 0x68, 0x00, 0x65, 0x69, 0x5d, 0x00, 0x00, 0x3b, 540x6c, 0x61, 0x79, 0x65, 0x64, 0x00, 0x77, 0x69, 0x74, 0x68,
550x01, 0xa2, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 550x00, 0x65, 0x69, 0x5d, 0x00, 0x00, 0x3b, 0x01, 0xa2, 0x6b,
560x00, 0x6f, 0x10, 0x00, 0x50, 0x6d, 0x6f, 0x75, 0x73, 0x65, 560x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x00, 0x6f, 0x10,
570x57, 0x00, 0xf4, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 570x00, 0x50, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x57, 0x00, 0xf4,
580x6c, 0x69, 0x63, 0x6b, 0x00, 0x69, 0x6e, 0x00, 0x61, 0xbe, 580x00, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63,
590x00, 0x24, 0x74, 0x6f, 0x7c, 0x00, 0x01, 0x51, 0x01, 0x00, 590x6b, 0x00, 0x69, 0x6e, 0x00, 0x61, 0xbe, 0x00, 0x24, 0x74,
600x4c, 0x01, 0xa6, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 600x6f, 0x7c, 0x00, 0x01, 0x51, 0x01, 0x00, 0x4c, 0x01, 0xa6,
610x74, 0x65, 0x64, 0xdb, 0x01, 0x61, 0x6f, 0x72, 0x00, 0x75, 610x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64,
620x73, 0x65, 0x52, 0x00, 0x60, 0x63, 0x75, 0x72, 0x73, 0x6f, 620xdb, 0x01, 0x61, 0x6f, 0x72, 0x00, 0x75, 0x73, 0x65, 0x52,
630x72, 0x69, 0x00, 0x01, 0xcc, 0x01, 0x04, 0x99, 0x01, 0x08, 630x00, 0x60, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x69, 0x00,
640x97, 0x01, 0x01, 0xc4, 0x01, 0x80, 0x70, 0x61, 0x63, 0x65, 640x01, 0xcc, 0x01, 0x04, 0x99, 0x01, 0x08, 0x97, 0x01, 0x01,
650x00, 0x62, 0x61, 0x72, 0x3c, 0x00, 0x41, 0x45, 0x6e, 0x74, 650xc4, 0x01, 0x80, 0x70, 0x61, 0x63, 0x65, 0x00, 0x62, 0x61,
660x65, 0x33, 0x00, 0x04, 0x70, 0x00, 0x00, 0x92, 0x00, 0x21, 660x72, 0x3c, 0x00, 0x41, 0x45, 0x6e, 0x74, 0x65, 0x33, 0x00,
670x49, 0x66, 0xfb, 0x00, 0x04, 0x58, 0x00, 0xf4, 0x06, 0x60, 670x04, 0x70, 0x00, 0x00, 0x92, 0x00, 0x21, 0x49, 0x66, 0xfb,
680x53, 0x6f, 0x6c, 0x76, 0x65, 0x27, 0x00, 0x66, 0x75, 0x6e, 680x00, 0x04, 0x58, 0x00, 0xf4, 0x06, 0x60, 0x53, 0x6f, 0x6c,
690x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x6f, 0x6e, 0x00, 0x74, 690x76, 0x65, 0x27, 0x00, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
700xf6, 0x00, 0x10, 0x2c, 0xa1, 0x00, 0x60, 0x77, 0x69, 0x6c, 700x6f, 0x6e, 0x00, 0x6f, 0x6e, 0x00, 0x74, 0xf6, 0x00, 0x10,
710x6c, 0x00, 0x6d, 0xce, 0x01, 0x01, 0x5b, 0x02, 0x29, 0x6f, 710x2c, 0xa1, 0x00, 0x60, 0x77, 0x69, 0x6c, 0x6c, 0x00, 0x6d,
720x66, 0x3f, 0x02, 0x74, 0x69, 0x6e, 0x00, 0x72, 0x65, 0x64, 720xce, 0x01, 0x01, 0x5b, 0x02, 0x29, 0x6f, 0x66, 0x3f, 0x02,
730x2e, 0x57, 0x00, 0x02, 0xeb, 0x00, 0x40, 0x6f, 0x6e, 0x63, 730x74, 0x69, 0x6e, 0x00, 0x72, 0x65, 0x64, 0x2e, 0x57, 0x00,
740x65, 0x1a, 0x00, 0x45, 0x65, 0x76, 0x65, 0x72, 0x3a, 0x02, 740x02, 0xeb, 0x00, 0x40, 0x6f, 0x6e, 0x63, 0x65, 0x1a, 0x00,
750x01, 0x34, 0x01, 0x10, 0x61, 0x2e, 0x00, 0x01, 0x4e, 0x00, 750x45, 0x65, 0x76, 0x65, 0x72, 0x3a, 0x02, 0x01, 0x34, 0x01,
760x11, 0x2c, 0x47, 0x00, 0x01, 0x5c, 0x01, 0x60, 0x73, 0x68, 760x10, 0x61, 0x2e, 0x00, 0x01, 0x4e, 0x00, 0x11, 0x2c, 0x47,
770x6f, 0x75, 0x6c, 0x64, 0x5f, 0x01, 0x10, 0x73, 0x8d, 0x00, 770x00, 0x01, 0x5c, 0x01, 0x60, 0x73, 0x68, 0x6f, 0x75, 0x6c,
780x49, 0x64, 0x2e, 0x00, 0x28, 0x4f, 0x00, 0x08, 0x3a, 0x01, 780x64, 0x5f, 0x01, 0x10, 0x73, 0x8d, 0x00, 0x49, 0x64, 0x2e,
790x00, 0x46, 0x00, 0x39, 0x6f, 0x75, 0x74, 0x49, 0x00, 0x06, 790x00, 0x28, 0x4f, 0x00, 0x08, 0x3a, 0x01, 0x00, 0x46, 0x00,
800x0c, 0x00, 0x02, 0xad, 0x00, 0x60, 0x61, 0x70, 0x70, 0x65, 800x39, 0x6f, 0x75, 0x74, 0x49, 0x00, 0x06, 0x0c, 0x00, 0x02,
810x61, 0x72, 0x37, 0x00, 0x11, 0x69, 0x93, 0x02, 0x70, 0x69, 810xad, 0x00, 0x60, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x37,
820x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0xf1, 0x00, 0x21, 0x61, 820x00, 0x11, 0x69, 0x93, 0x02, 0x70, 0x69, 0x6e, 0x64, 0x69,
830x74, 0x58, 0x00, 0x01, 0x27, 0x00, 0x40, 0x6e, 0x65, 0x65, 830x63, 0x61, 0x74, 0xf1, 0x00, 0x21, 0x61, 0x74, 0x58, 0x00,
840x64, 0x1f, 0x00, 0x10, 0x72, 0xa7, 0x00, 0x13, 0x73, 0x1e, 840x01, 0x27, 0x00, 0x40, 0x6e, 0x65, 0x65, 0x64, 0x1f, 0x00,
850x00, 0x51, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x09, 0x01, 0x01, 850x10, 0x72, 0xa7, 0x00, 0x13, 0x73, 0x1e, 0x00, 0x51, 0x6f,
860x1a, 0x00, 0x00, 0x72, 0x02, 0x21, 0x74, 0x68, 0x99, 0x00, 860x70, 0x65, 0x72, 0x61, 0x09, 0x01, 0x01, 0x1a, 0x00, 0x00,
870x10, 0x75, 0x16, 0x00, 0x73, 0x2e, 0x29, 0x00, 0x00, 0x00, 870x72, 0x02, 0x21, 0x74, 0x68, 0x99, 0x00, 0x10, 0x75, 0x16,
880x28, 0x41, 0x44, 0x03, 0x11, 0x61, 0x33, 0x01, 0xb0, 0x73, 880x00, 0x73, 0x2e, 0x29, 0x00, 0x00, 0x00, 0x28, 0x41, 0x44,
890x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 890x03, 0x11, 0x61, 0x33, 0x01, 0xb0, 0x73, 0x00, 0x64, 0x65,
900x74, 0x00, 0x22, 0x73, 0x65, 0x49, 0x01, 0x41, 0x32, 0x2e, 900x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x74, 0x00, 0x22,
910x31, 0x00, 0x9b, 0x01, 0xf2, 0x00, 0x6c, 0x73, 0x6f, 0x00, 910x73, 0x65, 0x49, 0x01, 0x41, 0x32, 0x2e, 0x31, 0x00, 0x9b,
920x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 920x01, 0xf2, 0x00, 0x6c, 0x73, 0x6f, 0x00, 0x61, 0x76, 0x61,
930x29, 0x6d, 0x02, 0x12, 0x32, 0x6d, 0x02, 0x93, 0x70, 0x61, 930x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0x6d, 0x02,
940x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x6f, 0x02, 0x46, 940x12, 0x32, 0x6d, 0x02, 0x93, 0x70, 0x61, 0x72, 0x61, 0x6d,
950x65, 0x73, 0x65, 0x00, 0x14, 0x00, 0x02, 0x40, 0x00, 0x04, 950x65, 0x74, 0x65, 0x72, 0x6f, 0x02, 0x46, 0x65, 0x73, 0x65,
960x3b, 0x00, 0x02, 0x69, 0x03, 0x01, 0xb5, 0x01, 0xd6, 0x43, 960x00, 0x14, 0x00, 0x02, 0x40, 0x00, 0x04, 0x3b, 0x00, 0x02,
970x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 970x69, 0x03, 0x01, 0xb5, 0x01, 0xd6, 0x43, 0x75, 0x73, 0x74,
980x6f, 0x70, 0xb7, 0x01, 0xd0, 0x65, 0x00, 0x60, 0x54, 0x79, 980x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0xb7,
990x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xed, 0x01, 990x01, 0xd0, 0x65, 0x00, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27,
1000x91, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 1000x00, 0x6d, 0x65, 0x6e, 0x75, 0xed, 0x01, 0x91, 0x57, 0x69,
1010x9e, 0x03, 0x51, 0x00, 0x00, 0x53, 0x69, 0x7a, 0xc2, 0x01, 1010x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x9e, 0x03, 0x51,
1020x01, 0x45, 0x04, 0x24, 0x69, 0x6e, 0xc6, 0x01, 0x10, 0x2e, 1020x00, 0x00, 0x53, 0x69, 0x7a, 0xc2, 0x01, 0x01, 0x45, 0x04,
1030x1b, 0x00, 0x94, 0x68, 0x61, 0x70, 0x65, 0x20, 0x74, 0x79, 1030x24, 0x69, 0x6e, 0xc6, 0x01, 0x10, 0x2e, 0x1b, 0x00, 0x94,
1040x70, 0x65, 0xf8, 0x02, 0x03, 0x09, 0x03, 0x20, 0x00, 0x64, 1040x68, 0x61, 0x70, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0xf8,
1050x8c, 0x00, 0x52, 0x6d, 0x69, 0x6e, 0x65, 0x73, 0x0b, 0x01, 1050x02, 0x03, 0x09, 0x03, 0x20, 0x00, 0x64, 0x8c, 0x00, 0x52,
1060x00, 0x29, 0x00, 0x04, 0x07, 0x02, 0x30, 0x72, 0x65, 0x67, 1060x6d, 0x69, 0x6e, 0x65, 0x73, 0x0b, 0x01, 0x00, 0x29, 0x00,
1070x7e, 0x00, 0x02, 0x6d, 0x03, 0x21, 0x69, 0x73, 0x66, 0x02, 1070x04, 0x07, 0x02, 0x30, 0x72, 0x65, 0x67, 0x7e, 0x00, 0x02,
1080x62, 0x70, 0x65, 0x64, 0x00, 0x62, 0x79, 0xbc, 0x01, 0x00, 1080x6d, 0x03, 0x21, 0x69, 0x73, 0x66, 0x02, 0x62, 0x70, 0x65,
1090x8a, 0x03, 0x21, 0x69, 0x6e, 0x41, 0x04, 0x44, 0x67, 0x69, 1090x64, 0x00, 0x62, 0x79, 0xbc, 0x01, 0x00, 0x8a, 0x03, 0x21,
1100x76, 0x65, 0x72, 0x00, 0x10, 0x2e, 0xeb, 0x00, 0xfa, 0x14, 1100x69, 0x6e, 0x41, 0x04, 0x44, 0x67, 0x69, 0x76, 0x65, 0x72,
1110x00, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x73, 1110x00, 0x10, 0x2e, 0xeb, 0x00, 0xfa, 0x14, 0x00, 0x64, 0x65,
1120x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x2c, 0x00, 0x60, 0x43, 1120x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x73, 0x65, 0x74, 0x74,
1130x72, 0x6f, 0x73, 0x73, 0x65, 0x73, 0x27, 0x2c, 0x00, 0x63, 1130x69, 0x6e, 0x67, 0x2c, 0x00, 0x60, 0x43, 0x72, 0x6f, 0x73,
1140x61, 0x75, 0x73, 0x65, 0x73, 0x42, 0x02, 0x06, 0x36, 0x03, 1140x73, 0x65, 0x73, 0x27, 0x2c, 0x00, 0x63, 0x61, 0x75, 0x73,
1150x45, 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x03, 0x10, 0x66, 0xe7, 1150x65, 0x73, 0x42, 0x02, 0x06, 0x36, 0x03, 0x45, 0x73, 0x65,
1160x04, 0x60, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0xe5, 0x01, 1160x6c, 0x66, 0x3a, 0x03, 0x10, 0x66, 0xe7, 0x04, 0x60, 0x69,
1170x10, 0x6e, 0xed, 0x00, 0x71, 0x62, 0x6f, 0x75, 0x72, 0x73, 1170x6d, 0x6d, 0x65, 0x64, 0x69, 0xe5, 0x01, 0x10, 0x6e, 0xed,
1180x00, 0x28, 0x8f, 0x03, 0x31, 0x72, 0x65, 0x65, 0x98, 0x03, 1180x00, 0x71, 0x62, 0x6f, 0x75, 0x72, 0x73, 0x00, 0x28, 0x8f,
1190xc0, 0x77, 0x6f, 0x00, 0x69, 0x66, 0x00, 0x69, 0x74, 0x27, 1190x03, 0x31, 0x72, 0x65, 0x65, 0x98, 0x03, 0xc0, 0x77, 0x6f,
1200x73, 0x00, 0x61, 0x78, 0x03, 0x41, 0x00, 0x65, 0x64, 0x67, 1200x00, 0x69, 0x66, 0x00, 0x69, 0x74, 0x27, 0x73, 0x00, 0x61,
1210x1a, 0x00, 0x72, 0x63, 0x6f, 0x72, 0x6e, 0x65, 0x72, 0x29, 1210x78, 0x03, 0x41, 0x00, 0x65, 0x64, 0x67, 0x1a, 0x00, 0x72,
1220x95, 0x00, 0x03, 0x32, 0x04, 0x05, 0x93, 0x00, 0x66, 0x52, 1220x63, 0x6f, 0x72, 0x6e, 0x65, 0x72, 0x29, 0x95, 0x00, 0x03,
1230x61, 0x6e, 0x64, 0x6f, 0x6d, 0x92, 0x00, 0x31, 0x61, 0x00, 1230x32, 0x04, 0x05, 0x93, 0x00, 0x66, 0x52, 0x61, 0x6e, 0x64,
1240x72, 0x12, 0x00, 0x03, 0x08, 0x01, 0x20, 0x74, 0x6f, 0xb8, 1240x6f, 0x6d, 0x92, 0x00, 0x31, 0x61, 0x00, 0x72, 0x12, 0x00,
1250x02, 0xa9, 0x63, 0x68, 0x6f, 0x73, 0x65, 0x6e, 0x00, 0x66, 1250x03, 0x08, 0x01, 0x20, 0x74, 0x6f, 0xb8, 0x02, 0xa9, 0x63,
1260x6f, 0x72, 0xb2, 0x00, 0x00, 0x9d, 0x05, 0x06, 0xe7, 0x02, 1260x68, 0x6f, 0x73, 0x65, 0x6e, 0x00, 0x66, 0x6f, 0x72, 0xb2,
1270xc3, 0x69, 0x73, 0x00, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 1270x00, 0x00, 0x9d, 0x05, 0x06, 0xe7, 0x02, 0xc3, 0x69, 0x73,
1280x65, 0x6e, 0x74, 0x27, 0x00, 0x60, 0x74, 0x69, 0x6d, 0x65, 1280x00, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74,
1290x2e, 0x00, 1290x27, 0x00, 0x60, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x00,
130}; 130};
131 131
132const unsigned short help_text_len = 1522; 132const unsigned short help_text_len = 1539;
133const unsigned short help_text_words = 298; 133const unsigned short help_text_words = 299;
134const char quick_help_text[] = "Flip groups of squares to light them all up at once."; 134const char quick_help_text[] = "Flip groups of squares to light them all up at once.";
diff --git a/apps/plugins/puzzles/help/flood.c b/apps/plugins/puzzles/help/flood.c
index 80e4383903..48905fd784 100644
--- a/apps/plugins/puzzles/help/flood.c
+++ b/apps/plugins/puzzles/help/flood.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,180 +6,180 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 155, TEXT_CENTER | C_RED }, 9 { 156, TEXT_CENTER | C_RED },
10 { 261, TEXT_CENTER | C_RED }, 10 { 262, TEXT_CENTER | C_RED },
11 { 278, TEXT_UNDERLINE },
12 { 279, TEXT_UNDERLINE }, 11 { 279, TEXT_UNDERLINE },
13 { 290, TEXT_UNDERLINE }, 12 { 280, TEXT_UNDERLINE },
14 { 332, TEXT_UNDERLINE }, 13 { 291, TEXT_UNDERLINE },
15 { 444, TEXT_UNDERLINE }, 14 { 333, TEXT_UNDERLINE },
15 { 445, TEXT_UNDERLINE },
16 LAST_STYLE_ITEM 16 LAST_STYLE_ITEM
17}; 17};
18 18
19/* orig 2377 comp 1592 ratio 0.669752 level 10 saved 785 */ 19/* orig 2395 comp 1600 ratio 0.668058 level 10 saved 795 */
20const char help_text[] = { 20const char help_text[] = {
210xf3, 0x45, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 210xfc, 0x05, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
220x33, 0x39, 0x3a, 0x20, 0x46, 0x6c, 0x6f, 0x6f, 0x64, 0x20, 220x33, 0x39, 0x3a, 0x20, 0x46, 0x6c, 0x6f, 0x6f, 0x64, 0x20,
230x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x61, 0x72, 0x65, 230x00, 0x2d, 0x01, 0x00, 0xf3, 0x33, 0x00, 0x00, 0x00, 0x59,
240x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 0x67, 240x6f, 0x75, 0x00, 0x61, 0x72, 0x65, 0x00, 0x67, 0x69, 0x76,
250x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 250x65, 0x6e, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00,
260x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 260x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73,
270x75, 0x72, 0x65, 0x64, 0x00, 0x61, 0x74, 0x00, 0x72, 0x61, 270x2c, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x65, 0x64,
280x6e, 0x64, 0x6f, 0x6d, 0x00, 0x69, 0x6e, 0x00, 0x6d, 0x75, 280x00, 0x61, 0x74, 0x00, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d,
290x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x1f, 0x00, 0xf0, 0x0b, 290x00, 0x69, 0x6e, 0x00, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70,
300x73, 0x2e, 0x00, 0x49, 0x6e, 0x00, 0x65, 0x61, 0x63, 0x68, 300x6c, 0x65, 0x1f, 0x00, 0xf0, 0x0b, 0x73, 0x2e, 0x00, 0x49,
310x00, 0x6d, 0x6f, 0x76, 0x65, 0x2c, 0x00, 0x79, 0x6f, 0x75, 310x6e, 0x00, 0x65, 0x61, 0x63, 0x68, 0x00, 0x6d, 0x6f, 0x76,
320x00, 0x63, 0x61, 0x6e, 0x00, 0x66, 0x68, 0x00, 0xf3, 0x03, 320x65, 0x2c, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x63, 0x61, 0x6e,
330x2d, 0x66, 0x69, 0x6c, 0x6c, 0x00, 0x74, 0x68, 0x65, 0x00, 330x00, 0x66, 0x7a, 0x00, 0xf3, 0x03, 0x2d, 0x66, 0x69, 0x6c,
340x74, 0x6f, 0x70, 0x00, 0x6c, 0x65, 0x66, 0x74, 0x5f, 0x00, 340x6c, 0x00, 0x74, 0x68, 0x65, 0x00, 0x74, 0x6f, 0x70, 0x00,
350x00, 0x4a, 0x00, 0x13, 0x61, 0x43, 0x00, 0x00, 0x75, 0x00, 350x6c, 0x65, 0x66, 0x74, 0x5f, 0x00, 0x00, 0x4a, 0x00, 0x13,
360x10, 0x79, 0x08, 0x00, 0xf4, 0x03, 0x63, 0x68, 0x6f, 0x69, 360x61, 0x43, 0x00, 0x00, 0x75, 0x00, 0x10, 0x79, 0x08, 0x00,
370x63, 0x65, 0x00, 0x28, 0x69, 0x2e, 0x65, 0x2e, 0x00, 0x65, 370xf4, 0x03, 0x63, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x00, 0x28,
380x76, 0x65, 0x72, 0x79, 0x2e, 0x00, 0x10, 0x72, 0x61, 0x00, 380x69, 0x2e, 0x65, 0x2e, 0x00, 0x65, 0x76, 0x65, 0x72, 0x79,
390x91, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x66, 0x72, 0x6f, 0x6d, 390x2e, 0x00, 0x10, 0x72, 0x61, 0x00, 0x91, 0x61, 0x62, 0x6c,
400x51, 0x00, 0x84, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 400x65, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x51, 0x00, 0x84, 0x73,
410x67, 0x23, 0x00, 0xf7, 0x12, 0x62, 0x79, 0x00, 0x61, 0x6e, 410x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x23, 0x00, 0xf7,
420x00, 0x6f, 0x72, 0x74, 0x68, 0x6f, 0x67, 0x6f, 0x6e, 0x61, 420x12, 0x62, 0x79, 0x00, 0x61, 0x6e, 0x00, 0x6f, 0x72, 0x74,
430x6c, 0x6c, 0x79, 0x00, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 430x68, 0x6f, 0x67, 0x6f, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0x00,
440x74, 0x65, 0x64, 0x00, 0x70, 0x61, 0x74, 0x68, 0xdc, 0x00, 440x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x00,
450x23, 0x00, 0x61, 0x96, 0x00, 0x44, 0x73, 0x61, 0x6d, 0x65, 450x70, 0x61, 0x74, 0x68, 0xdc, 0x00, 0x23, 0x00, 0x61, 0x96,
460x86, 0x00, 0x10, 0x77, 0xab, 0x00, 0x30, 0x62, 0x65, 0x00, 460x00, 0x44, 0x73, 0x61, 0x6d, 0x65, 0x86, 0x00, 0x10, 0x77,
470xb3, 0x00, 0x20, 0x65, 0x64, 0xa1, 0x00, 0x00, 0x22, 0x00, 470xab, 0x00, 0x30, 0x62, 0x65, 0x00, 0xb3, 0x00, 0x20, 0x65,
480x33, 0x6e, 0x65, 0x77, 0x21, 0x00, 0x51, 0x29, 0x2e, 0x00, 480x64, 0xa1, 0x00, 0x00, 0x22, 0x00, 0x33, 0x6e, 0x65, 0x77,
490x41, 0x73, 0xdf, 0x00, 0xf2, 0x02, 0x64, 0x6f, 0x00, 0x74, 490x21, 0x00, 0x51, 0x29, 0x2e, 0x00, 0x41, 0x73, 0xdf, 0x00,
500x68, 0x69, 0x73, 0x2c, 0x00, 0x6d, 0x6f, 0x72, 0x65, 0x00, 500xf2, 0x02, 0x64, 0x6f, 0x00, 0x74, 0x68, 0x69, 0x73, 0x2c,
510x61, 0x6e, 0x64, 0x09, 0x00, 0x21, 0x6f, 0x66, 0x32, 0x00, 510x00, 0x6d, 0x6f, 0x72, 0x65, 0x00, 0x61, 0x6e, 0x64, 0x09,
520x01, 0x48, 0x01, 0x77, 0x62, 0x65, 0x63, 0x6f, 0x6d, 0x65, 520x00, 0x21, 0x6f, 0x66, 0x32, 0x00, 0x01, 0x48, 0x01, 0x77,
530x73, 0x83, 0x00, 0x2f, 0x74, 0x6f, 0xb7, 0x00, 0x01, 0x12, 530x62, 0x65, 0x63, 0x6f, 0x6d, 0x65, 0x73, 0x83, 0x00, 0x2f,
540x2e, 0x89, 0x01, 0x80, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 540x74, 0x6f, 0xb7, 0x00, 0x01, 0x12, 0x2e, 0x89, 0x01, 0x80,
550x69, 0x73, 0x26, 0x00, 0x41, 0x6d, 0x61, 0x6b, 0x65, 0x2b, 550x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 0x69, 0x73, 0x26, 0x00,
560x00, 0x43, 0x77, 0x68, 0x6f, 0x6c, 0x4f, 0x00, 0x0b, 0xac, 560x41, 0x6d, 0x61, 0x6b, 0x65, 0x2b, 0x00, 0x43, 0x77, 0x68,
570x00, 0x11, 0x2c, 0x3f, 0x01, 0x51, 0x73, 0x00, 0x66, 0x65, 570x6f, 0x6c, 0x4f, 0x00, 0x0b, 0xac, 0x00, 0x11, 0x2c, 0x3f,
580x77, 0x76, 0x01, 0x10, 0x73, 0x0d, 0x00, 0xb0, 0x70, 0x6f, 580x01, 0x51, 0x73, 0x00, 0x66, 0x65, 0x77, 0x76, 0x01, 0x10,
590x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x2e, 0x00, 0x54, 0x86, 590x73, 0x0d, 0x00, 0xb0, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62,
600x00, 0x00, 0x2e, 0x00, 0x01, 0xd3, 0x00, 0xd3, 0x73, 0x65, 600x6c, 0x65, 0x2e, 0x00, 0x54, 0x86, 0x00, 0x00, 0x2e, 0x00,
610x74, 0x00, 0x61, 0x00, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x00, 610x01, 0xd3, 0x00, 0xd3, 0x73, 0x65, 0x74, 0x00, 0x61, 0x00,
620x6f, 0xd5, 0x00, 0x41, 0x75, 0x6d, 0x62, 0x65, 0x78, 0x01, 620x6c, 0x69, 0x6d, 0x69, 0x74, 0x00, 0x6f, 0xd5, 0x00, 0x41,
630x01, 0x3e, 0x00, 0x70, 0x2c, 0x00, 0x62, 0x61, 0x73, 0x65, 630x75, 0x6d, 0x62, 0x65, 0x78, 0x01, 0x01, 0x3e, 0x00, 0x70,
640x64, 0x1e, 0x00, 0x40, 0x72, 0x75, 0x6e, 0x6e, 0x9e, 0x00, 640x2c, 0x00, 0x62, 0x61, 0x73, 0x65, 0x64, 0x1e, 0x00, 0x40,
650xf1, 0x09, 0x69, 0x74, 0x73, 0x00, 0x6f, 0x77, 0x6e, 0x00, 650x72, 0x75, 0x6e, 0x6e, 0x9e, 0x00, 0xf1, 0x09, 0x69, 0x74,
660x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x00, 0x73, 660x73, 0x00, 0x6f, 0x77, 0x6e, 0x00, 0x69, 0x6e, 0x74, 0x65,
670x6f, 0x6c, 0x76, 0x65, 0x72, 0x2e, 0x36, 0x02, 0x65, 0x77, 670x72, 0x6e, 0x61, 0x6c, 0x00, 0x73, 0x6f, 0x6c, 0x76, 0x65,
680x69, 0x6e, 0x00, 0x69, 0x66, 0xea, 0x01, 0x0f, 0xb1, 0x00, 680x72, 0x2e, 0x36, 0x02, 0x65, 0x77, 0x69, 0x6e, 0x00, 0x69,
690x10, 0x02, 0x4e, 0x01, 0x73, 0x61, 0x74, 0x00, 0x6d, 0x61, 690x66, 0xea, 0x01, 0x0f, 0xb1, 0x00, 0x10, 0x02, 0x4e, 0x01,
700x6e, 0x79, 0xb3, 0x00, 0x20, 0x6f, 0x72, 0xc0, 0x00, 0x20, 700x73, 0x61, 0x74, 0x00, 0x6d, 0x61, 0x6e, 0x79, 0xb3, 0x00,
710x65, 0x72, 0x03, 0x01, 0x51, 0x49, 0x00, 0x73, 0x61, 0x77, 710x20, 0x6f, 0x72, 0xc0, 0x00, 0x20, 0x65, 0x72, 0x03, 0x01,
720x55, 0x01, 0x02, 0xb9, 0x00, 0xd2, 0x28, 0x77, 0x69, 0x74, 720x51, 0x49, 0x00, 0x73, 0x61, 0x77, 0x55, 0x01, 0x02, 0xb9,
730x68, 0x00, 0x61, 0x00, 0x66, 0x69, 0x78, 0x65, 0x64, 0x52, 730x00, 0xd2, 0x28, 0x77, 0x69, 0x74, 0x68, 0x00, 0x61, 0x00,
740x00, 0x53, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x11, 0x00, 0x06, 740x66, 0x69, 0x78, 0x65, 0x64, 0x52, 0x00, 0x53, 0x73, 0x69,
750xc0, 0x00, 0x03, 0x85, 0x02, 0x11, 0x2c, 0x86, 0x01, 0x02, 750x7a, 0x65, 0x2c, 0x11, 0x00, 0x06, 0xc0, 0x00, 0x03, 0x85,
760x1d, 0x00, 0x00, 0x5e, 0x00, 0x02, 0xef, 0x00, 0x10, 0x29, 760x02, 0x11, 0x2c, 0x86, 0x01, 0x02, 0x1d, 0x00, 0x00, 0x5e,
770xba, 0x02, 0x71, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 770x00, 0x02, 0xef, 0x00, 0x10, 0x29, 0xba, 0x02, 0x71, 0x68,
780x8f, 0x02, 0xf2, 0x0f, 0x69, 0x74, 0x2e, 0x61, 0x70, 0x70, 780x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x8f, 0x02, 0xf2, 0x0f,
790x73, 0x70, 0x6f, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x28, 790x69, 0x74, 0x2e, 0x61, 0x70, 0x70, 0x73, 0x70, 0x6f, 0x74,
800x6e, 0x6f, 0x00, 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x00, 800x2e, 0x63, 0x6f, 0x6d, 0x00, 0x28, 0x6e, 0x6f, 0x00, 0x6c,
810x61, 0x63, 0x63, 0x65, 0x3f, 0x01, 0x10, 0x29, 0x90, 0x00, 810x6f, 0x6e, 0x67, 0x65, 0x72, 0x00, 0x61, 0x63, 0x63, 0x65,
820x43, 0x33, 0x39, 0x2e, 0x31, 0x2a, 0x03, 0x80, 0x63, 0x6f, 820x3f, 0x01, 0x10, 0x29, 0x90, 0x00, 0x43, 0x33, 0x39, 0x2e,
830x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x33, 0x03, 0x81, 0x54, 830x31, 0x3c, 0x03, 0xf1, 0x05, 0x63, 0x6f, 0x6e, 0x74, 0x72,
840x6f, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x00, 0x1a, 0x00, 0x71, 840x6f, 0x6c, 0x73, 0x20, 0x00, 0x00, 0x00, 0x54, 0x6f, 0x00,
850x2c, 0x00, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0xeb, 0x00, 0x43, 850x70, 0x6c, 0x61, 0x79, 0x00, 0x1a, 0x00, 0x71, 0x2c, 0x00,
860x6d, 0x6f, 0x75, 0x73, 0xd4, 0x02, 0x04, 0xd8, 0x01, 0x18, 860x63, 0x6c, 0x69, 0x63, 0x6b, 0xeb, 0x00, 0x43, 0x6d, 0x6f,
870x54, 0xf5, 0x02, 0x61, 0x63, 0x6f, 0x72, 0x6e, 0x65, 0x72, 870x75, 0x73, 0xd4, 0x02, 0x04, 0xd8, 0x01, 0x18, 0x54, 0xf5,
880xa5, 0x00, 0x01, 0xd8, 0x02, 0x20, 0x74, 0x68, 0x65, 0x01, 880x02, 0x61, 0x63, 0x6f, 0x72, 0x6e, 0x65, 0x72, 0xa5, 0x00,
890x09, 0x1d, 0x02, 0x26, 0x69, 0x74, 0x82, 0x02, 0x05, 0x3b, 890x01, 0xd8, 0x02, 0x20, 0x74, 0x68, 0x65, 0x01, 0x09, 0x1d,
900x03, 0x31, 0x65, 0x64, 0x00, 0x0a, 0x01, 0x25, 0x74, 0x68, 900x02, 0x26, 0x69, 0x74, 0x82, 0x02, 0x05, 0x3b, 0x03, 0x31,
910x4a, 0x01, 0x03, 0x66, 0x02, 0x03, 0xf6, 0x02, 0x01, 0x84, 910x65, 0x64, 0x00, 0x0a, 0x01, 0x25, 0x74, 0x68, 0x4a, 0x01,
920x01, 0x00, 0x87, 0x00, 0x50, 0x65, 0x64, 0x2e, 0x00, 0x43, 920x03, 0x66, 0x02, 0x03, 0xf6, 0x02, 0x01, 0x84, 0x01, 0x00,
930x09, 0x00, 0x00, 0x59, 0x00, 0x04, 0x86, 0x00, 0x0d, 0x87, 930x87, 0x00, 0x50, 0x65, 0x64, 0x2e, 0x00, 0x43, 0x09, 0x00,
940x01, 0x4f, 0x61, 0x73, 0x00, 0x74, 0x98, 0x00, 0x00, 0xd2, 940x00, 0x59, 0x00, 0x04, 0x86, 0x00, 0x0d, 0x87, 0x01, 0x4f,
950x68, 0x61, 0x73, 0x00, 0x6e, 0x6f, 0x00, 0x65, 0x66, 0x66, 950x61, 0x73, 0x00, 0x74, 0x98, 0x00, 0x00, 0xd2, 0x68, 0x61,
960x65, 0x63, 0x74, 0x4c, 0x01, 0x60, 0x74, 0x68, 0x65, 0x72, 960x73, 0x00, 0x6e, 0x6f, 0x00, 0x65, 0x66, 0x66, 0x65, 0x63,
970x65, 0x66, 0xd7, 0x02, 0x30, 0x64, 0x6f, 0x65, 0x1e, 0x00, 970x74, 0x4c, 0x01, 0x60, 0x74, 0x68, 0x65, 0x72, 0x65, 0x66,
980x00, 0x2d, 0x00, 0x30, 0x75, 0x6e, 0x74, 0x43, 0x00, 0x11, 980xd7, 0x02, 0x30, 0x64, 0x6f, 0x65, 0x1e, 0x00, 0x00, 0x2d,
990x61, 0x64, 0x01, 0x03, 0xbb, 0x02, 0x01, 0x03, 0x02, 0x50, 990x00, 0x30, 0x75, 0x6e, 0x74, 0x43, 0x00, 0x11, 0x61, 0x64,
1000x61, 0x6c, 0x73, 0x6f, 0x00, 0x03, 0x01, 0x01, 0xa9, 0x00, 1000x01, 0x03, 0xbb, 0x02, 0x01, 0x03, 0x02, 0x50, 0x61, 0x6c,
1010x92, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 1010x73, 0x6f, 0x00, 0x03, 0x01, 0x01, 0xa9, 0x00, 0x92, 0x75,
1020xd0, 0x02, 0x00, 0x90, 0x01, 0x14, 0x61, 0x16, 0x00, 0xe3, 1020x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0xd0, 0x02,
1030x28, 0x6f, 0x75, 0x74, 0x6c, 0x69, 0x6e, 0x65, 0x00, 0x62, 1030x00, 0x90, 0x01, 0x14, 0x61, 0x16, 0x00, 0xe3, 0x28, 0x6f,
1040x6c, 0x61, 0x63, 0x6b, 0xa8, 0x00, 0x85, 0x29, 0x00, 0x61, 1040x75, 0x74, 0x6c, 0x69, 0x6e, 0x65, 0x00, 0x62, 0x6c, 0x61,
1050x72, 0x6f, 0x75, 0x6e, 0x64, 0x40, 0x03, 0x40, 0x2e, 0x00, 1050x63, 0x6b, 0xa8, 0x00, 0x85, 0x29, 0x00, 0x61, 0x72, 0x6f,
1060x50, 0x72, 0x90, 0x01, 0x21, 0x6e, 0x67, 0x13, 0x00, 0x60, 1060x75, 0x6e, 0x64, 0x40, 0x03, 0x40, 0x2e, 0x00, 0x50, 0x72,
1070x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x52, 0x00, 0x02, 0x24, 1070x90, 0x01, 0x21, 0x6e, 0x67, 0x13, 0x00, 0x60, 0x72, 0x65,
1080x01, 0x0e, 0x56, 0x04, 0x03, 0xc9, 0x00, 0x2f, 0x69, 0x6e, 1080x74, 0x75, 0x72, 0x6e, 0x52, 0x00, 0x02, 0x24, 0x01, 0x0e,
1090x2b, 0x01, 0x07, 0x57, 0x75, 0x6e, 0x64, 0x65, 0x72, 0xa1, 1090x56, 0x04, 0x03, 0xc9, 0x00, 0x2f, 0x69, 0x6e, 0x2b, 0x01,
1100x00, 0x00, 0xc0, 0x00, 0x23, 0x28, 0x41, 0x49, 0x00, 0xf2, 1100x07, 0x57, 0x75, 0x6e, 0x64, 0x65, 0x72, 0xa1, 0x00, 0x00,
1110x00, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x64, 1110xc0, 0x00, 0x23, 0x28, 0x41, 0x49, 0x00, 0xf2, 0x00, 0x61,
1120x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x00, 0x04, 0x21, 0x73, 1120x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x64, 0x65, 0x73,
1130x65, 0x16, 0x00, 0x41, 0x00, 0x32, 0x2e, 0x31, 0x2a, 0x05, 1130x63, 0x72, 0x69, 0x62, 0x00, 0x04, 0x21, 0x73, 0x65, 0x16,
1140x01, 0xe6, 0x00, 0x60, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 1140x00, 0x41, 0x00, 0x32, 0x2e, 0x31, 0x2a, 0x05, 0x01, 0xe6,
1150x68, 0x03, 0x12, 0x29, 0x29, 0x02, 0x13, 0x32, 0x29, 0x02, 1150x00, 0x60, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x68, 0x03,
1160x92, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 1160x12, 0x29, 0x29, 0x02, 0x13, 0x32, 0x29, 0x02, 0x92, 0x70,
1170x2b, 0x02, 0x56, 0x68, 0x65, 0x73, 0x65, 0x00, 0x14, 0x00, 1170x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x2b, 0x02,
1180x02, 0x41, 0x00, 0x04, 0x3c, 0x00, 0x06, 0xc7, 0x04, 0xe1, 1180x56, 0x68, 0x65, 0x73, 0x65, 0x00, 0x14, 0x00, 0x02, 0x41,
1190x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 1190x00, 0x04, 0x3c, 0x00, 0x06, 0xc7, 0x04, 0xe1, 0x60, 0x43,
1200x27, 0x00, 0x6f, 0x70, 0x6f, 0x00, 0x03, 0xa5, 0x03, 0xb0, 1200x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00,
1210x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 1210x6f, 0x70, 0x6f, 0x00, 0x03, 0xa5, 0x03, 0xb0, 0x60, 0x54,
1220x75, 0xab, 0x00, 0xf9, 0x04, 0x57, 0x69, 0x64, 0x74, 0x68, 1220x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xab,
1230x2c, 0x00, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x00, 0x00, 1230x00, 0xf9, 0x04, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00,
1240x00, 0x53, 0x69, 0x7a, 0x73, 0x04, 0x01, 0x14, 0x04, 0x03, 1240x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x00, 0x00, 0x00, 0x53,
1250xe0, 0x04, 0x00, 0x30, 0x00, 0x12, 0x43, 0x1a, 0x03, 0x4c, 1250x69, 0x7a, 0x73, 0x04, 0x01, 0x14, 0x04, 0x03, 0xe0, 0x04,
1260x00, 0x00, 0x00, 0x4e, 0x2e, 0x03, 0x00, 0xaa, 0x01, 0x01, 1260x00, 0x30, 0x00, 0x12, 0x43, 0x1a, 0x03, 0x4c, 0x00, 0x00,
1270x74, 0x02, 0x05, 0x48, 0x01, 0x02, 0x74, 0x01, 0x40, 0x4d, 1270x00, 0x4e, 0x2e, 0x03, 0x00, 0xaa, 0x01, 0x01, 0x74, 0x02,
1280x75, 0x73, 0x74, 0x80, 0x02, 0xa3, 0x61, 0x74, 0x00, 0x6c, 1280x05, 0x48, 0x01, 0x02, 0x74, 0x01, 0x40, 0x4d, 0x75, 0x73,
1290x65, 0x61, 0x73, 0x74, 0x00, 0x33, 0x89, 0x03, 0x35, 0x74, 1290x74, 0x80, 0x02, 0xa3, 0x61, 0x74, 0x00, 0x6c, 0x65, 0x61,
1300x77, 0x6f, 0x3c, 0x00, 0x01, 0x19, 0x02, 0x50, 0x00, 0x77, 1300x73, 0x74, 0x00, 0x33, 0x89, 0x03, 0x35, 0x74, 0x77, 0x6f,
1310x6f, 0x75, 0x6c, 0x31, 0x04, 0x20, 0x6c, 0x79, 0x31, 0x00, 1310x3c, 0x00, 0x01, 0x19, 0x02, 0x50, 0x00, 0x77, 0x6f, 0x75,
1320x93, 0x6f, 0x6e, 0x65, 0x00, 0x6c, 0x65, 0x67, 0x61, 0x6c, 1320x6c, 0x31, 0x04, 0x20, 0x6c, 0x79, 0x31, 0x00, 0x93, 0x6f,
1330xed, 0x01, 0x20, 0x74, 0x00, 0xe7, 0x03, 0xc0, 0x73, 0x74, 1330x6e, 0x65, 0x00, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0xed, 0x01,
1340x61, 0x67, 0x65, 0x2c, 0x00, 0x68, 0x65, 0x6e, 0x63, 0x65, 1340x20, 0x74, 0x00, 0xe7, 0x03, 0xc0, 0x73, 0x74, 0x61, 0x67,
1350x5f, 0x02, 0x03, 0xdf, 0x05, 0x04, 0xe3, 0x04, 0x20, 0x61, 1350x65, 0x2c, 0x00, 0x68, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x02,
1360x74, 0x87, 0x05, 0x12, 0x29, 0x6f, 0x02, 0x00, 0x1b, 0x04, 1360x03, 0xdf, 0x05, 0x04, 0xe3, 0x04, 0x20, 0x61, 0x74, 0x87,
1370x60, 0x6f, 0x73, 0x74, 0x00, 0x31, 0x30, 0xbc, 0x00, 0x61, 1370x05, 0x12, 0x29, 0x6f, 0x02, 0x00, 0x1b, 0x04, 0x60, 0x6f,
1380x45, 0x78, 0x74, 0x72, 0x61, 0x20, 0x27, 0x04, 0x70, 0x20, 1380x73, 0x74, 0x00, 0x31, 0x30, 0xbc, 0x00, 0x61, 0x45, 0x78,
1390x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x25, 0x03, 0x00, 0xd4, 1390x74, 0x72, 0x61, 0x20, 0x27, 0x04, 0x70, 0x20, 0x70, 0x65,
1400x00, 0x02, 0x8c, 0x03, 0x01, 0xb4, 0x00, 0xa4, 0x64, 0x69, 1400x72, 0x6d, 0x69, 0x74, 0x25, 0x03, 0x00, 0xd4, 0x00, 0x02,
1410x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x07, 0x01, 1410x8c, 0x03, 0x01, 0xb4, 0x00, 0xa4, 0x64, 0x69, 0x66, 0x66,
1420x70, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x2c, 0x0b, 0x06, 1420x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x07, 0x01, 0x70, 0x70,
1430x65, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x41, 0x02, 0x06, 1430x75, 0x7a, 0x7a, 0x6c, 0x65, 0x2c, 0x0b, 0x06, 0x65, 0x69,
1440x14, 0x04, 0x06, 0xaf, 0x06, 0x00, 0xda, 0x05, 0x02, 0x39, 1440x6e, 0x63, 0x72, 0x65, 0x61, 0x41, 0x02, 0x06, 0x14, 0x04,
1450x01, 0x01, 0xc0, 0x01, 0x02, 0x5a, 0x02, 0x5d, 0x72, 0x75, 1450x06, 0xaf, 0x06, 0x00, 0xda, 0x05, 0x02, 0x39, 0x01, 0x01,
1460x6e, 0x00, 0x61, 0xf7, 0x04, 0x00, 0xb4, 0x00, 0x85, 0x67, 1460xc0, 0x01, 0x02, 0x5a, 0x02, 0x5d, 0x72, 0x75, 0x6e, 0x00,
1470x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x1b, 0x05, 0x40, 1470x61, 0xf7, 0x04, 0x00, 0xb4, 0x00, 0x85, 0x67, 0x65, 0x6e,
1480x73, 0x6f, 0x6c, 0x75, 0xb0, 0x01, 0x05, 0x30, 0x03, 0x02, 1480x65, 0x72, 0x61, 0x74, 0x65, 0x1b, 0x05, 0x40, 0x73, 0x6f,
1490xb7, 0x01, 0x41, 0x76, 0x61, 0x6c, 0x75, 0x0b, 0x04, 0x01, 1490x6c, 0x75, 0xb0, 0x01, 0x05, 0x30, 0x03, 0x02, 0xb7, 0x01,
1500xce, 0x04, 0x55, 0x66, 0x69, 0x65, 0x6c, 0x64, 0xd9, 0x03, 1500x41, 0x76, 0x61, 0x6c, 0x75, 0x0b, 0x04, 0x01, 0xce, 0x04,
1510x36, 0x61, 0x64, 0x64, 0x0a, 0x06, 0x42, 0x6c, 0x65, 0x6e, 1510x55, 0x66, 0x69, 0x65, 0x6c, 0x64, 0xd9, 0x03, 0x36, 0x61,
1520x67, 0x96, 0x06, 0x01, 0x80, 0x00, 0x25, 0x27, 0x73, 0x52, 1520x64, 0x64, 0x0a, 0x06, 0x42, 0x6c, 0x65, 0x6e, 0x67, 0x96,
1530x00, 0x09, 0x6f, 0x00, 0x13, 0x74, 0xcd, 0x05, 0x29, 0x27, 1530x06, 0x01, 0x80, 0x00, 0x25, 0x27, 0x73, 0x52, 0x00, 0x09,
1540x73, 0xc6, 0x00, 0x43, 0x53, 0x6f, 0x00, 0x61, 0x6c, 0x00, 1540x6f, 0x00, 0x13, 0x74, 0xcd, 0x05, 0x29, 0x27, 0x73, 0xc6,
1550xc2, 0x6f, 0x66, 0x00, 0x30, 0x00, 0x72, 0x65, 0x71, 0x75, 1550x00, 0x43, 0x53, 0x6f, 0x00, 0x61, 0x6c, 0x00, 0xc2, 0x6f,
1560x69, 0x72, 0x65, 0xa1, 0x06, 0x20, 0x74, 0x6f, 0x6e, 0x00, 1560x66, 0x00, 0x30, 0x00, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72,
1570x31, 0x6a, 0x75, 0x73, 0xaf, 0x03, 0x10, 0x65, 0x28, 0x01, 1570x65, 0xa1, 0x06, 0x20, 0x74, 0x6f, 0x6e, 0x00, 0x31, 0x6a,
1580x22, 0x69, 0x65, 0xbc, 0x03, 0x04, 0x6c, 0x00, 0x60, 0x61, 1580x75, 0x73, 0xaf, 0x03, 0x10, 0x65, 0x28, 0x01, 0x22, 0x69,
1590x75, 0x74, 0x6f, 0x6d, 0x61, 0x57, 0x01, 0x02, 0xe3, 0x00, 1590x65, 0xbc, 0x03, 0x04, 0x6c, 0x00, 0x60, 0x61, 0x75, 0x74,
1600x03, 0x87, 0x01, 0x40, 0x00, 0x6c, 0x61, 0x72, 0x10, 0x05, 1600x6f, 0x6d, 0x61, 0x57, 0x01, 0x02, 0xe3, 0x00, 0x03, 0x87,
1610x02, 0x5a, 0x00, 0x00, 0xa8, 0x01, 0x10, 0x73, 0x9a, 0x04, 1610x01, 0x40, 0x00, 0x6c, 0x61, 0x72, 0x10, 0x05, 0x02, 0x5a,
1620x00, 0x4b, 0x01, 0x12, 0x65, 0x32, 0x03, 0x42, 0x4e, 0x6f, 1620x00, 0x00, 0xa8, 0x01, 0x10, 0x73, 0x9a, 0x04, 0x00, 0x4b,
1630x74, 0x65, 0xcc, 0x05, 0x04, 0x4b, 0x00, 0x0c, 0x2d, 0x01, 1630x01, 0x12, 0x65, 0x32, 0x03, 0x42, 0x4e, 0x6f, 0x74, 0x65,
1640x01, 0xee, 0x00, 0x00, 0x31, 0x04, 0x20, 0x6e, 0x65, 0x55, 1640xcc, 0x05, 0x04, 0x4b, 0x00, 0x0c, 0x2d, 0x01, 0x01, 0xee,
1650x05, 0x93, 0x61, 0x72, 0x69, 0x6c, 0x79, 0x00, 0x66, 0x69, 1650x00, 0x00, 0x31, 0x04, 0x20, 0x6e, 0x65, 0x55, 0x05, 0x93,
1660x6e, 0x16, 0x06, 0x75, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x73, 1660x61, 0x72, 0x69, 0x6c, 0x79, 0x00, 0x66, 0x69, 0x6e, 0x16,
1670x74, 0xb0, 0x06, 0x07, 0x49, 0x01, 0xf0, 0x00, 0x74, 0x68, 1670x06, 0x75, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x73, 0x74, 0xb0,
1680x6f, 0x75, 0x67, 0x68, 0x00, 0x49, 0x00, 0x62, 0x65, 0x6c, 1680x06, 0x07, 0x49, 0x01, 0xf0, 0x00, 0x74, 0x68, 0x6f, 0x75,
1690x69, 0x65, 0x76, 0x6c, 0x01, 0xf0, 0x07, 0x27, 0x73, 0x00, 1690x67, 0x68, 0x00, 0x49, 0x00, 0x62, 0x65, 0x6c, 0x69, 0x65,
1700x70, 0x72, 0x65, 0x74, 0x74, 0x79, 0x00, 0x63, 0x6c, 0x6f, 1700x76, 0x6c, 0x01, 0xf0, 0x07, 0x27, 0x73, 0x00, 0x70, 0x72,
1710x73, 0x65, 0x2e, 0x00, 0x46, 0x6f, 0x72, 0x00, 0x61, 0x11, 1710x65, 0x74, 0x74, 0x79, 0x00, 0x63, 0x6c, 0x6f, 0x73, 0x65,
1720x08, 0x60, 0x6c, 0x00, 0x63, 0x68, 0x61, 0x6c, 0x46, 0x01, 1720x2e, 0x00, 0x46, 0x6f, 0x72, 0x00, 0x61, 0x11, 0x08, 0x60,
1730x21, 0x65, 0x2c, 0xe5, 0x06, 0x01, 0x71, 0x01, 0x02, 0xb9, 1730x6c, 0x00, 0x63, 0x68, 0x61, 0x6c, 0x46, 0x01, 0x21, 0x65,
1740x00, 0x47, 0x74, 0x6f, 0x00, 0x30, 0x97, 0x01, 0x20, 0x72, 1740x2c, 0xe5, 0x06, 0x01, 0x71, 0x01, 0x02, 0xb9, 0x00, 0x47,
1750x79, 0x12, 0x00, 0x01, 0x9f, 0x00, 0x04, 0xe9, 0x08, 0x00, 1750x74, 0x6f, 0x00, 0x30, 0x97, 0x01, 0x20, 0x72, 0x79, 0x12,
1760x2d, 0x03, 0x81, 0x74, 0x72, 0x69, 0x63, 0x74, 0x6c, 0x79, 1760x00, 0x01, 0x9f, 0x00, 0x04, 0xe9, 0x08, 0x00, 0x2d, 0x03,
1770x20, 0x87, 0x06, 0x03, 0x96, 0x06, 0x32, 0x74, 0x68, 0x61, 1770x81, 0x74, 0x72, 0x69, 0x63, 0x74, 0x6c, 0x79, 0x20, 0x87,
1780xc8, 0x01, 0x02, 0x31, 0x07, 0xf0, 0x00, 0x79, 0x6f, 0x75, 1780x06, 0x03, 0x96, 0x06, 0x32, 0x74, 0x68, 0x61, 0xc8, 0x01,
1790x27, 0x72, 0x65, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x21, 1790x02, 0x31, 0x07, 0xf0, 0x00, 0x79, 0x6f, 0x75, 0x27, 0x72,
1800x29, 0x00, 1800x65, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x21, 0x29, 0x00,
181}; 181};
182 182
183const unsigned short help_text_len = 2377; 183const unsigned short help_text_len = 2395;
184const unsigned short help_text_words = 451; 184const unsigned short help_text_words = 452;
185const char quick_help_text[] = "Turn the grid the same colour in as few flood fills as possible."; 185const char quick_help_text[] = "Turn the grid the same colour in as few flood fills as possible.";
diff --git a/apps/plugins/puzzles/help/galaxies.c b/apps/plugins/puzzles/help/galaxies.c
index 3942832c52..17b0d4a945 100644
--- a/apps/plugins/puzzles/help/galaxies.c
+++ b/apps/plugins/puzzles/help/galaxies.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,206 +6,206 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 132, TEXT_CENTER | C_RED }, 9 { 133, TEXT_CENTER | C_RED },
10 { 444, TEXT_CENTER | C_RED }, 10 { 445, TEXT_CENTER | C_RED },
11 { 461, TEXT_UNDERLINE },
12 { 462, TEXT_UNDERLINE }, 11 { 462, TEXT_UNDERLINE },
13 { 472, TEXT_UNDERLINE }, 12 { 463, TEXT_UNDERLINE },
13 { 473, TEXT_UNDERLINE },
14 LAST_STYLE_ITEM 14 LAST_STYLE_ITEM
15}; 15};
16 16
17/* orig 2754 comp 1877 ratio 0.681554 level 10 saved 877 */ 17/* orig 2766 comp 1876 ratio 0.678236 level 10 saved 890 */
18const char help_text[] = { 18const char help_text[] = {
190xf0, 0x41, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 190xff, 0x08, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
200x32, 0x38, 0x3a, 0x20, 0x47, 0x61, 0x6c, 0x61, 0x78, 0x69, 200x32, 0x38, 0x3a, 0x20, 0x47, 0x61, 0x6c, 0x61, 0x78, 0x69,
210x65, 0x73, 0x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 210x65, 0x73, 0x20, 0x00, 0x2d, 0x01, 0x00, 0x00, 0xf0, 0x2c,
220x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x72, 0x65, 0x63, 220x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76,
230x74, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x00, 0x67, 230x65, 0x00, 0x61, 0x00, 0x72, 0x65, 0x63, 0x74, 0x61, 0x6e,
240x72, 0x69, 0x64, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 240x67, 0x75, 0x6c, 0x61, 0x72, 0x00, 0x67, 0x72, 0x69, 0x64,
250x6e, 0x69, 0x6e, 0x67, 0x00, 0x61, 0x00, 0x6e, 0x75, 0x6d, 250x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e,
260x62, 0x65, 0x72, 0x00, 0x6f, 0x66, 0x00, 0x64, 0x6f, 0x74, 260x67, 0x00, 0x61, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
270x73, 0x2e, 0x39, 0x00, 0xf4, 0x0a, 0x72, 0x00, 0x61, 0x69, 270x00, 0x6f, 0x66, 0x00, 0x64, 0x6f, 0x74, 0x73, 0x2e, 0x39,
280x6d, 0x00, 0x69, 0x73, 0x00, 0x74, 0x6f, 0x00, 0x70, 0x61, 280x00, 0xf4, 0x0a, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 0x69,
290x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x74, 0x68, 290x73, 0x00, 0x74, 0x6f, 0x00, 0x70, 0x61, 0x72, 0x74, 0x69,
300x65, 0x4b, 0x00, 0x70, 0x6c, 0x65, 0x00, 0x69, 0x6e, 0x74, 300x74, 0x69, 0x6f, 0x6e, 0x00, 0x74, 0x68, 0x65, 0x4b, 0x00,
310x6f, 0x49, 0x00, 0xe0, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 310x70, 0x6c, 0x65, 0x00, 0x69, 0x6e, 0x74, 0x6f, 0x49, 0x00,
320x00, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x47, 0x00, 320xe0, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x00, 0x72, 0x65,
330xf3, 0x12, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 330x67, 0x69, 0x6f, 0x6e, 0x73, 0x47, 0x00, 0xf3, 0x12, 0x73,
340x00, 0x69, 0x6e, 0x00, 0x73, 0x75, 0x63, 0x68, 0x00, 0x61, 340x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x69, 0x6e,
350x00, 0x77, 0x61, 0x79, 0x00, 0x74, 0x68, 0x61, 0x74, 0x00, 350x00, 0x73, 0x75, 0x63, 0x68, 0x00, 0x61, 0x00, 0x77, 0x61,
360x65, 0x76, 0x65, 0x72, 0x79, 0x2d, 0x00, 0x00, 0x61, 0x00, 360x79, 0x00, 0x74, 0x68, 0x61, 0x74, 0x00, 0x65, 0x76, 0x65,
370xf0, 0x00, 0x31, 0x38, 0x30, 0x2d, 0x64, 0x65, 0x67, 0x72, 370x72, 0x79, 0x2d, 0x00, 0x00, 0x61, 0x00, 0xf0, 0x00, 0x31,
380x65, 0x65, 0x00, 0x72, 0x6f, 0x74, 0x61, 0x68, 0x00, 0xf5, 380x38, 0x30, 0x2d, 0x64, 0x65, 0x67, 0x72, 0x65, 0x65, 0x00,
390x03, 0x61, 0x6c, 0x6c, 0x79, 0x00, 0x73, 0x79, 0x6d, 0x6d, 390x72, 0x6f, 0x74, 0x61, 0x68, 0x00, 0xf5, 0x03, 0x61, 0x6c,
400x65, 0x74, 0x72, 0x69, 0x63, 0x2c, 0x00, 0x61, 0x6e, 0xb1, 400x6c, 0x79, 0x00, 0x73, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72,
410x00, 0xd0, 0x73, 0x00, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 410x69, 0x63, 0x2c, 0x00, 0x61, 0x6e, 0xb1, 0x00, 0xd0, 0x73,
420x79, 0x00, 0x6f, 0x6e, 0x65, 0xaf, 0x00, 0x60, 0x00, 0x77, 420x00, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 0x79, 0x00, 0x6f,
430x68, 0x69, 0x63, 0x68, 0x49, 0x00, 0x40, 0x6c, 0x6f, 0x63, 430x6e, 0x65, 0xaf, 0x00, 0x60, 0x00, 0x77, 0x68, 0x69, 0x63,
440x61, 0x88, 0x00, 0xd1, 0x61, 0x74, 0x00, 0x69, 0x74, 0x73, 440x68, 0x49, 0x00, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x88, 0x00,
450x00, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x65, 0x8e, 0x00, 0x02, 450xd1, 0x61, 0x74, 0x00, 0x69, 0x74, 0x73, 0x00, 0x63, 0x65,
460x4a, 0x00, 0xf0, 0x00, 0x79, 0x2e, 0x00, 0x00, 0x00, 0x54, 460x6e, 0x74, 0x72, 0x65, 0x8e, 0x00, 0x02, 0x4a, 0x00, 0xf0,
470x6f, 0x00, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x00, 0x79, 0xe4, 470x00, 0x79, 0x2e, 0x00, 0x00, 0x00, 0x54, 0x6f, 0x00, 0x65,
480x00, 0x40, 0x73, 0x6f, 0x6c, 0x75, 0x71, 0x00, 0x10, 0x2c, 480x6e, 0x74, 0x65, 0x72, 0x00, 0x79, 0xe4, 0x00, 0x40, 0x73,
490x0f, 0x00, 0xf1, 0x02, 0x00, 0x64, 0x72, 0x61, 0x77, 0x00, 490x6f, 0x6c, 0x75, 0x71, 0x00, 0x10, 0x2c, 0x0f, 0x00, 0xf1,
500x6c, 0x69, 0x6e, 0x65, 0x73, 0x00, 0x61, 0x6c, 0x6f, 0x6e, 500x02, 0x00, 0x64, 0x72, 0x61, 0x77, 0x00, 0x6c, 0x69, 0x6e,
510x67, 0xef, 0x00, 0x01, 0x2e, 0x01, 0x41, 0x65, 0x64, 0x67, 510x65, 0x73, 0x00, 0x61, 0x6c, 0x6f, 0x6e, 0x67, 0xef, 0x00,
520x65, 0x0b, 0x01, 0x41, 0x6d, 0x61, 0x72, 0x6b, 0x17, 0x00, 520x01, 0x2e, 0x01, 0x41, 0x65, 0x64, 0x67, 0x65, 0x0b, 0x01,
530x91, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x69, 0x65, 530x41, 0x6d, 0x61, 0x72, 0x6b, 0x17, 0x00, 0x91, 0x62, 0x6f,
540xf0, 0x00, 0x02, 0x18, 0x01, 0x01, 0xff, 0x00, 0xc0, 0x2e, 540x75, 0x6e, 0x64, 0x61, 0x72, 0x69, 0x65, 0xf0, 0x00, 0x02,
550x00, 0x54, 0x68, 0x65, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 550x18, 0x01, 0x01, 0xff, 0x00, 0xc0, 0x2e, 0x00, 0x54, 0x68,
560x65, 0x96, 0x00, 0xc2, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 560x65, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x96, 0x00,
570x74, 0x65, 0x00, 0x77, 0x68, 0x65, 0x41, 0x01, 0x00, 0x44, 570xc2, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x00,
580x00, 0x23, 0x65, 0x64, 0x69, 0x00, 0x26, 0x6f, 0x6e, 0x66, 580x77, 0x68, 0x65, 0x41, 0x01, 0x00, 0x44, 0x00, 0x23, 0x65,
590x00, 0xc0, 0x61, 0x72, 0x65, 0x00, 0x70, 0x72, 0x65, 0x63, 590x64, 0x69, 0x00, 0x26, 0x6f, 0x6e, 0x66, 0x00, 0xc0, 0x61,
600x69, 0x73, 0x65, 0x6c, 0x2d, 0x01, 0x32, 0x6f, 0x73, 0x65, 600x72, 0x65, 0x00, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x65,
610x33, 0x01, 0xc4, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 610x6c, 0x2d, 0x01, 0x32, 0x6f, 0x73, 0x65, 0x33, 0x01, 0xc4,
620x65, 0x00, 0x74, 0x77, 0x6f, 0x5c, 0x01, 0x30, 0x00, 0x62, 620x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x00, 0x74,
630x65, 0xa4, 0x00, 0x10, 0x69, 0xa7, 0x00, 0xb6, 0x6f, 0x00, 630x77, 0x6f, 0x5c, 0x01, 0x30, 0x00, 0x62, 0x65, 0xa4, 0x00,
640x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x87, 640x10, 0x69, 0xa7, 0x00, 0xb6, 0x6f, 0x00, 0x64, 0x69, 0x66,
650x00, 0x64, 0x00, 0x00, 0x54, 0x68, 0x69, 0x73, 0x8a, 0x00, 650x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x87, 0x00, 0x64, 0x00,
660x90, 0x77, 0x61, 0x73, 0x00, 0x69, 0x6e, 0x76, 0x65, 0x6e, 660x00, 0x54, 0x68, 0x69, 0x73, 0x8a, 0x00, 0x90, 0x77, 0x61,
670x22, 0x01, 0xf1, 0x06, 0x62, 0x79, 0x00, 0x4e, 0x69, 0x6b, 670x73, 0x00, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x22, 0x01, 0xf1,
680x6f, 0x6c, 0x69, 0x00, 0x5b, 0x31, 0x33, 0x5d, 0x2c, 0x00, 680x06, 0x62, 0x79, 0x00, 0x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69,
690x75, 0x6e, 0x64, 0x65, 0x72, 0x88, 0x00, 0x80, 0x6e, 0x61, 690x00, 0x5b, 0x31, 0x33, 0x5d, 0x2c, 0x00, 0x75, 0x6e, 0x64,
700x6d, 0x65, 0x00, 0x60, 0x54, 0x65, 0x6c, 0x01, 0x71, 0x00, 700x65, 0x72, 0x88, 0x00, 0x80, 0x6e, 0x61, 0x6d, 0x65, 0x00,
710x53, 0x68, 0x6f, 0x77, 0x27, 0x3b, 0x4d, 0x01, 0x01, 0x18, 710x60, 0x54, 0x65, 0x6c, 0x01, 0x71, 0x00, 0x53, 0x68, 0x6f,
720x00, 0x02, 0xce, 0x00, 0x30, 0x6d, 0x6f, 0x6e, 0x9e, 0x00, 720x77, 0x27, 0x3b, 0x4d, 0x01, 0x01, 0x18, 0x00, 0x02, 0xce,
730x51, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x70, 0x01, 0x01, 0x07, 730x00, 0x30, 0x6d, 0x6f, 0x6e, 0x9e, 0x00, 0x51, 0x72, 0x61,
740x02, 0xf4, 0x04, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 740x6e, 0x73, 0x6c, 0x70, 0x01, 0x01, 0x07, 0x02, 0xf4, 0x04,
750x00, 0x61, 0x73, 0x00, 0x60, 0x53, 0x70, 0x69, 0x72, 0x61, 750x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x00, 0x61, 0x73,
760x6c, 0x00, 0x8b, 0x02, 0x10, 0x27, 0x8c, 0x00, 0x04, 0x0d, 760x00, 0x60, 0x53, 0x70, 0x69, 0x72, 0x61, 0x6c, 0x00, 0xa0,
770x00, 0x01, 0x89, 0x00, 0x00, 0xcc, 0x01, 0x40, 0x72, 0x69, 770x02, 0x10, 0x27, 0x8c, 0x00, 0x04, 0x0d, 0x00, 0x01, 0x89,
780x62, 0x75, 0x3e, 0x00, 0x51, 0x74, 0x6f, 0x00, 0x74, 0x68, 780x00, 0x00, 0xcc, 0x01, 0x40, 0x72, 0x69, 0x62, 0x75, 0x3e,
790x5a, 0x00, 0x41, 0x6c, 0x6c, 0x65, 0x63, 0x66, 0x02, 0xe1, 790x00, 0x51, 0x74, 0x6f, 0x00, 0x74, 0x68, 0x5a, 0x00, 0x41,
800x62, 0x79, 0x00, 0x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 800x6c, 0x6c, 0x65, 0x63, 0x66, 0x02, 0xe1, 0x62, 0x79, 0x00,
810x61, 0x72, 0x76, 0x65, 0xb7, 0x01, 0x00, 0xa8, 0x00, 0xd1, 810x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61, 0x72, 0x76,
820x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 820x65, 0xb7, 0x01, 0x00, 0xa8, 0x00, 0xe1, 0x00, 0x68, 0x74,
830x77, 0x2e, 0x6e, 0xbf, 0x00, 0xa2, 0x2e, 0x63, 0x6f, 0x2e, 830x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
840x6a, 0x70, 0x2f, 0x65, 0x6e, 0x2f, 0xe6, 0x00, 0xf6, 0x10, 840x6e, 0xc0, 0x00, 0xa2, 0x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70,
850x73, 0x2f, 0x61, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x6f, 0x6d, 850x2f, 0x65, 0x6e, 0x2f, 0xe7, 0x00, 0x31, 0x73, 0x2f, 0x74,
860x69, 0x63, 0x61, 0x6c, 0x5f, 0x73, 0x68, 0x6f, 0x77, 0x2e, 860xbb, 0x00, 0xd6, 0x5f, 0x73, 0x68, 0x6f, 0x77, 0x2f, 0x00,
870x68, 0x74, 0x6d, 0x6c, 0x00, 0x00, 0x00, 0x32, 0x38, 0x2e, 870x00, 0x00, 0x32, 0x38, 0x2e, 0x31, 0x29, 0x03, 0x01, 0x78,
880x31, 0x1d, 0x03, 0x01, 0x81, 0x00, 0x21, 0x6f, 0x6c, 0x26, 880x00, 0xf0, 0x02, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00, 0x00,
890x03, 0xa0, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 890x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b,
900x63, 0x6b, 0x8d, 0x01, 0x32, 0x61, 0x6e, 0x79, 0x8d, 0x01, 900x84, 0x01, 0x32, 0x61, 0x6e, 0x79, 0x84, 0x01, 0x00, 0x96,
910x00, 0x9f, 0x01, 0x01, 0x5a, 0x01, 0x00, 0x15, 0x02, 0x21, 910x01, 0x01, 0x51, 0x01, 0x00, 0x0c, 0x02, 0x21, 0x61, 0x6e,
920x61, 0x6e, 0x03, 0x02, 0x21, 0x00, 0x69, 0xeb, 0x01, 0x10, 920xfa, 0x01, 0x21, 0x00, 0x69, 0xe2, 0x01, 0x10, 0x72, 0x02,
930x72, 0x0b, 0x01, 0x31, 0x6e, 0x27, 0x74, 0x83, 0x02, 0xb0, 930x01, 0x31, 0x6e, 0x27, 0x74, 0x7a, 0x02, 0xb0, 0x61, 0x6c,
940x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x2c, 0x00, 0x6f, 940x72, 0x65, 0x61, 0x64, 0x79, 0x2c, 0x00, 0x6f, 0x72, 0x2f,
950x72, 0x2f, 0x00, 0x61, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 950x00, 0x61, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x1a, 0x00,
960x1a, 0x00, 0x07, 0x2d, 0x00, 0x30, 0x2e, 0x00, 0x57, 0xfe, 960x07, 0x2d, 0x00, 0x30, 0x2e, 0x00, 0x57, 0xf5, 0x01, 0x00,
970x01, 0x00, 0x65, 0x02, 0x50, 0x63, 0x72, 0x65, 0x61, 0x74, 970x5c, 0x02, 0x50, 0x63, 0x72, 0x65, 0x61, 0x74, 0x8a, 0x03,
980x93, 0x03, 0x54, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x08, 0x03, 980x54, 0x76, 0x61, 0x6c, 0x69, 0x64, 0xff, 0x02, 0x10, 0x28,
990x10, 0x28, 0x31, 0x00, 0x05, 0xca, 0x02, 0x7f, 0x63, 0x6c, 990x31, 0x00, 0x05, 0xc1, 0x02, 0x7f, 0x63, 0x6c, 0x6f, 0x73,
1000x6f, 0x73, 0x65, 0x64, 0x2c, 0xf4, 0x02, 0x06, 0x1b, 0x2c, 1000x65, 0x64, 0x2c, 0xeb, 0x02, 0x06, 0x1b, 0x2c, 0x2f, 0x03,
1010x38, 0x03, 0x05, 0x2b, 0x03, 0x62, 0x00, 0x61, 0x62, 0x6f, 1010x05, 0x22, 0x03, 0x62, 0x00, 0x61, 0x62, 0x6f, 0x75, 0x74,
1020x75, 0x74, 0x35, 0x02, 0x01, 0x28, 0x00, 0x09, 0x3a, 0x03, 1020x2c, 0x02, 0x01, 0x28, 0x00, 0x09, 0x31, 0x03, 0x50, 0x6e,
1030x50, 0x6e, 0x6f, 0x00, 0x65, 0x78, 0xb9, 0x01, 0x43, 0x65, 1030x6f, 0x00, 0x65, 0x78, 0xb0, 0x01, 0x43, 0x65, 0x6f, 0x75,
1040x6f, 0x75, 0x73, 0xd4, 0x02, 0x71, 0x62, 0x65, 0x74, 0x77, 1040x73, 0xcb, 0x02, 0x71, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65,
1050x65, 0x65, 0x6e, 0x5a, 0x02, 0x21, 0x6f, 0x66, 0xec, 0x01, 1050x6e, 0x51, 0x02, 0x21, 0x6f, 0x66, 0xe3, 0x01, 0x34, 0x6f,
1060x34, 0x6f, 0x77, 0x6e, 0x65, 0x02, 0xf1, 0x07, 0x29, 0x2c, 1060x77, 0x6e, 0x5c, 0x02, 0xf1, 0x07, 0x29, 0x2c, 0x00, 0x69,
1070x00, 0x69, 0x74, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0x00, 0x62, 1070x74, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0x00, 0x62, 0x65, 0x00,
1080x65, 0x00, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 1080x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x5c, 0x03,
1090x65, 0x03, 0x80, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 1090x80, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0xa3,
1100x63, 0xac, 0x03, 0x6a, 0x3b, 0x00, 0x73, 0x6f, 0x00, 0x79, 1100x03, 0x6a, 0x3b, 0x00, 0x73, 0x6f, 0x00, 0x79, 0x2c, 0x04,
1110x35, 0x04, 0x01, 0x79, 0x04, 0x20, 0x74, 0x68, 0xd6, 0x00, 1110x01, 0x70, 0x04, 0x20, 0x74, 0x68, 0xd6, 0x00, 0x23, 0x6f,
1120x23, 0x6f, 0x6c, 0xe1, 0x02, 0x08, 0x41, 0x00, 0x22, 0x69, 1120x6c, 0xd8, 0x02, 0x08, 0x41, 0x00, 0x22, 0x69, 0x6e, 0xa7,
1130x6e, 0xa7, 0x00, 0x21, 0x77, 0x61, 0xe1, 0x01, 0x30, 0x44, 1130x00, 0x21, 0x77, 0x61, 0xd8, 0x01, 0x30, 0x44, 0x75, 0x72,
1140x75, 0x72, 0xcb, 0x02, 0x72, 0x73, 0x6f, 0x6c, 0x76, 0x69, 1140xc2, 0x02, 0x72, 0x73, 0x6f, 0x6c, 0x76, 0x69, 0x6e, 0x67,
1150x6e, 0x67, 0x90, 0x03, 0x10, 0x6d, 0x2b, 0x00, 0x52, 0x00, 1150x87, 0x03, 0x10, 0x6d, 0x2b, 0x00, 0x52, 0x00, 0x6b, 0x6e,
1160x6b, 0x6e, 0x6f, 0x77, 0x2b, 0x00, 0x12, 0x61, 0x8a, 0x04, 1160x6f, 0x77, 0x2b, 0x00, 0x12, 0x61, 0x81, 0x04, 0x16, 0x63,
1170x16, 0x63, 0xc6, 0x04, 0x02, 0xa7, 0x00, 0x03, 0x0b, 0x03, 1170xbd, 0x04, 0x02, 0xa7, 0x00, 0x03, 0x02, 0x03, 0x01, 0x77,
1180x01, 0x77, 0x00, 0xa2, 0x61, 0x00, 0x73, 0x70, 0x65, 0x63, 1180x00, 0xa2, 0x61, 0x00, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66,
1190x69, 0x66, 0x69, 0x63, 0x01, 0x01, 0x70, 0x62, 0x75, 0x74, 1190x69, 0x63, 0x01, 0x01, 0x70, 0x62, 0x75, 0x74, 0x00, 0x6e,
1200x00, 0x6e, 0x6f, 0x74, 0xbf, 0x00, 0x22, 0x73, 0x75, 0x0f, 1200x6f, 0x74, 0xbf, 0x00, 0x22, 0x73, 0x75, 0x06, 0x04, 0x11,
1210x04, 0x11, 0x77, 0x95, 0x01, 0x00, 0x9b, 0x00, 0x02, 0x03, 1210x77, 0x95, 0x01, 0x00, 0x9b, 0x00, 0x02, 0x03, 0x01, 0x21,
1220x01, 0x21, 0x67, 0x6f, 0x27, 0x01, 0x02, 0x7e, 0x01, 0x10, 1220x67, 0x6f, 0x27, 0x01, 0x02, 0x7e, 0x01, 0x10, 0x6f, 0xb3,
1230x6f, 0xb3, 0x01, 0x05, 0x64, 0x03, 0x00, 0x5d, 0x00, 0x06, 1230x01, 0x05, 0x5b, 0x03, 0x00, 0x5d, 0x00, 0x06, 0xd8, 0x04,
1240xe1, 0x04, 0x01, 0xab, 0x02, 0x01, 0x81, 0x01, 0x71, 0x2e, 1240x01, 0xa2, 0x02, 0x01, 0x81, 0x01, 0x71, 0x2e, 0x00, 0x49,
1250x00, 0x49, 0x6e, 0x00, 0x6f, 0x72, 0x36, 0x03, 0x05, 0x15, 1250x6e, 0x00, 0x6f, 0x72, 0x2d, 0x03, 0x05, 0x0c, 0x04, 0x23,
1260x04, 0x23, 0x69, 0x73, 0x07, 0x01, 0x30, 0x00, 0x64, 0x6f, 1260x69, 0x73, 0x07, 0x01, 0x30, 0x00, 0x64, 0x6f, 0x1e, 0x02,
1270x1e, 0x02, 0x72, 0x66, 0x6f, 0x72, 0x67, 0x65, 0x74, 0x2c, 1270x72, 0x66, 0x6f, 0x72, 0x67, 0x65, 0x74, 0x2c, 0xf6, 0x01,
1280xf6, 0x01, 0x40, 0x61, 0x6e, 0x00, 0x72, 0xcf, 0x00, 0x06, 1280x40, 0x61, 0x6e, 0x00, 0x72, 0xcf, 0x00, 0x06, 0x6a, 0x02,
1290x6a, 0x02, 0x03, 0x4b, 0x00, 0x01, 0x7c, 0x00, 0x53, 0x64, 1290x03, 0x4b, 0x00, 0x01, 0x7c, 0x00, 0x53, 0x64, 0x72, 0x61,
1300x72, 0x61, 0x67, 0x2c, 0x82, 0x00, 0x01, 0x6e, 0x01, 0x04, 1300x67, 0x2c, 0x82, 0x00, 0x01, 0x6e, 0x01, 0x04, 0x26, 0x02,
1310x26, 0x02, 0x72, 0x6e, 0x00, 0x61, 0x72, 0x72, 0x6f, 0x77, 1310x72, 0x6e, 0x00, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2b, 0x04,
1320x34, 0x04, 0x71, 0x72, 0x00, 0x70, 0x6f, 0x69, 0x6e, 0x74, 1320x71, 0x72, 0x00, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0xab, 0x05,
1330xb4, 0x05, 0x16, 0x74, 0x8b, 0x00, 0x42, 0x44, 0x72, 0x6f, 1330x16, 0x74, 0x8b, 0x00, 0x42, 0x44, 0x72, 0x6f, 0x70, 0x21,
1340x70, 0x21, 0x01, 0x44, 0x69, 0x6e, 0x00, 0x61, 0x14, 0x01, 1340x01, 0x44, 0x69, 0x6e, 0x00, 0x61, 0x14, 0x01, 0x22, 0x6f,
1350x22, 0x6f, 0x66, 0x92, 0x01, 0x61, 0x63, 0x68, 0x6f, 0x69, 1350x66, 0x92, 0x01, 0x61, 0x63, 0x68, 0x6f, 0x69, 0x63, 0x65,
1360x63, 0x65, 0x66, 0x00, 0x04, 0xcb, 0x01, 0x61, 0x72, 0x65, 1360x66, 0x00, 0x04, 0xcb, 0x01, 0x61, 0x72, 0x65, 0x6d, 0x69,
1370x6d, 0x69, 0x6e, 0x64, 0x98, 0x00, 0x02, 0x73, 0x00, 0x20, 1370x6e, 0x64, 0x98, 0x00, 0x02, 0x73, 0x00, 0x20, 0x64, 0x6f,
1380x64, 0x6f, 0x33, 0x05, 0x91, 0x27, 0x73, 0x00, 0x61, 0x73, 1380x2a, 0x05, 0x91, 0x27, 0x73, 0x00, 0x61, 0x73, 0x73, 0x6f,
1390x73, 0x6f, 0x63, 0x69, 0xd6, 0x03, 0x41, 0x77, 0x69, 0x74, 1390x63, 0x69, 0xcd, 0x03, 0x41, 0x77, 0x69, 0x74, 0x68, 0x01,
1400x68, 0x0a, 0x06, 0x01, 0xbc, 0x00, 0x4c, 0x61, 0x6c, 0x73, 1400x06, 0x01, 0xbc, 0x00, 0x4c, 0x61, 0x6c, 0x73, 0x6f, 0xc1,
1410x6f, 0xc1, 0x00, 0x42, 0x65, 0x78, 0x69, 0x73, 0x8d, 0x00, 1410x00, 0x42, 0x65, 0x78, 0x69, 0x73, 0x8d, 0x00, 0x00, 0xa3,
1420x00, 0xa3, 0x00, 0x02, 0x2a, 0x06, 0x21, 0x69, 0x63, 0x1f, 1420x00, 0x02, 0x21, 0x06, 0x21, 0x69, 0x63, 0x16, 0x05, 0x41,
1430x05, 0x41, 0x6d, 0x00, 0x75, 0x70, 0x73, 0x00, 0x01, 0x0d, 1430x6d, 0x00, 0x75, 0x70, 0x73, 0x00, 0x01, 0x0d, 0x03, 0x00,
1440x03, 0x00, 0x11, 0x00, 0x01, 0x20, 0x03, 0x20, 0x64, 0x65, 1440x11, 0x00, 0x01, 0x20, 0x03, 0x72, 0x64, 0x65, 0x73, 0x74,
1450x9f, 0x03, 0x12, 0x79, 0x22, 0x00, 0x81, 0x62, 0x79, 0x00, 1450x72, 0x6f, 0x79, 0x22, 0x00, 0x81, 0x62, 0x79, 0x00, 0x64,
1460x64, 0x72, 0x6f, 0x70, 0x70, 0xc2, 0x04, 0x00, 0x11, 0x00, 1460x72, 0x6f, 0x70, 0x70, 0xb9, 0x04, 0x00, 0x11, 0x00, 0x35,
1470x35, 0x6f, 0x66, 0x66, 0x96, 0x01, 0x04, 0x55, 0x05, 0x00, 1470x6f, 0x66, 0x66, 0x96, 0x01, 0x04, 0x4c, 0x05, 0x00, 0xe6,
1480xe6, 0x01, 0xa1, 0x2e, 0x00, 0x28, 0x41, 0x6c, 0x73, 0x6f, 1480x01, 0xa1, 0x2e, 0x00, 0x28, 0x41, 0x6c, 0x73, 0x6f, 0x2c,
1490x2c, 0x00, 0x69, 0xd3, 0x00, 0x31, 0x27, 0x72, 0x65, 0xd2, 1490x00, 0x69, 0xd3, 0x00, 0x31, 0x27, 0x72, 0x65, 0xd2, 0x01,
1500x01, 0x01, 0xcf, 0x01, 0x06, 0xc0, 0x00, 0x05, 0x2b, 0x01, 1500x01, 0xcf, 0x01, 0x06, 0xc0, 0x00, 0x05, 0x2b, 0x01, 0x28,
1510x28, 0x69, 0x73, 0x27, 0x01, 0x06, 0x7f, 0x01, 0x01, 0x9c, 1510x69, 0x73, 0x27, 0x01, 0x06, 0x7f, 0x01, 0x01, 0x9c, 0x00,
1520x00, 0x29, 0x69, 0x74, 0x9a, 0x00, 0x50, 0x69, 0x74, 0x00, 1520x29, 0x69, 0x74, 0x9a, 0x00, 0x50, 0x69, 0x74, 0x00, 0x61,
1530x61, 0x72, 0xca, 0x05, 0x02, 0xc7, 0x01, 0x11, 0x6b, 0x12, 1530x72, 0xc1, 0x05, 0x02, 0xc7, 0x01, 0x11, 0x6b, 0x12, 0x00,
1540x00, 0xa3, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x65, 0x72, 0x2e, 1540xa3, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x65, 0x72, 0x2e, 0x00,
1550x00, 0x49, 0x30, 0x01, 0x60, 0x73, 0x77, 0x69, 0x76, 0x65, 1550x49, 0x30, 0x01, 0x60, 0x73, 0x77, 0x69, 0x76, 0x65, 0x6c,
1560x6c, 0x09, 0x02, 0x40, 0x73, 0x74, 0x61, 0x6e, 0x88, 0x03, 1560x09, 0x02, 0x40, 0x73, 0x74, 0x61, 0x6e, 0x88, 0x03, 0x24,
1570x24, 0x61, 0x73, 0x31, 0x06, 0x50, 0x67, 0x00, 0x69, 0x74, 1570x61, 0x73, 0x28, 0x06, 0x50, 0x67, 0x00, 0x69, 0x74, 0x2c,
1580x2c, 0x3e, 0x00, 0x42, 0x73, 0x74, 0x61, 0x79, 0x79, 0x00, 1580x3e, 0x00, 0x42, 0x73, 0x74, 0x61, 0x79, 0x79, 0x00, 0x06,
1590x06, 0x83, 0x06, 0x21, 0x70, 0x61, 0x93, 0x05, 0x00, 0xa6, 1590x7a, 0x06, 0x21, 0x70, 0x61, 0x8a, 0x05, 0x00, 0xa6, 0x01,
1600x01, 0x3a, 0x29, 0x00, 0x00, 0x4d, 0x01, 0x22, 0x75, 0x73, 1600x3a, 0x29, 0x00, 0x00, 0x4d, 0x01, 0x22, 0x75, 0x73, 0x84,
1610x84, 0x02, 0xa2, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x00, 1610x02, 0xa2, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x00, 0x6b,
1620x6b, 0x65, 0x79, 0x61, 0x06, 0x00, 0x97, 0x00, 0x04, 0x94, 1620x65, 0x79, 0x58, 0x06, 0x00, 0x97, 0x00, 0x04, 0x94, 0x00,
1630x00, 0x04, 0x19, 0x06, 0x05, 0x8f, 0x02, 0x13, 0x6e, 0x37, 1630x04, 0x10, 0x06, 0x05, 0x8f, 0x02, 0x13, 0x6e, 0x2e, 0x06,
1640x06, 0x83, 0x2e, 0x00, 0x50, 0x72, 0x65, 0x73, 0x73, 0x69, 1640x83, 0x2e, 0x00, 0x50, 0x72, 0x65, 0x73, 0x73, 0x69, 0x9b,
1650xa4, 0x06, 0x60, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x44, 1650x06, 0x60, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x44, 0x00,
1660x00, 0x02, 0x66, 0x06, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x00, 1660x02, 0x5d, 0x06, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x00, 0x61,
1670x61, 0xc8, 0x04, 0x01, 0xc7, 0x00, 0x01, 0xca, 0x04, 0x22, 1670xc8, 0x04, 0x01, 0xc7, 0x00, 0x01, 0xca, 0x04, 0x22, 0x6f,
1680x6f, 0x72, 0xe0, 0x00, 0x01, 0xa0, 0x00, 0x00, 0x6a, 0x01, 1680x72, 0xe0, 0x00, 0x01, 0xa0, 0x00, 0x00, 0x6a, 0x01, 0x10,
1690x10, 0x2c, 0xcd, 0x00, 0x5f, 0x61, 0x62, 0x6f, 0x76, 0x65, 1690x2c, 0xcd, 0x00, 0x5f, 0x61, 0x62, 0x6f, 0x76, 0x65, 0x55,
1700x55, 0x00, 0x13, 0x23, 0x64, 0x6f, 0x16, 0x01, 0x01, 0x50, 1700x00, 0x13, 0x23, 0x64, 0x6f, 0x16, 0x01, 0x01, 0x50, 0x01,
1710x01, 0x25, 0x75, 0x70, 0x79, 0x01, 0x01, 0x06, 0x01, 0x22, 1710x25, 0x75, 0x70, 0x79, 0x01, 0x01, 0x06, 0x01, 0x22, 0x62,
1720x62, 0x65, 0xd5, 0x01, 0x22, 0x65, 0x64, 0x4f, 0x06, 0x8c, 1720x65, 0xd5, 0x01, 0x22, 0x65, 0x64, 0x46, 0x06, 0x8c, 0x65,
1730x65, 0x78, 0x74, 0x00, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x00, 1730x78, 0x74, 0x00, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x00, 0x00,
1740x00, 0xa5, 0x01, 0x00, 0x6d, 0x00, 0x33, 0x65, 0x64, 0x3b, 1740xa5, 0x01, 0x00, 0x6d, 0x00, 0x33, 0x65, 0x64, 0x3b, 0xf6,
1750xff, 0x05, 0x04, 0x18, 0x01, 0x20, 0x62, 0x65, 0x1b, 0x01, 1750x05, 0x04, 0x18, 0x01, 0x20, 0x62, 0x65, 0x1b, 0x01, 0x15,
1760x15, 0x64, 0x0c, 0x01, 0x0c, 0x66, 0x02, 0x02, 0x1c, 0x01, 1760x64, 0x0c, 0x01, 0x0c, 0x66, 0x02, 0x02, 0x1c, 0x01, 0x12,
1770x12, 0x2c, 0x69, 0x05, 0x05, 0x3c, 0x02, 0x0e, 0x4d, 0x02, 1770x2c, 0x69, 0x05, 0x05, 0x3c, 0x02, 0x0e, 0x4d, 0x02, 0x13,
1780x13, 0x6e, 0xac, 0x00, 0x52, 0x6f, 0x72, 0x00, 0x61, 0x6e, 1780x6e, 0xac, 0x00, 0x52, 0x6f, 0x72, 0x00, 0x61, 0x6e, 0xd6,
1790xd6, 0x03, 0x01, 0x42, 0x00, 0x00, 0x6d, 0x04, 0x41, 0x28, 1790x03, 0x01, 0x42, 0x00, 0x00, 0x6d, 0x04, 0x41, 0x28, 0x41,
1800x41, 0x6c, 0x6c, 0x92, 0x00, 0x11, 0x61, 0x71, 0x06, 0x10, 1800x6c, 0x6c, 0x92, 0x00, 0x11, 0x61, 0x68, 0x06, 0x10, 0x73,
1810x73, 0x99, 0x02, 0x42, 0x63, 0x72, 0x69, 0x62, 0x97, 0x04, 1810x99, 0x02, 0x42, 0x63, 0x72, 0x69, 0x62, 0x97, 0x04, 0x13,
1820x13, 0x73, 0x87, 0x06, 0x31, 0x32, 0x2e, 0x31, 0x01, 0x04, 1820x73, 0x7e, 0x06, 0x31, 0x32, 0x2e, 0x31, 0x01, 0x04, 0x01,
1830x01, 0x97, 0x00, 0xb2, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 1830x97, 0x00, 0xb2, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62,
1840x62, 0x6c, 0x65, 0x2e, 0x29, 0x4e, 0x06, 0x16, 0x32, 0x4e, 1840x6c, 0x65, 0x2e, 0x29, 0x4e, 0x06, 0x16, 0x32, 0x4e, 0x06,
1850x06, 0x00, 0x9d, 0x07, 0x71, 0x6d, 0x65, 0x74, 0x65, 0x72, 1850x00, 0x94, 0x07, 0x71, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73,
1860x73, 0x20, 0x76, 0x07, 0x46, 0x65, 0x73, 0x65, 0x00, 0x14, 1860x20, 0x6d, 0x07, 0x46, 0x65, 0x73, 0x65, 0x00, 0x14, 0x00,
1870x00, 0x02, 0x44, 0x00, 0x04, 0x3f, 0x00, 0x51, 0x00, 0x66, 1870x02, 0x44, 0x00, 0x04, 0x3f, 0x00, 0x51, 0x00, 0x66, 0x72,
1880x72, 0x6f, 0x6d, 0x7c, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 1880x6f, 0x6d, 0x7c, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74,
1890x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 1890x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x72,
1900x72, 0x00, 0x03, 0x16, 0x04, 0xb0, 0x60, 0x54, 0x79, 0x70, 1900x00, 0x03, 0x16, 0x04, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65,
1910x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xae, 0x00, 0x91, 1910x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xae, 0x00, 0x91, 0x57,
1920x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x0f, 1920x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x0f, 0x05,
1930x05, 0x51, 0x00, 0x00, 0x53, 0x69, 0x7a, 0x20, 0x03, 0x01, 1930x51, 0x00, 0x00, 0x53, 0x69, 0x7a, 0x20, 0x03, 0x01, 0xdf,
1940xdf, 0x01, 0x15, 0x69, 0xac, 0x05, 0x01, 0x46, 0x05, 0x30, 1940x01, 0x15, 0x69, 0xac, 0x05, 0x01, 0x46, 0x05, 0x30, 0x69,
1950x69, 0x66, 0x66, 0x20, 0x05, 0x63, 0x74, 0x79, 0x00, 0x00, 1950x66, 0x66, 0x20, 0x05, 0x63, 0x74, 0x79, 0x00, 0x00, 0x00,
1960x00, 0x43, 0xe5, 0x06, 0x02, 0x2a, 0x04, 0x06, 0x1a, 0x00, 1960x43, 0xe5, 0x06, 0x02, 0x2a, 0x04, 0x06, 0x1a, 0x00, 0x04,
1970x04, 0x5b, 0x03, 0x41, 0x65, 0x6e, 0x65, 0x72, 0xeb, 0x03, 1970x5b, 0x03, 0x41, 0x65, 0x6e, 0x65, 0x72, 0xeb, 0x03, 0x02,
1980x02, 0x3d, 0x07, 0x57, 0x2e, 0x00, 0x4d, 0x6f, 0x72, 0x29, 1980x33, 0x07, 0x57, 0x2e, 0x00, 0x4d, 0x6f, 0x72, 0x29, 0x00,
1990x00, 0x13, 0x00, 0x54, 0x07, 0xa0, 0x00, 0x72, 0x65, 0x71, 1990x13, 0x00, 0x4a, 0x07, 0xa0, 0x00, 0x72, 0x65, 0x71, 0x75,
2000x75, 0x69, 0x72, 0x65, 0x00, 0x6d, 0x1f, 0x00, 0x02, 0xcf, 2000x69, 0x72, 0x65, 0x00, 0x6d, 0x1f, 0x00, 0x02, 0xc6, 0x08,
2010x08, 0x62, 0x78, 0x00, 0x64, 0x65, 0x64, 0x75, 0x3d, 0x01, 2010x62, 0x78, 0x00, 0x64, 0x65, 0x64, 0x75, 0x3d, 0x01, 0x02,
2020x02, 0x65, 0x06, 0x01, 0xb8, 0x00, 0x80, 0x55, 0x6e, 0x72, 2020x65, 0x06, 0x01, 0xb8, 0x00, 0x80, 0x55, 0x6e, 0x72, 0x65,
2030x65, 0x61, 0x73, 0x6f, 0x6e, 0xe9, 0x00, 0x18, 0x27, 0x73, 2030x61, 0x73, 0x6f, 0x6e, 0xe9, 0x00, 0x18, 0x27, 0x73, 0x00,
2040x00, 0x20, 0x6c, 0x65, 0x41, 0x03, 0x35, 0x6d, 0x61, 0x79, 2040x20, 0x6c, 0x65, 0x41, 0x03, 0x35, 0x6d, 0x61, 0x79, 0x4d,
2050x4d, 0x00, 0xe0, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 2050x00, 0xe0, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63,
2060x63, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x00, 2060x6b, 0x69, 0x6e, 0x67, 0x2e, 0x00,
207}; 207};
208 208
209const unsigned short help_text_len = 2754; 209const unsigned short help_text_len = 2766;
210const unsigned short help_text_words = 497; 210const unsigned short help_text_words = 498;
211const char quick_help_text[] = "Divide the grid into rotationally symmetric regions each centred on a dot."; 211const char quick_help_text[] = "Divide the grid into rotationally symmetric regions each centred on a dot.";
diff --git a/apps/plugins/puzzles/help/guess.c b/apps/plugins/puzzles/help/guess.c
index cdfc24e6b3..9749854e1e 100644
--- a/apps/plugins/puzzles/help/guess.c
+++ b/apps/plugins/puzzles/help/guess.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,209 +6,236 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 123, TEXT_CENTER | C_RED }, 9 { 124, TEXT_CENTER | C_RED },
10 { 404, TEXT_CENTER | C_RED }, 10 { 444, TEXT_CENTER | C_RED },
11 { 432, TEXT_UNDERLINE }, 11 { 472, TEXT_UNDERLINE },
12 { 452, TEXT_UNDERLINE }, 12 { 492, TEXT_UNDERLINE },
13 { 465, TEXT_UNDERLINE }, 13 { 505, TEXT_UNDERLINE },
14 { 483, TEXT_UNDERLINE }, 14 { 523, TEXT_UNDERLINE },
15 { 543, TEXT_UNDERLINE }, 15 { 583, TEXT_UNDERLINE },
16 { 614, TEXT_CENTER | C_RED },
16 LAST_STYLE_ITEM 17 LAST_STYLE_ITEM
17}; 18};
18 19
19/* orig 3042 comp 1883 ratio 0.619001 level 10 saved 1159 */ 20/* orig 3506 comp 2143 ratio 0.611238 level 10 saved 1363 */
20const char help_text[] = { 21const char help_text[] = {
210xf2, 0x2a, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 220xfc, 0x05, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
220x31, 0x35, 0x3a, 0x20, 0x47, 0x75, 0x65, 0x73, 0x73, 0x20, 230x31, 0x35, 0x3a, 0x20, 0x47, 0x75, 0x65, 0x73, 0x73, 0x20,
230x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 240x00, 0x2d, 0x01, 0x00, 0xf2, 0x18, 0x00, 0x00, 0x00, 0x59,
240x65, 0x00, 0x61, 0x00, 0x73, 0x65, 0x74, 0x00, 0x6f, 0x66, 250x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00,
250x00, 0x63, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x65, 0x64, 0x00, 260x73, 0x65, 0x74, 0x00, 0x6f, 0x66, 0x00, 0x63, 0x6f, 0x6c,
260x70, 0x65, 0x67, 0x73, 0x2c, 0x00, 0x61, 0x6e, 0x64, 0x21, 270x6f, 0x75, 0x72, 0x65, 0x64, 0x00, 0x70, 0x65, 0x67, 0x73,
270x00, 0xb0, 0x74, 0x6f, 0x00, 0x72, 0x65, 0x70, 0x72, 0x6f, 280x2c, 0x00, 0x61, 0x6e, 0x64, 0x21, 0x00, 0xb0, 0x74, 0x6f,
280x64, 0x75, 0x63, 0x2e, 0x00, 0xf0, 0x07, 0x70, 0x72, 0x65, 290x00, 0x72, 0x65, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x2e,
290x64, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x65, 0x64, 300x00, 0xf0, 0x07, 0x70, 0x72, 0x65, 0x64, 0x65, 0x74, 0x65,
300x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x41, 310x72, 0x6d, 0x69, 0x6e, 0x65, 0x64, 0x00, 0x73, 0x65, 0x71,
310x00, 0xf0, 0x00, 0x74, 0x68, 0x65, 0x6d, 0x00, 0x28, 0x63, 320x75, 0x65, 0x6e, 0x63, 0x65, 0x41, 0x00, 0xf0, 0x00, 0x74,
320x68, 0x6f, 0x73, 0x65, 0x6e, 0x00, 0x62, 0x79, 0x10, 0x00, 330x68, 0x65, 0x6d, 0x00, 0x28, 0x63, 0x68, 0x6f, 0x73, 0x65,
330xf0, 0x13, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 340x6e, 0x00, 0x62, 0x79, 0x10, 0x00, 0xf0, 0x13, 0x00, 0x63,
340x72, 0x29, 0x00, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x00, 350x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x29, 0x00, 0x77,
350x61, 0x00, 0x63, 0x65, 0x72, 0x74, 0x61, 0x69, 0x6e, 0x00, 360x69, 0x74, 0x68, 0x69, 0x6e, 0x00, 0x61, 0x00, 0x63, 0x65,
360x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x39, 0x00, 0x10, 0x67, 370x72, 0x74, 0x61, 0x69, 0x6e, 0x00, 0x6e, 0x75, 0x6d, 0x62,
370x95, 0x00, 0xa2, 0x65, 0x73, 0x2e, 0x00, 0x00, 0x00, 0x45, 380x65, 0x72, 0x39, 0x00, 0x10, 0x67, 0xa7, 0x00, 0xa2, 0x65,
380x61, 0x63, 0x68, 0x10, 0x00, 0xc1, 0x00, 0x67, 0x65, 0x74, 390x73, 0x2e, 0x00, 0x00, 0x00, 0x45, 0x61, 0x63, 0x68, 0x10,
390x73, 0x00, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x3d, 0x00, 400x00, 0xc1, 0x00, 0x67, 0x65, 0x74, 0x73, 0x00, 0x6d, 0x61,
400x01, 0x50, 0x00, 0x06, 0x35, 0x00, 0xa9, 0x63, 0x6f, 0x72, 410x72, 0x6b, 0x65, 0x64, 0x3d, 0x00, 0x01, 0x50, 0x00, 0x06,
410x72, 0x65, 0x63, 0x74, 0x6c, 0x79, 0x2d, 0xb9, 0x00, 0x33, 420x35, 0x00, 0xa9, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74,
420x00, 0x69, 0x6e, 0x79, 0x00, 0x01, 0x1f, 0x00, 0xf2, 0x03, 430x6c, 0x79, 0x2d, 0xb9, 0x00, 0x33, 0x00, 0x69, 0x6e, 0x79,
430x00, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x00, 0x28, 0x69, 440x00, 0x01, 0x1f, 0x00, 0xf2, 0x03, 0x00, 0x70, 0x6c, 0x61,
440x6e, 0x00, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x29, 0xda, 0x00, 450x63, 0x65, 0x73, 0x00, 0x28, 0x69, 0x6e, 0x00, 0x62, 0x6c,
450x4f, 0x61, 0x6c, 0x73, 0x6f, 0x51, 0x00, 0x06, 0x1f, 0x00, 460x61, 0x63, 0x6b, 0x29, 0xda, 0x00, 0x4f, 0x61, 0x6c, 0x73,
460x52, 0x00, 0x02, 0x58, 0x77, 0x72, 0x6f, 0x6e, 0x67, 0x50, 470x6f, 0x51, 0x00, 0x06, 0x1f, 0x00, 0x52, 0x00, 0x02, 0x58,
470x00, 0x60, 0x77, 0x68, 0x69, 0x74, 0x65, 0x29, 0xb6, 0x00, 480x77, 0x72, 0x6f, 0x6e, 0x67, 0x50, 0x00, 0x60, 0x77, 0x68,
480xc2, 0x54, 0x68, 0x69, 0x73, 0x00, 0x67, 0x61, 0x6d, 0x65, 490x69, 0x74, 0x65, 0x29, 0xb6, 0x00, 0xc2, 0x54, 0x68, 0x69,
490x00, 0x69, 0x73, 0x5b, 0x00, 0x70, 0x6b, 0x6e, 0x6f, 0x77, 500x73, 0x00, 0x67, 0x61, 0x6d, 0x65, 0x00, 0x69, 0x73, 0x5b,
500x6e, 0x00, 0x28, 0x6b, 0x00, 0x01, 0xc3, 0x00, 0x40, 0x74, 510x00, 0x70, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x28, 0x6b,
510x65, 0x64, 0x2c, 0x14, 0x01, 0xf2, 0x0b, 0x48, 0x61, 0x73, 520x00, 0x01, 0xc3, 0x00, 0x40, 0x74, 0x65, 0x64, 0x2c, 0x14,
520x62, 0x72, 0x6f, 0x2c, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x6c, 530x01, 0xf2, 0x0b, 0x48, 0x61, 0x73, 0x62, 0x72, 0x6f, 0x2c,
530x79, 0x29, 0x00, 0x61, 0x73, 0x00, 0x61, 0x00, 0x62, 0x6f, 540x00, 0x6d, 0x61, 0x69, 0x6e, 0x6c, 0x79, 0x29, 0x00, 0x61,
540x61, 0x72, 0x64, 0x40, 0x00, 0x42, 0x60, 0x4d, 0x61, 0x73, 550x73, 0x00, 0x61, 0x00, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x40,
550x5d, 0x01, 0x32, 0x64, 0x27, 0x2c, 0xf7, 0x00, 0x13, 0x36, 560x00, 0x42, 0x60, 0x4d, 0x61, 0x73, 0x5d, 0x01, 0x32, 0x64,
560x8f, 0x00, 0x42, 0x73, 0x2c, 0x00, 0x34, 0x91, 0x00, 0x72, 570x27, 0x2c, 0xf7, 0x00, 0x13, 0x36, 0x8f, 0x00, 0x42, 0x73,
570x70, 0x65, 0x72, 0x00, 0x72, 0x6f, 0x77, 0xca, 0x00, 0x26, 580x2c, 0x00, 0x34, 0x91, 0x00, 0x72, 0x70, 0x65, 0x72, 0x00,
580x31, 0x30, 0x40, 0x01, 0xa0, 0x48, 0x6f, 0x77, 0x65, 0x76, 590x72, 0x6f, 0x77, 0xca, 0x00, 0x26, 0x31, 0x30, 0x40, 0x01,
590x65, 0x72, 0x2c, 0x00, 0x74, 0x91, 0x00, 0xf0, 0x06, 0x76, 600xa0, 0x48, 0x6f, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2c, 0x00,
600x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x61, 0x6c, 0x6c, 610x74, 0x91, 0x00, 0xf0, 0x06, 0x76, 0x65, 0x72, 0x73, 0x69,
610x6f, 0x77, 0x73, 0x00, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 620x6f, 0x6e, 0x00, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x00,
620xee, 0x01, 0x50, 0x74, 0x69, 0x6e, 0x67, 0x73, 0xf3, 0x00, 630x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0xee, 0x01, 0x50, 0x74,
630x08, 0xfd, 0x00, 0x01, 0x63, 0x00, 0x40, 0x00, 0x28, 0x75, 640x69, 0x6e, 0x67, 0x73, 0xf3, 0x00, 0x08, 0xfd, 0x00, 0x01,
640x70, 0xf1, 0x01, 0x47, 0x31, 0x30, 0x29, 0x2c, 0x1e, 0x00, 650x63, 0x00, 0x40, 0x00, 0x28, 0x75, 0x70, 0xf1, 0x01, 0x47,
650x0e, 0x76, 0x00, 0x0f, 0xbd, 0x01, 0x02, 0x11, 0x47, 0xb8, 660x31, 0x30, 0x29, 0x2c, 0x1e, 0x00, 0x0e, 0x76, 0x00, 0x0f,
660x01, 0xf0, 0x00, 0x77, 0x61, 0x73, 0x00, 0x63, 0x6f, 0x6e, 670xbd, 0x01, 0x02, 0x11, 0x47, 0xb8, 0x01, 0xf0, 0x00, 0x77,
670x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x4f, 0x00, 680x61, 0x73, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62,
680x01, 0x8f, 0x00, 0x91, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 690x75, 0x74, 0x65, 0x64, 0x4f, 0x00, 0x01, 0x8f, 0x00, 0x91,
690x74, 0x69, 0x6f, 0x1d, 0x02, 0xc0, 0x4a, 0x61, 0x6d, 0x65, 700x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x1d,
700x73, 0x00, 0x48, 0x61, 0x72, 0x76, 0x65, 0x79, 0x3c, 0x00, 710x02, 0xc0, 0x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61,
710x43, 0x31, 0x35, 0x2e, 0x31, 0x9e, 0x02, 0x01, 0x3d, 0x00, 720x72, 0x76, 0x65, 0x79, 0x3c, 0x00, 0x43, 0x31, 0x35, 0x2e,
720x49, 0x6f, 0x6c, 0x73, 0x20, 0x5a, 0x01, 0x60, 0x63, 0x61, 730x31, 0xb0, 0x02, 0x01, 0x3d, 0x00, 0x49, 0x6f, 0x6c, 0x73,
730x6e, 0x00, 0x62, 0x65, 0x80, 0x01, 0x14, 0x79, 0x11, 0x02, 740x20, 0x5a, 0x01, 0x60, 0x63, 0x61, 0x6e, 0x00, 0x62, 0x65,
740x61, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x9d, 0x01, 0x32, 750x80, 0x01, 0x14, 0x79, 0x11, 0x02, 0x61, 0x65, 0x69, 0x74,
750x6b, 0x65, 0x79, 0x46, 0x01, 0x12, 0x6f, 0x10, 0x00, 0x50, 760x68, 0x65, 0x72, 0x9d, 0x01, 0x32, 0x6b, 0x65, 0x79, 0x46,
760x6d, 0x6f, 0x75, 0x73, 0x65, 0x58, 0x00, 0x14, 0x57, 0x3a, 770x01, 0x12, 0x6f, 0x10, 0x00, 0x50, 0x6d, 0x6f, 0x75, 0x73,
770x02, 0x01, 0x12, 0x00, 0x89, 0x2c, 0x00, 0x64, 0x72, 0x61, 780x65, 0x58, 0x00, 0x14, 0x57, 0x3a, 0x02, 0x01, 0x12, 0x00,
780x67, 0x00, 0x61, 0xe2, 0x01, 0x51, 0x00, 0x66, 0x72, 0x6f, 790x89, 0x2c, 0x00, 0x64, 0x72, 0x61, 0x67, 0x00, 0x61, 0xe2,
790x6d, 0x24, 0x00, 0x62, 0x74, 0x72, 0x61, 0x79, 0x00, 0x6f, 800x01, 0x51, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x24, 0x00, 0x62,
800xef, 0x01, 0x60, 0x6c, 0x65, 0x66, 0x74, 0x2d, 0x68, 0xec, 810x74, 0x72, 0x61, 0x79, 0x00, 0x6f, 0xef, 0x01, 0x60, 0x6c,
810x00, 0x31, 0x73, 0x69, 0x64, 0x06, 0x03, 0x91, 0x69, 0x74, 820x65, 0x66, 0x74, 0x2d, 0x68, 0xec, 0x00, 0x31, 0x73, 0x69,
820x73, 0x00, 0x72, 0x65, 0x71, 0x75, 0x69, 0x38, 0x00, 0x31, 830x64, 0x06, 0x03, 0x91, 0x69, 0x74, 0x73, 0x00, 0x72, 0x65,
830x6f, 0x73, 0x69, 0xcc, 0x00, 0x04, 0x70, 0x02, 0x62, 0x75, 840x71, 0x75, 0x69, 0x38, 0x00, 0x31, 0x6f, 0x73, 0x69, 0xcc,
840x72, 0x72, 0x65, 0x6e, 0x74, 0x0f, 0x01, 0x12, 0x3b, 0x32, 850x00, 0x04, 0x70, 0x02, 0x62, 0x75, 0x72, 0x72, 0x65, 0x6e,
850x01, 0x32, 0x6d, 0x61, 0x79, 0x0e, 0x02, 0x21, 0x62, 0x65, 860x74, 0x0f, 0x01, 0x12, 0x3b, 0x32, 0x01, 0x32, 0x6d, 0x61,
860x78, 0x00, 0x32, 0x67, 0x65, 0x64, 0x6c, 0x00, 0x04, 0x2d, 870x79, 0x0e, 0x02, 0x21, 0x62, 0x65, 0x78, 0x00, 0x32, 0x67,
870x00, 0x00, 0x5e, 0x00, 0x44, 0x70, 0x61, 0x73, 0x74, 0x45, 880x65, 0x64, 0x6c, 0x00, 0x04, 0x2d, 0x00, 0x00, 0x5e, 0x00,
880x01, 0x00, 0x66, 0x00, 0x42, 0x63, 0x6f, 0x70, 0x79, 0x4b, 890x44, 0x70, 0x61, 0x73, 0x74, 0x45, 0x01, 0x00, 0x66, 0x00,
890x03, 0xc0, 0x65, 0x6c, 0x73, 0x65, 0x77, 0x68, 0x65, 0x72, 900x42, 0x63, 0x6f, 0x70, 0x79, 0x4b, 0x03, 0xc0, 0x65, 0x6c,
900x65, 0x2e, 0x00, 0x54, 0x84, 0x03, 0x31, 0x6d, 0x6f, 0x76, 910x73, 0x65, 0x77, 0x68, 0x65, 0x72, 0x65, 0x2e, 0x00, 0x54,
910x81, 0x03, 0x23, 0x65, 0x67, 0xc7, 0x00, 0x10, 0x69, 0xb8, 920x84, 0x03, 0x31, 0x6d, 0x6f, 0x76, 0x81, 0x03, 0x23, 0x65,
920x03, 0x11, 0x66, 0x98, 0x00, 0x04, 0x52, 0x00, 0x05, 0x97, 930x67, 0xc7, 0x00, 0x10, 0x69, 0xb8, 0x03, 0x11, 0x66, 0x98,
930x00, 0x62, 0x74, 0x6f, 0x00, 0x73, 0x6f, 0x6d, 0x40, 0x00, 940x00, 0x04, 0x52, 0x00, 0x05, 0x97, 0x00, 0x62, 0x74, 0x6f,
940x80, 0x00, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x10, 950x00, 0x73, 0x6f, 0x6d, 0x40, 0x00, 0x80, 0x00, 0x69, 0x6e,
950x01, 0xef, 0x52, 0x69, 0x67, 0x68, 0x74, 0x2d, 0x63, 0x6c, 960x76, 0x61, 0x6c, 0x69, 0x64, 0x10, 0x01, 0xef, 0x52, 0x69,
960x69, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0xbe, 0x00, 0x02, 0x40, 970x67, 0x68, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x69,
970x00, 0x61, 0x64, 0x64, 0x97, 0x02, 0x62, 0x60, 0x68, 0x6f, 980x6e, 0x67, 0xbe, 0x00, 0x02, 0x40, 0x00, 0x61, 0x64, 0x64,
980x6c, 0x64, 0x27, 0xc0, 0x02, 0x13, 0x72, 0xd3, 0x00, 0x42, 990x97, 0x02, 0x62, 0x60, 0x68, 0x6f, 0x6c, 0x64, 0x27, 0xc0,
990x74, 0x68, 0x61, 0x74, 0x17, 0x04, 0x00, 0x1d, 0x00, 0x03, 1000x02, 0x13, 0x72, 0xd3, 0x00, 0x42, 0x74, 0x68, 0x61, 0x74,
1000x1c, 0x00, 0x60, 0x73, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0xe6, 1010x17, 0x04, 0x00, 0x1d, 0x00, 0x03, 0x1c, 0x00, 0x60, 0x73,
1010x00, 0xd0, 0x61, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 1020x00, 0x77, 0x69, 0x6c, 0x6c, 0xe6, 0x00, 0xd0, 0x61, 0x75,
1020x63, 0x61, 0x6c, 0x6c, 0x79, 0x48, 0x00, 0x04, 0x00, 0x02, 1030x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x6c,
1030x55, 0x65, 0x00, 0x6e, 0x65, 0x78, 0x60, 0x00, 0x41, 0x66, 1040x79, 0x48, 0x00, 0x04, 0x00, 0x02, 0x55, 0x65, 0x00, 0x6e,
1040x74, 0x65, 0x72, 0x3c, 0x00, 0x30, 0x69, 0x6e, 0x67, 0x95, 1050x65, 0x78, 0x60, 0x00, 0x41, 0x66, 0x74, 0x65, 0x72, 0x3c,
1050x00, 0xd3, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 1060x00, 0x30, 0x69, 0x6e, 0x67, 0x95, 0x00, 0xd3, 0x41, 0x6c,
1060x69, 0x76, 0x65, 0x6c, 0x79, 0xf7, 0x02, 0x08, 0xd6, 0x01, 1070x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x6c,
1070x11, 0x2c, 0x0e, 0x00, 0x21, 0x75, 0x70, 0x31, 0x01, 0x10, 1080x79, 0xf7, 0x02, 0x08, 0xd6, 0x01, 0x11, 0x2c, 0x0e, 0x00,
1080x64, 0x5a, 0x03, 0x60, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 1090x21, 0x75, 0x70, 0x31, 0x01, 0x10, 0x64, 0x5a, 0x03, 0x60,
1090x21, 0x00, 0x14, 0x73, 0x1a, 0x02, 0x22, 0x75, 0x73, 0x6d, 1100x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x21, 0x00, 0x14, 0x73,
1100x00, 0x20, 0x73, 0x65, 0x67, 0x02, 0x02, 0x29, 0x01, 0x03, 1110x1a, 0x02, 0x22, 0x75, 0x73, 0x6d, 0x00, 0x20, 0x73, 0x65,
1110xe8, 0x01, 0x15, 0x2c, 0xd2, 0x01, 0x01, 0x42, 0x00, 0x10, 1120x67, 0x02, 0x02, 0x29, 0x01, 0x03, 0xe8, 0x01, 0x15, 0x2c,
1120x72, 0x04, 0x01, 0x02, 0x3c, 0x00, 0x0c, 0x30, 0x00, 0x04, 1130xd2, 0x01, 0x01, 0x42, 0x00, 0x10, 0x72, 0x04, 0x01, 0x02,
1130x40, 0x01, 0x02, 0xe6, 0x02, 0x00, 0x36, 0x00, 0x90, 0x73, 1140x3c, 0x00, 0x0c, 0x30, 0x00, 0x04, 0x40, 0x01, 0x02, 0xe6,
1140x70, 0x61, 0x63, 0x65, 0x00, 0x62, 0x61, 0x72, 0x5b, 0x02, 1150x02, 0x00, 0x36, 0x00, 0x41, 0x45, 0x6e, 0x74, 0x65, 0x69,
1150x41, 0x45, 0x6e, 0x74, 0x65, 0x76, 0x00, 0x00, 0x39, 0x00, 1160x00, 0x00, 0x2c, 0x00, 0x01, 0xfe, 0x03, 0x03, 0x2b, 0x00,
1160x01, 0x0b, 0x04, 0x03, 0x38, 0x00, 0x02, 0xff, 0x04, 0x03, 1170x02, 0xf2, 0x04, 0x03, 0x3f, 0x00, 0x23, 0x65, 0x64, 0x6b,
1170x4c, 0x00, 0x23, 0x65, 0x64, 0x78, 0x00, 0x05, 0x5f, 0x01, 1180x00, 0x05, 0x52, 0x01, 0x02, 0x07, 0x05, 0x04, 0x50, 0x00,
1180x02, 0x14, 0x05, 0x04, 0x5d, 0x00, 0x50, 0x2e, 0x00, 0x60, 1190x50, 0x2e, 0x00, 0x60, 0x44, 0x27, 0x9d, 0x02, 0x60, 0x42,
1190x44, 0x27, 0x4f, 0x00, 0x42, 0x42, 0x61, 0x63, 0x6b, 0x60, 1200x61, 0x63, 0x6b, 0x73, 0x70, 0x46, 0x00, 0x02, 0xd1, 0x01,
1200x00, 0x02, 0xde, 0x01, 0x14, 0x73, 0xdf, 0x01, 0x00, 0x7d, 1210x14, 0x73, 0xd2, 0x01, 0x00, 0x70, 0x00, 0x11, 0x53, 0x19,
1210x00, 0x11, 0x53, 0x19, 0x00, 0x03, 0x8c, 0x01, 0x07, 0x6e, 1220x00, 0x03, 0x7f, 0x01, 0x07, 0x61, 0x01, 0x02, 0x64, 0x04,
1220x01, 0x00, 0x31, 0x01, 0x50, 0x50, 0x72, 0x65, 0x73, 0x73, 1230x05, 0xad, 0x04, 0x05, 0xf6, 0x00, 0x04, 0x5d, 0x02, 0x04,
1230xc0, 0x01, 0x21, 0x60, 0x68, 0x49, 0x00, 0x32, 0x60, 0x3f, 1240xfb, 0x00, 0x61, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0xaa,
1240x27, 0x84, 0x01, 0x10, 0x66, 0x05, 0x00, 0x0e, 0xd2, 0x01, 1250x01, 0x53, 0x3a, 0x00, 0x60, 0x31, 0x27, 0x11, 0x00, 0x12,
1250x01, 0x52, 0x01, 0x80, 0x61, 0x00, 0x73, 0x75, 0x67, 0x67, 1260x73, 0xdd, 0x02, 0x75, 0x6f, 0x70, 0x2d, 0x6d, 0x6f, 0x73,
1260x65, 0x73, 0xa0, 0x00, 0x01, 0x17, 0x00, 0x31, 0x2e, 0x00, 1270x74, 0x14, 0x01, 0x33, 0x60, 0x32, 0x27, 0xc2, 0x00, 0x82,
1270x55, 0x45, 0x00, 0x01, 0x9f, 0x03, 0xf0, 0x01, 0x69, 0x73, 1280x63, 0x6f, 0x6e, 0x64, 0x00, 0x6f, 0x6e, 0x65, 0x86, 0x00,
1290x90, 0x73, 0x6f, 0x00, 0x66, 0x6f, 0x72, 0x74, 0x68, 0x2e,
1300x74, 0x00, 0x22, 0x73, 0x65, 0x66, 0x00, 0x01, 0x7d, 0x02,
1310x00, 0x2e, 0x00, 0x01, 0x56, 0x01, 0x02, 0x7e, 0x01, 0x03,
1320xda, 0x01, 0x01, 0x4f, 0x01, 0x70, 0x2e, 0x00, 0x50, 0x72,
1330x65, 0x73, 0x73, 0x54, 0x02, 0x32, 0x60, 0x4c, 0x27, 0x11,
1340x02, 0x54, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x35, 0x00, 0x15,
1350x73, 0xd7, 0x01, 0x23, 0x69, 0x72, 0xc9, 0x00, 0x01, 0x35,
1360x04, 0x06, 0x37, 0x00, 0x11, 0x68, 0x21, 0x01, 0x23, 0x60,
1370x3f, 0x3e, 0x00, 0x10, 0x66, 0x05, 0x00, 0x0e, 0x9d, 0x02,
1380x01, 0x46, 0x00, 0x80, 0x61, 0x00, 0x73, 0x75, 0x67, 0x67,
1390x65, 0x73, 0x78, 0x01, 0x01, 0x17, 0x00, 0x31, 0x2e, 0x00,
1400x55, 0x45, 0x00, 0x01, 0x6a, 0x04, 0xf0, 0x01, 0x69, 0x73,
1280x00, 0x6e, 0x6f, 0x74, 0x00, 0x72, 0x65, 0x63, 0x6f, 0x6d, 1410x00, 0x6e, 0x6f, 0x74, 0x00, 0x72, 0x65, 0x63, 0x6f, 0x6d,
1290x6d, 0x65, 0x6e, 0x64, 0xac, 0x02, 0x20, 0x6f, 0x72, 0x5f, 1420x6d, 0x65, 0x6e, 0x64, 0x77, 0x03, 0x20, 0x6f, 0x72, 0x2a,
1300x04, 0x72, 0x6f, 0x72, 0x00, 0x6d, 0x6f, 0x72, 0x65, 0x01, 1430x05, 0x63, 0x6f, 0x72, 0x00, 0x6d, 0x6f, 0x72, 0x90, 0x00,
1310x02, 0x20, 0x61, 0x73, 0x77, 0x02, 0x71, 0x69, 0x73, 0x00, 1440x20, 0x61, 0x73, 0x42, 0x03, 0x71, 0x69, 0x73, 0x00, 0x73,
1320x73, 0x6c, 0x6f, 0x77, 0x61, 0x03, 0x22, 0x68, 0x65, 0xe5, 1450x6c, 0x6f, 0x77, 0x2c, 0x04, 0x22, 0x68, 0x65, 0xbd, 0x01,
1330x00, 0x02, 0x6a, 0x00, 0x21, 0x69, 0x73, 0xf4, 0x05, 0x52, 1460x02, 0x6a, 0x00, 0x21, 0x69, 0x73, 0xbf, 0x06, 0x52, 0x6c,
1340x6c, 0x65, 0x74, 0x65, 0x2c, 0x13, 0x01, 0xf2, 0x00, 0x6d, 1470x65, 0x74, 0x65, 0x2c, 0x29, 0x01, 0xf4, 0x00, 0x6d, 0x61,
1350x61, 0x6c, 0x6c, 0x65, 0x72, 0x00, 0x66, 0x65, 0x65, 0x64, 1480x6c, 0x6c, 0x65, 0x72, 0x00, 0x66, 0x65, 0x65, 0x64, 0x62,
1360x62, 0x61, 0x63, 0x6b, 0x47, 0x00, 0x04, 0x31, 0x02, 0x50, 1490x61, 0x63, 0x6b, 0xd7, 0x00, 0x02, 0xfc, 0x02, 0x50, 0x68,
1370x68, 0x69, 0x67, 0x68, 0x6c, 0x8f, 0x01, 0x45, 0x65, 0x64, 1500x69, 0x67, 0x68, 0x6c, 0x0b, 0x01, 0x45, 0x65, 0x64, 0x3b,
1380x3b, 0x00, 0x96, 0x02, 0x02, 0x83, 0x03, 0x41, 0x73, 0x65, 1510x00, 0x61, 0x03, 0x02, 0x4e, 0x04, 0x41, 0x73, 0x65, 0x00,
1390x00, 0x28, 0x7c, 0x00, 0x12, 0x76, 0xa5, 0x00, 0x01, 0x82, 1520x28, 0x7c, 0x00, 0x12, 0x76, 0xa5, 0x00, 0x0f, 0x47, 0x01,
1400x00, 0x04, 0xfa, 0x01, 0x02, 0x56, 0x02, 0x16, 0x6d, 0x2c, 1530x00, 0x16, 0x6d, 0xf7, 0x02, 0x52, 0x61, 0x72, 0x72, 0x6f,
1410x02, 0x52, 0x61, 0x72, 0x72, 0x6f, 0x77, 0xd5, 0x01, 0x01, 1540x77, 0xe6, 0x01, 0x01, 0x22, 0x04, 0x04, 0x22, 0x01, 0x01,
1420x57, 0x03, 0x04, 0x22, 0x01, 0x0f, 0xc4, 0x01, 0x07, 0x12, 1550x84, 0x00, 0x01, 0x23, 0x02, 0x30, 0x62, 0x61, 0x72, 0xcc,
1430x29, 0x86, 0x00, 0x00, 0x56, 0x01, 0x0e, 0x33, 0x01, 0x12, 1560x00, 0x05, 0x9c, 0x02, 0x12, 0x29, 0x86, 0x00, 0x00, 0x2e,
1440x2c, 0x89, 0x03, 0x73, 0x61, 0x6e, 0x79, 0x00, 0x68, 0x65, 1570x02, 0x0e, 0x33, 0x01, 0x12, 0x2c, 0x54, 0x04, 0x73, 0x61,
1450x6c, 0x0a, 0x06, 0x0d, 0xcb, 0x02, 0x02, 0xaa, 0x01, 0x01, 1580x6e, 0x79, 0x00, 0x68, 0x65, 0x6c, 0xd5, 0x06, 0x0d, 0x96,
1460x99, 0x03, 0x00, 0x19, 0x00, 0x19, 0x60, 0x43, 0x00, 0x17, 1590x03, 0x02, 0xfc, 0x01, 0x05, 0xe7, 0x01, 0x19, 0x60, 0x43,
1470x27, 0xb1, 0x01, 0x66, 0x49, 0x66, 0x00, 0x79, 0x6f, 0x75, 1600x00, 0x17, 0x27, 0x89, 0x02, 0x66, 0x49, 0x66, 0x00, 0x79,
1480x64, 0x06, 0x06, 0xa9, 0x03, 0x13, 0x61, 0xb1, 0x01, 0x03, 1610x6f, 0x75, 0x2f, 0x07, 0x06, 0x74, 0x04, 0x27, 0x61, 0x6c,
1490x5f, 0x03, 0x61, 0x65, 0x00, 0x73, 0x6f, 0x6c, 0x75, 0x1a, 1620xee, 0x01, 0x01, 0xad, 0x00, 0x31, 0x6f, 0x6c, 0x75, 0x1a,
1500x00, 0x04, 0x24, 0x01, 0x33, 0x64, 0x69, 0x73, 0xf6, 0x04, 1630x00, 0x04, 0x24, 0x01, 0x33, 0x64, 0x69, 0x73, 0xc1, 0x05,
1510x82, 0x62, 0x65, 0x6c, 0x6f, 0x77, 0x3b, 0x00, 0x69, 0x4d, 1640x82, 0x62, 0x65, 0x6c, 0x6f, 0x77, 0x3b, 0x00, 0x69, 0x4d,
1520x00, 0x77, 0x72, 0x75, 0x6e, 0x00, 0x6f, 0x75, 0x74, 0x85, 1650x00, 0x77, 0x72, 0x75, 0x6e, 0x00, 0x6f, 0x75, 0x74, 0x50,
1530x05, 0x01, 0x30, 0x01, 0x03, 0xd0, 0x02, 0xbe, 0x60, 0x53, 1660x06, 0x01, 0x30, 0x01, 0x03, 0x9b, 0x03, 0xbe, 0x60, 0x53,
1540x6f, 0x6c, 0x76, 0x65, 0x2e, 0x2e, 0x2e, 0x27, 0x29, 0x57, 1670x6f, 0x6c, 0x76, 0x65, 0x2e, 0x2e, 0x2e, 0x27, 0x29, 0x57,
1550x00, 0x05, 0x97, 0x04, 0x71, 0x72, 0x65, 0x76, 0x65, 0x61, 1680x00, 0x05, 0x05, 0x03, 0x71, 0x72, 0x65, 0x76, 0x65, 0x61,
1560x6c, 0x65, 0x1b, 0x04, 0x23, 0x28, 0x41, 0x8b, 0x00, 0x11, 1690x6c, 0x65, 0xe6, 0x04, 0x23, 0x28, 0x41, 0x8b, 0x00, 0x11,
1570x61, 0xa6, 0x05, 0xb0, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 1700x61, 0x71, 0x06, 0xb0, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63,
1580x72, 0x69, 0x62, 0x65, 0x64, 0xc8, 0x02, 0x13, 0x73, 0xbc, 1710x72, 0x69, 0x62, 0x65, 0x64, 0xa0, 0x03, 0x13, 0x73, 0x87,
1590x05, 0x72, 0x32, 0x2e, 0x31, 0x00, 0x61, 0x72, 0x65, 0x42, 1720x06, 0x63, 0x32, 0x2e, 0x31, 0x00, 0x61, 0x72, 0xe1, 0x02,
1600x00, 0xb2, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 1730xb2, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65,
1610x65, 0x2e, 0x29, 0xc4, 0x05, 0x13, 0x32, 0xc4, 0x05, 0x50, 1740x2e, 0x29, 0x8f, 0x06, 0x13, 0x32, 0x8f, 0x06, 0x50, 0x70,
1620x70, 0x61, 0x72, 0x61, 0x6d, 0x27, 0x08, 0x03, 0xc6, 0x05, 1750x61, 0x72, 0x61, 0x6d, 0xf2, 0x08, 0x03, 0x91, 0x06, 0x00,
1630x00, 0xcd, 0x01, 0x06, 0x14, 0x00, 0x02, 0x41, 0x00, 0x04, 1760xcd, 0x01, 0x06, 0x14, 0x00, 0x02, 0x41, 0x00, 0x04, 0x3c,
1640x3c, 0x00, 0x06, 0x80, 0x05, 0x21, 0x60, 0x43, 0xa4, 0x06, 1770x00, 0x06, 0x4b, 0x06, 0x21, 0x60, 0x43, 0x6f, 0x07, 0x00,
1650x00, 0xb5, 0x00, 0x31, 0x00, 0x6f, 0x70, 0x6f, 0x00, 0x03, 1780xb5, 0x00, 0x31, 0x00, 0x6f, 0x70, 0x6f, 0x00, 0x03, 0x59,
1660x8e, 0x05, 0xc0, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 1790x06, 0xc1, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d,
1670x6d, 0x65, 0x6e, 0x75, 0x2e, 0x4f, 0x00, 0x82, 0x00, 0x64, 1800x65, 0x6e, 0x75, 0x2e, 0xd6, 0x03, 0x72, 0x64, 0x65, 0x66,
1680x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x1c, 0x06, 0x62, 0x6d, 1810x61, 0x75, 0x6c, 0x74, 0xe7, 0x06, 0x62, 0x6d, 0x61, 0x74,
1690x61, 0x74, 0x63, 0x68, 0x65, 0x3f, 0x01, 0x07, 0x66, 0x00, 1820x63, 0x68, 0x65, 0x3f, 0x01, 0x07, 0x66, 0x00, 0x13, 0x66,
1700x13, 0x66, 0x0d, 0x06, 0x0f, 0x60, 0x07, 0x04, 0x00, 0xf4, 1830xd8, 0x06, 0x0f, 0x2b, 0x08, 0x04, 0x00, 0xf4, 0x00, 0x13,
1710x00, 0x13, 0x43, 0xf8, 0x06, 0x3d, 0x00, 0x00, 0x4e, 0x0c, 1840x43, 0xc3, 0x07, 0x3d, 0x00, 0x00, 0x4e, 0xd7, 0x07, 0x09,
1720x07, 0x09, 0x36, 0x01, 0x24, 0x69, 0x73, 0xc6, 0x03, 0x00, 1850x36, 0x01, 0x24, 0x69, 0x73, 0x9e, 0x04, 0x00, 0xae, 0x00,
1730xae, 0x00, 0x12, 0x3b, 0xb4, 0x00, 0x12, 0x32, 0x2c, 0x07, 1860x12, 0x3b, 0xb4, 0x00, 0x12, 0x32, 0xf7, 0x07, 0x21, 0x00,
1740x21, 0x00, 0x28, 0x20, 0x03, 0xa1, 0x69, 0x73, 0x00, 0x68, 1870x28, 0x20, 0x03, 0xa1, 0x69, 0x73, 0x00, 0x68, 0x61, 0x72,
1750x61, 0x72, 0x64, 0x65, 0x72, 0x29, 0xa3, 0x03, 0x82, 0x65, 1880x64, 0x65, 0x72, 0x29, 0xa3, 0x03, 0x82, 0x65, 0x67, 0x73,
1760x67, 0x73, 0x20, 0x70, 0x65, 0x72, 0x20, 0x18, 0x03, 0x08, 1890x20, 0x70, 0x65, 0x72, 0x20, 0x18, 0x03, 0x08, 0x61, 0x00,
1770x61, 0x00, 0x05, 0x4f, 0x07, 0x02, 0x1b, 0x00, 0x0e, 0x3e, 1900x05, 0x1a, 0x08, 0x02, 0x1b, 0x00, 0x0e, 0x3e, 0x00, 0x03,
1780x00, 0x03, 0x4b, 0x07, 0x1a, 0x65, 0x37, 0x00, 0x04, 0xe5, 1910x16, 0x08, 0x1a, 0x65, 0x37, 0x00, 0x04, 0xe5, 0x01, 0x00,
1790x01, 0x00, 0xfc, 0x01, 0x04, 0x9a, 0x09, 0x4b, 0x66, 0x69, 1920xfc, 0x01, 0x04, 0x65, 0x0a, 0x4b, 0x66, 0x69, 0x6e, 0x64,
1800x6e, 0x64, 0xa9, 0x00, 0x8b, 0x6e, 0x00, 0x28, 0x66, 0x65, 1930xa9, 0x00, 0x8b, 0x6e, 0x00, 0x28, 0x66, 0x65, 0x77, 0x65,
1810x77, 0x65, 0x72, 0x52, 0x00, 0x10, 0x41, 0x06, 0x08, 0x74, 1940x72, 0x52, 0x00, 0x10, 0x41, 0xd1, 0x08, 0x74, 0x20, 0x62,
1820x20, 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x73, 0x0f, 0x00, 0x21, 1950x6c, 0x61, 0x6e, 0x6b, 0x73, 0x0f, 0x00, 0x21, 0x73, 0x00,
1830x73, 0x00, 0x10, 0x00, 0x05, 0xdd, 0x02, 0x80, 0x62, 0x65, 1960x10, 0x00, 0x05, 0xdd, 0x02, 0x80, 0x62, 0x65, 0x00, 0x67,
1840x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0xe6, 0x03, 0x31, 0x70, 1970x69, 0x76, 0x65, 0x6e, 0xe6, 0x03, 0x31, 0x70, 0x61, 0x72,
1850x61, 0x72, 0x5b, 0x02, 0x15, 0x61, 0xa6, 0x00, 0x31, 0x61, 1980x5b, 0x02, 0x15, 0x61, 0xa6, 0x00, 0x31, 0x61, 0x6b, 0x65,
1860x6b, 0x65, 0xfd, 0x03, 0x40, 0x65, 0x61, 0x73, 0x69, 0x65, 1990xfd, 0x03, 0x40, 0x65, 0x61, 0x73, 0x69, 0x30, 0x09, 0x71,
1870x08, 0x71, 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x90, 2000x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x90, 0x00, 0x00,
1880x00, 0x00, 0xf0, 0x08, 0x02, 0x1d, 0x06, 0x10, 0x74, 0x26, 2010xbb, 0x09, 0x02, 0xe8, 0x06, 0x10, 0x74, 0x26, 0x01, 0x02,
1890x01, 0x02, 0x65, 0x02, 0x10, 0x6e, 0x8d, 0x08, 0x20, 0x00, 2020x65, 0x02, 0x10, 0x6e, 0x58, 0x09, 0x20, 0x00, 0x62, 0x58,
1900x62, 0x8d, 0x09, 0x20, 0x75, 0x6e, 0x76, 0x04, 0x07, 0x57, 2030x0a, 0x20, 0x75, 0x6e, 0x76, 0x04, 0x07, 0x57, 0x00, 0x08,
1910x00, 0x08, 0xb4, 0x00, 0x10, 0x29, 0xd3, 0x01, 0x02, 0x83, 2040xb4, 0x00, 0x10, 0x29, 0xd3, 0x01, 0x02, 0x83, 0x04, 0x30,
1920x04, 0x30, 0x74, 0x75, 0x72, 0x57, 0x0a, 0x00, 0xd7, 0x06, 2050x74, 0x75, 0x72, 0x22, 0x0b, 0x00, 0xa2, 0x07, 0x24, 0x62,
1930x24, 0x62, 0x79, 0xe5, 0x01, 0x10, 0x2e, 0x07, 0x01, 0x34, 2060x79, 0xe5, 0x01, 0x10, 0x2e, 0x07, 0x01, 0x34, 0x6f, 0x74,
1940x6f, 0x74, 0x65, 0x61, 0x00, 0xa2, 0x69, 0x73, 0x00, 0x64, 2070x65, 0x61, 0x00, 0xa2, 0x69, 0x73, 0x00, 0x64, 0x6f, 0x65,
1950x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0xdc, 0x08, 0x08, 0xc6, 2080x73, 0x6e, 0x27, 0x74, 0xa7, 0x09, 0x08, 0xc6, 0x00, 0x29,
1960x00, 0x29, 0x69, 0x6e, 0x5b, 0x00, 0x06, 0x2d, 0x03, 0x11, 2090x69, 0x6e, 0x5b, 0x00, 0x06, 0x2d, 0x03, 0x11, 0x65, 0x5e,
1970x65, 0x93, 0x06, 0x21, 0x77, 0x61, 0x89, 0x00, 0x00, 0x49, 2100x07, 0x21, 0x77, 0x61, 0x89, 0x00, 0x00, 0x49, 0x00, 0x10,
1980x00, 0x20, 0x2c, 0x00, 0xbd, 0x00, 0x84, 0x6f, 0x6e, 0x65, 2110x2c, 0x02, 0x06, 0x00, 0xc1, 0x05, 0x54, 0x00, 0x65, 0x78,
1990x00, 0x65, 0x78, 0x74, 0x72, 0x13, 0x08, 0x06, 0x2b, 0x01, 2120x74, 0x72, 0xde, 0x08, 0x06, 0x2b, 0x01, 0x97, 0x64, 0x75,
2000x97, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 2130x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x2f, 0x01, 0x09,
2010x2f, 0x01, 0x09, 0x6a, 0x01, 0x14, 0x28, 0x23, 0x06, 0x03, 2140x6a, 0x01, 0x14, 0x28, 0xee, 0x06, 0x03, 0x99, 0x01, 0x12,
2020x99, 0x01, 0x12, 0x29, 0xbf, 0x07, 0x11, 0x6e, 0xde, 0x0a, 2150x29, 0x8a, 0x08, 0x11, 0x6e, 0xa9, 0x0b, 0x04, 0x45, 0x02,
2030x04, 0x45, 0x02, 0x01, 0xdc, 0x01, 0x30, 0x74, 0x68, 0x61, 2160x01, 0xdc, 0x01, 0x30, 0x74, 0x68, 0x61, 0xca, 0x02, 0x33,
2040xca, 0x02, 0x33, 0x63, 0x65, 0x3b, 0x6c, 0x05, 0x51, 0x6e, 2170x63, 0x65, 0x3b, 0x6c, 0x05, 0x51, 0x6e, 0x63, 0x72, 0x65,
2050x63, 0x72, 0x65, 0x61, 0xf1, 0x07, 0x01, 0x35, 0x06, 0x43, 2180x61, 0xbc, 0x08, 0x01, 0x4b, 0x06, 0x43, 0x61, 0x72, 0x63,
2060x61, 0x72, 0x63, 0x68, 0xa5, 0x04, 0x00, 0x67, 0x01, 0x03, 2190x68, 0xa5, 0x04, 0x00, 0x67, 0x01, 0x03, 0x94, 0x05, 0x25,
2070x94, 0x05, 0x25, 0x6e, 0x67, 0xc1, 0x01, 0x02, 0x68, 0x04, 2200x6e, 0x67, 0xc1, 0x01, 0x02, 0x68, 0x04, 0x07, 0x20, 0x01,
2080x07, 0x20, 0x01, 0x14, 0x6e, 0x1f, 0x01, 0x50, 0x75, 0x6c, 2210x1b, 0x6e, 0x1f, 0x01, 0x43, 0x31, 0x35, 0x2e, 0x33, 0x7b,
2090x74, 0x2e, 0x00, 2220x03, 0xb0, 0x75, 0x73, 0x65, 0x72, 0x20, 0x70, 0x72, 0x65,
2230x66, 0x65, 0x72, 0x65, 0x0c, 0x01, 0x81, 0x03, 0x20, 0x4f,
2240x6e, 0x86, 0x07, 0x53, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x8f,
2250x08, 0x80, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x00,
2260x2e, 0x00, 0x17, 0x00, 0x2e, 0x00, 0x12, 0x2c, 0x6f, 0x03,
2270x16, 0x50, 0x12, 0x00, 0x0d, 0x8b, 0x03, 0x33, 0x47, 0x61,
2280x6d, 0x8b, 0x03, 0x03, 0xb2, 0x06, 0x23, 0x65, 0x74, 0xdd,
2290x04, 0xb1, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x00,
2300x77, 0x68, 0x65, 0x65, 0x0a, 0x02, 0x32, 0x06, 0x22, 0x72,
2310x65, 0xd5, 0x06, 0x3f, 0x6c, 0x65, 0x64, 0xcf, 0x06, 0x02,
2320x53, 0x55, 0x6e, 0x6c, 0x69, 0x6b, 0x41, 0x05, 0x20, 0x4c,
2330x27, 0x9a, 0x05, 0x03, 0x8c, 0x0b, 0x01, 0x5e, 0x00, 0x10,
2340x70, 0x91, 0x0b, 0xf0, 0x03, 0x73, 0x74, 0x00, 0x62, 0x65,
2350x74, 0x77, 0x65, 0x65, 0x6e, 0x00, 0x67, 0x61, 0x6d, 0x65,
2360x73, 0x2e, 0x00,
210}; 237};
211 238
212const unsigned short help_text_len = 3042; 239const unsigned short help_text_len = 3506;
213const unsigned short help_text_words = 572; 240const unsigned short help_text_words = 650;
214const char quick_help_text[] = "Guess the hidden combination of colours."; 241const char quick_help_text[] = "Guess the hidden combination of colours.";
diff --git a/apps/plugins/puzzles/help/inertia.c b/apps/plugins/puzzles/help/inertia.c
index 956d133d44..ba8d71d0a5 100644
--- a/apps/plugins/puzzles/help/inertia.c
+++ b/apps/plugins/puzzles/help/inertia.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,176 +6,177 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 39, TEXT_UNDERLINE }, 9 { 40, TEXT_UNDERLINE },
10 { 110, TEXT_UNDERLINE }, 10 { 111, TEXT_UNDERLINE },
11 { 196, TEXT_CENTER | C_RED }, 11 { 197, TEXT_CENTER | C_RED },
12 { 404, TEXT_CENTER | C_RED }, 12 { 405, TEXT_CENTER | C_RED },
13 { 421, TEXT_UNDERLINE },
14 { 422, TEXT_UNDERLINE }, 13 { 422, TEXT_UNDERLINE },
14 { 423, TEXT_UNDERLINE },
15 LAST_STYLE_ITEM 15 LAST_STYLE_ITEM
16}; 16};
17 17
18/* orig 2266 comp 1565 ratio 0.690644 level 10 saved 701 */ 18/* orig 2286 comp 1571 ratio 0.687227 level 10 saved 715 */
19const char help_text[] = { 19const char help_text[] = {
200xf0, 0x1f, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 200xfe, 0x07, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
210x32, 0x34, 0x3a, 0x20, 0x49, 0x6e, 0x65, 0x72, 0x74, 0x69, 210x32, 0x34, 0x3a, 0x20, 0x49, 0x6e, 0x65, 0x72, 0x74, 0x69,
220x61, 0x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x61, 220x61, 0x20, 0x00, 0x2d, 0x01, 0x00, 0xf0, 0x0b, 0x00, 0x00,
230x72, 0x65, 0x00, 0x61, 0x00, 0x73, 0x6d, 0x61, 0x6c, 0x6c, 230x00, 0x59, 0x6f, 0x75, 0x00, 0x61, 0x72, 0x65, 0x00, 0x61,
240x00, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x00, 0x62, 0x0b, 0x00, 240x00, 0x73, 0x6d, 0x61, 0x6c, 0x6c, 0x00, 0x67, 0x72, 0x65,
250xf0, 0x15, 0x73, 0x69, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x00, 250x65, 0x6e, 0x00, 0x62, 0x0b, 0x00, 0xf0, 0x15, 0x73, 0x69,
260x69, 0x6e, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 260x74, 0x74, 0x69, 0x6e, 0x67, 0x00, 0x69, 0x6e, 0x00, 0x61,
270x66, 0x75, 0x6c, 0x6c, 0x00, 0x6f, 0x66, 0x00, 0x6f, 0x62, 270x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x66, 0x75, 0x6c, 0x6c,
280x73, 0x74, 0x61, 0x63, 0x6c, 0x65, 0x73, 0x2e, 0x40, 0x00, 280x00, 0x6f, 0x66, 0x00, 0x6f, 0x62, 0x73, 0x74, 0x61, 0x63,
290xf0, 0x05, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 0x69, 0x73, 290x6c, 0x65, 0x73, 0x2e, 0x40, 0x00, 0xf0, 0x05, 0x72, 0x00,
300x00, 0x74, 0x6f, 0x00, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 300x61, 0x69, 0x6d, 0x00, 0x69, 0x73, 0x00, 0x74, 0x6f, 0x00,
310x74, 0x00, 0x40, 0x00, 0xf2, 0x06, 0x74, 0x68, 0x65, 0x00, 310x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x00, 0x40, 0x00,
320x67, 0x65, 0x6d, 0x73, 0x00, 0x77, 0x69, 0x74, 0x68, 0x6f, 320xf2, 0x06, 0x74, 0x68, 0x65, 0x00, 0x67, 0x65, 0x6d, 0x73,
330x75, 0x74, 0x00, 0x72, 0x75, 0x6e, 0x6e, 0x51, 0x00, 0xa0, 330x00, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x00, 0x72,
340x74, 0x6f, 0x00, 0x61, 0x6e, 0x79, 0x00, 0x6d, 0x69, 0x6e, 340x75, 0x6e, 0x6e, 0x51, 0x00, 0xa0, 0x74, 0x6f, 0x00, 0x61,
350x44, 0x00, 0x02, 0x86, 0x00, 0x81, 0x63, 0x61, 0x6e, 0x00, 350x6e, 0x79, 0x00, 0x6d, 0x69, 0x6e, 0x44, 0x00, 0x02, 0x86,
360x6d, 0x6f, 0x76, 0x65, 0x38, 0x00, 0x01, 0x81, 0x00, 0x21, 360x00, 0x81, 0x63, 0x61, 0x6e, 0x00, 0x6d, 0x6f, 0x76, 0x65,
370x69, 0x6e, 0x26, 0x00, 0xf2, 0x02, 0x6f, 0x72, 0x74, 0x68, 370x38, 0x00, 0x01, 0x81, 0x00, 0x21, 0x69, 0x6e, 0x26, 0x00,
380x6f, 0x67, 0x6f, 0x6e, 0x61, 0x6c, 0x00, 0x6f, 0x72, 0x20, 380xf2, 0x02, 0x6f, 0x72, 0x74, 0x68, 0x6f, 0x67, 0x6f, 0x6e,
390x64, 0x69, 0x61, 0x0c, 0x00, 0xe7, 0x64, 0x69, 0x72, 0x65, 390x61, 0x6c, 0x00, 0x6f, 0x72, 0x20, 0x64, 0x69, 0x61, 0x0c,
400x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x00, 0x4f, 0x6e, 0x63, 400x00, 0xe7, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f,
410x37, 0x00, 0x60, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x4c, 410x6e, 0x2e, 0x00, 0x4f, 0x6e, 0x63, 0x37, 0x00, 0x60, 0x73,
420x00, 0xf0, 0x13, 0x69, 0x6e, 0x67, 0x2c, 0x00, 0x69, 0x74, 420x74, 0x61, 0x72, 0x74, 0x73, 0x4c, 0x00, 0xf0, 0x13, 0x69,
430x00, 0x77, 0x69, 0x6c, 0x6c, 0x00, 0x63, 0x6f, 0x6e, 0x74, 430x6e, 0x67, 0x2c, 0x00, 0x69, 0x74, 0x00, 0x77, 0x69, 0x6c,
440x69, 0x6e, 0x75, 0x65, 0x00, 0x75, 0x6e, 0x74, 0x69, 0x6c, 440x6c, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65,
450x00, 0x73, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x8f, 0x00, 0xf4, 450x00, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x00, 0x73, 0x6f, 0x6d,
460x00, 0x73, 0x74, 0x6f, 0x70, 0x73, 0x00, 0x69, 0x74, 0x2e, 460x65, 0x74, 0x68, 0x8f, 0x00, 0xf4, 0x00, 0x73, 0x74, 0x6f,
470x00, 0x41, 0x00, 0x77, 0x61, 0x6c, 0x5a, 0x00, 0x20, 0x6c, 470x70, 0x73, 0x00, 0x69, 0x74, 0x2e, 0x00, 0x41, 0x00, 0x77,
480x79, 0x81, 0x00, 0x82, 0x69, 0x74, 0x73, 0x00, 0x70, 0x61, 480x61, 0x6c, 0x5a, 0x00, 0x20, 0x6c, 0x79, 0x81, 0x00, 0x82,
490x74, 0x68, 0x44, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x51, 0x00, 490x69, 0x74, 0x73, 0x00, 0x70, 0x61, 0x74, 0x68, 0x44, 0x00,
500x70, 0x28, 0x62, 0x75, 0x74, 0x00, 0x69, 0x66, 0x0b, 0x00, 500x00, 0x2b, 0x00, 0x00, 0x51, 0x00, 0x70, 0x28, 0x62, 0x75,
510x14, 0x69, 0x6a, 0x00, 0x14, 0x00, 0x9a, 0x00, 0x26, 0x6c, 510x74, 0x00, 0x69, 0x66, 0x0b, 0x00, 0x14, 0x69, 0x6a, 0x00,
520x79, 0x75, 0x00, 0x03, 0xd1, 0x00, 0x85, 0x72, 0x6f, 0x75, 520x14, 0x00, 0x9a, 0x00, 0x26, 0x6c, 0x79, 0x75, 0x00, 0x03,
530x67, 0x68, 0x00, 0x61, 0x00, 0xbd, 0x00, 0x80, 0x67, 0x61, 530xd1, 0x00, 0x85, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x00, 0x61,
540x70, 0x00, 0x62, 0x65, 0x74, 0x77, 0x6d, 0x01, 0x91, 0x74, 540x00, 0xbd, 0x00, 0x80, 0x67, 0x61, 0x70, 0x00, 0x62, 0x65,
550x77, 0x6f, 0x00, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x7e, 0x00, 550x74, 0x77, 0x6d, 0x01, 0x91, 0x74, 0x77, 0x6f, 0x00, 0x6f,
560x06, 0x2f, 0x01, 0x00, 0x6d, 0x00, 0xc1, 0x70, 0x69, 0x6e, 560x74, 0x68, 0x65, 0x72, 0x7e, 0x00, 0x06, 0x2f, 0x01, 0x00,
570x67, 0x29, 0x2e, 0x00, 0x41, 0x6c, 0x73, 0x6f, 0x2c, 0xb3, 570x6d, 0x00, 0xc1, 0x70, 0x69, 0x6e, 0x67, 0x29, 0x2e, 0x00,
580x00, 0x00, 0x7f, 0x01, 0x00, 0xea, 0x00, 0x71, 0x73, 0x71, 580x41, 0x6c, 0x73, 0x6f, 0x2c, 0xb3, 0x00, 0x00, 0x7f, 0x01,
590x75, 0x61, 0x72, 0x65, 0x73, 0xbc, 0x01, 0x11, 0x60, 0xc2, 590x00, 0xea, 0x00, 0x71, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65,
600x00, 0x76, 0x27, 0x3b, 0x00, 0x77, 0x68, 0x65, 0x6e, 0x08, 600x73, 0xbc, 0x01, 0x11, 0x60, 0xc2, 0x00, 0x76, 0x27, 0x3b,
610x01, 0x00, 0x7c, 0x00, 0x50, 0x73, 0x00, 0x6f, 0x6e, 0x00, 610x00, 0x77, 0x68, 0x65, 0x6e, 0x08, 0x01, 0x00, 0x7c, 0x00,
620x6e, 0x01, 0x01, 0x4e, 0x00, 0x06, 0x98, 0x00, 0x01, 0xc9, 620x50, 0x73, 0x00, 0x6f, 0x6e, 0x00, 0x6e, 0x01, 0x01, 0x4e,
630x00, 0x03, 0xb8, 0x00, 0x70, 0x6e, 0x6f, 0x00, 0x6d, 0x61, 630x00, 0x06, 0x98, 0x00, 0x01, 0xc9, 0x00, 0x03, 0xb8, 0x00,
640x74, 0x74, 0x80, 0x00, 0x36, 0x68, 0x61, 0x74, 0x58, 0x01, 640x70, 0x6e, 0x6f, 0x00, 0x6d, 0x61, 0x74, 0x74, 0x80, 0x00,
650x01, 0x2d, 0x00, 0x52, 0x61, 0x73, 0x00, 0x67, 0x6f, 0xb5, 650x36, 0x68, 0x61, 0x74, 0x58, 0x01, 0x01, 0x2d, 0x00, 0x52,
660x01, 0x30, 0x2e, 0x00, 0x47, 0xce, 0x01, 0x52, 0x64, 0x6f, 660x61, 0x73, 0x00, 0x67, 0x6f, 0xb5, 0x01, 0x30, 0x2e, 0x00,
670x00, 0x6e, 0x6f, 0x9e, 0x00, 0x05, 0x6c, 0x00, 0x10, 0x3b, 670x47, 0xce, 0x01, 0x52, 0x64, 0x6f, 0x00, 0x6e, 0x6f, 0x9e,
680x2c, 0x00, 0x50, 0x70, 0x69, 0x63, 0x6b, 0x73, 0x13, 0x00, 680x00, 0x05, 0x6c, 0x00, 0x10, 0x3b, 0x2c, 0x00, 0x50, 0x70,
690xd1, 0x6d, 0x00, 0x75, 0x70, 0x00, 0x61, 0x6e, 0x64, 0x00, 690x69, 0x63, 0x6b, 0x73, 0x13, 0x00, 0xd1, 0x6d, 0x00, 0x75,
700x6b, 0x65, 0x65, 0x70, 0x82, 0x00, 0x01, 0x43, 0x00, 0x00, 700x70, 0x00, 0x61, 0x6e, 0x64, 0x00, 0x6b, 0x65, 0x65, 0x70,
710xe9, 0x01, 0x19, 0x52, 0x03, 0x02, 0x01, 0x01, 0x02, 0x00, 710x82, 0x00, 0x01, 0x43, 0x00, 0x00, 0xe9, 0x01, 0x19, 0x52,
720x42, 0x01, 0xb0, 0x66, 0x61, 0x74, 0x61, 0x6c, 0x2e, 0x00, 720x03, 0x02, 0x01, 0x01, 0x02, 0x00, 0x42, 0x01, 0xb0, 0x66,
730x45, 0x76, 0x65, 0x6e, 0x57, 0x01, 0x31, 0x79, 0x6f, 0x75, 730x61, 0x74, 0x61, 0x6c, 0x2e, 0x00, 0x45, 0x76, 0x65, 0x6e,
740x4e, 0x00, 0x42, 0x65, 0x64, 0x00, 0x75, 0x65, 0x00, 0x40, 740x57, 0x01, 0x31, 0x79, 0x6f, 0x75, 0x4e, 0x00, 0x42, 0x65,
750x6c, 0x61, 0x73, 0x74, 0x4d, 0x02, 0x00, 0x93, 0x01, 0x01, 750x64, 0x00, 0x75, 0x65, 0x00, 0x40, 0x6c, 0x61, 0x73, 0x74,
760xff, 0x00, 0x32, 0x61, 0x6d, 0x65, 0x5d, 0x01, 0x70, 0x77, 760x4d, 0x02, 0x00, 0x93, 0x01, 0x01, 0xff, 0x00, 0x32, 0x61,
770x68, 0x69, 0x63, 0x68, 0x00, 0x74, 0xfa, 0x00, 0x33, 0x68, 770x6d, 0x65, 0x5d, 0x01, 0x70, 0x77, 0x68, 0x69, 0x63, 0x68,
780x69, 0x74, 0x54, 0x00, 0x12, 0x2c, 0x7d, 0x02, 0x00, 0x25, 780x00, 0x74, 0xfa, 0x00, 0x33, 0x68, 0x69, 0x74, 0x54, 0x00,
790x00, 0x03, 0xfc, 0x01, 0x31, 0x75, 0x6e, 0x74, 0x57, 0x00, 790x12, 0x2c, 0x7d, 0x02, 0x00, 0x25, 0x00, 0x03, 0xfc, 0x01,
800xa1, 0x61, 0x73, 0x00, 0x64, 0x65, 0x61, 0x64, 0x00, 0x72, 800x31, 0x75, 0x6e, 0x74, 0x57, 0x00, 0xa1, 0x61, 0x73, 0x00,
810x61, 0x72, 0x01, 0xe1, 0x74, 0x68, 0x61, 0x6e, 0x00, 0x76, 810x64, 0x65, 0x61, 0x64, 0x00, 0x72, 0x61, 0x72, 0x01, 0xe1,
820x69, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x6f, 0x75, 0x8c, 0x02, 820x74, 0x68, 0x61, 0x6e, 0x00, 0x76, 0x69, 0x63, 0x74, 0x6f,
830x43, 0x54, 0x68, 0x69, 0x73, 0x3b, 0x00, 0x81, 0x61, 0x73, 830x72, 0x69, 0x6f, 0x75, 0x8c, 0x02, 0x43, 0x54, 0x68, 0x69,
840x00, 0x6f, 0x72, 0x69, 0x67, 0x69, 0xd5, 0x01, 0xf0, 0x16, 840x73, 0x3b, 0x00, 0x81, 0x61, 0x73, 0x00, 0x6f, 0x72, 0x69,
850x00, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 850x67, 0x69, 0xd5, 0x01, 0xf0, 0x16, 0x00, 0x69, 0x6d, 0x70,
860x65, 0x64, 0x00, 0x66, 0x6f, 0x72, 0x00, 0x57, 0x69, 0x6e, 860x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x00, 0x66,
870x64, 0x6f, 0x77, 0x73, 0x00, 0x62, 0x79, 0x00, 0x42, 0x65, 870x6f, 0x72, 0x00, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73,
880x6e, 0x00, 0x4f, 0x6c, 0x6d, 0x73, 0x74, 0x5b, 0x00, 0x91, 880x00, 0x62, 0x79, 0x00, 0x42, 0x65, 0x6e, 0x00, 0x4f, 0x6c,
890x5b, 0x31, 0x31, 0x5d, 0x2c, 0x00, 0x77, 0x68, 0x6f, 0x41, 890x6d, 0x73, 0x74, 0x5b, 0x00, 0x91, 0x5b, 0x31, 0x31, 0x5d,
900x00, 0x71, 0x6b, 0x69, 0x6e, 0x64, 0x00, 0x65, 0x6e, 0x01, 900x2c, 0x00, 0x77, 0x68, 0x6f, 0x41, 0x00, 0x71, 0x6b, 0x69,
910x02, 0xb0, 0x74, 0x6f, 0x00, 0x72, 0x65, 0x6c, 0x65, 0x61, 910x6e, 0x64, 0x00, 0x65, 0x6e, 0x01, 0x02, 0xb0, 0x74, 0x6f,
920x73, 0x65, 0x00, 0x65, 0x00, 0xb0, 0x73, 0x6f, 0x75, 0x72, 920x00, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x00, 0x65,
930x63, 0x65, 0x00, 0x63, 0x6f, 0x64, 0x65, 0x25, 0x01, 0xa0, 930x00, 0xb0, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x63,
940x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x00, 0x73, 0x6f, 940x6f, 0x64, 0x65, 0x25, 0x01, 0xa0, 0x72, 0x65, 0x71, 0x75,
950x97, 0x00, 0x10, 0x74, 0x53, 0x01, 0xcc, 0x63, 0x6f, 0x75, 950x65, 0x73, 0x74, 0x00, 0x73, 0x6f, 0x97, 0x00, 0x10, 0x74,
960x6c, 0x64, 0x00, 0x62, 0x65, 0x00, 0x72, 0x65, 0x2d, 0x7f, 960x53, 0x01, 0xcc, 0x63, 0x6f, 0x75, 0x6c, 0x64, 0x00, 0x62,
970x00, 0x10, 0x74, 0x43, 0x00, 0x03, 0x70, 0x03, 0x01, 0x06, 970x65, 0x00, 0x72, 0x65, 0x2d, 0x7f, 0x00, 0x10, 0x74, 0x43,
980x03, 0x11, 0x00, 0x7a, 0x00, 0xf5, 0x09, 0x00, 0x68, 0x74, 980x00, 0x03, 0x70, 0x03, 0x01, 0x06, 0x03, 0x11, 0x00, 0x7a,
990x74, 0x70, 0x3a, 0x2f, 0x2f, 0x78, 0x6e, 0x31, 0x33, 0x2e, 990x00, 0xf5, 0x09, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
1000x63, 0x6f, 0x6d, 0x2f, 0x00, 0x00, 0x00, 0x32, 0x34, 0x2e, 1000x2f, 0x78, 0x6e, 0x31, 0x33, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
1010x31, 0xf5, 0x03, 0x00, 0x08, 0x03, 0x5f, 0x72, 0x6f, 0x6c, 1010x00, 0x00, 0x00, 0x32, 0x34, 0x2e, 0x31, 0x09, 0x04, 0x00,
1020x73, 0x20, 0x78, 0x03, 0x0e, 0x02, 0x6a, 0x02, 0x47, 0x65, 1020x08, 0x03, 0x5f, 0x72, 0x6f, 0x6c, 0x73, 0x20, 0x78, 0x03,
1030x69, 0x67, 0x68, 0x16, 0x02, 0x40, 0x73, 0x00, 0x75, 0x73, 1030x0e, 0x02, 0x6a, 0x02, 0x47, 0x65, 0x69, 0x67, 0x68, 0x16,
1040xc2, 0x01, 0x00, 0x1b, 0x00, 0xe0, 0x6e, 0x75, 0x6d, 0x65, 1040x02, 0x40, 0x73, 0x00, 0x75, 0x73, 0xc2, 0x01, 0x00, 0x1b,
1050x72, 0x69, 0x63, 0x00, 0x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 1050x00, 0xe0, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x00,
1060xa7, 0x02, 0x91, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 1060x6b, 0x65, 0x79, 0x70, 0x61, 0x64, 0xa7, 0x02, 0x91, 0x74,
1070x76, 0x65, 0x05, 0x03, 0x02, 0xca, 0x01, 0x52, 0x63, 0x6c, 1070x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x05, 0x03,
1080x69, 0x63, 0x6b, 0xc6, 0x01, 0xf2, 0x03, 0x65, 0x66, 0x74, 1080x02, 0xca, 0x01, 0x52, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0xc6,
1090x00, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x00, 0x62, 0x75, 0x74, 1090x01, 0xf2, 0x03, 0x65, 0x66, 0x74, 0x00, 0x6d, 0x6f, 0x75,
1100x74, 0x6f, 0x6e, 0x00, 0x6f, 0xcf, 0x01, 0x00, 0x5e, 0x04, 1100x73, 0x65, 0x00, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x00,
1110x16, 0x2c, 0x81, 0x00, 0x01, 0xb4, 0x01, 0x31, 0x62, 0x65, 1110x6f, 0xcf, 0x01, 0x00, 0x5e, 0x04, 0x16, 0x2c, 0x81, 0x00,
1120x67, 0x7a, 0x04, 0x01, 0x9c, 0x00, 0x23, 0x69, 0x6e, 0x4f, 1120x01, 0xb4, 0x01, 0x31, 0x62, 0x65, 0x67, 0x7a, 0x04, 0x01,
1130x04, 0x38, 0x6e, 0x65, 0x72, 0xfc, 0x03, 0x00, 0xa5, 0x00, 1130x9c, 0x00, 0x23, 0x69, 0x6e, 0x4f, 0x04, 0x38, 0x6e, 0x65,
1140x56, 0x77, 0x68, 0x65, 0x72, 0x65, 0x6a, 0x00, 0x20, 0x65, 1140x72, 0xfc, 0x03, 0x00, 0xa5, 0x00, 0x56, 0x77, 0x68, 0x65,
1150x64, 0x0b, 0x01, 0x12, 0x49, 0x7c, 0x00, 0x22, 0x75, 0x73, 1150x72, 0x65, 0x6a, 0x00, 0x20, 0x65, 0x64, 0x0b, 0x01, 0x12,
1160xd8, 0x00, 0xb3, 0x60, 0x53, 0x6f, 0x6c, 0x76, 0x65, 0x27, 1160x49, 0x7c, 0x00, 0x22, 0x75, 0x73, 0xd8, 0x00, 0xb3, 0x60,
1170x00, 0x66, 0x75, 0x6e, 0x38, 0x00, 0x00, 0x51, 0x00, 0x03, 1170x53, 0x6f, 0x6c, 0x76, 0x65, 0x27, 0x00, 0x66, 0x75, 0x6e,
1180xe9, 0x01, 0x02, 0x7a, 0x00, 0x74, 0x70, 0x72, 0x6f, 0x67, 1180x38, 0x00, 0x00, 0x51, 0x00, 0x03, 0xe9, 0x01, 0x02, 0x7a,
1190x72, 0x61, 0x6d, 0x31, 0x02, 0x40, 0x6d, 0x70, 0x75, 0x74, 1190x00, 0x74, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x31,
1200x17, 0x05, 0x01, 0xfd, 0x03, 0x04, 0xc2, 0x03, 0x04, 0xac, 1200x02, 0x40, 0x6d, 0x70, 0x75, 0x74, 0x17, 0x05, 0x01, 0xfd,
1210x00, 0x03, 0x76, 0x02, 0x03, 0x7e, 0x01, 0x15, 0x73, 0xef, 1210x03, 0x04, 0xc2, 0x03, 0x04, 0xac, 0x00, 0x03, 0x76, 0x02,
1220x04, 0x51, 0x72, 0x65, 0x6d, 0x61, 0x69, 0xe1, 0x02, 0x01, 1220x03, 0x7e, 0x01, 0x15, 0x73, 0xef, 0x04, 0x51, 0x72, 0x65,
1230xf9, 0x04, 0x00, 0x04, 0x03, 0x61, 0x72, 0x65, 0x74, 0x75, 1230x6d, 0x61, 0x69, 0xe1, 0x02, 0x01, 0xf9, 0x04, 0x00, 0x04,
1240x72, 0x6e, 0x1d, 0x05, 0x00, 0x22, 0x00, 0xc2, 0x63, 0x75, 1240x03, 0x61, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x1d, 0x05,
1250x72, 0x72, 0x65, 0x6e, 0x74, 0x00, 0x70, 0x6f, 0x73, 0x69, 1250x00, 0x22, 0x00, 0xc2, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
1260xb7, 0x01, 0xc2, 0x41, 0x00, 0x68, 0x69, 0x6e, 0x74, 0x00, 1260x74, 0x00, 0x70, 0x6f, 0x73, 0x69, 0xb7, 0x01, 0xc2, 0x41,
1270x61, 0x72, 0x72, 0x6f, 0x77, 0x7d, 0x00, 0x64, 0x61, 0x70, 1270x00, 0x68, 0x69, 0x6e, 0x74, 0x00, 0x61, 0x72, 0x72, 0x6f,
1280x70, 0x65, 0x61, 0x72, 0x1c, 0x01, 0x03, 0x93, 0x01, 0x54, 1280x77, 0x7d, 0x00, 0x64, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72,
1290x64, 0x69, 0x63, 0x61, 0x74, 0x79, 0x01, 0x07, 0xa4, 0x03, 1290x1c, 0x01, 0x03, 0x93, 0x01, 0x54, 0x64, 0x69, 0x63, 0x61,
1300x13, 0x6e, 0x8c, 0x00, 0x00, 0xee, 0x00, 0x21, 0x73, 0x68, 1300x74, 0x79, 0x01, 0x07, 0xa4, 0x03, 0x13, 0x6e, 0x8c, 0x00,
1310x30, 0x02, 0x02, 0xce, 0x01, 0x13, 0x6f, 0x42, 0x01, 0x04, 1310x00, 0xee, 0x00, 0x21, 0x73, 0x68, 0x30, 0x02, 0x02, 0xce,
1320xea, 0x00, 0x00, 0xc9, 0x00, 0x14, 0x2e, 0x18, 0x01, 0x01, 1320x01, 0x13, 0x6f, 0x42, 0x01, 0x04, 0xea, 0x00, 0x00, 0xc9,
1330x30, 0x03, 0x06, 0x5a, 0x01, 0x08, 0xf7, 0x03, 0x02, 0x0e, 1330x00, 0x14, 0x2e, 0x18, 0x01, 0x01, 0x30, 0x03, 0x06, 0x5a,
1340x01, 0x07, 0x8f, 0x00, 0x51, 0x75, 0x70, 0x64, 0x61, 0x74, 1340x01, 0x08, 0xf7, 0x03, 0x02, 0x0e, 0x01, 0x07, 0x8f, 0x00,
1350x51, 0x00, 0x03, 0x86, 0x00, 0x12, 0x65, 0xfd, 0x01, 0x28, 1350x51, 0x75, 0x70, 0x64, 0x61, 0x74, 0x51, 0x00, 0x03, 0x86,
1360x65, 0x78, 0x2d, 0x04, 0x03, 0xae, 0x00, 0x02, 0x66, 0x00, 1360x00, 0x12, 0x65, 0xfd, 0x01, 0x28, 0x65, 0x78, 0x2d, 0x04,
1370x04, 0x58, 0x02, 0xf1, 0x01, 0x61, 0x6c, 0x73, 0x6f, 0x00, 1370x03, 0xae, 0x00, 0x02, 0x66, 0x00, 0x04, 0x58, 0x02, 0xf1,
1380x70, 0x72, 0x65, 0x73, 0x73, 0x00, 0x53, 0x70, 0x61, 0x63, 1380x01, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0x70, 0x72, 0x65, 0x73,
1390x65, 0x8b, 0x04, 0x81, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 1390x73, 0x00, 0x53, 0x70, 0x61, 0x63, 0x65, 0x8b, 0x04, 0x81,
1400x69, 0x63, 0x55, 0x03, 0x08, 0xde, 0x01, 0x09, 0xd6, 0x01, 1400x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x55, 0x03,
1410x00, 0x11, 0x00, 0x06, 0x19, 0x01, 0x05, 0xb9, 0x00, 0x04, 1410x08, 0xde, 0x01, 0x09, 0xd6, 0x01, 0x00, 0x11, 0x00, 0x06,
1420x30, 0x00, 0x00, 0x4c, 0x05, 0x31, 0x66, 0x66, 0x65, 0x4c, 1420x19, 0x01, 0x05, 0xb9, 0x00, 0x04, 0x30, 0x00, 0x00, 0x4c,
1430x01, 0x06, 0x38, 0x00, 0x41, 0x66, 0x72, 0x6f, 0x6d, 0x3a, 1430x05, 0x31, 0x66, 0x66, 0x65, 0x4c, 0x01, 0x06, 0x38, 0x00,
1440x00, 0x30, 0x6f, 0x6e, 0x65, 0x0e, 0x01, 0x20, 0x77, 0x6e, 1440x41, 0x66, 0x72, 0x6f, 0x6d, 0x3a, 0x00, 0x30, 0x6f, 0x6e,
1450x9e, 0x03, 0x05, 0xd0, 0x00, 0x12, 0x2c, 0x07, 0x00, 0x14, 1450x65, 0x0e, 0x01, 0x20, 0x77, 0x6e, 0x9e, 0x03, 0x05, 0xd0,
1460x73, 0x61, 0x02, 0x03, 0x23, 0x00, 0x20, 0x6f, 0x6e, 0xde, 1460x00, 0x12, 0x2c, 0x07, 0x00, 0x14, 0x73, 0x61, 0x02, 0x03,
1470x03, 0x12, 0x66, 0xc0, 0x00, 0x41, 0x75, 0x7a, 0x7a, 0x6c, 1470x23, 0x00, 0x20, 0x6f, 0x6e, 0xde, 0x03, 0x12, 0x66, 0xc0,
1480x94, 0x04, 0x21, 0x73, 0x74, 0x29, 0x05, 0x70, 0x6f, 0x6c, 1480x00, 0x41, 0x75, 0x7a, 0x7a, 0x6c, 0x94, 0x04, 0x21, 0x73,
1490x76, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x02, 0x13, 0x41, 0xe6, 1490x74, 0x29, 0x05, 0x70, 0x6f, 0x6c, 0x76, 0x61, 0x62, 0x6c,
1500x01, 0x13, 0x61, 0x09, 0x03, 0x90, 0x64, 0x65, 0x73, 0x63, 1500x65, 0x54, 0x02, 0x13, 0x41, 0xe6, 0x01, 0x13, 0x61, 0x09,
1510x72, 0x69, 0x62, 0x65, 0x64, 0x91, 0x00, 0x13, 0x73, 0x83, 1510x03, 0x90, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
1520x00, 0x32, 0x32, 0x2e, 0x31, 0x51, 0x07, 0x00, 0xfb, 0x00, 1520x64, 0x91, 0x00, 0x13, 0x73, 0x83, 0x00, 0x32, 0x32, 0x2e,
1530x52, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x3f, 0x00, 0xd5, 0x49, 1530x31, 0x51, 0x07, 0x00, 0xfb, 0x00, 0x52, 0x61, 0x76, 0x61,
1540x6e, 0x00, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x75, 0x6c, 1540x69, 0x6c, 0x3f, 0x00, 0xd5, 0x49, 0x6e, 0x00, 0x70, 0x61,
1550x61, 0x72, 0x1c, 0x03, 0x20, 0x64, 0x6f, 0x16, 0x07, 0x09, 1550x72, 0x74, 0x69, 0x63, 0x75, 0x6c, 0x61, 0x72, 0x1c, 0x03,
1560x0f, 0x05, 0x00, 0x35, 0x02, 0x63, 0x64, 0x69, 0x65, 0x2c, 1560x20, 0x64, 0x6f, 0x16, 0x07, 0x09, 0x0f, 0x05, 0x00, 0x35,
1570x00, 0x79, 0x45, 0x01, 0x04, 0xc4, 0x02, 0x46, 0x55, 0x6e, 1570x02, 0x63, 0x64, 0x69, 0x65, 0x2c, 0x00, 0x79, 0x45, 0x01,
1580x64, 0x6f, 0xc1, 0x02, 0x02, 0x5c, 0x02, 0x90, 0x73, 0x75, 1580x04, 0xc4, 0x02, 0x46, 0x55, 0x6e, 0x64, 0x6f, 0xc1, 0x02,
1590x6d, 0x65, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x1a, 0x02, 0x01, 1590x02, 0x5c, 0x02, 0x90, 0x73, 0x75, 0x6d, 0x65, 0x00, 0x70,
1600xfe, 0x00, 0x52, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x31, 0x00, 1600x6c, 0x61, 0x79, 0x1a, 0x02, 0x01, 0xfe, 0x00, 0x52, 0x62,
1610x01, 0x56, 0x05, 0x01, 0x32, 0x01, 0x39, 0x2e, 0x00, 0x54, 1610x65, 0x66, 0x6f, 0x72, 0x31, 0x00, 0x01, 0x56, 0x05, 0x01,
1620x10, 0x05, 0x00, 0x99, 0x05, 0x64, 0x00, 0x74, 0x72, 0x61, 1620x32, 0x01, 0x39, 0x2e, 0x00, 0x54, 0x10, 0x05, 0x00, 0x99,
1630x63, 0x6b, 0x6b, 0x01, 0x61, 0x6e, 0x75, 0x6d, 0x62, 0x65, 1630x05, 0x64, 0x00, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x6b, 0x01,
1640x72, 0x0e, 0x00, 0x41, 0x69, 0x6d, 0x65, 0x73, 0x7d, 0x00, 1640x61, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x0e, 0x00, 0x41,
1650x60, 0x68, 0x61, 0x76, 0x65, 0x00, 0x64, 0x4b, 0x01, 0x00, 1650x69, 0x6d, 0x65, 0x73, 0x7d, 0x00, 0x60, 0x68, 0x61, 0x76,
1660x41, 0x02, 0x12, 0x2e, 0x49, 0x04, 0x15, 0x32, 0x49, 0x04, 1660x65, 0x00, 0x64, 0x4b, 0x01, 0x00, 0x41, 0x02, 0x12, 0x2e,
1670xb1, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 1670x49, 0x04, 0x15, 0x32, 0x49, 0x04, 0xb1, 0x70, 0x61, 0x72,
1680x73, 0x20, 0x37, 0x05, 0x46, 0x65, 0x73, 0x65, 0x00, 0x14, 1680x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x37, 0x05,
1690x00, 0x02, 0x05, 0x01, 0x04, 0x00, 0x01, 0x06, 0x9a, 0x01, 1690x46, 0x65, 0x73, 0x65, 0x00, 0x14, 0x00, 0x02, 0x05, 0x01,
1700xe8, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 1700x04, 0x00, 0x01, 0x06, 0x9a, 0x01, 0xe8, 0x60, 0x43, 0x75,
1710x2e, 0x27, 0x00, 0x6f, 0x70, 0x3b, 0x02, 0xb0, 0x60, 0x54, 1710x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f,
1720x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0x6c, 1720x70, 0x3b, 0x02, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27,
1730x00, 0x82, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 1730x00, 0x6d, 0x65, 0x6e, 0x75, 0x6c, 0x00, 0x82, 0x57, 0x69,
1740x80, 0x04, 0x51, 0x00, 0x00, 0x53, 0x69, 0x7a, 0xfe, 0x06, 1740x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x80, 0x04, 0x51, 0x00,
1750x01, 0x80, 0x03, 0x00, 0x71, 0x01, 0x80, 0x71, 0x75, 0x61, 1750x00, 0x53, 0x69, 0x7a, 0xfe, 0x06, 0x01, 0x80, 0x03, 0x00,
1760x72, 0x65, 0x73, 0x2e, 0x00, 1760x71, 0x01, 0x80, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2e,
1770x00,
177}; 178};
178 179
179const unsigned short help_text_len = 2266; 180const unsigned short help_text_len = 2286;
180const unsigned short help_text_words = 430; 181const unsigned short help_text_words = 431;
181const char quick_help_text[] = "Collect all the gems without running into any of the mines."; 182const char quick_help_text[] = "Collect all the gems without running into any of the mines.";
diff --git a/apps/plugins/puzzles/help/keen.c b/apps/plugins/puzzles/help/keen.c
index 58a5f0b2af..9152fed158 100644
--- a/apps/plugins/puzzles/help/keen.c
+++ b/apps/plugins/puzzles/help/keen.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,257 +6,258 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 324, TEXT_CENTER | C_RED }, 9 { 325, TEXT_CENTER | C_RED },
10 { 391, TEXT_UNDERLINE }, 10 { 392, TEXT_UNDERLINE },
11 { 649, TEXT_CENTER | C_RED }, 11 { 650, TEXT_CENTER | C_RED },
12 { 666, TEXT_UNDERLINE }, 12 { 667, TEXT_UNDERLINE },
13 { 698, TEXT_UNDERLINE }, 13 { 699, TEXT_UNDERLINE },
14 { 737, TEXT_UNDERLINE }, 14 { 738, TEXT_UNDERLINE },
15 LAST_STYLE_ITEM 15 LAST_STYLE_ITEM
16}; 16};
17 17
18/* orig 3952 comp 2376 ratio 0.601215 level 10 saved 1576 */ 18/* orig 3969 comp 2383 ratio 0.600403 level 10 saved 1586 */
19const char help_text[] = { 19const char help_text[] = {
200xf4, 0x21, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 200xfb, 0x04, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
210x33, 0x30, 0x3a, 0x20, 0x4b, 0x65, 0x65, 0x6e, 0x20, 0x00, 210x33, 0x30, 0x3a, 0x20, 0x4b, 0x65, 0x65, 0x6e, 0x20, 0x00,
220x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 220x2d, 0x01, 0x00, 0xf4, 0x10, 0x00, 0x00, 0x00, 0x59, 0x6f,
230x00, 0x61, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x00, 230x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x73,
240x67, 0x72, 0x69, 0x64, 0x3b, 0x00, 0x65, 0x61, 0x63, 0x68, 240x71, 0x75, 0x61, 0x72, 0x65, 0x00, 0x67, 0x72, 0x69, 0x64,
250x12, 0x00, 0xf1, 0x1a, 0x6d, 0x61, 0x79, 0x00, 0x63, 0x6f, 250x3b, 0x00, 0x65, 0x61, 0x63, 0x68, 0x12, 0x00, 0xf1, 0x1a,
260x6e, 0x74, 0x61, 0x69, 0x6e, 0x00, 0x61, 0x00, 0x64, 0x69, 260x6d, 0x61, 0x79, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
270x67, 0x69, 0x74, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x00, 0x31, 270x6e, 0x00, 0x61, 0x00, 0x64, 0x69, 0x67, 0x69, 0x74, 0x00,
280x00, 0x74, 0x6f, 0x00, 0x74, 0x68, 0x65, 0x00, 0x73, 0x69, 280x66, 0x72, 0x6f, 0x6d, 0x00, 0x31, 0x00, 0x74, 0x6f, 0x00,
290x7a, 0x65, 0x00, 0x6f, 0x66, 0x0c, 0x00, 0x00, 0x40, 0x00, 290x74, 0x68, 0x65, 0x00, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x6f,
300x33, 0x2e, 0x00, 0x54, 0x0a, 0x00, 0xf0, 0x08, 0x00, 0x69, 300x66, 0x0c, 0x00, 0x00, 0x40, 0x00, 0x33, 0x2e, 0x00, 0x54,
310x73, 0x00, 0x64, 0x69, 0x76, 0x69, 0x64, 0x65, 0x64, 0x00, 310x0a, 0x00, 0xf0, 0x08, 0x00, 0x69, 0x73, 0x00, 0x64, 0x69,
320x69, 0x6e, 0x74, 0x6f, 0x00, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 320x76, 0x69, 0x64, 0x65, 0x64, 0x00, 0x69, 0x6e, 0x74, 0x6f,
330x73, 0x2d, 0x00, 0xf1, 0x02, 0x76, 0x61, 0x72, 0x79, 0x69, 330x00, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x2d, 0x00, 0xf1,
340x6e, 0x67, 0x00, 0x73, 0x68, 0x61, 0x70, 0x65, 0x00, 0x61, 340x02, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x00, 0x73,
350x6e, 0x64, 0x47, 0x00, 0xf0, 0x13, 0x2c, 0x00, 0x77, 0x69, 350x68, 0x61, 0x70, 0x65, 0x00, 0x61, 0x6e, 0x64, 0x47, 0x00,
360x74, 0x68, 0x00, 0x61, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x65, 360xf0, 0x13, 0x2c, 0x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x61,
370x74, 0x69, 0x63, 0x00, 0x63, 0x6c, 0x75, 0x65, 0x73, 0x00, 370x72, 0x69, 0x74, 0x68, 0x6d, 0x65, 0x74, 0x69, 0x63, 0x00,
380x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x00, 0x69, 0x6e, 380x63, 0x6c, 0x75, 0x65, 0x73, 0x00, 0x77, 0x72, 0x69, 0x74,
390x66, 0x00, 0x20, 0x6d, 0x2e, 0xba, 0x00, 0x50, 0x72, 0x00, 390x74, 0x65, 0x6e, 0x00, 0x69, 0x6e, 0x66, 0x00, 0x20, 0x6d,
400x61, 0x69, 0x6d, 0x62, 0x00, 0xf5, 0x02, 0x74, 0x6f, 0x00, 400x2e, 0xba, 0x00, 0x50, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x62,
410x66, 0x75, 0x6c, 0x6c, 0x79, 0x00, 0x70, 0x6f, 0x70, 0x75, 410x00, 0xf5, 0x02, 0x74, 0x6f, 0x00, 0x66, 0x75, 0x6c, 0x6c,
420x6c, 0x61, 0x74, 0x65, 0x8a, 0x00, 0x02, 0x4e, 0x00, 0x01, 420x79, 0x00, 0x70, 0x6f, 0x70, 0x75, 0x6c, 0x61, 0x74, 0x65,
430xb4, 0x00, 0xf0, 0x03, 0x73, 0x00, 0x73, 0x75, 0x63, 0x68, 430x8a, 0x00, 0x02, 0x4e, 0x00, 0x01, 0xb4, 0x00, 0xf0, 0x03,
440x00, 0x74, 0x68, 0x61, 0x74, 0x3a, 0x00, 0x00, 0x00, 0x2d, 440x73, 0x00, 0x73, 0x75, 0x63, 0x68, 0x00, 0x74, 0x68, 0x61,
450x00, 0x45, 0xe4, 0x00, 0x34, 0x72, 0x6f, 0x77, 0xdd, 0x00, 450x74, 0x3a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x45, 0xe4, 0x00,
460xf1, 0x05, 0x73, 0x00, 0x6f, 0x6e, 0x6c, 0x79, 0x00, 0x6f, 460x34, 0x72, 0x6f, 0x77, 0xdd, 0x00, 0xf1, 0x05, 0x73, 0x00,
470x6e, 0x65, 0x00, 0x6f, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 470x6f, 0x6e, 0x6c, 0x79, 0x00, 0x6f, 0x6e, 0x65, 0x00, 0x6f,
480x6e, 0x63, 0xd7, 0x00, 0x01, 0x0d, 0x01, 0x02, 0xf8, 0x00, 480x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0xd7, 0x00,
490x05, 0x38, 0x00, 0x6f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 490x01, 0x0d, 0x01, 0x02, 0xf8, 0x00, 0x05, 0x38, 0x00, 0x6f,
500x3b, 0x00, 0x1d, 0x00, 0x17, 0x01, 0x03, 0x8d, 0x00, 0x22, 500x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x3b, 0x00, 0x1d, 0x00,
510x69, 0x6e, 0x1d, 0x00, 0x01, 0x11, 0x01, 0xf1, 0x01, 0x00, 510x17, 0x01, 0x03, 0x8d, 0x00, 0x22, 0x69, 0x6e, 0x1d, 0x00,
520x63, 0x61, 0x6e, 0x00, 0x62, 0x65, 0x00, 0x63, 0x6f, 0x6d, 520x01, 0x11, 0x01, 0xf1, 0x01, 0x00, 0x63, 0x61, 0x6e, 0x00,
530x62, 0x69, 0x6e, 0x65, 0x64, 0xd2, 0x00, 0x31, 0x6f, 0x72, 530x62, 0x65, 0x00, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65,
540x6d, 0xc8, 0x00, 0xd3, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 540x64, 0xd2, 0x00, 0x31, 0x6f, 0x72, 0x6d, 0xc8, 0x00, 0xd3,
550x00, 0x73, 0x74, 0x61, 0x74, 0x65, 0x64, 0x01, 0x01, 0x01, 550x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x00, 0x73, 0x74, 0x61,
560x16, 0x01, 0x40, 0x2c, 0x00, 0x75, 0x73, 0x42, 0x01, 0x00, 560x74, 0x65, 0x64, 0x01, 0x01, 0x01, 0x16, 0x01, 0x40, 0x2c,
570x10, 0x00, 0x07, 0x31, 0x01, 0xf8, 0x00, 0x6f, 0x70, 0x65, 570x00, 0x75, 0x73, 0x42, 0x01, 0x00, 0x10, 0x00, 0x07, 0x31,
580x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x67, 0x69, 0x76, 580x01, 0xf8, 0x00, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
590x65, 0x6e, 0x32, 0x00, 0x00, 0x99, 0x01, 0x52, 0x61, 0x74, 590x6f, 0x6e, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x32, 0x00,
600x00, 0x69, 0x73, 0x02, 0x01, 0x71, 0x41, 0x6e, 0x00, 0x61, 600x00, 0x99, 0x01, 0x52, 0x61, 0x74, 0x00, 0x69, 0x73, 0x02,
610x64, 0x64, 0x69, 0x2c, 0x00, 0x00, 0x1f, 0x00, 0x61, 0x00, 610x01, 0x71, 0x41, 0x6e, 0x00, 0x61, 0x64, 0x64, 0x69, 0x2c,
620x6d, 0x65, 0x61, 0x6e, 0x73, 0x23, 0x01, 0x02, 0xd8, 0x01, 620x00, 0x00, 0x1f, 0x00, 0x61, 0x00, 0x6d, 0x65, 0x61, 0x6e,
630x24, 0x75, 0x6d, 0xd7, 0x01, 0x06, 0xb6, 0x00, 0x00, 0x0e, 630x73, 0x23, 0x01, 0x02, 0xd8, 0x01, 0x24, 0x75, 0x6d, 0xd7,
640x00, 0x02, 0xb5, 0x00, 0x63, 0x6d, 0x75, 0x73, 0x74, 0x00, 640x01, 0x06, 0xb6, 0x00, 0x00, 0x0e, 0x00, 0x02, 0xb5, 0x00,
650x62, 0x6d, 0x01, 0x01, 0x6b, 0x00, 0x02, 0xab, 0x00, 0xf5, 650x63, 0x6d, 0x75, 0x73, 0x74, 0x00, 0x62, 0x6d, 0x01, 0x01,
660x05, 0x2e, 0x00, 0x46, 0x6f, 0x72, 0x00, 0x65, 0x78, 0x61, 660x6b, 0x00, 0x02, 0xab, 0x00, 0xf5, 0x05, 0x2e, 0x00, 0x46,
670x6d, 0x70, 0x6c, 0x65, 0x2c, 0x00, 0x60, 0x31, 0x35, 0x2b, 670x6f, 0x72, 0x00, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
680x27, 0x5b, 0x00, 0x11, 0x65, 0x34, 0x01, 0x31, 0x65, 0x6e, 680x2c, 0x00, 0x60, 0x31, 0x35, 0x2b, 0x27, 0x5b, 0x00, 0x11,
690x74, 0x05, 0x02, 0x06, 0x4d, 0x00, 0x71, 0x61, 0x64, 0x64, 690x65, 0x34, 0x01, 0x31, 0x65, 0x6e, 0x74, 0x05, 0x02, 0x06,
700x73, 0x00, 0x75, 0x70, 0xfa, 0x00, 0x72, 0x69, 0x66, 0x74, 700x4d, 0x00, 0x71, 0x61, 0x64, 0x64, 0x73, 0x00, 0x75, 0x70,
710x65, 0x65, 0x6e, 0x2e, 0xa4, 0x00, 0xb6, 0x00, 0x6d, 0x75, 710xfa, 0x00, 0x72, 0x69, 0x66, 0x74, 0x65, 0x65, 0x6e, 0x2e,
720x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x63, 0x61, 0xa9, 0x00, 720xa4, 0x00, 0xb6, 0x00, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70,
730xfc, 0x09, 0x28, 0x65, 0x2e, 0x67, 0x2e, 0x00, 0x60, 0x36, 730x6c, 0x69, 0x63, 0x61, 0xa9, 0x00, 0xfc, 0x09, 0x28, 0x65,
740x30, 0x2a, 0x27, 0x29, 0x2c, 0x00, 0x73, 0x69, 0x6d, 0x69, 740x2e, 0x67, 0x2e, 0x00, 0x60, 0x36, 0x30, 0x2a, 0x27, 0x29,
750x6c, 0x61, 0x72, 0x6c, 0x79, 0x2c, 0xc2, 0x00, 0x7f, 0x70, 750x2c, 0x00, 0x73, 0x69, 0x6d, 0x69, 0x6c, 0x61, 0x72, 0x6c,
760x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0xc6, 0x00, 0x23, 0x02, 760x79, 0x2c, 0xc2, 0x00, 0x7f, 0x70, 0x72, 0x6f, 0x64, 0x75,
770x7f, 0x00, 0x76, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 770x63, 0x74, 0xc6, 0x00, 0x23, 0x02, 0x7f, 0x00, 0x76, 0x73,
780x7c, 0x00, 0xb0, 0x77, 0x69, 0x6c, 0x6c, 0x00, 0x61, 0x6c, 780x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x7c, 0x00, 0xb0, 0x77,
790x77, 0x61, 0x79, 0x73, 0x38, 0x00, 0x07, 0x9a, 0x02, 0x13, 790x69, 0x6c, 0x6c, 0x00, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73,
800x61, 0x53, 0x00, 0x22, 0x6f, 0x66, 0x13, 0x03, 0x41, 0x74, 800x38, 0x00, 0x07, 0x9a, 0x02, 0x13, 0x61, 0x53, 0x00, 0x22,
810x77, 0x6f, 0x2c, 0xda, 0x02, 0x28, 0x69, 0x74, 0x99, 0x00, 810x6f, 0x66, 0x13, 0x03, 0x41, 0x74, 0x77, 0x6f, 0x2c, 0xda,
820x01, 0x27, 0x02, 0x0f, 0x91, 0x00, 0x07, 0xa0, 0x69, 0x73, 820x02, 0x28, 0x69, 0x74, 0x99, 0x00, 0x01, 0x27, 0x02, 0x0f,
830x00, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x2f, 0x00, 830x91, 0x00, 0x07, 0xa0, 0x69, 0x73, 0x00, 0x67, 0x72, 0x65,
840x02, 0x1a, 0x00, 0x87, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x00, 840x61, 0x74, 0x65, 0x72, 0x2f, 0x00, 0x02, 0x1a, 0x00, 0x87,
850x62, 0x79, 0xa6, 0x00, 0x6c, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 850x6f, 0x74, 0x68, 0x65, 0x72, 0x00, 0x62, 0x79, 0xa6, 0x00,
860x74, 0x6c, 0x01, 0x3f, 0x32, 0x2d, 0x27, 0x6b, 0x00, 0x1b, 860x6c, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x6c, 0x01, 0x3f,
870x6b, 0x32, 0x00, 0x6d, 0x6f, 0x72, 0x65, 0x6a, 0x00, 0x20, 870x32, 0x2d, 0x27, 0x6b, 0x00, 0x1b, 0x6b, 0x32, 0x00, 0x6d,
880x2c, 0x00, 0x55, 0x00, 0xb6, 0x71, 0x75, 0x69, 0x76, 0x61, 880x6f, 0x72, 0x65, 0x6a, 0x00, 0x20, 0x2c, 0x00, 0x55, 0x00,
890x6c, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x4e, 0x00, 0x02, 0xcd, 890xb6, 0x71, 0x75, 0x69, 0x76, 0x61, 0x6c, 0x65, 0x6e, 0x74,
900x02, 0x57, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x9a, 0x00, 0x00, 900x6c, 0x79, 0x4e, 0x00, 0x02, 0xcd, 0x02, 0x57, 0x6d, 0x69,
910x1a, 0x00, 0x00, 0x4d, 0x00, 0x02, 0xfa, 0x03, 0x34, 0x74, 910x6e, 0x75, 0x73, 0x9a, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x4d,
920x77, 0x6f, 0x6f, 0x00, 0x50, 0x63, 0x6f, 0x75, 0x6c, 0x64, 920x00, 0x02, 0xfa, 0x03, 0x34, 0x74, 0x77, 0x6f, 0x6f, 0x00,
930x27, 0x01, 0x21, 0x65, 0x69, 0x29, 0x00, 0xf4, 0x02, 0x77, 930x50, 0x63, 0x6f, 0x75, 0x6c, 0x64, 0x27, 0x01, 0x21, 0x65,
940x61, 0x79, 0x00, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2c, 0x00, 940x69, 0x29, 0x00, 0xf4, 0x02, 0x77, 0x61, 0x79, 0x00, 0x72,
950x74, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x67, 0x01, 0x00, 0x26, 950x6f, 0x75, 0x6e, 0x64, 0x2c, 0x00, 0x74, 0x68, 0x6f, 0x75,
960x04, 0x1c, 0x73, 0xe0, 0x01, 0x2b, 0x33, 0x2f, 0xdf, 0x01, 960x67, 0x68, 0x67, 0x01, 0x00, 0x26, 0x04, 0x1c, 0x73, 0xe0,
970x24, 0x69, 0x73, 0x7a, 0x01, 0x0f, 0x6f, 0x01, 0x03, 0x01, 970x01, 0x2b, 0x33, 0x2f, 0xdf, 0x01, 0x24, 0x69, 0x73, 0x7a,
980x6e, 0x01, 0x0b, 0x00, 0x01, 0x02, 0xb2, 0x00, 0x04, 0x86, 980x01, 0x0f, 0x6f, 0x01, 0x03, 0x01, 0x6e, 0x01, 0x0b, 0x00,
990x04, 0x27, 0x62, 0x79, 0xb7, 0x00, 0x20, 0x69, 0x73, 0xe6, 990x01, 0x02, 0xb2, 0x00, 0x04, 0x86, 0x04, 0x27, 0x62, 0x79,
1000x00, 0x24, 0x61, 0x6c, 0xc9, 0x04, 0x0a, 0x5a, 0x01, 0x62, 1000xb7, 0x00, 0x20, 0x69, 0x73, 0xe6, 0x00, 0x24, 0x61, 0x6c,
1010x00, 0x00, 0x4e, 0x6f, 0x74, 0x65, 0x49, 0x00, 0x04, 0x6c, 1010xc9, 0x04, 0x0a, 0x5a, 0x01, 0x62, 0x00, 0x00, 0x4e, 0x6f,
1020x00, 0x08, 0x0d, 0x05, 0x01, 0x23, 0x03, 0x25, 0x61, 0x6d, 1020x74, 0x65, 0x49, 0x00, 0x04, 0x6c, 0x00, 0x08, 0x0d, 0x05,
1030x14, 0x01, 0x05, 0x48, 0x01, 0x10, 0x6f, 0xfe, 0x03, 0x42, 1030x01, 0x23, 0x03, 0x25, 0x61, 0x6d, 0x14, 0x01, 0x05, 0x48,
1040x28, 0x70, 0x72, 0x6f, 0x73, 0x00, 0x00, 0x28, 0x00, 0x90, 1040x01, 0x10, 0x6f, 0xfe, 0x03, 0x42, 0x28, 0x70, 0x72, 0x6f,
1050x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x93, 1050x73, 0x00, 0x00, 0x28, 0x00, 0x90, 0x69, 0x64, 0x65, 0x6e,
1060x00, 0x20, 0x73, 0x00, 0x58, 0x05, 0x48, 0x6e, 0x6f, 0x74, 1060x74, 0x69, 0x63, 0x61, 0x6c, 0x93, 0x00, 0x20, 0x73, 0x00,
1070x00, 0x46, 0x00, 0x00, 0x8b, 0x04, 0x00, 0xbf, 0x00, 0x02, 1070x58, 0x05, 0x48, 0x6e, 0x6f, 0x74, 0x00, 0x46, 0x00, 0x00,
1080x5b, 0x04, 0x10, 0x29, 0x4b, 0x01, 0x61, 0x69, 0x73, 0x00, 1080x8b, 0x04, 0x00, 0xbf, 0x00, 0x02, 0x5b, 0x04, 0x10, 0x29,
1090x72, 0x75, 0x6c, 0x5b, 0x01, 0x83, 0x70, 0x72, 0x65, 0x63, 1090x4b, 0x01, 0x61, 0x69, 0x73, 0x00, 0x72, 0x75, 0x6c, 0x5b,
1100x69, 0x73, 0x65, 0x6c, 0xbf, 0x00, 0x65, 0x70, 0x70, 0x6f, 1100x01, 0x83, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x65, 0x6c,
1110x73, 0x69, 0x74, 0xdd, 0x01, 0x02, 0x26, 0x00, 0xf2, 0x0e, 1110xbf, 0x00, 0x65, 0x70, 0x70, 0x6f, 0x73, 0x69, 0x74, 0xdd,
1120x6e, 0x00, 0x53, 0x6f, 0x6c, 0x6f, 0x27, 0x73, 0x00, 0x60, 1120x01, 0x02, 0x26, 0x00, 0xf2, 0x0e, 0x6e, 0x00, 0x53, 0x6f,
1130x4b, 0x69, 0x6c, 0x6c, 0x65, 0x72, 0x27, 0x00, 0x6d, 0x6f, 1130x6c, 0x6f, 0x27, 0x73, 0x00, 0x60, 0x4b, 0x69, 0x6c, 0x6c,
1140x64, 0x65, 0x00, 0x28, 0x73, 0x65, 0x65, 0x00, 0x63, 0xfe, 1140x65, 0x72, 0x27, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0x00, 0x28,
1150x05, 0x40, 0x00, 0x31, 0x31, 0x29, 0xda, 0x00, 0x01, 0x5c, 1150x73, 0x65, 0x65, 0x00, 0x63, 0x0f, 0x06, 0x40, 0x00, 0x31,
1160x00, 0xd5, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x61, 1160x31, 0x29, 0xda, 0x00, 0x01, 0x5c, 0x00, 0xd5, 0x70, 0x75,
1170x70, 0x70, 0x65, 0x61, 0x72, 0x1b, 0x02, 0xb2, 0x54, 0x69, 1170x7a, 0x7a, 0x6c, 0x65, 0x00, 0x61, 0x70, 0x70, 0x65, 0x61,
1180x6d, 0x65, 0x73, 0x00, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x80, 1180x72, 0x1b, 0x02, 0xb2, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x00,
1190x04, 0x00, 0x9d, 0x00, 0x80, 0x60, 0x4b, 0x65, 0x6e, 0x4b, 1190x75, 0x6e, 0x64, 0x65, 0x72, 0x80, 0x04, 0x00, 0x9d, 0x00,
1200x65, 0x6e, 0x27, 0x3c, 0x00, 0x42, 0x33, 0x30, 0x2e, 0x31, 1200x80, 0x60, 0x4b, 0x65, 0x6e, 0x4b, 0x65, 0x6e, 0x27, 0x3c,
1210x42, 0x06, 0x00, 0x0a, 0x01, 0x40, 0x72, 0x6f, 0x6c, 0x73, 1210x00, 0x42, 0x33, 0x30, 0x2e, 0x31, 0x53, 0x06, 0x00, 0x0a,
1220x4b, 0x06, 0x00, 0x11, 0x00, 0x00, 0xcd, 0x05, 0x50, 0x72, 1220x01, 0x80, 0x72, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00, 0x00,
1230x65, 0x73, 0x00, 0x6d, 0x6a, 0x05, 0x32, 0x6f, 0x66, 0x00, 1230x11, 0x00, 0x00, 0xcd, 0x05, 0x50, 0x72, 0x65, 0x73, 0x00,
1240x02, 0x02, 0x01, 0x24, 0x00, 0x72, 0x00, 0x73, 0x79, 0x73, 1240x6d, 0x6a, 0x05, 0x32, 0x6f, 0x66, 0x00, 0x02, 0x02, 0x01,
1250x74, 0x65, 0x6d, 0x91, 0x05, 0x00, 0xa7, 0x00, 0x20, 0x00, 1250x24, 0x00, 0x72, 0x00, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d,
1260x28, 0xed, 0x00, 0x21, 0x55, 0x6e, 0x81, 0x01, 0x02, 0x94, 1260x91, 0x05, 0x00, 0xa7, 0x00, 0x20, 0x00, 0x28, 0xed, 0x00,
1270x00, 0x61, 0x6f, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x4a, 0x00, 1270x21, 0x55, 0x6e, 0x81, 0x01, 0x02, 0x94, 0x00, 0x61, 0x6f,
1280x01, 0xf6, 0x01, 0x91, 0x70, 0x6c, 0x79, 0x00, 0x63, 0x6c, 1280x00, 0x70, 0x6c, 0x61, 0x79, 0x4a, 0x00, 0x01, 0xf6, 0x01,
1290x69, 0x63, 0x6b, 0x88, 0x00, 0x51, 0x6d, 0x6f, 0x75, 0x73, 1290x91, 0x70, 0x6c, 0x79, 0x00, 0x63, 0x6c, 0x69, 0x63, 0x6b,
1300x65, 0xf8, 0x01, 0x84, 0x6e, 0x79, 0x00, 0x65, 0x6d, 0x70, 1300x88, 0x00, 0x51, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0xf8, 0x01,
1310x74, 0x79, 0xa2, 0x06, 0x21, 0x61, 0x6e, 0x65, 0x01, 0x65, 1310x84, 0x6e, 0x79, 0x00, 0x65, 0x6d, 0x70, 0x74, 0x79, 0xa2,
1320x6e, 0x00, 0x74, 0x79, 0x70, 0x65, 0xa4, 0x06, 0x12, 0x6f, 1320x06, 0x21, 0x61, 0x6e, 0x65, 0x01, 0x65, 0x6e, 0x00, 0x74,
1330xcf, 0x00, 0x72, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 1330x79, 0x70, 0x65, 0xa4, 0x06, 0x12, 0x6f, 0xcf, 0x00, 0x72,
1340x54, 0x05, 0x00, 0xbb, 0x03, 0x01, 0xd0, 0x01, 0x02, 0x3a, 1340x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x54, 0x05, 0x00,
1350x00, 0xc0, 0x2e, 0x00, 0x49, 0x66, 0x00, 0x79, 0x6f, 0x75, 1350xbb, 0x03, 0x01, 0xd0, 0x01, 0x02, 0x3a, 0x00, 0xc0, 0x2e,
1360x00, 0x6d, 0x61, 0x6b, 0x39, 0x00, 0x8f, 0x6d, 0x69, 0x73, 1360x00, 0x49, 0x66, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x6d, 0x61,
1370x74, 0x61, 0x6b, 0x65, 0x2c, 0x76, 0x00, 0x01, 0x01, 0xc6, 1370x6b, 0x39, 0x00, 0x8f, 0x6d, 0x69, 0x73, 0x74, 0x61, 0x6b,
1380x01, 0x88, 0x6e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 1380x65, 0x2c, 0x76, 0x00, 0x01, 0x01, 0xc6, 0x01, 0x88, 0x6e,
1390x7a, 0x00, 0xb0, 0x70, 0x72, 0x65, 0x73, 0x73, 0x00, 0x53, 1390x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x7a, 0x00, 0xb0,
1400x70, 0x61, 0x63, 0x65, 0x64, 0x00, 0x50, 0x63, 0x6c, 0x65, 1400x70, 0x72, 0x65, 0x73, 0x73, 0x00, 0x53, 0x70, 0x61, 0x63,
1410x61, 0x72, 0xf2, 0x03, 0x20, 0x61, 0x67, 0x25, 0x02, 0x62, 1410x65, 0x64, 0x00, 0x50, 0x63, 0x6c, 0x65, 0x61, 0x72, 0xf2,
1420x28, 0x6f, 0x72, 0x00, 0x75, 0x73, 0x5f, 0x04, 0xc1, 0x55, 1420x03, 0x20, 0x61, 0x67, 0x25, 0x02, 0x62, 0x28, 0x6f, 0x72,
1430x6e, 0x64, 0x6f, 0x00, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 1430x00, 0x75, 0x73, 0x5f, 0x04, 0xc1, 0x55, 0x6e, 0x64, 0x6f,
1440x65, 0xf2, 0x00, 0x03, 0x7e, 0x00, 0x62, 0x72, 0x69, 0x67, 1440x00, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0xf2, 0x00,
1450x68, 0x74, 0x2d, 0x74, 0x00, 0x01, 0xd8, 0x02, 0x0f, 0xd8, 1450x03, 0x7e, 0x00, 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x2d,
1460x00, 0x04, 0x02, 0x99, 0x04, 0x12, 0x2c, 0xc2, 0x00, 0x03, 1460x74, 0x00, 0x01, 0xd8, 0x02, 0x0f, 0xd8, 0x00, 0x04, 0x02,
1470x17, 0x06, 0x01, 0x8e, 0x04, 0x00, 0x60, 0x03, 0x46, 0x6e, 1470x99, 0x04, 0x12, 0x2c, 0xc2, 0x00, 0x03, 0x17, 0x06, 0x01,
1480x74, 0x65, 0x72, 0x20, 0x06, 0x04, 0x42, 0x00, 0xf1, 0x02, 1480x8e, 0x04, 0x00, 0x60, 0x03, 0x46, 0x6e, 0x74, 0x65, 0x72,
1490x73, 0x00, 0x61, 0x00, 0x60, 0x70, 0x65, 0x6e, 0x63, 0x69, 1490x20, 0x06, 0x04, 0x42, 0x00, 0xf1, 0x02, 0x73, 0x00, 0x61,
1500x6c, 0x00, 0x6d, 0x61, 0x72, 0x6b, 0x27, 0x3a, 0x07, 0x01, 1500x00, 0x60, 0x70, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x00, 0x6d,
1510x70, 0x06, 0x01, 0xf8, 0x07, 0x07, 0x1b, 0x00, 0x10, 0x73, 1510x61, 0x72, 0x6b, 0x27, 0x3a, 0x07, 0x01, 0x70, 0x06, 0x01,
1520x73, 0x06, 0x04, 0x6e, 0x05, 0x04, 0x77, 0x06, 0x19, 0x73, 1520xf8, 0x07, 0x07, 0x1b, 0x00, 0x10, 0x73, 0x73, 0x06, 0x04,
1530xa3, 0x02, 0x04, 0x36, 0x01, 0x11, 0x53, 0x08, 0x00, 0x14, 1530x6e, 0x05, 0x04, 0x77, 0x06, 0x19, 0x73, 0xa3, 0x02, 0x04,
1540x73, 0x0a, 0x03, 0x00, 0x85, 0x06, 0x10, 0x66, 0x72, 0x02, 1540x36, 0x01, 0x11, 0x53, 0x08, 0x00, 0x14, 0x73, 0x0a, 0x03,
1550x45, 0x64, 0x2d, 0x69, 0x6e, 0x39, 0x00, 0x30, 0x63, 0x61, 1550x00, 0x85, 0x06, 0x10, 0x66, 0x72, 0x02, 0x45, 0x64, 0x2d,
1560x6e, 0xe3, 0x02, 0x45, 0x61, 0x6c, 0x73, 0x6f, 0x33, 0x03, 1560x69, 0x6e, 0x39, 0x00, 0x30, 0x63, 0x61, 0x6e, 0xe3, 0x02,
1570x08, 0x6f, 0x00, 0x02, 0x87, 0x02, 0x30, 0x65, 0x00, 0x67, 1570x45, 0x61, 0x6c, 0x73, 0x6f, 0x33, 0x03, 0x08, 0x6f, 0x00,
1580x5a, 0x00, 0x10, 0x70, 0xd4, 0x03, 0x40, 0x6e, 0x6f, 0x00, 1580x02, 0x87, 0x02, 0x30, 0x65, 0x00, 0x67, 0x5a, 0x00, 0x10,
1590x61, 0x4c, 0x05, 0x01, 0x6c, 0x05, 0x29, 0x74, 0x6f, 0x2e, 1590x70, 0xd4, 0x03, 0x40, 0x6e, 0x6f, 0x00, 0x61, 0x4c, 0x05,
1600x00, 0x40, 0x2c, 0x00, 0x73, 0x6f, 0xe8, 0x04, 0x10, 0x63, 1600x01, 0x6c, 0x05, 0x29, 0x74, 0x6f, 0x2e, 0x00, 0x40, 0x2c,
1610x8e, 0x04, 0x10, 0x77, 0x01, 0x01, 0x00, 0x3a, 0x01, 0x03, 1610x00, 0x73, 0x6f, 0xe8, 0x04, 0x10, 0x63, 0x8e, 0x04, 0x10,
1620x5a, 0x01, 0x11, 0x6d, 0xbb, 0x00, 0x14, 0x69, 0x41, 0x06, 1620x77, 0x01, 0x01, 0x00, 0x3a, 0x01, 0x03, 0x5a, 0x01, 0x11,
1630x63, 0x79, 0x6f, 0x75, 0x3a, 0x00, 0x79, 0xe7, 0x00, 0x05, 1630x6d, 0xbb, 0x00, 0x14, 0x69, 0x41, 0x06, 0x63, 0x79, 0x6f,
1640x23, 0x00, 0x70, 0x61, 0x73, 0x00, 0x72, 0x65, 0x6d, 0x69, 1640x75, 0x3a, 0x00, 0x79, 0xe7, 0x00, 0x05, 0x23, 0x00, 0x70,
1650xd8, 0x02, 0x14, 0x73, 0xd5, 0x03, 0xa4, 0x70, 0x61, 0x72, 1650x61, 0x73, 0x00, 0x72, 0x65, 0x6d, 0x69, 0xd8, 0x02, 0x14,
1660x74, 0x69, 0x63, 0x75, 0x6c, 0x61, 0x72, 0x32, 0x01, 0x41, 1660x73, 0xd5, 0x03, 0xa4, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63,
1670x6e, 0x65, 0x65, 0x64, 0x52, 0x08, 0x60, 0x62, 0x65, 0x00, 1670x75, 0x6c, 0x61, 0x72, 0x32, 0x01, 0x41, 0x6e, 0x65, 0x65,
1680x72, 0x65, 0x2d, 0x5a, 0x05, 0x01, 0x92, 0x07, 0x01, 0xd4, 1680x64, 0x52, 0x08, 0x60, 0x62, 0x65, 0x00, 0x72, 0x65, 0x2d,
1690x03, 0x00, 0x54, 0x00, 0x42, 0x6b, 0x6e, 0x6f, 0x77, 0xec, 1690x5a, 0x05, 0x01, 0x92, 0x07, 0x01, 0xd4, 0x03, 0x00, 0x54,
1700x03, 0x4b, 0x61, 0x62, 0x6f, 0x75, 0x45, 0x00, 0x04, 0xa2, 1700x00, 0x42, 0x6b, 0x6e, 0x6f, 0x77, 0xec, 0x03, 0x4b, 0x61,
1710x01, 0x2f, 0x6f, 0x72, 0x80, 0x00, 0x02, 0x36, 0x6c, 0x69, 1710x62, 0x6f, 0x75, 0x45, 0x00, 0x04, 0xa2, 0x01, 0x2f, 0x6f,
1720x73, 0xf8, 0x06, 0x6a, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 1720x72, 0x80, 0x00, 0x02, 0x36, 0x6c, 0x69, 0x73, 0xf8, 0x06,
1730x6a, 0x01, 0x13, 0x61, 0x83, 0x04, 0x02, 0x8d, 0x00, 0x01, 1730x6a, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 0x6a, 0x01, 0x13,
1740x48, 0x00, 0x50, 0x61, 0x6e, 0x79, 0x74, 0x68, 0x62, 0x01, 1740x61, 0x83, 0x04, 0x02, 0x8d, 0x00, 0x01, 0x48, 0x00, 0x50,
1750x32, 0x65, 0x6c, 0x73, 0x82, 0x00, 0x93, 0x66, 0x65, 0x65, 1750x61, 0x6e, 0x79, 0x74, 0x68, 0x62, 0x01, 0x32, 0x65, 0x6c,
1760x6c, 0x00, 0x6c, 0x69, 0x6b, 0x65, 0x35, 0x03, 0x41, 0x65, 1760x73, 0x82, 0x00, 0x93, 0x66, 0x65, 0x65, 0x6c, 0x00, 0x6c,
1770x72, 0x61, 0x73, 0xc2, 0x09, 0x49, 0x69, 0x6e, 0x67, 0x6c, 1770x69, 0x6b, 0x65, 0x35, 0x03, 0x41, 0x65, 0x72, 0x61, 0x73,
1780xd3, 0x01, 0x1c, 0x2c, 0x5b, 0x02, 0x08, 0x1b, 0x02, 0x22, 1780xc2, 0x09, 0x49, 0x69, 0x6e, 0x67, 0x6c, 0xd3, 0x01, 0x1c,
1790x6e, 0x64, 0x58, 0x02, 0x05, 0xde, 0x01, 0x03, 0x52, 0x02, 1790x2c, 0x5b, 0x02, 0x08, 0x1b, 0x02, 0x22, 0x6e, 0x64, 0x58,
1800x01, 0xb8, 0x02, 0x00, 0x5b, 0x00, 0x3a, 0x41, 0x6c, 0x6c, 1800x02, 0x05, 0xde, 0x01, 0x03, 0x52, 0x02, 0x01, 0xb8, 0x02,
1810x20, 0x02, 0x09, 0x9c, 0x02, 0x22, 0x72, 0x65, 0x79, 0x00, 1810x00, 0x5b, 0x00, 0x3a, 0x41, 0x6c, 0x6c, 0x20, 0x02, 0x09,
1820x30, 0x64, 0x00, 0x77, 0xa3, 0x02, 0x00, 0x99, 0x00, 0x34, 1820x9c, 0x02, 0x22, 0x72, 0x65, 0x79, 0x00, 0x30, 0x64, 0x00,
1830x6c, 0x65, 0x66, 0x6c, 0x00, 0x05, 0x5e, 0x00, 0x18, 0x61, 1830x77, 0xa3, 0x02, 0x00, 0x99, 0x00, 0x34, 0x6c, 0x65, 0x66,
1840x14, 0x01, 0x0f, 0x2a, 0x00, 0x05, 0x02, 0x43, 0x03, 0x10, 1840x6c, 0x00, 0x05, 0x5e, 0x00, 0x18, 0x61, 0x14, 0x01, 0x0f,
1850x73, 0x43, 0x03, 0x36, 0x2e, 0x00, 0x52, 0xb3, 0x00, 0x00, 1850x2a, 0x00, 0x05, 0x02, 0x43, 0x03, 0x10, 0x73, 0x43, 0x03,
1860xf7, 0x00, 0x05, 0x20, 0x00, 0x01, 0x2d, 0x0a, 0x01, 0x66, 1860x36, 0x2e, 0x00, 0x52, 0xb3, 0x00, 0x00, 0xf7, 0x00, 0x05,
1870x03, 0x03, 0x82, 0x07, 0x14, 0x73, 0xfb, 0x00, 0x0c, 0x56, 1870x20, 0x00, 0x01, 0x2d, 0x0a, 0x01, 0x66, 0x03, 0x03, 0x82,
1880x02, 0x12, 0x41, 0xcb, 0x02, 0x00, 0x66, 0x04, 0x12, 0x2c, 1880x07, 0x14, 0x73, 0xfb, 0x00, 0x0c, 0x56, 0x02, 0x12, 0x41,
1890x73, 0x08, 0x50, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x0b, 0x04, 1890xcb, 0x02, 0x00, 0x66, 0x04, 0x12, 0x2c, 0x73, 0x08, 0x50,
1900x14, 0x73, 0x6b, 0x09, 0x22, 0x75, 0x73, 0x2d, 0x03, 0x62, 1900x75, 0x72, 0x73, 0x6f, 0x72, 0x0b, 0x04, 0x14, 0x73, 0x6b,
1910x63, 0x6f, 0x6e, 0x6a, 0x75, 0x6e, 0xdf, 0x07, 0x01, 0x9c, 1910x09, 0x22, 0x75, 0x73, 0x2d, 0x03, 0x62, 0x63, 0x6f, 0x6e,
1920x04, 0x05, 0x2c, 0x07, 0x02, 0x2f, 0x00, 0x65, 0x74, 0x6f, 1920x6a, 0x75, 0x6e, 0xdf, 0x07, 0x01, 0x9c, 0x04, 0x05, 0x2c,
1930x00, 0x73, 0x65, 0x74, 0xa4, 0x01, 0x2b, 0x6f, 0x72, 0x6e, 1930x07, 0x02, 0x2f, 0x00, 0x65, 0x74, 0x6f, 0x00, 0x73, 0x65,
1940x00, 0x3d, 0x55, 0x73, 0x65, 0x63, 0x00, 0x51, 0x74, 0x6f, 1940x74, 0xa4, 0x01, 0x2b, 0x6f, 0x72, 0x6e, 0x00, 0x3d, 0x55,
1950x00, 0x6d, 0x6f, 0x55, 0x0b, 0x50, 0x68, 0x69, 0x67, 0x68, 1950x73, 0x65, 0x63, 0x00, 0x51, 0x74, 0x6f, 0x00, 0x6d, 0x6f,
1960x6c, 0xd0, 0x00, 0x21, 0x00, 0x61, 0xf6, 0x06, 0x05, 0x99, 1960x55, 0x0b, 0x50, 0x68, 0x69, 0x67, 0x68, 0x6c, 0xd0, 0x00,
1970x0a, 0x02, 0x18, 0x08, 0x09, 0xb0, 0x04, 0x22, 0x74, 0x6f, 1970x21, 0x00, 0x61, 0xf6, 0x06, 0x05, 0x99, 0x0a, 0x02, 0x18,
1980xc5, 0x03, 0x25, 0x00, 0x69, 0x18, 0x06, 0x05, 0x3f, 0x00, 1980x08, 0x09, 0xb0, 0x04, 0x22, 0x74, 0x6f, 0xc5, 0x03, 0x25,
1990x25, 0x65, 0x64, 0x7c, 0x03, 0x14, 0x50, 0x0c, 0x01, 0x50, 1990x00, 0x69, 0x18, 0x06, 0x05, 0x3f, 0x00, 0x25, 0x65, 0x64,
2000x72, 0x65, 0x74, 0x75, 0x72, 0x28, 0x03, 0x5a, 0x67, 0x67, 2000x7c, 0x03, 0x14, 0x50, 0x0c, 0x01, 0x50, 0x72, 0x65, 0x74,
2010x6c, 0x65, 0x73, 0x30, 0x00, 0x02, 0x6d, 0x0b, 0x12, 0x61, 2010x75, 0x72, 0x28, 0x03, 0x5a, 0x67, 0x67, 0x6c, 0x65, 0x73,
2020x00, 0x06, 0x85, 0x69, 0x6e, 0x00, 0x77, 0x68, 0x69, 0x63, 2020x30, 0x00, 0x02, 0x6d, 0x0b, 0x12, 0x61, 0x00, 0x06, 0x85,
2030x68, 0x93, 0x02, 0x02, 0x67, 0x00, 0x20, 0x6f, 0x72, 0x10, 2030x69, 0x6e, 0x00, 0x77, 0x68, 0x69, 0x63, 0x68, 0x93, 0x02,
2040x03, 0x2e, 0x6f, 0x76, 0x40, 0x01, 0x05, 0x63, 0x00, 0x12, 2040x02, 0x67, 0x00, 0x20, 0x6f, 0x72, 0x10, 0x03, 0x2e, 0x6f,
2050x4d, 0x6b, 0x01, 0x01, 0x37, 0x05, 0x01, 0xfd, 0x01, 0x00, 2050x76, 0x40, 0x01, 0x05, 0x63, 0x00, 0x12, 0x4d, 0x6b, 0x01,
2060x67, 0x0b, 0x01, 0x10, 0x01, 0x2d, 0x6f, 0x66, 0x1b, 0x02, 2060x01, 0x37, 0x05, 0x01, 0xfd, 0x01, 0x00, 0x67, 0x0b, 0x01,
2070x45, 0x65, 0x76, 0x65, 0x72, 0x93, 0x05, 0x01, 0x60, 0x03, 2070x10, 0x01, 0x2d, 0x6f, 0x66, 0x1b, 0x02, 0x45, 0x65, 0x76,
2080x41, 0x64, 0x6f, 0x65, 0x73, 0xe7, 0x06, 0x03, 0x63, 0x0c, 2080x65, 0x72, 0x93, 0x05, 0x01, 0x60, 0x03, 0x41, 0x64, 0x6f,
2090x10, 0x6d, 0x03, 0x04, 0x02, 0xed, 0x00, 0x41, 0x69, 0x6e, 2090x65, 0x73, 0xe7, 0x06, 0x03, 0x63, 0x0c, 0x10, 0x6d, 0x03,
2100x00, 0x69, 0x63, 0x07, 0x10, 0x28, 0x66, 0x02, 0x01, 0xc2, 2100x04, 0x02, 0xed, 0x00, 0x41, 0x69, 0x6e, 0x00, 0x69, 0x63,
2110x0a, 0x01, 0x84, 0x01, 0x92, 0x73, 0x00, 0x64, 0x65, 0x73, 2110x07, 0x10, 0x28, 0x66, 0x02, 0x01, 0xc2, 0x0a, 0x01, 0x84,
2120x63, 0x72, 0x69, 0x62, 0x9e, 0x01, 0x22, 0x73, 0x65, 0x9a, 2120x01, 0x92, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
2130x01, 0x31, 0x32, 0x2e, 0x31, 0x72, 0x02, 0x01, 0xf5, 0x01, 2130x62, 0x9e, 0x01, 0x22, 0x73, 0x65, 0x9a, 0x01, 0x31, 0x32,
2140xb2, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 2140x2e, 0x31, 0x72, 0x02, 0x01, 0xf5, 0x01, 0xb2, 0x61, 0x76,
2150x2e, 0x29, 0x8e, 0x06, 0x12, 0x32, 0x8e, 0x06, 0xb2, 0x70, 2150x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0x8e,
2160x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 2160x06, 0x12, 0x32, 0x8e, 0x06, 0xb2, 0x70, 0x61, 0x72, 0x61,
2170x5b, 0x04, 0x00, 0x1b, 0x02, 0x05, 0x14, 0x00, 0x02, 0x40, 2170x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x5b, 0x04, 0x00,
2180x00, 0x04, 0x3b, 0x00, 0x02, 0xc2, 0x0c, 0x00, 0x78, 0x00, 2180x1b, 0x02, 0x05, 0x14, 0x00, 0x02, 0x40, 0x00, 0x04, 0x3b,
2190xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 2190x00, 0x02, 0xc2, 0x0c, 0x00, 0x78, 0x00, 0xe1, 0x60, 0x43,
2200x2e, 0x27, 0x00, 0x6f, 0x70, 0x6e, 0x00, 0x03, 0x3a, 0x06, 2200x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00,
2210x50, 0x60, 0x54, 0x79, 0x70, 0x65, 0x4f, 0x09, 0x20, 0x6e, 2210x6f, 0x70, 0x6e, 0x00, 0x03, 0x3a, 0x06, 0x50, 0x60, 0x54,
2220x75, 0xaa, 0x00, 0x51, 0x47, 0x72, 0x69, 0x64, 0x20, 0x69, 2220x79, 0x70, 0x65, 0x4f, 0x09, 0x20, 0x6e, 0x75, 0xaa, 0x00,
2230x08, 0xbf, 0x00, 0x00, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 2230x51, 0x47, 0x72, 0x69, 0x64, 0x20, 0x69, 0x08, 0xbf, 0x00,
2240x69, 0x65, 0x73, 0x00, 0x0d, 0x04, 0xb0, 0x4c, 0x6f, 0x77, 2240x00, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x73,
2250x65, 0x72, 0x00, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x97, 0x04, 2250x00, 0x0d, 0x04, 0xb0, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x00,
2260x68, 0x33, 0x3b, 0x00, 0x75, 0x70, 0x70, 0x12, 0x00, 0x74, 2260x6c, 0x69, 0x6d, 0x69, 0x74, 0x97, 0x04, 0x68, 0x33, 0x3b,
2270x39, 0x00, 0x28, 0x62, 0x65, 0x63, 0x61, 0x1a, 0x06, 0x20, 2270x00, 0x75, 0x70, 0x70, 0x12, 0x00, 0x74, 0x39, 0x00, 0x28,
2280x75, 0x73, 0xf8, 0x01, 0x00, 0x97, 0x01, 0x11, 0x66, 0xe1, 2280x62, 0x65, 0x63, 0x61, 0x1a, 0x06, 0x20, 0x75, 0x73, 0xf8,
2290x02, 0x03, 0x36, 0x09, 0x42, 0x63, 0x6f, 0x6d, 0x65, 0x6c, 2290x01, 0x00, 0x97, 0x01, 0x11, 0x66, 0xe1, 0x02, 0x03, 0x36,
2300x04, 0x40, 0x64, 0x69, 0x66, 0x66, 0x64, 0x04, 0x12, 0x74, 2300x09, 0x42, 0x63, 0x6f, 0x6d, 0x65, 0x6c, 0x04, 0x40, 0x64,
2310xa5, 0x02, 0x12, 0x60, 0x5f, 0x09, 0x64, 0x27, 0x00, 0x62, 2310x69, 0x66, 0x66, 0x64, 0x04, 0x12, 0x74, 0xa5, 0x02, 0x12,
2320x69, 0x67, 0x67, 0x29, 0x0a, 0x21, 0x39, 0x21, 0x55, 0x06, 2320x60, 0x5f, 0x09, 0x64, 0x27, 0x00, 0x62, 0x69, 0x67, 0x67,
2330x14, 0x44, 0x2b, 0x00, 0x53, 0x79, 0x00, 0x00, 0x00, 0x43, 2330x29, 0x0a, 0x21, 0x39, 0x21, 0x55, 0x06, 0x14, 0x44, 0x2b,
2340xa2, 0x07, 0x03, 0xd7, 0x02, 0x05, 0x1a, 0x00, 0x04, 0xae, 2340x00, 0x53, 0x79, 0x00, 0x00, 0x00, 0x43, 0xa2, 0x07, 0x03,
2350x00, 0x41, 0x65, 0x6e, 0x65, 0x72, 0x58, 0x0c, 0x02, 0x0c, 2350xd7, 0x02, 0x05, 0x1a, 0x00, 0x04, 0xae, 0x00, 0x41, 0x65,
2360x08, 0xd1, 0x2e, 0x00, 0x41, 0x74, 0x00, 0x55, 0x6e, 0x72, 2360x6e, 0x65, 0x72, 0x58, 0x0c, 0x02, 0x0c, 0x08, 0xd1, 0x2e,
2370x65, 0x61, 0x73, 0x6f, 0x6e, 0x28, 0x01, 0x50, 0x6c, 0x65, 2370x00, 0x41, 0x74, 0x00, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x73,
2380x76, 0x65, 0x6c, 0x7d, 0x05, 0x70, 0x6d, 0x65, 0x00, 0x62, 2380x6f, 0x6e, 0x28, 0x01, 0x50, 0x6c, 0x65, 0x76, 0x65, 0x6c,
2390x61, 0x63, 0x6b, 0x0c, 0x0b, 0x01, 0x98, 0x03, 0x04, 0x79, 2390x7d, 0x05, 0x70, 0x6d, 0x65, 0x00, 0x62, 0x61, 0x63, 0x6b,
2400x06, 0x10, 0x72, 0x28, 0x0a, 0x73, 0x72, 0x65, 0x64, 0x2c, 2400x0c, 0x0b, 0x01, 0x98, 0x03, 0x04, 0x79, 0x06, 0x10, 0x72,
2410x00, 0x62, 0x75, 0x37, 0x0c, 0x31, 0x6f, 0x6c, 0x75, 0x48, 2410x28, 0x0a, 0x73, 0x72, 0x65, 0x64, 0x2c, 0x00, 0x62, 0x75,
2420x01, 0x21, 0x73, 0x68, 0xc8, 0x00, 0x23, 0x73, 0x74, 0x2b, 2420x37, 0x0c, 0x31, 0x6f, 0x6c, 0x75, 0x48, 0x01, 0x21, 0x73,
2430x00, 0x42, 0x75, 0x6e, 0x69, 0x71, 0x85, 0x0c, 0x10, 0x65, 2430x68, 0xc8, 0x00, 0x23, 0x73, 0x74, 0x2b, 0x00, 0x42, 0x75,
2440x7b, 0x02, 0x03, 0x3a, 0x06, 0x01, 0x62, 0x00, 0x14, 0x73, 2440x6e, 0x69, 0x71, 0x85, 0x0c, 0x10, 0x65, 0x7b, 0x02, 0x03,
2450x48, 0x00, 0x00, 0x64, 0x07, 0x00, 0x7f, 0x00, 0x00, 0xcc, 2450x3a, 0x06, 0x01, 0x62, 0x00, 0x14, 0x73, 0x48, 0x00, 0x00,
2460x04, 0x00, 0x6b, 0x09, 0x00, 0xd8, 0x0a, 0x22, 0x78, 0x00, 2460x64, 0x07, 0x00, 0x7f, 0x00, 0x00, 0xcc, 0x04, 0x00, 0x6b,
2470x91, 0x00, 0x01, 0xed, 0x0c, 0x00, 0x00, 0x02, 0x30, 0x6f, 2470x09, 0x00, 0xd8, 0x0a, 0x22, 0x78, 0x00, 0x91, 0x00, 0x01,
2480x69, 0x64, 0x54, 0x02, 0x03, 0x10, 0x00, 0x05, 0x97, 0x00, 2480xed, 0x0c, 0x00, 0x00, 0x02, 0x30, 0x6f, 0x69, 0x64, 0x54,
2490x00, 0xfe, 0x00, 0x19, 0x4d, 0x2e, 0x0c, 0x11, 0x20, 0x98, 2490x02, 0x03, 0x10, 0x00, 0x05, 0x97, 0x00, 0x00, 0xfe, 0x00,
2500x0d, 0x01, 0x69, 0x07, 0x10, 0x74, 0xf2, 0x08, 0x00, 0xf1, 2500x19, 0x4d, 0x2e, 0x0c, 0x11, 0x20, 0x98, 0x0d, 0x01, 0x69,
2510x09, 0x01, 0xd8, 0x00, 0x00, 0x81, 0x03, 0x00, 0x95, 0x00, 2510x07, 0x10, 0x74, 0xf2, 0x08, 0x00, 0xf1, 0x09, 0x01, 0xd8,
2520x45, 0x6f, 0x78, 0x65, 0x73, 0xcb, 0x00, 0x0b, 0x6a, 0x0c, 2520x00, 0x00, 0x81, 0x03, 0x00, 0x95, 0x00, 0x45, 0x6f, 0x78,
2530x01, 0x1d, 0x00, 0x32, 0x2e, 0x00, 0x57, 0x16, 0x04, 0x03, 2530x65, 0x73, 0xcb, 0x00, 0x0b, 0x6a, 0x0c, 0x01, 0x1d, 0x00,
2540x8c, 0x09, 0x02, 0x51, 0x04, 0x03, 0x3a, 0x09, 0x21, 0x69, 2540x32, 0x2e, 0x00, 0x57, 0x16, 0x04, 0x03, 0x8c, 0x09, 0x02,
2550x73, 0x0f, 0x06, 0x10, 0x6e, 0xdc, 0x05, 0xf0, 0x02, 0x60, 2550x51, 0x04, 0x03, 0x3a, 0x09, 0x21, 0x69, 0x73, 0x0f, 0x06,
2560x49, 0x6e, 0x73, 0x68, 0x69, 0x00, 0x4e, 0x6f, 0x00, 0x48, 2560x10, 0x6e, 0xdc, 0x05, 0xf0, 0x02, 0x60, 0x49, 0x6e, 0x73,
2570x65, 0x79, 0x61, 0x27, 0x2e, 0x00, 2570x68, 0x69, 0x00, 0x4e, 0x6f, 0x00, 0x48, 0x65, 0x79, 0x61,
2580x27, 0x2e, 0x00,
258}; 259};
259 260
260const unsigned short help_text_len = 3952; 261const unsigned short help_text_len = 3969;
261const unsigned short help_text_words = 761; 262const unsigned short help_text_words = 762;
262const char quick_help_text[] = "Complete the latin square in accordance with the arithmetic clues."; 263const char quick_help_text[] = "Complete the latin square in accordance with the arithmetic clues.";
diff --git a/apps/plugins/puzzles/help/lightup.c b/apps/plugins/puzzles/help/lightup.c
index 5562b954b7..874a05c596 100644
--- a/apps/plugins/puzzles/help/lightup.c
+++ b/apps/plugins/puzzles/help/lightup.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,176 +6,189 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 169, TEXT_CENTER | C_RED }, 9 { 167, TEXT_CENTER | C_RED },
10 { 304, TEXT_CENTER | C_RED }, 10 { 302, TEXT_CENTER | C_RED },
11 { 321, TEXT_UNDERLINE }, 11 { 319, TEXT_UNDERLINE },
12 { 322, TEXT_UNDERLINE }, 12 { 320, TEXT_UNDERLINE },
13 { 332, TEXT_UNDERLINE }, 13 { 330, TEXT_UNDERLINE },
14 { 380, TEXT_UNDERLINE }, 14 { 378, TEXT_UNDERLINE },
15 { 409, TEXT_UNDERLINE }, 15 { 407, TEXT_UNDERLINE },
16 { 433, TEXT_CENTER | C_RED },
16 LAST_STYLE_ITEM 17 LAST_STYLE_ITEM
17}; 18};
18 19
19/* orig 2327 comp 1558 ratio 0.669532 level 10 saved 769 */ 20/* orig 2549 comp 1677 ratio 0.657905 level 10 saved 872 */
20const char help_text[] = { 21const char help_text[] = {
210xf0, 0x40, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 220xff, 0x08, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
220x32, 0x31, 0x3a, 0x20, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x20, 230x32, 0x31, 0x3a, 0x20, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x20,
230x55, 0x70, 0x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 240x55, 0x70, 0x20, 0x00, 0x2d, 0x01, 0x00, 0x00, 0xf0, 0x2b,
240x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 250x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76,
250x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 260x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f,
260x65, 0x73, 0x2e, 0x00, 0x53, 0x6f, 0x6d, 0x65, 0x00, 0x61, 270x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2e,
270x72, 0x65, 0x00, 0x66, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x00, 280x00, 0x53, 0x6f, 0x6d, 0x65, 0x00, 0x61, 0x72, 0x65, 0x00,
280x69, 0x6e, 0x00, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x3b, 0x00, 290x66, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x00, 0x69, 0x6e, 0x00,
290x73, 0x1a, 0x00, 0x62, 0x6f, 0x66, 0x00, 0x74, 0x68, 0x65, 300x62, 0x6c, 0x61, 0x63, 0x6b, 0x3b, 0x00, 0x73, 0x1a, 0x00,
300x13, 0x00, 0x04, 0x35, 0x00, 0x01, 0x2f, 0x00, 0x90, 0x6e, 310x62, 0x6f, 0x66, 0x00, 0x74, 0x68, 0x65, 0x13, 0x00, 0x04,
310x75, 0x6d, 0x62, 0x65, 0x72, 0x65, 0x64, 0x2e, 0x5e, 0x00, 320x35, 0x00, 0x01, 0x2f, 0x00, 0x90, 0x6e, 0x75, 0x6d, 0x62,
320xe0, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 0x69, 0x73, 0x00, 330x65, 0x72, 0x65, 0x64, 0x2e, 0x5e, 0x00, 0xe0, 0x72, 0x00,
330x74, 0x6f, 0x00, 0x60, 0x6c, 0x7a, 0x00, 0x81, 0x00, 0x75, 340x61, 0x69, 0x6d, 0x00, 0x69, 0x73, 0x00, 0x74, 0x6f, 0x00,
340x70, 0x27, 0x00, 0x61, 0x6c, 0x6c, 0x3e, 0x00, 0x55, 0x65, 350x60, 0x6c, 0x8f, 0x00, 0x81, 0x00, 0x75, 0x70, 0x27, 0x00,
350x6d, 0x70, 0x74, 0x79, 0x3e, 0x00, 0xb2, 0x62, 0x79, 0x00, 360x61, 0x6c, 0x6c, 0x3e, 0x00, 0x55, 0x65, 0x6d, 0x70, 0x74,
360x70, 0x6c, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x00, 0x2b, 0x00, 370x79, 0x3e, 0x00, 0xb2, 0x62, 0x79, 0x00, 0x70, 0x6c, 0x61,
370x50, 0x62, 0x75, 0x6c, 0x62, 0x73, 0x79, 0x00, 0x07, 0x72, 380x63, 0x69, 0x6e, 0x67, 0x00, 0x2b, 0x00, 0x50, 0x62, 0x75,
380x00, 0x97, 0x6d, 0x2e, 0x00, 0x00, 0x00, 0x45, 0x61, 0x63, 390x6c, 0x62, 0x73, 0x79, 0x00, 0x07, 0x72, 0x00, 0x97, 0x6d,
390x68, 0x24, 0x00, 0xc1, 0x00, 0x69, 0x6c, 0x6c, 0x75, 0x6d, 400x2e, 0x00, 0x00, 0x00, 0x45, 0x61, 0x63, 0x68, 0x24, 0x00,
400x69, 0x6e, 0x61, 0x74, 0x65, 0x73, 0x58, 0x00, 0x02, 0x52, 410xc1, 0x00, 0x69, 0x6c, 0x6c, 0x75, 0x6d, 0x69, 0x6e, 0x61,
410x00, 0x30, 0x00, 0x69, 0x74, 0x7b, 0x00, 0x81, 0x6f, 0x6e, 420x74, 0x65, 0x73, 0x58, 0x00, 0x02, 0x52, 0x00, 0x30, 0x00,
420x2c, 0x00, 0x70, 0x6c, 0x75, 0x73, 0x76, 0x00, 0x04, 0x6c, 430x69, 0x74, 0x7b, 0x00, 0x81, 0x6f, 0x6e, 0x2c, 0x00, 0x70,
430x00, 0xc0, 0x69, 0x6e, 0x00, 0x6c, 0x69, 0x6e, 0x65, 0x00, 440x6c, 0x75, 0x73, 0x76, 0x00, 0x04, 0x6c, 0x00, 0xc0, 0x69,
440x77, 0x69, 0x74, 0x68, 0x28, 0x00, 0xf1, 0x07, 0x68, 0x6f, 450x6e, 0x00, 0x6c, 0x69, 0x6e, 0x65, 0x00, 0x77, 0x69, 0x74,
450x72, 0x69, 0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x6c, 0x79, 460x68, 0x28, 0x00, 0xf1, 0x07, 0x68, 0x6f, 0x72, 0x69, 0x7a,
460x00, 0x6f, 0x72, 0x00, 0x76, 0x65, 0x72, 0x74, 0x69, 0x63, 470x6f, 0x6e, 0x74, 0x61, 0x6c, 0x6c, 0x79, 0x00, 0x6f, 0x72,
470x0e, 0x00, 0x89, 0x75, 0x6e, 0x6c, 0x65, 0x73, 0x73, 0x00, 480x00, 0x76, 0x65, 0x72, 0x74, 0x69, 0x63, 0x0e, 0x00, 0x89,
480x61, 0xec, 0x00, 0x00, 0x59, 0x00, 0x50, 0x62, 0x6c, 0x6f, 490x75, 0x6e, 0x6c, 0x65, 0x73, 0x73, 0x00, 0x61, 0xec, 0x00,
490x63, 0x6b, 0xae, 0x00, 0x00, 0x73, 0x00, 0x30, 0x77, 0x61, 500x00, 0x59, 0x00, 0x50, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0xae,
500x79, 0x9a, 0x00, 0x61, 0x54, 0x6f, 0x00, 0x77, 0x69, 0x6e, 510x00, 0x00, 0x73, 0x00, 0x30, 0x77, 0x61, 0x79, 0x9a, 0x00,
510x12, 0x00, 0xf1, 0x07, 0x67, 0x61, 0x6d, 0x65, 0x2c, 0x00, 520x61, 0x54, 0x6f, 0x00, 0x77, 0x69, 0x6e, 0x12, 0x00, 0xf1,
520x79, 0x6f, 0x75, 0x00, 0x6d, 0x75, 0x73, 0x74, 0x00, 0x73, 530x07, 0x67, 0x61, 0x6d, 0x65, 0x2c, 0x00, 0x79, 0x6f, 0x75,
530x61, 0x74, 0x69, 0x73, 0x66, 0x79, 0x1b, 0x00, 0x60, 0x66, 540x00, 0x6d, 0x75, 0x73, 0x74, 0x00, 0x73, 0x61, 0x74, 0x69,
540x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x3b, 0x00, 0xfe, 0x09, 0x63, 550x73, 0x66, 0x79, 0x1b, 0x00, 0x60, 0x66, 0x6f, 0x6c, 0x6c,
550x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 560x6f, 0x77, 0x3b, 0x00, 0xfe, 0x09, 0x63, 0x6f, 0x6e, 0x64,
560x00, 0x00, 0x00, 0x2d, 0x00, 0x41, 0x6c, 0x6c, 0x00, 0x6e, 570x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x00, 0x00, 0x00,
570x6f, 0x6e, 0x2d, 0x58, 0x01, 0x41, 0x6c, 0x69, 0x74, 0x2e, 580x2d, 0x00, 0x41, 0x6c, 0x6c, 0x00, 0x6e, 0x6f, 0x6e, 0x2d,
580x23, 0x00, 0x23, 0x4e, 0x6f, 0xfb, 0x00, 0x20, 0x69, 0x73, 590x58, 0x01, 0x41, 0x6c, 0x69, 0x74, 0x2e, 0x23, 0x00, 0x23,
590x15, 0x00, 0x00, 0x37, 0x01, 0x72, 0x61, 0x6e, 0x6f, 0x74, 600x4e, 0x6f, 0xfb, 0x00, 0x20, 0x69, 0x73, 0x15, 0x00, 0x00,
600x68, 0x65, 0x72, 0x18, 0x00, 0x16, 0x2e, 0x49, 0x00, 0x03, 610x37, 0x01, 0x72, 0x61, 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72,
610x8b, 0x01, 0x0b, 0xa6, 0x01, 0x01, 0xf2, 0x01, 0x60, 0x65, 620x18, 0x00, 0x16, 0x2e, 0x49, 0x00, 0x03, 0x8b, 0x01, 0x0b,
620x78, 0x61, 0x63, 0x74, 0x6c, 0x8f, 0x00, 0x23, 0x61, 0x74, 630xa6, 0x01, 0x01, 0xf2, 0x01, 0x60, 0x65, 0x78, 0x61, 0x63,
630x29, 0x00, 0x00, 0x62, 0x01, 0x01, 0x42, 0x00, 0xa0, 0x73, 640x74, 0x6c, 0x8f, 0x00, 0x23, 0x61, 0x74, 0x29, 0x00, 0x00,
640x00, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x65, 0x6e, 0x74, 0xb8, 650x62, 0x01, 0x01, 0x42, 0x00, 0xa0, 0x73, 0x00, 0x61, 0x64,
650x01, 0x00, 0x75, 0x01, 0x23, 0x00, 0x28, 0xd5, 0x00, 0x10, 660x6a, 0x61, 0x63, 0x65, 0x6e, 0x74, 0xb8, 0x01, 0x00, 0x75,
660x66, 0xd4, 0x01, 0x05, 0x97, 0x00, 0xf3, 0x01, 0x62, 0x6f, 670x01, 0x23, 0x00, 0x28, 0xd5, 0x00, 0x10, 0x66, 0xd4, 0x01,
670x76, 0x65, 0x2c, 0x00, 0x62, 0x65, 0x6c, 0x6f, 0x77, 0x2c, 680x05, 0x97, 0x00, 0xf3, 0x01, 0x62, 0x6f, 0x76, 0x65, 0x2c,
680x00, 0x61, 0x6e, 0x64, 0x2f, 0x00, 0x60, 0x00, 0x73, 0x69, 690x00, 0x62, 0x65, 0x6c, 0x6f, 0x77, 0x2c, 0x00, 0x61, 0x6e,
690x64, 0x65, 0x29, 0x88, 0x00, 0x4f, 0x4e, 0x6f, 0x6e, 0x2d, 700x64, 0x2f, 0x00, 0x60, 0x00, 0x73, 0x69, 0x64, 0x65, 0x29,
700x86, 0x00, 0x04, 0x33, 0x6d, 0x61, 0x79, 0x7c, 0x02, 0x2f, 710x88, 0x00, 0x4f, 0x4e, 0x6f, 0x6e, 0x2d, 0x86, 0x00, 0x04,
710x6e, 0x79, 0x81, 0x00, 0x0f, 0x00, 0x4d, 0x00, 0xf1, 0x0b, 720x33, 0x6d, 0x61, 0x79, 0x7c, 0x02, 0x2f, 0x6e, 0x79, 0x81,
720x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x00, 0x66, 0x6f, 0x72, 730x00, 0x0f, 0x00, 0x4d, 0x00, 0xf1, 0x0b, 0x43, 0x72, 0x65,
730x00, 0x74, 0x68, 0x69, 0x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 740x64, 0x69, 0x74, 0x00, 0x66, 0x6f, 0x72, 0x00, 0x74, 0x68,
740x6c, 0x65, 0x00, 0x67, 0x6f, 0x65, 0x60, 0x02, 0xa0, 0x4e, 750x69, 0x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00,
750x69, 0x6b, 0x6f, 0x6c, 0x69, 0x00, 0x5b, 0x39, 0x5d, 0x2d, 760x67, 0x6f, 0x65, 0x60, 0x02, 0xa0, 0x4e, 0x69, 0x6b, 0x6f,
760x00, 0x11, 0x4c, 0x23, 0x01, 0x60, 0x55, 0x70, 0x00, 0x77, 770x6c, 0x69, 0x00, 0x5b, 0x39, 0x5d, 0x2d, 0x00, 0x11, 0x4c,
770x61, 0x73, 0x66, 0x01, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 780x23, 0x01, 0x60, 0x55, 0x70, 0x00, 0x77, 0x61, 0x73, 0x66,
780x74, 0x65, 0xa3, 0x00, 0x10, 0x69, 0x14, 0x00, 0x40, 0x6c, 790x01, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0xa3,
790x6c, 0x65, 0x63, 0x7b, 0x01, 0x00, 0x42, 0x01, 0xb1, 0x4a, 800x00, 0x10, 0x69, 0x14, 0x00, 0x40, 0x6c, 0x6c, 0x65, 0x63,
800x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61, 0x72, 0x76, 0x65, 810x7b, 0x01, 0x00, 0x42, 0x01, 0xb1, 0x4a, 0x61, 0x6d, 0x65,
810xc8, 0x01, 0xf1, 0x01, 0x5b, 0x39, 0x5d, 0x00, 0x68, 0x74, 820x73, 0x00, 0x48, 0x61, 0x72, 0x76, 0x65, 0xc8, 0x01, 0xf1,
820x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 830x02, 0x5b, 0x39, 0x5d, 0x00, 0x68, 0x74, 0x74, 0x70, 0x73,
830x5c, 0x00, 0xa2, 0x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f, 840x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 0x5d, 0x00,
840x65, 0x6e, 0x2f, 0x7b, 0x00, 0xf1, 0x04, 0x73, 0x2f, 0x61, 850xa2, 0x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f, 0x65, 0x6e,
850x6b, 0x61, 0x72, 0x69, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x00, 860x2f, 0x7c, 0x00, 0xf6, 0x00, 0x73, 0x2f, 0x61, 0x6b, 0x61,
860x28, 0x62, 0x65, 0x77, 0x61, 0x72, 0xa7, 0x02, 0xd6, 0x46, 870x72, 0x69, 0x2f, 0x00, 0x00, 0x00, 0x32, 0x31, 0x2e, 0x31,
870x6c, 0x61, 0x73, 0x68, 0x29, 0x00, 0x00, 0x00, 0x32, 0x31, 880x71, 0x03, 0x01, 0x71, 0x00, 0x40, 0x6f, 0x6c, 0x73, 0x20,
880x2e, 0x31, 0x71, 0x03, 0x01, 0x86, 0x00, 0x40, 0x6f, 0x6c, 890x8a, 0x00, 0x72, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69,
890x73, 0x20, 0x9f, 0x00, 0x72, 0x65, 0x66, 0x74, 0x2d, 0x63, 900x2c, 0x02, 0x4d, 0x69, 0x6e, 0x00, 0x61, 0xe2, 0x01, 0x30,
900x6c, 0x69, 0x41, 0x02, 0x4d, 0x69, 0x6e, 0x00, 0x61, 0xf7, 910x00, 0x77, 0x69, 0x12, 0x03, 0x51, 0x6f, 0x67, 0x67, 0x6c,
910x01, 0x30, 0x00, 0x77, 0x69, 0x27, 0x03, 0x51, 0x6f, 0x67, 920x65, 0x41, 0x01, 0x71, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e,
920x67, 0x6c, 0x65, 0x56, 0x01, 0x71, 0x70, 0x72, 0x65, 0x73, 930x63, 0xf5, 0x02, 0x14, 0x61, 0xef, 0x01, 0x12, 0x6e, 0xad,
930x65, 0x6e, 0x63, 0x63, 0x00, 0x14, 0x61, 0x04, 0x02, 0x12, 940x01, 0x02, 0x33, 0x00, 0x30, 0x2e, 0x00, 0x52, 0x16, 0x00,
940x6e, 0xc2, 0x01, 0x02, 0x33, 0x00, 0x30, 0x2e, 0x00, 0x52, 950x0f, 0x59, 0x00, 0x0d, 0x02, 0x54, 0x00, 0x00, 0xbe, 0x02,
950x16, 0x00, 0x0f, 0x59, 0x00, 0x0d, 0x02, 0x54, 0x00, 0x00, 960x40, 0x6d, 0x61, 0x72, 0x6b, 0x5c, 0x00, 0x01, 0x15, 0x00,
960xd3, 0x02, 0x40, 0x6d, 0x61, 0x72, 0x6b, 0x5c, 0x00, 0x01, 970xd0, 0x00, 0x61, 0x69, 0x64, 0x00, 0x73, 0x6f, 0x6c, 0x76,
970x15, 0x00, 0xd0, 0x00, 0x61, 0x69, 0x64, 0x00, 0x73, 0x6f, 980x69, 0x6e, 0x67, 0x3b, 0x00, 0x03, 0x92, 0x63, 0x61, 0x6e,
980x6c, 0x76, 0x69, 0x6e, 0x67, 0x3b, 0x15, 0x03, 0x92, 0x63, 990x00, 0x62, 0x65, 0x00, 0x75, 0x73, 0x22, 0x01, 0x42, 0x68,
990x61, 0x6e, 0x00, 0x62, 0x65, 0x00, 0x75, 0x73, 0x37, 0x01, 1000x69, 0x67, 0x68, 0x76, 0x00, 0x04, 0xaf, 0x01, 0x01, 0x7b,
1000x42, 0x68, 0x69, 0x67, 0x68, 0x76, 0x00, 0x04, 0xc4, 0x01, 1010x00, 0x81, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x00, 0x62,
1010x01, 0x7b, 0x00, 0x81, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 1020x8e, 0x02, 0x11, 0x2c, 0x8a, 0x01, 0x83, 0x65, 0x78, 0x61,
1020x00, 0x62, 0xa3, 0x02, 0x11, 0x2c, 0x9f, 0x01, 0x83, 0x65, 1030x6d, 0x70, 0x6c, 0x65, 0x2e, 0x4e, 0x04, 0x00, 0xd6, 0x01,
1030x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x04, 0x00, 1040x00, 0x23, 0x00, 0x00, 0xc9, 0x03, 0x18, 0x65, 0xbb, 0x00,
1040xeb, 0x01, 0x00, 0x23, 0x00, 0x00, 0xde, 0x03, 0x18, 0x65, 1050x02, 0x81, 0x00, 0x23, 0x65, 0x64, 0x51, 0x00, 0x55, 0x2c,
1050xbb, 0x00, 0x02, 0x81, 0x00, 0x23, 0x65, 0x64, 0x51, 0x00, 1060x00, 0x6e, 0x6f, 0x72, 0x26, 0x00, 0x01, 0x9c, 0x00, 0x21,
1060x55, 0x2c, 0x00, 0x6e, 0x6f, 0x72, 0x26, 0x00, 0x01, 0x9c, 1070x69, 0x6e, 0x30, 0x00, 0x06, 0xe1, 0x00, 0x33, 0x00, 0x00,
1070x00, 0x21, 0x69, 0x6e, 0x30, 0x00, 0x06, 0xe1, 0x00, 0x33, 1080x54, 0x47, 0x03, 0x02, 0x20, 0x01, 0x06, 0x95, 0x00, 0xd1,
1080x00, 0x00, 0x54, 0x5c, 0x03, 0x02, 0x20, 0x01, 0x06, 0x95, 1090x6f, 0x62, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x00, 0x65, 0x72,
1090x00, 0xd1, 0x6f, 0x62, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x00, 1100x72, 0x6f, 0x72, 0xcd, 0x03, 0x01, 0x71, 0x04, 0x01, 0x7f,
1100x65, 0x72, 0x72, 0x6f, 0x72, 0xe2, 0x03, 0x01, 0x86, 0x04, 1110x01, 0x05, 0x15, 0x03, 0x07, 0x13, 0x03, 0x02, 0x42, 0x03,
1110x01, 0x7f, 0x01, 0x05, 0x2a, 0x03, 0x07, 0x28, 0x03, 0x02, 1120x05, 0x40, 0x00, 0x02, 0xce, 0x04, 0x01, 0x06, 0x02, 0x6a,
1120x57, 0x03, 0x05, 0x40, 0x00, 0x02, 0xe3, 0x04, 0x01, 0x1b, 1130x77, 0x61, 0x79, 0x2c, 0x00, 0x61, 0xba, 0x04, 0x05, 0xf4,
1130x02, 0x6a, 0x77, 0x61, 0x79, 0x2c, 0x00, 0x61, 0xcf, 0x04, 1140x00, 0x81, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x64, 0x6f,
1140x05, 0xf4, 0x00, 0x81, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 1150xd2, 0x00, 0x33, 0x28, 0x6f, 0x72, 0x00, 0x01, 0x12, 0x29,
1150x64, 0x6f, 0xd2, 0x00, 0x33, 0x28, 0x6f, 0x72, 0x00, 0x01, 1160xb8, 0x02, 0x00, 0xa8, 0x01, 0x11, 0x72, 0x8f, 0x00, 0x0d,
1160x12, 0x29, 0xcd, 0x02, 0x00, 0xa8, 0x01, 0x11, 0x72, 0x8f, 1170xbe, 0x02, 0x39, 0x6e, 0x65, 0x78, 0xba, 0x02, 0x52, 0x54,
1170x00, 0x0d, 0xd3, 0x02, 0x39, 0x6e, 0x65, 0x78, 0xcf, 0x02, 1180x68, 0x75, 0x73, 0x2c, 0x15, 0x04, 0x00, 0x67, 0x05, 0x21,
1180x52, 0x54, 0x68, 0x75, 0x73, 0x2c, 0x2a, 0x04, 0x00, 0x7c, 1190x69, 0x73, 0x7c, 0x01, 0x9e, 0x65, 0x64, 0x00, 0x77, 0x68,
1190x05, 0x21, 0x69, 0x73, 0x7c, 0x01, 0x9e, 0x65, 0x64, 0x00, 1200x65, 0x6e, 0x00, 0x61, 0xf4, 0x03, 0x04, 0xa6, 0x03, 0x20,
1200x77, 0x68, 0x65, 0x6e, 0x00, 0x61, 0x09, 0x04, 0x04, 0xbb, 1210x79, 0x65, 0x29, 0x04, 0x06, 0xba, 0x00, 0x12, 0x73, 0x66,
1210x03, 0x20, 0x79, 0x65, 0x3e, 0x04, 0x06, 0xba, 0x00, 0x12, 1220x03, 0x01, 0xc6, 0x01, 0x01, 0xb3, 0x00, 0x10, 0x6f, 0xfa,
1220x73, 0x7b, 0x03, 0x01, 0xc6, 0x01, 0x01, 0xb3, 0x00, 0x10, 1230x00, 0x03, 0x77, 0x00, 0x00, 0x6a, 0x00, 0x23, 0x28, 0x41,
1230x6f, 0xfa, 0x00, 0x03, 0x77, 0x00, 0x00, 0x6a, 0x00, 0x23, 1240x5b, 0x05, 0x21, 0x61, 0x63, 0x56, 0x04, 0x82, 0x00, 0x64,
1240x28, 0x41, 0x70, 0x05, 0x21, 0x61, 0x63, 0x6b, 0x04, 0x82, 1250x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0xf3, 0x00, 0x13, 0x73,
1250x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0xf3, 0x00, 1260xf1, 0x02, 0x31, 0x32, 0x2e, 0x31, 0x3f, 0x00, 0xf2, 0x01,
1260x13, 0x73, 0x06, 0x03, 0x31, 0x32, 0x2e, 0x31, 0x3f, 0x00, 1270x61, 0x6c, 0x73, 0x6f, 0x00, 0x61, 0x76, 0x61, 0x69, 0x6c,
1270xf3, 0x00, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0x61, 0x76, 0x61, 1280x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0xc8, 0x02, 0x16, 0x32,
1280x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0xc8, 0x02, 0x16, 1290xc8, 0x02, 0xb2, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74,
1290x32, 0xc8, 0x02, 0xb2, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 1300x65, 0x72, 0x73, 0x20, 0x8f, 0x01, 0x36, 0x73, 0x65, 0x00,
1300x74, 0x65, 0x72, 0x73, 0x20, 0x8f, 0x01, 0x36, 0x73, 0x65, 1310x14, 0x00, 0x02, 0x44, 0x00, 0x04, 0x3f, 0x00, 0x51, 0x00,
1310x00, 0x14, 0x00, 0x02, 0x44, 0x00, 0x04, 0x3f, 0x00, 0x51, 1320x66, 0x72, 0x6f, 0x6d, 0x7c, 0x00, 0xe1, 0x60, 0x43, 0x75,
1320x00, 0x66, 0x72, 0x6f, 0x6d, 0x7c, 0x00, 0xe1, 0x60, 0x43, 1330x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f,
1330x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 1340x70, 0x72, 0x00, 0x22, 0x6f, 0x6e, 0x1a, 0x00, 0xa0, 0x54,
1340x6f, 0x70, 0x72, 0x00, 0x22, 0x6f, 0x6e, 0x1a, 0x00, 0xa0, 1350x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xae,
1350x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 1360x00, 0x91, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48,
1360xae, 0x00, 0x91, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 1370x65, 0x47, 0x01, 0x51, 0x00, 0x00, 0x53, 0x69, 0x7a, 0xf3,
1370x48, 0x65, 0x47, 0x01, 0x51, 0x00, 0x00, 0x53, 0x69, 0x7a, 1380x02, 0x02, 0x26, 0x01, 0x16, 0x6e, 0x8d, 0x06, 0xa1, 0x00,
1380xf3, 0x02, 0x02, 0x26, 0x01, 0x16, 0x6e, 0xa2, 0x06, 0xa1, 1390x00, 0x25, 0x61, 0x67, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x25,
1390x00, 0x00, 0x25, 0x61, 0x67, 0x65, 0x20, 0x6f, 0x66, 0x20, 1400x01, 0x14, 0x20, 0x25, 0x01, 0xb0, 0x00, 0x00, 0x52, 0x6f,
1400x25, 0x01, 0x14, 0x20, 0x25, 0x01, 0xb0, 0x00, 0x00, 0x52, 1410x75, 0x67, 0x68, 0x00, 0x70, 0x65, 0x72, 0x2e, 0x04, 0x21,
1410x6f, 0x75, 0x67, 0x68, 0x00, 0x70, 0x65, 0x72, 0x43, 0x04, 1420x61, 0x67, 0x3f, 0x00, 0x0a, 0x49, 0x01, 0x25, 0x69, 0x6e,
1420x21, 0x61, 0x67, 0x3f, 0x00, 0x0a, 0x49, 0x01, 0x25, 0x69, 1430x7a, 0x01, 0x02, 0x8c, 0x01, 0x40, 0x69, 0x73, 0x00, 0x69,
1430x6e, 0x7a, 0x01, 0x02, 0x8c, 0x01, 0x40, 0x69, 0x73, 0x00, 1440x12, 0x03, 0x71, 0x68, 0x69, 0x6e, 0x74, 0x00, 0x72, 0x61,
1440x69, 0x12, 0x03, 0x71, 0x68, 0x69, 0x6e, 0x74, 0x00, 0x72, 1450x27, 0x02, 0xe1, 0x74, 0x68, 0x61, 0x6e, 0x00, 0x61, 0x6e,
1450x61, 0x27, 0x02, 0xe1, 0x74, 0x68, 0x61, 0x6e, 0x00, 0x61, 1460x00, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x26, 0x01, 0x46,
1460x6e, 0x00, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x26, 0x01, 1470x2e, 0x00, 0x49, 0x66, 0xb4, 0x01, 0x90, 0x67, 0x65, 0x6e,
1470x46, 0x2e, 0x00, 0x49, 0x66, 0xb4, 0x01, 0x90, 0x67, 0x65, 1480x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x00, 0x21, 0x75,
1480x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x00, 0x21, 1490x6e, 0xf1, 0x00, 0x24, 0x74, 0x6f, 0x17, 0x00, 0x00, 0xc5,
1490x75, 0x6e, 0xf1, 0x00, 0x24, 0x74, 0x6f, 0x17, 0x00, 0x00, 1500x02, 0x03, 0x8f, 0x04, 0x04, 0x60, 0x04, 0xf0, 0x02, 0x70,
1500xc5, 0x02, 0x03, 0xa4, 0x04, 0x04, 0x75, 0x04, 0xf0, 0x02, 1510x72, 0x65, 0x63, 0x69, 0x73, 0x65, 0x00, 0x73, 0x70, 0x65,
1510x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x65, 0x00, 0x73, 0x70, 1520x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x54, 0x00, 0x10, 0x2c,
1520x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x54, 0x00, 0x10, 1530x6c, 0x03, 0x01, 0xcd, 0x02, 0x74, 0x69, 0x6e, 0x63, 0x72,
1530x2c, 0x6c, 0x03, 0x01, 0xcd, 0x02, 0x74, 0x69, 0x6e, 0x63, 1540x65, 0x61, 0x73, 0xef, 0x03, 0x42, 0x6f, 0x70, 0x6f, 0x72,
1540x72, 0x65, 0x61, 0x73, 0xef, 0x03, 0x42, 0x6f, 0x70, 0x6f, 1550x29, 0x01, 0x0c, 0xbf, 0x00, 0x53, 0x75, 0x6e, 0x74, 0x69,
1550x72, 0x29, 0x01, 0x0c, 0xbf, 0x00, 0x53, 0x75, 0x6e, 0x74, 1560x6c, 0xa3, 0x03, 0x10, 0x2e, 0x24, 0x01, 0xb0, 0x79, 0x6d,
1560x69, 0x6c, 0xa3, 0x03, 0x10, 0x2e, 0x24, 0x01, 0xb0, 0x79, 1570x6d, 0x65, 0x74, 0x72, 0x79, 0x00, 0x00, 0x00, 0x41, 0x1d,
1570x6d, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x00, 0x00, 0x00, 0x41, 1580x02, 0x11, 0x73, 0x63, 0x06, 0x23, 0x74, 0x6f, 0x69, 0x00,
1580x1d, 0x02, 0x11, 0x73, 0x78, 0x06, 0x23, 0x74, 0x6f, 0x69, 1590x12, 0x79, 0x98, 0x02, 0x41, 0x65, 0x71, 0x75, 0x69, 0xcb,
1590x00, 0x12, 0x79, 0x98, 0x02, 0x41, 0x65, 0x71, 0x75, 0x69, 1600x02, 0x04, 0x2e, 0x00, 0x0e, 0xb0, 0x07, 0x0c, 0x1b, 0x01,
1600xcb, 0x02, 0x04, 0x2e, 0x00, 0x0e, 0xc5, 0x07, 0x0c, 0x1b, 1610x11, 0x28, 0x1a, 0x01, 0x10, 0x64, 0x4e, 0x05, 0x00, 0xf0,
1610x01, 0x11, 0x28, 0x1a, 0x01, 0x10, 0x64, 0x63, 0x05, 0x00, 1620x02, 0x61, 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x20, 0x00,
1620xf0, 0x02, 0x61, 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x20, 1630x95, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74,
1630x00, 0x95, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 1640x47, 0x00, 0x03, 0xff, 0x04, 0x00, 0x29, 0x00, 0x71, 0x69,
1640x74, 0x47, 0x00, 0x03, 0x15, 0x05, 0x00, 0x29, 0x00, 0x71, 1650x63, 0x65, 0x61, 0x62, 0x6c, 0x79, 0x3d, 0x02, 0x16, 0x44,
1650x69, 0x63, 0x65, 0x61, 0x62, 0x6c, 0x79, 0x3d, 0x02, 0x16, 1660x29, 0x00, 0x70, 0x00, 0x00, 0x60, 0x45, 0x61, 0x73, 0x79,
1660x44, 0x29, 0x00, 0x70, 0x00, 0x00, 0x60, 0x45, 0x61, 0x73, 1670xec, 0x01, 0x23, 0x61, 0x6e, 0x3f, 0x04, 0x08, 0x3a, 0x00,
1670x79, 0xec, 0x01, 0x23, 0x61, 0x6e, 0x3f, 0x04, 0x08, 0x3a, 1680x60, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x4b, 0x04, 0x62,
1680x00, 0x60, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x4b, 0x04, 1690x73, 0x6f, 0x6c, 0x75, 0x62, 0x6c, 0x8b, 0x07, 0xb2, 0x6f,
1690x62, 0x73, 0x6f, 0x6c, 0x75, 0x62, 0x6c, 0xa0, 0x07, 0xb2, 1700x75, 0x74, 0x00, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61,
1700x6f, 0x75, 0x74, 0x00, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 1710xd6, 0x04, 0xf9, 0x03, 0x6f, 0x72, 0x00, 0x67, 0x75, 0x65,
1710x61, 0xd6, 0x04, 0xf9, 0x03, 0x6f, 0x72, 0x00, 0x67, 0x75, 1720x73, 0x73, 0x69, 0x6e, 0x67, 0x2c, 0x00, 0x60, 0x48, 0x61,
1720x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x2c, 0x00, 0x60, 0x48, 1730x72, 0x64, 0x52, 0x00, 0x01, 0x19, 0x08, 0x01, 0x21, 0x00,
1730x61, 0x72, 0x64, 0x52, 0x00, 0x01, 0x2e, 0x08, 0x01, 0x21, 1740x22, 0x65, 0x73, 0x58, 0x01, 0x40, 0x70, 0x72, 0x6f, 0x62,
1740x00, 0x22, 0x65, 0x73, 0x58, 0x01, 0x40, 0x70, 0x72, 0x6f, 1750x90, 0x00, 0x00, 0x5a, 0x00, 0xa2, 0x6e, 0x65, 0x63, 0x65,
1750x62, 0x90, 0x00, 0x00, 0x5a, 0x00, 0xb0, 0x6e, 0x65, 0x63, 1760x73, 0x73, 0x61, 0x72, 0x79, 0x2e, 0xd9, 0x02, 0x16, 0x33,
1760x65, 0x73, 0x73, 0x61, 0x72, 0x79, 0x2e, 0x00, 1770xd9, 0x02, 0xb0, 0x75, 0x73, 0x65, 0x72, 0x20, 0x70, 0x72,
1780x65, 0x66, 0x65, 0x72, 0x68, 0x05, 0x01, 0xdf, 0x02, 0x20,
1790x4f, 0x6e, 0x91, 0x04, 0x54, 0x74, 0x66, 0x6f, 0x72, 0x6d,
1800x5f, 0x00, 0x20, 0x75, 0x70, 0x98, 0x01, 0x10, 0x00, 0x2e,
1810x00, 0x17, 0x00, 0x2e, 0x00, 0x12, 0x2c, 0xcd, 0x02, 0x16,
1820x50, 0x12, 0x00, 0x0d, 0xe9, 0x02, 0x33, 0x47, 0x61, 0x6d,
1830xe9, 0x02, 0x02, 0x98, 0x00, 0x31, 0x6c, 0x65, 0x74, 0xa9,
1840x01, 0x90, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72,
1850x65, 0xfc, 0x03, 0x01, 0x7b, 0x02, 0x23, 0x60, 0x74, 0x92,
1860x02, 0x01, 0x76, 0x01, 0x02, 0xcc, 0x03, 0x11, 0x27, 0x13,
1870x05, 0x02, 0x61, 0x03, 0x52, 0x73, 0x68, 0x6f, 0x77, 0x6e,
1880x2a, 0x04, 0x08, 0xdc, 0x08, 0x00, 0xd0, 0x08, 0x80, 0x73,
1890x6f, 0x00, 0x6c, 0x69, 0x74, 0x2e, 0x00,
177}; 190};
178 191
179const unsigned short help_text_len = 2327; 192const unsigned short help_text_len = 2549;
180const unsigned short help_text_words = 433; 193const unsigned short help_text_words = 468;
181const char quick_help_text[] = "Place bulbs to light up all the squares."; 194const char quick_help_text[] = "Place bulbs to light up all the squares.";
diff --git a/apps/plugins/puzzles/help/loopy.c b/apps/plugins/puzzles/help/loopy.c
index 425b157107..62ec8cfa0e 100644
--- a/apps/plugins/puzzles/help/loopy.c
+++ b/apps/plugins/puzzles/help/loopy.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,184 +6,262 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 169, TEXT_CENTER | C_RED }, 9 { 167, TEXT_CENTER | C_RED },
10 { 220, TEXT_UNDERLINE }, 10 { 218, TEXT_UNDERLINE },
11 { 262, TEXT_CENTER | C_RED }, 11 { 260, TEXT_CENTER | C_RED },
12 { 279, TEXT_UNDERLINE }, 12 { 277, TEXT_UNDERLINE },
13 { 280, TEXT_UNDERLINE }, 13 { 278, TEXT_UNDERLINE },
14 { 324, TEXT_UNDERLINE }, 14 { 322, TEXT_UNDERLINE },
15 { 353, TEXT_UNDERLINE },
15 { 355, TEXT_UNDERLINE }, 16 { 355, TEXT_UNDERLINE },
16 { 357, TEXT_UNDERLINE }, 17 { 373, TEXT_UNDERLINE },
17 { 375, TEXT_UNDERLINE }, 18 { 388, TEXT_UNDERLINE },
18 { 390, TEXT_UNDERLINE }, 19 { 402, TEXT_UNDERLINE },
19 { 404, TEXT_UNDERLINE }, 20 { 414, TEXT_CENTER | C_RED },
21 { 618, TEXT_UNDERLINE },
20 LAST_STYLE_ITEM 22 LAST_STYLE_ITEM
21}; 23};
22 24
23/* orig 2260 comp 1600 ratio 0.707965 level 10 saved 660 */ 25/* orig 3584 comp 2352 ratio 0.65625 level 10 saved 1232 */
24const char help_text[] = { 26const char help_text[] = {
250xf1, 0x4e, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 270xfc, 0x05, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
260x32, 0x33, 0x3a, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x79, 0x20, 280x32, 0x33, 0x3a, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x79, 0x20,
270x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x61, 0x72, 0x65, 290x00, 0x2d, 0x01, 0x00, 0xf1, 0x3c, 0x00, 0x00, 0x00, 0x59,
280x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 0x67, 300x6f, 0x75, 0x00, 0x61, 0x72, 0x65, 0x00, 0x67, 0x69, 0x76,
290x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x64, 0x6f, 0x74, 310x65, 0x6e, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00,
300x73, 0x2c, 0x00, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x00, 320x6f, 0x66, 0x00, 0x64, 0x6f, 0x74, 0x73, 0x2c, 0x00, 0x6d,
310x77, 0x69, 0x74, 0x68, 0x00, 0x79, 0x65, 0x6c, 0x6c, 0x6f, 330x61, 0x72, 0x6b, 0x65, 0x64, 0x00, 0x77, 0x69, 0x74, 0x68,
320x77, 0x00, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x00, 0x74, 0x6f, 340x00, 0x79, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x00, 0x6c, 0x69,
330x00, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 350x6e, 0x65, 0x73, 0x00, 0x74, 0x6f, 0x00, 0x69, 0x6e, 0x64,
340x77, 0x68, 0x69, 0x63, 0x68, 0x31, 0x00, 0x23, 0x00, 0x79, 360x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x77, 0x68, 0x69, 0x63,
350x4e, 0x00, 0x10, 0x61, 0x2b, 0x00, 0x20, 0x65, 0x64, 0x27, 370x68, 0x31, 0x00, 0x23, 0x00, 0x79, 0x4e, 0x00, 0x10, 0x61,
360x00, 0xf0, 0x0b, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 380x2b, 0x00, 0x20, 0x65, 0x64, 0x27, 0x00, 0xf0, 0x0b, 0x63,
370x00, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6c, 0x79, 0x00, 390x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x00, 0x64, 0x69, 0x72,
380x74, 0x6f, 0x67, 0x65, 0x74, 0x68, 0x65, 0x72, 0x2e, 0x7c, 400x65, 0x63, 0x74, 0x6c, 0x79, 0x00, 0x74, 0x6f, 0x67, 0x65,
390x00, 0x71, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 0x69, 0x51, 410x74, 0x68, 0x65, 0x72, 0x2e, 0x7c, 0x00, 0x71, 0x72, 0x00,
400x00, 0xf0, 0x00, 0x75, 0x73, 0x65, 0x00, 0x73, 0x6f, 0x6d, 420x61, 0x69, 0x6d, 0x00, 0x69, 0x51, 0x00, 0xf0, 0x00, 0x75,
410x65, 0x00, 0x73, 0x75, 0x62, 0x73, 0x65, 0x74, 0x86, 0x00, 430x73, 0x65, 0x00, 0x73, 0x6f, 0x6d, 0x65, 0x00, 0x73, 0x75,
420x5d, 0x74, 0x68, 0x6f, 0x73, 0x65, 0x7a, 0x00, 0xf0, 0x11, 440x62, 0x73, 0x65, 0x74, 0x86, 0x00, 0x5d, 0x74, 0x68, 0x6f,
430x64, 0x72, 0x61, 0x77, 0x00, 0x61, 0x00, 0x73, 0x69, 0x6e, 450x73, 0x65, 0x7a, 0x00, 0xf0, 0x11, 0x64, 0x72, 0x61, 0x77,
440x67, 0x6c, 0x65, 0x00, 0x75, 0x6e, 0x62, 0x72, 0x6f, 0x6b, 460x00, 0x61, 0x00, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x00,
450x65, 0x6e, 0x00, 0x6c, 0x6f, 0x6f, 0x70, 0x00, 0x66, 0x72, 470x75, 0x6e, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x6e, 0x00, 0x6c,
460x6f, 0x6d, 0x8c, 0x00, 0x01, 0x28, 0x00, 0x21, 0x6f, 0x74, 480x6f, 0x6f, 0x70, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x8c, 0x00,
470xbb, 0x00, 0x61, 0x69, 0x6e, 0x00, 0x74, 0x68, 0x65, 0xdb, 490x01, 0x28, 0x00, 0x21, 0x6f, 0x74, 0xbb, 0x00, 0x61, 0x69,
480x00, 0x50, 0x2e, 0x00, 0x00, 0x00, 0x53, 0x64, 0x00, 0x21, 500x6e, 0x00, 0x74, 0x68, 0x65, 0xdb, 0x00, 0x50, 0x2e, 0x00,
490x6f, 0x66, 0x14, 0x00, 0xd2, 0x73, 0x70, 0x61, 0x63, 0x65, 510x00, 0x00, 0x53, 0x64, 0x00, 0x21, 0x6f, 0x66, 0x14, 0x00,
500x73, 0x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x27, 0x00, 520xd2, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x00, 0x62, 0x65,
510x02, 0x67, 0x00, 0xf4, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 530x74, 0x77, 0x65, 0x65, 0x27, 0x00, 0x02, 0x67, 0x00, 0xf4,
520x69, 0x6e, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 540x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x00, 0x6e,
530x2e, 0x00, 0x54, 0x68, 0x65, 0x73, 0x65, 0x0f, 0x00, 0x06, 550x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2e, 0x00, 0x54, 0x68,
540xfd, 0x00, 0x84, 0x68, 0x6f, 0x77, 0x00, 0x6d, 0x61, 0x6e, 560x65, 0x73, 0x65, 0x0f, 0x00, 0x06, 0xfd, 0x00, 0x84, 0x68,
550x79, 0x51, 0x00, 0x02, 0x3e, 0x00, 0xb2, 0x61, 0x72, 0x6f, 570x6f, 0x77, 0x00, 0x6d, 0x61, 0x6e, 0x79, 0x51, 0x00, 0x02,
560x75, 0x6e, 0x64, 0x00, 0x74, 0x68, 0x61, 0x74, 0x63, 0x00, 580x3e, 0x00, 0xb2, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x00,
570xa5, 0x00, 0x66, 0x6f, 0x72, 0x6d, 0x00, 0x70, 0x61, 0x72, 590x74, 0x68, 0x61, 0x74, 0x63, 0x00, 0xa5, 0x00, 0x66, 0x6f,
580x74, 0x29, 0x00, 0x31, 0x6f, 0x6f, 0x70, 0x56, 0x00, 0x02, 600x72, 0x6d, 0x00, 0x70, 0x61, 0x72, 0x74, 0x29, 0x00, 0x31,
590xb8, 0x00, 0x00, 0x3a, 0x01, 0x01, 0xd8, 0x00, 0x83, 0x6d, 610x6f, 0x6f, 0x70, 0x56, 0x00, 0x02, 0xb8, 0x00, 0x00, 0x3a,
600x75, 0x73, 0x74, 0x00, 0x63, 0x6f, 0x72, 0x2e, 0x01, 0x70, 620x01, 0x01, 0xd8, 0x00, 0x83, 0x6d, 0x75, 0x73, 0x74, 0x00,
610x73, 0x61, 0x74, 0x69, 0x73, 0x66, 0x79, 0x52, 0x01, 0x03, 630x63, 0x6f, 0x72, 0x2e, 0x01, 0x70, 0x73, 0x61, 0x74, 0x69,
620x3a, 0x00, 0x62, 0x73, 0x65, 0x00, 0x63, 0x6c, 0x75, 0x0a, 640x73, 0x66, 0x79, 0x52, 0x01, 0x03, 0x3a, 0x00, 0x62, 0x73,
630x01, 0x20, 0x62, 0x65, 0xa9, 0x00, 0x94, 0x73, 0x69, 0x64, 650x65, 0x00, 0x63, 0x6c, 0x75, 0x0a, 0x01, 0x20, 0x62, 0x65,
640x65, 0x72, 0x65, 0x64, 0x00, 0x61, 0x38, 0x00, 0x90, 0x00, 660xa9, 0x00, 0x94, 0x73, 0x69, 0x64, 0x65, 0x72, 0x65, 0x64,
650x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0xef, 0x00, 670x00, 0x61, 0x38, 0x00, 0x90, 0x00, 0x73, 0x6f, 0x6c, 0x75,
660x12, 0x49, 0xd7, 0x00, 0xd2, 0x64, 0x65, 0x66, 0x61, 0x75, 680x74, 0x69, 0x6f, 0x6e, 0xef, 0x00, 0x12, 0x49, 0xd7, 0x00,
670x6c, 0x74, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0x2c, 0x12, 0x00, 690xd2, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x6d,
680x00, 0xb2, 0x01, 0x01, 0xae, 0x01, 0x98, 0x72, 0x72, 0x61, 700x6f, 0x64, 0x65, 0x2c, 0x12, 0x00, 0x00, 0xb2, 0x01, 0x01,
690x6e, 0x67, 0x65, 0x64, 0x00, 0x69, 0x02, 0x02, 0x80, 0x73, 710xae, 0x01, 0x98, 0x72, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x64,
700x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x3b, 0xe3, 0x00, 0x51, 720x00, 0x69, 0x02, 0x02, 0x80, 0x73, 0x71, 0x75, 0x61, 0x72,
710x65, 0x76, 0x65, 0x72, 0x2c, 0xa4, 0x00, 0xf1, 0x19, 0x63, 730x65, 0x73, 0x3b, 0xe3, 0x00, 0x51, 0x65, 0x76, 0x65, 0x72,
720x61, 0x6e, 0x00, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0x70, 0x6c, 740x2c, 0xa4, 0x00, 0xf1, 0x19, 0x63, 0x61, 0x6e, 0x00, 0x61,
730x61, 0x79, 0x00, 0x6f, 0x6e, 0x00, 0x74, 0x72, 0x69, 0x61, 750x6c, 0x73, 0x6f, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x00, 0x6f,
740x6e, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x00, 0x6f, 0x72, 0x00, 760x6e, 0x00, 0x74, 0x72, 0x69, 0x61, 0x6e, 0x67, 0x75, 0x6c,
750x68, 0x65, 0x78, 0x61, 0x67, 0x6f, 0x6e, 0x61, 0x6c, 0x47, 770x61, 0x72, 0x00, 0x6f, 0x72, 0x00, 0x68, 0x65, 0x78, 0x61,
760x00, 0x20, 0x73, 0x2c, 0x14, 0x00, 0x10, 0x65, 0x5a, 0x02, 780x67, 0x6f, 0x6e, 0x61, 0x6c, 0x47, 0x00, 0x20, 0x73, 0x2c,
770xf0, 0x01, 0x6d, 0x6f, 0x72, 0x65, 0x00, 0x65, 0x78, 0x6f, 790x14, 0x00, 0x10, 0x65, 0x5a, 0x02, 0xf0, 0x01, 0x6d, 0x6f,
780x74, 0x69, 0x63, 0x00, 0x6f, 0x6e, 0x65, 0x73, 0x9a, 0x00, 800x72, 0x65, 0x00, 0x65, 0x78, 0x6f, 0x74, 0x69, 0x63, 0x00,
790x60, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x1b, 0x01, 0x01, 810x6f, 0x6e, 0x65, 0x73, 0x9a, 0x00, 0x60, 0x43, 0x72, 0x65,
800x90, 0x00, 0xf2, 0x05, 0x62, 0x61, 0x73, 0x69, 0x63, 0x00, 820x64, 0x69, 0x74, 0x1b, 0x01, 0x01, 0x90, 0x00, 0xf2, 0x05,
810x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x69, 0x64, 0x65, 830x62, 0x61, 0x73, 0x69, 0x63, 0x00, 0x70, 0x75, 0x7a, 0x7a,
820x61, 0x00, 0x67, 0x6f, 0xe7, 0x00, 0xb0, 0x4e, 0x69, 0x6b, 840x6c, 0x65, 0x00, 0x69, 0x64, 0x65, 0x61, 0x00, 0x67, 0x6f,
830x6f, 0x6c, 0x69, 0x00, 0x5b, 0x31, 0x30, 0x5d, 0x38, 0x00, 850xe7, 0x00, 0xb0, 0x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69, 0x00,
840x01, 0xbd, 0x02, 0xf1, 0x00, 0x00, 0x77, 0x61, 0x73, 0x00, 860x5b, 0x31, 0x30, 0x5d, 0x38, 0x00, 0x01, 0xcf, 0x02, 0xf1,
850x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 870x00, 0x00, 0x77, 0x61, 0x73, 0x00, 0x6f, 0x72, 0x69, 0x67,
860xb1, 0x01, 0x52, 0x72, 0x69, 0x62, 0x75, 0x74, 0x77, 0x02, 880x69, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0xb1, 0x01, 0x52, 0x72,
870x30, 0x74, 0x68, 0x69, 0xc5, 0x01, 0x40, 0x6c, 0x6c, 0x65, 890x69, 0x62, 0x75, 0x74, 0x77, 0x02, 0x30, 0x74, 0x68, 0x69,
880x63, 0x09, 0x01, 0xf2, 0x04, 0x00, 0x62, 0x79, 0x00, 0x4d, 900xc5, 0x01, 0x40, 0x6c, 0x6c, 0x65, 0x63, 0x09, 0x01, 0xf2,
890x69, 0x6b, 0x65, 0x00, 0x50, 0x69, 0x6e, 0x6e, 0x61, 0x2c, 910x04, 0x00, 0x62, 0x79, 0x00, 0x4d, 0x69, 0x6b, 0x65, 0x00,
900x00, 0x61, 0x6e, 0x64, 0x67, 0x02, 0x40, 0x71, 0x75, 0x65, 920x50, 0x69, 0x6e, 0x6e, 0x61, 0x2c, 0x00, 0x61, 0x6e, 0x64,
910x6e, 0x68, 0x01, 0x62, 0x65, 0x6e, 0x68, 0x61, 0x6e, 0x63, 930x67, 0x02, 0x40, 0x71, 0x75, 0x65, 0x6e, 0x68, 0x01, 0x62,
920x3c, 0x00, 0xf0, 0x05, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 940x65, 0x6e, 0x68, 0x61, 0x6e, 0x63, 0x3c, 0x00, 0xf0, 0x05,
930x00, 0x76, 0x61, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x00, 0x74, 950x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x00, 0x76, 0x61, 0x72,
940x79, 0x70, 0x65, 0x73, 0x12, 0x01, 0x42, 0x6e, 0x6f, 0x6e, 960x69, 0x6f, 0x75, 0x73, 0x00, 0x74, 0x79, 0x70, 0x65, 0x73,
950x2d, 0x16, 0x01, 0x02, 0x25, 0x01, 0xa3, 0x62, 0x79, 0x00, 970x12, 0x01, 0x42, 0x6e, 0x6f, 0x6e, 0x2d, 0x16, 0x01, 0x02,
960x4c, 0x61, 0x6d, 0x62, 0x72, 0x6f, 0x73, 0x08, 0x00, 0x10, 980x25, 0x01, 0xa3, 0x62, 0x79, 0x00, 0x4c, 0x61, 0x6d, 0x62,
970x75, 0x9e, 0x00, 0x00, 0xa6, 0x00, 0xd1, 0x00, 0x68, 0x74, 990x72, 0x6f, 0x73, 0x08, 0x00, 0x10, 0x75, 0x9e, 0x00, 0x00,
980x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 1000xa6, 0x00, 0xe1, 0x00, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a,
990xbd, 0x00, 0xa2, 0x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f, 1010x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 0xbe, 0x00, 0xa2,
1000x65, 0x6e, 0x2f, 0xe1, 0x00, 0x50, 0x73, 0x2f, 0x73, 0x6c, 1020x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f, 0x65, 0x6e, 0x2f,
1010x69, 0x07, 0x03, 0xf1, 0x01, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 1030xe2, 0x00, 0x50, 0x73, 0x2f, 0x73, 0x6c, 0x69, 0x08, 0x03,
1020x68, 0x74, 0x6d, 0x6c, 0x00, 0x28, 0x62, 0x65, 0x77, 0x61, 1040xc3, 0x6c, 0x69, 0x6e, 0x6b, 0x2f, 0x00, 0x00, 0x00, 0x32,
1030x72, 0x9b, 0x02, 0xd3, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x29, 1050x33, 0x2e, 0x31, 0xaa, 0x03, 0x01, 0xcc, 0x00, 0x40, 0x6f,
1040x00, 0x00, 0x00, 0x32, 0x33, 0x2e, 0x31, 0xad, 0x03, 0x01, 1060x6c, 0x73, 0x20, 0x25, 0x01, 0x42, 0x6c, 0x69, 0x63, 0x6b,
1050xe1, 0x00, 0x40, 0x6f, 0x6c, 0x73, 0x20, 0x3a, 0x01, 0x42, 1070x32, 0x02, 0x20, 0x65, 0x66, 0xbf, 0x01, 0x00, 0x27, 0x03,
1060x6c, 0x69, 0x63, 0x6b, 0x47, 0x02, 0x20, 0x65, 0x66, 0xd4, 1080x60, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x7f, 0x01, 0x18,
1070x01, 0x00, 0x3c, 0x03, 0x60, 0x62, 0x75, 0x74, 0x74, 0x6f, 1090x61, 0x1e, 0x03, 0x01, 0xf9, 0x00, 0xd4, 0x75, 0x72, 0x6e,
1080x6e, 0x94, 0x01, 0x18, 0x61, 0x33, 0x03, 0x01, 0x0e, 0x01, 1100x00, 0x69, 0x74, 0x00, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x2c,
1090xd4, 0x75, 0x72, 0x6e, 0x00, 0x69, 0x74, 0x00, 0x62, 0x6c, 1110xa9, 0x02, 0x32, 0x69, 0x6e, 0x67, 0x8e, 0x02, 0x00, 0xc4,
1100x61, 0x63, 0x6b, 0x2c, 0xbe, 0x02, 0x32, 0x69, 0x6e, 0x67, 1120x01, 0x00, 0x12, 0x03, 0x10, 0x6b, 0x24, 0x00, 0x2e, 0x69,
1110xa3, 0x02, 0x00, 0xd9, 0x01, 0x00, 0x27, 0x03, 0x10, 0x6b, 1130x73, 0x93, 0x02, 0x03, 0x71, 0x00, 0x20, 0x61, 0x67, 0xfe,
1120x24, 0x00, 0x2e, 0x69, 0x73, 0xa8, 0x02, 0x03, 0x71, 0x00, 1140x02, 0x04, 0x50, 0x00, 0x04, 0xda, 0x02, 0x04, 0x6d, 0x00,
1130x20, 0x61, 0x67, 0x13, 0x03, 0x04, 0x50, 0x00, 0x04, 0xef, 1150x02, 0x1e, 0x00, 0x50, 0x28, 0x6d, 0x65, 0x61, 0x6e, 0x5a,
1140x02, 0x04, 0x6d, 0x00, 0x02, 0x1e, 0x00, 0x50, 0x28, 0x6d, 1160x00, 0x03, 0xf7, 0x03, 0x70, 0x6e, 0x27, 0x74, 0x00, 0x73,
1150x65, 0x61, 0x6e, 0x5a, 0x00, 0x03, 0x0c, 0x04, 0x70, 0x6e, 1170x75, 0x72, 0x26, 0x00, 0x21, 0x74, 0x29, 0x7b, 0x02, 0x15,
1160x27, 0x74, 0x00, 0x73, 0x75, 0x72, 0x26, 0x00, 0x21, 0x74, 1180x66, 0x12, 0x04, 0x01, 0x18, 0x00, 0x01, 0x82, 0x00, 0x11,
1170x29, 0x90, 0x02, 0x15, 0x66, 0x27, 0x04, 0x01, 0x18, 0x00, 1190x61, 0x74, 0x00, 0x21, 0x69, 0x63, 0x33, 0x02, 0x01, 0x55,
1180x01, 0x82, 0x00, 0x11, 0x61, 0x74, 0x00, 0x21, 0x69, 0x63, 1200x00, 0x61, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x8f, 0x00,
1190x48, 0x02, 0x01, 0x55, 0x00, 0x61, 0x73, 0x65, 0x67, 0x6d, 1210x3d, 0x6e, 0x6f, 0x74, 0x93, 0x00, 0x06, 0x79, 0x02, 0x15,
1200x65, 0x6e, 0x8f, 0x00, 0x3d, 0x6e, 0x6f, 0x74, 0x93, 0x00, 1220x63, 0x0c, 0x01, 0x4b, 0x72, 0x69, 0x67, 0x68, 0x0d, 0x01,
1210x06, 0x8e, 0x02, 0x15, 0x63, 0x0c, 0x01, 0x4b, 0x72, 0x69, 1230xb0, 0x74, 0x6f, 0x00, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65,
1220x67, 0x68, 0x0d, 0x01, 0xb0, 0x74, 0x6f, 0x00, 0x72, 0x65, 1240x00, 0x69, 0x41, 0x03, 0xb0, 0x6d, 0x70, 0x6c, 0x65, 0x74,
1230x6d, 0x6f, 0x76, 0x65, 0x00, 0x69, 0x56, 0x03, 0xb0, 0x6d, 1250x65, 0x6c, 0x79, 0x2e, 0x00, 0x41, 0xad, 0x00, 0x12, 0x2c,
1240x70, 0x6c, 0x65, 0x74, 0x65, 0x6c, 0x79, 0x2e, 0x00, 0x41, 1260x3d, 0x00, 0x00, 0xae, 0x00, 0x60, 0x61, 0x00, 0x73, 0x65,
1250xad, 0x00, 0x12, 0x2c, 0x3d, 0x00, 0x00, 0xae, 0x00, 0x60, 1270x63, 0x6f, 0x9f, 0x03, 0x8b, 0x69, 0x6d, 0x65, 0x00, 0x77,
1260x61, 0x00, 0x73, 0x65, 0x63, 0x6f, 0xb4, 0x03, 0x8b, 0x69, 1280x69, 0x6c, 0x6c, 0xe5, 0x00, 0x20, 0x62, 0x61, 0x66, 0x00,
1270x6d, 0x65, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0xe5, 0x00, 0x20, 1290x13, 0x6f, 0xed, 0x00, 0x00, 0xc9, 0x00, 0x41, 0x28, 0x41,
1280x62, 0x61, 0x66, 0x00, 0x13, 0x6f, 0xed, 0x00, 0x00, 0xc9, 1300x6c, 0x6c, 0x20, 0x00, 0x11, 0x61, 0x4e, 0x02, 0x92, 0x73,
1290x00, 0x41, 0x28, 0x41, 0x6c, 0x6c, 0x20, 0x00, 0x11, 0x61, 1310x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x34, 0x03,
1300x63, 0x02, 0x92, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 1320x13, 0x73, 0x64, 0x02, 0x33, 0x32, 0x2e, 0x31, 0xfe, 0x04,
1310x69, 0x62, 0x49, 0x03, 0x13, 0x73, 0x79, 0x02, 0x33, 0x32, 1330xe2, 0x73, 0x6f, 0x00, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,
1320x2e, 0x31, 0x13, 0x05, 0xd3, 0x73, 0x6f, 0x00, 0x61, 0x76, 1340x62, 0x6c, 0x65, 0x2e, 0x29, 0xdd, 0x01, 0x13, 0x32, 0xdd,
1330x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0xdd, 0x01, 1350x01, 0x91, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
1340x13, 0x32, 0xdd, 0x01, 0x91, 0x70, 0x61, 0x72, 0x61, 0x6d, 1360x72, 0xdf, 0x01, 0x02, 0x57, 0x04, 0x06, 0x14, 0x00, 0x02,
1350x65, 0x74, 0x65, 0x72, 0xdf, 0x01, 0x02, 0x6c, 0x04, 0x06, 1370x41, 0x00, 0x04, 0x3c, 0x00, 0x02, 0xcf, 0x04, 0x00, 0x79,
1360x14, 0x00, 0x02, 0x41, 0x00, 0x04, 0x3c, 0x00, 0x02, 0xe4, 1380x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e,
1370x04, 0x00, 0x79, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 1390x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x6f, 0x00, 0x22, 0x6f,
1380x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x6f, 1400x6e, 0x1a, 0x00, 0x91, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00,
1390x00, 0x22, 0x6f, 0x6e, 0x1a, 0x00, 0x91, 0x54, 0x79, 0x70, 1410x6d, 0x65, 0x6e, 0x7f, 0x02, 0x91, 0x57, 0x69, 0x64, 0x74,
1400x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x94, 0x02, 0x91, 0x57, 1420x68, 0x2c, 0x00, 0x48, 0x65, 0x22, 0x01, 0x51, 0x00, 0x00,
1410x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x22, 0x01, 1430x53, 0x69, 0x7a, 0xee, 0x04, 0x00, 0xb2, 0x02, 0x70, 0x2c,
1420x51, 0x00, 0x00, 0x53, 0x69, 0x7a, 0x68, 0x02, 0x00, 0xc7, 1440x00, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x2c, 0x04, 0x05, 0xdb,
1430x02, 0x70, 0x2c, 0x00, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x41, 1450x04, 0x00, 0x1c, 0x00, 0x31, 0x72, 0x65, 0x67, 0xd6, 0x00,
1440x04, 0x05, 0xf0, 0x04, 0x00, 0x1c, 0x00, 0x31, 0x72, 0x65, 1460x61, 0x61, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x1d, 0x03, 0x93,
1450x67, 0xd6, 0x00, 0x61, 0x61, 0x63, 0x72, 0x6f, 0x73, 0x73, 1470x64, 0x6f, 0x77, 0x6e, 0x2e, 0x00, 0x46, 0x6f, 0x72, 0x08,
1460x32, 0x03, 0x93, 0x64, 0x6f, 0x77, 0x6e, 0x2e, 0x00, 0x46, 1480x04, 0x04, 0xd0, 0x03, 0xa1, 0x69, 0x74, 0x27, 0x73, 0x00,
1470x6f, 0x72, 0x1d, 0x04, 0x04, 0xe5, 0x03, 0xa1, 0x69, 0x74, 1490x63, 0x6c, 0x65, 0x61, 0x72, 0xfb, 0x04, 0x01, 0x67, 0x03,
1480x27, 0x73, 0x00, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x10, 0x05, 1500x01, 0x6a, 0x03, 0x61, 0x75, 0x6e, 0x74, 0x65, 0x64, 0x3b,
1490x01, 0x7c, 0x03, 0x01, 0x7f, 0x03, 0x61, 0x75, 0x6e, 0x74, 1510xcd, 0x03, 0x10, 0x6f, 0xd7, 0x02, 0x06, 0x37, 0x03, 0x01,
1500x65, 0x64, 0x3b, 0xe2, 0x03, 0x10, 0x6f, 0xed, 0x02, 0x06, 1520x2c, 0x03, 0x00, 0xc3, 0x01, 0x72, 0x6d, 0x61, 0x79, 0x00,
1510x4c, 0x03, 0x01, 0x41, 0x03, 0x00, 0xc3, 0x01, 0x72, 0x6d, 1530x68, 0x61, 0x76, 0xa7, 0x02, 0x01, 0x84, 0x02, 0x41, 0x61,
1520x61, 0x79, 0x00, 0x68, 0x61, 0x76, 0xa7, 0x02, 0x01, 0x84, 1540x00, 0x62, 0x69, 0xab, 0x05, 0x22, 0x73, 0x65, 0x4b, 0x05,
1530x02, 0x41, 0x61, 0x00, 0x62, 0x69, 0xc0, 0x05, 0x22, 0x73, 1550x01, 0x98, 0x04, 0x52, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x91,
1540x65, 0x60, 0x05, 0x01, 0xad, 0x04, 0x52, 0x69, 0x6d, 0x65, 1560x00, 0x25, 0x72, 0x65, 0xb3, 0x00, 0x00, 0xdd, 0x00, 0x50,
1550x6e, 0x73, 0x91, 0x00, 0x25, 0x72, 0x65, 0xb3, 0x00, 0x00, 1570x47, 0x72, 0x69, 0x64, 0x20, 0x59, 0x00, 0x40, 0x00, 0x00,
1560xdd, 0x00, 0x50, 0x47, 0x72, 0x69, 0x64, 0x20, 0x59, 0x00, 1580x00, 0x41, 0x9d, 0x01, 0x02, 0x73, 0x06, 0x00, 0x67, 0x06,
1570x40, 0x00, 0x00, 0x00, 0x41, 0x9d, 0x01, 0x02, 0x88, 0x06, 1590x20, 0x68, 0x6f, 0x2b, 0x06, 0x04, 0xc9, 0x05, 0x00, 0xe4,
1580x00, 0x7c, 0x06, 0x20, 0x68, 0x6f, 0x40, 0x06, 0x04, 0xde, 1600x01, 0x04, 0xfb, 0x03, 0x26, 0x6f, 0x66, 0x8c, 0x00, 0x72,
1590x05, 0x00, 0xe4, 0x01, 0x04, 0x10, 0x04, 0x26, 0x6f, 0x66, 1610x74, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x2e, 0x04, 0x06, 0x01,
1600x8c, 0x00, 0x72, 0x74, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x2e, 1620x8c, 0x00, 0x13, 0x61, 0xda, 0x01, 0x11, 0x66, 0x09, 0x06,
1610x19, 0x06, 0x01, 0x8c, 0x00, 0x13, 0x61, 0xda, 0x01, 0x11, 1630x01, 0x14, 0x06, 0x21, 0x61, 0x6d, 0x55, 0x02, 0x06, 0xb0,
1620x66, 0x1e, 0x06, 0x01, 0x29, 0x06, 0x21, 0x61, 0x6d, 0x55, 1640x00, 0x70, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x9b,
1630x02, 0x06, 0xb0, 0x00, 0x70, 0x6d, 0x75, 0x6c, 0x74, 0x69, 1650x00, 0x40, 0x66, 0x66, 0x65, 0x72, 0xac, 0x02, 0x05, 0x52,
1640x70, 0x6c, 0x9b, 0x00, 0x40, 0x66, 0x66, 0x65, 0x72, 0xac, 1660x00, 0xc1, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x00, 0x28,
1650x02, 0x05, 0x52, 0x00, 0xc1, 0x76, 0x65, 0x72, 0x74, 0x65, 1670x65, 0x2e, 0x67, 0x2e, 0x3f, 0x00, 0x50, 0x43, 0x61, 0x69,
1660x78, 0x00, 0x28, 0x65, 0x2e, 0x67, 0x2e, 0x3f, 0x00, 0x50, 1680x72, 0x6f, 0xf8, 0x04, 0x51, 0x4b, 0x69, 0x74, 0x65, 0x73,
1670x43, 0x61, 0x69, 0x72, 0x6f, 0x0d, 0x05, 0x51, 0x4b, 0x69, 1690x70, 0x05, 0x22, 0x29, 0x3b, 0x14, 0x01, 0x1a, 0x73, 0x73,
1680x74, 0x65, 0x73, 0x85, 0x05, 0x22, 0x29, 0x3b, 0x14, 0x01, 1700x00, 0x00, 0x3b, 0x00, 0x1f, 0x69, 0x76, 0x00, 0x07, 0x0e,
1690x1a, 0x73, 0x73, 0x00, 0x00, 0x3b, 0x00, 0x1f, 0x69, 0x76, 1710x6d, 0x00, 0x01, 0xa5, 0x00, 0x07, 0x6b, 0x00, 0x74, 0x47,
1700x00, 0x07, 0x0e, 0x6d, 0x00, 0x01, 0xa5, 0x00, 0x07, 0x6b, 1720x72, 0x65, 0x61, 0x74, 0x20, 0x48, 0x74, 0x05, 0x12, 0x29,
1710x00, 0x74, 0x47, 0x72, 0x65, 0x61, 0x74, 0x20, 0x48, 0x89, 1730x50, 0x06, 0x02, 0xb1, 0x01, 0x18, 0x2c, 0x9a, 0x05, 0x00,
1720x05, 0x12, 0x29, 0x65, 0x06, 0x02, 0xb1, 0x01, 0x18, 0x2c, 1740xd2, 0x01, 0x92, 0x68, 0x6f, 0x6e, 0x65, 0x79, 0x63, 0x6f,
1730xaf, 0x05, 0x00, 0xd2, 0x01, 0x92, 0x68, 0x6f, 0x6e, 0x65, 1750x6d, 0x62, 0xcb, 0x01, 0x01, 0x5c, 0x01, 0x20, 0x66, 0x75,
1740x79, 0x63, 0x6f, 0x6d, 0x62, 0xcb, 0x01, 0x01, 0x5c, 0x01, 1760x3b, 0x05, 0x21, 0x72, 0x65, 0x26, 0x00, 0x02, 0x16, 0x05,
1750x20, 0x66, 0x75, 0x50, 0x05, 0x21, 0x72, 0x65, 0x26, 0x00, 1770x08, 0xa2, 0x00, 0x26, 0x69, 0x72, 0xa4, 0x00, 0x00, 0x1c,
1760x02, 0x2b, 0x05, 0x08, 0xa2, 0x00, 0x26, 0x69, 0x72, 0xa4, 1780x00, 0x0a, 0x24, 0x01, 0x12, 0x3b, 0xfe, 0x01, 0x32, 0x6d,
1770x00, 0x00, 0x1c, 0x00, 0x0a, 0x24, 0x01, 0x12, 0x3b, 0xfe, 1790x61, 0x6b, 0x15, 0x00, 0x13, 0x6d, 0xa6, 0x04, 0x11, 0x61,
1780x01, 0x32, 0x6d, 0x61, 0x6b, 0x15, 0x00, 0x13, 0x6d, 0xa6, 1800xc1, 0x06, 0x41, 0x6e, 0x66, 0x75, 0x73, 0x76, 0x04, 0x02,
1790x04, 0x11, 0x61, 0xd6, 0x06, 0x41, 0x6e, 0x66, 0x75, 0x73, 1810x2b, 0x06, 0x00, 0xbe, 0x01, 0x40, 0x44, 0x69, 0x66, 0x66,
1800x76, 0x04, 0x02, 0x40, 0x06, 0x00, 0xbe, 0x01, 0x40, 0x44, 1820xf8, 0x03, 0x20, 0x74, 0x79, 0xd8, 0x04, 0x03, 0xe4, 0x04,
1810x69, 0x66, 0x66, 0xf8, 0x03, 0x20, 0x74, 0x79, 0xd8, 0x04, 1830x03, 0xf3, 0x01, 0x05, 0x1a, 0x00, 0x03, 0xf9, 0x03, 0x60,
1820x03, 0xe4, 0x04, 0x03, 0xf3, 0x01, 0x05, 0x1a, 0x00, 0x03, 1840x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0xcd, 0x05, 0x02, 0x2f,
1830xf9, 0x03, 0x60, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0xe2, 1850x05, 0x12, 0x2e, 0x45, 0x03, 0x13, 0x33, 0x45, 0x03, 0x81,
1840x05, 0x80, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x2e, 0x00, 1860x75, 0x73, 0x65, 0x72, 0x20, 0x70, 0x72, 0x65, 0x21, 0x01,
1870x21, 0x63, 0x65, 0x4b, 0x03, 0x20, 0x4f, 0x6e, 0x6a, 0x00,
1880x10, 0x74, 0x6a, 0x07, 0x13, 0x73, 0x7b, 0x07, 0x70, 0x75,
1890x70, 0x70, 0x6f, 0x72, 0x74, 0x00, 0x2e, 0x00, 0x17, 0x00,
1900x2e, 0x00, 0x12, 0x2c, 0x39, 0x03, 0x16, 0x50, 0x12, 0x00,
1910x0d, 0x55, 0x03, 0x33, 0x47, 0x61, 0x6d, 0x55, 0x03, 0x02,
1920x22, 0x04, 0x22, 0x6c, 0x65, 0x3c, 0x05, 0x00, 0xd9, 0x00,
1930x22, 0x69, 0x67, 0xcd, 0x04, 0x00, 0xd6, 0x07, 0x00, 0x85,
1940x02, 0x02, 0x5d, 0x05, 0xa0, 0x69, 0x6e, 0x67, 0x73, 0x3a,
1950x00, 0x00, 0x00, 0x60, 0x44, 0xc7, 0x07, 0x82, 0x65, 0x78,
1960x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0xfe, 0x02, 0x02, 0x16,
1970x08, 0x30, 0x66, 0x61, 0x69, 0x6c, 0x06, 0x10, 0x27, 0xa7,
1980x01, 0x02, 0x37, 0x03, 0x02, 0x99, 0x06, 0x03, 0x9b, 0x07,
1990x41, 0x3a, 0x00, 0x77, 0x68, 0xbb, 0x02, 0x01, 0x85, 0x04,
2000x04, 0x08, 0x01, 0x00, 0x3f, 0x00, 0x20, 0x68, 0x61, 0xa3,
2010x08, 0xa1, 0x65, 0x6e, 0x00, 0x65, 0x78, 0x70, 0x6c, 0x69,
2020x63, 0x69, 0xb1, 0x06, 0x04, 0x61, 0x00, 0x05, 0x23, 0x04,
2030x04, 0xf5, 0x07, 0x00, 0x53, 0x00, 0x01, 0x20, 0x05, 0x15,
2040x2d, 0xf3, 0x04, 0x36, 0x69, 0x74, 0x2c, 0xdf, 0x04, 0x50,
2050x69, 0x73, 0x00, 0x73, 0x74, 0xd4, 0x00, 0x00, 0x70, 0x08,
2060x40, 0x6e, 0x2c, 0x00, 0x6a, 0x72, 0x08, 0x01, 0xfb, 0x07,
2070x01, 0xa1, 0x00, 0x50, 0x00, 0x67, 0x72, 0x65, 0x79, 0x3b,
2080x07, 0x44, 0x6f, 0x75, 0x72, 0x2e, 0xc3, 0x05, 0x03, 0x21,
2090x05, 0x25, 0x69, 0x73, 0x28, 0x01, 0x36, 0x66, 0x66, 0x2c,
2100x84, 0x00, 0x04, 0xf6, 0x08, 0x11, 0x65, 0xc1, 0x05, 0x01,
2110x58, 0x00, 0x30, 0x00, 0x61, 0x74, 0x47, 0x02, 0x10, 0x2e,
2120x12, 0x01, 0x52, 0x41, 0x75, 0x74, 0x6f, 0x2d, 0x2c, 0x01,
2130x60, 0x00, 0x75, 0x6e, 0x69, 0x71, 0x75, 0xf2, 0x04, 0x21,
2140x74, 0x68, 0xd3, 0x02, 0x58, 0x65, 0x64, 0x67, 0x65, 0x73,
2150x13, 0x01, 0x27, 0x66, 0x66, 0x14, 0x01, 0x30, 0x2e, 0x00,
2160x57, 0x14, 0x01, 0x01, 0x76, 0x04, 0x18, 0x6f, 0xc5, 0x05,
2170x01, 0xf3, 0x03, 0x00, 0xb6, 0x08, 0x02, 0xfb, 0x00, 0x41,
2180x74, 0x61, 0x74, 0x75, 0x4f, 0x00, 0x05, 0x17, 0x0a, 0x05,
2190x78, 0x01, 0x02, 0xc0, 0x01, 0x71, 0x70, 0x6f, 0x74, 0x65,
2200x6e, 0x74, 0x69, 0x2b, 0x08, 0x82, 0x70, 0x72, 0x6f, 0x70,
2210x61, 0x67, 0x61, 0x74, 0x3c, 0x00, 0x03, 0x47, 0x00, 0x56,
2220x61, 0x6c, 0x6f, 0x6e, 0x67, 0xea, 0x03, 0x01, 0xd2, 0x00,
2230x40, 0x2c, 0x00, 0x69, 0x66, 0xae, 0x08, 0x00, 0xce, 0x03,
2240x98, 0x62, 0x6f, 0x74, 0x68, 0x00, 0x65, 0x6e, 0x64, 0x73,
2250xea, 0x09, 0x02, 0x13, 0x02, 0x00, 0x94, 0x00, 0x25, 0x65,
2260x64, 0xea, 0x0a, 0x72, 0x74, 0x6f, 0x00, 0x6f, 0x6e, 0x6c,
2270x79, 0x39, 0x00, 0x01, 0x0b, 0x05, 0x00, 0x2b, 0x00, 0x53,
2280x2e, 0x00, 0x28, 0x54, 0x68, 0xd8, 0x08, 0x13, 0x69, 0xa0,
2290x02, 0x63, 0x69, 0x66, 0x00, 0x74, 0x77, 0x6f, 0x3e, 0x01,
2300x41, 0x6d, 0x65, 0x65, 0x74, 0x35, 0x01, 0x04, 0x53, 0x04,
2310x00, 0x72, 0x03, 0x27, 0x6e, 0x6f, 0x43, 0x00, 0x43, 0x73,
2320x00, 0x64, 0x6f, 0x57, 0x01, 0x01, 0xcf, 0x01, 0x13, 0x6e,
2330x20, 0x0b, 0x06, 0x7e, 0x01, 0x11, 0x65, 0x52, 0x08, 0x02,
2340xac, 0x00, 0x0c, 0x47, 0x07, 0x00, 0xc5, 0x00, 0x12, 0x6e,
2350x21, 0x00, 0x50, 0x2c, 0x00, 0x73, 0x6f, 0x00, 0x09, 0x00,
2360x30, 0x65, 0x27, 0x73, 0x63, 0x00, 0x61, 0x72, 0x65, 0x61,
2370x73, 0x6f, 0x6e, 0xcd, 0x00, 0x65, 0x73, 0x68, 0x6f, 0x75,
2380x6c, 0x64, 0xa7, 0x05, 0x02, 0x72, 0x07, 0x40, 0x73, 0x65,
2390x70, 0x61, 0x8d, 0x03, 0x01, 0xbe, 0x0b, 0x00, 0xc1, 0x0b,
2400x00, 0x61, 0x01, 0x40, 0x65, 0x61, 0x63, 0x68, 0xe4, 0x00,
2410x26, 0x2e, 0x29, 0x65, 0x0a, 0x00, 0xed, 0x04, 0x70, 0x00,
2420x60, 0x42, 0x61, 0x73, 0x65, 0x64, 0xdc, 0x02, 0x02, 0x4b,
2430x0a, 0x42, 0x6e, 0x6c, 0x79, 0x27, 0x7f, 0x02, 0x63, 0x65,
2440x66, 0x66, 0x65, 0x63, 0x74, 0xa8, 0x01, 0x02, 0x5b, 0x00,
2450x01, 0x9d, 0x01, 0x29, 0x6f, 0x6e, 0x96, 0x01, 0x03, 0x87,
2460x06, 0x07, 0x1f, 0x05, 0x23, 0x61, 0x74, 0x13, 0x05, 0x83,
2470x65, 0x67, 0x72, 0x65, 0x65, 0x00, 0x32, 0x00, 0xd3, 0x0b,
2480x70, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x79, 0x11, 0x02,
2490x02, 0xde, 0x0b, 0x10, 0x46, 0x70, 0x0a, 0x20, 0x78, 0x61,
2500xfd, 0x07, 0x14, 0x2c, 0x25, 0x00, 0x07, 0xc1, 0x06, 0x08,
2510x87, 0x00, 0x07, 0x7b, 0x00, 0x30, 0x6f, 0x63, 0x63, 0x8a,
2520x0c, 0x13, 0x74, 0xd4, 0x03, 0x22, 0x75, 0x72, 0xba, 0x00,
2530x41, 0x63, 0x6f, 0x72, 0x6e, 0xfc, 0x0b, 0x0f, 0xe0, 0x00,
2540x0a, 0x00, 0xa7, 0x01, 0x32, 0x67, 0x61, 0x6d, 0x85, 0x02,
2550x13, 0x65, 0xea, 0x00, 0x04, 0xcd, 0x00, 0x00, 0x2b, 0x03,
2560x01, 0x68, 0x00, 0x01, 0x14, 0x08, 0x30, 0x74, 0x61, 0x6b,
2570xde, 0x00, 0x01, 0x2d, 0x07, 0x05, 0xfc, 0x02, 0x00, 0x77,
2580x01, 0x11, 0x27, 0x74, 0x05, 0x4f, 0x72, 0x65, 0x61, 0x64,
2590xd9, 0x03, 0x09, 0x03, 0xb7, 0x01, 0x00, 0x39, 0x02, 0x03,
2600xbe, 0x00, 0x27, 0x64, 0x6f, 0x5e, 0x0b, 0xe0, 0x77, 0x6f,
2610x72, 0x6b, 0x00, 0x66, 0x6f, 0x72, 0x00, 0x79, 0x6f, 0x75,
2620x2e, 0x00,
185}; 263};
186 264
187const unsigned short help_text_len = 2260; 265const unsigned short help_text_len = 3584;
188const unsigned short help_text_words = 414; 266const unsigned short help_text_words = 660;
189const char quick_help_text[] = "Draw a single closed loop, given clues about number of adjacent edges."; 267const char quick_help_text[] = "Draw a single closed loop, given clues about number of adjacent edges.";
diff --git a/apps/plugins/puzzles/help/magnets.c b/apps/plugins/puzzles/help/magnets.c
index 8c53b2f127..b89b23b097 100644
--- a/apps/plugins/puzzles/help/magnets.c
+++ b/apps/plugins/puzzles/help/magnets.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,187 +6,188 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 143, TEXT_CENTER | C_RED }, 9 { 144, TEXT_CENTER | C_RED },
10 { 323, TEXT_CENTER | C_RED }, 10 { 324, TEXT_CENTER | C_RED },
11 { 340, TEXT_UNDERLINE },
12 { 341, TEXT_UNDERLINE }, 11 { 341, TEXT_UNDERLINE },
13 { 353, TEXT_UNDERLINE }, 12 { 342, TEXT_UNDERLINE },
14 { 355, TEXT_UNDERLINE }, 13 { 354, TEXT_UNDERLINE },
15 { 388, TEXT_UNDERLINE }, 14 { 356, TEXT_UNDERLINE },
16 { 416, TEXT_UNDERLINE }, 15 { 389, TEXT_UNDERLINE },
16 { 417, TEXT_UNDERLINE },
17 LAST_STYLE_ITEM 17 LAST_STYLE_ITEM
18}; 18};
19 19
20/* orig 2502 comp 1653 ratio 0.660671 level 10 saved 849 */ 20/* orig 2522 comp 1662 ratio 0.659001 level 10 saved 860 */
21const char help_text[] = { 21const char help_text[] = {
220xf2, 0x3e, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 220xfe, 0x07, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
230x33, 0x33, 0x3a, 0x20, 0x4d, 0x61, 0x67, 0x6e, 0x65, 0x74, 230x33, 0x33, 0x3a, 0x20, 0x4d, 0x61, 0x67, 0x6e, 0x65, 0x74,
240x73, 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x72, 0x65, 0x63, 240x73, 0x20, 0x00, 0x2d, 0x01, 0x00, 0xf2, 0x2a, 0x00, 0x00,
250x74, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x00, 0x67, 250x00, 0x41, 0x00, 0x72, 0x65, 0x63, 0x74, 0x61, 0x6e, 0x67,
260x72, 0x69, 0x64, 0x00, 0x68, 0x61, 0x73, 0x00, 0x62, 0x65, 260x75, 0x6c, 0x61, 0x72, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00,
270x65, 0x6e, 0x00, 0x66, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x00, 270x68, 0x61, 0x73, 0x00, 0x62, 0x65, 0x65, 0x6e, 0x00, 0x66,
280x77, 0x69, 0x74, 0x68, 0x00, 0x61, 0x00, 0x6d, 0x69, 0x78, 280x69, 0x6c, 0x6c, 0x65, 0x64, 0x00, 0x77, 0x69, 0x74, 0x68,
290x74, 0x75, 0x72, 0x65, 0x00, 0x6f, 0x66, 0x00, 0x6d, 0x40, 290x00, 0x61, 0x00, 0x6d, 0x69, 0x78, 0x74, 0x75, 0x72, 0x65,
300x00, 0xf2, 0x04, 0x00, 0x28, 0x74, 0x68, 0x61, 0x74, 0x00, 300x00, 0x6f, 0x66, 0x00, 0x6d, 0x54, 0x00, 0xf2, 0x04, 0x00,
310x69, 0x73, 0x2c, 0x00, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x6f, 310x28, 0x74, 0x68, 0x61, 0x74, 0x00, 0x69, 0x73, 0x2c, 0x00,
320x65, 0x73, 0x2d, 0x00, 0xf1, 0x05, 0x6f, 0x6e, 0x65, 0x00, 320x64, 0x6f, 0x6d, 0x69, 0x6e, 0x6f, 0x65, 0x73, 0x2d, 0x00,
330x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x00, 0x65, 330xf1, 0x05, 0x6f, 0x6e, 0x65, 0x00, 0x70, 0x6f, 0x73, 0x69,
340x6e, 0x64, 0x00, 0x61, 0x6e, 0x64, 0x15, 0x00, 0x44, 0x6e, 340x74, 0x69, 0x76, 0x65, 0x00, 0x65, 0x6e, 0x64, 0x00, 0x61,
350x65, 0x67, 0x61, 0x15, 0x00, 0x11, 0x29, 0x16, 0x00, 0x56, 350x6e, 0x64, 0x15, 0x00, 0x44, 0x6e, 0x65, 0x67, 0x61, 0x15,
360x62, 0x6c, 0x61, 0x6e, 0x6b, 0x3f, 0x00, 0x0f, 0x52, 0x00, 360x00, 0x11, 0x29, 0x16, 0x00, 0x56, 0x62, 0x6c, 0x61, 0x6e,
370x05, 0xf6, 0x0a, 0x74, 0x77, 0x6f, 0x00, 0x6e, 0x65, 0x75, 370x6b, 0x3f, 0x00, 0x0f, 0x52, 0x00, 0x05, 0xf6, 0x0a, 0x74,
380x74, 0x72, 0x61, 0x6c, 0x00, 0x70, 0x6f, 0x6c, 0x65, 0x73, 380x77, 0x6f, 0x00, 0x6e, 0x65, 0x75, 0x74, 0x72, 0x61, 0x6c,
390x29, 0x2e, 0x00, 0x54, 0x68, 0x65, 0x73, 0x65, 0x28, 0x00, 390x00, 0x70, 0x6f, 0x6c, 0x65, 0x73, 0x29, 0x2e, 0x00, 0x54,
400xf0, 0x05, 0x61, 0x72, 0x65, 0x00, 0x69, 0x6e, 0x69, 0x74, 400x68, 0x65, 0x73, 0x65, 0x28, 0x00, 0xf0, 0x05, 0x61, 0x72,
410x69, 0x61, 0x6c, 0x6c, 0x79, 0x00, 0x6f, 0x6e, 0x6c, 0x79, 410x65, 0x00, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x6c,
420x00, 0x73, 0xc6, 0x00, 0xf2, 0x0a, 0x69, 0x6e, 0x00, 0x73, 420x79, 0x00, 0x6f, 0x6e, 0x6c, 0x79, 0x00, 0x73, 0xc6, 0x00,
430x69, 0x6c, 0x68, 0x6f, 0x75, 0x65, 0x74, 0x74, 0x65, 0x2e, 430xf2, 0x0a, 0x69, 0x6e, 0x00, 0x73, 0x69, 0x6c, 0x68, 0x6f,
440x00, 0x41, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x00, 0x74, 0x68, 440x75, 0x65, 0x74, 0x74, 0x65, 0x2e, 0x00, 0x41, 0x72, 0x6f,
450x65, 0xee, 0x00, 0x00, 0x37, 0x00, 0xf0, 0x00, 0x70, 0x6c, 450x75, 0x6e, 0x64, 0x00, 0x74, 0x68, 0x65, 0xee, 0x00, 0x00,
460x61, 0x63, 0x65, 0x64, 0x00, 0x61, 0x00, 0x6e, 0x75, 0x6d, 460x37, 0x00, 0xf0, 0x00, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x64,
470x62, 0x65, 0x72, 0xe3, 0x00, 0xf1, 0x01, 0x63, 0x6c, 0x75, 470x00, 0x61, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0xe3,
480x65, 0x73, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 480x00, 0xf1, 0x01, 0x63, 0x6c, 0x75, 0x65, 0x73, 0x00, 0x69,
490x69, 0x6e, 0x67, 0x31, 0x00, 0x06, 0x1f, 0x00, 0x05, 0xde, 490x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x31,
500x00, 0x00, 0xc4, 0x00, 0x05, 0xd6, 0x00, 0x01, 0x9a, 0x00, 500x00, 0x06, 0x1f, 0x00, 0x05, 0xde, 0x00, 0x00, 0xc4, 0x00,
510xa0, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 510x05, 0xd6, 0x00, 0x01, 0x9a, 0x00, 0xa0, 0x00, 0x63, 0x6f,
520x64, 0x7b, 0x00, 0x50, 0x63, 0x65, 0x72, 0x74, 0x61, 0x08, 520x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x7b, 0x00, 0x50,
530x00, 0x61, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x30, 0x00, 530x63, 0x65, 0x72, 0x74, 0x61, 0x08, 0x00, 0x61, 0x6f, 0x6c,
540xf0, 0x0b, 0x72, 0x6f, 0x77, 0x73, 0x2e, 0x00, 0x00, 0x00, 540x75, 0x6d, 0x6e, 0x73, 0x30, 0x00, 0xf0, 0x0b, 0x72, 0x6f,
550x59, 0x6f, 0x75, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 0x69, 550x77, 0x73, 0x2e, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x72,
560x73, 0x00, 0x74, 0x6f, 0x00, 0x63, 0x6f, 0x72, 0x8c, 0x01, 560x00, 0x61, 0x69, 0x6d, 0x00, 0x69, 0x73, 0x00, 0x74, 0x6f,
570x22, 0x6c, 0x79, 0x90, 0x00, 0x01, 0x72, 0x00, 0x04, 0x6a, 570x00, 0x63, 0x6f, 0x72, 0x8c, 0x01, 0x22, 0x6c, 0x79, 0x90,
580x01, 0x0f, 0x2b, 0x01, 0x00, 0x51, 0x73, 0x75, 0x63, 0x68, 580x00, 0x01, 0x72, 0x00, 0x04, 0x6a, 0x01, 0x0f, 0x2b, 0x01,
590x00, 0x2f, 0x01, 0x31, 0x61, 0x6c, 0x6c, 0x2d, 0x00, 0x02, 590x00, 0x51, 0x73, 0x75, 0x63, 0x68, 0x00, 0x2f, 0x01, 0x31,
600xb4, 0x00, 0x00, 0xd1, 0x00, 0xa3, 0x73, 0x61, 0x74, 0x69, 600x61, 0x6c, 0x6c, 0x2d, 0x00, 0x02, 0xb4, 0x00, 0x00, 0xd1,
610x73, 0x66, 0x69, 0x65, 0x64, 0x2c, 0x3f, 0x01, 0xd0, 0x68, 610x00, 0xa3, 0x73, 0x61, 0x74, 0x69, 0x73, 0x66, 0x69, 0x65,
620x65, 0x00, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 620x64, 0x2c, 0x3f, 0x01, 0xd0, 0x68, 0x65, 0x00, 0x61, 0x64,
630x61, 0x6c, 0xa2, 0x00, 0x72, 0x73, 0x74, 0x72, 0x61, 0x69, 630x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0xa2, 0x00,
640x6e, 0x74, 0x41, 0x00, 0x21, 0x6e, 0x6f, 0x61, 0x01, 0x40, 640x72, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x41, 0x00,
650x73, 0x69, 0x6d, 0x69, 0x06, 0x02, 0x02, 0x75, 0x00, 0x23, 650x21, 0x6e, 0x6f, 0x61, 0x01, 0x40, 0x73, 0x69, 0x6d, 0x69,
660x69, 0x63, 0xd0, 0x00, 0xf1, 0x00, 0x6d, 0x61, 0x79, 0x00, 660x06, 0x02, 0x02, 0x75, 0x00, 0x23, 0x69, 0x63, 0xd0, 0x00,
670x62, 0x65, 0x00, 0x6f, 0x72, 0x74, 0x68, 0x6f, 0x67, 0x6f, 670xf1, 0x00, 0x6d, 0x61, 0x79, 0x00, 0x62, 0x65, 0x00, 0x6f,
680x6e, 0x5f, 0x01, 0xd2, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x65, 680x72, 0x74, 0x68, 0x6f, 0x67, 0x6f, 0x6e, 0x5f, 0x01, 0xd2,
690x6e, 0x74, 0x00, 0x28, 0x73, 0x69, 0x6e, 0xac, 0x00, 0xb8, 690x61, 0x64, 0x6a, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x00, 0x28,
700x79, 0x00, 0x72, 0x65, 0x70, 0x65, 0x6c, 0x29, 0x2e, 0x00, 700x73, 0x69, 0x6e, 0xac, 0x00, 0xb8, 0x79, 0x00, 0x72, 0x65,
710x4e, 0xa9, 0x01, 0x72, 0x00, 0x64, 0x6f, 0x00, 0x6e, 0x6f, 710x70, 0x65, 0x6c, 0x29, 0x2e, 0x00, 0x4e, 0xa9, 0x01, 0x72,
720x74, 0x1d, 0x00, 0x11, 0x2c, 0xc9, 0x00, 0x30, 0x63, 0x61, 720x00, 0x64, 0x6f, 0x00, 0x6e, 0x6f, 0x74, 0x1d, 0x00, 0x11,
730x6e, 0x51, 0x00, 0x05, 0x44, 0x00, 0xc1, 0x74, 0x6f, 0x00, 730x2c, 0xc9, 0x00, 0x30, 0x63, 0x61, 0x6e, 0x51, 0x00, 0x05,
740x61, 0x6e, 0x79, 0x00, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x35, 740x44, 0x00, 0xc1, 0x74, 0x6f, 0x00, 0x61, 0x6e, 0x79, 0x00,
750x00, 0x00, 0x1d, 0x01, 0xf1, 0x0b, 0x43, 0x72, 0x65, 0x64, 750x6f, 0x74, 0x68, 0x65, 0x72, 0x35, 0x00, 0x00, 0x1d, 0x01,
760x69, 0x74, 0x00, 0x66, 0x6f, 0x72, 0x00, 0x74, 0x68, 0x69, 760xf1, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x00, 0x66,
770x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x67, 770x6f, 0x72, 0x00, 0x74, 0x68, 0x69, 0x73, 0x00, 0x70, 0x75,
780x6f, 0x65, 0x2d, 0x01, 0xa0, 0x4a, 0x61, 0x6e, 0x6b, 0x6f, 780x7a, 0x7a, 0x6c, 0x65, 0x00, 0x67, 0x6f, 0x65, 0x2d, 0x01,
790x00, 0x5b, 0x31, 0x36, 0x5d, 0x2d, 0x00, 0x13, 0x4d, 0x27, 790xa0, 0x4a, 0x61, 0x6e, 0x6b, 0x6f, 0x00, 0x5b, 0x31, 0x36,
800x01, 0x22, 0x77, 0x61, 0x7f, 0x01, 0x70, 0x72, 0x69, 0x62, 800x5d, 0x2d, 0x00, 0x13, 0x4d, 0x27, 0x01, 0x22, 0x77, 0x61,
810x75, 0x74, 0x65, 0x64, 0x29, 0x00, 0x01, 0x3d, 0x00, 0x60, 810x7f, 0x01, 0x70, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64,
820x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0xfe, 0x00, 0xf0, 0x01, 820x29, 0x00, 0x01, 0x3d, 0x00, 0x60, 0x63, 0x6f, 0x6c, 0x6c,
830x00, 0x62, 0x79, 0x00, 0x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 830x65, 0x63, 0xfe, 0x00, 0xf0, 0x01, 0x00, 0x62, 0x79, 0x00,
840x48, 0x61, 0x72, 0x76, 0x65, 0x79, 0x3e, 0x00, 0x00, 0x46, 840x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61, 0x72, 0x76,
850x00, 0xd0, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 850x65, 0x79, 0x3e, 0x00, 0x00, 0x46, 0x00, 0xd0, 0x00, 0x68,
860x77, 0x77, 0x77, 0x2e, 0x6a, 0x5c, 0x00, 0xc2, 0x2e, 0x61, 860x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
870x74, 0x2f, 0x52, 0x61, 0x65, 0x74, 0x73, 0x65, 0x6c, 0x2f, 870x6a, 0x5c, 0x00, 0xc2, 0x2e, 0x61, 0x74, 0x2f, 0x52, 0x61,
880x5f, 0x00, 0xf5, 0x03, 0x65, 0x2f, 0x69, 0x6e, 0x64, 0x65, 880x65, 0x74, 0x73, 0x65, 0x6c, 0x2f, 0x5f, 0x00, 0xf5, 0x03,
890x78, 0x2e, 0x68, 0x74, 0x6d, 0x00, 0x00, 0x00, 0x33, 0x33, 890x65, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74,
900x2e, 0x31, 0x49, 0x03, 0x01, 0x74, 0x00, 0x21, 0x6f, 0x6c, 900x6d, 0x00, 0x00, 0x00, 0x33, 0x33, 0x2e, 0x31, 0x5d, 0x03,
910x52, 0x03, 0xa0, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 910x01, 0x74, 0x00, 0xf0, 0x02, 0x6f, 0x6c, 0x73, 0x20, 0x00,
920x69, 0x63, 0x6b, 0x37, 0x02, 0xf5, 0x00, 0x6f, 0x6e, 0x00, 920x00, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69,
930x61, 0x6e, 0x00, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x00, 0x73, 930x63, 0x6b, 0x37, 0x02, 0xf5, 0x00, 0x6f, 0x6e, 0x00, 0x61,
940x71, 0x75, 0x6e, 0x02, 0x33, 0x73, 0x00, 0x61, 0x68, 0x01, 940x6e, 0x00, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x00, 0x73, 0x71,
950x23, 0x00, 0x61, 0x86, 0x01, 0x02, 0x54, 0x02, 0x26, 0x6f, 950x75, 0x6e, 0x02, 0x33, 0x73, 0x00, 0x61, 0x68, 0x01, 0x23,
960x6e, 0xb3, 0x01, 0x05, 0x66, 0x02, 0x00, 0x15, 0x01, 0x00, 960x00, 0x61, 0x86, 0x01, 0x02, 0x54, 0x02, 0x26, 0x6f, 0x6e,
970x4b, 0x00, 0x00, 0x15, 0x00, 0x03, 0x46, 0x00, 0x13, 0x61, 970xb3, 0x01, 0x05, 0x66, 0x02, 0x00, 0x15, 0x01, 0x00, 0x4b,
980xc5, 0x02, 0x09, 0x7d, 0x02, 0x04, 0x24, 0x00, 0x02, 0x4b, 980x00, 0x00, 0x15, 0x00, 0x03, 0x46, 0x00, 0x13, 0x61, 0xc5,
990x01, 0x40, 0x68, 0x61, 0x6c, 0x66, 0xad, 0x02, 0x06, 0x49, 990x02, 0x09, 0x7d, 0x02, 0x04, 0x24, 0x00, 0x02, 0x4b, 0x01,
1000x02, 0x39, 0x3b, 0x00, 0x6c, 0x9e, 0x00, 0x20, 0x61, 0x67, 1000x40, 0x68, 0x61, 0x6c, 0x66, 0xad, 0x02, 0x06, 0x49, 0x02,
1010x9c, 0x02, 0x83, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 1010x39, 0x3b, 0x00, 0x6c, 0x9e, 0x00, 0x20, 0x61, 0x67, 0x9c,
1020x73, 0x74, 0x00, 0x62, 0x6c, 0x61, 0x72, 0x69, 0x74, 0x79, 1020x02, 0x83, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x73,
1030xab, 0x01, 0x10, 0x61, 0x40, 0x01, 0x31, 0x72, 0x64, 0x00, 1030x74, 0x00, 0x62, 0x6c, 0x61, 0x72, 0x69, 0x74, 0x79, 0xab,
1040x32, 0x00, 0x87, 0x00, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 1040x01, 0x10, 0x61, 0x40, 0x01, 0x31, 0x72, 0x64, 0x00, 0x32,
1050x73, 0x51, 0x00, 0x00, 0x3f, 0x01, 0x4f, 0x52, 0x69, 0x67, 1050x00, 0x87, 0x00, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x73,
1060x68, 0xf2, 0x00, 0x14, 0x08, 0xc3, 0x02, 0x10, 0x00, 0xa4, 1060x51, 0x00, 0x00, 0x3f, 0x01, 0x4f, 0x52, 0x69, 0x67, 0x68,
1070x00, 0x2c, 0x65, 0x2e, 0x3f, 0x00, 0x02, 0x93, 0x00, 0x03, 1070xf2, 0x00, 0x14, 0x08, 0xc3, 0x02, 0x10, 0x00, 0xa4, 0x00,
1080x32, 0x00, 0x00, 0x96, 0x02, 0x41, 0x71, 0x75, 0x65, 0x73, 1080x2c, 0x65, 0x2e, 0x3f, 0x00, 0x02, 0x93, 0x00, 0x03, 0x32,
1090x17, 0x01, 0x54, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0xe2, 0x00, 1090x00, 0x00, 0x96, 0x02, 0x41, 0x71, 0x75, 0x65, 0x73, 0x17,
1100x02, 0x44, 0x00, 0x90, 0x2c, 0x00, 0x73, 0x69, 0x67, 0x6e, 1100x01, 0x54, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0xe2, 0x00, 0x02,
1110x69, 0x66, 0x79, 0x3a, 0x00, 0x12, 0x60, 0xeb, 0x01, 0x20, 1110x44, 0x00, 0x90, 0x2c, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x69,
1120x61, 0x6e, 0x6f, 0x02, 0x22, 0x62, 0x65, 0x6d, 0x00, 0x84, 1120x66, 0x79, 0x3a, 0x00, 0x12, 0x60, 0xeb, 0x01, 0x20, 0x61,
1130x27, 0x00, 0x28, 0x77, 0x68, 0x69, 0x63, 0x68, 0x75, 0x02, 1130x6e, 0x6f, 0x02, 0x22, 0x62, 0x65, 0x6d, 0x00, 0x84, 0x27,
1140x81, 0x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x00, 0x74, 0x95, 1140x00, 0x28, 0x77, 0x68, 0x69, 0x63, 0x68, 0x75, 0x02, 0x81,
1150x02, 0x61, 0x65, 0x00, 0x64, 0x65, 0x64, 0x75, 0x18, 0x02, 1150x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x00, 0x74, 0x95, 0x02,
1160xf2, 0x02, 0x73, 0x00, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x00, 1160x61, 0x65, 0x00, 0x64, 0x65, 0x64, 0x75, 0x18, 0x02, 0xf2,
1170x73, 0x6f, 0x6c, 0x76, 0x69, 0x6e, 0x67, 0x29, 0x2c, 0xaa, 1170x02, 0x73, 0x00, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x00, 0x73,
1180x03, 0x0e, 0x9c, 0x00, 0x02, 0xdb, 0x00, 0x37, 0x69, 0x65, 1180x6f, 0x6c, 0x76, 0x69, 0x6e, 0x67, 0x29, 0x2c, 0xaa, 0x03,
1190x73, 0x87, 0x00, 0x1d, 0x2e, 0xf7, 0x01, 0x11, 0x61, 0x8d, 1190x0e, 0x9c, 0x00, 0x02, 0xdb, 0x00, 0x37, 0x69, 0x65, 0x73,
1200x03, 0x51, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0xb8, 0x00, 0x50, 1200x87, 0x00, 0x1d, 0x2e, 0xf7, 0x01, 0x11, 0x61, 0x8d, 0x03,
1210x00, 0x69, 0x74, 0x00, 0x61, 0x0c, 0x03, 0x80, 0x6e, 0x65, 1210x51, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0xb8, 0x00, 0x50, 0x00,
1220x00, 0x28, 0x67, 0x72, 0x65, 0x79, 0x11, 0x00, 0xb4, 0x6f, 1220x69, 0x74, 0x00, 0x61, 0x0c, 0x03, 0x80, 0x6e, 0x65, 0x00,
1230x75, 0x74, 0x29, 0x2c, 0x00, 0x6f, 0x72, 0x00, 0x75, 0x6e, 1230x28, 0x67, 0x72, 0x65, 0x79, 0x11, 0x00, 0xb4, 0x6f, 0x75,
1240x24, 0x00, 0x21, 0x69, 0x66, 0x06, 0x00, 0x91, 0x73, 0x00, 1240x74, 0x29, 0x2c, 0x00, 0x6f, 0x72, 0x00, 0x75, 0x6e, 0x24,
1250x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x3d, 0x00, 0x23, 1250x00, 0x21, 0x69, 0x66, 0x06, 0x00, 0x91, 0x73, 0x00, 0x61,
1260x65, 0x64, 0x2e, 0x04, 0x01, 0xc5, 0x00, 0x40, 0x61, 0x6c, 1260x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x3d, 0x00, 0x23, 0x65,
1270x73, 0x6f, 0xc7, 0x00, 0x02, 0xf3, 0x03, 0x91, 0x75, 0x72, 1270x64, 0x2e, 0x04, 0x01, 0xc5, 0x00, 0x40, 0x61, 0x6c, 0x73,
1280x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x16, 0x03, 0x20, 1280x6f, 0xc7, 0x00, 0x02, 0xf3, 0x03, 0x91, 0x75, 0x72, 0x73,
1290x6d, 0x6f, 0x93, 0x04, 0x04, 0x16, 0x00, 0x1a, 0x61, 0xeb, 1290x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x16, 0x03, 0x20, 0x6d,
1300x04, 0x74, 0x2e, 0x00, 0x50, 0x72, 0x65, 0x73, 0x73, 0xcd, 1300x6f, 0x93, 0x04, 0x04, 0x16, 0x00, 0x1a, 0x61, 0xeb, 0x04,
1310x04, 0x60, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x00, 1310x74, 0x2e, 0x00, 0x50, 0x72, 0x65, 0x73, 0x73, 0xcd, 0x04,
1320x02, 0xa7, 0x00, 0x54, 0x6c, 0x61, 0x79, 0x00, 0x61, 0x9c, 1320x60, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x00, 0x02,
1330x01, 0x03, 0xf4, 0x05, 0x0a, 0x81, 0x02, 0x0c, 0xa9, 0x02, 1330xa7, 0x00, 0x54, 0x6c, 0x61, 0x79, 0x00, 0x61, 0x9c, 0x01,
1340x34, 0x3b, 0x00, 0x70, 0x51, 0x00, 0x0f, 0x49, 0x02, 0x08, 1340x03, 0xf4, 0x05, 0x0a, 0x81, 0x02, 0x0c, 0xa9, 0x02, 0x34,
1350x04, 0xaa, 0x02, 0x19, 0x6e, 0x3f, 0x02, 0x04, 0xc0, 0x01, 1350x3b, 0x00, 0x70, 0x51, 0x00, 0x0f, 0x49, 0x02, 0x08, 0x04,
1360x13, 0x61, 0xe1, 0x05, 0x09, 0x98, 0x02, 0x35, 0x2e, 0x00, 1360xaa, 0x02, 0x19, 0x6e, 0x3f, 0x02, 0x04, 0xc0, 0x01, 0x13,
1370x55, 0xa7, 0x00, 0x20, 0x73, 0x70, 0x0c, 0x05, 0x30, 0x62, 1370x61, 0xe1, 0x05, 0x09, 0x98, 0x02, 0x35, 0x2e, 0x00, 0x55,
1380x61, 0x72, 0xe7, 0x04, 0x32, 0x6f, 0x77, 0x73, 0x1b, 0x02, 1380xa7, 0x00, 0x20, 0x73, 0x70, 0x0c, 0x05, 0x30, 0x62, 0x61,
1390x10, 0x6d, 0x38, 0x04, 0x2c, 0x6f, 0x66, 0x14, 0x05, 0x03, 1390x72, 0xe7, 0x04, 0x32, 0x6f, 0x77, 0x73, 0x1b, 0x02, 0x10,
1400x5e, 0x04, 0x72, 0x6e, 0x6f, 0x74, 0x2d, 0x62, 0x65, 0x2d, 1400x6d, 0x38, 0x04, 0x2c, 0x6f, 0x66, 0x14, 0x05, 0x03, 0x5e,
1410x1d, 0x00, 0x51, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x69, 0x00, 1410x04, 0x72, 0x6e, 0x6f, 0x74, 0x2d, 0x62, 0x65, 0x2d, 0x1d,
1420x00, 0x4c, 0x04, 0x02, 0xd2, 0x01, 0x16, 0x00, 0x6a, 0x00, 1420x00, 0x51, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x69, 0x00, 0x00,
1430x43, 0x00, 0x00, 0x28, 0x41, 0x40, 0x05, 0x13, 0x61, 0x0a, 1430x4c, 0x04, 0x02, 0xd2, 0x01, 0x16, 0x00, 0x6a, 0x00, 0x43,
1440x02, 0x72, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0xc1, 1440x00, 0x00, 0x28, 0x41, 0x40, 0x05, 0x13, 0x61, 0x0a, 0x02,
1450x05, 0x13, 0x73, 0x38, 0x04, 0x31, 0x32, 0x2e, 0x31, 0x5b, 1450x72, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0xc1, 0x05,
1460x05, 0x01, 0x7f, 0x01, 0xb2, 0x61, 0x76, 0x61, 0x69, 0x6c, 1460x13, 0x73, 0x38, 0x04, 0x31, 0x32, 0x2e, 0x31, 0x5b, 0x05,
1470x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0x0b, 0x04, 0x15, 0x32, 1470x01, 0x7f, 0x01, 0xb2, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,
1480x0b, 0x04, 0x91, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 1480x62, 0x6c, 0x65, 0x2e, 0x29, 0x0b, 0x04, 0x15, 0x32, 0x0b,
1490x65, 0x72, 0x0d, 0x04, 0x02, 0xa4, 0x06, 0x06, 0x14, 0x00, 1490x04, 0x91, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
1500x02, 0x43, 0x00, 0x04, 0x3e, 0x00, 0x51, 0x00, 0x66, 0x72, 1500x72, 0x0d, 0x04, 0x02, 0xa4, 0x06, 0x06, 0x14, 0x00, 0x02,
1510x6f, 0x6d, 0x7b, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 1510x43, 0x00, 0x04, 0x3e, 0x00, 0x51, 0x00, 0x66, 0x72, 0x6f,
1520x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x71, 1520x6d, 0x7b, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f,
1530x00, 0x03, 0xe9, 0x02, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 1530x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x71, 0x00,
1540x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xad, 0x00, 0x90, 0x57, 1540x03, 0xe9, 0x02, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27,
1550x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0xc8, 0x00, 1550x00, 0x6d, 0x65, 0x6e, 0x75, 0xad, 0x00, 0x90, 0x57, 0x69,
1560x61, 0x00, 0x00, 0x00, 0x53, 0x69, 0x7a, 0x93, 0x07, 0x01, 1560x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0xc8, 0x00, 0x61,
1570xcc, 0x06, 0x23, 0x69, 0x6e, 0x72, 0x03, 0x11, 0x73, 0x1e, 1570x00, 0x00, 0x00, 0x53, 0x69, 0x7a, 0x93, 0x07, 0x01, 0xcc,
1580x07, 0x13, 0x72, 0x81, 0x02, 0x22, 0x62, 0x65, 0x0b, 0x04, 1580x06, 0x23, 0x69, 0x6e, 0x72, 0x03, 0x11, 0x73, 0x1e, 0x07,
1590x01, 0x3c, 0x00, 0x24, 0x00, 0x78, 0x3d, 0x00, 0x05, 0x36, 1590x13, 0x72, 0x81, 0x02, 0x22, 0x62, 0x65, 0x0b, 0x04, 0x01,
1600x01, 0x25, 0x69, 0x6e, 0x24, 0x02, 0x10, 0x3a, 0x82, 0x02, 1600x3c, 0x00, 0x24, 0x00, 0x78, 0x3d, 0x00, 0x05, 0x36, 0x01,
1610x01, 0x48, 0x03, 0x03, 0xec, 0x06, 0x53, 0x69, 0x73, 0x00, 1610x25, 0x69, 0x6e, 0x24, 0x02, 0x10, 0x3a, 0x82, 0x02, 0x01,
1620x6f, 0x64, 0xc0, 0x01, 0x25, 0x6f, 0x6e, 0x7e, 0x04, 0x04, 1620x48, 0x03, 0x03, 0xec, 0x06, 0x53, 0x69, 0x73, 0x00, 0x6f,
1630x58, 0x00, 0x01, 0x63, 0x01, 0x01, 0x45, 0x01, 0x53, 0x47, 1630x64, 0xc0, 0x01, 0x25, 0x6f, 0x6e, 0x7e, 0x04, 0x04, 0x58,
1640x72, 0x69, 0x64, 0x73, 0x38, 0x02, 0x71, 0x74, 0x00, 0x6c, 1640x00, 0x01, 0x63, 0x01, 0x01, 0x45, 0x01, 0x53, 0x47, 0x72,
1650x65, 0x61, 0x73, 0x74, 0x31, 0x00, 0x00, 0x3e, 0x00, 0x70, 1650x69, 0x64, 0x73, 0x38, 0x02, 0x71, 0x74, 0x00, 0x6c, 0x65,
1660x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0xd2, 0x00, 0x21, 1660x61, 0x73, 0x74, 0x31, 0x00, 0x00, 0x3e, 0x00, 0x70, 0x64,
1670x65, 0x6e, 0x96, 0x05, 0x90, 0x62, 0x65, 0x00, 0x65, 0x61, 1670x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0xd2, 0x00, 0x21, 0x65,
1680x73, 0x69, 0x65, 0x72, 0x0d, 0x00, 0x00, 0x74, 0x03, 0x02, 1680x6e, 0x96, 0x05, 0x90, 0x62, 0x65, 0x00, 0x65, 0x61, 0x73,
1690x4a, 0x01, 0xa0, 0x44, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 1690x69, 0x65, 0x72, 0x0d, 0x00, 0x00, 0x74, 0x03, 0x02, 0x4a,
1700x6c, 0x74, 0x79, 0x02, 0x06, 0x03, 0x55, 0x05, 0x02, 0x30, 1700x01, 0xa0, 0x44, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c,
1710x02, 0x06, 0x1a, 0x00, 0x03, 0xd2, 0x04, 0x60, 0x67, 0x65, 1710x74, 0x79, 0x02, 0x06, 0x03, 0x55, 0x05, 0x02, 0x30, 0x02,
1720x6e, 0x65, 0x72, 0x61, 0xe6, 0x05, 0x02, 0x1b, 0x06, 0xf0, 1720x06, 0x1a, 0x00, 0x03, 0xd2, 0x04, 0x60, 0x67, 0x65, 0x6e,
1730x00, 0x2e, 0x00, 0x41, 0x74, 0x00, 0x54, 0x72, 0x69, 0x63, 1730x65, 0x72, 0x61, 0xe6, 0x05, 0x02, 0x1b, 0x06, 0xf0, 0x00,
1740x6b, 0x79, 0x00, 0x6c, 0x65, 0x76, 0x6d, 0x06, 0x31, 0x79, 1740x2e, 0x00, 0x41, 0x74, 0x00, 0x54, 0x72, 0x69, 0x63, 0x6b,
1750x6f, 0x75, 0x71, 0x01, 0x62, 0x72, 0x65, 0x71, 0x75, 0x69, 1750x79, 0x00, 0x6c, 0x65, 0x76, 0x6d, 0x06, 0x31, 0x79, 0x6f,
1760x72, 0x10, 0x06, 0x89, 0x6d, 0x61, 0x6b, 0x65, 0x00, 0x6d, 1760x75, 0x71, 0x01, 0x62, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72,
1770x6f, 0x72, 0xfc, 0x03, 0x53, 0x61, 0x62, 0x6f, 0x75, 0x74, 1770x10, 0x06, 0x89, 0x6d, 0x61, 0x6b, 0x65, 0x00, 0x6d, 0x6f,
1780xb4, 0x04, 0x09, 0x4d, 0x02, 0x42, 0x72, 0x6f, 0x77, 0x2f, 1780x72, 0xfc, 0x03, 0x53, 0x61, 0x62, 0x6f, 0x75, 0x74, 0xb4,
1790xbb, 0x07, 0x61, 0x00, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0xb8, 1790x04, 0x09, 0x4d, 0x02, 0x42, 0x72, 0x6f, 0x77, 0x2f, 0xbb,
1800x07, 0x62, 0x53, 0x74, 0x72, 0x69, 0x70, 0x20, 0x6e, 0x07, 1800x07, 0x61, 0x00, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0xb8, 0x07,
1810xe1, 0x00, 0x00, 0x49, 0x66, 0x00, 0x74, 0x72, 0x75, 0x65, 1810x62, 0x53, 0x74, 0x72, 0x69, 0x70, 0x20, 0x6e, 0x07, 0xe1,
1820x2c, 0x00, 0x73, 0x6f, 0x6d, 0x8b, 0x01, 0x08, 0x8b, 0x07, 1820x00, 0x00, 0x49, 0x66, 0x00, 0x74, 0x72, 0x75, 0x65, 0x2c,
1830x0e, 0x6c, 0x08, 0x02, 0x05, 0x03, 0x10, 0x64, 0x25, 0x01, 1830x00, 0x73, 0x6f, 0x6d, 0x8b, 0x01, 0x08, 0x8b, 0x07, 0x0e,
1840x03, 0xc2, 0x00, 0x01, 0x18, 0x01, 0x40, 0x69, 0x6d, 0x65, 1840x6c, 0x08, 0x02, 0x05, 0x03, 0x10, 0x64, 0x25, 0x01, 0x03,
1850x2c, 0x9c, 0x00, 0x04, 0xf7, 0x02, 0x03, 0xef, 0x06, 0x02, 1850xc2, 0x00, 0x01, 0x18, 0x01, 0x40, 0x69, 0x6d, 0x65, 0x2c,
1860xa9, 0x00, 0xa0, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 1860x9c, 0x00, 0x04, 0xf7, 0x02, 0x03, 0xef, 0x06, 0x02, 0xa9,
1870x74, 0x2e, 0x00, 1870x00, 0xa0, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74,
1880x2e, 0x00,
188}; 189};
189 190
190const unsigned short help_text_len = 2502; 191const unsigned short help_text_len = 2522;
191const unsigned short help_text_words = 438; 192const unsigned short help_text_words = 439;
192const char quick_help_text[] = "Place magnets to satisfy the clues and avoid like poles touching."; 193const char quick_help_text[] = "Place magnets to satisfy the clues and avoid like poles touching.";
diff --git a/apps/plugins/puzzles/help/map.c b/apps/plugins/puzzles/help/map.c
index 2f577ae6b2..18b3fb5ace 100644
--- a/apps/plugins/puzzles/help/map.c
+++ b/apps/plugins/puzzles/help/map.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,251 +6,269 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 81, TEXT_UNDERLINE }, 9 { 87, TEXT_UNDERLINE },
10 { 157, TEXT_CENTER | C_RED }, 10 { 163, TEXT_CENTER | C_RED },
11 { 244, TEXT_UNDERLINE }, 11 { 250, TEXT_UNDERLINE },
12 { 268, TEXT_UNDERLINE }, 12 { 274, TEXT_UNDERLINE },
13 { 507, TEXT_CENTER | C_RED }, 13 { 513, TEXT_CENTER | C_RED },
14 { 524, TEXT_UNDERLINE }, 14 { 530, TEXT_UNDERLINE },
15 { 525, TEXT_UNDERLINE }, 15 { 531, TEXT_UNDERLINE },
16 { 535, TEXT_UNDERLINE }, 16 { 541, TEXT_UNDERLINE },
17 { 547, TEXT_UNDERLINE }, 17 { 553, TEXT_UNDERLINE },
18 { 650, TEXT_CENTER | C_RED },
18 LAST_STYLE_ITEM 19 LAST_STYLE_ITEM
19}; 20};
20 21
21/* orig 3466 comp 2283 ratio 0.658684 level 10 saved 1183 */ 22/* orig 3752 comp 2460 ratio 0.65565 level 10 saved 1292 */
22const char help_text[] = { 23const char help_text[] = {
230xf0, 0x2e, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 240xfa, 0x03, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
240x32, 0x32, 0x3a, 0x20, 0x4d, 0x61, 0x70, 0x20, 0x00, 0x00, 250x32, 0x32, 0x3a, 0x20, 0x4d, 0x61, 0x70, 0x20, 0x00, 0x2d,
250x00, 0x59, 0x6f, 0x75, 0x00, 0x61, 0x72, 0x65, 0x00, 0x67, 260x01, 0x00, 0xf0, 0x1e, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75,
260x69, 0x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x61, 0x70, 270x00, 0x61, 0x72, 0x65, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e,
270x00, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x69, 0x6e, 280x00, 0x61, 0x00, 0x6d, 0x61, 0x70, 0x00, 0x63, 0x6f, 0x6e,
280x67, 0x00, 0x6f, 0x66, 0x00, 0x61, 0x00, 0x6e, 0x75, 0x6d, 290x73, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x00, 0x6f, 0x66,
290x62, 0x65, 0x72, 0x0c, 0x00, 0x80, 0x72, 0x65, 0x67, 0x69, 300x00, 0x61, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x0c,
300x6f, 0x6e, 0x73, 0x2e, 0x37, 0x00, 0xf0, 0x01, 0x72, 0x00, 310x00, 0x80, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
310x74, 0x61, 0x73, 0x6b, 0x00, 0x69, 0x73, 0x00, 0x74, 0x6f, 320x37, 0x00, 0xf0, 0x01, 0x72, 0x00, 0x74, 0x61, 0x73, 0x6b,
320x00, 0x63, 0x6f, 0x6c, 0x12, 0x00, 0x43, 0x65, 0x61, 0x63, 330x00, 0x69, 0x73, 0x00, 0x74, 0x6f, 0x00, 0x63, 0x6f, 0x6c,
330x68, 0x25, 0x00, 0x90, 0x00, 0x77, 0x69, 0x74, 0x68, 0x00, 340x12, 0x00, 0x43, 0x65, 0x61, 0x63, 0x68, 0x25, 0x00, 0x90,
340x6f, 0x6e, 0x65, 0x38, 0x00, 0x10, 0x66, 0x1d, 0x00, 0x02, 350x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x6f, 0x6e, 0x65, 0x38,
350x24, 0x00, 0xf4, 0x0d, 0x73, 0x2c, 0x00, 0x69, 0x6e, 0x00, 360x00, 0x10, 0x66, 0x1d, 0x00, 0x02, 0x24, 0x00, 0xf4, 0x0d,
360x73, 0x75, 0x63, 0x68, 0x00, 0x61, 0x00, 0x77, 0x61, 0x79, 370x73, 0x2c, 0x00, 0x69, 0x6e, 0x00, 0x73, 0x75, 0x63, 0x68,
370x00, 0x74, 0x68, 0x61, 0x74, 0x00, 0x6e, 0x6f, 0x00, 0x74, 380x00, 0x61, 0x00, 0x77, 0x61, 0x79, 0x00, 0x74, 0x68, 0x61,
380x77, 0x6f, 0x60, 0x00, 0x50, 0x00, 0x73, 0x68, 0x61, 0x72, 390x74, 0x00, 0x6e, 0x6f, 0x00, 0x74, 0x77, 0x6f, 0x60, 0x00,
390x7f, 0x00, 0xf3, 0x09, 0x61, 0x00, 0x62, 0x6f, 0x75, 0x6e, 400x50, 0x00, 0x73, 0x68, 0x61, 0x72, 0x7f, 0x00, 0xf3, 0x09,
400x64, 0x61, 0x72, 0x79, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 410x61, 0x00, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79,
410x74, 0x68, 0x65, 0x00, 0x73, 0x61, 0x6d, 0x65, 0x4c, 0x00, 420x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x74, 0x68, 0x65, 0x00,
420x15, 0x2e, 0xbf, 0x00, 0x82, 0x70, 0x72, 0x6f, 0x76, 0x69, 430x73, 0x61, 0x6d, 0x65, 0x4c, 0x00, 0x15, 0x2e, 0xbf, 0x00,
430x64, 0x65, 0x64, 0x76, 0x00, 0x45, 0x73, 0x6f, 0x6d, 0x65, 440x82, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x76,
440x4c, 0x00, 0x73, 0x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 450x00, 0x45, 0x73, 0x6f, 0x6d, 0x65, 0x4c, 0x00, 0x73, 0x61,
450x33, 0x00, 0xe0, 0x65, 0x64, 0x2c, 0x00, 0x73, 0x75, 0x66, 460x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x33, 0x00, 0xe0, 0x65,
460x66, 0x69, 0x63, 0x69, 0x65, 0x6e, 0x74, 0xbb, 0x00, 0x32, 470x64, 0x2c, 0x00, 0x73, 0x75, 0x66, 0x66, 0x69, 0x63, 0x69,
470x6d, 0x61, 0x6b, 0x59, 0x00, 0x72, 0x72, 0x65, 0x6d, 0x61, 480x65, 0x6e, 0x74, 0xbb, 0x00, 0x32, 0x6d, 0x61, 0x6b, 0x59,
480x69, 0x6e, 0x64, 0xea, 0x00, 0x01, 0x6a, 0x00, 0x40, 0x6f, 490x00, 0x72, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x64, 0xea,
490x6c, 0x75, 0x74, 0xcb, 0x00, 0xe5, 0x75, 0x6e, 0x69, 0x71, 500x00, 0x01, 0x6a, 0x00, 0x40, 0x6f, 0x6c, 0x75, 0x74, 0xcb,
500x75, 0x65, 0x2e, 0x00, 0x00, 0x00, 0x4f, 0x6e, 0x6c, 0x79, 510x00, 0xb0, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x2c, 0x00,
510x5a, 0x00, 0x51, 0x77, 0x68, 0x69, 0x63, 0x68, 0xac, 0x00, 520x61, 0x6e, 0x64, 0x19, 0x00, 0xf5, 0x0d, 0x73, 0x65, 0x00,
520xa0, 0x65, 0x00, 0x61, 0x00, 0x6c, 0x65, 0x6e, 0x67, 0x74, 530x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x00, 0x62, 0x65, 0x00,
530x68, 0x3c, 0x00, 0x30, 0x62, 0x6f, 0x72, 0x46, 0x00, 0x20, 540x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x2e, 0x00, 0x00,
540x61, 0x72, 0x54, 0x00, 0x60, 0x71, 0x75, 0x69, 0x72, 0x65, 550x00, 0x4f, 0x6e, 0x6c, 0x79, 0x77, 0x00, 0x51, 0x77, 0x68,
550x64, 0x69, 0x00, 0x90, 0x62, 0x65, 0x00, 0x64, 0x69, 0x66, 560x69, 0x63, 0x68, 0xc9, 0x00, 0xa0, 0x65, 0x00, 0x61, 0x00,
560x66, 0x65, 0x72, 0x79, 0x00, 0x03, 0x0d, 0x01, 0x5b, 0x2e, 570x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x59, 0x00, 0x30, 0x62,
570x00, 0x54, 0x77, 0x6f, 0x51, 0x00, 0x90, 0x6d, 0x65, 0x65, 580x6f, 0x72, 0x63, 0x00, 0x20, 0x61, 0x72, 0x71, 0x00, 0x60,
580x74, 0x00, 0x61, 0x74, 0x00, 0x6f, 0x6c, 0x00, 0x00, 0x41, 590x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x86, 0x00, 0x90, 0x62,
590x01, 0xb1, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x00, 0x28, 0x69, 600x65, 0x00, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x96, 0x00,
600x2e, 0x65, 0x2e, 0x55, 0x00, 0xff, 0x0c, 0x64, 0x69, 0x61, 610x03, 0x2a, 0x01, 0x5b, 0x2e, 0x00, 0x54, 0x77, 0x6f, 0x51,
610x67, 0x6f, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0x00, 0x73, 0x65, 620x00, 0x90, 0x6d, 0x65, 0x65, 0x74, 0x00, 0x61, 0x74, 0x00,
620x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x64, 0x29, 0x00, 0x6d, 630x6f, 0x6c, 0x00, 0x00, 0x5e, 0x01, 0xb1, 0x70, 0x6f, 0x69,
630x61, 0x79, 0x00, 0x62, 0x23, 0x01, 0x00, 0x91, 0x00, 0x00, 640x6e, 0x74, 0x00, 0x28, 0x69, 0x2e, 0x65, 0x2e, 0x55, 0x00,
640x49, 0x00, 0x62, 0x65, 0x6c, 0x69, 0x65, 0x40, 0x01, 0x90, 650xff, 0x0c, 0x64, 0x69, 0x61, 0x67, 0x6f, 0x6e, 0x61, 0x6c,
650x69, 0x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0xb9, 660x6c, 0x79, 0x00, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74,
660x01, 0xf0, 0x08, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 670x65, 0x64, 0x29, 0x00, 0x6d, 0x61, 0x79, 0x00, 0x62, 0x40,
670x6c, 0x3b, 0x00, 0x49, 0x27, 0x76, 0x65, 0x00, 0x6e, 0x65, 680x01, 0x00, 0x91, 0x00, 0x00, 0x49, 0x00, 0x62, 0x65, 0x6c,
680x76, 0x65, 0x72, 0x00, 0x73, 0x65, 0x09, 0x02, 0xc1, 0x6e, 690x69, 0x65, 0x5d, 0x01, 0x90, 0x69, 0x73, 0x00, 0x70, 0x75,
690x00, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 700x7a, 0x7a, 0x6c, 0x65, 0xd6, 0x01, 0xf0, 0x08, 0x6f, 0x72,
700x61, 0x04, 0x01, 0xf0, 0x09, 0x6f, 0x66, 0x00, 0x69, 0x74, 710x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x3b, 0x00, 0x49, 0x27,
710x00, 0x61, 0x6e, 0x79, 0x77, 0x68, 0x65, 0x72, 0x65, 0x00, 720x76, 0x65, 0x00, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x00, 0x73,
720x65, 0x6c, 0x73, 0x65, 0x2e, 0x00, 0x54, 0x68, 0x65, 0x2e, 730x65, 0x26, 0x02, 0xc1, 0x6e, 0x00, 0x69, 0x6d, 0x70, 0x6c,
730x02, 0x42, 0x63, 0x65, 0x70, 0x74, 0x2b, 0x02, 0x00, 0xe9, 740x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x21, 0x01, 0xf0, 0x09,
740x01, 0x12, 0x2d, 0x7a, 0x00, 0x00, 0xc0, 0x01, 0x03, 0x6b, 750x6f, 0x66, 0x00, 0x69, 0x74, 0x00, 0x61, 0x6e, 0x79, 0x77,
750x00, 0xf0, 0x20, 0x77, 0x61, 0x73, 0x00, 0x73, 0x75, 0x67, 760x68, 0x65, 0x72, 0x65, 0x00, 0x65, 0x6c, 0x73, 0x65, 0x2e,
760x67, 0x65, 0x73, 0x74, 0x65, 0x64, 0x00, 0x62, 0x79, 0x00, 770x00, 0x54, 0x68, 0x65, 0x4b, 0x02, 0x42, 0x63, 0x65, 0x70,
770x4f, 0x77, 0x65, 0x6e, 0x00, 0x44, 0x75, 0x6e, 0x6e, 0x3b, 780x74, 0x48, 0x02, 0x00, 0x06, 0x02, 0x12, 0x2d, 0x7a, 0x00,
780x00, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x00, 0x6d, 0x75, 790x00, 0xdd, 0x01, 0x03, 0x6b, 0x00, 0xf0, 0x26, 0x77, 0x61,
790x73, 0x74, 0x00, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0x67, 0x6f, 800x73, 0x00, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65,
800x2d, 0x01, 0x91, 0x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69, 0x00, 810x64, 0x00, 0x62, 0x79, 0x00, 0x41, 0x6c, 0x65, 0x78, 0x61,
810x61, 0x6e, 0x3b, 0x01, 0xf1, 0x07, 0x56, 0x65, 0x72, 0x69, 820x6e, 0x64, 0x72, 0x61, 0x00, 0x4c, 0x61, 0x6e, 0x65, 0x73,
820x74, 0x79, 0x00, 0x41, 0x6c, 0x6c, 0x61, 0x6e, 0x00, 0x66, 830x3b, 0x00, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x00, 0x6d,
830x6f, 0x72, 0x00, 0x69, 0x6e, 0x73, 0x70, 0x69, 0x63, 0x00, 840x75, 0x73, 0x74, 0x00, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0x67,
840x00, 0xf0, 0x00, 0x52, 0x74, 0x72, 0x61, 0x69, 0x6e, 0xb6, 850x6f, 0x33, 0x01, 0x62, 0x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69,
850x01, 0x52, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x54, 0x02, 0x12, 860x95, 0x01, 0x70, 0x6f, 0x00, 0x56, 0x65, 0x72, 0x69, 0x74,
860x6c, 0x77, 0x01, 0x01, 0x0b, 0x02, 0x40, 0x61, 0x6c, 0x69, 870x3d, 0x00, 0xd1, 0x6c, 0x61, 0x6e, 0x00, 0x66, 0x6f, 0x72,
870x73, 0x2e, 0x00, 0x00, 0x79, 0x00, 0x15, 0x27, 0x8d, 0x00, 880x00, 0x69, 0x6e, 0x73, 0x70, 0x69, 0x69, 0x00, 0x00, 0xf6,
880x01, 0xa7, 0x02, 0xb3, 0x61, 0x73, 0x00, 0x61, 0x00, 0x76, 890x00, 0x52, 0x74, 0x72, 0x61, 0x69, 0x6e, 0xd9, 0x01, 0x52,
890x69, 0x61, 0x62, 0x6c, 0x65, 0xb0, 0x00, 0x00, 0xd8, 0x00, 900x6f, 0x75, 0x67, 0x68, 0x74, 0x77, 0x02, 0x12, 0x6c, 0x7d,
900x42, 0x61, 0x6e, 0x6b, 0x73, 0x90, 0x00, 0xf1, 0x01, 0x74, 910x01, 0x01, 0x2e, 0x02, 0x40, 0x61, 0x6c, 0x69, 0x73, 0x2e,
910x6f, 0x00, 0x47, 0x61, 0x72, 0x65, 0x74, 0x68, 0x00, 0x54, 920x00, 0x00, 0x7f, 0x00, 0x15, 0x27, 0x93, 0x00, 0x01, 0xca,
920x61, 0x79, 0x6c, 0x6f, 0x72, 0x80, 0x00, 0xa0, 0x6d, 0x61, 930x02, 0xb3, 0x61, 0x73, 0x00, 0x61, 0x00, 0x76, 0x69, 0x61,
930x6e, 0x79, 0x00, 0x64, 0x65, 0x74, 0x61, 0x69, 0x66, 0x00, 940x62, 0x6c, 0x65, 0xb6, 0x00, 0x00, 0xde, 0x00, 0x42, 0x61,
940x06, 0x4f, 0x00, 0x10, 0x73, 0x70, 0x01, 0x41, 0x32, 0x32, 950x6e, 0x6b, 0x73, 0x90, 0x00, 0xf1, 0x01, 0x74, 0x6f, 0x00,
950x2e, 0x31, 0x60, 0x03, 0x80, 0x63, 0x6f, 0x6e, 0x74, 0x72, 960x47, 0x61, 0x72, 0x65, 0x74, 0x68, 0x00, 0x54, 0x61, 0x79,
960x6f, 0x6c, 0x73, 0x69, 0x03, 0x15, 0x54, 0x25, 0x03, 0x13, 970x6c, 0x6f, 0x72, 0x80, 0x00, 0xa0, 0x6d, 0x61, 0x6e, 0x79,
970x61, 0xf0, 0x01, 0x71, 0x2c, 0x00, 0x63, 0x6c, 0x69, 0x63, 980x00, 0x64, 0x65, 0x74, 0x61, 0x69, 0x66, 0x00, 0x06, 0x4f,
980x6b, 0xc2, 0x00, 0xf0, 0x00, 0x6c, 0x65, 0x66, 0x74, 0x00, 990x00, 0x10, 0x73, 0x76, 0x01, 0x41, 0x32, 0x32, 0x2e, 0x31,
990x6d, 0x6f, 0x75, 0x73, 0x65, 0x00, 0x62, 0x75, 0x74, 0x74, 1000x93, 0x03, 0xd5, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
1000x70, 0x01, 0x01, 0x85, 0x01, 0x23, 0x65, 0x78, 0x89, 0x03, 1010x73, 0x20, 0x00, 0x00, 0x00, 0x54, 0x48, 0x03, 0x13, 0x61,
1010x03, 0x55, 0x03, 0x03, 0x9a, 0x02, 0x31, 0x64, 0x65, 0x73, 1020xf6, 0x01, 0x71, 0x2c, 0x00, 0x63, 0x6c, 0x69, 0x63, 0x6b,
1020x56, 0x02, 0x04, 0x52, 0x00, 0x72, 0x6e, 0x64, 0x00, 0x64, 1030xc2, 0x00, 0xf0, 0x00, 0x6c, 0x65, 0x66, 0x74, 0x00, 0x6d,
1030x72, 0x61, 0x67, 0xf8, 0x00, 0x03, 0x15, 0x00, 0x41, 0x69, 1040x6f, 0x75, 0x73, 0x65, 0x00, 0x62, 0x75, 0x74, 0x74, 0x76,
1040x6e, 0x74, 0x6f, 0x2d, 0x00, 0x33, 0x6e, 0x65, 0x77, 0x3f, 1050x01, 0x01, 0x8b, 0x01, 0x23, 0x65, 0x78, 0xac, 0x03, 0x03,
1050x00, 0x00, 0x9d, 0x00, 0x31, 0x28, 0x54, 0x68, 0x2f, 0x03, 1060x78, 0x03, 0x03, 0xbd, 0x02, 0x31, 0x64, 0x65, 0x73, 0x5c,
1060xf3, 0x07, 0x67, 0x72, 0x61, 0x6d, 0x00, 0x77, 0x69, 0x6c, 1070x02, 0x04, 0x52, 0x00, 0x72, 0x6e, 0x64, 0x00, 0x64, 0x72,
1070x6c, 0x00, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x00, 0x65, 1080x61, 0x67, 0xf8, 0x00, 0x03, 0x15, 0x00, 0x41, 0x69, 0x6e,
1080x6e, 0x73, 0x75, 0x72, 0x40, 0x02, 0x47, 0x74, 0x61, 0x72, 1090x74, 0x6f, 0x2d, 0x00, 0x33, 0x6e, 0x65, 0x77, 0x3f, 0x00,
1090x74, 0xc0, 0x01, 0x10, 0x68, 0x24, 0x01, 0x00, 0x51, 0x01, 1100x00, 0x9d, 0x00, 0x31, 0x28, 0x54, 0x68, 0x52, 0x03, 0xf3,
1100x31, 0x61, 0x73, 0x74, 0x92, 0x02, 0x06, 0x8e, 0x00, 0x01, 1110x07, 0x67, 0x72, 0x61, 0x6d, 0x00, 0x77, 0x69, 0x6c, 0x6c,
1110xf2, 0x03, 0x02, 0x72, 0x00, 0x42, 0x2c, 0x00, 0x73, 0x6f, 1120x00, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x00, 0x65, 0x6e,
1120x82, 0x00, 0x01, 0x67, 0x02, 0x24, 0x69, 0x73, 0x5a, 0x00, 1130x73, 0x75, 0x72, 0x46, 0x02, 0x47, 0x74, 0x61, 0x72, 0x74,
1130xa0, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x21, 1140xc6, 0x01, 0x10, 0x68, 0x24, 0x01, 0x00, 0x51, 0x01, 0x31,
1140x29, 0x8d, 0x02, 0x82, 0x66, 0x00, 0x79, 0x6f, 0x75, 0x00, 1150x61, 0x73, 0x74, 0x98, 0x02, 0x06, 0x8e, 0x00, 0x01, 0x15,
1150x6e, 0x65, 0x9e, 0x01, 0x48, 0x63, 0x6c, 0x65, 0x61, 0x13, 1160x04, 0x02, 0x72, 0x00, 0x42, 0x2c, 0x00, 0x73, 0x6f, 0x82,
1160x01, 0x00, 0x1c, 0x00, 0x32, 0x63, 0x61, 0x6e, 0xcf, 0x00, 1170x00, 0x01, 0x6d, 0x02, 0x24, 0x69, 0x73, 0x5a, 0x00, 0xa0,
1170x41, 0x66, 0x72, 0x6f, 0x6d, 0x06, 0x01, 0x45, 0x6d, 0x70, 1180x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x21, 0x29,
1180x74, 0x79, 0x23, 0x00, 0x22, 0x6f, 0x72, 0x19, 0x00, 0x24, 1190x93, 0x02, 0x82, 0x66, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x6e,
1190x74, 0x68, 0xb1, 0x01, 0x06, 0x26, 0x04, 0x11, 0x69, 0x20, 1200x65, 0x9e, 0x01, 0x48, 0x63, 0x6c, 0x65, 0x61, 0x13, 0x01,
1200x01, 0x21, 0x72, 0x65, 0x28, 0x03, 0x29, 0x6e, 0x6f, 0x3a, 1210x00, 0x1c, 0x00, 0x32, 0x63, 0x61, 0x6e, 0xcf, 0x00, 0x41,
1210x00, 0x11, 0x73, 0x66, 0x01, 0x00, 0x04, 0x01, 0x52, 0x44, 1220x66, 0x72, 0x6f, 0x6d, 0x06, 0x01, 0x45, 0x6d, 0x70, 0x74,
1220x72, 0x61, 0x67, 0x67, 0x60, 0x04, 0x03, 0x2d, 0x01, 0x24, 1230x79, 0x23, 0x00, 0x22, 0x6f, 0x72, 0x19, 0x00, 0x24, 0x74,
1230x75, 0x73, 0x4c, 0x02, 0x4b, 0x72, 0x69, 0x67, 0x68, 0x8b, 1240x68, 0xb1, 0x01, 0x06, 0x49, 0x04, 0x11, 0x69, 0x20, 0x01,
1240x01, 0x01, 0x26, 0x01, 0x64, 0x73, 0x74, 0x69, 0x70, 0x70, 1250x21, 0x72, 0x65, 0x2e, 0x03, 0x29, 0x6e, 0x6f, 0x3a, 0x00,
1250x6c, 0x2a, 0x04, 0x01, 0xff, 0x00, 0x28, 0x69, 0x6e, 0x71, 1260x11, 0x73, 0x66, 0x01, 0x00, 0x04, 0x01, 0x52, 0x44, 0x72,
1260x01, 0x13, 0x2c, 0xbf, 0x03, 0x04, 0xc2, 0x00, 0x00, 0x41, 1270x61, 0x67, 0x67, 0x83, 0x04, 0x03, 0x2d, 0x01, 0x24, 0x75,
1270x00, 0x01, 0x5c, 0x02, 0x40, 0x6e, 0x6f, 0x74, 0x65, 0xeb, 1280x73, 0x4c, 0x02, 0x4b, 0x72, 0x69, 0x67, 0x68, 0x8b, 0x01,
1280x00, 0x10, 0x79, 0xf1, 0x03, 0x32, 0x65, 0x6c, 0x66, 0x35, 1290x01, 0x26, 0x01, 0x64, 0x73, 0x74, 0x69, 0x70, 0x70, 0x6c,
1290x00, 0x00, 0x27, 0x00, 0x58, 0x74, 0x68, 0x69, 0x6e, 0x6b, 1300x4d, 0x04, 0x01, 0xff, 0x00, 0x28, 0x69, 0x6e, 0x71, 0x01,
1300x52, 0x00, 0x11, 0x6d, 0x7d, 0x00, 0x28, 0x62, 0x65, 0x58, 1310x13, 0x2c, 0xc5, 0x03, 0x04, 0xc2, 0x00, 0x00, 0x41, 0x00,
1310x00, 0x34, 0x2e, 0x00, 0x41, 0x1f, 0x00, 0x00, 0x57, 0x00, 1320x01, 0x5c, 0x02, 0x40, 0x6e, 0x6f, 0x74, 0x65, 0xeb, 0x00,
1320x00, 0x54, 0x02, 0x00, 0xee, 0x02, 0x03, 0x90, 0x00, 0x10, 1330x10, 0x79, 0xf7, 0x03, 0x32, 0x65, 0x6c, 0x66, 0x35, 0x00,
1330x73, 0x86, 0x00, 0x74, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 1340x00, 0x27, 0x00, 0x58, 0x74, 0x68, 0x69, 0x6e, 0x6b, 0x52,
1340x6c, 0xf4, 0x03, 0x01, 0xad, 0x01, 0x00, 0x96, 0x03, 0x10, 1350x00, 0x11, 0x6d, 0x7d, 0x00, 0x28, 0x62, 0x65, 0x58, 0x00,
1350x2e, 0xee, 0x01, 0x02, 0x8b, 0x01, 0x41, 0x6f, 0x66, 0x74, 1360x34, 0x2e, 0x00, 0x41, 0x1f, 0x00, 0x00, 0x57, 0x00, 0x00,
1360x65, 0x94, 0x00, 0x41, 0x66, 0x75, 0x6c, 0x00, 0xa3, 0x01, 1370x54, 0x02, 0x00, 0xee, 0x02, 0x03, 0x90, 0x00, 0x10, 0x73,
1370x00, 0xd7, 0x01, 0x01, 0xa8, 0x04, 0x20, 0x64, 0x69, 0x0f, 1380x86, 0x00, 0x74, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c,
1380x05, 0xd3, 0x75, 0x6c, 0x74, 0x79, 0x00, 0x6c, 0x65, 0x76, 1390xfa, 0x03, 0x01, 0xad, 0x01, 0x00, 0x9c, 0x03, 0x10, 0x2e,
1390x65, 0x6c, 0x73, 0x2e, 0x29, 0x19, 0x06, 0x00, 0x70, 0x00, 1400xee, 0x01, 0x02, 0x8b, 0x01, 0x41, 0x6f, 0x66, 0x74, 0x65,
1400x01, 0x04, 0x03, 0x22, 0x75, 0x73, 0xf9, 0x00, 0xb1, 0x63, 1410x94, 0x00, 0x41, 0x66, 0x75, 0x6c, 0x00, 0xa3, 0x01, 0x00,
1410x75, 0x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x73, 1420xd7, 0x01, 0x01, 0xae, 0x04, 0x20, 0x64, 0x69, 0x32, 0x05,
1420x5b, 0x03, 0x20, 0x6f, 0x76, 0x6a, 0x01, 0x00, 0x7d, 0x01, 1430xd3, 0x75, 0x6c, 0x74, 0x79, 0x00, 0x6c, 0x65, 0x76, 0x65,
1430x01, 0x1f, 0x00, 0x42, 0x6d, 0x61, 0x70, 0x3a, 0x28, 0x00, 1440x6c, 0x73, 0x2e, 0x29, 0x3c, 0x06, 0x00, 0x70, 0x00, 0x01,
1440x02, 0x56, 0x01, 0x28, 0x6f, 0x66, 0x36, 0x00, 0x92, 0x69, 1450x04, 0x03, 0x22, 0x75, 0x73, 0xf9, 0x00, 0xb1, 0x63, 0x75,
1450x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0xba, 0x01, 1460x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x73, 0x5b,
1460x34, 0x6f, 0x73, 0x69, 0x59, 0x04, 0x07, 0x33, 0x00, 0x00, 1470x03, 0x20, 0x6f, 0x76, 0x6a, 0x01, 0x22, 0x6f, 0x75, 0x3b,
1470x17, 0x01, 0x43, 0x77, 0x6f, 0x75, 0x6c, 0xd1, 0x02, 0x12, 1480x05, 0x00, 0x60, 0x06, 0x12, 0x3a, 0x28, 0x00, 0x02, 0x56,
1480x28, 0x54, 0x01, 0x20, 0x69, 0x73, 0x46, 0x01, 0xa1, 0x00, 1490x01, 0x28, 0x6f, 0x66, 0x36, 0x00, 0x92, 0x69, 0x6e, 0x64,
1490x6f, 0x62, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x00, 0x69, 0x44, 1500x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0xba, 0x01, 0x34, 0x6f,
1500x02, 0x31, 0x27, 0x72, 0x65, 0x26, 0x03, 0x03, 0x1e, 0x01, 1510x73, 0x69, 0x5f, 0x04, 0x07, 0x33, 0x00, 0x00, 0x17, 0x01,
1510x25, 0x27, 0x73, 0x07, 0x02, 0x70, 0x2c, 0x00, 0x73, 0x69, 1520x43, 0x77, 0x6f, 0x75, 0x6c, 0xd1, 0x02, 0x12, 0x28, 0x54,
1520x6e, 0x63, 0x65, 0xb1, 0x04, 0x70, 0x64, 0x65, 0x70, 0x65, 1530x01, 0x30, 0x69, 0x73, 0x00, 0x92, 0x05, 0x91, 0x6f, 0x62,
1530x6e, 0x64, 0x73, 0x29, 0x00, 0x01, 0x39, 0x03, 0x41, 0x69, 1540x76, 0x69, 0x6f, 0x75, 0x73, 0x00, 0x69, 0x44, 0x02, 0x31,
1540x72, 0x65, 0x63, 0x77, 0x00, 0x01, 0x43, 0x02, 0x06, 0xb2, 1550x27, 0x72, 0x65, 0x26, 0x03, 0x03, 0x1e, 0x01, 0x25, 0x27,
1550x01, 0x92, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x61, 0x63, 0x68, 1560x73, 0x07, 0x02, 0x70, 0x2c, 0x00, 0x73, 0x69, 0x6e, 0x63,
1560x65, 0xca, 0x00, 0x04, 0x4a, 0x00, 0x76, 0x29, 0x2e, 0x00, 1570x65, 0xb7, 0x04, 0x70, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64,
1570x50, 0x72, 0x65, 0x73, 0x1e, 0x02, 0x50, 0x65, 0x74, 0x75, 1580x73, 0x29, 0x00, 0x01, 0x39, 0x03, 0x41, 0x69, 0x72, 0x65,
1580x72, 0x6e, 0x01, 0x01, 0x02, 0x25, 0x03, 0x00, 0xe0, 0x01, 1590x63, 0x77, 0x00, 0x01, 0x43, 0x02, 0x06, 0xb2, 0x01, 0x92,
1590x01, 0xa9, 0x00, 0x2a, 0x6f, 0x66, 0x0c, 0x02, 0x00, 0xfa, 1600x61, 0x70, 0x70, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x65, 0xca,
1600x01, 0x49, 0x62, 0x6f, 0x76, 0x65, 0x16, 0x02, 0x02, 0x0f, 1610x00, 0x04, 0x4a, 0x00, 0x76, 0x29, 0x2e, 0x00, 0x50, 0x72,
1610x04, 0x02, 0xa4, 0x06, 0x0b, 0x4f, 0x01, 0x3f, 0x3b, 0x00, 1620x65, 0x73, 0x1e, 0x02, 0x50, 0x65, 0x74, 0x75, 0x72, 0x6e,
1620x70, 0x68, 0x00, 0x04, 0x20, 0x61, 0x67, 0xef, 0x01, 0x63, 1630x01, 0x01, 0x02, 0x25, 0x03, 0x00, 0xe0, 0x01, 0x01, 0xa9,
1630x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x3c, 0x01, 0x00, 0x72, 1640x00, 0x2a, 0x6f, 0x66, 0x0c, 0x02, 0x00, 0xfa, 0x01, 0x49,
1640x00, 0x02, 0x7d, 0x05, 0x91, 0x73, 0x70, 0x61, 0x63, 0x65, 1650x62, 0x6f, 0x76, 0x65, 0x16, 0x02, 0x02, 0x0f, 0x04, 0x02,
1650x00, 0x62, 0x61, 0x72, 0xac, 0x01, 0x20, 0x62, 0x65, 0xaa, 1660xc7, 0x06, 0x0b, 0x4f, 0x01, 0x3f, 0x3b, 0x00, 0x70, 0x68,
1660x01, 0xb1, 0x64, 0x00, 0x73, 0x69, 0x6d, 0x69, 0x6c, 0x61, 1670x00, 0x04, 0x20, 0x61, 0x67, 0xef, 0x01, 0x63, 0x66, 0x69,
1670x72, 0x6c, 0x79, 0x62, 0x03, 0x40, 0x72, 0x65, 0x61, 0x74, 1680x6e, 0x69, 0x73, 0x68, 0x3c, 0x01, 0x00, 0x72, 0x00, 0x02,
1680xa1, 0x06, 0x03, 0x32, 0x02, 0x15, 0x64, 0x0d, 0x04, 0x7f, 1690x83, 0x05, 0x91, 0x73, 0x70, 0x61, 0x63, 0x65, 0x00, 0x62,
1690x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x2d, 0x79, 0x00, 0x05, 1700x61, 0x72, 0xac, 0x01, 0x20, 0x62, 0x65, 0xaa, 0x01, 0xb1,
1700x30, 0x28, 0x77, 0x69, 0x50, 0x05, 0x10, 0x74, 0xe7, 0x01, 1710x64, 0x00, 0x73, 0x69, 0x6d, 0x69, 0x6c, 0x61, 0x72, 0x6c,
1710x04, 0x1f, 0x00, 0x02, 0xb2, 0x00, 0x12, 0x29, 0x13, 0x03, 1720x79, 0x62, 0x03, 0x40, 0x72, 0x65, 0x61, 0x74, 0xa7, 0x06,
1720x02, 0xbc, 0x03, 0x06, 0xbf, 0x02, 0x02, 0xf6, 0x00, 0x0f, 1730x03, 0x32, 0x02, 0x15, 0x64, 0x0d, 0x04, 0x7f, 0x44, 0x6f,
1730xbb, 0x03, 0x07, 0x65, 0x00, 0x64, 0x6f, 0x65, 0x73, 0x3a, 1740x75, 0x62, 0x6c, 0x65, 0x2d, 0x79, 0x00, 0x05, 0x30, 0x28,
1740x1e, 0x04, 0x03, 0x8d, 0x02, 0x0c, 0x0e, 0x01, 0x43, 0x6d, 1750x77, 0x69, 0x50, 0x05, 0x10, 0x74, 0xe7, 0x01, 0x04, 0x1f,
1750x6f, 0x64, 0x65, 0xe2, 0x01, 0x02, 0xf5, 0x07, 0x43, 0x66, 1760x00, 0x02, 0xb2, 0x00, 0x12, 0x29, 0x13, 0x03, 0x02, 0xbc,
1760x69, 0x6c, 0x6c, 0x97, 0x01, 0x51, 0x65, 0x6e, 0x74, 0x69, 1770x03, 0x06, 0xbf, 0x02, 0x02, 0xf6, 0x00, 0x0f, 0xbb, 0x03,
1770x72, 0x68, 0x02, 0x00, 0xf7, 0x02, 0x36, 0x62, 0x75, 0x74, 1780x07, 0x65, 0x00, 0x64, 0x6f, 0x65, 0x73, 0x3a, 0x1e, 0x04,
1780x48, 0x04, 0x20, 0x6f, 0x72, 0xda, 0x01, 0x02, 0x4d, 0x05, 1790x03, 0x8d, 0x02, 0x0c, 0x0e, 0x01, 0x43, 0x6d, 0x6f, 0x64,
1790x66, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x6d, 0x04, 0x01, 1800x65, 0xe2, 0x01, 0x02, 0x18, 0x08, 0x43, 0x66, 0x69, 0x6c,
1800xe2, 0x00, 0x43, 0x00, 0x4c, 0x00, 0x64, 0x96, 0x06, 0x41, 1810x6c, 0x97, 0x01, 0x51, 0x65, 0x6e, 0x74, 0x69, 0x72, 0x68,
1810x6c, 0x61, 0x79, 0x2c, 0x2a, 0x00, 0x10, 0x67, 0x29, 0x07, 1820x02, 0x00, 0xf7, 0x02, 0x36, 0x62, 0x75, 0x74, 0x48, 0x04,
1820x01, 0xcc, 0x00, 0x50, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x20, 1830x20, 0x6f, 0x72, 0xda, 0x01, 0x02, 0x4d, 0x05, 0x66, 0x61,
1830x02, 0x10, 0x73, 0x1e, 0x00, 0x09, 0xf8, 0x08, 0x29, 0x69, 1840x79, 0x6f, 0x75, 0x74, 0x2e, 0x6d, 0x04, 0x01, 0xe2, 0x00,
1840x6e, 0xd8, 0x08, 0x24, 0x6f, 0x66, 0xec, 0x02, 0x00, 0x83, 1850x43, 0x00, 0x4c, 0x00, 0x64, 0x9c, 0x06, 0x41, 0x6c, 0x61,
1850x01, 0x09, 0xcb, 0x00, 0x03, 0xb6, 0x00, 0x22, 0x77, 0x61, 1860x79, 0x2c, 0x2a, 0x00, 0x10, 0x67, 0x2f, 0x07, 0x01, 0xcc,
1860x5a, 0x08, 0x60, 0x64, 0x69, 0x73, 0x63, 0x75, 0x73, 0x13, 1870x00, 0x50, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x20, 0x02, 0x10,
1870x01, 0x10, 0x70, 0x50, 0x05, 0x55, 0x63, 0x75, 0x6c, 0x61, 1880x73, 0x1e, 0x00, 0x09, 0x1b, 0x09, 0x29, 0x69, 0x6e, 0xfb,
1880x72, 0x7e, 0x07, 0x40, 0x6e, 0x73, 0x74, 0x61, 0xa4, 0x02, 1890x08, 0x24, 0x6f, 0x66, 0xec, 0x02, 0x00, 0x83, 0x01, 0x09,
1890x01, 0xff, 0x00, 0xa0, 0x61, 0x00, 0x66, 0x72, 0x69, 0x65, 1900xcb, 0x00, 0x03, 0xb6, 0x00, 0x22, 0x77, 0x61, 0x7d, 0x08,
1900x6e, 0x64, 0x00, 0x2d, 0xf3, 0x00, 0x01, 0x9a, 0x04, 0x00, 1910x60, 0x64, 0x69, 0x73, 0x63, 0x75, 0x73, 0x13, 0x01, 0x10,
1910x76, 0x08, 0x60, 0x61, 0x6d, 0x62, 0x69, 0x67, 0x75, 0xf2, 1920x70, 0x50, 0x05, 0x55, 0x63, 0x75, 0x6c, 0x61, 0x72, 0x84,
1920x02, 0x10, 0x6e, 0xa9, 0x00, 0x2a, 0x66, 0x6f, 0x62, 0x09, 1930x07, 0x40, 0x6e, 0x73, 0x74, 0x61, 0xa4, 0x02, 0x01, 0xff,
1930x40, 0x69, 0x73, 0x00, 0x6d, 0x48, 0x09, 0x60, 0x65, 0x61, 1940x00, 0xa0, 0x61, 0x00, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64,
1940x73, 0x69, 0x65, 0x72, 0x80, 0x02, 0x51, 0x6e, 0x00, 0x74, 1950x00, 0x2d, 0xf3, 0x00, 0x01, 0x9a, 0x04, 0x00, 0x99, 0x08,
1950x72, 0x79, 0xac, 0x01, 0x00, 0x55, 0x08, 0x10, 0x66, 0x15, 1960x60, 0x61, 0x6d, 0x62, 0x69, 0x67, 0x75, 0xf2, 0x02, 0x10,
1960x00, 0x01, 0x04, 0x06, 0x50, 0x6d, 0x00, 0x61, 0x6c, 0x6c, 1970x6e, 0xa9, 0x00, 0x2a, 0x66, 0x6f, 0x85, 0x09, 0x40, 0x69,
1970x79, 0x07, 0x00, 0x48, 0x00, 0x13, 0x73, 0x7e, 0x09, 0x30, 1980x73, 0x00, 0x6d, 0x6b, 0x09, 0x60, 0x65, 0x61, 0x73, 0x69,
1980x73, 0x00, 0x60, 0xc9, 0x00, 0x00, 0xd0, 0x05, 0x41, 0x64, 1990x65, 0x72, 0x80, 0x02, 0x51, 0x6e, 0x00, 0x74, 0x72, 0x79,
1990x6f, 0x77, 0x6e, 0x46, 0x06, 0x02, 0xfe, 0x04, 0x03, 0xe3, 2000xac, 0x01, 0x00, 0x5b, 0x08, 0x10, 0x66, 0x15, 0x00, 0x01,
2000x00, 0x20, 0x62, 0x72, 0x17, 0x00, 0x01, 0xc3, 0x09, 0x12, 2010x04, 0x06, 0x50, 0x6d, 0x00, 0x61, 0x6c, 0x6c, 0x7f, 0x07,
2010x6e, 0x68, 0x07, 0x23, 0x6f, 0x70, 0xdd, 0x08, 0x11, 0x27, 2020x00, 0x48, 0x00, 0x13, 0x73, 0xa1, 0x09, 0x30, 0x73, 0x00,
2020x4b, 0x06, 0x31, 0x41, 0x6c, 0x6c, 0x18, 0x00, 0x21, 0x61, 2030x60, 0xc9, 0x00, 0x00, 0xd0, 0x05, 0x41, 0x64, 0x6f, 0x77,
2030x63, 0xfc, 0x06, 0x00, 0x97, 0x06, 0x61, 0x63, 0x72, 0x69, 2040x6e, 0x46, 0x06, 0x02, 0xfe, 0x04, 0x03, 0xe3, 0x00, 0x20,
2040x62, 0x65, 0x64, 0xe3, 0x09, 0x03, 0x69, 0x03, 0x31, 0x32, 2050x62, 0x72, 0x17, 0x00, 0x01, 0xe6, 0x09, 0x12, 0x6e, 0x68,
2050x2e, 0x31, 0x8e, 0x05, 0x01, 0x49, 0x04, 0x50, 0x61, 0x76, 2060x07, 0x23, 0x6f, 0x70, 0xe3, 0x08, 0x11, 0x27, 0x4b, 0x06,
2060x61, 0x69, 0x6c, 0x6b, 0x07, 0x22, 0x2e, 0x29, 0x29, 0x07, 2070x31, 0x41, 0x6c, 0x6c, 0x18, 0x00, 0x21, 0x61, 0x63, 0xfc,
2070x11, 0x32, 0x29, 0x07, 0x00, 0xc5, 0x08, 0x52, 0x6d, 0x65, 2080x06, 0x00, 0x97, 0x06, 0x61, 0x63, 0x72, 0x69, 0x62, 0x65,
2080x74, 0x65, 0x72, 0x2b, 0x07, 0x56, 0x68, 0x65, 0x73, 0x65, 2090x64, 0x06, 0x0a, 0x03, 0x69, 0x03, 0x31, 0x32, 0x2e, 0x31,
2090x00, 0x14, 0x00, 0x02, 0x3f, 0x00, 0x04, 0x3a, 0x00, 0x06, 2100x8e, 0x05, 0x01, 0x49, 0x04, 0x50, 0x61, 0x76, 0x61, 0x69,
2100xfd, 0x05, 0xe2, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 2110x6c, 0x6b, 0x07, 0x22, 0x2e, 0x29, 0x29, 0x07, 0x11, 0x32,
2110x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x4d, 0x04, 0x12, 2120x29, 0x07, 0x00, 0xcb, 0x08, 0x52, 0x6d, 0x65, 0x74, 0x65,
2120x6e, 0x1a, 0x00, 0xa0, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 2130x72, 0x2b, 0x07, 0x01, 0x86, 0x09, 0x06, 0x14, 0x00, 0x02,
2130x6d, 0x65, 0x6e, 0x75, 0xa9, 0x00, 0x91, 0x57, 0x69, 0x64, 2140x3f, 0x00, 0x04, 0x3a, 0x00, 0x06, 0xfd, 0x05, 0xe2, 0x60,
2140x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0xde, 0x00, 0x51, 0x00, 2150x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27,
2150x00, 0x53, 0x69, 0x7a, 0x97, 0x0a, 0x32, 0x67, 0x72, 0x69, 2160x00, 0x6f, 0x70, 0x4d, 0x04, 0x12, 0x6e, 0x1a, 0x00, 0xa0,
2160xab, 0x00, 0x51, 0x71, 0x75, 0x61, 0x72, 0x65, 0xbc, 0x07, 2170x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75,
2170x13, 0x52, 0x2b, 0x06, 0x3c, 0x00, 0x00, 0x4e, 0xf6, 0x0a, 2180xa9, 0x00, 0x91, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00,
2180x22, 0x00, 0x69, 0x5d, 0x00, 0x41, 0x67, 0x65, 0x6e, 0x65, 2190x48, 0x65, 0xde, 0x00, 0x51, 0x00, 0x00, 0x53, 0x69, 0x7a,
2190x74, 0x09, 0x02, 0x04, 0x02, 0x36, 0x00, 0x00, 0x44, 0x41, 2200xba, 0x0a, 0x32, 0x67, 0x72, 0x69, 0xab, 0x00, 0x51, 0x71,
2200x05, 0xb1, 0x00, 0x00, 0x49, 0x6e, 0x00, 0x60, 0x45, 0x61, 2210x75, 0x61, 0x72, 0x65, 0xbc, 0x07, 0x13, 0x52, 0x2b, 0x06,
2210x73, 0x79, 0x27, 0xc9, 0x02, 0x13, 0x2c, 0x8f, 0x06, 0x21, 2220x3c, 0x00, 0x00, 0x4e, 0x19, 0x0b, 0x22, 0x00, 0x69, 0x5d,
2220x73, 0x68, 0xd4, 0x04, 0x03, 0x11, 0x07, 0x2f, 0x62, 0x65, 2230x00, 0x41, 0x67, 0x65, 0x6e, 0x65, 0x7a, 0x09, 0x02, 0x04,
2230x4f, 0x07, 0x02, 0x45, 0x77, 0x68, 0x6f, 0x73, 0x09, 0x05, 2240x02, 0x36, 0x00, 0x00, 0x44, 0x41, 0x05, 0xb1, 0x00, 0x00,
2240x03, 0xd0, 0x03, 0x10, 0x64, 0x02, 0x01, 0x30, 0x6d, 0x69, 2250x49, 0x6e, 0x00, 0x60, 0x45, 0x61, 0x73, 0x79, 0x27, 0xc9,
2250x6e, 0xe6, 0x02, 0x40, 0x72, 0x69, 0x76, 0x69, 0xf6, 0x09, 2260x02, 0x13, 0x2c, 0x8f, 0x06, 0x21, 0x73, 0x68, 0xd4, 0x04,
2260x11, 0x2e, 0x65, 0x00, 0x71, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 2270x03, 0x11, 0x07, 0x2f, 0x62, 0x65, 0x4f, 0x07, 0x02, 0x45,
2270x6c, 0x27, 0xb7, 0x01, 0x52, 0x60, 0x48, 0x61, 0x72, 0x64, 2280x77, 0x68, 0x6f, 0x73, 0x09, 0x05, 0x03, 0xd0, 0x03, 0x10,
2280x72, 0x00, 0x12, 0x73, 0x44, 0x07, 0x01, 0xd5, 0x02, 0x02, 2290x64, 0x02, 0x01, 0x30, 0x6d, 0x69, 0x6e, 0xe6, 0x02, 0x40,
2290x34, 0x0b, 0x02, 0xbf, 0x05, 0x20, 0x69, 0x6e, 0x09, 0x04, 2300x72, 0x69, 0x76, 0x69, 0xfc, 0x09, 0x11, 0x2e, 0x65, 0x00,
2300x00, 0xe8, 0x03, 0x10, 0x6c, 0x0c, 0x0b, 0x00, 0xdd, 0x09, 2310x71, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x27, 0xb7, 0x01,
2310x71, 0x78, 0x00, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0xab, 0x02, 2320x52, 0x60, 0x48, 0x61, 0x72, 0x64, 0x72, 0x00, 0x12, 0x73,
2320x5b, 0x65, 0x64, 0x75, 0x63, 0x65, 0xbc, 0x05, 0x08, 0x47, 2330x44, 0x07, 0x01, 0xd5, 0x02, 0x02, 0x57, 0x0b, 0x02, 0xbf,
2330x0b, 0x50, 0x2e, 0x00, 0x48, 0x6f, 0x77, 0x20, 0x0a, 0x10, 2340x05, 0x20, 0x69, 0x6e, 0x09, 0x04, 0x00, 0xe8, 0x03, 0x10,
2340x2c, 0x56, 0x05, 0x08, 0x38, 0x08, 0x25, 0x62, 0x65, 0xe1, 2350x6c, 0x2f, 0x0b, 0x00, 0xe3, 0x09, 0x71, 0x78, 0x00, 0x6c,
2350x07, 0x14, 0x00, 0x32, 0x04, 0x03, 0xc5, 0x02, 0x70, 0x74, 2360x6f, 0x67, 0x69, 0x63, 0xab, 0x02, 0x5b, 0x65, 0x64, 0x75,
2360x6f, 0x00, 0x67, 0x75, 0x65, 0x73, 0x69, 0x0a, 0xb3, 0x00, 2370x63, 0x65, 0xbc, 0x05, 0x08, 0x6a, 0x0b, 0x50, 0x2e, 0x00,
2370x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x2e, 2380x48, 0x6f, 0x77, 0x26, 0x0a, 0x10, 0x2c, 0x56, 0x05, 0x08,
2380x25, 0x01, 0x20, 0x55, 0x6e, 0x90, 0x00, 0x20, 0x6f, 0x6e, 2390x38, 0x08, 0x25, 0x62, 0x65, 0xe1, 0x07, 0x14, 0x00, 0x32,
2390xd4, 0x01, 0x07, 0x2d, 0x01, 0x0a, 0x9c, 0x08, 0x81, 0x66, 2400x04, 0x03, 0xc5, 0x02, 0x70, 0x74, 0x6f, 0x00, 0x67, 0x75,
2400x65, 0x65, 0x6c, 0x00, 0x66, 0x72, 0x65, 0xc7, 0x00, 0x04, 2410x65, 0x73, 0x6f, 0x0a, 0xb3, 0x00, 0x62, 0x61, 0x63, 0x6b,
2410x79, 0x01, 0x03, 0x44, 0x03, 0x04, 0x30, 0x0b, 0x01, 0x1e, 2420x74, 0x72, 0x61, 0x63, 0x6b, 0x2e, 0x25, 0x01, 0x20, 0x55,
2420x02, 0x11, 0x73, 0xce, 0x06, 0x00, 0x08, 0x00, 0x21, 0x69, 2430x6e, 0x90, 0x00, 0x20, 0x6f, 0x6e, 0xd4, 0x01, 0x07, 0x2d,
2430x74, 0x3c, 0x01, 0x03, 0x94, 0x00, 0x15, 0x79, 0xe0, 0x0b, 2440x01, 0x0a, 0x9c, 0x08, 0x81, 0x66, 0x65, 0x65, 0x6c, 0x00,
2440x12, 0x6d, 0x9b, 0x06, 0x01, 0x56, 0x0b, 0x00, 0xe2, 0x0c, 2450x66, 0x72, 0x65, 0xc7, 0x00, 0x04, 0x79, 0x01, 0x03, 0x44,
2450x01, 0x35, 0x0a, 0x11, 0x74, 0xc0, 0x0c, 0x12, 0x68, 0x11, 2460x03, 0x04, 0x36, 0x0b, 0x01, 0x1e, 0x02, 0x11, 0x73, 0xce,
2460x07, 0x14, 0x79, 0xa7, 0x01, 0x25, 0x73, 0x74, 0x3e, 0x01, 2470x06, 0x00, 0x08, 0x00, 0x21, 0x69, 0x74, 0x3c, 0x01, 0x03,
2470x13, 0x61, 0xfd, 0x0b, 0x05, 0x0d, 0x0c, 0x51, 0x2e, 0x00, 2480x94, 0x00, 0x15, 0x79, 0x03, 0x0c, 0x12, 0x6d, 0x9b, 0x06,
2480x53, 0x6f, 0x6c, 0xde, 0x00, 0x08, 0xc1, 0x00, 0x05, 0x93, 2490x01, 0x5c, 0x0b, 0x00, 0x05, 0x0d, 0x01, 0x35, 0x0a, 0x11,
2490x00, 0x00, 0x86, 0x0b, 0x03, 0xf5, 0x0b, 0x02, 0xfc, 0x00, 2500x74, 0xe3, 0x0c, 0x12, 0x68, 0x11, 0x07, 0x14, 0x79, 0xa7,
2500x02, 0xcd, 0x03, 0x16, 0x64, 0x00, 0x01, 0x50, 0x69, 0x6e, 2510x01, 0x25, 0x73, 0x74, 0x3e, 0x01, 0x13, 0x61, 0x20, 0x0c,
2510x67, 0x2e, 0x00, 2520x05, 0x30, 0x0c, 0x51, 0x2e, 0x00, 0x53, 0x6f, 0x6c, 0xde,
2530x00, 0x08, 0xc1, 0x00, 0x05, 0x93, 0x00, 0x00, 0x8c, 0x0b,
2540x03, 0xfb, 0x0b, 0x02, 0xfc, 0x00, 0x02, 0xcd, 0x03, 0x16,
2550x64, 0x00, 0x01, 0x33, 0x69, 0x6e, 0x67, 0x25, 0x0a, 0x11,
2560x33, 0xfc, 0x02, 0x81, 0x75, 0x73, 0x65, 0x72, 0x20, 0x70,
2570x72, 0x65, 0x1f, 0x0c, 0x41, 0x63, 0x65, 0x73, 0x20, 0x6d,
2580x0c, 0x00, 0xa5, 0x04, 0x53, 0x74, 0x66, 0x6f, 0x72, 0x6d,
2590x9f, 0x00, 0x80, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74,
2600x00, 0x2e, 0x00, 0x17, 0x00, 0x2e, 0x00, 0x12, 0x2c, 0xf0,
2610x02, 0x16, 0x50, 0x12, 0x00, 0x0d, 0x0c, 0x03, 0x33, 0x47,
2620x61, 0x6d, 0x0c, 0x03, 0x02, 0x54, 0x01, 0x34, 0x6c, 0x65,
2630x74, 0x8f, 0x06, 0x36, 0x66, 0x69, 0x67, 0xf4, 0x09, 0x34,
2640x79, 0x6c, 0x65, 0xfa, 0x03, 0xd1, 0x76, 0x69, 0x63, 0x74,
2650x6f, 0x72, 0x79, 0x00, 0x66, 0x6c, 0x61, 0x73, 0x68, 0xbf,
2660x00, 0x01, 0xbe, 0x03, 0x30, 0x77, 0x68, 0x65, 0xcf, 0x02,
2670x07, 0xf3, 0x05, 0x12, 0x73, 0x07, 0x07, 0x10, 0x00, 0xf5,
2680x01, 0x64, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x6c, 0xa7, 0x0d,
2690x90, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2e, 0x00,
252}; 270};
253 271
254const unsigned short help_text_len = 3466; 272const unsigned short help_text_len = 3752;
255const unsigned short help_text_words = 642; 273const unsigned short help_text_words = 686;
256const char quick_help_text[] = "Colour the map so that adjacent regions are never the same colour."; 274const char quick_help_text[] = "Colour the map so that adjacent regions are never the same colour.";
diff --git a/apps/plugins/puzzles/help/mines.c b/apps/plugins/puzzles/help/mines.c
index c2f73d4b54..8a4f4038c0 100644
--- a/apps/plugins/puzzles/help/mines.c
+++ b/apps/plugins/puzzles/help/mines.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,258 +6,258 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 29, TEXT_UNDERLINE }, 9 { 30, TEXT_UNDERLINE },
10 { 119, TEXT_UNDERLINE }, 10 { 120, TEXT_UNDERLINE },
11 { 171, TEXT_CENTER | C_RED }, 11 { 172, TEXT_CENTER | C_RED },
12 { 248, TEXT_UNDERLINE }, 12 { 249, TEXT_UNDERLINE },
13 { 283, TEXT_UNDERLINE }, 13 { 284, TEXT_UNDERLINE },
14 { 334, TEXT_UNDERLINE }, 14 { 335, TEXT_UNDERLINE },
15 { 583, TEXT_CENTER | C_RED }, 15 { 584, TEXT_CENTER | C_RED },
16 { 600, TEXT_UNDERLINE },
17 { 601, TEXT_UNDERLINE }, 16 { 601, TEXT_UNDERLINE },
18 { 611, TEXT_UNDERLINE }, 17 { 602, TEXT_UNDERLINE },
19 { 685, TEXT_UNDERLINE }, 18 { 612, TEXT_UNDERLINE },
19 { 686, TEXT_UNDERLINE },
20 LAST_STYLE_ITEM 20 LAST_STYLE_ITEM
21}; 21};
22 22
23/* orig 3796 comp 2333 ratio 0.614594 level 10 saved 1463 */ 23/* orig 3814 comp 2339 ratio 0.613267 level 10 saved 1475 */
24const char help_text[] = { 24const char help_text[] = {
250xf0, 0x2e, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 250xfc, 0x05, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
260x31, 0x32, 0x3a, 0x20, 0x4d, 0x69, 0x6e, 0x65, 0x73, 0x20, 260x31, 0x32, 0x3a, 0x20, 0x4d, 0x69, 0x6e, 0x65, 0x73, 0x20,
270x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 270x00, 0x2d, 0x01, 0x00, 0xf0, 0x1c, 0x00, 0x00, 0x00, 0x59,
280x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 280x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00,
290x66, 0x00, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x65, 0x64, 0x00, 290x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x63, 0x6f,
300x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x73, 300x76, 0x65, 0x72, 0x65, 0x64, 0x00, 0x73, 0x71, 0x75, 0x61,
310x6f, 0x6d, 0x65, 0x19, 0x00, 0xf0, 0x02, 0x77, 0x68, 0x69, 310x72, 0x65, 0x73, 0x2c, 0x00, 0x73, 0x6f, 0x6d, 0x65, 0x19,
320x63, 0x68, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 320x00, 0xf0, 0x02, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x63,
330x00, 0x6d, 0x69, 0x6e, 0x1d, 0x00, 0xf2, 0x03, 0x62, 0x75, 330x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x00, 0x6d, 0x69, 0x6e,
340x74, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x64, 0x6f, 0x6e, 0x27, 340x1d, 0x00, 0xf2, 0x03, 0x62, 0x75, 0x74, 0x00, 0x79, 0x6f,
350x74, 0x00, 0x6b, 0x6e, 0x6f, 0x77, 0x28, 0x00, 0x10, 0x2e, 350x75, 0x00, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x00, 0x6b, 0x6e,
360x5b, 0x00, 0xe1, 0x72, 0x00, 0x6a, 0x6f, 0x62, 0x00, 0x69, 360x6f, 0x77, 0x28, 0x00, 0x10, 0x2e, 0x5b, 0x00, 0xe1, 0x72,
370x73, 0x00, 0x74, 0x6f, 0x00, 0x75, 0x6e, 0x59, 0x00, 0x63, 370x00, 0x6a, 0x6f, 0x62, 0x00, 0x69, 0x73, 0x00, 0x74, 0x6f,
380x00, 0x65, 0x76, 0x65, 0x72, 0x79, 0x5d, 0x00, 0x03, 0x53, 380x00, 0x75, 0x6e, 0x59, 0x00, 0x63, 0x00, 0x65, 0x76, 0x65,
390x00, 0x85, 0x64, 0x6f, 0x65, 0x73, 0x00, 0x6e, 0x6f, 0x74, 390x72, 0x79, 0x5d, 0x00, 0x03, 0x53, 0x00, 0x85, 0x64, 0x6f,
400x5c, 0x00, 0x11, 0x61, 0x5e, 0x00, 0x41, 0x2e, 0x00, 0x49, 400x65, 0x73, 0x00, 0x6e, 0x6f, 0x74, 0x5c, 0x00, 0x11, 0x61,
410x66, 0x5c, 0x00, 0x04, 0x3b, 0x00, 0x14, 0x61, 0x37, 0x00, 410x5e, 0x00, 0x41, 0x2e, 0x00, 0x49, 0x66, 0x5c, 0x00, 0x04,
420x03, 0x28, 0x00, 0x33, 0x69, 0x6e, 0x67, 0x2b, 0x00, 0x11, 420x3b, 0x00, 0x14, 0x61, 0x37, 0x00, 0x03, 0x28, 0x00, 0x33,
430x2c, 0x28, 0x00, 0x3f, 0x6c, 0x6f, 0x73, 0x35, 0x00, 0x08, 430x69, 0x6e, 0x67, 0x2b, 0x00, 0x11, 0x2c, 0x28, 0x00, 0x3f,
440x0f, 0x6c, 0x00, 0x0a, 0x02, 0x41, 0x00, 0x00, 0x27, 0x00, 440x6c, 0x6f, 0x73, 0x35, 0x00, 0x08, 0x0f, 0x6c, 0x00, 0x0a,
450xd2, 0x74, 0x6f, 0x6c, 0x64, 0x00, 0x68, 0x6f, 0x77, 0x00, 450x02, 0x41, 0x00, 0x00, 0x27, 0x00, 0xd2, 0x74, 0x6f, 0x6c,
460x6d, 0x61, 0x6e, 0x79, 0xe6, 0x00, 0x17, 0x00, 0x74, 0x00, 460x64, 0x00, 0x68, 0x6f, 0x77, 0x00, 0x6d, 0x61, 0x6e, 0x79,
470xf0, 0x0d, 0x65, 0x64, 0x00, 0x77, 0x69, 0x74, 0x68, 0x69, 470xe6, 0x00, 0x17, 0x00, 0x74, 0x00, 0xf0, 0x0d, 0x65, 0x64,
480x6e, 0x00, 0x74, 0x68, 0x65, 0x00, 0x65, 0x69, 0x67, 0x68, 480x00, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x00, 0x74, 0x68,
490x74, 0x00, 0x73, 0x75, 0x72, 0x72, 0x6f, 0x75, 0x6e, 0x64, 490x65, 0x00, 0x65, 0x69, 0x67, 0x68, 0x74, 0x00, 0x73, 0x75,
500x90, 0x00, 0x03, 0x36, 0x01, 0xf0, 0x03, 0x2e, 0x00, 0x00, 500x72, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x90, 0x00, 0x03, 0x36,
510x00, 0x54, 0x68, 0x69, 0x73, 0x00, 0x67, 0x61, 0x6d, 0x65, 510x01, 0xf0, 0x03, 0x2e, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69,
520x00, 0x6e, 0x65, 0x65, 0x64, 0x76, 0x00, 0xf0, 0x1a, 0x00, 520x73, 0x00, 0x67, 0x61, 0x6d, 0x65, 0x00, 0x6e, 0x65, 0x65,
530x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 530x64, 0x76, 0x00, 0xf0, 0x1a, 0x00, 0x69, 0x6e, 0x74, 0x72,
540x6f, 0x6e, 0x3b, 0x00, 0x70, 0x6f, 0x70, 0x75, 0x6c, 0x61, 540x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x00,
550x72, 0x69, 0x73, 0x65, 0x64, 0x00, 0x62, 0x79, 0x00, 0x57, 550x70, 0x6f, 0x70, 0x75, 0x6c, 0x61, 0x72, 0x69, 0x73, 0x65,
560x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x2c, 0x00, 0x69, 0x74, 560x64, 0x00, 0x62, 0x79, 0x00, 0x57, 0x69, 0x6e, 0x64, 0x6f,
570x34, 0x01, 0x71, 0x70, 0x65, 0x72, 0x68, 0x61, 0x70, 0x73, 570x77, 0x73, 0x2c, 0x00, 0x69, 0x74, 0x34, 0x01, 0x71, 0x70,
580x68, 0x00, 0xa2, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x00, 580x65, 0x72, 0x68, 0x61, 0x70, 0x73, 0x68, 0x00, 0xa2, 0x73,
590x62, 0x65, 0x73, 0x64, 0x01, 0xf2, 0x01, 0x6e, 0x00, 0x64, 590x69, 0x6e, 0x67, 0x6c, 0x65, 0x00, 0x62, 0x65, 0x73, 0x64,
600x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x00, 0x70, 0x75, 0x7a, 600x01, 0xf2, 0x01, 0x6e, 0x00, 0x64, 0x65, 0x73, 0x6b, 0x74,
610x7a, 0x6c, 0x65, 0x67, 0x00, 0xc5, 0x69, 0x6e, 0x00, 0x65, 610x6f, 0x70, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x67,
620x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x81, 0x00, 620x00, 0xc5, 0x69, 0x6e, 0x00, 0x65, 0x78, 0x69, 0x73, 0x74,
630x70, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0xc1, 0x01, 630x65, 0x6e, 0x63, 0x65, 0x81, 0x00, 0x70, 0x76, 0x65, 0x72,
640xf1, 0x17, 0x69, 0x74, 0x00, 0x68, 0x61, 0x73, 0x00, 0x61, 640x73, 0x69, 0x6f, 0x6e, 0xc1, 0x01, 0xf1, 0x17, 0x69, 0x74,
650x6e, 0x00, 0x75, 0x6e, 0x75, 0x73, 0x75, 0x61, 0x6c, 0x00, 650x00, 0x68, 0x61, 0x73, 0x00, 0x61, 0x6e, 0x00, 0x75, 0x6e,
660x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x2e, 0x00, 660x75, 0x73, 0x75, 0x61, 0x6c, 0x00, 0x70, 0x72, 0x6f, 0x70,
670x42, 0x79, 0x00, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 670x65, 0x72, 0x74, 0x79, 0x2e, 0x00, 0x42, 0x79, 0x00, 0x64,
680x80, 0x00, 0xf1, 0x02, 0x77, 0x69, 0x6c, 0x6c, 0x00, 0x67, 680x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x80, 0x00, 0xf1, 0x02,
690x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x00, 0x69, 0x74, 690x77, 0x69, 0x6c, 0x6c, 0x00, 0x67, 0x65, 0x6e, 0x65, 0x72,
700x73, 0x0a, 0x01, 0x50, 0x00, 0x70, 0x6f, 0x73, 0x69, 0xbc, 700x61, 0x74, 0x65, 0x00, 0x69, 0x74, 0x73, 0x0a, 0x01, 0x50,
710x00, 0x10, 0x73, 0x6c, 0x00, 0xc1, 0x73, 0x75, 0x63, 0x68, 710x00, 0x70, 0x6f, 0x73, 0x69, 0xbc, 0x00, 0x10, 0x73, 0x6c,
720x00, 0x61, 0x00, 0x77, 0x61, 0x79, 0x00, 0x61, 0xe3, 0x01, 720x00, 0xc1, 0x73, 0x75, 0x63, 0x68, 0x00, 0x61, 0x00, 0x77,
730x40, 0x65, 0x6e, 0x73, 0x75, 0x42, 0x01, 0x22, 0x68, 0x61, 730x61, 0x79, 0x00, 0x61, 0xe3, 0x01, 0x40, 0x65, 0x6e, 0x73,
740x14, 0x02, 0x10, 0x6e, 0xec, 0x01, 0x01, 0xfd, 0x00, 0x00, 740x75, 0x42, 0x01, 0x22, 0x68, 0x61, 0x14, 0x02, 0x10, 0x6e,
750x1e, 0x00, 0xb3, 0x67, 0x75, 0x65, 0x73, 0x73, 0x00, 0x77, 750xec, 0x01, 0x01, 0xfd, 0x00, 0x00, 0x1e, 0x00, 0xb3, 0x67,
760x68, 0x65, 0x72, 0x65, 0x75, 0x01, 0x41, 0x00, 0x69, 0x73, 760x75, 0x65, 0x73, 0x73, 0x00, 0x77, 0x68, 0x65, 0x72, 0x65,
770x3a, 0x29, 0x00, 0x01, 0x6e, 0x00, 0xe0, 0x61, 0x6c, 0x77, 770x75, 0x01, 0x41, 0x00, 0x69, 0x73, 0x3a, 0x29, 0x00, 0x01,
780x61, 0x79, 0x73, 0x00, 0x62, 0x65, 0x00, 0x61, 0x62, 0x6c, 780x6e, 0x00, 0xe0, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x00,
790x65, 0x32, 0x00, 0x50, 0x64, 0x65, 0x64, 0x75, 0x63, 0x7e, 790x62, 0x65, 0x00, 0x61, 0x62, 0x6c, 0x65, 0x32, 0x00, 0x50,
800x00, 0x01, 0x83, 0x02, 0x76, 0x68, 0x6f, 0x77, 0x2e, 0x00, 800x64, 0x65, 0x64, 0x75, 0x63, 0x7e, 0x00, 0x01, 0x83, 0x02,
810x53, 0x6f, 0x31, 0x00, 0x01, 0x5f, 0x00, 0x10, 0x2c, 0x7c, 810x76, 0x68, 0x6f, 0x77, 0x2e, 0x00, 0x53, 0x6f, 0x31, 0x00,
820x00, 0xa0, 0x63, 0x61, 0x6e, 0x00, 0x68, 0x61, 0x70, 0x70, 820x01, 0x5f, 0x00, 0x10, 0x2c, 0x7c, 0x00, 0xa0, 0x63, 0x61,
830x65, 0x6e, 0x98, 0x00, 0x54, 0x6f, 0x74, 0x68, 0x65, 0x72, 830x6e, 0x00, 0x68, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x98, 0x00,
840xf8, 0x00, 0x60, 0x73, 0x2c, 0x00, 0x67, 0x65, 0x74, 0x4e, 840x54, 0x6f, 0x74, 0x68, 0x65, 0x72, 0xf8, 0x00, 0x60, 0x73,
850x00, 0x00, 0x48, 0x01, 0x60, 0x6c, 0x61, 0x73, 0x74, 0x00, 850x2c, 0x00, 0x67, 0x65, 0x74, 0x4e, 0x00, 0x00, 0x48, 0x01,
860x66, 0x99, 0x02, 0x03, 0xa8, 0x01, 0x82, 0x00, 0x61, 0x6e, 860x60, 0x6c, 0x61, 0x73, 0x74, 0x00, 0x66, 0x99, 0x02, 0x03,
870x64, 0x00, 0x64, 0x69, 0x73, 0x2c, 0x02, 0x01, 0xba, 0x00, 870xa8, 0x01, 0x82, 0x00, 0x61, 0x6e, 0x64, 0x00, 0x64, 0x69,
880x12, 0x74, 0xa2, 0x00, 0x00, 0xc9, 0x00, 0x23, 0x77, 0x6f, 880x73, 0x2c, 0x02, 0x01, 0xba, 0x00, 0x12, 0x74, 0xa2, 0x00,
890x01, 0x02, 0x45, 0x6c, 0x65, 0x66, 0x74, 0xeb, 0x02, 0x01, 890x00, 0xc9, 0x00, 0x23, 0x77, 0x6f, 0x01, 0x02, 0x45, 0x6c,
900x30, 0x03, 0x21, 0x6e, 0x6f, 0xf9, 0x00, 0x21, 0x6f, 0x66, 900x65, 0x66, 0x74, 0xeb, 0x02, 0x01, 0x30, 0x03, 0x21, 0x6e,
910x90, 0x01, 0x00, 0xfa, 0x01, 0x41, 0x66, 0x6f, 0x72, 0x00, 910x6f, 0xf9, 0x00, 0x21, 0x6f, 0x66, 0x90, 0x01, 0x00, 0xfa,
920x00, 0x01, 0x02, 0xe3, 0x00, 0x40, 0x74, 0x68, 0x65, 0x79, 920x01, 0x41, 0x66, 0x6f, 0x72, 0x00, 0x00, 0x01, 0x02, 0xe3,
930x46, 0x00, 0x00, 0x89, 0x01, 0x43, 0x31, 0x32, 0x2e, 0x31, 930x00, 0x40, 0x74, 0x68, 0x65, 0x79, 0x46, 0x00, 0x00, 0x89,
940x74, 0x03, 0x20, 0x63, 0x6f, 0x03, 0x02, 0x39, 0x6c, 0x73, 940x01, 0x43, 0x31, 0x32, 0x2e, 0x31, 0x86, 0x03, 0x20, 0x63,
950x20, 0x21, 0x02, 0x00, 0xef, 0x01, 0x33, 0x6c, 0x61, 0x79, 950x6f, 0x03, 0x02, 0x39, 0x6c, 0x73, 0x20, 0x21, 0x02, 0x00,
960x5d, 0x02, 0x01, 0xab, 0x00, 0x41, 0x6d, 0x6f, 0x75, 0x73, 960xef, 0x01, 0x33, 0x6c, 0x61, 0x79, 0x5d, 0x02, 0x01, 0xab,
970x3d, 0x00, 0x03, 0xd0, 0x02, 0x00, 0x83, 0x00, 0x71, 0x2d, 970x00, 0x41, 0x6d, 0x6f, 0x75, 0x73, 0x3d, 0x00, 0x03, 0xd0,
980x63, 0x6c, 0x69, 0x63, 0x6b, 0x00, 0xb6, 0x02, 0x0a, 0xa7, 980x02, 0x00, 0x83, 0x00, 0x71, 0x2d, 0x63, 0x6c, 0x69, 0x63,
990x03, 0x06, 0xb5, 0x01, 0x24, 0x62, 0x65, 0xfb, 0x02, 0x27, 990x6b, 0x00, 0xb6, 0x02, 0x0a, 0xa7, 0x03, 0x06, 0xb5, 0x01,
1000x65, 0x64, 0x3f, 0x00, 0x10, 0x72, 0xaa, 0x02, 0x0f, 0x40, 1000x24, 0x62, 0x65, 0xfb, 0x02, 0x27, 0x65, 0x64, 0x3f, 0x00,
1010x00, 0x11, 0x40, 0x70, 0x6c, 0x61, 0x63, 0xa1, 0x01, 0x43, 1010x10, 0x72, 0xaa, 0x02, 0x0f, 0x40, 0x00, 0x11, 0x40, 0x70,
1020x66, 0x6c, 0x61, 0x67, 0x34, 0x03, 0x95, 0x69, 0x6e, 0x64, 1020x6c, 0x61, 0x63, 0xa1, 0x01, 0x43, 0x66, 0x6c, 0x61, 0x67,
1030x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x21, 0x01, 0x04, 0x54, 1030x34, 0x03, 0x95, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74,
1040x03, 0x10, 0x69, 0xb0, 0x01, 0x42, 0x6c, 0x69, 0x65, 0x76, 1040x65, 0x73, 0x21, 0x01, 0x04, 0x54, 0x03, 0x10, 0x69, 0xb0,
1050xe3, 0x01, 0x25, 0x62, 0x65, 0xbb, 0x03, 0x15, 0x4c, 0xaf, 1050x01, 0x42, 0x6c, 0x69, 0x65, 0x76, 0xe3, 0x01, 0x25, 0x62,
1060x00, 0x00, 0x1c, 0x01, 0x02, 0x68, 0x03, 0x35, 0x61, 0x72, 1060x65, 0xbb, 0x03, 0x15, 0x4c, 0xaf, 0x00, 0x00, 0x1c, 0x01,
1070x6b, 0x71, 0x00, 0x03, 0xc3, 0x01, 0x25, 0x6f, 0x74, 0xa9, 1070x02, 0x68, 0x03, 0x35, 0x61, 0x72, 0x6b, 0x71, 0x00, 0x03,
1080x03, 0x32, 0x69, 0x74, 0x2c, 0x44, 0x01, 0x51, 0x61, 0x66, 1080xc3, 0x01, 0x25, 0x6f, 0x74, 0xa9, 0x03, 0x32, 0x69, 0x74,
1090x65, 0x74, 0x79, 0x40, 0x04, 0x01, 0xd9, 0x01, 0x08, 0xba, 1090x2c, 0x44, 0x01, 0x51, 0x61, 0x66, 0x65, 0x74, 0x79, 0x40,
1100x00, 0x30, 0x61, 0x67, 0x61, 0x7a, 0x03, 0x83, 0x6f, 0x00, 1100x04, 0x01, 0xd9, 0x01, 0x08, 0xba, 0x00, 0x30, 0x61, 0x67,
1110x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x55, 0x00, 0x02, 0xb4, 1110x61, 0x7a, 0x03, 0x83, 0x6f, 0x00, 0x72, 0x65, 0x6d, 0x6f,
1120x00, 0x11, 0x64, 0x00, 0x03, 0x4f, 0x72, 0x72, 0x6f, 0x72, 1120x76, 0x65, 0x55, 0x00, 0x02, 0xb4, 0x00, 0x11, 0x64, 0x00,
1130x36, 0x01, 0x07, 0x00, 0xfa, 0x02, 0x0f, 0xf9, 0x00, 0x05, 1130x03, 0x4f, 0x72, 0x72, 0x6f, 0x72, 0x36, 0x01, 0x07, 0x00,
1140x81, 0x60, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x00, 0x61, 0xcb, 1140xfa, 0x02, 0x0f, 0xf9, 0x00, 0x05, 0x81, 0x60, 0x63, 0x6c,
1150x03, 0x17, 0x27, 0xe6, 0x00, 0x12, 0x2e, 0xa9, 0x01, 0x98, 1150x65, 0x61, 0x72, 0x00, 0x61, 0xcb, 0x03, 0x17, 0x27, 0xe6,
1160x6d, 0x65, 0x61, 0x6e, 0x73, 0x3a, 0x00, 0x69, 0x66, 0x01, 1160x00, 0x12, 0x2e, 0xa9, 0x01, 0x98, 0x6d, 0x65, 0x61, 0x6e,
1170x01, 0x00, 0x50, 0x03, 0x61, 0x65, 0x78, 0x61, 0x63, 0x74, 1170x73, 0x3a, 0x00, 0x69, 0x66, 0x01, 0x01, 0x00, 0x50, 0x03,
1180x6c, 0x05, 0x03, 0x01, 0x34, 0x04, 0x00, 0x3a, 0x01, 0x19, 1180x61, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 0x05, 0x03, 0x01,
1190x73, 0x15, 0x04, 0x20, 0x69, 0x74, 0x1d, 0x00, 0x00, 0xc8, 1190x34, 0x04, 0x00, 0x3a, 0x01, 0x19, 0x73, 0x15, 0x04, 0x20,
1200x02, 0x52, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x42, 0x02, 0x03, 1200x69, 0x74, 0x1d, 0x00, 0x00, 0xc8, 0x02, 0x52, 0x68, 0x6f,
1210x41, 0x05, 0x81, 0x74, 0x68, 0x65, 0x6e, 0x00, 0x61, 0x6c, 1210x75, 0x6c, 0x64, 0x42, 0x02, 0x03, 0x41, 0x05, 0x81, 0x74,
1220x6c, 0x56, 0x00, 0x0b, 0x7c, 0x05, 0x41, 0x00, 0x6e, 0x65, 1220x68, 0x65, 0x6e, 0x00, 0x61, 0x6c, 0x6c, 0x56, 0x00, 0x0b,
1230x78, 0xbc, 0x02, 0x23, 0x69, 0x74, 0x8b, 0x01, 0x00, 0x74, 1230x7c, 0x05, 0x41, 0x00, 0x6e, 0x65, 0x78, 0xbc, 0x02, 0x23,
1240x00, 0x00, 0x35, 0x01, 0x00, 0x64, 0x00, 0x3e, 0x67, 0x65, 1240x69, 0x74, 0x8b, 0x01, 0x00, 0x74, 0x00, 0x00, 0x35, 0x01,
1250x64, 0xf3, 0x01, 0x01, 0x23, 0x03, 0x41, 0x6f, 0x6e, 0x63, 1250x00, 0x64, 0x00, 0x3e, 0x67, 0x65, 0x64, 0xf3, 0x01, 0x01,
1260x65, 0xff, 0x00, 0x00, 0xa9, 0x04, 0x11, 0x6b, 0x0a, 0x00, 1260x23, 0x03, 0x41, 0x6f, 0x6e, 0x63, 0x65, 0xff, 0x00, 0x00,
1270x01, 0x9a, 0x05, 0x01, 0x03, 0x03, 0x43, 0x6f, 0x63, 0x61, 1270xa9, 0x04, 0x11, 0x6b, 0x0a, 0x00, 0x01, 0x9a, 0x05, 0x01,
1280x74, 0x11, 0x04, 0x04, 0x77, 0x00, 0x04, 0xe6, 0x04, 0x00, 1280x03, 0x03, 0x43, 0x6f, 0x63, 0x61, 0x74, 0x11, 0x04, 0x04,
1290xb0, 0x00, 0x05, 0x31, 0x05, 0x02, 0x13, 0x05, 0x10, 0x63, 1290x77, 0x00, 0x04, 0xe6, 0x04, 0x00, 0xb0, 0x00, 0x05, 0x31,
1300x34, 0x01, 0x20, 0x73, 0x65, 0x4a, 0x00, 0x61, 0x73, 0x00, 1300x05, 0x02, 0x13, 0x05, 0x10, 0x63, 0x34, 0x01, 0x20, 0x73,
1310x66, 0x75, 0x6e, 0x63, 0x3c, 0x00, 0x00, 0x46, 0x04, 0x00, 1310x65, 0x4a, 0x00, 0x61, 0x73, 0x00, 0x66, 0x75, 0x6e, 0x63,
1320xcd, 0x00, 0x41, 0x72, 0x74, 0x63, 0x75, 0xa1, 0x00, 0x41, 1320x3c, 0x00, 0x00, 0x46, 0x04, 0x00, 0xcd, 0x00, 0x41, 0x72,
1330x61, 0x76, 0x6f, 0x69, 0xd8, 0x00, 0x00, 0xef, 0x00, 0x32, 1330x74, 0x63, 0x75, 0xa1, 0x00, 0x41, 0x61, 0x76, 0x6f, 0x69,
1340x74, 0x6f, 0x00, 0x73, 0x01, 0x92, 0x6f, 0x6e, 0x00, 0x65, 1340xd8, 0x00, 0x00, 0xef, 0x00, 0x32, 0x74, 0x6f, 0x00, 0x73,
1350x61, 0x63, 0x68, 0x00, 0x6f, 0x34, 0x01, 0x33, 0x72, 0x65, 1350x01, 0x92, 0x6f, 0x6e, 0x00, 0x65, 0x61, 0x63, 0x68, 0x00,
1360x6d, 0xb6, 0x05, 0x04, 0xe0, 0x00, 0x30, 0x6f, 0x6e, 0x65, 1360x6f, 0x34, 0x01, 0x33, 0x72, 0x65, 0x6d, 0xb6, 0x05, 0x04,
1370xfa, 0x04, 0x28, 0x6f, 0x6e, 0xea, 0x02, 0x0f, 0xba, 0x05, 1370xe0, 0x00, 0x30, 0x6f, 0x6e, 0x65, 0xfa, 0x04, 0x28, 0x6f,
1380x04, 0x00, 0x6b, 0x01, 0x14, 0x6e, 0x91, 0x03, 0x03, 0x80, 1380x6e, 0xea, 0x02, 0x0f, 0xba, 0x05, 0x04, 0x00, 0x6b, 0x01,
1390x05, 0x08, 0x65, 0x01, 0x03, 0x8c, 0x05, 0x04, 0xb6, 0x06, 1390x14, 0x6e, 0x91, 0x03, 0x03, 0x80, 0x05, 0x08, 0x65, 0x01,
1400x01, 0x58, 0x01, 0x02, 0x4a, 0x05, 0x91, 0x6f, 0x62, 0x76, 1400x03, 0x8c, 0x05, 0x04, 0xb6, 0x06, 0x01, 0x58, 0x01, 0x02,
1410x69, 0x6f, 0x75, 0x73, 0x6c, 0x79, 0x5c, 0x02, 0x08, 0x8d, 1410x4a, 0x05, 0x91, 0x6f, 0x62, 0x76, 0x69, 0x6f, 0x75, 0x73,
1420x06, 0x44, 0x74, 0x68, 0x6f, 0x73, 0xcc, 0x01, 0x02, 0x55, 1420x6c, 0x79, 0x5c, 0x02, 0x08, 0x8d, 0x06, 0x44, 0x74, 0x68,
1430x00, 0x41, 0x75, 0x72, 0x6e, 0x2c, 0x15, 0x04, 0x10, 0x73, 1430x6f, 0x73, 0xcc, 0x01, 0x02, 0x55, 0x00, 0x41, 0x75, 0x72,
1440x47, 0x01, 0x00, 0xee, 0x01, 0x00, 0xd3, 0x01, 0x02, 0xc1, 1440x6e, 0x2c, 0x15, 0x04, 0x10, 0x73, 0x47, 0x01, 0x00, 0xee,
1450x00, 0x64, 0x6d, 0x00, 0x61, 0x6c, 0x73, 0x6f, 0x89, 0x00, 1450x01, 0x00, 0xd3, 0x01, 0x02, 0xc1, 0x00, 0x64, 0x6d, 0x00,
1460x08, 0x7c, 0x00, 0x01, 0x95, 0x00, 0x03, 0x28, 0x02, 0x04, 1460x61, 0x6c, 0x73, 0x6f, 0x89, 0x00, 0x08, 0x7c, 0x00, 0x01,
1470x93, 0x01, 0x10, 0x64, 0xdd, 0x00, 0x00, 0xd1, 0x02, 0x01, 1470x95, 0x00, 0x03, 0x28, 0x02, 0x04, 0x93, 0x01, 0x10, 0x64,
1480x5a, 0x06, 0xd0, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 1480xdd, 0x00, 0x00, 0xd1, 0x02, 0x01, 0x5a, 0x06, 0xd0, 0x75,
1490x63, 0x61, 0x6c, 0x6c, 0x79, 0x3b, 0x5d, 0x00, 0x00, 0xd3, 1490x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x6c,
1500x04, 0x41, 0x74, 0x69, 0x6d, 0x65, 0x13, 0x05, 0x1f, 0x6e, 1500x79, 0x3b, 0x5d, 0x00, 0x00, 0xd3, 0x04, 0x41, 0x74, 0x69,
1510xf9, 0x00, 0x02, 0x10, 0x2c, 0x5e, 0x05, 0x30, 0x68, 0x6f, 1510x6d, 0x65, 0x13, 0x05, 0x1f, 0x6e, 0xf9, 0x00, 0x02, 0x10,
1520x6c, 0x41, 0x06, 0x10, 0x77, 0xfb, 0x01, 0x12, 0x61, 0x5d, 1520x2c, 0x5e, 0x05, 0x30, 0x68, 0x6f, 0x6c, 0x41, 0x06, 0x10,
1530x00, 0x10, 0x6f, 0xe9, 0x04, 0x23, 0x75, 0x70, 0x72, 0x03, 1530x77, 0xfb, 0x01, 0x12, 0x61, 0x5d, 0x00, 0x10, 0x6f, 0xe9,
1540x53, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0xed, 0x03, 0x04, 0x34, 1540x04, 0x23, 0x75, 0x70, 0x72, 0x03, 0x53, 0x65, 0x78, 0x70,
1550x03, 0x01, 0xa8, 0x00, 0x02, 0xb7, 0x01, 0xc1, 0x65, 0x00, 1550x6c, 0x6f, 0xed, 0x03, 0x04, 0x34, 0x03, 0x01, 0xa8, 0x00,
1560x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 1560x02, 0xb7, 0x01, 0xc1, 0x65, 0x00, 0x63, 0x75, 0x72, 0x73,
1570xa6, 0x05, 0x02, 0x39, 0x03, 0x02, 0xec, 0x01, 0x04, 0xfd, 1570x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0xa6, 0x05, 0x02, 0x39,
1580x01, 0xb0, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x2e, 0x00, 0x50, 1580x03, 0x02, 0xec, 0x01, 0x04, 0xfd, 0x01, 0xb0, 0x66, 0x69,
1590x72, 0x65, 0x73, 0x6b, 0x06, 0x03, 0xae, 0x01, 0x00, 0x0d, 1590x65, 0x6c, 0x64, 0x2e, 0x00, 0x50, 0x72, 0x65, 0x73, 0x6b,
1600x01, 0x00, 0x37, 0x00, 0x0f, 0x31, 0x04, 0x01, 0x04, 0xad, 1600x06, 0x03, 0xae, 0x01, 0x00, 0x0d, 0x01, 0x00, 0x37, 0x00,
1610x00, 0x00, 0xd7, 0x02, 0x02, 0x31, 0x01, 0x0e, 0x60, 0x03, 1610x0f, 0x31, 0x04, 0x01, 0x04, 0xad, 0x00, 0x00, 0xd7, 0x02,
1620x06, 0xe8, 0x03, 0x08, 0x5b, 0x03, 0x00, 0x95, 0x01, 0x31, 1620x02, 0x31, 0x01, 0x0e, 0x60, 0x03, 0x06, 0xe8, 0x03, 0x08,
1630x28, 0x73, 0x6f, 0x15, 0x03, 0x52, 0x63, 0x74, 0x73, 0x00, 1630x5b, 0x03, 0x00, 0x95, 0x01, 0x31, 0x28, 0x73, 0x6f, 0x15,
1640x61, 0xe3, 0x06, 0x04, 0x63, 0x05, 0x78, 0x74, 0x6f, 0x6e, 1640x03, 0x52, 0x63, 0x74, 0x73, 0x00, 0x61, 0xe3, 0x06, 0x04,
1650x29, 0x2c, 0x00, 0x70, 0x8a, 0x00, 0x20, 0x73, 0x70, 0x93, 1650x63, 0x05, 0x78, 0x74, 0x6f, 0x6e, 0x29, 0x2c, 0x00, 0x70,
1660x04, 0x3f, 0x62, 0x61, 0x72, 0x89, 0x00, 0x02, 0x0e, 0xb6, 1660x8a, 0x00, 0x20, 0x73, 0x70, 0x93, 0x04, 0x3f, 0x62, 0x61,
1670x04, 0xbc, 0x28, 0x73, 0x69, 0x6d, 0x69, 0x6c, 0x61, 0x72, 1670x72, 0x89, 0x00, 0x02, 0x0e, 0xb6, 0x04, 0xbc, 0x28, 0x73,
1680x6c, 0x79, 0x2c, 0x66, 0x00, 0x01, 0x4d, 0x04, 0x04, 0x67, 1680x69, 0x6d, 0x69, 0x6c, 0x61, 0x72, 0x6c, 0x79, 0x2c, 0x66,
1690x00, 0x00, 0x32, 0x01, 0x13, 0x41, 0x03, 0x03, 0x22, 0x61, 1690x00, 0x01, 0x4d, 0x04, 0x04, 0x67, 0x00, 0x00, 0x32, 0x01,
1700x63, 0xd8, 0x06, 0x72, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 1700x13, 0x41, 0x03, 0x03, 0x22, 0x61, 0x63, 0xd8, 0x06, 0x72,
1710x62, 0x4e, 0x04, 0x22, 0x73, 0x65, 0xef, 0x02, 0x31, 0x32, 1710x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x4e, 0x04, 0x22,
1720x2e, 0x31, 0x7a, 0x03, 0x01, 0x57, 0x01, 0x50, 0x61, 0x76, 1720x73, 0x65, 0xef, 0x02, 0x31, 0x32, 0x2e, 0x31, 0x7a, 0x03,
1730x61, 0x69, 0x6c, 0xa3, 0x06, 0x00, 0x3f, 0x00, 0x90, 0x45, 1730x01, 0x57, 0x01, 0x50, 0x61, 0x76, 0x61, 0x69, 0x6c, 0xa3,
1740x76, 0x65, 0x6e, 0x00, 0x55, 0x6e, 0x64, 0x6f, 0x68, 0x02, 1740x06, 0x00, 0x3f, 0x00, 0x90, 0x45, 0x76, 0x65, 0x6e, 0x00,
1750x05, 0x1a, 0x00, 0xa1, 0x2c, 0x00, 0x61, 0x6c, 0x74, 0x68, 1750x55, 0x6e, 0x64, 0x6f, 0x68, 0x02, 0x05, 0x1a, 0x00, 0xa1,
1760x6f, 0x75, 0x67, 0x68, 0xd8, 0x01, 0x11, 0x6d, 0x75, 0x00, 1760x2c, 0x00, 0x61, 0x6c, 0x74, 0x68, 0x6f, 0x75, 0x67, 0x68,
1770x61, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0xe9, 0x04, 0x63, 1770xd8, 0x01, 0x11, 0x6d, 0x75, 0x00, 0x61, 0x63, 0x6f, 0x6e,
1780x00, 0x63, 0x68, 0x65, 0x61, 0x74, 0x2b, 0x03, 0x20, 0x75, 1780x73, 0x69, 0x64, 0xe9, 0x04, 0x63, 0x00, 0x63, 0x68, 0x65,
1790x73, 0xe3, 0x06, 0x05, 0xb8, 0x08, 0x66, 0x73, 0x74, 0x65, 1790x61, 0x74, 0x2b, 0x03, 0x20, 0x75, 0x73, 0xe3, 0x06, 0x05,
1800x70, 0x00, 0x6f, 0x98, 0x08, 0x00, 0x9d, 0x00, 0x73, 0x70, 1800xb8, 0x08, 0x66, 0x73, 0x74, 0x65, 0x70, 0x00, 0x6f, 0x98,
1810x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0xfe, 0x01, 0x96, 0x6e, 1810x08, 0x00, 0x9d, 0x00, 0x73, 0x70, 0x72, 0x6f, 0x67, 0x72,
1820x6c, 0x79, 0x00, 0x72, 0x65, 0x76, 0x65, 0x61, 0xbd, 0x03, 1820x61, 0x6d, 0xfe, 0x01, 0x96, 0x6e, 0x6c, 0x79, 0x00, 0x72,
1830x00, 0xad, 0x00, 0x41, 0x71, 0x75, 0x65, 0x73, 0xae, 0x00, 1830x65, 0x76, 0x65, 0x61, 0xbd, 0x03, 0x00, 0xad, 0x00, 0x41,
1840x60, 0x28, 0x75, 0x6e, 0x6c, 0x69, 0x6b, 0x42, 0x06, 0x23, 1840x71, 0x75, 0x65, 0x73, 0xae, 0x00, 0x60, 0x28, 0x75, 0x6e,
1850x73, 0x74, 0x0d, 0x07, 0xb2, 0x69, 0x6d, 0x70, 0x6c, 0x65, 1850x6c, 0x69, 0x6b, 0x42, 0x06, 0x23, 0x73, 0x74, 0x0d, 0x07,
1860x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x14, 0x07, 0x02, 0x53, 1860xb2, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74,
1870x03, 0x03, 0x46, 0x00, 0x00, 0x07, 0x04, 0x03, 0xe2, 0x02, 1870x61, 0x74, 0x14, 0x07, 0x02, 0x53, 0x03, 0x03, 0x46, 0x00,
1880x16, 0x29, 0x78, 0x05, 0x24, 0x74, 0x68, 0xdb, 0x00, 0x10, 1880x00, 0x07, 0x04, 0x03, 0xe2, 0x02, 0x16, 0x29, 0x78, 0x05,
1890x79, 0x31, 0x07, 0x53, 0x66, 0x61, 0x74, 0x61, 0x6c, 0x3d, 1890x24, 0x74, 0x68, 0xdb, 0x00, 0x10, 0x79, 0x31, 0x07, 0x53,
1900x02, 0x21, 0x6e, 0x64, 0x0f, 0x09, 0x41, 0x69, 0x6e, 0x75, 1900x66, 0x61, 0x74, 0x61, 0x6c, 0x3d, 0x02, 0x21, 0x6e, 0x64,
1910x65, 0xb8, 0x06, 0x01, 0xe4, 0x04, 0x03, 0x71, 0x05, 0x21, 1910x0f, 0x09, 0x41, 0x69, 0x6e, 0x75, 0x65, 0xb8, 0x06, 0x01,
1920x69, 0x6b, 0x31, 0x05, 0x0b, 0xb5, 0x00, 0x51, 0x74, 0x72, 1920xe4, 0x04, 0x03, 0x71, 0x05, 0x21, 0x69, 0x6b, 0x31, 0x05,
1930x61, 0x63, 0x6b, 0xaf, 0x00, 0x61, 0x6e, 0x75, 0x6d, 0x62, 1930x0b, 0xb5, 0x00, 0x51, 0x74, 0x72, 0x61, 0x63, 0x6b, 0xaf,
1940x65, 0x72, 0x70, 0x00, 0x01, 0xfe, 0x02, 0x01, 0x3d, 0x0a, 1940x00, 0x61, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x70, 0x00,
1950x50, 0x69, 0x65, 0x64, 0x00, 0x28, 0x57, 0x00, 0x01, 0x70, 1950x01, 0xfe, 0x02, 0x01, 0x3d, 0x0a, 0x50, 0x69, 0x65, 0x64,
1960x00, 0x05, 0x1b, 0x06, 0x12, 0x72, 0x01, 0x08, 0x01, 0x76, 1960x00, 0x28, 0x57, 0x00, 0x01, 0x70, 0x00, 0x05, 0x1b, 0x06,
1970x06, 0x80, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x29, 1970x12, 0x72, 0x01, 0x08, 0x01, 0x76, 0x06, 0x80, 0x63, 0x6f,
1980x90, 0x0a, 0x06, 0x33, 0x03, 0x07, 0xdc, 0x07, 0x34, 0x65, 1980x75, 0x6e, 0x74, 0x65, 0x72, 0x29, 0x90, 0x0a, 0x06, 0x33,
1990x6e, 0x64, 0x69, 0x04, 0x01, 0x54, 0x07, 0x05, 0xf6, 0x04, 1990x03, 0x07, 0xdc, 0x07, 0x34, 0x65, 0x6e, 0x64, 0x69, 0x04,
2000x31, 0x77, 0x68, 0x65, 0x05, 0x01, 0x21, 0x6f, 0x72, 0x55, 2000x01, 0x54, 0x07, 0x05, 0xf6, 0x04, 0x31, 0x77, 0x68, 0x65,
2010x00, 0x02, 0x71, 0x00, 0x12, 0x64, 0xf8, 0x05, 0x00, 0xa6, 2010x05, 0x01, 0x21, 0x6f, 0x72, 0x55, 0x00, 0x02, 0x71, 0x00,
2020x01, 0x41, 0x74, 0x00, 0x6d, 0x61, 0xa6, 0x06, 0x00, 0xea, 2020x12, 0x64, 0xf8, 0x05, 0x00, 0xa6, 0x01, 0x41, 0x74, 0x00,
2030x03, 0x01, 0x41, 0x06, 0x01, 0xbf, 0x09, 0x14, 0x28, 0x3a, 2030x6d, 0x61, 0xa6, 0x06, 0x00, 0xea, 0x03, 0x01, 0x41, 0x06,
2040x07, 0x10, 0x65, 0xb4, 0x03, 0x41, 0x00, 0x77, 0x61, 0x6e, 2040x01, 0xbf, 0x09, 0x14, 0x28, 0x3a, 0x07, 0x10, 0x65, 0xb4,
2050x6b, 0x00, 0x05, 0x49, 0x05, 0x80, 0x66, 0x75, 0x6c, 0x6c, 2050x03, 0x41, 0x00, 0x77, 0x61, 0x6e, 0x6b, 0x00, 0x05, 0x49,
2060x00, 0x6c, 0x61, 0x79, 0x41, 0x00, 0x04, 0x78, 0x00, 0x34, 2060x05, 0x80, 0x66, 0x75, 0x6c, 0x6c, 0x00, 0x6c, 0x61, 0x79,
2070x72, 0x69, 0x64, 0x5c, 0x01, 0x0f, 0x79, 0x01, 0x02, 0x02, 2070x41, 0x00, 0x04, 0x78, 0x00, 0x34, 0x72, 0x69, 0x64, 0x5c,
2080xdb, 0x00, 0x10, 0x73, 0x5f, 0x0a, 0x01, 0x16, 0x04, 0x44, 2080x01, 0x0f, 0x79, 0x01, 0x02, 0x02, 0xdb, 0x00, 0x10, 0x73,
2090x66, 0x74, 0x65, 0x72, 0x02, 0x01, 0x06, 0x70, 0x05, 0x03, 2090x5f, 0x0a, 0x01, 0x16, 0x04, 0x44, 0x66, 0x74, 0x65, 0x72,
2100x0a, 0x09, 0x04, 0xc0, 0x03, 0x30, 0x53, 0x6f, 0x6c, 0x2f, 2100x02, 0x01, 0x06, 0x70, 0x05, 0x03, 0x0a, 0x09, 0x04, 0xc0,
2110x06, 0x60, 0x65, 0x6e, 0x75, 0x00, 0x6f, 0x70, 0x47, 0x00, 2110x03, 0x30, 0x53, 0x6f, 0x6c, 0x2f, 0x06, 0x60, 0x65, 0x6e,
2120x22, 0x2e, 0x29, 0x54, 0x08, 0x13, 0x32, 0x54, 0x08, 0x93, 2120x75, 0x00, 0x6f, 0x70, 0x47, 0x00, 0x22, 0x2e, 0x29, 0x54,
2130x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 2130x08, 0x13, 0x32, 0x54, 0x08, 0x93, 0x70, 0x61, 0x72, 0x61,
2140x08, 0x13, 0x65, 0x28, 0x00, 0x07, 0x92, 0x02, 0x51, 0x00, 2140x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x08, 0x13, 0x65, 0x28,
2150x66, 0x72, 0x6f, 0x6d, 0x4e, 0x00, 0xb3, 0x60, 0x43, 0x75, 2150x00, 0x07, 0x92, 0x02, 0x51, 0x00, 0x66, 0x72, 0x6f, 0x6d,
2160x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x27, 0x00, 2160x4e, 0x00, 0xb3, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d,
2170x00, 0x6e, 0x02, 0x01, 0x1a, 0x00, 0x52, 0x54, 0x79, 0x70, 2170x2e, 0x2e, 0x2e, 0x27, 0x27, 0x00, 0x00, 0x6e, 0x02, 0x01,
2180x65, 0x27, 0x69, 0x00, 0xf2, 0x00, 0x61, 0x72, 0x65, 0x3a, 2180x1a, 0x00, 0x52, 0x54, 0x79, 0x70, 0x65, 0x27, 0x69, 0x00,
2190x00, 0x00, 0x00, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 2190xf2, 0x00, 0x61, 0x72, 0x65, 0x3a, 0x00, 0x00, 0x00, 0x57,
2200x48, 0x5c, 0x05, 0x51, 0x00, 0x00, 0x53, 0x69, 0x7a, 0x0b, 2200x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x5c, 0x05, 0x51,
2210x0c, 0x01, 0x2c, 0x0c, 0x28, 0x69, 0x6e, 0xee, 0x0a, 0x11, 2210x00, 0x00, 0x53, 0x69, 0x7a, 0x0b, 0x0c, 0x01, 0x2c, 0x0c,
2220x4d, 0x98, 0x05, 0x35, 0x00, 0x00, 0x4e, 0xe0, 0x01, 0x09, 2220x28, 0x69, 0x6e, 0xee, 0x0a, 0x11, 0x4d, 0x98, 0x05, 0x35,
2230xaa, 0x05, 0x00, 0x32, 0x00, 0x06, 0x5c, 0x02, 0x10, 0x65, 2230x00, 0x00, 0x4e, 0xe0, 0x01, 0x09, 0xaa, 0x05, 0x00, 0x32,
2240xcb, 0x01, 0x02, 0x54, 0x06, 0x02, 0x91, 0x0a, 0x73, 0x61, 2240x00, 0x06, 0x5c, 0x02, 0x10, 0x65, 0xcb, 0x01, 0x02, 0x54,
2250x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0xce, 0x02, 0x01, 0xec, 2250x06, 0x02, 0x91, 0x0a, 0x73, 0x61, 0x62, 0x73, 0x6f, 0x6c,
2260x01, 0x10, 0x2c, 0xb1, 0x01, 0xd5, 0x61, 0x6c, 0x74, 0x65, 2260x75, 0x74, 0xce, 0x02, 0x01, 0xec, 0x01, 0x10, 0x2c, 0xb1,
2270x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x6c, 0x79, 0x21, 2270x01, 0xd5, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74,
2280x01, 0xb5, 0x70, 0x75, 0x74, 0x00, 0x61, 0x00, 0x25, 0x00, 2280x69, 0x76, 0x65, 0x6c, 0x79, 0x21, 0x01, 0xb5, 0x70, 0x75,
2290x73, 0x69, 0x67, 0xbe, 0x00, 0x12, 0x65, 0x83, 0x04, 0x03, 2290x74, 0x00, 0x61, 0x00, 0x25, 0x00, 0x73, 0x69, 0x67, 0xbe,
2300xa5, 0x0c, 0x36, 0x61, 0x73, 0x65, 0x0a, 0x02, 0x02, 0x5f, 2300x00, 0x12, 0x65, 0x83, 0x04, 0x03, 0xa5, 0x0c, 0x36, 0x61,
2310x0a, 0x52, 0x72, 0x72, 0x61, 0x6e, 0x67, 0x92, 0x05, 0x01, 2310x73, 0x65, 0x0a, 0x02, 0x02, 0x5f, 0x0a, 0x52, 0x72, 0x72,
2320x51, 0x02, 0x00, 0xfc, 0x0a, 0x24, 0x6f, 0x72, 0x0b, 0x07, 2320x61, 0x6e, 0x67, 0x92, 0x05, 0x01, 0x51, 0x02, 0x00, 0xfc,
2330x06, 0xd4, 0x07, 0x09, 0xb3, 0x00, 0x03, 0x64, 0x05, 0x03, 2330x0a, 0x24, 0x6f, 0x72, 0x0b, 0x07, 0x06, 0xd4, 0x07, 0x09,
2340xe0, 0x05, 0x71, 0x00, 0x00, 0x42, 0x65, 0x77, 0x61, 0x72, 2340xb3, 0x00, 0x03, 0x64, 0x05, 0x03, 0xe0, 0x05, 0x71, 0x00,
2350x03, 0x01, 0x44, 0x73, 0x65, 0x74, 0x74, 0xa1, 0x04, 0x06, 2350x00, 0x42, 0x65, 0x77, 0x61, 0x72, 0x03, 0x01, 0x44, 0x73,
2360xb5, 0x00, 0xe1, 0x00, 0x74, 0x6f, 0x6f, 0x00, 0x68, 0x69, 2360x65, 0x74, 0x74, 0xa1, 0x04, 0x06, 0xb5, 0x00, 0xe1, 0x00,
2370x67, 0x68, 0x2e, 0x00, 0x41, 0x74, 0x00, 0xeb, 0x0c, 0x00, 2370x74, 0x6f, 0x6f, 0x00, 0x68, 0x69, 0x67, 0x68, 0x2e, 0x00,
2380x0e, 0x00, 0x40, 0x00, 0x64, 0x65, 0x6e, 0x3a, 0x0b, 0x2a, 2380x41, 0x74, 0x00, 0xeb, 0x0c, 0x00, 0x0e, 0x00, 0x40, 0x00,
2390x65, 0x73, 0xd1, 0x03, 0x60, 0x6d, 0x61, 0x79, 0x00, 0x73, 2390x64, 0x65, 0x6e, 0x3a, 0x0b, 0x2a, 0x65, 0x73, 0xd1, 0x03,
2400x70, 0xbb, 0x00, 0x31, 0x66, 0x6f, 0x72, 0x2e, 0x0b, 0x64, 2400x60, 0x6d, 0x61, 0x79, 0x00, 0x73, 0x70, 0xbb, 0x00, 0x31,
2410x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x0a, 0x61, 0x61, 2410x66, 0x6f, 0x72, 0x2e, 0x0b, 0x64, 0x73, 0x65, 0x61, 0x72,
2420x00, 0x73, 0x6f, 0x6c, 0x76, 0xc1, 0x01, 0x02, 0x41, 0x01, 2420x63, 0x68, 0x50, 0x0a, 0x61, 0x61, 0x00, 0x73, 0x6f, 0x6c,
2430x31, 0x00, 0x00, 0x45, 0x65, 0x0b, 0x10, 0x20, 0x2f, 0x01, 2430x76, 0xc1, 0x01, 0x02, 0x41, 0x01, 0x31, 0x00, 0x00, 0x45,
2440x60, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0xa7, 0x01, 0x00, 2440x65, 0x0b, 0x10, 0x20, 0x2f, 0x01, 0x60, 0x62, 0x69, 0x6c,
2450x0f, 0x03, 0x01, 0x4e, 0x01, 0x03, 0xd2, 0x01, 0x50, 0x69, 2450x69, 0x74, 0x79, 0xa7, 0x01, 0x00, 0x0f, 0x03, 0x01, 0x4e,
2460x73, 0x00, 0x65, 0x6e, 0x37, 0x00, 0x00, 0x57, 0x03, 0x13, 2460x01, 0x03, 0xd2, 0x01, 0x50, 0x69, 0x73, 0x00, 0x65, 0x6e,
2470x73, 0x07, 0x07, 0x15, 0x62, 0xe3, 0x0b, 0x23, 0x29, 0x2c, 2470x37, 0x00, 0x00, 0x57, 0x03, 0x13, 0x73, 0x07, 0x07, 0x15,
2480xaf, 0x01, 0x01, 0x1a, 0x01, 0x08, 0xb7, 0x0b, 0x02, 0x4a, 2480x62, 0xe3, 0x0b, 0x23, 0x29, 0x2c, 0xaf, 0x01, 0x01, 0x1a,
2490x01, 0x33, 0x74, 0x69, 0x72, 0xff, 0x00, 0x00, 0x6e, 0x01, 2490x01, 0x08, 0xb7, 0x0b, 0x02, 0x4a, 0x01, 0x33, 0x74, 0x69,
2500x12, 0x62, 0xec, 0x02, 0x13, 0x79, 0x90, 0x0b, 0x61, 0x64, 2500x72, 0xff, 0x00, 0x00, 0x6e, 0x01, 0x12, 0x62, 0xec, 0x02,
2510x00, 0x73, 0x74, 0x61, 0x72, 0xfc, 0x00, 0x05, 0x55, 0x02, 2510x13, 0x79, 0x90, 0x0b, 0x61, 0x64, 0x00, 0x73, 0x74, 0x61,
2520x63, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x9a, 0x06, 0x01, 2520x72, 0xfc, 0x00, 0x05, 0x55, 0x02, 0x63, 0x69, 0x6e, 0x69,
2530xaf, 0x05, 0x05, 0xd0, 0x04, 0x63, 0x70, 0x72, 0x65, 0x66, 2530x74, 0x69, 0x61, 0x9a, 0x06, 0x01, 0xaf, 0x05, 0x05, 0xd0,
2540x65, 0x72, 0x7d, 0x05, 0x51, 0x73, 0x6b, 0x69, 0x65, 0x72, 2540x04, 0x63, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x7d, 0x05,
2550x5a, 0x00, 0x15, 0x73, 0x5e, 0x0c, 0x01, 0xfc, 0x0c, 0x0f, 2550x51, 0x73, 0x6b, 0x69, 0x65, 0x72, 0x5a, 0x00, 0x15, 0x73,
2560xa7, 0x04, 0x04, 0x04, 0xf1, 0x01, 0x41, 0x73, 0x77, 0x69, 2560x5e, 0x0c, 0x01, 0xfc, 0x0c, 0x0f, 0xa7, 0x04, 0x04, 0x04,
2570x74, 0x48, 0x08, 0x15, 0x66, 0xe7, 0x00, 0x50, 0x69, 0x6f, 2570xf1, 0x01, 0x41, 0x73, 0x77, 0x69, 0x74, 0x48, 0x08, 0x15,
2580x6e, 0x2e, 0x00, 2580x66, 0xe7, 0x00, 0x50, 0x69, 0x6f, 0x6e, 0x2e, 0x00,
259}; 259};
260 260
261const unsigned short help_text_len = 3796; 261const unsigned short help_text_len = 3814;
262const unsigned short help_text_words = 731; 262const unsigned short help_text_words = 732;
263const char quick_help_text[] = "Find all the mines without treading on any of them."; 263const char quick_help_text[] = "Find all the mines without treading on any of them.";
diff --git a/apps/plugins/puzzles/help/mosaic.c b/apps/plugins/puzzles/help/mosaic.c
new file mode 100644
index 0000000000..835de1898d
--- /dev/null
+++ b/apps/plugins/puzzles/help/mosaic.c
@@ -0,0 +1,150 @@
1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */
4
5#include "lib/display_text.h"
6
7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED },
9 { 43, TEXT_UNDERLINE },
10 { 105, TEXT_CENTER | C_RED },
11 { 223, TEXT_CENTER | C_RED },
12 { 240, TEXT_UNDERLINE },
13 { 241, TEXT_UNDERLINE },
14 { 251, TEXT_UNDERLINE },
15 LAST_STYLE_ITEM
16};
17
18/* orig 1673 comp 1259 ratio 0.75254 level 10 saved 414 */
19const char help_text[] = {
200xfd, 0x06, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
210x34, 0x32, 0x3a, 0x20, 0x4d, 0x6f, 0x73, 0x61, 0x69, 0x63,
220x20, 0x00, 0x2d, 0x01, 0x00, 0xf0, 0x3a, 0x00, 0x00, 0x00,
230x59, 0x6f, 0x75, 0x00, 0x61, 0x72, 0x65, 0x00, 0x67, 0x69,
240x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64,
250x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65,
260x73, 0x2c, 0x00, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x79,
270x6f, 0x75, 0x00, 0x6d, 0x75, 0x73, 0x74, 0x00, 0x63, 0x6f,
280x6c, 0x6f, 0x75, 0x72, 0x00, 0x65, 0x69, 0x74, 0x68, 0x65,
290x72, 0x00, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x00, 0x6f, 0x72,
300x26, 0x00, 0xa4, 0x74, 0x65, 0x2e, 0x00, 0x00, 0x00, 0x53,
310x6f, 0x6d, 0x65, 0x3d, 0x00, 0xf2, 0x0c, 0x00, 0x63, 0x6f,
320x6e, 0x74, 0x61, 0x69, 0x6e, 0x00, 0x63, 0x6c, 0x75, 0x65,
330x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2e, 0x00,
340x45, 0x61, 0x63, 0x68, 0x13, 0x00, 0x51, 0x74, 0x65, 0x6c,
350x6c, 0x73, 0x5c, 0x00, 0x24, 0x74, 0x68, 0x21, 0x00, 0x00,
360x7d, 0x00, 0x02, 0x57, 0x00, 0x04, 0x46, 0x00, 0x21, 0x69,
370x6e, 0x1f, 0x00, 0xf1, 0x07, 0x33, 0x2a, 0x33, 0x00, 0x72,
380x65, 0x67, 0x69, 0x6f, 0x6e, 0x00, 0x73, 0x75, 0x72, 0x72,
390x6f, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x1b, 0x00, 0x01,
400x4d, 0x00, 0x7a, 0x2d, 0x00, 0x69, 0x6e, 0x63, 0x6c, 0x75,
410x15, 0x00, 0x02, 0x44, 0x00, 0x70, 0x00, 0x69, 0x74, 0x73,
420x65, 0x6c, 0x66, 0xa0, 0x00, 0xf0, 0x0d, 0x54, 0x68, 0x69,
430x73, 0x00, 0x67, 0x61, 0x6d, 0x65, 0x00, 0x69, 0x73, 0x00,
440x76, 0x61, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x6c, 0x79, 0x00,
450x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x6a, 0x00, 0x11, 0x6f, 0xd8,
460x00, 0xf2, 0x02, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
470x6e, 0x73, 0x00, 0x61, 0x73, 0x3a, 0x00, 0x41, 0x72, 0x74,
480x44, 0x01, 0xf0, 0x0e, 0x6f, 0x2c, 0x00, 0x43, 0x6f, 0x75,
490x6e, 0x74, 0x00, 0x61, 0x6e, 0x64, 0x00, 0x44, 0x61, 0x72,
500x6b, 0x65, 0x6e, 0x2c, 0x00, 0x43, 0x75, 0x65, 0x6e, 0x74,
510x61, 0x00, 0x59, 0xfb, 0x00, 0xf3, 0x01, 0x62, 0x72, 0x65,
520x61, 0x2c, 0x00, 0x46, 0x69, 0x6c, 0x6c, 0x2d, 0x61, 0x2d,
530x50, 0x69, 0x78, 0x0c, 0x00, 0xf0, 0x0a, 0x49, 0x6e, 0x2c,
540x00, 0x4b, 0x6f, 0x6d, 0x73, 0x75, 0x00, 0x4b, 0x61, 0x72,
550x61, 0x6c, 0x61, 0x2c, 0x00, 0x4d, 0x61, 0x67, 0x69, 0x70,
560x69, 0x63, 0x09, 0x00, 0x85, 0x6a, 0x69, 0x70, 0x69, 0x6b,
570x75, 0x2c, 0x00, 0x63, 0x00, 0x01, 0x09, 0x00, 0x10, 0x6b,
580x08, 0x00, 0xf4, 0x0d, 0x7a, 0x61, 0x69, 0x65, 0x6b, 0x2c,
590x00, 0x4e, 0x61, 0x6d, 0x70, 0x72, 0x65, 0x00, 0x50, 0x75,
600x7a, 0x7a, 0x6c, 0x65, 0x2c, 0x00, 0x4e, 0x75, 0x72, 0x69,
610x65, 0x2d, 0x0e, 0x00, 0x62, 0x4f, 0x65, 0x6b, 0x61, 0x6b,
620x69, 0x6d, 0x00, 0x81, 0x56, 0x6f, 0x69, 0x73, 0x69, 0x6d,
630x61, 0x67, 0x8a, 0x01, 0x02, 0x50, 0x00, 0x32, 0x00, 0x77,
640x61, 0x88, 0x01, 0xe0, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
650x64, 0x00, 0x74, 0x6f, 0x00, 0x74, 0x68, 0x69, 0x14, 0x00,
660x50, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x4f, 0x01, 0xf2, 0x01,
670x62, 0x79, 0x00, 0x44, 0x69, 0x64, 0x69, 0x00, 0x4b, 0x6f,
680x68, 0x65, 0x6e, 0x2e, 0x00, 0x43, 0xe3, 0x01, 0x51, 0x64,
690x65, 0x73, 0x69, 0x67, 0x1d, 0x00, 0xf0, 0x0a, 0x4d, 0x69,
700x63, 0x68, 0x61, 0x6c, 0x00, 0x53, 0x68, 0x6f, 0x6d, 0x65,
710x72, 0x2e, 0x00, 0x54, 0x68, 0x65, 0x00, 0x69, 0x6d, 0x70,
720x6c, 0x65, 0x6d, 0xf9, 0x00, 0x01, 0x42, 0x00, 0xf2, 0x1b,
730x69, 0x73, 0x00, 0x6c, 0x6f, 0x6f, 0x73, 0x65, 0x6c, 0x79,
740x00, 0x62, 0x61, 0x73, 0x65, 0x64, 0x00, 0x6f, 0x6e, 0x00,
750x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
760x2f, 0x6d, 0x6f, 0x72, 0x64, 0x65, 0x63, 0x68, 0x61, 0x69,
770x6d, 0x2f, 0x96, 0x00, 0x00, 0xa0, 0x00, 0x44, 0x34, 0x32,
780x2e, 0x31, 0x9c, 0x02, 0x01, 0xa1, 0x00, 0x40, 0x6f, 0x6c,
790x73, 0x20, 0xa2, 0x01, 0x63, 0x6f, 0x00, 0x70, 0x6c, 0x61,
800x79, 0xc0, 0x00, 0x71, 0x2c, 0x00, 0x63, 0x6c, 0x69, 0x63,
810x6b, 0xd2, 0x01, 0x50, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0xa5,
820x01, 0x14, 0x61, 0xd8, 0x01, 0x81, 0x74, 0x6f, 0x00, 0x63,
830x68, 0x61, 0x6e, 0x67, 0xe2, 0x01, 0x03, 0x9c, 0x02, 0x71,
840x2e, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x37, 0x00, 0x00,
850x0c, 0x02, 0x84, 0x61, 0x6e, 0x00, 0x65, 0x6d, 0x70, 0x74,
860x79, 0x34, 0x00, 0xc2, 0x77, 0x69, 0x6c, 0x6c, 0x00, 0x74,
870x75, 0x72, 0x6e, 0x00, 0x69, 0x74, 0x6a, 0x02, 0x11, 0x2c,
880xd0, 0x01, 0x47, 0x72, 0x69, 0x67, 0x68, 0x37, 0x00, 0x09,
890x27, 0x00, 0x03, 0xdf, 0x02, 0x42, 0x4b, 0x65, 0x65, 0x70,
900x90, 0x00, 0x04, 0x65, 0x02, 0x10, 0x73, 0x4a, 0x02, 0x61,
910x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x8d, 0x00, 0xc1, 0x79,
920x63, 0x6c, 0x65, 0x00, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67,
930x68, 0x21, 0x00, 0xf2, 0x0a, 0x74, 0x68, 0x72, 0x65, 0x65,
940x00, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x00,
950x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x00, 0x66, 0x6f, 0x72,
960x3f, 0x00, 0x01, 0x93, 0x00, 0x00, 0x0e, 0x01, 0x21, 0x49,
970x66, 0x08, 0x03, 0x60, 0x68, 0x6f, 0x6c, 0x64, 0x00, 0x64,
980x8c, 0x02, 0x06, 0xf1, 0x00, 0x03, 0x5f, 0x00, 0x00, 0xa4,
990x00, 0x51, 0x64, 0x72, 0x61, 0x67, 0x2c, 0x29, 0x00, 0x34,
1000x63, 0x61, 0x6e, 0x8c, 0x03, 0xa1, 0x6d, 0x75, 0x6c, 0x74,
1010x69, 0x70, 0x6c, 0x65, 0x00, 0x63, 0x4f, 0x03, 0x02, 0x20,
1020x01, 0x71, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x00, 0x61, 0xe1,
1030x01, 0x13, 0x2e, 0xe8, 0x03, 0x00, 0x34, 0x00, 0x50, 0x61,
1040x6c, 0x73, 0x6f, 0x00, 0x56, 0x00, 0x01, 0x23, 0x03, 0xa0,
1050x75, 0x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x73,
1060xbe, 0x00, 0x61, 0x6d, 0x6f, 0x76, 0x65, 0x00, 0x61, 0x5a,
1070x03, 0x01, 0x1f, 0x00, 0x00, 0x0c, 0x04, 0x74, 0x2e, 0x00,
1080x50, 0x72, 0x65, 0x73, 0x73, 0xf0, 0x00, 0x21, 0x72, 0x65,
1090x13, 0x01, 0x82, 0x6f, 0x72, 0x00, 0x73, 0x70, 0x61, 0x63,
1100x65, 0x3b, 0x00, 0x06, 0x2b, 0x01, 0x0c, 0x6c, 0x01, 0x0a,
1110x20, 0x04, 0x50, 0x00, 0x72, 0x65, 0x73, 0x70, 0x74, 0x02,
1120x10, 0x76, 0x29, 0x02, 0x22, 0x28, 0x61, 0x67, 0x00, 0x15,
1130x6e, 0x36, 0x01, 0x13, 0x65, 0xd2, 0x00, 0x05, 0xf3, 0x03,
1140x01, 0x5e, 0x01, 0x6d, 0x77, 0x61, 0x79, 0x00, 0x61, 0x73,
1150x10, 0x01, 0x22, 0x73, 0x29, 0xb7, 0x01, 0x14, 0x70, 0x9f,
1160x00, 0x42, 0x42, 0x61, 0x63, 0x6b, 0x95, 0x00, 0x01, 0x90,
1170x00, 0x59, 0x72, 0x65, 0x73, 0x65, 0x74, 0x2a, 0x02, 0x01,
1180x9a, 0x00, 0x03, 0x7a, 0x02, 0x14, 0x32, 0x7a, 0x02, 0x92,
1190x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x7c,
1200x02, 0x56, 0x68, 0x65, 0x73, 0x65, 0x00, 0x14, 0x00, 0x01,
1210x1b, 0x05, 0x60, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0xbe,
1220x01, 0x41, 0x66, 0x72, 0x6f, 0x6d, 0x89, 0x00, 0xe1, 0x60,
1230x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27,
1240x00, 0x6f, 0x70, 0x03, 0x03, 0x22, 0x6f, 0x6e, 0x1a, 0x00,
1250xa0, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e,
1260x75, 0x6b, 0x00, 0x90, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c,
1270x00, 0x48, 0x65, 0x5d, 0x02, 0x00, 0x1f, 0x05, 0x30, 0x69,
1280x7a, 0x65, 0xe2, 0x04, 0x01, 0x67, 0x05, 0x24, 0x69, 0x6e,
1290xe4, 0x04, 0x00, 0x2b, 0x00, 0x31, 0x41, 0x67, 0x67, 0xcb,
1300x00, 0x82, 0x76, 0x65, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72,
1310x5a, 0x03, 0x00, 0x43, 0x00, 0x22, 0x74, 0x68, 0xb3, 0x03,
1320x03, 0x6a, 0x00, 0x42, 0x73, 0x65, 0x74, 0x2c, 0xa0, 0x01,
1330x00, 0x1f, 0x01, 0x03, 0x2c, 0x00, 0x23, 0x6f, 0x72, 0x87,
1340x01, 0x91, 0x72, 0x79, 0x00, 0x68, 0x61, 0x72, 0x64, 0x65,
1350x72, 0xf3, 0x00, 0xf1, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x6e,
1360x61, 0x74, 0x65, 0x00, 0x75, 0x6e, 0x6e, 0x65, 0x63, 0x65,
1370x73, 0x73, 0x61, 0x72, 0x79, 0x1a, 0x05, 0x14, 0x73, 0xb1,
1380x00, 0x62, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x2e, 0x18, 0x05,
1390x52, 0x73, 0x6c, 0x6f, 0x77, 0x73, 0x7f, 0x02, 0x06, 0x83,
1400x00, 0xf1, 0x0a, 0x2c, 0x00, 0x73, 0x6f, 0x00, 0x69, 0x74,
1410x27, 0x73, 0x00, 0x6e, 0x6f, 0x74, 0x00, 0x72, 0x65, 0x63,
1420x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x65, 0x64, 0xc6, 0x02,
1430x01, 0x3f, 0x00, 0x70, 0x73, 0x00, 0x6c, 0x61, 0x72, 0x67,
1440x65, 0xd4, 0x02, 0x10, 0x61, 0x30, 0x00, 0xb0, 0x61, 0x79,
1450x2c, 0x00, 0x33, 0x30, 0x2a, 0x33, 0x30, 0x2e, 0x00,
146};
147
148const unsigned short help_text_len = 1673;
149const unsigned short help_text_words = 285;
150const char quick_help_text[] = "Fill in the grid given clues about number of nearby black squares.";
diff --git a/apps/plugins/puzzles/help/net.c b/apps/plugins/puzzles/help/net.c
index b0224838cf..9b42b5eca3 100644
--- a/apps/plugins/puzzles/help/net.c
+++ b/apps/plugins/puzzles/help/net.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,268 +6,295 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 3, TEXT_UNDERLINE }, 9 { 4, TEXT_UNDERLINE },
10 { 120, TEXT_CENTER | C_RED }, 10 { 121, TEXT_CENTER | C_RED },
11 { 140, TEXT_UNDERLINE }, 11 { 141, TEXT_UNDERLINE },
12 { 147, TEXT_UNDERLINE }, 12 { 148, TEXT_UNDERLINE },
13 { 155, TEXT_UNDERLINE }, 13 { 156, TEXT_UNDERLINE },
14 { 163, TEXT_UNDERLINE }, 14 { 164, TEXT_UNDERLINE },
15 { 168, TEXT_UNDERLINE }, 15 { 169, TEXT_UNDERLINE },
16 { 221, TEXT_UNDERLINE }, 16 { 222, TEXT_UNDERLINE },
17 { 257, TEXT_UNDERLINE }, 17 { 258, TEXT_UNDERLINE },
18 { 313, TEXT_UNDERLINE }, 18 { 314, TEXT_UNDERLINE },
19 { 344, TEXT_CENTER | C_RED }, 19 { 345, TEXT_CENTER | C_RED },
20 { 361, TEXT_UNDERLINE },
21 { 362, TEXT_UNDERLINE }, 20 { 362, TEXT_UNDERLINE },
22 { 372, TEXT_UNDERLINE }, 21 { 363, TEXT_UNDERLINE },
23 { 398, TEXT_UNDERLINE }, 22 { 373, TEXT_UNDERLINE },
24 { 485, TEXT_UNDERLINE }, 23 { 399, TEXT_UNDERLINE },
25 { 553, TEXT_UNDERLINE }, 24 { 486, TEXT_UNDERLINE },
26 { 598, TEXT_UNDERLINE }, 25 { 554, TEXT_UNDERLINE },
26 { 599, TEXT_UNDERLINE },
27 { 614, TEXT_CENTER | C_RED },
27 LAST_STYLE_ITEM 28 LAST_STYLE_ITEM
28}; 29};
29 30
30/* orig 3439 comp 2361 ratio 0.686537 level 10 saved 1078 */ 31/* orig 3919 comp 2622 ratio 0.669048 level 10 saved 1297 */
31const char help_text[] = { 32const char help_text[] = {
320xf4, 0x57, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 330xf9, 0x02, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
330x33, 0x3a, 0x20, 0x4e, 0x65, 0x74, 0x20, 0x00, 0x00, 0x00, 340x33, 0x3a, 0x20, 0x4e, 0x65, 0x74, 0x20, 0x00, 0x2d, 0x01,
340x28, 0x4e, 0x6f, 0x74, 0x65, 0x3a, 0x00, 0x74, 0x68, 0x65, 350x00, 0xf4, 0x48, 0x00, 0x00, 0x00, 0x28, 0x4e, 0x6f, 0x74,
350x00, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x00, 0x76, 360x65, 0x3a, 0x00, 0x74, 0x68, 0x65, 0x00, 0x57, 0x69, 0x6e,
360x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x6f, 0x66, 0x00, 370x64, 0x6f, 0x77, 0x73, 0x00, 0x76, 0x65, 0x72, 0x73, 0x69,
370x74, 0x68, 0x69, 0x73, 0x00, 0x67, 0x61, 0x6d, 0x65, 0x00, 380x6f, 0x6e, 0x00, 0x6f, 0x66, 0x00, 0x74, 0x68, 0x69, 0x73,
380x69, 0x73, 0x00, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x00, 390x00, 0x67, 0x61, 0x6d, 0x65, 0x00, 0x69, 0x73, 0x00, 0x63,
390x4e, 0x45, 0x54, 0x47, 0x41, 0x4d, 0x45, 0x2e, 0x45, 0x58, 400x61, 0x6c, 0x6c, 0x65, 0x64, 0x00, 0x4e, 0x45, 0x54, 0x47,
400x45, 0x00, 0x74, 0x6f, 0x00, 0x61, 0x76, 0x6f, 0x69, 0x64, 410x41, 0x4d, 0x45, 0x2e, 0x45, 0x58, 0x45, 0x00, 0x74, 0x6f,
410x00, 0x63, 0x6c, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x00, 420x00, 0x61, 0x76, 0x6f, 0x69, 0x64, 0x00, 0x63, 0x6c, 0x61,
420x77, 0x69, 0x74, 0x68, 0x4a, 0x00, 0x60, 0x27, 0x73, 0x00, 430x73, 0x68, 0x69, 0x6e, 0x67, 0x00, 0x77, 0x69, 0x74, 0x68,
430x6f, 0x77, 0x6e, 0x31, 0x00, 0x00, 0x2d, 0x00, 0xf2, 0x06, 440x4a, 0x00, 0x60, 0x27, 0x73, 0x00, 0x6f, 0x77, 0x6e, 0x31,
440x2e, 0x29, 0x00, 0x00, 0x00, 0x49, 0x00, 0x6f, 0x72, 0x69, 450x00, 0x00, 0x2d, 0x00, 0xf2, 0x06, 0x2e, 0x29, 0x00, 0x00,
450x67, 0x69, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0x00, 0x73, 0x61, 460x00, 0x49, 0x00, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61,
460x77, 0x62, 0x00, 0x21, 0x69, 0x6e, 0x81, 0x00, 0x40, 0x66, 470x6c, 0x6c, 0x79, 0x00, 0x73, 0x61, 0x77, 0x62, 0x00, 0x21,
470x6f, 0x72, 0x6d, 0x76, 0x00, 0x30, 0x61, 0x00, 0x46, 0x4f, 480x69, 0x6e, 0x81, 0x00, 0x40, 0x66, 0x6f, 0x72, 0x6d, 0x76,
480x00, 0x02, 0x79, 0x00, 0x03, 0x76, 0x00, 0xf0, 0x18, 0x46, 490x00, 0x30, 0x61, 0x00, 0x46, 0x4f, 0x00, 0x02, 0x79, 0x00,
490x72, 0x65, 0x65, 0x4e, 0x65, 0x74, 0x00, 0x5b, 0x31, 0x5d, 500x03, 0x76, 0x00, 0xf0, 0x18, 0x46, 0x72, 0x65, 0x65, 0x4e,
500x2c, 0x00, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x00, 510x65, 0x74, 0x00, 0x5b, 0x31, 0x5d, 0x2c, 0x00, 0x77, 0x72,
510x62, 0x79, 0x00, 0x50, 0x61, 0x76, 0x69, 0x6c, 0x73, 0x00, 520x69, 0x74, 0x74, 0x65, 0x6e, 0x00, 0x62, 0x79, 0x00, 0x50,
520x4a, 0x75, 0x72, 0x6a, 0x61, 0x6e, 0x73, 0x3b, 0x48, 0x00, 530x61, 0x76, 0x69, 0x6c, 0x73, 0x00, 0x4a, 0x75, 0x72, 0x6a,
530xf0, 0x01, 0x72, 0x65, 0x00, 0x61, 0x72, 0x65, 0x00, 0x73, 540x61, 0x6e, 0x73, 0x3b, 0x48, 0x00, 0xf0, 0x01, 0x72, 0x65,
540x65, 0x76, 0x65, 0x72, 0x61, 0x6c, 0x00, 0x6f, 0x13, 0x00, 550x00, 0x61, 0x72, 0x65, 0x00, 0x73, 0x65, 0x76, 0x65, 0x72,
550xf1, 0x07, 0x00, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 560x61, 0x6c, 0x00, 0x6f, 0x13, 0x00, 0xf1, 0x07, 0x00, 0x69,
560x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x75, 570x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74,
570x6e, 0x64, 0x65, 0x72, 0x76, 0x00, 0x10, 0x6e, 0x66, 0x00, 580x69, 0x6f, 0x6e, 0x73, 0x00, 0x75, 0x6e, 0x64, 0x65, 0x72,
580xf0, 0x19, 0x4e, 0x65, 0x74, 0x57, 0x61, 0x6c, 0x6b, 0x2e, 590x76, 0x00, 0x10, 0x6e, 0x66, 0x00, 0xf0, 0x19, 0x4e, 0x65,
590x00, 0x54, 0x68, 0x65, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x75, 600x74, 0x57, 0x61, 0x6c, 0x6b, 0x2e, 0x00, 0x54, 0x68, 0x65,
600x74, 0x65, 0x72, 0x00, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 610x00, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x00,
610x65, 0x73, 0x00, 0x61, 0x00, 0x6e, 0x65, 0x74, 0x77, 0x6f, 620x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x73, 0x00, 0x61,
620x72, 0x6b, 0x73, 0x00, 0x70, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 630x00, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x00,
630x63, 0x74, 0xee, 0x00, 0x21, 0x75, 0x70, 0x43, 0x00, 0x40, 640x70, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0xee, 0x00,
640x63, 0x65, 0x6e, 0x74, 0x27, 0x00, 0x61, 0x6f, 0x66, 0x00, 650x21, 0x75, 0x70, 0x43, 0x00, 0x40, 0x63, 0x65, 0x6e, 0x74,
650x73, 0x71, 0x75, 0x32, 0x00, 0xe0, 0x69, 0x6e, 0x00, 0x61, 660x27, 0x00, 0x61, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x32,
660x00, 0x67, 0x72, 0x69, 0x64, 0x2c, 0x00, 0x61, 0x6e, 0x64, 670x00, 0xe0, 0x69, 0x6e, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69,
670x26, 0x00, 0xa2, 0x6e, 0x00, 0x73, 0x68, 0x75, 0x66, 0x66, 680x64, 0x2c, 0x00, 0x61, 0x6e, 0x64, 0x26, 0x00, 0xa2, 0x6e,
680x6c, 0x65, 0x73, 0x77, 0x00, 0x06, 0x51, 0x00, 0x41, 0x72, 690x00, 0x73, 0x68, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x73, 0x77,
690x6f, 0x74, 0x61, 0x4f, 0x00, 0x00, 0xb2, 0x00, 0xf0, 0x0a, 700x00, 0x06, 0x51, 0x00, 0x41, 0x72, 0x6f, 0x74, 0x61, 0x4f,
700x79, 0x00, 0x74, 0x69, 0x6c, 0x65, 0x00, 0x72, 0x61, 0x6e, 710x00, 0x00, 0xb2, 0x00, 0xf0, 0x0a, 0x79, 0x00, 0x74, 0x69,
710x64, 0x6f, 0x6d, 0x6c, 0x79, 0x2e, 0x00, 0x59, 0x6f, 0x75, 720x6c, 0x65, 0x00, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x6c,
720x72, 0x00, 0x6a, 0x6f, 0x62, 0x83, 0x01, 0x22, 0x74, 0x6f, 730x79, 0x2e, 0x00, 0x59, 0x6f, 0x75, 0x72, 0x00, 0x6a, 0x6f,
730x2d, 0x00, 0xf2, 0x09, 0x65, 0x00, 0x69, 0x74, 0x00, 0x61, 740x62, 0x83, 0x01, 0x22, 0x74, 0x6f, 0x2d, 0x00, 0xf2, 0x09,
740x6c, 0x6c, 0x00, 0x62, 0x61, 0x63, 0x6b, 0x00, 0x69, 0x6e, 750x65, 0x00, 0x69, 0x74, 0x00, 0x61, 0x6c, 0x6c, 0x00, 0x62,
750x74, 0x6f, 0x00, 0x70, 0x6c, 0x61, 0x63, 0x65, 0xc0, 0x00, 760x61, 0x63, 0x6b, 0x00, 0x69, 0x6e, 0x74, 0x6f, 0x00, 0x70,
760xf0, 0x01, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 770x6c, 0x61, 0x63, 0x65, 0xc0, 0x00, 0xf0, 0x01, 0x73, 0x75,
770x75, 0x6c, 0x00, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0xcd, 0x01, 780x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x00, 0x73,
780x20, 0x77, 0x69, 0x2e, 0x00, 0xc5, 0x65, 0x00, 0x61, 0x6e, 790x6f, 0x6c, 0x75, 0x74, 0xcd, 0x01, 0x20, 0x77, 0x69, 0x2e,
790x00, 0x65, 0x6e, 0x74, 0x69, 0x72, 0x65, 0x6c, 0xc9, 0x00, 800x00, 0xc5, 0x65, 0x00, 0x61, 0x6e, 0x00, 0x65, 0x6e, 0x74,
800x24, 0x65, 0x64, 0x8d, 0x00, 0x12, 0x2c, 0xbf, 0x01, 0xf0, 810x69, 0x72, 0x65, 0x6c, 0xc9, 0x00, 0x24, 0x65, 0x64, 0x8d,
810x03, 0x6e, 0x6f, 0x00, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 820x00, 0x12, 0x2c, 0xbf, 0x01, 0xf0, 0x03, 0x6e, 0x6f, 0x00,
820x00, 0x6c, 0x6f, 0x6f, 0x70, 0x73, 0x2e, 0x00, 0x41, 0x02, 830x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x00, 0x6c, 0x6f, 0x6f,
830x01, 0x81, 0x76, 0x69, 0x73, 0x75, 0x61, 0x6c, 0x00, 0x61, 840x70, 0x73, 0x2e, 0x00, 0x41, 0x02, 0x01, 0x81, 0x76, 0x69,
840xd3, 0x00, 0x21, 0x6c, 0x6c, 0xa7, 0x00, 0x71, 0x73, 0x00, 850x73, 0x75, 0x61, 0x6c, 0x00, 0x61, 0xd3, 0x00, 0x21, 0x6c,
850x77, 0x68, 0x69, 0x63, 0x68, 0x70, 0x01, 0x06, 0x4e, 0x00, 860x6c, 0xa7, 0x00, 0x71, 0x73, 0x00, 0x77, 0x68, 0x69, 0x63,
860x21, 0x74, 0x6f, 0xe2, 0x00, 0x34, 0x6f, 0x6e, 0x65, 0xda, 870x68, 0x70, 0x01, 0x06, 0x4e, 0x00, 0x21, 0x74, 0x6f, 0xe2,
870x01, 0x52, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x97, 0x01, 0xe0, 880x00, 0x34, 0x6f, 0x6e, 0x65, 0xda, 0x01, 0x52, 0x6d, 0x69,
880x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 890x64, 0x64, 0x6c, 0x97, 0x01, 0xe0, 0x68, 0x69, 0x67, 0x68,
890x64, 0x2e, 0x00, 0x00, 0xd0, 0x01, 0xd2, 0x00, 0x68, 0x74, 900x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x2e, 0x00, 0x00,
900x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6a, 910xd0, 0x01, 0xd2, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
910xc8, 0x01, 0xe3, 0x2e, 0x6c, 0x76, 0x2f, 0x73, 0x74, 0x75, 920x2f, 0x77, 0x77, 0x77, 0x2e, 0x6a, 0xc8, 0x01, 0xe3, 0x2e,
920x66, 0x66, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0xfc, 0x01, 0xa1, 930x6c, 0x76, 0x2f, 0x73, 0x74, 0x75, 0x66, 0x66, 0x2f, 0x6e,
930x2e, 0x68, 0x74, 0x6d, 0x00, 0x00, 0x00, 0x33, 0x2e, 0x31, 940x65, 0x74, 0x2f, 0xfc, 0x01, 0xa1, 0x2e, 0x68, 0x74, 0x6d,
940xbd, 0x02, 0x80, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 950x00, 0x00, 0x00, 0x33, 0x2e, 0x31, 0xcc, 0x02, 0xd5, 0x63,
950x73, 0xc6, 0x02, 0x15, 0x54, 0xa8, 0x02, 0x30, 0x63, 0x61, 960x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00,
960x6e, 0xe7, 0x00, 0x62, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x64, 970x00, 0x54, 0xa8, 0x02, 0x30, 0x63, 0x61, 0x6e, 0xe7, 0x00,
970xcf, 0x00, 0x43, 0x65, 0x69, 0x74, 0x68, 0xec, 0x01, 0xb2, 980x62, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x64, 0xcf, 0x00, 0x43,
980x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x00, 0x6f, 990x65, 0x69, 0x74, 0x68, 0xec, 0x01, 0xb2, 0x6b, 0x65, 0x79,
990x72, 0x98, 0x00, 0x33, 0x6f, 0x75, 0x73, 0x35, 0x01, 0x04, 1000x62, 0x6f, 0x61, 0x72, 0x64, 0x00, 0x6f, 0x72, 0x98, 0x00,
1000x4f, 0x00, 0x00, 0xa5, 0x00, 0xb0, 0x3a, 0x00, 0x00, 0x00, 1010x33, 0x6f, 0x75, 0x73, 0x35, 0x01, 0x04, 0x4f, 0x00, 0x00,
1010x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, 0xe6, 0x00, 0x12, 1020xa5, 0x00, 0xb0, 0x3a, 0x00, 0x00, 0x00, 0x53, 0x65, 0x6c,
1020x3a, 0x28, 0x00, 0xf0, 0x00, 0x00, 0x70, 0x6f, 0x69, 0x6e, 1030x65, 0x63, 0x74, 0x20, 0xe6, 0x00, 0x12, 0x3a, 0x28, 0x00,
1030x74, 0x65, 0x72, 0x2c, 0x00, 0x61, 0x72, 0x72, 0x6f, 0x77, 1040xf0, 0x00, 0x00, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72,
1040x4d, 0x00, 0x51, 0x73, 0x00, 0x00, 0x00, 0x52, 0x91, 0x01, 1050x2c, 0x00, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x4d, 0x00, 0x51,
1050x01, 0x29, 0x00, 0xf3, 0x05, 0x20, 0x61, 0x6e, 0x74, 0x69, 1060x73, 0x00, 0x00, 0x00, 0x52, 0x91, 0x01, 0x01, 0x29, 0x00,
1060x63, 0x6c, 0x6f, 0x63, 0x6b, 0x77, 0x69, 0x73, 0x65, 0x3a, 1070xf3, 0x05, 0x20, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x6c, 0x6f,
1070x00, 0x6c, 0x65, 0x66, 0x74, 0x3c, 0x00, 0xb0, 0x62, 0x75, 1080x63, 0x6b, 0x77, 0x69, 0x73, 0x65, 0x3a, 0x00, 0x6c, 0x65,
1080x74, 0x74, 0x6f, 0x6e, 0x2c, 0x00, 0x60, 0x41, 0x27, 0x39, 1090x66, 0x74, 0x3c, 0x00, 0xb0, 0x62, 0x75, 0x74, 0x74, 0x6f,
1090x00, 0x0b, 0x38, 0x00, 0x07, 0x34, 0x00, 0x10, 0x72, 0x1c, 1100x6e, 0x2c, 0x00, 0x60, 0x41, 0x27, 0x39, 0x00, 0x0b, 0x38,
1100x01, 0x0c, 0x35, 0x00, 0x1f, 0x44, 0x35, 0x00, 0x01, 0xf4, 1110x00, 0x07, 0x34, 0x00, 0x10, 0x72, 0x1c, 0x01, 0x0c, 0x35,
1110x03, 0x62, 0x79, 0x20, 0x31, 0x38, 0x30, 0x20, 0x64, 0x65, 1120x00, 0x1f, 0x44, 0x35, 0x00, 0x01, 0xf4, 0x03, 0x62, 0x79,
1120x67, 0x72, 0x65, 0x65, 0x73, 0x3a, 0x00, 0x60, 0x46, 0x26, 1130x20, 0x31, 0x38, 0x30, 0x20, 0x64, 0x65, 0x67, 0x72, 0x65,
1130x00, 0xb0, 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x28, 0x6f, 0x72, 1140x65, 0x73, 0x3a, 0x00, 0x60, 0x46, 0x26, 0x00, 0xb0, 0x4c,
1140x20, 0x75, 0x6e, 0x59, 0x00, 0x14, 0x29, 0xc6, 0x00, 0x02, 1150x6f, 0x63, 0x6b, 0x20, 0x28, 0x6f, 0x72, 0x20, 0x75, 0x6e,
1150x86, 0x01, 0x0a, 0x5c, 0x00, 0xf4, 0x00, 0x73, 0x68, 0x69, 1160x59, 0x00, 0x14, 0x29, 0xc6, 0x00, 0x02, 0x86, 0x01, 0x0a,
1160x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x2c, 0x00, 1170x5c, 0x00, 0xf4, 0x00, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2d,
1170x60, 0x53, 0x43, 0x00, 0x31, 0x59, 0x6f, 0x75, 0x4c, 0x01, 1180x63, 0x6c, 0x69, 0x63, 0x6b, 0x2c, 0x00, 0x60, 0x53, 0x43,
1180x00, 0x40, 0x00, 0x22, 0x00, 0x61, 0x94, 0x02, 0xa0, 0x6f, 1190x00, 0x31, 0x59, 0x6f, 0x75, 0x4c, 0x01, 0x00, 0x40, 0x00,
1190x6e, 0x63, 0x65, 0x00, 0x79, 0x6f, 0x75, 0x27, 0x72, 0x64, 1200x22, 0x00, 0x61, 0x94, 0x02, 0xa0, 0x6f, 0x6e, 0x63, 0x65,
1200x02, 0x20, 0x72, 0x65, 0xf0, 0x02, 0x30, 0x69, 0x74, 0x73, 1210x00, 0x79, 0x6f, 0x75, 0x27, 0x72, 0x64, 0x02, 0x20, 0x72,
1210xd3, 0x03, 0x04, 0x59, 0x03, 0x15, 0x2e, 0x39, 0x00, 0x52, 1220x65, 0xf0, 0x02, 0x30, 0x69, 0x74, 0x73, 0xd3, 0x03, 0x04,
1220x61, 0x6c, 0x73, 0x6f, 0x00, 0x80, 0x00, 0x01, 0xad, 0x02, 1230x59, 0x03, 0x15, 0x2e, 0x39, 0x00, 0x52, 0x61, 0x6c, 0x73,
1230x50, 0x67, 0x61, 0x69, 0x6e, 0x2c, 0x76, 0x00, 0x00, 0x33, 1240x6f, 0x00, 0x80, 0x00, 0x01, 0xad, 0x02, 0x50, 0x67, 0x61,
1240x02, 0x10, 0x6c, 0xc1, 0x02, 0x21, 0x27, 0x73, 0x5e, 0x00, 1250x69, 0x6e, 0x2c, 0x76, 0x00, 0x00, 0x33, 0x02, 0x10, 0x6c,
1250x42, 0x65, 0x64, 0x00, 0x79, 0x34, 0x00, 0x80, 0x27, 0x74, 1260xc1, 0x02, 0x21, 0x27, 0x73, 0x5e, 0x00, 0x42, 0x65, 0x64,
1260x00, 0x61, 0x63, 0x63, 0x69, 0x64, 0x4d, 0x00, 0x00, 0x20, 1270x00, 0x79, 0x34, 0x00, 0x80, 0x27, 0x74, 0x00, 0x61, 0x63,
1270x04, 0x81, 0x74, 0x75, 0x72, 0x6e, 0x00, 0x69, 0x74, 0x2e, 1280x63, 0x69, 0x64, 0x4d, 0x00, 0x00, 0x20, 0x04, 0x81, 0x74,
1280xe1, 0x01, 0x00, 0x1f, 0x04, 0x40, 0x6c, 0x6c, 0x6f, 0x77, 1290x75, 0x72, 0x6e, 0x00, 0x69, 0x74, 0x2e, 0xe1, 0x01, 0x00,
1290x28, 0x03, 0x08, 0xac, 0x01, 0x70, 0x00, 0x6e, 0x6f, 0x74, 1300x1f, 0x04, 0x40, 0x6c, 0x6c, 0x6f, 0x77, 0x28, 0x03, 0x08,
1300x00, 0x6e, 0x65, 0xf1, 0x02, 0x10, 0x61, 0x3d, 0x03, 0x11, 1310xac, 0x01, 0x70, 0x00, 0x6e, 0x6f, 0x74, 0x00, 0x6e, 0x65,
1310x6f, 0xbf, 0x03, 0x41, 0x6c, 0x65, 0x74, 0x65, 0xe2, 0x01, 1320xf1, 0x02, 0x10, 0x61, 0x3d, 0x03, 0x11, 0x6f, 0xbf, 0x03,
1320x00, 0x15, 0x02, 0x02, 0x77, 0x00, 0x30, 0x6d, 0x61, 0x79, 1330x41, 0x6c, 0x65, 0x74, 0x65, 0xe2, 0x01, 0x00, 0x15, 0x02,
1330x1a, 0x02, 0x61, 0x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0xe2, 1340x02, 0x77, 0x00, 0x30, 0x6d, 0x61, 0x79, 0x1a, 0x02, 0x61,
1340x01, 0x00, 0xfa, 0x00, 0x10, 0x20, 0xa4, 0x03, 0x12, 0x3a, 1350x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0xe2, 0x01, 0x00, 0xfa,
1350x0c, 0x00, 0x2a, 0x00, 0x2b, 0xda, 0x01, 0x21, 0x4f, 0x6e, 1360x00, 0x10, 0x20, 0xa4, 0x03, 0x12, 0x3a, 0x0c, 0x00, 0x2a,
1360xc2, 0x03, 0x00, 0xb0, 0x03, 0x84, 0x61, 0x74, 0x00, 0x77, 1370x00, 0x2b, 0xda, 0x01, 0x21, 0x4f, 0x6e, 0xc2, 0x03, 0x00,
1370x72, 0x61, 0x70, 0x2c, 0xab, 0x00, 0x42, 0x00, 0x6d, 0x6f, 1380xb0, 0x03, 0x84, 0x61, 0x74, 0x00, 0x77, 0x72, 0x61, 0x70,
1380x76, 0x61, 0x00, 0x02, 0xd0, 0x04, 0x02, 0x2d, 0x05, 0x13, 1390x2c, 0xab, 0x00, 0x42, 0x00, 0x6d, 0x6f, 0x76, 0x61, 0x00,
1390x65, 0xf2, 0x03, 0x22, 0x73, 0x6f, 0x33, 0x00, 0x02, 0x23, 1400x02, 0xd0, 0x04, 0x02, 0x2d, 0x05, 0x13, 0x65, 0xf2, 0x03,
1400x03, 0x02, 0x3e, 0x00, 0x00, 0x97, 0x04, 0x00, 0x55, 0x05, 1410x22, 0x73, 0x6f, 0x33, 0x00, 0x02, 0x23, 0x03, 0x02, 0x3e,
1410xd8, 0x70, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x00, 0x73, 1420x00, 0x00, 0x97, 0x04, 0x00, 0x55, 0x05, 0xd8, 0x70, 0x70,
1420x69, 0x64, 0x65, 0x73, 0x37, 0x00, 0x04, 0xbb, 0x02, 0x90, 1430x6f, 0x73, 0x69, 0x74, 0x65, 0x00, 0x73, 0x69, 0x64, 0x65,
1430x73, 0x65, 0x65, 0x6e, 0x00, 0x74, 0x6f, 0x67, 0x65, 0xb6, 1440x73, 0x37, 0x00, 0x04, 0xbb, 0x02, 0x90, 0x73, 0x65, 0x65,
1440x02, 0x00, 0xfc, 0x00, 0x52, 0x4d, 0x6f, 0x76, 0x65, 0x20, 1450x6e, 0x00, 0x74, 0x6f, 0x67, 0x65, 0xb6, 0x02, 0x00, 0xfc,
1450x63, 0x04, 0x6c, 0x3a, 0x00, 0x43, 0x74, 0x72, 0x6c, 0xa8, 1460x00, 0x52, 0x4d, 0x6f, 0x76, 0x65, 0x20, 0x63, 0x04, 0x6c,
1460x00, 0x04, 0x73, 0x01, 0x63, 0x63, 0x68, 0x61, 0x6e, 0x67, 1470x3a, 0x00, 0x43, 0x74, 0x72, 0x6c, 0xa8, 0x00, 0x04, 0x73,
1470x65, 0x93, 0x03, 0x11, 0x74, 0x65, 0x01, 0x30, 0x73, 0x00, 1480x01, 0x63, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x93, 0x03,
1480x75, 0xc8, 0x03, 0x12, 0x61, 0x74, 0x04, 0x51, 0x73, 0x6f, 1490x11, 0x74, 0x65, 0x01, 0x30, 0x73, 0x00, 0x75, 0xc8, 0x03,
1490x75, 0x72, 0x63, 0xb7, 0x01, 0x05, 0x86, 0x03, 0xd0, 0x69, 1500x12, 0x61, 0x74, 0x04, 0x51, 0x73, 0x6f, 0x75, 0x72, 0x63,
1500x6e, 0x67, 0x2e, 0x00, 0x28, 0x49, 0x74, 0x00, 0x64, 0x6f, 1510xb7, 0x01, 0x05, 0x86, 0x03, 0xd0, 0x69, 0x6e, 0x67, 0x2e,
1510x65, 0x73, 0x82, 0x01, 0x70, 0x75, 0x6c, 0x74, 0x69, 0x6d, 1520x00, 0x28, 0x49, 0x74, 0x00, 0x64, 0x6f, 0x65, 0x73, 0x82,
1520x61, 0x74, 0x20, 0x04, 0x30, 0x6d, 0x61, 0x74, 0x06, 0x05, 1530x01, 0x70, 0x75, 0x6c, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x20,
1530x07, 0x50, 0x00, 0x02, 0xae, 0x05, 0x20, 0x73, 0x2c, 0x51, 1540x04, 0x30, 0x6d, 0x61, 0x74, 0x06, 0x05, 0x07, 0x50, 0x00,
1540x00, 0x07, 0xad, 0x04, 0x04, 0x5d, 0x04, 0x09, 0x03, 0x04, 1550x02, 0xae, 0x05, 0x20, 0x73, 0x2c, 0x51, 0x00, 0x07, 0xad,
1550x02, 0x20, 0x00, 0x02, 0x7e, 0x05, 0x02, 0x8d, 0x00, 0x00, 1560x04, 0x04, 0x5d, 0x04, 0x09, 0x03, 0x04, 0x02, 0x20, 0x00,
1560x13, 0x05, 0x75, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 1570x02, 0x7e, 0x05, 0x02, 0x8d, 0x00, 0x00, 0x13, 0x05, 0x75,
1570x99, 0x04, 0x02, 0x9c, 0x01, 0x15, 0x69, 0x9f, 0x01, 0x40, 1580x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x99, 0x04, 0x02,
1580x68, 0x65, 0x6c, 0x70, 0xb9, 0x04, 0x03, 0x39, 0x04, 0x01, 1590x9c, 0x01, 0x15, 0x69, 0x9f, 0x01, 0x40, 0x68, 0x65, 0x6c,
1590x71, 0x03, 0x50, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x33, 0x01, 1600x70, 0xb9, 0x04, 0x03, 0x39, 0x04, 0x01, 0x71, 0x03, 0x50,
1600x33, 0x74, 0x61, 0x67, 0x66, 0x05, 0x30, 0x6f, 0x6c, 0x76, 1610x6d, 0x65, 0x64, 0x69, 0x61, 0x33, 0x01, 0x33, 0x74, 0x61,
1610x09, 0x02, 0x00, 0x23, 0x00, 0x61, 0x70, 0x75, 0x7a, 0x7a, 1620x67, 0x66, 0x05, 0x30, 0x6f, 0x6c, 0x76, 0x09, 0x02, 0x00,
1620x6c, 0x65, 0x5e, 0x06, 0x52, 0x4a, 0x75, 0x6d, 0x62, 0x6c, 1630x23, 0x00, 0x61, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x5e,
1630x1e, 0x03, 0x00, 0x10, 0x03, 0x14, 0x4a, 0xcd, 0x02, 0x01, 1640x06, 0x52, 0x4a, 0x75, 0x6d, 0x62, 0x6c, 0x1e, 0x03, 0x00,
1640x1f, 0x04, 0x22, 0x6b, 0x65, 0x52, 0x02, 0x17, 0x73, 0xbe, 1650x10, 0x03, 0x14, 0x4a, 0xcd, 0x02, 0x01, 0x1f, 0x04, 0x22,
1650x04, 0x01, 0x9b, 0x01, 0x04, 0x45, 0x02, 0x03, 0x8d, 0x02, 1660x6b, 0x65, 0x52, 0x02, 0x17, 0x73, 0xbe, 0x04, 0x01, 0x9b,
1660x23, 0x74, 0x6f, 0x7d, 0x05, 0x08, 0xd8, 0x02, 0x20, 0x73, 1670x01, 0x04, 0x45, 0x02, 0x03, 0x8d, 0x02, 0x23, 0x74, 0x6f,
1670x2e, 0x2c, 0x07, 0x31, 0x41, 0x6c, 0x6c, 0x73, 0x00, 0x22, 1680x7d, 0x05, 0x08, 0xd8, 0x02, 0x20, 0x73, 0x2e, 0x2c, 0x07,
1680x61, 0x63, 0x45, 0x06, 0x90, 0x64, 0x65, 0x73, 0x63, 0x72, 1690x31, 0x41, 0x6c, 0x6c, 0x73, 0x00, 0x22, 0x61, 0x63, 0x45,
1690x69, 0x62, 0x65, 0x64, 0xaf, 0x00, 0x31, 0x73, 0x65, 0x63, 1700x06, 0x90, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
1700x6a, 0x05, 0x31, 0x32, 0x2e, 0x31, 0x53, 0x00, 0x01, 0x01, 1710x64, 0xaf, 0x00, 0x31, 0x73, 0x65, 0x63, 0x6a, 0x05, 0x31,
1710x03, 0x73, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0xa0, 1720x32, 0x2e, 0x31, 0x53, 0x00, 0x01, 0x01, 0x03, 0x73, 0x61,
1720x00, 0x31, 0x33, 0x2e, 0x32, 0xbb, 0x04, 0x93, 0x70, 0x61, 1730x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0xa0, 0x00, 0x31, 0x33,
1730x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0xbd, 0x04, 0x10, 1740x2e, 0x32, 0xbb, 0x04, 0x93, 0x70, 0x61, 0x72, 0x61, 0x6d,
1740x65, 0x5d, 0x04, 0x05, 0x14, 0x00, 0x02, 0x3e, 0x00, 0x04, 1750x65, 0x74, 0x65, 0x72, 0xbd, 0x04, 0x10, 0x65, 0x5d, 0x04,
1750x39, 0x00, 0x51, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x76, 0x00, 1760x05, 0x14, 0x00, 0x02, 0x3e, 0x00, 0x04, 0x39, 0x00, 0x51,
1760xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 1770x00, 0x66, 0x72, 0x6f, 0x6d, 0x76, 0x00, 0xe1, 0x60, 0x43,
1770x2e, 0x27, 0x00, 0x6f, 0x70, 0x6c, 0x00, 0x22, 0x6f, 0x6e, 1780x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00,
1780x1a, 0x00, 0xa0, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 1790x6f, 0x70, 0x6c, 0x00, 0x22, 0x6f, 0x6e, 0x1a, 0x00, 0xa0,
1790x65, 0x6e, 0x75, 0xa8, 0x00, 0x91, 0x57, 0x69, 0x64, 0x74, 1800x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75,
1800x68, 0x2c, 0x00, 0x48, 0x65, 0x4b, 0x04, 0x51, 0x00, 0x00, 1810xa8, 0x00, 0x91, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00,
1810x53, 0x69, 0x7a, 0xf5, 0x01, 0x01, 0x66, 0x02, 0x22, 0x69, 1820x48, 0x65, 0x4b, 0x04, 0x51, 0x00, 0x00, 0x53, 0x69, 0x7a,
1820x6e, 0xfc, 0x00, 0x01, 0x29, 0x00, 0x50, 0x61, 0x6c, 0x6c, 1830xf5, 0x01, 0x01, 0x66, 0x02, 0x22, 0x69, 0x6e, 0xfc, 0x00,
1830x73, 0x20, 0xd9, 0x02, 0x70, 0x20, 0x61, 0x72, 0x6f, 0x75, 1840x01, 0x29, 0x00, 0x50, 0x61, 0x6c, 0x6c, 0x73, 0x20, 0xd9,
1840x6e, 0x64, 0xa2, 0x07, 0x50, 0x66, 0x00, 0x63, 0x68, 0x65, 1850x02, 0x70, 0x20, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0xa2,
1850x0a, 0x01, 0x61, 0x2c, 0x00, 0x66, 0x6c, 0x6f, 0x77, 0x5a, 1860x07, 0x50, 0x66, 0x00, 0x63, 0x68, 0x65, 0x0a, 0x01, 0x61,
1860x02, 0x46, 0x70, 0x61, 0x73, 0x73, 0x89, 0x00, 0x01, 0xd7, 1870x2c, 0x00, 0x66, 0x6c, 0x6f, 0x77, 0x5a, 0x02, 0x46, 0x70,
1870x04, 0x44, 0x65, 0x64, 0x67, 0x65, 0xea, 0x05, 0x02, 0xb4, 1880x61, 0x73, 0x73, 0x89, 0x00, 0x01, 0xd7, 0x04, 0x44, 0x65,
1880x04, 0x00, 0x12, 0x00, 0x02, 0xee, 0x06, 0x02, 0x2a, 0x00, 1890x64, 0x67, 0x65, 0xea, 0x05, 0x02, 0xb4, 0x04, 0x00, 0x12,
1890x20, 0x6f, 0x70, 0x20, 0x00, 0x62, 0x62, 0x6f, 0x74, 0x74, 1900x00, 0x02, 0xee, 0x06, 0x02, 0x2a, 0x00, 0x20, 0x6f, 0x70,
1900x6f, 0x6d, 0x18, 0x00, 0x41, 0x76, 0x69, 0x63, 0x65, 0x5f, 1910x20, 0x00, 0x62, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x18,
1910x08, 0x10, 0x61, 0x7e, 0x00, 0xf0, 0x03, 0x42, 0x61, 0x72, 1920x00, 0x41, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x08, 0x10, 0x61,
1920x72, 0x69, 0x65, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x62, 0x61, 1930x7e, 0x00, 0xf0, 0x03, 0x42, 0x61, 0x72, 0x72, 0x69, 0x65,
1930x62, 0x69, 0x6c, 0x69, 0x74, 0xac, 0x01, 0xd0, 0x41, 0x00, 1940x72, 0x20, 0x70, 0x72, 0x6f, 0x62, 0x61, 0x62, 0x69, 0x6c,
1940x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x00, 0x62, 0x65, 0x74, 1950x69, 0x74, 0xac, 0x01, 0xd0, 0x41, 0x00, 0x6e, 0x75, 0x6d,
1950x77, 0x0b, 0x03, 0x31, 0x30, 0x2e, 0x30, 0x3d, 0x00, 0x34, 1960x62, 0x65, 0x72, 0x00, 0x62, 0x65, 0x74, 0x77, 0x0b, 0x03,
1960x31, 0x2e, 0x30, 0xf9, 0x03, 0x11, 0x6c, 0x6a, 0x08, 0x11, 1970x31, 0x30, 0x2e, 0x30, 0x3d, 0x00, 0x34, 0x31, 0x2e, 0x30,
1970x68, 0x22, 0x03, 0x00, 0xd2, 0x06, 0x51, 0x69, 0x6d, 0x6d, 1980xf9, 0x03, 0x11, 0x6c, 0x6a, 0x08, 0x11, 0x68, 0x22, 0x03,
1980x6f, 0x76, 0x2d, 0x01, 0x12, 0x62, 0x54, 0x00, 0x00, 0xf9, 1990x00, 0xd2, 0x06, 0x51, 0x69, 0x6d, 0x6d, 0x6f, 0x76, 0x2d,
1990x02, 0x01, 0x11, 0x07, 0x15, 0x64, 0x47, 0x00, 0x34, 0x74, 2000x01, 0x12, 0x62, 0x54, 0x00, 0x00, 0xf9, 0x02, 0x01, 0x11,
2000x77, 0x6f, 0xf5, 0x01, 0x10, 0x6f, 0xd9, 0x07, 0x42, 0x76, 2010x07, 0x15, 0x64, 0x47, 0x00, 0x34, 0x74, 0x77, 0x6f, 0xf5,
2010x65, 0x6e, 0x74, 0xe1, 0x00, 0x05, 0x22, 0x00, 0x61, 0x68, 2020x01, 0x10, 0x6f, 0xd9, 0x07, 0x42, 0x76, 0x65, 0x6e, 0x74,
2020x65, 0x6d, 0x00, 0x28, 0x61, 0x1c, 0x03, 0x24, 0x65, 0x72, 2030xe1, 0x00, 0x05, 0x22, 0x00, 0x61, 0x68, 0x65, 0x6d, 0x00,
2030x87, 0x00, 0x95, 0x67, 0x69, 0x76, 0x65, 0x73, 0x00, 0x6d, 2040x28, 0x61, 0x1c, 0x03, 0x24, 0x65, 0x72, 0x87, 0x00, 0x95,
2040x6f, 0x72, 0x5d, 0x00, 0x86, 0x73, 0x29, 0x2e, 0x00, 0x53, 2050x67, 0x69, 0x76, 0x65, 0x73, 0x00, 0x6d, 0x6f, 0x72, 0x5d,
2050x69, 0x6e, 0x63, 0x11, 0x00, 0x01, 0xb2, 0x01, 0x05, 0x85, 2060x00, 0x86, 0x73, 0x29, 0x2e, 0x00, 0x53, 0x69, 0x6e, 0x63,
2060x00, 0x10, 0x2c, 0x4a, 0x00, 0x10, 0x79, 0x25, 0x02, 0x00, 2070x11, 0x00, 0x01, 0xb2, 0x01, 0x05, 0x85, 0x00, 0x10, 0x2c,
2070x27, 0x03, 0xb4, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 2080x4a, 0x00, 0x10, 0x79, 0x25, 0x02, 0x00, 0x27, 0x03, 0xb4,
2080x69, 0x6e, 0x74, 0x73, 0xaf, 0x01, 0x05, 0x95, 0x07, 0x80, 2090x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74,
2090x28, 0x69, 0x2e, 0x65, 0x2e, 0x2c, 0x00, 0x68, 0x1d, 0x00, 2100x73, 0xaf, 0x01, 0x05, 0x95, 0x07, 0x80, 0x28, 0x69, 0x2e,
2100x14, 0x29, 0xe7, 0x04, 0x01, 0xa6, 0x01, 0x51, 0x67, 0x65, 2110x65, 0x2e, 0x2c, 0x00, 0x68, 0x1d, 0x00, 0x14, 0x29, 0xe7,
2110x6e, 0x65, 0x72, 0x7a, 0x02, 0x00, 0xb1, 0x01, 0x00, 0xf9, 2120x04, 0x01, 0xa6, 0x01, 0x51, 0x67, 0x65, 0x6e, 0x65, 0x72,
2120x08, 0x50, 0x68, 0x61, 0x73, 0x00, 0x62, 0xa7, 0x00, 0x30, 2130x7a, 0x02, 0x00, 0xb1, 0x01, 0x00, 0xf9, 0x08, 0x50, 0x68,
2130x63, 0x61, 0x72, 0xc2, 0x04, 0x20, 0x6c, 0x79, 0x05, 0x04, 2140x61, 0x73, 0x00, 0x62, 0xa7, 0x00, 0x30, 0x63, 0x61, 0x72,
2140x00, 0xf1, 0x03, 0x16, 0x64, 0x70, 0x04, 0x1c, 0x68, 0x94, 2150xc2, 0x04, 0x20, 0x6c, 0x79, 0x05, 0x04, 0x00, 0xf1, 0x03,
2150x00, 0x60, 0x6e, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x52, 0x05, 2160x16, 0x64, 0x70, 0x04, 0x1c, 0x68, 0x94, 0x00, 0x60, 0x6e,
2160x04, 0x6b, 0x04, 0x48, 0x72, 0x65, 0x73, 0x74, 0x77, 0x04, 2170x64, 0x65, 0x70, 0x65, 0x6e, 0x52, 0x05, 0x04, 0x6b, 0x04,
2170x12, 0x2e, 0x1e, 0x03, 0x43, 0x6d, 0x65, 0x61, 0x6e, 0x10, 2180x48, 0x72, 0x65, 0x73, 0x74, 0x77, 0x04, 0x12, 0x2e, 0x1e,
2180x03, 0x21, 0x69, 0x66, 0xe6, 0x04, 0x82, 0x6e, 0x6f, 0x74, 2190x03, 0x43, 0x6d, 0x65, 0x61, 0x6e, 0x10, 0x03, 0x21, 0x69,
2190x65, 0x00, 0x64, 0x6f, 0x77, 0xb4, 0x00, 0x03, 0x13, 0x03, 2200x66, 0xe6, 0x04, 0x82, 0x6e, 0x6f, 0x74, 0x65, 0x00, 0x64,
2200x42, 0x73, 0x65, 0x65, 0x64, 0x53, 0x04, 0x24, 0x74, 0x6f, 2210x6f, 0x77, 0xb4, 0x00, 0x03, 0x13, 0x03, 0x42, 0x73, 0x65,
2210xa5, 0x00, 0x12, 0x65, 0x04, 0x09, 0x30, 0x75, 0x72, 0x72, 2220x65, 0x64, 0x53, 0x04, 0x24, 0x74, 0x6f, 0xa5, 0x00, 0x12,
2220x67, 0x00, 0x02, 0x8f, 0x03, 0x57, 0x00, 0x28, 0x73, 0x65, 2230x65, 0x04, 0x09, 0x30, 0x75, 0x72, 0x72, 0x67, 0x00, 0x02,
2230x65, 0x13, 0x03, 0x34, 0x32, 0x29, 0x2c, 0x9f, 0x04, 0x00, 2240x8f, 0x03, 0x57, 0x00, 0x28, 0x73, 0x65, 0x65, 0x13, 0x03,
2240x2d, 0x00, 0x0f, 0xfb, 0x01, 0x01, 0x05, 0x01, 0x03, 0x07, 2250x34, 0x32, 0x29, 0x2c, 0x9f, 0x04, 0x00, 0x2d, 0x00, 0x0f,
2250x32, 0x09, 0x40, 0x72, 0x65, 0x2d, 0x65, 0x02, 0x04, 0x02, 2260xfb, 0x01, 0x01, 0x05, 0x01, 0x03, 0x07, 0x32, 0x09, 0x40,
2260x37, 0x01, 0x29, 0x61, 0x6d, 0x88, 0x00, 0x02, 0x8d, 0x05, 2270x72, 0x65, 0x2d, 0x65, 0x02, 0x04, 0x02, 0x37, 0x01, 0x29,
2270x70, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x00, 0x6f, 0x00, 2280x61, 0x6d, 0x88, 0x00, 0x02, 0x8d, 0x05, 0x70, 0x73, 0x68,
2280x76, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 0x79, 0x2d, 0x00, 2290x6f, 0x75, 0x6c, 0x64, 0x00, 0x6f, 0x00, 0x76, 0x65, 0x78,
2290x41, 0x73, 0x74, 0x61, 0x72, 0x59, 0x09, 0x02, 0x97, 0x05, 2300x61, 0x63, 0x74, 0x6c, 0x79, 0x2d, 0x00, 0x41, 0x73, 0x74,
2300x01, 0x0e, 0x08, 0x02, 0x9a, 0x08, 0x24, 0x6c, 0x79, 0x8f, 2310x61, 0x72, 0x59, 0x09, 0x02, 0x97, 0x05, 0x01, 0x0e, 0x08,
2310x00, 0x24, 0x62, 0x65, 0x49, 0x04, 0x03, 0xf1, 0x01, 0x25, 2320x02, 0x9a, 0x08, 0x24, 0x6c, 0x79, 0x8f, 0x00, 0x24, 0x62,
2320x6f, 0x66, 0x44, 0x01, 0x43, 0x2e, 0x00, 0x53, 0x6f, 0x0f, 2330x65, 0x49, 0x04, 0x03, 0xf1, 0x01, 0x25, 0x6f, 0x66, 0x44,
2330x01, 0x01, 0xf4, 0x06, 0x60, 0x74, 0x75, 0x63, 0x6b, 0x00, 2340x01, 0x43, 0x2e, 0x00, 0x53, 0x6f, 0x0f, 0x01, 0x01, 0xf4,
2340x6f, 0xc7, 0x04, 0x10, 0x70, 0x59, 0x00, 0x52, 0x63, 0x75, 2350x06, 0x60, 0x74, 0x75, 0x63, 0x6b, 0x00, 0x6f, 0xc7, 0x04,
2350x6c, 0x61, 0x72, 0xb0, 0x01, 0x20, 0x61, 0x6e, 0x45, 0x09, 2360x10, 0x70, 0x59, 0x00, 0x52, 0x63, 0x75, 0x6c, 0x61, 0x72,
2360x00, 0x6a, 0x05, 0x01, 0xce, 0x01, 0x03, 0x28, 0x06, 0x02, 2370xb0, 0x01, 0x20, 0x61, 0x6e, 0x45, 0x09, 0x00, 0x6a, 0x05,
2370x9a, 0x00, 0x00, 0x85, 0x00, 0x00, 0x2a, 0x0a, 0x23, 0x61, 2380x01, 0xce, 0x01, 0x03, 0x28, 0x06, 0x02, 0x9a, 0x00, 0x00,
2380x6e, 0x8b, 0x0a, 0x52, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x88, 2390x85, 0x00, 0x00, 0x2a, 0x0a, 0x23, 0x61, 0x6e, 0x8b, 0x0a,
2390x05, 0x71, 0x4e, 0x65, 0x74, 0x2c, 0x00, 0x73, 0x65, 0x20, 2400x52, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x88, 0x05, 0x71, 0x4e,
2400x00, 0x05, 0xb7, 0x00, 0x07, 0x0b, 0x04, 0x00, 0x1d, 0x05, 2410x65, 0x74, 0x2c, 0x00, 0x73, 0x65, 0x20, 0x00, 0x05, 0xb7,
2410x05, 0x92, 0x02, 0x04, 0xdd, 0x02, 0x07, 0x36, 0x01, 0x02, 2420x00, 0x07, 0x0b, 0x04, 0x00, 0x1d, 0x05, 0x05, 0x92, 0x02,
2420x2c, 0x01, 0x06, 0x24, 0x01, 0x01, 0x04, 0x09, 0x01, 0xa5, 2430x04, 0xdd, 0x02, 0x07, 0x36, 0x01, 0x02, 0x2c, 0x01, 0x06,
2430x01, 0x05, 0xae, 0x03, 0x04, 0x71, 0x0b, 0x01, 0x46, 0x02, 2440x24, 0x01, 0x01, 0x04, 0x09, 0x01, 0xa5, 0x01, 0x05, 0xae,
2440x11, 0x77, 0x9a, 0x0b, 0x00, 0x6b, 0x02, 0x20, 0x45, 0x6e, 2450x03, 0x04, 0x71, 0x0b, 0x01, 0x46, 0x02, 0x11, 0x77, 0x9a,
2450xc3, 0x07, 0x85, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 2460x0b, 0x00, 0x6b, 0x02, 0x20, 0x45, 0x6e, 0xc3, 0x07, 0x85,
2460x20, 0x93, 0x02, 0x60, 0x00, 0x00, 0x4e, 0x6f, 0x72, 0x6d, 2470x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x93, 0x02,
2470x7f, 0x07, 0x13, 0x2c, 0x31, 0x00, 0x63, 0x6c, 0x6c, 0x00, 2480x60, 0x00, 0x00, 0x4e, 0x6f, 0x72, 0x6d, 0x7f, 0x07, 0x13,
2480x6d, 0x61, 0x6b, 0xf2, 0x07, 0x05, 0x67, 0x02, 0x02, 0xe7, 2490x2c, 0x31, 0x00, 0x63, 0x6c, 0x6c, 0x00, 0x6d, 0x61, 0x6b,
2490x01, 0x10, 0x73, 0xba, 0x05, 0x50, 0x70, 0x72, 0x65, 0x73, 2500xf2, 0x07, 0x05, 0x67, 0x02, 0x02, 0xe7, 0x01, 0x10, 0x73,
2500x65, 0xdf, 0x02, 0x33, 0x68, 0x61, 0x76, 0x5c, 0x01, 0x26, 2510xba, 0x05, 0x50, 0x70, 0x72, 0x65, 0x73, 0x65, 0xdf, 0x02,
2510x6f, 0x6e, 0xe6, 0x02, 0x33, 0x2e, 0x00, 0x50, 0x2c, 0x00, 2520x33, 0x68, 0x61, 0x76, 0x5c, 0x01, 0x26, 0x6f, 0x6e, 0xe6,
2520x01, 0x80, 0x01, 0x94, 0x61, 0x6d, 0x62, 0x69, 0x67, 0x75, 2530x02, 0x33, 0x2e, 0x00, 0x50, 0x2c, 0x00, 0x01, 0x80, 0x01,
2530x6f, 0x75, 0x73, 0x1e, 0x02, 0x14, 0x73, 0xf9, 0x06, 0x01, 2540x94, 0x61, 0x6d, 0x62, 0x69, 0x67, 0x75, 0x6f, 0x75, 0x73,
2540x64, 0x03, 0x40, 0x64, 0x69, 0x66, 0x66, 0x59, 0x01, 0x11, 2550x1e, 0x02, 0x14, 0x73, 0xf9, 0x06, 0x01, 0x64, 0x03, 0x40,
2550x74, 0xd9, 0x00, 0x21, 0x6d, 0x6f, 0x6b, 0x08, 0x41, 0x62, 2560x64, 0x69, 0x66, 0x66, 0x59, 0x01, 0x11, 0x74, 0xd9, 0x00,
2560x74, 0x6c, 0x65, 0x56, 0x07, 0x03, 0x9b, 0x02, 0x45, 0x6c, 2570x21, 0x6d, 0x6f, 0x6b, 0x08, 0x41, 0x62, 0x74, 0x6c, 0x65,
2570x69, 0x6b, 0x65, 0x8a, 0x07, 0x01, 0x26, 0x08, 0x23, 0x6f, 2580x56, 0x07, 0x03, 0x9b, 0x02, 0x45, 0x6c, 0x69, 0x6b, 0x65,
2580x66, 0xad, 0x0c, 0x40, 0x66, 0x65, 0x61, 0x74, 0xa9, 0x00, 2590x8a, 0x07, 0x01, 0x26, 0x08, 0x23, 0x6f, 0x66, 0xad, 0x0c,
2590x00, 0x3e, 0x00, 0x40, 0x72, 0x69, 0x73, 0x6b, 0x95, 0x00, 2600x40, 0x66, 0x65, 0x61, 0x74, 0xa9, 0x00, 0x00, 0x3e, 0x00,
2600x00, 0xe1, 0x01, 0x06, 0x77, 0x00, 0x03, 0xba, 0x00, 0x10, 2610x40, 0x72, 0x69, 0x73, 0x6b, 0x95, 0x00, 0x00, 0xe1, 0x01,
2610x2e, 0xcf, 0x05, 0x81, 0x73, 0x6f, 0x2c, 0x00, 0x66, 0x69, 2620x06, 0x77, 0x00, 0x03, 0xba, 0x00, 0x10, 0x2e, 0xcf, 0x05,
2620x6e, 0x64, 0x22, 0x00, 0x03, 0xdd, 0x05, 0x76, 0x70, 0x6f, 2630x81, 0x73, 0x6f, 0x2c, 0x00, 0x66, 0x69, 0x6e, 0x64, 0x22,
2630x73, 0x73, 0x69, 0x62, 0x6c, 0xc1, 0x00, 0x05, 0xa1, 0x00, 2640x00, 0x03, 0xdd, 0x05, 0x76, 0x70, 0x6f, 0x73, 0x73, 0x69,
2640x00, 0xd6, 0x08, 0x30, 0x64, 0x64, 0x69, 0x14, 0x00, 0x20, 2650x62, 0x6c, 0xc1, 0x00, 0x05, 0xa1, 0x00, 0x00, 0xd6, 0x08,
2650x61, 0x6c, 0x40, 0x02, 0x51, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 2660x30, 0x64, 0x64, 0x69, 0x14, 0x00, 0x20, 0x61, 0x6c, 0x40,
2660xb8, 0x0c, 0x02, 0x1c, 0x00, 0x30, 0x76, 0x61, 0x6e, 0x73, 2670x02, 0x51, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0xb8, 0x0c, 0x02,
2670x04, 0x90, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x2e, 0x29, 2680x1c, 0x00, 0x10, 0x76, 0xd7, 0x01, 0x12, 0x64, 0x7d, 0x0a,
2680x00, 2690x13, 0x72, 0xf2, 0x05, 0x11, 0x33, 0xf2, 0x05, 0x21, 0x75,
2700x73, 0xee, 0x02, 0xa2, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
2710x63, 0x65, 0x73, 0x20, 0x5f, 0x08, 0x40, 0x70, 0x6c, 0x61,
2720x74, 0xf6, 0x0c, 0x03, 0x7a, 0x03, 0x50, 0x73, 0x75, 0x70,
2730x70, 0x6f, 0x2d, 0x02, 0x12, 0x73, 0x7d, 0x0c, 0x04, 0x2e,
2740x00, 0x12, 0x2c, 0xe6, 0x05, 0x16, 0x50, 0x12, 0x00, 0x0d,
2750x02, 0x06, 0x33, 0x47, 0x61, 0x6d, 0x02, 0x06, 0x02, 0xb3,
2760x01, 0x33, 0x6c, 0x65, 0x74, 0x84, 0x02, 0x40, 0x6e, 0x66,
2770x69, 0x67, 0x12, 0x01, 0x10, 0x77, 0x51, 0x03, 0x01, 0xd1,
2780x0b, 0x0c, 0x88, 0x0b, 0x01, 0xce, 0x07, 0x30, 0x72, 0x72,
2790x6f, 0xf1, 0x02, 0xa2, 0x42, 0x79, 0x00, 0x64, 0x65, 0x66,
2800x61, 0x75, 0x6c, 0x74, 0xc7, 0x04, 0x11, 0x27, 0xca, 0x06,
2810x48, 0x77, 0x61, 0x79, 0x73, 0x32, 0x00, 0x33, 0x3b, 0x00,
2820x62, 0x41, 0x03, 0x02, 0x3d, 0x03, 0x23, 0x69, 0x73, 0x90,
2830x00, 0x06, 0x21, 0x09, 0x32, 0x61, 0x73, 0x6b, 0x19, 0x01,
2840x01, 0x74, 0x00, 0x01, 0x0a, 0x06, 0x0a, 0x75, 0x00, 0x01,
2850x29, 0x02, 0x28, 0x69, 0x66, 0x48, 0x08, 0x00, 0x0b, 0x01,
2860x00, 0x51, 0x00, 0x00, 0x5e, 0x03, 0x04, 0xa4, 0x04, 0x01,
2870x3e, 0x00, 0x14, 0x69, 0x2b, 0x0a, 0x03, 0xae, 0x04, 0x01,
2880x75, 0x0e, 0x16, 0x73, 0x20, 0x00, 0x08, 0xcf, 0x08, 0x01,
2890x9e, 0x07, 0x00, 0x07, 0x00, 0x00, 0xb5, 0x0c, 0x72, 0x73,
2900x70, 0x6f, 0x69, 0x6c, 0x65, 0x72, 0x8a, 0x00, 0x05, 0x53,
2910x07, 0x43, 0x64, 0x65, 0x64, 0x75, 0x7c, 0x02, 0x55, 0x61,
2920x62, 0x6f, 0x75, 0x74, 0xb6, 0x0d, 0x00, 0xbd, 0x00, 0x00,
2930xc6, 0x02, 0x00, 0x09, 0x09, 0x22, 0x65, 0x76, 0x30, 0x01,
2940x00, 0x14, 0x08, 0x80, 0x61, 0x74, 0x00, 0x79, 0x65, 0x74,
2950x2e, 0x00,
269}; 296};
270 297
271const unsigned short help_text_len = 3439; 298const unsigned short help_text_len = 3919;
272const unsigned short help_text_words = 611; 299const unsigned short help_text_words = 689;
273const char quick_help_text[] = "Rotate each tile to reassemble the network."; 300const char quick_help_text[] = "Rotate each tile to reassemble the network.";
diff --git a/apps/plugins/puzzles/help/netslide.c b/apps/plugins/puzzles/help/netslide.c
index 0035c6e3e1..e8d066e1fc 100644
--- a/apps/plugins/puzzles/help/netslide.c
+++ b/apps/plugins/puzzles/help/netslide.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -9,52 +9,53 @@ struct style_text help_text_style[] = {
9 LAST_STYLE_ITEM 9 LAST_STYLE_ITEM
10}; 10};
11 11
12/* orig 526 comp 419 ratio 0.796578 level 3 saved 107 */ 12/* orig 546 comp 425 ratio 0.778388 level 3 saved 121 */
13const char help_text[] = { 13const char help_text[] = {
140xf2, 0x3c, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 140xfe, 0x07, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
150x39, 0x3a, 0x20, 0x4e, 0x65, 0x74, 0x73, 0x6c, 0x69, 0x64, 150x39, 0x3a, 0x20, 0x4e, 0x65, 0x74, 0x73, 0x6c, 0x69, 0x64,
160x65, 0x20, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x73, 0x00, 160x65, 0x20, 0x00, 0x2d, 0x01, 0x00, 0xf2, 0x28, 0x00, 0x00,
170x67, 0x61, 0x6d, 0x65, 0x00, 0x63, 0x6f, 0x6d, 0x62, 0x69, 170x00, 0x54, 0x68, 0x69, 0x73, 0x00, 0x67, 0x61, 0x6d, 0x65,
180x6e, 0x65, 0x73, 0x00, 0x74, 0x68, 0x65, 0x00, 0x67, 0x72, 180x00, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x73, 0x00,
190x69, 0x64, 0x00, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 190x74, 0x68, 0x65, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x67,
200x69, 0x6f, 0x6e, 0x00, 0x6f, 0x66, 0x00, 0x4e, 0x65, 0x74, 200x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00,
210x00, 0x28, 0x73, 0x65, 0x65, 0x00, 0x63, 0x4a, 0x00, 0x81, 210x6f, 0x66, 0x00, 0x4e, 0x65, 0x74, 0x00, 0x28, 0x73, 0x65,
220x00, 0x33, 0x29, 0x00, 0x77, 0x69, 0x74, 0x68, 0x30, 0x00, 220x65, 0x00, 0x63, 0x5e, 0x00, 0x81, 0x00, 0x33, 0x29, 0x00,
230x80, 0x6d, 0x6f, 0x76, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x29, 230x77, 0x69, 0x74, 0x68, 0x30, 0x00, 0x80, 0x6d, 0x6f, 0x76,
240x00, 0x7a, 0x53, 0x69, 0x78, 0x74, 0x65, 0x65, 0x6e, 0x2d, 240x65, 0x6d, 0x65, 0x6e, 0x74, 0x29, 0x00, 0x7a, 0x53, 0x69,
250x00, 0xe1, 0x36, 0x29, 0x3a, 0x00, 0x79, 0x6f, 0x75, 0x00, 250x78, 0x74, 0x65, 0x65, 0x6e, 0x2d, 0x00, 0xe1, 0x36, 0x29,
260x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x4d, 0x00, 0x00, 0x64, 260x3a, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65,
270x00, 0xd0, 0x2c, 0x00, 0x62, 0x75, 0x74, 0x00, 0x69, 0x6e, 270x00, 0x61, 0x4d, 0x00, 0x00, 0x64, 0x00, 0xd0, 0x2c, 0x00,
280x73, 0x74, 0x65, 0x61, 0x64, 0x3d, 0x00, 0xf6, 0x0f, 0x72, 280x62, 0x75, 0x74, 0x00, 0x69, 0x6e, 0x73, 0x74, 0x65, 0x61,
290x6f, 0x74, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x00, 0x74, 0x69, 290x64, 0x3d, 0x00, 0xf6, 0x0f, 0x72, 0x6f, 0x74, 0x61, 0x74,
300x6c, 0x65, 0x73, 0x00, 0x62, 0x61, 0x63, 0x6b, 0x00, 0x69, 300x69, 0x6e, 0x67, 0x00, 0x74, 0x69, 0x6c, 0x65, 0x73, 0x00,
310x6e, 0x74, 0x6f, 0x00, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 310x62, 0x61, 0x63, 0x6b, 0x00, 0x69, 0x6e, 0x74, 0x6f, 0x00,
320x00, 0x31, 0x74, 0x6f, 0x00, 0xc4, 0x00, 0x00, 0x7e, 0x00, 320x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x00, 0x31, 0x74, 0x6f,
330x18, 0x6d, 0x22, 0x00, 0x20, 0x62, 0x79, 0x8d, 0x00, 0x00, 330x00, 0xd8, 0x00, 0x00, 0x7e, 0x00, 0x18, 0x6d, 0x22, 0x00,
340x42, 0x00, 0xf4, 0x0f, 0x61, 0x00, 0x77, 0x68, 0x6f, 0x6c, 340x20, 0x62, 0x79, 0x8d, 0x00, 0x00, 0x42, 0x00, 0xf4, 0x0f,
350x65, 0x00, 0x72, 0x6f, 0x77, 0x00, 0x61, 0x74, 0x00, 0x61, 350x61, 0x00, 0x77, 0x68, 0x6f, 0x6c, 0x65, 0x00, 0x72, 0x6f,
360x00, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x00, 0x00, 0x00, 0x41, 360x77, 0x00, 0x61, 0x74, 0x00, 0x61, 0x00, 0x74, 0x69, 0x6d,
370x73, 0x00, 0x69, 0x6e, 0xa7, 0x00, 0xc8, 0x2c, 0x00, 0x63, 370x65, 0x2e, 0x00, 0x00, 0x00, 0x41, 0x73, 0x00, 0x69, 0x6e,
380x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x00, 0x69, 0x73, 0xd0, 380xa7, 0x00, 0xc8, 0x2c, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x72,
390x00, 0xf1, 0x0c, 0x75, 0x73, 0x65, 0x00, 0x6f, 0x72, 0x00, 390x6f, 0x6c, 0x00, 0x69, 0x73, 0xd0, 0x00, 0xf1, 0x0c, 0x75,
400x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 400x73, 0x65, 0x00, 0x6f, 0x72, 0x00, 0x63, 0x75, 0x72, 0x73,
410x73, 0x2e, 0x00, 0x53, 0x65, 0x65, 0x00, 0x73, 0x65, 0x63, 410x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x00, 0x53,
420x12, 0x01, 0x41, 0x36, 0x2e, 0x31, 0x2e, 0x40, 0x01, 0xb2, 420x65, 0x65, 0x00, 0x73, 0x65, 0x63, 0x12, 0x01, 0x41, 0x36,
430x65, 0x00, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 430x2e, 0x31, 0x2e, 0x40, 0x01, 0xb2, 0x65, 0x00, 0x61, 0x76,
440x65, 0x49, 0x01, 0xa2, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 440x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x01, 0xa2,
450x74, 0x65, 0x72, 0x73, 0xab, 0x00, 0xf0, 0x01, 0x73, 0x69, 450x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73,
460x6d, 0x69, 0x6c, 0x61, 0x72, 0x00, 0x6d, 0x65, 0x61, 0x6e, 460xab, 0x00, 0xf0, 0x01, 0x73, 0x69, 0x6d, 0x69, 0x6c, 0x61,
470x69, 0x6e, 0x67, 0x73, 0xbc, 0x00, 0x50, 0x74, 0x68, 0x6f, 470x72, 0x00, 0x6d, 0x65, 0x61, 0x6e, 0x69, 0x6e, 0x67, 0x73,
480x73, 0x65, 0x86, 0x00, 0x05, 0x56, 0x01, 0x04, 0x58, 0x00, 480xbc, 0x00, 0x50, 0x74, 0x68, 0x6f, 0x73, 0x65, 0x86, 0x00,
490x8a, 0x33, 0x2e, 0x32, 0x29, 0x00, 0x61, 0x6e, 0x64, 0x47, 490x05, 0x56, 0x01, 0x04, 0x58, 0x00, 0x8a, 0x33, 0x2e, 0x32,
500x01, 0x06, 0x76, 0x00, 0x20, 0x32, 0x29, 0x77, 0x00, 0x04, 500x29, 0x00, 0x61, 0x6e, 0x64, 0x47, 0x01, 0x06, 0x76, 0x00,
510xc3, 0x01, 0x42, 0x00, 0x77, 0x61, 0x73, 0xc1, 0x00, 0x62, 510x20, 0x32, 0x29, 0x77, 0x00, 0x04, 0xd7, 0x01, 0x42, 0x00,
520x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x5c, 0x00, 0x10, 0x69, 520x77, 0x61, 0x73, 0xc1, 0x00, 0x62, 0x69, 0x62, 0x75, 0x74,
530x14, 0x00, 0x23, 0x6c, 0x6c, 0x34, 0x00, 0xf0, 0x05, 0x62, 530x65, 0x64, 0x5c, 0x00, 0x10, 0x69, 0x14, 0x00, 0x23, 0x6c,
540x79, 0x00, 0x52, 0x69, 0x63, 0x68, 0x61, 0x72, 0x64, 0x00, 540x6c, 0x34, 0x00, 0xf0, 0x05, 0x62, 0x79, 0x00, 0x52, 0x69,
550x42, 0x6f, 0x75, 0x6c, 0x74, 0x6f, 0x6e, 0x2e, 0x00, 550x63, 0x68, 0x61, 0x72, 0x64, 0x00, 0x42, 0x6f, 0x75, 0x6c,
560x74, 0x6f, 0x6e, 0x2e, 0x00,
56}; 57};
57 58
58const unsigned short help_text_len = 526; 59const unsigned short help_text_len = 546;
59const unsigned short help_text_words = 98; 60const unsigned short help_text_words = 99;
60const char quick_help_text[] = "Slide a row at a time to reassemble the network."; 61const char quick_help_text[] = "Slide a row at a time to reassemble the network.";
diff --git a/apps/plugins/puzzles/help/nullgame.c b/apps/plugins/puzzles/help/nullgame.c
new file mode 100644
index 0000000000..219a68c7e8
--- /dev/null
+++ b/apps/plugins/puzzles/help/nullgame.c
@@ -0,0 +1 @@
const char quick_help_text[] = "";
diff --git a/apps/plugins/puzzles/help/palisade.c b/apps/plugins/puzzles/help/palisade.c
index 1094502ea7..9b95b07eae 100644
--- a/apps/plugins/puzzles/help/palisade.c
+++ b/apps/plugins/puzzles/help/palisade.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,89 +6,90 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 87, TEXT_CENTER | C_RED }, 9 { 88, TEXT_CENTER | C_RED },
10 { 149, TEXT_CENTER | C_RED }, 10 { 150, TEXT_CENTER | C_RED },
11 { 166, TEXT_UNDERLINE },
12 { 167, TEXT_UNDERLINE }, 11 { 167, TEXT_UNDERLINE },
13 { 177, TEXT_UNDERLINE }, 12 { 168, TEXT_UNDERLINE },
13 { 178, TEXT_UNDERLINE },
14 LAST_STYLE_ITEM 14 LAST_STYLE_ITEM
15}; 15};
16 16
17/* orig 1113 comp 892 ratio 0.801438 level 3 saved 221 */ 17/* orig 1135 comp 902 ratio 0.794714 level 3 saved 233 */
18const char help_text[] = { 18const char help_text[] = {
190xf0, 0x2d, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 190xff, 0x08, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
200x34, 0x31, 0x3a, 0x20, 0x50, 0x61, 0x6c, 0x69, 0x73, 0x61, 200x34, 0x31, 0x3a, 0x20, 0x50, 0x61, 0x6c, 0x69, 0x73, 0x61,
210x64, 0x65, 0x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x27, 210x64, 0x65, 0x20, 0x00, 0x2d, 0x01, 0x00, 0x00, 0xf0, 0x18,
220x72, 0x65, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x00, 0x61, 220x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x27, 0x72, 0x65, 0x00,
230x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 230x67, 0x69, 0x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 0x67, 0x72,
240x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x73, 0x6f, 240x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x61,
250x6d, 0x65, 0x11, 0x00, 0xf0, 0x07, 0x77, 0x68, 0x69, 0x63, 250x72, 0x65, 0x73, 0x2c, 0x00, 0x73, 0x6f, 0x6d, 0x65, 0x11,
260x68, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x00, 260x00, 0xf0, 0x07, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x63,
270x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2e, 0x3f, 0x00, 270x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x00, 0x6e, 0x75, 0x6d,
280xf2, 0x0b, 0x72, 0x00, 0x67, 0x6f, 0x61, 0x6c, 0x00, 0x69, 280x62, 0x65, 0x72, 0x73, 0x2e, 0x3f, 0x00, 0xf2, 0x0b, 0x72,
290x73, 0x00, 0x74, 0x6f, 0x00, 0x73, 0x75, 0x62, 0x64, 0x69, 290x00, 0x67, 0x6f, 0x61, 0x6c, 0x00, 0x69, 0x73, 0x00, 0x74,
300x76, 0x69, 0x64, 0x65, 0x00, 0x74, 0x68, 0x65, 0x4e, 0x00, 300x6f, 0x00, 0x73, 0x75, 0x62, 0x64, 0x69, 0x76, 0x69, 0x64,
310x41, 0x69, 0x6e, 0x74, 0x6f, 0x39, 0x00, 0xf0, 0x04, 0x69, 310x65, 0x00, 0x74, 0x68, 0x65, 0x4e, 0x00, 0x41, 0x69, 0x6e,
320x67, 0x75, 0x6f, 0x75, 0x73, 0x00, 0x72, 0x65, 0x67, 0x69, 320x74, 0x6f, 0x39, 0x00, 0xf0, 0x04, 0x69, 0x67, 0x75, 0x6f,
330x6f, 0x6e, 0x73, 0x2c, 0x00, 0x61, 0x6c, 0x6c, 0x5a, 0x00, 330x75, 0x73, 0x00, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73,
340x00, 0x29, 0x00, 0x61, 0x73, 0x61, 0x6d, 0x65, 0x00, 0x28, 340x2c, 0x00, 0x61, 0x6c, 0x6c, 0x5a, 0x00, 0x00, 0x29, 0x00,
350x85, 0x00, 0xf3, 0x07, 0x29, 0x00, 0x73, 0x69, 0x7a, 0x65, 350x61, 0x73, 0x61, 0x6d, 0x65, 0x00, 0x28, 0x85, 0x00, 0xf3,
360x2c, 0x00, 0x73, 0x75, 0x63, 0x68, 0x00, 0x74, 0x68, 0x61, 360x07, 0x29, 0x00, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x00, 0x73,
370x74, 0x00, 0x65, 0x61, 0x63, 0x68, 0x91, 0x00, 0x04, 0x81, 370x75, 0x63, 0x68, 0x00, 0x74, 0x68, 0x61, 0x74, 0x00, 0x65,
380x00, 0x53, 0x69, 0x6e, 0x67, 0x00, 0x61, 0x86, 0x00, 0x00, 380x61, 0x63, 0x68, 0x91, 0x00, 0x04, 0x81, 0x00, 0x53, 0x69,
390x7a, 0x00, 0x80, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x65, 0x6e, 390x6e, 0x67, 0x00, 0x61, 0x86, 0x00, 0x00, 0x7a, 0x00, 0x80,
400x74, 0x83, 0x00, 0x72, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 400x61, 0x64, 0x6a, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x83, 0x00,
410x79, 0x3c, 0x00, 0xf0, 0x03, 0x6d, 0x61, 0x6e, 0x79, 0x00, 410x72, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 0x79, 0x3c, 0x00,
420x65, 0x64, 0x67, 0x65, 0x73, 0x00, 0x28, 0x69, 0x6e, 0x63, 420xf0, 0x03, 0x6d, 0x61, 0x6e, 0x79, 0x00, 0x65, 0x64, 0x67,
430x6c, 0x75, 0x64, 0x3b, 0x00, 0xd1, 0x74, 0x68, 0x6f, 0x73, 430x65, 0x73, 0x00, 0x28, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,
440x65, 0x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x81, 440x3b, 0x00, 0xd1, 0x74, 0x68, 0x6f, 0x73, 0x65, 0x00, 0x62,
450x00, 0x30, 0x69, 0x6e, 0x73, 0xb5, 0x00, 0x31, 0x61, 0x6e, 450x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x81, 0x00, 0x30, 0x69,
460x64, 0x0f, 0x00, 0x31, 0x6f, 0x75, 0x74, 0x10, 0x00, 0x25, 460x6e, 0x73, 0xb5, 0x00, 0x31, 0x61, 0x6e, 0x64, 0x0f, 0x00,
470x6f, 0x66, 0xc8, 0x00, 0xf1, 0x10, 0x29, 0x2e, 0x00, 0x00, 470x31, 0x6f, 0x75, 0x74, 0x10, 0x00, 0x25, 0x6f, 0x66, 0xc8,
480x00, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x00, 0x66, 0x6f, 480x00, 0xf1, 0x10, 0x29, 0x2e, 0x00, 0x00, 0x00, 0x43, 0x72,
490x72, 0x00, 0x74, 0x68, 0x69, 0x73, 0x00, 0x70, 0x75, 0x7a, 490x65, 0x64, 0x69, 0x74, 0x00, 0x66, 0x6f, 0x72, 0x00, 0x74,
500x7a, 0x6c, 0x65, 0x00, 0x67, 0x6f, 0x65, 0xfe, 0x00, 0xd0, 500x68, 0x69, 0x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65,
510x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69, 0x2c, 0x00, 0x77, 0x68, 510x00, 0x67, 0x6f, 0x65, 0xfe, 0x00, 0xd0, 0x4e, 0x69, 0x6b,
520x6f, 0x00, 0x63, 0xdf, 0x00, 0xf0, 0x06, 0x69, 0x74, 0x00, 520x6f, 0x6c, 0x69, 0x2c, 0x00, 0x77, 0x68, 0x6f, 0x00, 0x63,
530x60, 0x46, 0x69, 0x76, 0x65, 0x00, 0x43, 0x65, 0x6c, 0x6c, 530xdf, 0x00, 0xf0, 0x06, 0x69, 0x74, 0x00, 0x60, 0x46, 0x69,
540x73, 0x27, 0x2e, 0x00, 0x5b, 0x32, 0x32, 0x5d, 0x49, 0x00, 540x76, 0x65, 0x00, 0x43, 0x65, 0x6c, 0x6c, 0x73, 0x27, 0x2e,
550x04, 0x83, 0x01, 0x41, 0x00, 0x77, 0x61, 0x73, 0xd5, 0x00, 550x00, 0x5b, 0x32, 0x32, 0x5d, 0x49, 0x00, 0x04, 0x98, 0x01,
560x70, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x46, 0x00, 560x41, 0x00, 0x77, 0x61, 0x73, 0xd5, 0x00, 0x70, 0x72, 0x69,
570x01, 0x5a, 0x00, 0xf0, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 570x62, 0x75, 0x74, 0x65, 0x64, 0x46, 0x00, 0x01, 0x5a, 0x00,
580x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x62, 0x79, 0x00, 0x4a, 580xf0, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69,
590x6f, 0x6e, 0x61, 0x73, 0x00, 0x4b, 0x6f, 0x65, 0x6c, 0x6b, 590x6f, 0x6e, 0x00, 0x62, 0x79, 0x00, 0x4a, 0x6f, 0x6e, 0x61,
600x65, 0x72, 0x40, 0x00, 0x00, 0x48, 0x00, 0x91, 0x00, 0x68, 600x73, 0x00, 0x4b, 0x6f, 0x65, 0x6c, 0x6b, 0x65, 0x72, 0x40,
610x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x76, 0x00, 0xa2, 610x00, 0x00, 0x48, 0x00, 0xe1, 0x00, 0x68, 0x74, 0x74, 0x70,
620x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f, 0x65, 0x6e, 0x2f, 620x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 0x7b,
630x95, 0x00, 0x80, 0x73, 0x2f, 0x66, 0x69, 0x76, 0x65, 0x5f, 630x00, 0xa2, 0x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f, 0x65,
640x63, 0x79, 0x00, 0xc6, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x00, 640x6e, 0x2f, 0x9a, 0x00, 0x80, 0x73, 0x2f, 0x66, 0x69, 0x76,
650x00, 0x00, 0x34, 0x31, 0x2e, 0x31, 0xfe, 0x01, 0x01, 0x77, 650x65, 0x5f, 0x63, 0x7e, 0x00, 0x86, 0x2f, 0x00, 0x00, 0x00,
660x00, 0x30, 0x6f, 0x6c, 0x73, 0x07, 0x02, 0xa0, 0x4c, 0x65, 660x34, 0x31, 0x2e, 0x31, 0x14, 0x02, 0x01, 0x78, 0x00, 0xf0,
670x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x82, 0x00, 670x02, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00, 0x00, 0x4c, 0x65,
680x40, 0x70, 0x6c, 0x61, 0x63, 0x0d, 0x01, 0x01, 0x3a, 0x01, 680x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x83, 0x00,
690x40, 0x70, 0x6c, 0x61, 0x63, 0x0e, 0x01, 0x01, 0x3b, 0x01,
690x67, 0x2e, 0x00, 0x52, 0x69, 0x67, 0x68, 0x1e, 0x00, 0xc1, 700x67, 0x2e, 0x00, 0x52, 0x69, 0x67, 0x68, 0x1e, 0x00, 0xc1,
700x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x60, 710x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x60,
710x6e, 0x6f, 0x22, 0x00, 0xf1, 0x02, 0x27, 0x2e, 0x00, 0x41, 720x6e, 0x6f, 0x22, 0x00, 0xf1, 0x02, 0x27, 0x2e, 0x00, 0x41,
720x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 730x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65,
730x6c, 0x79, 0x2c, 0x35, 0x01, 0xf0, 0x07, 0x61, 0x72, 0x72, 740x6c, 0x79, 0x2c, 0x36, 0x01, 0xf0, 0x07, 0x61, 0x72, 0x72,
740x6f, 0x77, 0x00, 0x6b, 0x65, 0x79, 0x73, 0x00, 0x77, 0x69, 750x6f, 0x77, 0x00, 0x6b, 0x65, 0x79, 0x73, 0x00, 0x77, 0x69,
750x6c, 0x6c, 0x00, 0x6d, 0x6f, 0x76, 0x65, 0x00, 0x61, 0x11, 760x6c, 0x6c, 0x00, 0x6d, 0x6f, 0x76, 0x65, 0x00, 0x61, 0x11,
760x00, 0xf1, 0x02, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x00, 0x63, 770x00, 0xf1, 0x02, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x00, 0x63,
770x75, 0x72, 0x73, 0x6f, 0x72, 0x2e, 0x00, 0x48, 0x6f, 0x6c, 780x75, 0x72, 0x73, 0x6f, 0x72, 0x2e, 0x00, 0x48, 0x6f, 0x6c,
780x95, 0x01, 0x12, 0x43, 0x8f, 0x00, 0x00, 0x6a, 0x02, 0x81, 790x96, 0x01, 0x12, 0x43, 0x8f, 0x00, 0x00, 0x6b, 0x02, 0x81,
790x6c, 0x65, 0x00, 0x70, 0x72, 0x65, 0x73, 0x73, 0xe7, 0x01, 800x6c, 0x65, 0x00, 0x70, 0x72, 0x65, 0x73, 0x73, 0xe8, 0x01,
800x16, 0x6e, 0x4a, 0x00, 0x02, 0x49, 0x00, 0x0b, 0x9e, 0x00, 810x16, 0x6e, 0x4a, 0x00, 0x02, 0x49, 0x00, 0x0b, 0x9e, 0x00,
810x10, 0x50, 0x2a, 0x00, 0x72, 0x00, 0x53, 0x68, 0x69, 0x66, 820x10, 0x50, 0x2a, 0x00, 0x72, 0x00, 0x53, 0x68, 0x69, 0x66,
820x74, 0x2d, 0x2b, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x8c, 0x02, 830x74, 0x2d, 0x2b, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x8d, 0x02,
830x97, 0x77, 0x69, 0x74, 0x63, 0x68, 0x00, 0x6f, 0x66, 0x66, 840x97, 0x77, 0x69, 0x74, 0x63, 0x68, 0x00, 0x6f, 0x66, 0x66,
840xcb, 0x00, 0x51, 0x65, 0x70, 0x65, 0x61, 0x74, 0x55, 0x00, 850xcb, 0x00, 0x51, 0x65, 0x70, 0x65, 0x61, 0x74, 0x55, 0x00,
850x02, 0x5d, 0x01, 0x00, 0xee, 0x00, 0xf0, 0x03, 0x65, 0x72, 860x02, 0x5e, 0x01, 0x00, 0xee, 0x00, 0xf0, 0x03, 0x65, 0x72,
860x66, 0x6f, 0x72, 0x6d, 0x00, 0x69, 0x74, 0x73, 0x00, 0x69, 870x66, 0x6f, 0x72, 0x6d, 0x00, 0x69, 0x74, 0x73, 0x00, 0x69,
870x6e, 0x76, 0x65, 0x72, 0x73, 0x65, 0x63, 0x01, 0x42, 0x28, 880x6e, 0x76, 0x65, 0x72, 0x73, 0x65, 0x64, 0x01, 0x42, 0x28,
880x41, 0x6c, 0x6c, 0xc9, 0x00, 0x01, 0x2a, 0x00, 0xa0, 0x73, 890x41, 0x6c, 0x6c, 0xc9, 0x00, 0x01, 0x2a, 0x00, 0xa0, 0x73,
890x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xd3, 900x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xd4,
900x02, 0x23, 0x00, 0x73, 0x9d, 0x01, 0x40, 0x32, 0x2e, 0x31, 910x02, 0x23, 0x00, 0x73, 0x9e, 0x01, 0x40, 0x32, 0x2e, 0x31,
910x00, 0x99, 0x02, 0xf2, 0x01, 0x61, 0x6c, 0x73, 0x6f, 0x00, 920x00, 0x9a, 0x02, 0xf2, 0x01, 0x61, 0x6c, 0x73, 0x6f, 0x00,
920x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 930x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e,
930x29, 0x6e, 0x01, 0x16, 0x32, 0x6e, 0x01, 0x91, 0x70, 0x61, 940x29, 0x6e, 0x01, 0x16, 0x32, 0x6e, 0x01, 0x91, 0x70, 0x61,
940x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x70, 0x01, 0x66, 950x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x70, 0x01, 0x66,
@@ -99,15 +100,15 @@ const char help_text[] = {
990x6f, 0x6e, 0x1a, 0x00, 0xa0, 0x54, 0x79, 0x70, 0x65, 0x27, 1000x6f, 0x6e, 0x1a, 0x00, 0xa0, 0x54, 0x79, 0x70, 0x65, 0x27,
1000x00, 0x6d, 0x65, 0x6e, 0x75, 0xae, 0x00, 0x90, 0x57, 0x69, 1010x00, 0x6d, 0x65, 0x6e, 0x75, 0xae, 0x00, 0x90, 0x57, 0x69,
1010x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0xac, 0x01, 0x61, 1020x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0xac, 0x01, 0x61,
1020x00, 0x00, 0x00, 0x53, 0x69, 0x7a, 0xbf, 0x02, 0x03, 0x83, 1030x00, 0x00, 0x00, 0x53, 0x69, 0x7a, 0xc0, 0x02, 0x03, 0x84,
1030x03, 0x04, 0xd1, 0x03, 0x00, 0x2b, 0x00, 0x11, 0x52, 0x81, 1040x03, 0x04, 0xd2, 0x03, 0x00, 0x2b, 0x00, 0x11, 0x52, 0x82,
1040x03, 0x10, 0x20, 0x67, 0x03, 0x02, 0x8a, 0x00, 0x01, 0x72, 1050x03, 0x10, 0x20, 0x68, 0x03, 0x02, 0x8a, 0x00, 0x01, 0x73,
1050x03, 0x04, 0xec, 0x02, 0x03, 0x9f, 0x03, 0x02, 0xb7, 0x03, 1060x03, 0x04, 0xed, 0x02, 0x03, 0xa0, 0x03, 0x02, 0xb8, 0x03,
1060x02, 0xf6, 0x03, 0x05, 0xcb, 0x03, 0x74, 0x6d, 0x75, 0x73, 1070x02, 0xf7, 0x03, 0x05, 0xcc, 0x03, 0x74, 0x6d, 0x75, 0x73,
1070x74, 0x00, 0x62, 0x65, 0xe6, 0x03, 0x50, 0x64, 0x65, 0x64, 1080x74, 0x00, 0x62, 0x65, 0xe7, 0x03, 0x50, 0x64, 0x65, 0x64,
1080x2e, 0x00, 1090x2e, 0x00,
109}; 110};
110 111
111const unsigned short help_text_len = 1113; 112const unsigned short help_text_len = 1135;
112const unsigned short help_text_words = 192; 113const unsigned short help_text_words = 193;
113const char quick_help_text[] = "Divide the grid into equal-sized areas in accordance with the clues."; 114const char quick_help_text[] = "Divide the grid into equal-sized areas in accordance with the clues.";
diff --git a/apps/plugins/puzzles/help/pattern.c b/apps/plugins/puzzles/help/pattern.c
index 2b43a878bd..b5775f32ed 100644
--- a/apps/plugins/puzzles/help/pattern.c
+++ b/apps/plugins/puzzles/help/pattern.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,92 +6,94 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 137, TEXT_UNDERLINE }, 9 { 142, TEXT_UNDERLINE },
10 { 173, TEXT_CENTER | C_RED }, 10 { 178, TEXT_CENTER | C_RED },
11 { 362, TEXT_CENTER | C_RED }, 11 { 367, TEXT_CENTER | C_RED },
12 { 378, TEXT_UNDERLINE }, 12 { 383, TEXT_UNDERLINE },
13 { 380, TEXT_UNDERLINE }, 13 { 385, TEXT_UNDERLINE },
14 LAST_STYLE_ITEM 14 LAST_STYLE_ITEM
15}; 15};
16 16
17/* orig 2125 comp 1459 ratio 0.686588 level 4 saved 666 */ 17/* orig 2167 comp 1479 ratio 0.68251 level 4 saved 688 */
18const char help_text[] = { 18const char help_text[] = {
190xf0, 0x4f, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 190xfe, 0x07, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
200x31, 0x30, 0x3a, 0x20, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 200x31, 0x30, 0x3a, 0x20, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72,
210x6e, 0x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 210x6e, 0x20, 0x00, 0x2d, 0x01, 0x00, 0xf0, 0x3b, 0x00, 0x00,
220x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 220x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00,
230x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 230x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00,
240x73, 0x2c, 0x00, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x6d, 240x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x77,
250x75, 0x73, 0x74, 0x00, 0x61, 0x6c, 0x6c, 0x00, 0x62, 0x65, 250x68, 0x69, 0x63, 0x68, 0x00, 0x6d, 0x75, 0x73, 0x74, 0x00,
260x00, 0x66, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x00, 0x69, 0x6e, 260x61, 0x6c, 0x6c, 0x00, 0x62, 0x65, 0x00, 0x66, 0x69, 0x6c,
270x00, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x00, 0x62, 0x6c, 270x6c, 0x65, 0x64, 0x00, 0x69, 0x6e, 0x00, 0x65, 0x69, 0x74,
280x61, 0x63, 0x6b, 0x00, 0x6f, 0x72, 0x2c, 0x00, 0xf0, 0x04, 280x68, 0x65, 0x72, 0x00, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x00,
290x74, 0x65, 0x2e, 0x00, 0x42, 0x65, 0x73, 0x69, 0x64, 0x65, 290x6f, 0x72, 0x2c, 0x00, 0xf0, 0x04, 0x74, 0x65, 0x2e, 0x00,
300x00, 0x65, 0x61, 0x63, 0x68, 0x00, 0x72, 0x6f, 0x77, 0x4f, 300x42, 0x65, 0x73, 0x69, 0x64, 0x65, 0x00, 0x65, 0x61, 0x63,
310x00, 0x32, 0x74, 0x68, 0x65, 0x5b, 0x00, 0xa1, 0x61, 0x72, 310x68, 0x00, 0x72, 0x6f, 0x77, 0x4f, 0x00, 0x32, 0x74, 0x68,
320x65, 0x00, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x14, 0x00, 320x65, 0x5b, 0x00, 0xb0, 0x61, 0x72, 0x65, 0x00, 0x6c, 0x69,
330x74, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x73, 0x23, 0x00, 330x73, 0x74, 0x65, 0x64, 0x2c, 0x42, 0x00, 0x61, 0x6f, 0x72,
340x31, 0x72, 0x75, 0x6e, 0x0c, 0x00, 0x02, 0x52, 0x00, 0x03, 340x64, 0x65, 0x72, 0x2c, 0x1f, 0x00, 0x74, 0x6c, 0x65, 0x6e,
350x84, 0x00, 0x80, 0x00, 0x6f, 0x6e, 0x00, 0x74, 0x68, 0x61, 350x67, 0x74, 0x68, 0x73, 0x2e, 0x00, 0x31, 0x72, 0x75, 0x6e,
360x74, 0x4c, 0x00, 0x63, 0x3b, 0x00, 0x61, 0x62, 0x6f, 0x76, 360x0c, 0x00, 0x02, 0x5d, 0x00, 0x03, 0x8f, 0x00, 0x80, 0x00,
370x5c, 0x00, 0x6f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x53, 370x6f, 0x6e, 0x00, 0x74, 0x68, 0x61, 0x74, 0x57, 0x00, 0x63,
380x00, 0x22, 0x13, 0x69, 0x53, 0x00, 0x02, 0x43, 0x00, 0x10, 380x3b, 0x00, 0x61, 0x62, 0x6f, 0x76, 0x67, 0x00, 0x6f, 0x63,
390x2e, 0x02, 0x01, 0xb1, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 390x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5e, 0x00, 0x2d, 0x13, 0x69,
400x69, 0x73, 0x00, 0x74, 0x6f, 0xe3, 0x00, 0x02, 0x24, 0x00, 400x5e, 0x00, 0x02, 0x4e, 0x00, 0x10, 0x2e, 0x18, 0x01, 0xb1,
410x73, 0x65, 0x00, 0x65, 0x6e, 0x74, 0x69, 0x72, 0xbe, 0x00, 410x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 0x69, 0x73, 0x00, 0x74,
420x0c, 0xea, 0x00, 0xf1, 0x22, 0x00, 0x00, 0x49, 0x00, 0x66, 420x6f, 0xf9, 0x00, 0x02, 0x24, 0x00, 0x73, 0x65, 0x00, 0x65,
430x69, 0x72, 0x73, 0x74, 0x00, 0x73, 0x61, 0x77, 0x00, 0x74, 430x6e, 0x74, 0x69, 0x72, 0xd4, 0x00, 0x0c, 0x00, 0x01, 0xf1,
440x68, 0x69, 0x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 440x22, 0x00, 0x00, 0x49, 0x00, 0x66, 0x69, 0x72, 0x73, 0x74,
450x00, 0x66, 0x6f, 0x72, 0x6d, 0x00, 0x61, 0x72, 0x6f, 0x75, 450x00, 0x73, 0x61, 0x77, 0x00, 0x74, 0x68, 0x69, 0x73, 0x00,
460x6e, 0x64, 0x00, 0x31, 0x39, 0x39, 0x35, 0x2c, 0x00, 0x75, 460x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x66, 0x6f, 0x72,
470x6e, 0x64, 0x65, 0x72, 0x52, 0x00, 0xf0, 0x0f, 0x6e, 0x61, 470x6d, 0x00, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x00, 0x31,
480x6d, 0x65, 0x00, 0x60, 0x6e, 0x6f, 0x6e, 0x6f, 0x67, 0x72, 480x39, 0x39, 0x35, 0x2c, 0x00, 0x75, 0x6e, 0x64, 0x65, 0x72,
490x61, 0x6d, 0x73, 0x27, 0x2e, 0x00, 0x49, 0x27, 0x76, 0x65, 490x52, 0x00, 0xf0, 0x0f, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x60,
500x00, 0x73, 0x65, 0x65, 0x6e, 0x00, 0x69, 0x74, 0x78, 0x00, 500x6e, 0x6f, 0x6e, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x73, 0x27,
510xf0, 0x05, 0x76, 0x61, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x00, 510x2e, 0x00, 0x49, 0x27, 0x76, 0x65, 0x00, 0x73, 0x65, 0x65,
520x70, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x00, 0x73, 0x69, 0x6e, 520x6e, 0x00, 0x69, 0x74, 0x78, 0x00, 0xf0, 0x05, 0x76, 0x61,
530x63, 0x65, 0x3b, 0x00, 0x14, 0x6e, 0x47, 0x00, 0x91, 0x64, 530x72, 0x69, 0x6f, 0x75, 0x73, 0x00, 0x70, 0x6c, 0x61, 0x63,
540x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x4d, 0x00, 540x65, 0x73, 0x00, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x3b, 0x00,
550x10, 0x73, 0x8a, 0x00, 0x93, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 550x14, 0x6e, 0x47, 0x00, 0x91, 0x64, 0x69, 0x66, 0x66, 0x65,
560x6c, 0x6c, 0x79, 0x2c, 0x83, 0x00, 0x03, 0x02, 0x01, 0x00, 560x72, 0x65, 0x6e, 0x74, 0x4d, 0x00, 0x10, 0x73, 0x8a, 0x00,
570xd1, 0x00, 0xc0, 0x79, 0x70, 0x65, 0x00, 0x74, 0x75, 0x72, 570x93, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x6c, 0x79, 0x2c,
580x6e, 0x00, 0x6f, 0x75, 0x74, 0xdf, 0x00, 0x10, 0x62, 0xea, 580x83, 0x00, 0x03, 0x02, 0x01, 0x00, 0xd1, 0x00, 0xc0, 0x79,
590x01, 0xf1, 0x03, 0x6d, 0x65, 0x61, 0x6e, 0x69, 0x6e, 0x67, 590x70, 0x65, 0x00, 0x74, 0x75, 0x72, 0x6e, 0x00, 0x6f, 0x75,
600x66, 0x75, 0x6c, 0x00, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 600x74, 0xdf, 0x00, 0x10, 0x62, 0x00, 0x02, 0xf1, 0x03, 0x6d,
610x65, 0xf8, 0x01, 0xa0, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x69, 610x65, 0x61, 0x6e, 0x69, 0x6e, 0x67, 0x66, 0x75, 0x6c, 0x00,
620x6e, 0x67, 0x00, 0x6f, 0x74, 0x00, 0x31, 0x79, 0x6f, 0x75, 620x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x0e, 0x02, 0xa0,
630x9b, 0x00, 0x32, 0x6f, 0x6c, 0x76, 0x5f, 0x01, 0xb5, 0x6d, 630x6f, 0x6d, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x00, 0x6f,
640x2e, 0x00, 0x48, 0x6f, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2c, 640x74, 0x00, 0x31, 0x79, 0x6f, 0x75, 0x9b, 0x00, 0x50, 0x6f,
650x97, 0x00, 0xf1, 0x05, 0x69, 0x73, 0x00, 0x76, 0x65, 0x72, 650x6c, 0x76, 0x65, 0x64, 0x82, 0x00, 0x80, 0x6d, 0x2e, 0x00,
660x73, 0x69, 0x6f, 0x6e, 0x00, 0x67, 0x65, 0x6e, 0x65, 0x72, 660x48, 0x6f, 0x77, 0x65, 0x76, 0x6e, 0x01, 0x04, 0x97, 0x00,
670x61, 0x74, 0x65, 0x73, 0xe9, 0x00, 0x04, 0x89, 0x00, 0x92, 670xf1, 0x05, 0x69, 0x73, 0x00, 0x76, 0x65, 0x72, 0x73, 0x69,
680x61, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0xa0, 680x6f, 0x6e, 0x00, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74,
690x00, 0x60, 0x74, 0x68, 0x65, 0x79, 0x00, 0x77, 0x63, 0x01, 690x65, 0x73, 0xe9, 0x00, 0x04, 0x89, 0x00, 0x92, 0x61, 0x75,
700x10, 0x6a, 0x57, 0x02, 0xf7, 0x0b, 0x6c, 0x6f, 0x6f, 0x6b, 700x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0xa0, 0x00, 0x60,
710x00, 0x6c, 0x69, 0x6b, 0x65, 0x00, 0x72, 0x61, 0x6e, 0x64, 710x74, 0x68, 0x65, 0x79, 0x00, 0x77, 0x63, 0x01, 0x10, 0x6a,
720x6f, 0x6d, 0x00, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x6e, 720x6d, 0x02, 0xf7, 0x0b, 0x6c, 0x6f, 0x6f, 0x6b, 0x00, 0x6c,
730x67, 0x73, 0x89, 0x02, 0xf3, 0x06, 0x2e, 0x00, 0x28, 0x4f, 730x69, 0x6b, 0x65, 0x00, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d,
740x6e, 0x65, 0x00, 0x75, 0x73, 0x65, 0x72, 0x00, 0x68, 0x61, 740x00, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x6e, 0x67, 0x73,
750x73, 0x00, 0x73, 0x75, 0x67, 0x67, 0x65, 0xf4, 0x01, 0x22, 750x9f, 0x02, 0xf0, 0x06, 0x2e, 0x00, 0x28, 0x4f, 0x6e, 0x65,
760x61, 0x74, 0x85, 0x00, 0x70, 0x69, 0x73, 0x00, 0x61, 0x63, 760x00, 0x75, 0x73, 0x65, 0x72, 0x00, 0x68, 0x61, 0x73, 0x00,
770x74, 0x75, 0x65, 0x00, 0x00, 0xca, 0x02, 0x41, 0x6f, 0x6f, 770x73, 0x75, 0x67, 0x67, 0x65, 0xff, 0x01, 0x02, 0xc8, 0x01,
780x64, 0x00, 0xcb, 0x00, 0x04, 0xaa, 0x00, 0xb0, 0x69, 0x74, 780x01, 0x85, 0x00, 0x70, 0x69, 0x73, 0x00, 0x61, 0x63, 0x74,
790x00, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0xd9, 790x75, 0x65, 0x00, 0x00, 0xe0, 0x02, 0x41, 0x6f, 0x6f, 0x64,
800x00, 0x30, 0x00, 0x66, 0x72, 0x6d, 0x00, 0x40, 0x75, 0x65, 800x00, 0xcb, 0x00, 0x04, 0xaa, 0x00, 0xb0, 0x69, 0x74, 0x00,
810x73, 0x73, 0xf0, 0x00, 0x00, 0xb1, 0x00, 0x30, 0x63, 0x6f, 810x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0xd9, 0x00,
820x6c, 0x09, 0x02, 0x06, 0x77, 0x00, 0x62, 0x00, 0x62, 0x61, 820x30, 0x00, 0x66, 0x72, 0x6d, 0x00, 0x40, 0x75, 0x65, 0x73,
830x73, 0x65, 0x64, 0x82, 0x02, 0x14, 0x65, 0x28, 0x01, 0x50, 830x73, 0xf0, 0x00, 0x00, 0xb1, 0x00, 0x30, 0x63, 0x6f, 0x6c,
840x2c, 0x00, 0x61, 0x6e, 0x64, 0xe2, 0x01, 0x22, 0x63, 0x65, 840x09, 0x02, 0x06, 0x77, 0x00, 0x62, 0x00, 0x62, 0x61, 0x73,
850x49, 0x00, 0x20, 0x74, 0x6f, 0x99, 0x00, 0xf0, 0x0f, 0x00, 850x65, 0x64, 0x8d, 0x02, 0x14, 0x65, 0x28, 0x01, 0x50, 0x2c,
860x6c, 0x6f, 0x67, 0x69, 0x63, 0x00, 0x69, 0x6e, 0x73, 0x74, 860x00, 0x61, 0x6e, 0x64, 0xe2, 0x01, 0x22, 0x63, 0x65, 0x49,
870x65, 0x61, 0x64, 0x2e, 0x29, 0x00, 0x54, 0x68, 0x65, 0x00, 870x00, 0x20, 0x74, 0x6f, 0x99, 0x00, 0xf0, 0x0f, 0x00, 0x6c,
880x61, 0x64, 0x76, 0x61, 0x6e, 0x74, 0x61, 0x67, 0x65, 0xf7, 880x6f, 0x67, 0x69, 0x63, 0x00, 0x69, 0x6e, 0x73, 0x74, 0x65,
890x00, 0x51, 0x6f, 0x75, 0x67, 0x68, 0x2c, 0x63, 0x02, 0x00, 890x61, 0x64, 0x2e, 0x29, 0x00, 0x54, 0x68, 0x65, 0x00, 0x61,
900xb4, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x6e, 0x4a, 0x01, 0x00, 900x64, 0x76, 0x61, 0x6e, 0x74, 0x61, 0x67, 0x65, 0xf7, 0x00,
910xa4, 0x02, 0x01, 0x9b, 0x01, 0x23, 0x6f, 0x66, 0x63, 0x01, 910x51, 0x6f, 0x75, 0x67, 0x68, 0x2c, 0x63, 0x02, 0x00, 0xb4,
920x65, 0x00, 0x00, 0x31, 0x30, 0x2e, 0x31, 0xa3, 0x03, 0x80, 920x00, 0x00, 0x3a, 0x00, 0x10, 0x6e, 0x4a, 0x01, 0x00, 0xa4,
930x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0xac, 0x03, 930x02, 0x01, 0x9b, 0x01, 0x23, 0x6f, 0x66, 0x63, 0x01, 0x65,
940x10, 0x54, 0xea, 0x00, 0x10, 0x67, 0x42, 0x02, 0x11, 0x69, 940x00, 0x00, 0x31, 0x30, 0x2e, 0x31, 0xcd, 0x03, 0xd0, 0x63,
950x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00,
960x00, 0x54, 0xea, 0x00, 0x10, 0x67, 0x42, 0x02, 0x11, 0x69,
950x20, 0x02, 0x81, 0x79, 0x65, 0x64, 0x00, 0x77, 0x69, 0x74, 970x20, 0x02, 0x81, 0x79, 0x65, 0x64, 0x00, 0x77, 0x69, 0x74,
960x68, 0xa1, 0x00, 0x41, 0x6d, 0x6f, 0x75, 0x73, 0x97, 0x02, 980x68, 0xa1, 0x00, 0x41, 0x6d, 0x6f, 0x75, 0x73, 0x97, 0x02,
970xa0, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 990xa0, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63,
@@ -111,7 +113,7 @@ const char help_text[] = {
1110x74, 0x00, 0x67, 0x72, 0x65, 0x79, 0x00, 0x28, 0xb2, 0x02, 1130x74, 0x00, 0x67, 0x72, 0x65, 0x79, 0x00, 0x28, 0xb2, 0x02,
1120x20, 0x00, 0x60, 0x04, 0x03, 0xe3, 0x63, 0x69, 0x64, 0x65, 1140x20, 0x00, 0x60, 0x04, 0x03, 0xe3, 0x63, 0x69, 0x64, 0x65,
1130x64, 0x27, 0x29, 0x00, 0x61, 0x67, 0x61, 0x69, 0x6e, 0x2e, 1150x64, 0x27, 0x29, 0x00, 0x61, 0x67, 0x61, 0x69, 0x6e, 0x2e,
1140xc5, 0x04, 0x00, 0x91, 0x00, 0x02, 0xca, 0x00, 0x00, 0xa2, 1160xdb, 0x04, 0x00, 0x91, 0x00, 0x02, 0xca, 0x00, 0x00, 0xa2,
1150x01, 0x46, 0x64, 0x72, 0x61, 0x67, 0x1c, 0x01, 0x40, 0x6c, 1170x01, 0x46, 0x64, 0x72, 0x61, 0x67, 0x1c, 0x01, 0x40, 0x6c,
1160x65, 0x66, 0x74, 0xa0, 0x00, 0x10, 0x72, 0xf0, 0x00, 0x02, 1180x65, 0x66, 0x74, 0xa0, 0x00, 0x10, 0x72, 0xf0, 0x00, 0x02,
1170x2a, 0x01, 0x03, 0x84, 0x00, 0x07, 0x83, 0x00, 0x10, 0x61, 1190x2a, 0x01, 0x03, 0x84, 0x00, 0x07, 0x83, 0x00, 0x10, 0x61,
@@ -126,8 +128,8 @@ const char help_text[] = {
1260x6f, 0x01, 0x05, 0xa8, 0x00, 0xe9, 0x77, 0x68, 0x6f, 0x6c, 1280x6f, 0x01, 0x05, 0xa8, 0x00, 0xe9, 0x77, 0x68, 0x6f, 0x6c,
1270x65, 0x00, 0x72, 0x65, 0x63, 0x74, 0x61, 0x6e, 0x67, 0x6c, 1290x65, 0x00, 0x72, 0x65, 0x63, 0x74, 0x61, 0x6e, 0x67, 0x6c,
1280x9c, 0x00, 0x00, 0x2e, 0x01, 0x08, 0x12, 0x01, 0x60, 0x61, 1300x9c, 0x00, 0x00, 0x2e, 0x01, 0x08, 0x12, 0x01, 0x60, 0x61,
1290x6c, 0x73, 0x6f, 0x00, 0x6d, 0x37, 0x05, 0x03, 0x91, 0x04, 1310x6c, 0x73, 0x6f, 0x00, 0x6d, 0x42, 0x05, 0x03, 0x91, 0x04,
1300x05, 0x8e, 0x05, 0x05, 0x39, 0x02, 0xf7, 0x00, 0x63, 0x75, 1320x05, 0xa4, 0x05, 0x05, 0x39, 0x02, 0xf7, 0x00, 0x63, 0x75,
1310x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x73, 0x2e, 1330x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x73, 0x2e,
1320x00, 0x50, 0x72, 0x13, 0x03, 0x21, 0x72, 0x65, 0x3a, 0x04, 1340x00, 0x50, 0x72, 0x13, 0x03, 0x21, 0x72, 0x65, 0x3a, 0x04,
1330x14, 0x6b, 0xb3, 0x03, 0x54, 0x63, 0x79, 0x63, 0x6c, 0x65, 1350x14, 0x6b, 0xb3, 0x03, 0x54, 0x63, 0x79, 0x63, 0x6c, 0x65,
@@ -148,8 +150,8 @@ const char help_text[] = {
1480x6f, 0x74, 0x68, 0x3b, 0x00, 0x15, 0x6d, 0x87, 0x01, 0x21, 1500x6f, 0x74, 0x68, 0x3b, 0x00, 0x15, 0x6d, 0x87, 0x01, 0x21,
1490x28, 0x41, 0x20, 0x01, 0x10, 0x65, 0x9d, 0x04, 0xc2, 0x69, 1510x28, 0x41, 0x20, 0x01, 0x10, 0x65, 0x9d, 0x04, 0xc2, 0x69,
1500x6f, 0x6e, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 1520x6f, 0x6e, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
1510x62, 0x44, 0x07, 0x21, 0x73, 0x65, 0x16, 0x00, 0x41, 0x00, 1530x62, 0x5a, 0x07, 0x21, 0x73, 0x65, 0x16, 0x00, 0x41, 0x00,
1520x32, 0x2e, 0x31, 0xca, 0x06, 0x01, 0xad, 0x01, 0xb2, 0x61, 1540x32, 0x2e, 0x31, 0xd5, 0x06, 0x01, 0xad, 0x01, 0xb2, 0x61,
1530x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 1550x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29,
1540x0c, 0x04, 0x15, 0x32, 0x0c, 0x04, 0x93, 0x70, 0x61, 0x72, 1560x0c, 0x04, 0x15, 0x32, 0x0c, 0x04, 0x93, 0x70, 0x61, 0x72,
1550x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x0e, 0x04, 0x92, 0x65, 1570x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x0e, 0x04, 0x92, 0x65,
@@ -159,11 +161,11 @@ const char help_text[] = {
1590x27, 0x27, 0x00, 0x04, 0xd0, 0x04, 0xb1, 0x60, 0x54, 0x79, 1610x27, 0x27, 0x00, 0x04, 0xd0, 0x04, 0xb1, 0x60, 0x54, 0x79,
1600x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0x7c, 0x00, 1620x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0x7c, 0x00,
1610x31, 0x57, 0x69, 0x64, 0x9d, 0x03, 0x40, 0x64, 0x00, 0x48, 1630x31, 0x57, 0x69, 0x64, 0x9d, 0x03, 0x40, 0x64, 0x00, 0x48,
1620x65, 0x26, 0x03, 0x04, 0xfe, 0x07, 0x00, 0x1c, 0x00, 0xf0, 1640x65, 0x26, 0x03, 0x04, 0x14, 0x08, 0x00, 0x1c, 0x00, 0xf0,
1630x03, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x65, 0x78, 0x70, 0x6c, 1650x03, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x65, 0x78, 0x70, 0x6c,
1640x61, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x00, 1660x61, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x00,
165}; 167};
166 168
167const unsigned short help_text_len = 2125; 169const unsigned short help_text_len = 2167;
168const unsigned short help_text_words = 384; 170const unsigned short help_text_words = 389;
169const char quick_help_text[] = "Fill in the pattern in the grid, given only the lengths of runs of black squares."; 171const char quick_help_text[] = "Fill in the pattern in the grid, given only the lengths of runs of black squares.";
diff --git a/apps/plugins/puzzles/help/pearl.c b/apps/plugins/puzzles/help/pearl.c
index 353c541d47..b8f32ce3b8 100644
--- a/apps/plugins/puzzles/help/pearl.c
+++ b/apps/plugins/puzzles/help/pearl.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,180 +6,247 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 138, TEXT_UNDERLINE }, 9 { 139, TEXT_UNDERLINE },
10 { 164, TEXT_UNDERLINE }, 10 { 165, TEXT_UNDERLINE },
11 { 185, TEXT_UNDERLINE }, 11 { 186, TEXT_UNDERLINE },
12 { 223, TEXT_CENTER | C_RED }, 12 { 221, TEXT_CENTER | C_RED },
13 { 369, TEXT_UNDERLINE }, 13 { 367, TEXT_UNDERLINE },
14 { 460, TEXT_CENTER | C_RED }, 14 { 458, TEXT_CENTER | C_RED },
15 { 475, TEXT_UNDERLINE },
16 { 476, TEXT_UNDERLINE },
17 { 486, TEXT_UNDERLINE },
18 { 498, TEXT_UNDERLINE },
19 { 586, TEXT_CENTER | C_RED },
20 { 652, TEXT_UNDERLINE },
15 LAST_STYLE_ITEM 21 LAST_STYLE_ITEM
16}; 22};
17 23
18/* orig 2570 comp 1610 ratio 0.626459 level 10 saved 960 */ 24/* orig 3598 comp 2217 ratio 0.616176 level 10 saved 1381 */
19const char help_text[] = { 25const char help_text[] = {
200xf0, 0x21, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 260xfc, 0x05, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
210x33, 0x36, 0x3a, 0x20, 0x50, 0x65, 0x61, 0x72, 0x6c, 0x20, 270x33, 0x36, 0x3a, 0x20, 0x50, 0x65, 0x61, 0x72, 0x6c, 0x20,
220x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 280x00, 0x2d, 0x01, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x59,
230x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 290x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00,
240x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2e, 300x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71,
250x1c, 0x00, 0xf0, 0x1b, 0x72, 0x00, 0x6a, 0x6f, 0x62, 0x00, 310x75, 0x61, 0x72, 0x65, 0x73, 0x2e, 0x1c, 0x00, 0xf0, 0x1b,
260x69, 0x73, 0x00, 0x74, 0x6f, 0x00, 0x64, 0x72, 0x61, 0x77, 320x72, 0x00, 0x6a, 0x6f, 0x62, 0x00, 0x69, 0x73, 0x00, 0x74,
270x00, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x00, 0x62, 0x65, 0x74, 330x6f, 0x00, 0x64, 0x72, 0x61, 0x77, 0x00, 0x6c, 0x69, 0x6e,
280x77, 0x65, 0x65, 0x6e, 0x00, 0x74, 0x68, 0x65, 0x00, 0x63, 340x65, 0x73, 0x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e,
290x65, 0x6e, 0x74, 0x72, 0x65, 0x73, 0x3a, 0x00, 0xf1, 0x07, 350x00, 0x74, 0x68, 0x65, 0x00, 0x63, 0x65, 0x6e, 0x74, 0x72,
300x68, 0x6f, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, 360x65, 0x73, 0x3a, 0x00, 0xf1, 0x07, 0x68, 0x6f, 0x72, 0x69,
310x6c, 0x79, 0x00, 0x6f, 0x72, 0x00, 0x76, 0x65, 0x72, 0x74, 370x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x6c, 0x79, 0x00, 0x6f,
320x69, 0x63, 0x0e, 0x00, 0x40, 0x61, 0x64, 0x6a, 0x61, 0x2a, 380x72, 0x00, 0x76, 0x65, 0x72, 0x74, 0x69, 0x63, 0x0e, 0x00,
330x00, 0x04, 0x5e, 0x00, 0x91, 0x2c, 0x00, 0x73, 0x6f, 0x00, 390x40, 0x61, 0x64, 0x6a, 0x61, 0x2a, 0x00, 0x04, 0x5e, 0x00,
340x74, 0x68, 0x61, 0x74, 0x44, 0x00, 0x02, 0x56, 0x00, 0xf2, 400x91, 0x2c, 0x00, 0x73, 0x6f, 0x00, 0x74, 0x68, 0x61, 0x74,
350x0d, 0x66, 0x6f, 0x72, 0x6d, 0x00, 0x61, 0x00, 0x73, 0x69, 410x44, 0x00, 0x02, 0x56, 0x00, 0xf2, 0x0d, 0x66, 0x6f, 0x72,
360x6e, 0x67, 0x6c, 0x65, 0x00, 0x63, 0x6c, 0x6f, 0x73, 0x65, 420x6d, 0x00, 0x61, 0x00, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65,
370x64, 0x00, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x00, 0x49, 0x6c, 430x00, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x00, 0x6c, 0x6f,
380x00, 0x91, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 440x6f, 0x70, 0x2e, 0x00, 0x49, 0x6c, 0x00, 0x91, 0x72, 0x65,
390x67, 0xad, 0x00, 0x00, 0x44, 0x00, 0x20, 0x6d, 0x65, 0x79, 450x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67, 0xad, 0x00, 0x00,
400x00, 0x00, 0x1c, 0x00, 0x03, 0x59, 0x00, 0x07, 0x55, 0x00, 460x44, 0x00, 0x20, 0x6d, 0x65, 0x79, 0x00, 0x00, 0x1c, 0x00,
410x81, 0x6f, 0x6f, 0x70, 0x00, 0x70, 0x61, 0x73, 0x73, 0x15, 470x03, 0x59, 0x00, 0x07, 0x55, 0x00, 0x81, 0x6f, 0x6f, 0x70,
420x00, 0xc0, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x00, 0x77, 0x69, 480x00, 0x70, 0x61, 0x73, 0x73, 0x15, 0x00, 0xc0, 0x72, 0x6f,
430x6c, 0x6c, 0x00, 0x63, 0xa3, 0x00, 0xf2, 0x00, 0x69, 0x6e, 490x75, 0x67, 0x68, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0x00, 0x63,
440x00, 0x63, 0x6f, 0x72, 0x6e, 0x65, 0x72, 0x73, 0x2c, 0x00, 500xa3, 0x00, 0xf2, 0x00, 0x69, 0x6e, 0x00, 0x63, 0x6f, 0x72,
450x61, 0x6e, 0x64, 0x4b, 0x00, 0x01, 0x1f, 0x00, 0xb7, 0x62, 510x6e, 0x65, 0x72, 0x73, 0x2c, 0x00, 0x61, 0x6e, 0x64, 0x4b,
460x65, 0x00, 0x73, 0x74, 0x72, 0x61, 0x69, 0x67, 0x68, 0x74, 520x00, 0x01, 0x1f, 0x00, 0xb7, 0x62, 0x65, 0x00, 0x73, 0x74,
470xd2, 0x00, 0x08, 0xd0, 0x00, 0x02, 0xb0, 0x00, 0x44, 0x2e, 530x72, 0x61, 0x69, 0x67, 0x68, 0x74, 0xd2, 0x00, 0x08, 0xd0,
480x00, 0x28, 0x41, 0x39, 0x00, 0x04, 0x7d, 0x00, 0x30, 0x63, 540x00, 0x02, 0xb0, 0x00, 0x44, 0x2e, 0x00, 0x28, 0x41, 0x39,
490x61, 0x6e, 0x40, 0x00, 0xf6, 0x03, 0x63, 0x6f, 0x6d, 0x70, 550x00, 0x04, 0x7d, 0x00, 0x30, 0x63, 0x61, 0x6e, 0x40, 0x00,
500x6c, 0x65, 0x74, 0x65, 0x6c, 0x79, 0x00, 0x65, 0x6d, 0x70, 560xf6, 0x03, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65,
510x74, 0x79, 0x00, 0x2d, 0x92, 0x00, 0x72, 0x64, 0x6f, 0x65, 570x6c, 0x79, 0x00, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x00, 0x2d,
520x73, 0x6e, 0x27, 0x74, 0x76, 0x01, 0x21, 0x74, 0x6f, 0xa2, 580x92, 0x00, 0x72, 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74,
530x00, 0x05, 0xa0, 0x00, 0x53, 0x65, 0x76, 0x65, 0x72, 0x79, 590x76, 0x01, 0x21, 0x74, 0x6f, 0xa2, 0x00, 0x05, 0xa0, 0x00,
540x4e, 0x00, 0x6e, 0x2e, 0x29, 0x00, 0x00, 0x00, 0x53, 0xe2, 600x53, 0x65, 0x76, 0x65, 0x72, 0x79, 0x4e, 0x00, 0x6e, 0x2e,
550x00, 0x05, 0xc0, 0x00, 0x51, 0x62, 0x6c, 0x61, 0x63, 0x6b, 610x29, 0x00, 0x00, 0x00, 0x53, 0xe2, 0x00, 0x05, 0xc0, 0x00,
560xbd, 0x00, 0xb0, 0x77, 0x68, 0x69, 0x74, 0x65, 0x00, 0x63, 620x51, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0xbd, 0x00, 0xb0, 0x77,
570x69, 0x72, 0x63, 0x6c, 0x5b, 0x01, 0x80, 0x77, 0x68, 0x69, 630x68, 0x69, 0x74, 0x65, 0x00, 0x63, 0x69, 0x72, 0x63, 0x6c,
580x63, 0x68, 0x00, 0x61, 0x72, 0x45, 0x01, 0x1d, 0x75, 0x13, 640x5b, 0x01, 0x80, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x61,
590x01, 0xf3, 0x02, 0x6d, 0x75, 0x73, 0x74, 0x00, 0x73, 0x61, 650x72, 0x45, 0x01, 0x1d, 0x75, 0x13, 0x01, 0xf3, 0x02, 0x6d,
600x74, 0x69, 0x73, 0x66, 0x79, 0x2e, 0x00, 0x00, 0x00, 0x41, 660x75, 0x73, 0x74, 0x00, 0x73, 0x61, 0x74, 0x69, 0x73, 0x66,
610x49, 0x00, 0x02, 0x3f, 0x00, 0x53, 0x00, 0x69, 0x6e, 0x00, 670x79, 0x2e, 0x00, 0x00, 0x00, 0x41, 0x49, 0x00, 0x02, 0x3f,
620x61, 0x6b, 0x00, 0x86, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x63, 680x00, 0x53, 0x00, 0x69, 0x6e, 0x00, 0x61, 0x6b, 0x00, 0x86,
630x61, 0x74, 0x43, 0x00, 0x14, 0x61, 0xc1, 0x01, 0x00, 0x14, 690x00, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x43, 0x00,
640x02, 0x13, 0x61, 0x42, 0x01, 0xdc, 0x2c, 0x00, 0x62, 0x75, 700x14, 0x61, 0xc1, 0x01, 0x00, 0x14, 0x02, 0x13, 0x61, 0x42,
650x74, 0x00, 0x6e, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0xad, 710x01, 0xdc, 0x2c, 0x00, 0x62, 0x75, 0x74, 0x00, 0x6e, 0x65,
660x00, 0x05, 0xf9, 0x01, 0x50, 0x74, 0x6f, 0x00, 0x69, 0x74, 720x69, 0x74, 0x68, 0x65, 0x72, 0xad, 0x00, 0x05, 0xf9, 0x01,
670x5e, 0x00, 0x05, 0x89, 0x00, 0x00, 0x43, 0x00, 0x35, 0x6c, 730x50, 0x74, 0x6f, 0x00, 0x69, 0x74, 0x5e, 0x00, 0x05, 0x89,
680x73, 0x6f, 0x48, 0x00, 0x02, 0x8d, 0x00, 0x08, 0xcc, 0x00, 740x00, 0x00, 0x43, 0x00, 0x35, 0x6c, 0x73, 0x6f, 0x48, 0x00,
690x0e, 0x81, 0x00, 0x19, 0x65, 0x80, 0x00, 0x05, 0xa8, 0x01, 750x02, 0x8d, 0x00, 0x08, 0xcc, 0x00, 0x0e, 0x81, 0x00, 0x19,
700x42, 0x65, 0x64, 0x67, 0x65, 0x87, 0x00, 0xcf, 0x61, 0x74, 760x65, 0x80, 0x00, 0x05, 0xa8, 0x01, 0x42, 0x65, 0x64, 0x67,
710x20, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x20, 0x6f, 0x6e, 0x65, 770x65, 0x87, 0x00, 0xcf, 0x61, 0x74, 0x20, 0x6c, 0x65, 0x61,
720x8c, 0x00, 0x1c, 0x07, 0x87, 0x00, 0xc0, 0x28, 0x49, 0x6e, 780x73, 0x74, 0x20, 0x6f, 0x6e, 0x65, 0x8c, 0x00, 0x1c, 0x07,
730x00, 0x62, 0x6f, 0x74, 0x68, 0x00, 0x63, 0x61, 0x73, 0x52, 790x87, 0x00, 0xc0, 0x28, 0x49, 0x6e, 0x00, 0x62, 0x6f, 0x74,
740x01, 0x22, 0x74, 0x68, 0x4c, 0x01, 0x50, 0x00, 0x6f, 0x6e, 800x68, 0x00, 0x63, 0x61, 0x73, 0x52, 0x01, 0x22, 0x74, 0x68,
750x6c, 0x79, 0x81, 0x01, 0x01, 0x7a, 0x00, 0x21, 0x6e, 0x73, 810x4c, 0x01, 0x50, 0x00, 0x6f, 0x6e, 0x6c, 0x79, 0x81, 0x01,
760x19, 0x00, 0x3e, 0x74, 0x77, 0x6f, 0x63, 0x00, 0x70, 0x69, 820x01, 0x7a, 0x00, 0x21, 0x6e, 0x73, 0x19, 0x00, 0x3e, 0x74,
770x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x5d, 0x00, 0x12, 0x2c, 830x77, 0x6f, 0x63, 0x00, 0x70, 0x69, 0x6e, 0x20, 0x74, 0x68,
780xbd, 0x00, 0x3f, 0x69, 0x73, 0x2c, 0xa9, 0x02, 0x0f, 0xf0, 840x65, 0x20, 0x5d, 0x00, 0x12, 0x2c, 0xbd, 0x00, 0x3f, 0x69,
790x00, 0x69, 0x6e, 0x74, 0x6f, 0x00, 0x61, 0x66, 0x74, 0x65, 850x73, 0x2c, 0xa9, 0x02, 0x0f, 0xf0, 0x00, 0x69, 0x6e, 0x74,
800x72, 0x00, 0x6c, 0x65, 0x61, 0x76, 0xeb, 0x02, 0x05, 0x7c, 860x6f, 0x00, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, 0x6c, 0x65,
810x00, 0x03, 0x17, 0x02, 0x2c, 0x00, 0x54, 0x45, 0x00, 0x23, 870x61, 0x76, 0xeb, 0x02, 0x05, 0x7c, 0x00, 0x03, 0x17, 0x02,
820x61, 0x72, 0x99, 0x00, 0x0c, 0x7e, 0x00, 0x01, 0xd3, 0x03, 880x2c, 0x00, 0x54, 0x45, 0x00, 0x23, 0x61, 0x72, 0x99, 0x00,
830x00, 0x1e, 0x00, 0x36, 0x6e, 0x6f, 0x74, 0xb6, 0x00, 0x21, 890x0c, 0x7e, 0x00, 0x01, 0xd3, 0x03, 0x00, 0x1e, 0x00, 0x36,
840x65, 0x64, 0x5b, 0x02, 0x60, 0x43, 0x72, 0x65, 0x64, 0x69, 900x6e, 0x6f, 0x74, 0xb6, 0x00, 0x21, 0x65, 0x64, 0x5b, 0x02,
850x74, 0x76, 0x03, 0xf1, 0x01, 0x00, 0x74, 0x68, 0x69, 0x73, 910x60, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x76, 0x03, 0xf1,
860x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x67, 0x6f, 920x01, 0x00, 0x74, 0x68, 0x69, 0x73, 0x00, 0x70, 0x75, 0x7a,
870x65, 0xef, 0x03, 0x60, 0x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69, 930x7a, 0x6c, 0x65, 0x00, 0x67, 0x6f, 0x65, 0xef, 0x03, 0x60,
880x4d, 0x02, 0x20, 0x6f, 0x00, 0xc4, 0x03, 0x00, 0x32, 0x01, 940x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69, 0x4d, 0x02, 0x20, 0x6f,
890xf1, 0x06, 0x60, 0x4d, 0x61, 0x73, 0x79, 0x75, 0x27, 0x2e, 950x00, 0xc4, 0x03, 0x00, 0x32, 0x01, 0xf1, 0x06, 0x60, 0x4d,
900x00, 0x5b, 0x31, 0x39, 0x5d, 0x00, 0x00, 0x00, 0x54, 0x68, 960x61, 0x73, 0x79, 0x75, 0x27, 0x2e, 0x00, 0x5b, 0x31, 0x39,
910x61, 0x6e, 0x6b, 0x2e, 0x00, 0xc1, 0x4a, 0x61, 0x6d, 0x65, 970x5d, 0x00, 0x00, 0x00, 0x54, 0x68, 0x61, 0x6e, 0x6b, 0x2e,
920x73, 0x00, 0x48, 0x61, 0x72, 0x76, 0x65, 0x79, 0x53, 0x00, 980x00, 0xc1, 0x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61,
930x90, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 990x72, 0x76, 0x65, 0x79, 0x53, 0x00, 0x90, 0x61, 0x73, 0x73,
940x56, 0x03, 0x21, 0x74, 0x68, 0xc6, 0x00, 0x10, 0x69, 0x16, 1000x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x56, 0x03, 0x21, 0x74,
950x03, 0x90, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 1010x68, 0xc6, 0x00, 0x10, 0x69, 0x16, 0x03, 0x90, 0x6d, 0x65,
960x6e, 0x68, 0x01, 0x01, 0x48, 0x00, 0xc1, 0x68, 0x74, 0x74, 1020x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x68, 0x01, 0x01,
970x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 0x75, 1030x48, 0x00, 0xd1, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f,
980x00, 0xa2, 0x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f, 0x65, 1040x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 0x76, 0x00, 0xa2, 0x2e,
990x6e, 0x2f, 0x94, 0x00, 0x30, 0x73, 0x2f, 0x6d, 0x78, 0x00, 1050x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f, 0x65, 0x6e, 0x2f, 0x95,
1000xc1, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x00, 0x28, 0x62, 0x65, 1060x00, 0x30, 0x73, 0x2f, 0x6d, 0x79, 0x00, 0x83, 0x2f, 0x00,
1010x77, 0x61, 0x72, 0xdc, 0x01, 0x50, 0x46, 0x6c, 0x61, 0x73, 1070x00, 0x00, 0x33, 0x36, 0x2e, 0x31, 0xd1, 0x04, 0x00, 0x08,
1020x68, 0xcb, 0x00, 0x43, 0x33, 0x36, 0x2e, 0x31, 0xd4, 0x04, 1080x03, 0x50, 0x72, 0x6f, 0x6c, 0x73, 0x20, 0xcd, 0x00, 0x46,
1030x00, 0x1d, 0x03, 0x50, 0x72, 0x6f, 0x6c, 0x73, 0x20, 0xe2, 1090x6c, 0x69, 0x63, 0x6b, 0x6a, 0x00, 0x40, 0x6c, 0x65, 0x66,
1040x00, 0x46, 0x6c, 0x69, 0x63, 0x6b, 0x7f, 0x00, 0x40, 0x6c, 1100x74, 0x0f, 0x02, 0x64, 0x74, 0x6f, 0x6e, 0x00, 0x6f, 0x6e,
1050x65, 0x66, 0x74, 0x24, 0x02, 0x64, 0x74, 0x6f, 0x6e, 0x00, 1110xdd, 0x04, 0x00, 0x26, 0x02, 0x05, 0xca, 0x04, 0x50, 0x61,
1060x6f, 0x6e, 0xf2, 0x04, 0x00, 0x3b, 0x02, 0x05, 0xdf, 0x04, 1120x00, 0x73, 0x65, 0x67, 0x8d, 0x00, 0x04, 0x26, 0x02, 0x01,
1070x50, 0x61, 0x00, 0x73, 0x65, 0x67, 0xa2, 0x00, 0x04, 0x3b, 1130x87, 0x01, 0x04, 0x89, 0x03, 0x01, 0x58, 0x01, 0x02, 0x56,
1080x02, 0x01, 0x9c, 0x01, 0x04, 0x9e, 0x03, 0x01, 0x6d, 0x01, 1140x02, 0x20, 0x6f, 0x72, 0x34, 0x00, 0x68, 0x72, 0x65, 0x6d,
1090x02, 0x6b, 0x02, 0x20, 0x6f, 0x72, 0x34, 0x00, 0x68, 0x72, 1150x6f, 0x76, 0x65, 0x36, 0x00, 0x00, 0xdb, 0x00, 0x10, 0x69,
1100x65, 0x6d, 0x6f, 0x76, 0x65, 0x36, 0x00, 0x00, 0xf0, 0x00, 1160xd7, 0x01, 0x01, 0x50, 0x00, 0x01, 0xcf, 0x00, 0x4f, 0x44,
1110x10, 0x69, 0xec, 0x01, 0x01, 0x50, 0x00, 0x01, 0xe4, 0x00, 1170x72, 0x61, 0x67, 0x85, 0x00, 0x03, 0x04, 0x58, 0x00, 0x00,
1120x4f, 0x44, 0x72, 0x61, 0x67, 0x85, 0x00, 0x03, 0x04, 0x58, 1180x40, 0x00, 0x47, 0x72, 0x69, 0x65, 0x73, 0x69, 0x05, 0x05,
1130x00, 0x00, 0x40, 0x00, 0x47, 0x72, 0x69, 0x65, 0x73, 0x7e, 1190x92, 0x00, 0x40, 0x6d, 0x6f, 0x72, 0x65, 0x79, 0x00, 0x00,
1140x05, 0x05, 0x92, 0x00, 0x40, 0x6d, 0x6f, 0x72, 0x65, 0x79, 1200xb3, 0x00, 0x1f, 0x65, 0x9e, 0x00, 0x02, 0x12, 0x69, 0x1b,
1150x00, 0x00, 0xb3, 0x00, 0x1f, 0x65, 0x9e, 0x00, 0x02, 0x12, 1210x00, 0xf0, 0x05, 0x67, 0x6f, 0x2e, 0x00, 0x41, 0x6c, 0x74,
1160x69, 0x1b, 0x00, 0xf0, 0x05, 0x67, 0x6f, 0x2e, 0x00, 0x41, 1220x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x6c, 0x79,
1170x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 1230x2c, 0x00, 0x64, 0x7a, 0x00, 0xc1, 0x6f, 0x76, 0x65, 0x72,
1180x6c, 0x79, 0x2c, 0x00, 0x64, 0x7a, 0x00, 0xc1, 0x6f, 0x76, 1240x00, 0x61, 0x6e, 0x00, 0x65, 0x78, 0x69, 0x73, 0x26, 0x05,
1190x65, 0x72, 0x00, 0x61, 0x6e, 0x00, 0x65, 0x78, 0x69, 0x73, 1250x3b, 0x70, 0x61, 0x72, 0xdf, 0x00, 0x41, 0x6f, 0x00, 0x75,
1200x3b, 0x05, 0x3b, 0x70, 0x61, 0x72, 0xdf, 0x00, 0x41, 0x6f, 1260x6e, 0x6d, 0x00, 0x24, 0x69, 0x74, 0xda, 0x00, 0x03, 0x11,
1210x00, 0x75, 0x6e, 0x6d, 0x00, 0x24, 0x69, 0x74, 0xda, 0x00, 1270x00, 0x04, 0x2c, 0x00, 0x21, 0x69, 0x74, 0x53, 0x04, 0x72,
1220x03, 0x11, 0x00, 0x04, 0x2c, 0x00, 0x21, 0x69, 0x74, 0x68, 1280x74, 0x68, 0x65, 0x6e, 0x00, 0x67, 0x6f, 0x0f, 0x04, 0x60,
1230x04, 0x72, 0x74, 0x68, 0x65, 0x6e, 0x00, 0x67, 0x6f, 0x24, 1290x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x8e, 0x00, 0x54, 0x64,
1240x04, 0x60, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x8e, 0x00, 1300x69, 0x72, 0x65, 0x63, 0xbe, 0x01, 0x0b, 0x75, 0x01, 0x11,
1250x54, 0x64, 0x69, 0x72, 0x65, 0x63, 0xd3, 0x01, 0x0b, 0x75, 1310x72, 0x8b, 0x03, 0x0f, 0x76, 0x01, 0x06, 0x40, 0x6d, 0x61,
1260x01, 0x11, 0x72, 0xa0, 0x03, 0x0f, 0x76, 0x01, 0x06, 0x40, 1320x72, 0x6b, 0x5e, 0x00, 0x01, 0x30, 0x00, 0x84, 0x61, 0x00,
1270x6d, 0x61, 0x72, 0x6b, 0x5e, 0x00, 0x01, 0x30, 0x00, 0x84, 1330x63, 0x72, 0x6f, 0x73, 0x73, 0x2c, 0xe2, 0x03, 0x02, 0xe9,
1280x61, 0x00, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x2c, 0xf7, 0x03, 1340x02, 0x61, 0x61, 0x74, 0x00, 0x79, 0x6f, 0x75, 0xb2, 0x02,
1290x02, 0xfe, 0x02, 0x61, 0x61, 0x74, 0x00, 0x79, 0x6f, 0x75, 1350x4a, 0x73, 0x75, 0x72, 0x65, 0x35, 0x05, 0x01, 0xc5, 0x02,
1300xc7, 0x02, 0x4a, 0x73, 0x75, 0x72, 0x65, 0x4a, 0x05, 0x01, 1360x2e, 0x67, 0x6f, 0xa3, 0x01, 0x92, 0x2e, 0x00, 0x28, 0x46,
1310xda, 0x02, 0x2e, 0x67, 0x6f, 0xa3, 0x01, 0x92, 0x2e, 0x00, 1370x6f, 0x72, 0x00, 0x69, 0x6e, 0x70, 0x02, 0x64, 0x2c, 0x00,
1320x28, 0x46, 0x6f, 0x72, 0x00, 0x69, 0x6e, 0x85, 0x02, 0x64, 1380x69, 0x66, 0x00, 0x79, 0xd8, 0x06, 0x73, 0x64, 0x65, 0x63,
1330x2c, 0x00, 0x69, 0x66, 0x00, 0x79, 0xed, 0x06, 0x73, 0x64, 1390x69, 0x64, 0x65, 0x64, 0x14, 0x05, 0x0f, 0x11, 0x04, 0x08,
1340x65, 0x63, 0x69, 0x64, 0x65, 0x64, 0x29, 0x05, 0x0f, 0x26, 1400x14, 0x61, 0x7a, 0x04, 0x00, 0x6b, 0x03, 0x21, 0x68, 0x61,
1350x04, 0x08, 0x14, 0x61, 0x8f, 0x04, 0x00, 0x80, 0x03, 0x21, 1410x97, 0x01, 0x2b, 0x62, 0x65, 0xe5, 0x04, 0x20, 0x64, 0x6f,
1360x68, 0x61, 0x97, 0x01, 0x2b, 0x62, 0x65, 0xfa, 0x04, 0x20, 1420xbb, 0x05, 0x83, 0x79, 0x65, 0x74, 0x00, 0x6b, 0x6e, 0x6f,
1370x64, 0x6f, 0xd0, 0x05, 0x83, 0x79, 0x65, 0x74, 0x00, 0x6b, 1430x77, 0x55, 0x00, 0x32, 0x77, 0x61, 0x79, 0xa5, 0x03, 0x01,
1380x6e, 0x6f, 0x77, 0x55, 0x00, 0x32, 0x77, 0x61, 0x79, 0xba, 1440x29, 0x00, 0x71, 0x00, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2c,
1390x03, 0x01, 0x29, 0x00, 0x71, 0x00, 0x74, 0x75, 0x72, 0x6e, 1450x82, 0x00, 0x11, 0x6d, 0x12, 0x01, 0x01, 0xf9, 0x00, 0x00,
1400x73, 0x2c, 0x82, 0x00, 0x11, 0x6d, 0x12, 0x01, 0x01, 0xf9, 1460x21, 0x00, 0x00, 0xbc, 0x01, 0x00, 0x2d, 0x00, 0x20, 0x69,
1410x00, 0x00, 0x21, 0x00, 0x00, 0xbc, 0x01, 0x00, 0x2d, 0x00, 1470x74, 0x29, 0x06, 0x11, 0x27, 0xce, 0x00, 0x08, 0x0e, 0x01,
1420x20, 0x69, 0x74, 0x3e, 0x06, 0x11, 0x27, 0xce, 0x00, 0x08, 1480x01, 0x97, 0x03, 0x0b, 0xd9, 0x01, 0x32, 0x75, 0x73, 0x65,
1430x0e, 0x01, 0x01, 0xac, 0x03, 0x0b, 0xd9, 0x01, 0x32, 0x75, 1490x5d, 0x00, 0x91, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x00, 0x6b,
1440x73, 0x65, 0x5d, 0x00, 0x91, 0x75, 0x72, 0x73, 0x6f, 0x72, 1500x65, 0x79, 0x9a, 0x00, 0x01, 0x8d, 0x02, 0x06, 0x18, 0x00,
1450x00, 0x6b, 0x65, 0x79, 0x9a, 0x00, 0x01, 0x8d, 0x02, 0x06, 1510x33, 0x2e, 0x00, 0x55, 0x28, 0x00, 0x41, 0x45, 0x6e, 0x74,
1460x18, 0x00, 0x33, 0x2e, 0x00, 0x55, 0x28, 0x00, 0x41, 0x45, 1520x65, 0x27, 0x00, 0x02, 0xc0, 0x00, 0x31, 0x67, 0x69, 0x6e,
1470x6e, 0x74, 0x65, 0x27, 0x00, 0x02, 0xc0, 0x00, 0x31, 0x67, 1530xcf, 0x01, 0x30, 0x65, 0x6e, 0x64, 0x15, 0x00, 0x70, 0x62,
1480x69, 0x6e, 0xcf, 0x01, 0x30, 0x65, 0x6e, 0x64, 0x15, 0x00, 1540x6f, 0x61, 0x72, 0x64, 0x00, 0x60, 0x2e, 0x02, 0x61, 0x27,
1490x70, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x00, 0x60, 0x2e, 0x02, 1550x00, 0x6f, 0x70, 0x65, 0x72, 0x8a, 0x03, 0x16, 0x73, 0x3f,
1500x61, 0x27, 0x00, 0x6f, 0x70, 0x65, 0x72, 0x9f, 0x03, 0x16, 1560x00, 0x30, 0x53, 0x70, 0x61, 0x42, 0x01, 0x60, 0x45, 0x73,
1510x73, 0x3f, 0x00, 0x30, 0x53, 0x70, 0x61, 0x42, 0x01, 0x60, 1570x63, 0x61, 0x70, 0x65, 0x21, 0x02, 0x50, 0x42, 0x61, 0x63,
1520x45, 0x73, 0x63, 0x61, 0x70, 0x65, 0x21, 0x02, 0x50, 0x42, 1580x6b, 0x73, 0x15, 0x00, 0x05, 0x7b, 0x00, 0x10, 0x63, 0x65,
1530x61, 0x63, 0x6b, 0x73, 0x15, 0x00, 0x05, 0x7b, 0x00, 0x10, 1590x01, 0x11, 0x6c, 0x2e, 0x00, 0x00, 0x48, 0x00, 0xc2, 0x2e,
1540x63, 0x65, 0x01, 0x11, 0x6c, 0x2e, 0x00, 0x00, 0x48, 0x00, 1600x00, 0x4f, 0x72, 0x2c, 0x00, 0x68, 0x6f, 0x6c, 0x64, 0x00,
1550xc2, 0x2e, 0x00, 0x4f, 0x72, 0x2c, 0x00, 0x68, 0x6f, 0x6c, 1610x43, 0x91, 0x03, 0x00, 0x17, 0x01, 0x12, 0x6c, 0x1d, 0x00,
1560x64, 0x00, 0x43, 0x91, 0x03, 0x00, 0x17, 0x01, 0x12, 0x6c, 1620x37, 0x67, 0x69, 0x6e, 0x11, 0x03, 0x0b, 0xc4, 0x00, 0x55,
1570x1d, 0x00, 0x37, 0x67, 0x69, 0x6e, 0x11, 0x03, 0x0b, 0xc4, 1630x74, 0x6f, 0x67, 0x67, 0x6c, 0xe9, 0x02, 0x42, 0x73, 0x00,
1580x00, 0x55, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0xe9, 0x02, 0x42, 1640x61, 0x73, 0x35, 0x01, 0x00, 0xdb, 0x00, 0x04, 0x62, 0x08,
1590x73, 0x00, 0x61, 0x73, 0x35, 0x01, 0x00, 0xdb, 0x00, 0x04, 1650x05, 0x8d, 0x08, 0x60, 0x00, 0x00, 0x50, 0x72, 0x65, 0x73,
1600x77, 0x08, 0x05, 0xa2, 0x08, 0x60, 0x00, 0x00, 0x50, 0x72, 1660x1c, 0x08, 0x04, 0x67, 0x00, 0xe1, 0x2d, 0x53, 0x68, 0x69,
1610x65, 0x73, 0x31, 0x08, 0x04, 0x67, 0x00, 0xe1, 0x2d, 0x53, 1670x66, 0x74, 0x2d, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x6b, 0x65,
1620x68, 0x69, 0x66, 0x74, 0x2d, 0x61, 0x72, 0x72, 0x6f, 0x77, 1680x71, 0x08, 0x0b, 0x12, 0x00, 0x51, 0x73, 0x69, 0x6d, 0x75,
1630x6b, 0x65, 0x86, 0x08, 0x0b, 0x12, 0x00, 0x51, 0x73, 0x69, 1690x6c, 0x3e, 0x06, 0x12, 0x61, 0x8d, 0x03, 0x23, 0x6f, 0x72,
1640x6d, 0x75, 0x6c, 0x53, 0x06, 0x12, 0x61, 0x8d, 0x03, 0x23, 1700xa5, 0x02, 0x10, 0x63, 0xba, 0x02, 0x10, 0x2c, 0x50, 0x08,
1650x6f, 0x72, 0xa5, 0x02, 0x10, 0x63, 0xba, 0x02, 0x10, 0x2c, 1710x34, 0x70, 0x65, 0x63, 0x6b, 0x01, 0x12, 0x6f, 0x10, 0x06,
1660x65, 0x08, 0x34, 0x70, 0x65, 0x63, 0x6b, 0x01, 0x12, 0x6f, 1720x01, 0xb0, 0x02, 0x03, 0x1c, 0x06, 0x05, 0xef, 0x02, 0x04,
1670x25, 0x06, 0x01, 0xb0, 0x02, 0x03, 0x31, 0x06, 0x05, 0xef, 1730x3a, 0x02, 0x31, 0x6b, 0x65, 0x79, 0x20, 0x06, 0x22, 0x41,
1680x02, 0x04, 0x3a, 0x02, 0x31, 0x6b, 0x65, 0x79, 0x35, 0x06, 1740x6c, 0x02, 0x01, 0x21, 0x61, 0x63, 0x41, 0x01, 0xa0, 0x00,
1690x22, 0x41, 0x6c, 0x02, 0x01, 0x21, 0x61, 0x63, 0x41, 0x01, 1750x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x3a,
1700xa0, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 1760x00, 0x13, 0x73, 0x34, 0x00, 0x31, 0x32, 0x2e, 0x31, 0xcc,
1710x64, 0x3a, 0x00, 0x13, 0x73, 0x34, 0x00, 0x31, 0x32, 0x2e, 1770x02, 0x02, 0xe6, 0x06, 0x72, 0x76, 0x61, 0x69, 0x6c, 0x61,
1720x31, 0xcc, 0x02, 0x02, 0xfb, 0x06, 0x93, 0x76, 0x61, 0x69, 1780x62, 0x6c, 0xd8, 0x07, 0x43, 0x33, 0x36, 0x2e, 0x32, 0xc7,
1730x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0xc7, 0x04, 0x13, 0x32, 1790x04, 0xb1, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
1740xc7, 0x04, 0xb1, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 1800x72, 0x73, 0x20, 0x53, 0x05, 0x46, 0x65, 0x73, 0x65, 0x00,
1750x65, 0x72, 0x73, 0x20, 0x68, 0x05, 0x46, 0x65, 0x73, 0x65, 1810x14, 0x00, 0x02, 0x41, 0x00, 0x04, 0x3c, 0x00, 0x51, 0x00,
1760x00, 0x14, 0x00, 0x02, 0x41, 0x00, 0x04, 0x3c, 0x00, 0x51, 1820x66, 0x72, 0x6f, 0x6d, 0x79, 0x00, 0xa0, 0x60, 0x43, 0x75,
1770x00, 0x66, 0x72, 0x6f, 0x6d, 0x79, 0x00, 0xa0, 0x60, 0x43, 1830x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0xc9, 0x01, 0x02,
1780x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0xc9, 0x01, 1840xa3, 0x00, 0x12, 0x6e, 0x1a, 0x00, 0xa0, 0x54, 0x79, 0x70,
1790x02, 0xa3, 0x00, 0x12, 0x6e, 0x1a, 0x00, 0xc0, 0x54, 0x79, 1850x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xab, 0x00, 0x91,
1800x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0x2e, 0x00, 1860x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0xf9,
1870x00, 0x51, 0x00, 0x00, 0x53, 0x69, 0x7a, 0x19, 0x07, 0x01,
1880x9c, 0x03, 0x19, 0x69, 0x62, 0x01, 0xa0, 0x44, 0x69, 0x66,
1890x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0xdd, 0x03, 0x03,
1900x5e, 0x05, 0x03, 0x08, 0x01, 0x05, 0x1a, 0x00, 0x03, 0x09,
1910x01, 0x30, 0x67, 0x65, 0x6e, 0x3e, 0x02, 0x23, 0x65, 0x64,
1920x38, 0x06, 0x11, 0x2e, 0xbb, 0x02, 0xa0, 0x6c, 0x6f, 0x77,
1930x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x75, 0xad, 0x00, 0x42,
1940x00, 0x00, 0x49, 0x66, 0x5c, 0x06, 0x72, 0x69, 0x73, 0x00,
1950x73, 0x65, 0x74, 0x2c, 0x56, 0x04, 0x01, 0x3f, 0x00, 0x17,
1960x61, 0x6f, 0x09, 0x06, 0x4c, 0x00, 0x03, 0x77, 0x01, 0x11,
1970x73, 0x2a, 0x06, 0x20, 0x73, 0x74, 0x2e, 0x03, 0x13, 0x3a,
1980x15, 0x09, 0x07, 0x03, 0x07, 0x02, 0xfb, 0x03, 0x00, 0x6c,
1990x09, 0x80, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x79,
2000x46, 0x00, 0x42, 0x70, 0x72, 0x6f, 0x76, 0xeb, 0x03, 0x04,
2010xc6, 0x09, 0x42, 0x68, 0x6f, 0x77, 0x6e, 0xde, 0x09, 0x07,
2020xb2, 0x00, 0x22, 0x6f, 0x72, 0x21, 0x00, 0x01, 0x13, 0x07,
2030x20, 0x68, 0x65, 0xc1, 0x04, 0x21, 0x68, 0x65, 0xba, 0x08,
2040x00, 0x25, 0x00, 0x03, 0x05, 0x07, 0x03, 0xc8, 0x09, 0x50,
2050x75, 0x6e, 0x69, 0x71, 0x75, 0xc6, 0x09, 0x71, 0x73, 0x6f,
2060x6c, 0x76, 0x65, 0x64, 0x2e, 0xa0, 0x01, 0x00, 0xcc, 0x00,
2070x82, 0x70, 0x65, 0x65, 0x64, 0x73, 0x00, 0x75, 0x70, 0xc8,
2080x00, 0x03, 0x5a, 0x00, 0x23, 0x69, 0x6f, 0x6e, 0x00, 0x10,
2090x61, 0x08, 0x01, 0xd1, 0x73, 0x00, 0x6d, 0x75, 0x63, 0x68,
2100x00, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x6e, 0x01, 0x04,
2110x53, 0x04, 0x40, 0x70, 0x6c, 0x61, 0x79, 0x4d, 0x00, 0x31,
2120x41, 0x74, 0x00, 0xab, 0x08, 0x01, 0x18, 0x04, 0x03, 0xca,
2130x00, 0x20, 0x65, 0x00, 0x3d, 0x01, 0x01, 0xcf, 0x01, 0x01,
2140xa6, 0x00, 0x20, 0x73, 0x74, 0x06, 0x00, 0x62, 0x61, 0x6c,
2150x77, 0x61, 0x79, 0x73, 0xd8, 0x05, 0x02, 0x89, 0x04, 0x00,
2160xb1, 0x00, 0x20, 0x65, 0x27, 0x14, 0x05, 0xa3, 0x00, 0x67,
2170x75, 0x61, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x67, 0x08,
2180x15, 0x74, 0x01, 0x01, 0x02, 0xbf, 0x00, 0x02, 0xe8, 0x05,
2190x0b, 0x1b, 0x00, 0x05, 0x6f, 0x00, 0x00, 0x7d, 0x06, 0x32,
2200x65, 0x64, 0x75, 0xcc, 0x06, 0x71, 0x73, 0x74, 0x65, 0x70,
2210x00, 0x62, 0x79, 0x08, 0x00, 0x12, 0x2e, 0xa6, 0x02, 0x13,
2220x33, 0xa6, 0x02, 0x81, 0x75, 0x73, 0x65, 0x72, 0x20, 0x70,
2230x72, 0x65, 0x08, 0x06, 0x21, 0x63, 0x65, 0xac, 0x02, 0x20,
2240x4f, 0x6e, 0xcc, 0x00, 0x10, 0x74, 0xb8, 0x0b, 0x13, 0x73,
2250x1d, 0x0a, 0x70, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x00,
2260x2e, 0x00, 0x17, 0x00, 0x2e, 0x00, 0x12, 0x2c, 0x9a, 0x02,
2270x16, 0x50, 0x12, 0x00, 0x0d, 0xb6, 0x02, 0x33, 0x47, 0x61,
2280x6d, 0xb6, 0x02, 0x02, 0xa5, 0x00, 0x22, 0x6c, 0x65, 0x0d,
2290x06, 0x64, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x0e, 0x06,
2300x45, 0x73, 0x74, 0x79, 0x6c, 0xd8, 0x09, 0x01, 0x7d, 0x01,
2310x30, 0x64, 0x69, 0x73, 0x51, 0x01, 0x80, 0x2e, 0x00, 0x60,
2320x54, 0x72, 0x61, 0x64, 0x69, 0x54, 0x00, 0x53, 0x61, 0x6c,
2330x27, 0x00, 0x69, 0xb9, 0x02, 0xb0, 0x65, 0x66, 0x61, 0x75,
2340x6c, 0x74, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0x6d, 0x06, 0x03,
2350xb3, 0x05, 0x05, 0x59, 0x06, 0x36, 0x72, 0x75, 0x6e, 0xcf,
2360x0c, 0x07, 0xcb, 0x0c, 0x01, 0x1e, 0x03, 0x05, 0xac, 0x0c,
2370x01, 0x42, 0x05, 0x33, 0x61, 0x63, 0x68, 0x04, 0x0a, 0x51,
2380x63, 0x63, 0x75, 0x70, 0x69, 0x56, 0x04, 0x04, 0x93, 0x09,
2390x71, 0x60, 0x4c, 0x6f, 0x6f, 0x70, 0x79, 0x2d, 0x9e, 0x00,
2400x11, 0x27, 0x4d, 0x0a, 0x36, 0x6e, 0x00, 0x61, 0xc9, 0x05,
2410x01, 0x7f, 0x00, 0x02, 0x22, 0x01, 0x52, 0x6c, 0x6f, 0x6f,
2420x6b, 0x73, 0xeb, 0x07, 0x51, 0x6c, 0x69, 0x6b, 0x65, 0x00,
2430x39, 0x00, 0x32, 0x00, 0x28, 0x63, 0xaf, 0x0d, 0x4f, 0x00,
2440x32, 0x33, 0x29, 0xa7, 0x00, 0x0e, 0x01, 0x9c, 0x00, 0x02,
2450x8c, 0x0c, 0x04, 0x9d, 0x00, 0x04, 0x24, 0x0a, 0x03, 0x52,
2460x0b, 0x01, 0xa2, 0x00, 0xc0, 0x79, 0x00, 0x76, 0x65, 0x72,
2470x74, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x00,
181}; 248};
182 249
183const unsigned short help_text_len = 2570; 250const unsigned short help_text_len = 3598;
184const unsigned short help_text_words = 475; 251const unsigned short help_text_words = 659;
185const char quick_help_text[] = "Draw a single closed loop, given clues about corner and straight squares."; 252const char quick_help_text[] = "Draw a single closed loop, given clues about corner and straight squares.";
diff --git a/apps/plugins/puzzles/help/pegs.c b/apps/plugins/puzzles/help/pegs.c
index 14cbbf7f94..b7159ffc5c 100644
--- a/apps/plugins/puzzles/help/pegs.c
+++ b/apps/plugins/puzzles/help/pegs.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,143 +6,146 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 72, TEXT_CENTER | C_RED }, 9 { 73, TEXT_CENTER | C_RED },
10 { 228, TEXT_CENTER | C_RED }, 10 { 229, TEXT_CENTER | C_RED },
11 { 245, TEXT_UNDERLINE },
12 { 246, TEXT_UNDERLINE }, 11 { 246, TEXT_UNDERLINE },
13 { 256, TEXT_UNDERLINE }, 12 { 247, TEXT_UNDERLINE },
13 { 257, TEXT_UNDERLINE },
14 LAST_STYLE_ITEM 14 LAST_STYLE_ITEM
15}; 15};
16 16
17/* orig 1689 comp 1250 ratio 0.740083 level 3 saved 439 */ 17/* orig 1734 comp 1272 ratio 0.733564 level 4 saved 462 */
18const char help_text[] = { 18const char help_text[] = {
190xf0, 0x46, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 190xfb, 0x04, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
200x31, 0x36, 0x3a, 0x20, 0x50, 0x65, 0x67, 0x73, 0x20, 0x00, 200x31, 0x36, 0x3a, 0x20, 0x50, 0x65, 0x67, 0x73, 0x20, 0x00,
210x00, 0x00, 0x41, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 210x2d, 0x01, 0x00, 0xf0, 0x35, 0x00, 0x00, 0x00, 0x41, 0x00,
220x00, 0x6f, 0x66, 0x00, 0x70, 0x65, 0x67, 0x73, 0x00, 0x61, 220x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x00, 0x6f, 0x66, 0x00,
230x72, 0x65, 0x00, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x00, 230x70, 0x65, 0x67, 0x73, 0x00, 0x61, 0x72, 0x65, 0x00, 0x70,
240x69, 0x6e, 0x00, 0x68, 0x6f, 0x6c, 0x65, 0x73, 0x00, 0x6f, 240x6c, 0x61, 0x63, 0x65, 0x64, 0x00, 0x69, 0x6e, 0x00, 0x68,
250x6e, 0x00, 0x61, 0x00, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x2e, 250x6f, 0x6c, 0x65, 0x73, 0x00, 0x6f, 0x6e, 0x00, 0x61, 0x00,
260x00, 0x59, 0x6f, 0x75, 0x00, 0x63, 0x61, 0x6e, 0x00, 0x72, 260x62, 0x6f, 0x61, 0x72, 0x64, 0x2e, 0x00, 0x59, 0x6f, 0x75,
270x65, 0x6d, 0x6f, 0x76, 0x65, 0x00, 0x61, 0x36, 0x00, 0xf1, 270x00, 0x63, 0x61, 0x6e, 0x00, 0x72, 0x65, 0x6d, 0x6f, 0x76,
280x08, 0x00, 0x62, 0x79, 0x00, 0x6a, 0x75, 0x6d, 0x70, 0x69, 280x65, 0x00, 0x61, 0x36, 0x00, 0xf1, 0x08, 0x00, 0x62, 0x79,
290x6e, 0x67, 0x00, 0x61, 0x6e, 0x00, 0x61, 0x64, 0x6a, 0x61, 290x00, 0x6a, 0x75, 0x6d, 0x70, 0x69, 0x6e, 0x67, 0x00, 0x61,
300x63, 0x65, 0x6e, 0x74, 0x1b, 0x00, 0xf0, 0x10, 0x6f, 0x76, 300x6e, 0x00, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x65, 0x6e, 0x74,
310x65, 0x72, 0x00, 0x69, 0x74, 0x00, 0x28, 0x68, 0x6f, 0x72, 310x1b, 0x00, 0xf0, 0x10, 0x6f, 0x76, 0x65, 0x72, 0x00, 0x69,
320x69, 0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x6c, 0x79, 0x00, 320x74, 0x00, 0x28, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x6f, 0x6e,
330x6f, 0x72, 0x00, 0x76, 0x65, 0x72, 0x74, 0x69, 0x63, 0x0e, 330x74, 0x61, 0x6c, 0x6c, 0x79, 0x00, 0x6f, 0x72, 0x00, 0x76,
340x00, 0xd1, 0x29, 0x00, 0x74, 0x6f, 0x00, 0x61, 0x00, 0x76, 340x65, 0x72, 0x74, 0x69, 0x63, 0x0e, 0x00, 0xd1, 0x29, 0x00,
350x61, 0x63, 0x61, 0x6e, 0x74, 0x73, 0x00, 0x00, 0x72, 0x00, 350x74, 0x6f, 0x00, 0x61, 0x00, 0x76, 0x61, 0x63, 0x61, 0x6e,
360xe1, 0x74, 0x68, 0x65, 0x00, 0x6f, 0x74, 0x68, 0x65, 0x72, 360x74, 0x73, 0x00, 0x00, 0x72, 0x00, 0xe1, 0x74, 0x68, 0x65,
370x00, 0x73, 0x69, 0x64, 0x65, 0x79, 0x00, 0x80, 0x72, 0x00, 370x00, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x00, 0x73, 0x69, 0x64,
380x61, 0x69, 0x6d, 0x00, 0x69, 0x73, 0x30, 0x00, 0x04, 0x80, 380x65, 0x79, 0x00, 0x80, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00,
390x00, 0xa0, 0x6c, 0x6c, 0x00, 0x62, 0x75, 0x74, 0x00, 0x6f, 390x69, 0x73, 0x30, 0x00, 0x04, 0x80, 0x00, 0xa0, 0x6c, 0x6c,
400x6e, 0x65, 0xc3, 0x00, 0x00, 0x35, 0x00, 0x01, 0xc7, 0x00, 400x00, 0x62, 0x75, 0x74, 0x00, 0x6f, 0x6e, 0x65, 0xc3, 0x00,
410x51, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6b, 0x00, 0xf0, 0x25, 410x00, 0x35, 0x00, 0x01, 0xc7, 0x00, 0x51, 0x69, 0x6e, 0x69,
420x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2e, 0x00, 0x00, 420x74, 0x69, 0x6b, 0x00, 0xf0, 0x25, 0x70, 0x72, 0x65, 0x73,
430x00, 0x54, 0x68, 0x69, 0x73, 0x00, 0x67, 0x61, 0x6d, 0x65, 430x65, 0x6e, 0x74, 0x2e, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69,
440x2c, 0x00, 0x62, 0x65, 0x73, 0x74, 0x00, 0x6b, 0x6e, 0x6f, 440x73, 0x00, 0x67, 0x61, 0x6d, 0x65, 0x2c, 0x00, 0x62, 0x65,
450x77, 0x6e, 0x00, 0x61, 0x73, 0x00, 0x60, 0x50, 0x65, 0x67, 450x73, 0x74, 0x00, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x61,
460x00, 0x53, 0x6f, 0x6c, 0x69, 0x74, 0x61, 0x69, 0x72, 0x65, 460x73, 0x00, 0x60, 0x50, 0x65, 0x67, 0x00, 0x53, 0x6f, 0x6c,
470x27, 0x2c, 0x64, 0x00, 0x88, 0x70, 0x6f, 0x73, 0x73, 0x69, 470x69, 0x74, 0x61, 0x69, 0x72, 0x65, 0x27, 0x2c, 0x64, 0x00,
480x62, 0x6c, 0x79, 0x5b, 0x00, 0x30, 0x6f, 0x6c, 0x64, 0x38, 480x88, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x79, 0x5b,
490x00, 0x61, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x4a, 0x00, 490x00, 0x30, 0x6f, 0x6c, 0x64, 0x38, 0x00, 0x61, 0x70, 0x75,
500xf2, 0x01, 0x73, 0x00, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x00, 500x7a, 0x7a, 0x6c, 0x65, 0x4a, 0x00, 0xf2, 0x01, 0x73, 0x00,
510x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x6c, 0x79, 0x54, 0x00, 510x73, 0x74, 0x69, 0x6c, 0x6c, 0x00, 0x63, 0x6f, 0x6d, 0x6d,
520x00, 0x6d, 0x00, 0x42, 0x31, 0x36, 0x2e, 0x31, 0x67, 0x01, 520x6f, 0x6e, 0x6c, 0x79, 0x54, 0x00, 0x00, 0x6d, 0x00, 0x42,
530x71, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x01, 530x31, 0x36, 0x2e, 0x31, 0x78, 0x01, 0x90, 0x63, 0x6f, 0x6e,
540x36, 0x54, 0x6f, 0x00, 0x38, 0x01, 0x60, 0x2c, 0x00, 0x64, 540x74, 0x72, 0x6f, 0x6c, 0x73, 0x20, 0x83, 0x00, 0x26, 0x6f,
550x72, 0x61, 0x67, 0x1e, 0x01, 0x41, 0x77, 0x69, 0x74, 0x68, 550x00, 0x38, 0x01, 0x60, 0x2c, 0x00, 0x64, 0x72, 0x61, 0x67,
560x62, 0x00, 0xf1, 0x04, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x00, 560x1e, 0x01, 0x41, 0x77, 0x69, 0x74, 0x68, 0x62, 0x00, 0xf1,
570x66, 0x72, 0x6f, 0x6d, 0x00, 0x69, 0x74, 0x73, 0x00, 0x63, 570x04, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x00, 0x66, 0x72, 0x6f,
580x75, 0x72, 0x72, 0x4a, 0x01, 0x50, 0x6f, 0x73, 0x69, 0x74, 580x6d, 0x00, 0x69, 0x74, 0x73, 0x00, 0x63, 0x75, 0x72, 0x72,
590x69, 0x16, 0x01, 0x11, 0x6f, 0x18, 0x00, 0x55, 0x66, 0x69, 590x4a, 0x01, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x16, 0x01,
600x6e, 0x61, 0x6c, 0x16, 0x00, 0x32, 0x2e, 0x00, 0x49, 0xa0, 600x11, 0x6f, 0x18, 0x00, 0x55, 0x66, 0x69, 0x6e, 0x61, 0x6c,
610x00, 0x0a, 0x17, 0x00, 0x00, 0xc6, 0x00, 0xb3, 0x65, 0x78, 610x16, 0x00, 0x32, 0x2e, 0x00, 0x49, 0xa0, 0x00, 0x0a, 0x17,
620x61, 0x63, 0x74, 0x6c, 0x79, 0x00, 0x74, 0x77, 0x6f, 0xcd, 620x00, 0x00, 0xc6, 0x00, 0xb3, 0x65, 0x78, 0x61, 0x63, 0x74,
630x01, 0x42, 0x61, 0x77, 0x61, 0x79, 0x61, 0x00, 0x00, 0x32, 630x6c, 0x79, 0x00, 0x74, 0x77, 0x6f, 0xcd, 0x01, 0x42, 0x61,
640x00, 0x03, 0x28, 0x01, 0x05, 0x34, 0x00, 0x01, 0xfb, 0x00, 640x77, 0x61, 0x79, 0x61, 0x00, 0x00, 0x32, 0x00, 0x03, 0x28,
650x03, 0x76, 0x00, 0xd0, 0x6c, 0x79, 0x00, 0x75, 0x6e, 0x6f, 650x01, 0x05, 0x34, 0x00, 0x01, 0xfb, 0x00, 0x03, 0x76, 0x00,
660x63, 0x63, 0x75, 0x70, 0x69, 0x65, 0x64, 0xe4, 0x01, 0x03, 660xd0, 0x6c, 0x79, 0x00, 0x75, 0x6e, 0x6f, 0x63, 0x63, 0x75,
670xb5, 0x00, 0x30, 0x61, 0x6e, 0x64, 0x3c, 0x00, 0x20, 0x72, 670x70, 0x69, 0x65, 0x64, 0xe4, 0x01, 0x03, 0xb5, 0x00, 0x30,
680x65, 0x2c, 0x00, 0x02, 0x01, 0x02, 0x23, 0x69, 0x6e, 0x4e, 680x61, 0x6e, 0x64, 0x3c, 0x00, 0x20, 0x72, 0x65, 0x2c, 0x00,
690x00, 0x60, 0x74, 0x65, 0x72, 0x76, 0x65, 0x6e, 0x09, 0x02, 690x02, 0x01, 0x02, 0x23, 0x69, 0x6e, 0x4e, 0x00, 0x60, 0x74,
700x73, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x2c, 0xd6, 0x00, 700x65, 0x72, 0x76, 0x65, 0x6e, 0x09, 0x02, 0x73, 0x73, 0x71,
710x40, 0x76, 0x65, 0x00, 0x77, 0x28, 0x01, 0x10, 0x62, 0xa0, 710x75, 0x61, 0x72, 0x65, 0x2c, 0xd6, 0x00, 0x40, 0x76, 0x65,
720x01, 0x74, 0x72, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x49, 720x00, 0x77, 0x28, 0x01, 0x10, 0x62, 0xa0, 0x01, 0x74, 0x72,
730x00, 0x09, 0x37, 0x00, 0x00, 0x4e, 0x00, 0x04, 0x2a, 0x00, 730x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x49, 0x00, 0x09, 0x37,
740x02, 0xe4, 0x01, 0x10, 0x64, 0x4e, 0x01, 0x12, 0x56, 0x1d, 740x00, 0x00, 0x4e, 0x00, 0x04, 0x2a, 0x00, 0x02, 0xe4, 0x01,
750x02, 0xe3, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x00, 0x77, 750x10, 0x64, 0x4e, 0x01, 0x12, 0x56, 0x1d, 0x02, 0xe3, 0x73,
760x68, 0x69, 0x63, 0x68, 0x00, 0x79, 0x8b, 0x02, 0x06, 0x51, 760x70, 0x61, 0x63, 0x65, 0x73, 0x00, 0x77, 0x68, 0x69, 0x63,
770x01, 0x00, 0x4a, 0x00, 0x11, 0x6f, 0xc3, 0x02, 0x62, 0x6d, 770x68, 0x00, 0x79, 0x8b, 0x02, 0x07, 0x89, 0x02, 0x41, 0x69,
780x61, 0x72, 0x6b, 0x65, 0x64, 0x58, 0x01, 0x01, 0xf8, 0x00, 780x6e, 0x74, 0x6f, 0xc3, 0x02, 0x62, 0x6d, 0x61, 0x72, 0x6b,
790x32, 0x2e, 0x00, 0x41, 0x3e, 0x00, 0x02, 0x14, 0x00, 0x21, 790x65, 0x64, 0x58, 0x01, 0x01, 0xf8, 0x00, 0x32, 0x2e, 0x00,
800x6e, 0x6f, 0x30, 0x00, 0x00, 0x82, 0x00, 0x12, 0x6e, 0x1a, 800x41, 0x3e, 0x00, 0x02, 0x14, 0x00, 0x21, 0x6e, 0x6f, 0x30,
810x01, 0x00, 0xcd, 0x00, 0xf0, 0x02, 0x6e, 0x6f, 0x74, 0x00, 810x00, 0x00, 0x82, 0x00, 0x12, 0x6e, 0x1a, 0x01, 0x00, 0xcd,
820x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x00, 820x00, 0xf0, 0x02, 0x6e, 0x6f, 0x74, 0x00, 0x61, 0x76, 0x61,
830x66, 0x6f, 0x72, 0x5c, 0x00, 0x01, 0xd6, 0x02, 0x10, 0x74, 830x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x66, 0x6f, 0x72,
840x6a, 0x02, 0x10, 0x3a, 0xab, 0x01, 0x00, 0xf4, 0x00, 0xa7, 840x5c, 0x00, 0x01, 0xd6, 0x02, 0x10, 0x74, 0x6a, 0x02, 0x10,
850x6e, 0x00, 0x6f, 0x62, 0x73, 0x74, 0x61, 0x63, 0x6c, 0x65, 850x3a, 0xab, 0x01, 0x00, 0xf4, 0x00, 0xa7, 0x6e, 0x00, 0x6f,
860x8b, 0x00, 0xf1, 0x00, 0x6d, 0x75, 0x73, 0x74, 0x00, 0x77, 860x62, 0x73, 0x74, 0x61, 0x63, 0x6c, 0x65, 0x8b, 0x00, 0xf1,
870x6f, 0x72, 0x6b, 0x00, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0xb7, 870x00, 0x6d, 0x75, 0x73, 0x74, 0x00, 0x77, 0x6f, 0x72, 0x6b,
880x00, 0x04, 0x2e, 0x03, 0x50, 0x61, 0x6c, 0x73, 0x6f, 0x00, 880x00, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0xb7, 0x00, 0x04, 0x2e,
890xda, 0x01, 0x00, 0xef, 0x00, 0xa1, 0x63, 0x75, 0x72, 0x73, 890x03, 0x50, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0xda, 0x01, 0x00,
900x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0xca, 0x02, 0x04, 0x10, 900xef, 0x00, 0xa1, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x00,
910x02, 0x05, 0xb6, 0x01, 0x83, 0x6e, 0x64, 0x69, 0x63, 0x61, 910x6b, 0x65, 0x79, 0xca, 0x02, 0x04, 0x10, 0x02, 0x05, 0xb6,
920x74, 0x6f, 0x72, 0x48, 0x00, 0x01, 0x34, 0x00, 0x03, 0x7e, 920x01, 0x83, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72,
930x03, 0x50, 0x50, 0x72, 0x65, 0x73, 0x73, 0x91, 0x00, 0x00, 930x48, 0x00, 0x01, 0x34, 0x00, 0x03, 0x7e, 0x03, 0x50, 0x50,
940x14, 0x00, 0x60, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x48, 940x72, 0x65, 0x73, 0x73, 0x91, 0x00, 0x00, 0x14, 0x00, 0x60,
950x00, 0x00, 0x86, 0x00, 0x22, 0x6c, 0x65, 0x6c, 0x03, 0x03, 950x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x48, 0x00, 0x00, 0x86,
960xa5, 0x01, 0x64, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0xb8, 960x00, 0x22, 0x6c, 0x65, 0x6c, 0x03, 0x03, 0xa5, 0x01, 0x64,
970x01, 0x06, 0x73, 0x00, 0x12, 0x2c, 0x5e, 0x01, 0x00, 0xaf, 970x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0xb8, 0x01, 0x06, 0x73,
980x03, 0x04, 0x2e, 0x03, 0x02, 0xbe, 0x01, 0x81, 0x61, 0x74, 980x00, 0x12, 0x2c, 0x5e, 0x01, 0x00, 0xaf, 0x03, 0x04, 0x2e,
990x00, 0x64, 0x69, 0x72, 0x65, 0x63, 0x84, 0x00, 0x32, 0x28, 990x03, 0x02, 0xbe, 0x01, 0x81, 0x61, 0x74, 0x00, 0x64, 0x69,
1000x69, 0x66, 0x13, 0x00, 0x01, 0xe2, 0x01, 0x51, 0x6c, 0x65, 1000x72, 0x65, 0x63, 0x84, 0x00, 0x32, 0x28, 0x69, 0x66, 0x13,
1010x67, 0x61, 0x6c, 0xa8, 0x00, 0x10, 0x29, 0xd5, 0x00, 0x41, 1010x00, 0x01, 0xe2, 0x01, 0x51, 0x6c, 0x65, 0x67, 0x61, 0x6c,
1020x28, 0x41, 0x6c, 0x6c, 0x3c, 0x00, 0x11, 0x61, 0x2d, 0x00, 1020xa8, 0x00, 0x10, 0x29, 0xd5, 0x00, 0x41, 0x28, 0x41, 0x6c,
1030x92, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 1030x6c, 0x3c, 0x00, 0x11, 0x61, 0x2d, 0x00, 0x92, 0x73, 0x00,
1040x33, 0x04, 0x13, 0x73, 0x43, 0x00, 0x31, 0x32, 0x2e, 0x31, 1040x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x33, 0x04, 0x13,
1050x8a, 0x01, 0x01, 0xfb, 0x00, 0x05, 0x55, 0x01, 0x22, 0x2e, 1050x73, 0x43, 0x00, 0x31, 0x32, 0x2e, 0x31, 0x8a, 0x01, 0x01,
1060x29, 0x1b, 0x03, 0x12, 0x32, 0x1b, 0x03, 0x92, 0x70, 0x61, 1060xfb, 0x00, 0x05, 0x55, 0x01, 0x22, 0x2e, 0x29, 0x1b, 0x03,
1070x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x1d, 0x03, 0x56, 1070x12, 0x32, 0x1b, 0x03, 0x92, 0x70, 0x61, 0x72, 0x61, 0x6d,
1080x68, 0x65, 0x73, 0x65, 0x00, 0x14, 0x00, 0x02, 0x40, 0x00, 1080x65, 0x74, 0x65, 0x72, 0x1d, 0x03, 0x56, 0x68, 0x65, 0x73,
1090x06, 0x90, 0x01, 0x04, 0xb5, 0x02, 0xe1, 0x60, 0x43, 0x75, 1090x65, 0x00, 0x14, 0x00, 0x02, 0x40, 0x00, 0x06, 0x90, 0x01,
1100x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 1100x04, 0xb5, 0x02, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f,
1110x70, 0x6e, 0x00, 0x03, 0x31, 0x04, 0xb0, 0x60, 0x54, 0x79, 1110x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x6e, 0x00,
1120x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xaa, 0x00, 1120x03, 0x31, 0x04, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27,
1130xf1, 0x04, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 1130x00, 0x6d, 0x65, 0x6e, 0x75, 0xaa, 0x00, 0xf1, 0x04, 0x57,
1140x65, 0x69, 0x67, 0x68, 0x74, 0x00, 0x00, 0x00, 0x53, 0x69, 1140x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x69, 0x67,
1150x7a, 0xcc, 0x03, 0x36, 0x67, 0x72, 0x69, 0xdf, 0x04, 0x00, 1150x68, 0x74, 0x00, 0x00, 0x00, 0x53, 0x69, 0x7a, 0xcc, 0x03,
1160x29, 0x00, 0x10, 0x42, 0x5f, 0x01, 0x93, 0x20, 0x74, 0x79, 1160x36, 0x67, 0x72, 0x69, 0xdf, 0x04, 0x00, 0x29, 0x00, 0x10,
1170x70, 0x65, 0x00, 0x00, 0x00, 0x43, 0xb0, 0x03, 0x41, 0x00, 1170x42, 0x5f, 0x01, 0x93, 0x20, 0x74, 0x79, 0x70, 0x65, 0x00,
1180x77, 0x68, 0x65, 0x81, 0x04, 0x00, 0xde, 0x01, 0x00, 0x8b, 1180x00, 0x00, 0x43, 0xb0, 0x03, 0x41, 0x00, 0x77, 0x68, 0x65,
1190x00, 0x45, 0x67, 0x69, 0x76, 0x65, 0x0b, 0x05, 0x00, 0x48, 1190x81, 0x04, 0x00, 0xde, 0x01, 0x00, 0x8b, 0x00, 0x45, 0x67,
1200x00, 0x70, 0x61, 0x00, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x0e, 1200x69, 0x76, 0x65, 0x0b, 0x05, 0x00, 0x48, 0x00, 0x70, 0x61,
1210x00, 0x50, 0x73, 0x68, 0x61, 0x70, 0x65, 0xd8, 0x04, 0xf3, 1210x00, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x0e, 0x00, 0x50, 0x73,
1220x04, 0x61, 0x00, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x6c, 1220x68, 0x61, 0x70, 0x65, 0xd8, 0x04, 0xf3, 0x04, 0x61, 0x00,
1230x79, 0x00, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 1230x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x6c, 0x79, 0x00, 0x67,
1240x1e, 0x00, 0x10, 0x2e, 0xe1, 0x00, 0x01, 0x8a, 0x03, 0x0a, 1240x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x1e, 0x00, 0x10,
1250x36, 0x00, 0x08, 0x71, 0x03, 0x61, 0x73, 0x75, 0x70, 0x70, 1250x2e, 0xe1, 0x00, 0x01, 0x8a, 0x03, 0x0a, 0x36, 0x00, 0x08,
1260x6f, 0x72, 0x1d, 0x03, 0x10, 0x72, 0xe9, 0x00, 0x51, 0x72, 1260x71, 0x03, 0x61, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x1d,
1270x6f, 0x73, 0x73, 0x27, 0xa7, 0x02, 0xb1, 0x60, 0x4f, 0x63, 1270x03, 0x10, 0x72, 0xe9, 0x00, 0xf1, 0x09, 0x72, 0x6f, 0x73,
1280x74, 0x61, 0x67, 0x6f, 0x6e, 0x27, 0x00, 0x28, 0x53, 0x01, 1280x73, 0x27, 0x00, 0x28, 0x69, 0x6e, 0x00, 0x76, 0x61, 0x72,
1290x0a, 0x72, 0x04, 0x00, 0xc6, 0x04, 0x00, 0x01, 0x01, 0x71, 1290x69, 0x6f, 0x75, 0x73, 0x00, 0x73, 0x69, 0x7a, 0x65, 0x73,
1300x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x32, 0x00, 0xd1, 1300x29, 0xba, 0x02, 0x92, 0x60, 0x4f, 0x63, 0x74, 0x61, 0x67,
1310x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x61, 0x6e, 0x00, 0x74, 1310x6f, 0x6e, 0x27, 0x5a, 0x00, 0x41, 0x37, 0x78, 0x37, 0x00,
1320x72, 0x61, 0x64, 0x5c, 0x02, 0x23, 0x61, 0x6c, 0xbc, 0x00, 1320x31, 0x00, 0x01, 0x23, 0x05, 0x00, 0x6b, 0x00, 0x31, 0x72,
1330xc0, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x73, 0x00, 0x72, 1330x61, 0x64, 0x54, 0x02, 0xa3, 0x61, 0x6c, 0x00, 0x45, 0x6e,
1340x65, 0x73, 0x70, 0xb0, 0x01, 0xa0, 0x76, 0x65, 0x6c, 0x79, 1340x67, 0x6c, 0x69, 0x73, 0x68, 0xbc, 0x00, 0x62, 0x6c, 0x61,
1350x29, 0x2e, 0x00, 0x53, 0x65, 0x6c, 0x0e, 0x00, 0x51, 0x6e, 1350x79, 0x6f, 0x75, 0x74, 0x37, 0x00, 0x03, 0x45, 0x00, 0x0f,
1360x67, 0x00, 0x60, 0x52, 0xc5, 0x00, 0x12, 0x27, 0x2e, 0x02, 1360x35, 0x00, 0x01, 0x60, 0x46, 0x72, 0x65, 0x6e, 0x63, 0x68,
1370x00, 0xf9, 0x00, 0x02, 0x06, 0x01, 0x61, 0x00, 0x64, 0x69, 1370x02, 0x05, 0x50, 0x2e, 0x00, 0x53, 0x65, 0x6c, 0xda, 0x01,
1380x66, 0x66, 0x65, 0x94, 0x04, 0x26, 0x62, 0x6f, 0xf8, 0x00, 1380x51, 0x6e, 0x67, 0x00, 0x60, 0x52, 0xe1, 0x00, 0x12, 0x27,
1390xc0, 0x65, 0x76, 0x65, 0x72, 0x79, 0x00, 0x74, 0x69, 0x6d, 1390x4a, 0x02, 0x00, 0x15, 0x01, 0x02, 0x22, 0x01, 0x61, 0x00,
1400x65, 0x00, 0x28, 0x8f, 0x05, 0x61, 0x61, 0x6c, 0x77, 0x61, 1400x64, 0x69, 0x66, 0x66, 0x65, 0xb0, 0x04, 0x26, 0x62, 0x6f,
1410x79, 0x73, 0x3b, 0x05, 0x04, 0x47, 0x02, 0x02, 0xa7, 0x00, 1410x14, 0x01, 0xc0, 0x65, 0x76, 0x65, 0x72, 0x79, 0x00, 0x74,
1420x51, 0x74, 0x6f, 0x00, 0x68, 0x61, 0xf0, 0x02, 0xb0, 0x73, 1420x69, 0x6d, 0x65, 0x00, 0x28, 0xab, 0x05, 0x61, 0x61, 0x6c,
1430x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x2e, 0x00, 1430x77, 0x61, 0x79, 0x73, 0x57, 0x05, 0x04, 0x63, 0x02, 0x02,
1440x89, 0x05, 0x51, 0x74, 0x6f, 0x00, 0x68, 0x61, 0x0c, 0x03,
1450xb0, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x29,
1460x2e, 0x00,
144}; 147};
145 148
146const unsigned short help_text_len = 1689; 149const unsigned short help_text_len = 1734;
147const unsigned short help_text_words = 318; 150const unsigned short help_text_words = 326;
148const char quick_help_text[] = "Jump pegs over each other to remove all but one."; 151const char quick_help_text[] = "Jump pegs over each other to remove all but one.";
diff --git a/apps/plugins/puzzles/help/range.c b/apps/plugins/puzzles/help/range.c
index 1ce92c05d1..5a9e3ab71d 100644
--- a/apps/plugins/puzzles/help/range.c
+++ b/apps/plugins/puzzles/help/range.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,157 +6,168 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 212, TEXT_CENTER | C_RED }, 9 { 213, TEXT_CENTER | C_RED },
10 { 245, TEXT_UNDERLINE }, 10 { 246, TEXT_UNDERLINE },
11 { 339, TEXT_CENTER | C_RED }, 11 { 340, TEXT_CENTER | C_RED },
12 { 356, TEXT_UNDERLINE },
13 { 357, TEXT_UNDERLINE }, 12 { 357, TEXT_UNDERLINE },
13 { 358, TEXT_UNDERLINE },
14 { 368, TEXT_CENTER | C_RED },
14 LAST_STYLE_ITEM 15 LAST_STYLE_ITEM
15}; 16};
16 17
17/* orig 2036 comp 1387 ratio 0.681238 level 4 saved 649 */ 18/* orig 2223 comp 1486 ratio 0.668466 level 10 saved 737 */
18const char help_text[] = { 19const char help_text[] = {
190xf4, 0x26, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 200xfc, 0x05, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
200x33, 0x35, 0x3a, 0x20, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x20, 210x33, 0x35, 0x3a, 0x20, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x20,
210x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 220x00, 0x2d, 0x01, 0x00, 0xf4, 0x14, 0x00, 0x00, 0x00, 0x59,
220x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 230x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00,
230x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x3b, 240x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71,
240x00, 0x73, 0x6f, 0x6d, 0x65, 0x0e, 0x00, 0xf0, 0x02, 0x00, 250x75, 0x61, 0x72, 0x65, 0x73, 0x3b, 0x00, 0x73, 0x6f, 0x6d,
250x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x00, 0x6e, 0x75, 260x65, 0x0e, 0x00, 0xf0, 0x02, 0x00, 0x63, 0x6f, 0x6e, 0x74,
260x6d, 0x62, 0x65, 0x72, 0x73, 0x2e, 0x3a, 0x00, 0xf0, 0x00, 270x61, 0x69, 0x6e, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
270x72, 0x00, 0x6a, 0x6f, 0x62, 0x00, 0x69, 0x73, 0x00, 0x74, 280x73, 0x2e, 0x3a, 0x00, 0xf0, 0x00, 0x72, 0x00, 0x6a, 0x6f,
280x6f, 0x00, 0x63, 0x6f, 0x6c, 0x11, 0x00, 0x01, 0x34, 0x00, 290x62, 0x00, 0x69, 0x73, 0x00, 0x74, 0x6f, 0x00, 0x63, 0x6f,
290x56, 0x6f, 0x66, 0x00, 0x74, 0x68, 0x3b, 0x00, 0xf3, 0x28, 300x6c, 0x11, 0x00, 0x01, 0x34, 0x00, 0x56, 0x6f, 0x66, 0x00,
300x62, 0x6c, 0x61, 0x63, 0x6b, 0x2c, 0x00, 0x73, 0x75, 0x63, 310x74, 0x68, 0x3b, 0x00, 0xf3, 0x28, 0x62, 0x6c, 0x61, 0x63,
310x68, 0x00, 0x74, 0x68, 0x61, 0x74, 0x00, 0x73, 0x65, 0x76, 320x6b, 0x2c, 0x00, 0x73, 0x75, 0x63, 0x68, 0x00, 0x74, 0x68,
320x65, 0x72, 0x61, 0x6c, 0x00, 0x63, 0x72, 0x69, 0x74, 0x65, 330x61, 0x74, 0x00, 0x73, 0x65, 0x76, 0x65, 0x72, 0x61, 0x6c,
330x72, 0x69, 0x61, 0x00, 0x61, 0x72, 0x65, 0x00, 0x73, 0x61, 340x00, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, 0x61, 0x00,
340x74, 0x69, 0x73, 0x66, 0x69, 0x65, 0x64, 0x3a, 0x00, 0x00, 350x61, 0x72, 0x65, 0x00, 0x73, 0x61, 0x74, 0x69, 0x73, 0x66,
350x00, 0x2d, 0x00, 0x6e, 0x6f, 0x40, 0x00, 0x73, 0x00, 0x77, 360x69, 0x65, 0x64, 0x3a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x6e,
360x69, 0x74, 0x68, 0x00, 0x61, 0x79, 0x00, 0x00, 0x6e, 0x00, 370x6f, 0x40, 0x00, 0x73, 0x00, 0x77, 0x69, 0x74, 0x68, 0x00,
370x02, 0x6b, 0x00, 0x22, 0x65, 0x64, 0x59, 0x00, 0x14, 0x2e, 380x61, 0x79, 0x00, 0x00, 0x6e, 0x00, 0x02, 0x6b, 0x00, 0x22,
380x2f, 0x00, 0x32, 0x74, 0x77, 0x6f, 0x12, 0x00, 0x05, 0x79, 390x65, 0x64, 0x59, 0x00, 0x14, 0x2e, 0x2f, 0x00, 0x32, 0x74,
390x00, 0x00, 0x3e, 0x00, 0xf0, 0x00, 0x61, 0x64, 0x6a, 0x61, 400x77, 0x6f, 0x12, 0x00, 0x05, 0x79, 0x00, 0x00, 0x3e, 0x00,
400x63, 0x65, 0x6e, 0x74, 0x00, 0x28, 0x68, 0x6f, 0x72, 0x69, 410xf0, 0x00, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x65, 0x6e, 0x74,
410x7a, 0xc6, 0x00, 0xd0, 0x6c, 0x6c, 0x79, 0x00, 0x6f, 0x72, 420x00, 0x28, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0xc6, 0x00, 0xd0,
420x00, 0x76, 0x65, 0x72, 0x74, 0x69, 0x63, 0x0e, 0x00, 0x12, 430x6c, 0x6c, 0x79, 0x00, 0x6f, 0x72, 0x00, 0x76, 0x65, 0x72,
430x29, 0x44, 0x00, 0x71, 0x66, 0x6f, 0x72, 0x00, 0x61, 0x6e, 440x74, 0x69, 0x63, 0x0e, 0x00, 0x12, 0x29, 0x44, 0x00, 0x71,
440x79, 0x49, 0x00, 0x45, 0x77, 0x68, 0x69, 0x74, 0xc2, 0x00, 450x66, 0x6f, 0x72, 0x00, 0x61, 0x6e, 0x79, 0x49, 0x00, 0x45,
450x10, 0x2c, 0xcf, 0x00, 0x20, 0x72, 0x65, 0x7c, 0x00, 0xe0, 460x77, 0x68, 0x69, 0x74, 0xc2, 0x00, 0x10, 0x2c, 0xcf, 0x00,
460x61, 0x00, 0x70, 0x61, 0x74, 0x68, 0x00, 0x62, 0x65, 0x74, 470x20, 0x72, 0x65, 0x7c, 0x00, 0xe0, 0x61, 0x00, 0x70, 0x61,
470x77, 0x65, 0x65, 0x6e, 0x18, 0x00, 0xca, 0x6d, 0x00, 0x75, 480x74, 0x68, 0x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e,
480x73, 0x69, 0x6e, 0x67, 0x00, 0x6f, 0x6e, 0x6c, 0x79, 0x37, 490x18, 0x00, 0xca, 0x6d, 0x00, 0x75, 0x73, 0x69, 0x6e, 0x67,
490x00, 0x06, 0x56, 0x00, 0x4f, 0x65, 0x61, 0x63, 0x68, 0xcf, 500x00, 0x6f, 0x6e, 0x6c, 0x79, 0x37, 0x00, 0x06, 0x56, 0x00,
500x00, 0x02, 0x12, 0x2c, 0x11, 0x01, 0x03, 0xdc, 0x00, 0x71, 510x4f, 0x65, 0x61, 0x63, 0x68, 0xcf, 0x00, 0x02, 0x12, 0x2c,
510x64, 0x65, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x3d, 0x01, 0x54, 520x11, 0x01, 0x03, 0xdc, 0x00, 0x71, 0x64, 0x65, 0x6e, 0x6f,
520x74, 0x6f, 0x74, 0x61, 0x6c, 0x19, 0x00, 0x2a, 0x6f, 0x66, 530x74, 0x65, 0x73, 0x3d, 0x01, 0x54, 0x74, 0x6f, 0x74, 0x61,
530x5a, 0x00, 0x20, 0x00, 0x72, 0x52, 0x00, 0x93, 0x61, 0x62, 540x6c, 0x19, 0x00, 0x2a, 0x6f, 0x66, 0x5a, 0x00, 0x20, 0x00,
540x6c, 0x65, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x56, 0x01, 0x02, 550x72, 0x52, 0x00, 0x93, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x66,
550x60, 0x00, 0x20, 0x67, 0x6f, 0x8e, 0x00, 0xf1, 0x03, 0x69, 560x72, 0x6f, 0x6d, 0x56, 0x01, 0x02, 0x60, 0x00, 0x20, 0x67,
560x6e, 0x00, 0x61, 0x00, 0x73, 0x74, 0x72, 0x61, 0x69, 0x67, 570x6f, 0x8e, 0x00, 0xf1, 0x03, 0x69, 0x6e, 0x00, 0x61, 0x00,
570x68, 0x74, 0x00, 0x6c, 0x69, 0x6e, 0x65, 0x13, 0x00, 0x36, 580x73, 0x74, 0x72, 0x61, 0x69, 0x67, 0x68, 0x74, 0x00, 0x6c,
580x6e, 0x79, 0x00, 0x07, 0x01, 0x08, 0x05, 0x01, 0xf0, 0x06, 590x69, 0x6e, 0x65, 0x13, 0x00, 0x36, 0x6e, 0x79, 0x00, 0x07,
590x00, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 600x01, 0x08, 0x05, 0x01, 0xf0, 0x06, 0x00, 0x64, 0x69, 0x72,
600x00, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x00, 0x68, 0x69, 0x74, 610x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x75, 0x6e, 0x74,
610x74, 0x49, 0x00, 0x51, 0x61, 0x00, 0x77, 0x61, 0x6c, 0x2b, 620x69, 0x6c, 0x00, 0x68, 0x69, 0x74, 0x74, 0x49, 0x00, 0x51,
620x00, 0x19, 0x61, 0x5e, 0x01, 0x17, 0x3b, 0xe3, 0x01, 0x02, 630x61, 0x00, 0x77, 0x61, 0x6c, 0x2b, 0x00, 0x19, 0x61, 0x5e,
630xd4, 0x00, 0x00, 0x10, 0x00, 0x06, 0xa5, 0x01, 0x80, 0x69, 640x01, 0x17, 0x3b, 0xe3, 0x01, 0x02, 0xd4, 0x00, 0x00, 0x10,
640x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x77, 0x00, 0x06, 650x00, 0x06, 0xa5, 0x01, 0x80, 0x69, 0x6e, 0x63, 0x6c, 0x75,
650xd0, 0x00, 0x51, 0x28, 0x6f, 0x6e, 0x63, 0x65, 0x6f, 0x01, 660x64, 0x65, 0x64, 0x77, 0x00, 0x06, 0xd0, 0x00, 0x51, 0x28,
660xf4, 0x00, 0x46, 0x6f, 0x72, 0x00, 0x69, 0x6e, 0x73, 0x74, 670x6f, 0x6e, 0x63, 0x65, 0x6f, 0x01, 0xf4, 0x00, 0x46, 0x6f,
670x61, 0x6e, 0x63, 0x65, 0x2c, 0x00, 0x61, 0x4a, 0x00, 0x03, 680x72, 0x00, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
680x67, 0x02, 0x00, 0x7a, 0x00, 0x07, 0x50, 0x00, 0x82, 0x6f, 690x2c, 0x00, 0x61, 0x4a, 0x00, 0x03, 0x67, 0x02, 0x00, 0x7a,
690x6e, 0x65, 0x00, 0x6d, 0x75, 0x73, 0x74, 0xab, 0x02, 0x10, 700x00, 0x07, 0x50, 0x00, 0x82, 0x6f, 0x6e, 0x65, 0x00, 0x6d,
700x66, 0x69, 0x02, 0x0b, 0xea, 0x01, 0xf1, 0x04, 0x73, 0x00, 710x75, 0x73, 0x74, 0xab, 0x02, 0x10, 0x66, 0x69, 0x02, 0x0b,
710x69, 0x74, 0x73, 0x00, 0x6e, 0x65, 0x69, 0x67, 0x68, 0x62, 720xea, 0x01, 0xf1, 0x04, 0x73, 0x00, 0x69, 0x74, 0x73, 0x00,
720x6f, 0x75, 0x72, 0x73, 0x00, 0x62, 0x79, 0x41, 0x00, 0x44, 730x6e, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6f, 0x75, 0x72, 0x73,
730x6c, 0x61, 0x73, 0x74, 0x68, 0x02, 0x70, 0x6f, 0x6e, 0x3b, 740x00, 0x62, 0x79, 0x41, 0x00, 0x44, 0x6c, 0x61, 0x73, 0x74,
740x00, 0x62, 0x75, 0x74, 0x18, 0x00, 0xe1, 0x6e, 0x00, 0x69, 750x68, 0x02, 0x70, 0x6f, 0x6e, 0x3b, 0x00, 0x62, 0x75, 0x74,
750x74, 0x27, 0x73, 0x00, 0x69, 0x6d, 0x70, 0x6f, 0x73, 0x73, 760x18, 0x00, 0xe1, 0x6e, 0x00, 0x69, 0x74, 0x27, 0x73, 0x00,
760x69, 0x48, 0x01, 0x00, 0x90, 0x00, 0x10, 0x74, 0xca, 0x02, 770x69, 0x6d, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x48, 0x01, 0x00,
770x11, 0x62, 0x86, 0x00, 0x60, 0x6e, 0x65, 0x63, 0x74, 0x65, 780x90, 0x00, 0x10, 0x74, 0xca, 0x02, 0x11, 0x62, 0x86, 0x00,
780x64, 0x10, 0x00, 0x00, 0x35, 0x01, 0x79, 0x6f, 0x75, 0x74, 790x60, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x10, 0x00, 0x00,
790x73, 0x69, 0x64, 0x65, 0x86, 0x01, 0x10, 0x2c, 0x0e, 0x00, 800x35, 0x01, 0x79, 0x6f, 0x75, 0x74, 0x73, 0x69, 0x64, 0x65,
800x84, 0x63, 0x68, 0x00, 0x76, 0x69, 0x6f, 0x6c, 0x61, 0xb7, 810x86, 0x01, 0x10, 0x2c, 0x0e, 0x00, 0x84, 0x63, 0x68, 0x00,
810x01, 0x51, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x37, 0x00, 0x0a, 820x76, 0x69, 0x6f, 0x6c, 0x61, 0xb7, 0x01, 0x51, 0x73, 0x65,
820x7a, 0x00, 0x49, 0x2e, 0x00, 0x53, 0x6f, 0xd4, 0x02, 0x25, 830x63, 0x6f, 0x6e, 0x37, 0x00, 0x0a, 0x7a, 0x00, 0x49, 0x2e,
830x6c, 0x6c, 0x53, 0x03, 0x0a, 0xe9, 0x00, 0x00, 0x1d, 0x01, 840x00, 0x53, 0x6f, 0xd4, 0x02, 0x25, 0x6c, 0x6c, 0x53, 0x03,
840x61, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x94, 0x00, 0xa0, 850x0a, 0xe9, 0x00, 0x00, 0x1d, 0x01, 0x61, 0x43, 0x72, 0x65,
850x74, 0x68, 0x69, 0x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 860x64, 0x69, 0x74, 0x94, 0x00, 0xa0, 0x74, 0x68, 0x69, 0x73,
860xdb, 0x01, 0x11, 0x65, 0x6c, 0x03, 0x60, 0x4e, 0x69, 0x6b, 870x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0xdb, 0x01, 0x11, 0x65,
870x6f, 0x6c, 0x69, 0x80, 0x00, 0x12, 0x6f, 0x12, 0x01, 0xa0, 880x6c, 0x03, 0x60, 0x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69, 0x80,
880x76, 0x61, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x6c, 0x79, 0x00, 890x00, 0x12, 0x6f, 0x12, 0x01, 0xa0, 0x76, 0x61, 0x72, 0x69,
890xd0, 0x02, 0x00, 0x75, 0x01, 0xd2, 0x74, 0x00, 0x60, 0x4b, 900x6f, 0x75, 0x73, 0x6c, 0x79, 0x00, 0xd0, 0x02, 0x20, 0x65,
900x75, 0x72, 0x6f, 0x64, 0x6f, 0x6b, 0x6f, 0x27, 0x2c, 0x0c, 910x64, 0xca, 0x00, 0xb2, 0x60, 0x4b, 0x75, 0x72, 0x6f, 0x64,
910x00, 0x50, 0x6d, 0x61, 0x73, 0x75, 0x27, 0xc9, 0x01, 0x24, 920x6f, 0x6b, 0x6f, 0x27, 0x2c, 0x0c, 0x00, 0x50, 0x6d, 0x61,
920x60, 0x57, 0xce, 0x02, 0x11, 0x42, 0x45, 0x01, 0xc0, 0x43, 930x73, 0x75, 0x27, 0xc9, 0x01, 0x24, 0x60, 0x57, 0xce, 0x02,
930x65, 0x6c, 0x6c, 0x73, 0x27, 0x2e, 0x00, 0x5b, 0x31, 0x38, 940x11, 0x42, 0x45, 0x01, 0xc0, 0x43, 0x65, 0x6c, 0x6c, 0x73,
940x5d, 0x7e, 0x00, 0x01, 0x1d, 0x04, 0x32, 0x00, 0x77, 0x61, 950x27, 0x2e, 0x00, 0x5b, 0x31, 0x38, 0x5d, 0x7e, 0x00, 0x01,
950xf5, 0x03, 0x43, 0x72, 0x69, 0x62, 0x75, 0x0a, 0x01, 0x22, 960x2f, 0x04, 0x32, 0x00, 0x77, 0x61, 0xf5, 0x03, 0x43, 0x72,
960x74, 0x68, 0x7e, 0x03, 0x13, 0x6c, 0x2a, 0x02, 0xf0, 0x01, 970x69, 0x62, 0x75, 0x0a, 0x01, 0x22, 0x74, 0x68, 0x7e, 0x03,
970x62, 0x79, 0x00, 0x4a, 0x6f, 0x6e, 0x61, 0x73, 0x00, 0x4b, 980x13, 0x6c, 0x2a, 0x02, 0xf0, 0x01, 0x62, 0x79, 0x00, 0x4a,
980x6f, 0x65, 0x6c, 0x6b, 0x65, 0x72, 0x3d, 0x00, 0x00, 0x45, 990x6f, 0x6e, 0x61, 0x73, 0x00, 0x4b, 0x6f, 0x65, 0x6c, 0x6b,
990x00, 0xd1, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 1000x65, 0x72, 0x3d, 0x00, 0x00, 0x45, 0x00, 0xe1, 0x00, 0x68,
1000x77, 0x77, 0x77, 0x2e, 0x6e, 0xac, 0x00, 0xa2, 0x2e, 0x63, 1010x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
1010x6f, 0x2e, 0x6a, 0x70, 0x2f, 0x65, 0x6e, 0x2f, 0xcb, 0x00, 1020x2e, 0x6e, 0xad, 0x00, 0xa2, 0x2e, 0x63, 0x6f, 0x2e, 0x6a,
1020x30, 0x73, 0x2f, 0x77, 0x84, 0x00, 0x41, 0x5f, 0x69, 0x73, 1030x70, 0x2f, 0x65, 0x6e, 0x2f, 0xcc, 0x00, 0x33, 0x73, 0x2f,
1030x5f, 0xc9, 0x01, 0x20, 0x5f, 0x63, 0x84, 0x00, 0xc3, 0x2e, 1040x6b, 0x9f, 0x00, 0x83, 0x2f, 0x00, 0x00, 0x00, 0x33, 0x35,
1040x68, 0x74, 0x6d, 0x6c, 0x00, 0x00, 0x00, 0x33, 0x35, 0x2e, 1050x2e, 0x31, 0xa6, 0x04, 0x01, 0x73, 0x00, 0x40, 0x6f, 0x6c,
1050x31, 0xa3, 0x04, 0x01, 0x82, 0x00, 0x30, 0x6f, 0x6c, 0x73, 1060x73, 0x20, 0x07, 0x01, 0x46, 0x6c, 0x69, 0x63, 0x6b, 0x5d,
1060xac, 0x04, 0x56, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x6c, 0x02, 1070x02, 0x40, 0x6c, 0x65, 0x66, 0x74, 0xc1, 0x01, 0x30, 0x74,
1070x40, 0x6c, 0x65, 0x66, 0x74, 0xd0, 0x01, 0x30, 0x74, 0x6f, 1080x6f, 0x6e, 0x8e, 0x00, 0x56, 0x70, 0x61, 0x69, 0x6e, 0x74,
1080x6e, 0x9d, 0x00, 0x56, 0x70, 0x61, 0x69, 0x6e, 0x74, 0x49, 1090x3a, 0x02, 0x03, 0x66, 0x04, 0x26, 0x6f, 0x72, 0x31, 0x00,
1090x02, 0x03, 0x75, 0x04, 0x26, 0x6f, 0x72, 0x31, 0x00, 0x11, 1100x11, 0x72, 0xfd, 0x02, 0x06, 0x32, 0x00, 0x6b, 0x6d, 0x61,
1100x72, 0x0c, 0x03, 0x06, 0x32, 0x00, 0x6b, 0x6d, 0x61, 0x72, 1110x72, 0x6b, 0x00, 0x61, 0x89, 0x03, 0x21, 0x64, 0x6f, 0xf6,
1110x6b, 0x00, 0x61, 0x98, 0x03, 0x21, 0x64, 0x6f, 0x05, 0x02, 1120x01, 0x82, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65,
1120x82, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5b, 1130x4c, 0x03, 0x32, 0x79, 0x6f, 0x75, 0x95, 0x04, 0x30, 0x75,
1130x03, 0x32, 0x79, 0x6f, 0x75, 0xa4, 0x04, 0x10, 0x75, 0x38, 1140x72, 0x65, 0x4d, 0x01, 0xa0, 0x73, 0x68, 0x6f, 0x75, 0x6c,
1140x01, 0xc0, 0x74, 0x00, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 1150x64, 0x00, 0x6e, 0x6f, 0x74, 0x1f, 0x02, 0x01, 0x7a, 0x00,
1150x00, 0x6e, 0x6f, 0x74, 0x2e, 0x02, 0x01, 0x7a, 0x00, 0x06, 1160x06, 0x80, 0x04, 0x50, 0x52, 0x65, 0x70, 0x65, 0x61, 0x10,
1160x8f, 0x04, 0x50, 0x52, 0x65, 0x70, 0x65, 0x61, 0x10, 0x00, 1170x00, 0x10, 0x63, 0xb0, 0x00, 0x00, 0xbb, 0x02, 0x01, 0x5b,
1170x10, 0x63, 0xb0, 0x00, 0x00, 0xca, 0x02, 0x01, 0x5b, 0x00, 1180x00, 0x20, 0x65, 0x69, 0x36, 0x04, 0x04, 0x7f, 0x00, 0x02,
1180x20, 0x65, 0x69, 0x45, 0x04, 0x04, 0x7f, 0x00, 0x02, 0x01, 1190xf2, 0x01, 0x48, 0x79, 0x63, 0x6c, 0x65, 0x39, 0x03, 0x72,
1190x02, 0x48, 0x79, 0x63, 0x6c, 0x65, 0x48, 0x03, 0x62, 0x74, 1200x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x22, 0x03, 0x55,
1200x68, 0x72, 0x6f, 0x75, 0x67, 0xae, 0x00, 0x65, 0x74, 0x68, 1210x68, 0x72, 0x65, 0x65, 0x00, 0x91, 0x02, 0x21, 0x73, 0x74,
1210x72, 0x65, 0x65, 0x00, 0xa0, 0x02, 0x21, 0x73, 0x74, 0x64, 1220x55, 0x02, 0x30, 0x28, 0x66, 0x69, 0xd2, 0x01, 0x10, 0x2c,
1220x02, 0x30, 0x28, 0x66, 0x69, 0xe1, 0x01, 0x10, 0x2c, 0xa8, 1230xa8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x4e, 0x04, 0x50, 0x6d,
1230x00, 0x00, 0x64, 0x00, 0x00, 0x5d, 0x04, 0x50, 0x6d, 0x70, 1240x70, 0x74, 0x79, 0x29, 0x59, 0x03, 0x50, 0x6f, 0x70, 0x70,
1240x74, 0x79, 0x29, 0x68, 0x03, 0x50, 0x6f, 0x70, 0x70, 0x6f, 1250x6f, 0x73, 0x92, 0x02, 0x05, 0xbe, 0x03, 0x23, 0x73, 0x2e,
1250x73, 0xa1, 0x02, 0x05, 0xcd, 0x03, 0x23, 0x73, 0x2e, 0xe4, 1260xd5, 0x05, 0xb2, 0x63, 0x61, 0x6e, 0x00, 0x61, 0x6c, 0x73,
1260x05, 0xb2, 0x63, 0x61, 0x6e, 0x00, 0x61, 0x6c, 0x73, 0x6f, 1270x6f, 0x00, 0x75, 0x73, 0x72, 0x00, 0xb1, 0x63, 0x75, 0x72,
1270x00, 0x75, 0x73, 0x72, 0x00, 0xa1, 0x63, 0x75, 0x72, 0x73, 1280x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x73, 0x0c, 0x01,
1280x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x53, 0x02, 0x20, 0x6d, 1290x10, 0x6f, 0xf5, 0x05, 0x51, 0x72, 0x6f, 0x75, 0x6e, 0x64,
1290x6f, 0x04, 0x06, 0x51, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x1f, 1300x1f, 0x00, 0x01, 0xfe, 0x05, 0x05, 0xb9, 0x04, 0x41, 0x50,
1300x00, 0x01, 0x0d, 0x06, 0x05, 0xc8, 0x04, 0x41, 0x50, 0x72, 1310x72, 0x65, 0x73, 0xd6, 0x04, 0x94, 0x52, 0x65, 0x74, 0x75,
1310x65, 0x73, 0xe5, 0x04, 0x94, 0x52, 0x65, 0x74, 0x75, 0x72, 1320x72, 0x6e, 0x00, 0x64, 0x6f, 0xe0, 0x02, 0x30, 0x61, 0x6d,
1320x6e, 0x00, 0x64, 0x6f, 0xef, 0x02, 0x30, 0x61, 0x6d, 0x65, 1330x65, 0x6e, 0x03, 0x0a, 0xeb, 0x00, 0x0b, 0x9e, 0x01, 0x01,
1330x7d, 0x03, 0x0a, 0xeb, 0x00, 0x0b, 0x9e, 0x01, 0x01, 0x29, 1340x1a, 0x03, 0x44, 0x6c, 0x65, 0x00, 0x70, 0x46, 0x00, 0x5e,
1340x03, 0x44, 0x6c, 0x65, 0x00, 0x70, 0x46, 0x00, 0x5e, 0x53, 1350x53, 0x70, 0x61, 0x63, 0x65, 0x45, 0x00, 0x1a, 0x61, 0xa2,
1350x70, 0x61, 0x63, 0x65, 0x45, 0x00, 0x1a, 0x61, 0xa2, 0x01, 1360x01, 0x01, 0x54, 0x00, 0x59, 0x2e, 0x00, 0x4d, 0x6f, 0x76,
1360x01, 0x54, 0x00, 0x59, 0x2e, 0x00, 0x4d, 0x6f, 0x76, 0x59, 1370x59, 0x00, 0x08, 0xb9, 0x00, 0x02, 0x58, 0x00, 0x41, 0x68,
1370x00, 0x08, 0xb9, 0x00, 0x02, 0x58, 0x00, 0x41, 0x68, 0x6f, 1380x6f, 0x6c, 0x64, 0x57, 0x00, 0x42, 0x68, 0x69, 0x66, 0x74,
1380x6c, 0x64, 0x57, 0x00, 0x42, 0x68, 0x69, 0x66, 0x74, 0x5a, 1390x5a, 0x01, 0x22, 0x70, 0x6c, 0x62, 0x00, 0x21, 0x74, 0x73,
1390x01, 0x22, 0x70, 0x6c, 0x62, 0x00, 0x21, 0x74, 0x73, 0xf7, 1400xe8, 0x04, 0x25, 0x6c, 0x6c, 0x1b, 0x04, 0x01, 0xd0, 0x01,
1400x04, 0x25, 0x6c, 0x6c, 0x2a, 0x04, 0x01, 0xd0, 0x01, 0x00, 1410x00, 0x6c, 0x01, 0x00, 0xf2, 0x00, 0x14, 0x64, 0x72, 0x01,
1410x6c, 0x01, 0x00, 0xf2, 0x00, 0x14, 0x64, 0x72, 0x01, 0x00, 1420x00, 0x27, 0x01, 0x41, 0x28, 0x41, 0x6c, 0x6c, 0x62, 0x00,
1420x27, 0x01, 0x41, 0x28, 0x41, 0x6c, 0x6c, 0x62, 0x00, 0x12, 1430x12, 0x61, 0x3b, 0x01, 0x82, 0x00, 0x64, 0x65, 0x73, 0x63,
1430x61, 0x3b, 0x01, 0x82, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 1440x72, 0x69, 0x62, 0xb5, 0x04, 0x13, 0x73, 0xe5, 0x02, 0x32,
1440x69, 0x62, 0xc4, 0x04, 0x13, 0x73, 0xf4, 0x02, 0x32, 0x32, 1450x32, 0x2e, 0x31, 0x49, 0x06, 0x00, 0x4d, 0x01, 0x50, 0x61,
1450x2e, 0x31, 0x58, 0x06, 0x00, 0x4d, 0x01, 0x50, 0x61, 0x76, 1460x76, 0x61, 0x69, 0x6c, 0x78, 0x05, 0x22, 0x2e, 0x29, 0xb7,
1460x61, 0x69, 0x6c, 0x87, 0x05, 0x22, 0x2e, 0x29, 0xb7, 0x02, 1470x02, 0x13, 0x32, 0xb7, 0x02, 0x91, 0x70, 0x61, 0x72, 0x61,
1470x13, 0x32, 0xb7, 0x02, 0x91, 0x70, 0x61, 0x72, 0x61, 0x6d, 1480x6d, 0x65, 0x74, 0x65, 0x72, 0xb9, 0x02, 0x66, 0x54, 0x68,
1480x65, 0x74, 0x65, 0x72, 0xb9, 0x02, 0x66, 0x54, 0x68, 0x65, 1490x65, 0x73, 0x65, 0x00, 0x14, 0x00, 0x02, 0x41, 0x00, 0x04,
1490x73, 0x65, 0x00, 0x14, 0x00, 0x02, 0x41, 0x00, 0x04, 0x3c, 1500x3c, 0x00, 0x04, 0xb4, 0x05, 0xf1, 0x01, 0x65, 0x00, 0x60,
1500x00, 0x04, 0xc3, 0x05, 0xf1, 0x01, 0x65, 0x00, 0x60, 0x43, 1510x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27,
1510x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 1520x00, 0x6f, 0x70, 0x6f, 0x00, 0x22, 0x6f, 0x6e, 0x1a, 0x00,
1520x6f, 0x70, 0x6f, 0x00, 0x22, 0x6f, 0x6e, 0x1a, 0x00, 0xa0, 1530xa0, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e,
1530x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 1540x75, 0xab, 0x00, 0x91, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c,
1540xab, 0x00, 0x91, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 1550x00, 0x48, 0x65, 0x30, 0x01, 0x51, 0x00, 0x00, 0x53, 0x69,
1550x48, 0x65, 0x30, 0x01, 0x51, 0x00, 0x00, 0x53, 0x69, 0x7a, 1560x7a, 0x67, 0x07, 0x01, 0xb6, 0x01, 0x28, 0x69, 0x6e, 0x72,
1560x76, 0x07, 0x01, 0xb6, 0x01, 0x00, 0xad, 0x00, 0x80, 0x71, 1570x06, 0x43, 0x33, 0x35, 0x2e, 0x33, 0x95, 0x00, 0xf1, 0x00,
1570x75, 0x61, 0x72, 0x65, 0x73, 0x2e, 0x00, 1580x75, 0x73, 0x65, 0x72, 0x20, 0x70, 0x72, 0x65, 0x66, 0x65,
1590x72, 0x65, 0x6e, 0x63, 0x65, 0x9b, 0x00, 0x20, 0x4f, 0x6e,
1600x2c, 0x01, 0x63, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x38,
1610x06, 0x70, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x00, 0x2e,
1620x00, 0x17, 0x00, 0x2e, 0x00, 0x12, 0x2c, 0x89, 0x00, 0x16,
1630x50, 0x12, 0x00, 0x0d, 0xa5, 0x00, 0x33, 0x47, 0x61, 0x6d,
1640xa5, 0x00, 0x02, 0x86, 0x01, 0x22, 0x6c, 0x65, 0x3b, 0x03,
1650x60, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x3c, 0x03, 0x02,
1660x23, 0x05, 0x46, 0x77, 0x61, 0x79, 0x00, 0x6b, 0x02, 0x20,
1670x6d, 0x6f, 0x94, 0x02, 0x02, 0xf5, 0x01, 0x80, 0x73, 0x00,
1680x77, 0x6f, 0x72, 0x6b, 0x2e, 0x00,
158}; 169};
159 170
160const unsigned short help_text_len = 2036; 171const unsigned short help_text_len = 2223;
161const unsigned short help_text_words = 365; 172const unsigned short help_text_words = 395;
162const char quick_help_text[] = "Place black squares to limit the visible distance from each numbered cell."; 173const char quick_help_text[] = "Place black squares to limit the visible distance from each numbered cell.";
diff --git a/apps/plugins/puzzles/help/rect.c b/apps/plugins/puzzles/help/rect.c
index e86a77091b..c608c4fc98 100644
--- a/apps/plugins/puzzles/help/rect.c
+++ b/apps/plugins/puzzles/help/rect.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,257 +6,256 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 144, TEXT_CENTER | C_RED }, 9 { 142, TEXT_CENTER | C_RED },
10 { 311, TEXT_CENTER | C_RED }, 10 { 309, TEXT_CENTER | C_RED },
11 { 328, TEXT_UNDERLINE }, 11 { 326, TEXT_UNDERLINE },
12 { 329, TEXT_UNDERLINE }, 12 { 327, TEXT_UNDERLINE },
13 { 339, TEXT_UNDERLINE }, 13 { 337, TEXT_UNDERLINE },
14 { 381, TEXT_UNDERLINE }, 14 { 379, TEXT_UNDERLINE },
15 { 512, TEXT_UNDERLINE }, 15 { 510, TEXT_UNDERLINE },
16 { 537, TEXT_UNDERLINE }, 16 { 535, TEXT_UNDERLINE },
17 { 582, TEXT_UNDERLINE }, 17 { 580, TEXT_UNDERLINE },
18 LAST_STYLE_ITEM 18 LAST_STYLE_ITEM
19}; 19};
20 20
21/* orig 3535 comp 2341 ratio 0.662235 level 10 saved 1194 */ 21/* orig 3536 comp 2332 ratio 0.659502 level 10 saved 1204 */
22const char help_text[] = { 22const char help_text[] = {
230xf0, 0x50, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 230xff, 0x09, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
240x38, 0x3a, 0x20, 0x52, 0x65, 0x63, 0x74, 0x61, 0x6e, 0x67, 240x38, 0x3a, 0x20, 0x52, 0x65, 0x63, 0x74, 0x61, 0x6e, 0x67,
250x6c, 0x65, 0x73, 0x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 250x6c, 0x65, 0x73, 0x20, 0x00, 0x2d, 0x01, 0x00, 0x01, 0xf0,
260x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x67, 0x72, 260x3a, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61,
270x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x61, 270x76, 0x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00,
280x72, 0x65, 0x73, 0x2c, 0x00, 0x77, 0x69, 0x74, 0x68, 0x00, 280x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73,
290x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x00, 0x77, 0x72, 290x2c, 0x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x6e, 0x75, 0x6d,
300x69, 0x74, 0x74, 0x65, 0x6e, 0x00, 0x69, 0x6e, 0x00, 0x73, 300x62, 0x65, 0x72, 0x73, 0x00, 0x77, 0x72, 0x69, 0x74, 0x74,
310x6f, 0x6d, 0x65, 0x00, 0x28, 0x62, 0x75, 0x74, 0x00, 0x6e, 310x65, 0x6e, 0x00, 0x69, 0x6e, 0x00, 0x73, 0x6f, 0x6d, 0x65,
320x6f, 0x74, 0x00, 0x61, 0x6c, 0x6c, 0x29, 0x37, 0x00, 0x34, 320x00, 0x28, 0x62, 0x75, 0x74, 0x00, 0x6e, 0x6f, 0x74, 0x00,
330x74, 0x68, 0x65, 0x3b, 0x00, 0x10, 0x2e, 0x57, 0x00, 0xf1, 330x61, 0x6c, 0x6c, 0x29, 0x37, 0x00, 0x34, 0x74, 0x68, 0x65,
340x07, 0x72, 0x00, 0x74, 0x61, 0x73, 0x6b, 0x00, 0x69, 0x73, 340x3b, 0x00, 0x10, 0x2e, 0x57, 0x00, 0xf1, 0x07, 0x72, 0x00,
350x00, 0x74, 0x6f, 0x00, 0x73, 0x75, 0x62, 0x64, 0x69, 0x76, 350x74, 0x61, 0x73, 0x6b, 0x00, 0x69, 0x73, 0x00, 0x74, 0x6f,
360x69, 0x64, 0x65, 0x27, 0x00, 0x01, 0x6a, 0x00, 0x65, 0x69, 360x00, 0x73, 0x75, 0x62, 0x64, 0x69, 0x76, 0x69, 0x64, 0x65,
370x6e, 0x74, 0x6f, 0x00, 0x72, 0x8d, 0x00, 0x00, 0x43, 0x00, 370x27, 0x00, 0x01, 0x6a, 0x00, 0x65, 0x69, 0x6e, 0x74, 0x6f,
380xb0, 0x76, 0x61, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x00, 0x73, 380x00, 0x72, 0xa3, 0x00, 0x00, 0x43, 0x00, 0xb0, 0x76, 0x61,
390x69, 0x7a, 0x80, 0x00, 0xf6, 0x04, 0x73, 0x75, 0x63, 0x68, 390x72, 0x69, 0x6f, 0x75, 0x73, 0x00, 0x73, 0x69, 0x7a, 0x80,
400x00, 0x74, 0x68, 0x61, 0x74, 0x00, 0x28, 0x61, 0x29, 0x00, 400x00, 0xf6, 0x04, 0x73, 0x75, 0x63, 0x68, 0x00, 0x74, 0x68,
410x65, 0x76, 0x65, 0x72, 0x79, 0x31, 0x00, 0xf3, 0x06, 0x00, 410x61, 0x74, 0x00, 0x28, 0x61, 0x29, 0x00, 0x65, 0x76, 0x65,
420x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x00, 0x65, 420x72, 0x79, 0x31, 0x00, 0xf3, 0x06, 0x00, 0x63, 0x6f, 0x6e,
430x78, 0x61, 0x63, 0x74, 0x6c, 0x79, 0x00, 0x6f, 0x6e, 0x65, 430x74, 0x61, 0x69, 0x6e, 0x73, 0x00, 0x65, 0x78, 0x61, 0x63,
440xae, 0x00, 0x23, 0x65, 0x64, 0x8a, 0x00, 0x91, 0x2c, 0x00, 440x74, 0x6c, 0x79, 0x00, 0x6f, 0x6e, 0x65, 0xae, 0x00, 0x23,
450x61, 0x6e, 0x64, 0x00, 0x28, 0x62, 0x29, 0x77, 0x00, 0x40, 450x65, 0x64, 0x8a, 0x00, 0x91, 0x2c, 0x00, 0x61, 0x6e, 0x64,
460x61, 0x72, 0x65, 0x61, 0x67, 0x00, 0x47, 0x65, 0x61, 0x63, 460x00, 0x28, 0x62, 0x29, 0x77, 0x00, 0x40, 0x61, 0x72, 0x65,
470x68, 0x49, 0x00, 0x80, 0x69, 0x73, 0x00, 0x65, 0x71, 0x75, 470x61, 0x67, 0x00, 0x47, 0x65, 0x61, 0x63, 0x68, 0x49, 0x00,
480x61, 0x6c, 0xa8, 0x00, 0x24, 0x74, 0x68, 0x44, 0x00, 0x08, 480x80, 0x69, 0x73, 0x00, 0x65, 0x71, 0x75, 0x61, 0x6c, 0xa8,
490xf1, 0x00, 0x3c, 0x69, 0x74, 0x73, 0x5a, 0x00, 0xf4, 0x0e, 490x00, 0x24, 0x74, 0x68, 0x44, 0x00, 0x08, 0xf1, 0x00, 0x3c,
500x2e, 0x00, 0x00, 0x00, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 500x69, 0x74, 0x73, 0x5a, 0x00, 0xf4, 0x0e, 0x2e, 0x00, 0x00,
510x00, 0x66, 0x6f, 0x72, 0x00, 0x74, 0x68, 0x69, 0x73, 0x00, 510x00, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x00, 0x66, 0x6f,
520x67, 0x61, 0x6d, 0x65, 0x00, 0x67, 0x6f, 0x65, 0x73, 0x4a, 520x72, 0x00, 0x74, 0x68, 0x69, 0x73, 0x00, 0x67, 0x61, 0x6d,
530x00, 0xf0, 0x18, 0x4a, 0x61, 0x70, 0x61, 0x6e, 0x65, 0x73, 530x65, 0x00, 0x67, 0x6f, 0x65, 0x73, 0x4a, 0x00, 0xf0, 0x18,
540x65, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x6d, 540x4a, 0x61, 0x70, 0x61, 0x6e, 0x65, 0x73, 0x65, 0x00, 0x70,
550x61, 0x67, 0x61, 0x7a, 0x69, 0x6e, 0x65, 0x00, 0x4e, 0x69, 550x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x6d, 0x61, 0x67, 0x61,
560x6b, 0x6f, 0x6c, 0x69, 0x00, 0x5b, 0x33, 0x5d, 0x3b, 0x00, 560x7a, 0x69, 0x6e, 0x65, 0x00, 0x4e, 0x69, 0x6b, 0x6f, 0x6c,
570x49, 0x27, 0x7e, 0x01, 0xf2, 0x14, 0x6c, 0x73, 0x6f, 0x00, 570x69, 0x00, 0x5b, 0x33, 0x5d, 0x3b, 0x00, 0x49, 0x27, 0x7e,
580x73, 0x65, 0x65, 0x6e, 0x00, 0x61, 0x00, 0x50, 0x61, 0x6c, 580x01, 0xf2, 0x14, 0x6c, 0x73, 0x6f, 0x00, 0x73, 0x65, 0x65,
590x6d, 0x00, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 590x6e, 0x00, 0x61, 0x00, 0x50, 0x61, 0x6c, 0x6d, 0x00, 0x69,
600x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x61, 0x74, 0x00, 600x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74,
610x50, 0x44, 0x00, 0xfa, 0x03, 0x50, 0x61, 0x6c, 0x61, 0x63, 610x69, 0x6f, 0x6e, 0x00, 0x61, 0x74, 0x00, 0x50, 0x44, 0x00,
620x65, 0x00, 0x5b, 0x34, 0x5d, 0x2e, 0x00, 0x55, 0x6e, 0x6c, 620xfa, 0x03, 0x50, 0x61, 0x6c, 0x61, 0x63, 0x65, 0x00, 0x5b,
630x69, 0x6b, 0x65, 0x1a, 0x00, 0x2b, 0x27, 0x73, 0x3c, 0x00, 630x34, 0x5d, 0x2e, 0x00, 0x55, 0x6e, 0x6c, 0x69, 0x6b, 0x65,
640x91, 0x2c, 0x00, 0x6d, 0x79, 0x00, 0x76, 0x65, 0x72, 0x73, 640x1a, 0x00, 0x2b, 0x27, 0x73, 0x3c, 0x00, 0x91, 0x2c, 0x00,
650x48, 0x00, 0xf1, 0x0e, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 650x6d, 0x79, 0x00, 0x76, 0x65, 0x72, 0x73, 0x48, 0x00, 0xf1,
660x69, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x00, 0x67, 0x65, 0x6e, 660x0e, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61,
670x65, 0x72, 0x61, 0x74, 0x65, 0x73, 0x00, 0x72, 0x61, 0x6e, 670x6c, 0x6c, 0x79, 0x00, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61,
680x64, 0x6f, 0x6d, 0x99, 0x01, 0x01, 0x8a, 0x01, 0x31, 0x61, 680x74, 0x65, 0x73, 0x00, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d,
690x6e, 0x79, 0x86, 0x01, 0x50, 0x00, 0x79, 0x6f, 0x75, 0x00, 690x99, 0x01, 0x01, 0x8a, 0x01, 0x31, 0x61, 0x6e, 0x79, 0x86,
700x65, 0x00, 0x60, 0x2e, 0x00, 0x54, 0x68, 0x65, 0x00, 0x27, 700x01, 0x50, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x65, 0x00, 0x60,
710x01, 0x30, 0x69, 0x74, 0x79, 0x22, 0x00, 0x03, 0xd3, 0x00, 710x2e, 0x00, 0x54, 0x68, 0x65, 0x00, 0x27, 0x01, 0x30, 0x69,
720x61, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0xe6, 0x01, 0x81, 720x74, 0x79, 0x22, 0x00, 0x03, 0xd3, 0x00, 0x61, 0x64, 0x65,
730x68, 0x65, 0x72, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x16, 0x02, 730x73, 0x69, 0x67, 0x6e, 0xe6, 0x01, 0x81, 0x68, 0x65, 0x72,
740xd0, 0x71, 0x75, 0x69, 0x74, 0x65, 0x00, 0x61, 0x73, 0x00, 740x65, 0x66, 0x6f, 0x72, 0x65, 0x16, 0x02, 0xd0, 0x71, 0x75,
750x67, 0x6f, 0x6f, 0x64, 0x08, 0x00, 0xc3, 0x68, 0x61, 0x6e, 750x69, 0x74, 0x65, 0x00, 0x61, 0x73, 0x00, 0x67, 0x6f, 0x6f,
760x64, 0x2d, 0x63, 0x72, 0x61, 0x66, 0x74, 0x65, 0x64, 0x3d, 760x64, 0x08, 0x00, 0xc3, 0x68, 0x61, 0x6e, 0x64, 0x2d, 0x63,
770x00, 0xc0, 0x73, 0x00, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x00, 770x72, 0x61, 0x66, 0x74, 0x65, 0x64, 0x3d, 0x00, 0xc0, 0x73,
780x62, 0x65, 0x2c, 0x00, 0x4e, 0x02, 0x21, 0x6f, 0x6e, 0x36, 780x00, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x00, 0x62, 0x65, 0x2c,
790x01, 0x21, 0x70, 0x6c, 0x03, 0x02, 0x12, 0x64, 0x7d, 0x00, 790x00, 0x4e, 0x02, 0x21, 0x6f, 0x6e, 0x36, 0x01, 0x21, 0x70,
800x50, 0x67, 0x65, 0x74, 0x00, 0x61, 0x86, 0x01, 0xf7, 0x02, 800x6c, 0x03, 0x02, 0x12, 0x64, 0x7d, 0x00, 0x50, 0x67, 0x65,
810x65, 0x78, 0x68, 0x61, 0x75, 0x73, 0x74, 0x69, 0x62, 0x6c, 810x74, 0x00, 0x61, 0x86, 0x01, 0xf7, 0x02, 0x65, 0x78, 0x68,
820x65, 0x00, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x87, 0x00, 0x70, 820x61, 0x75, 0x73, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x00, 0x73,
830x73, 0x00, 0x74, 0x61, 0x69, 0x6c, 0x6f, 0x9f, 0x01, 0x40, 830x75, 0x70, 0x70, 0x6c, 0x87, 0x00, 0x70, 0x73, 0x00, 0x74,
840x74, 0x6f, 0x00, 0x79, 0x7d, 0x02, 0xc1, 0x6f, 0x77, 0x6e, 840x61, 0x69, 0x6c, 0x6f, 0x9f, 0x01, 0x40, 0x74, 0x6f, 0x00,
850x00, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x08, 850x79, 0x7d, 0x02, 0xc1, 0x6f, 0x77, 0x6e, 0x00, 0x73, 0x70,
860x01, 0x00, 0xb2, 0x01, 0xf1, 0x01, 0x5b, 0x33, 0x5d, 0x00, 860x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x08, 0x01, 0x00, 0xb2,
870x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 870x01, 0xf1, 0x02, 0x5b, 0x33, 0x5d, 0x00, 0x68, 0x74, 0x74,
880x2e, 0x6e, 0x87, 0x01, 0xa3, 0x2e, 0x63, 0x6f, 0x2e, 0x6a, 880x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e,
890x70, 0x2f, 0x65, 0x6e, 0x2f, 0x4d, 0x00, 0xf0, 0x06, 0x2f, 890x88, 0x01, 0xa3, 0x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f,
900x73, 0x68, 0x69, 0x6b, 0x61, 0x6b, 0x75, 0x2e, 0x68, 0x74, 900x65, 0x6e, 0x2f, 0x4e, 0x00, 0x90, 0x2f, 0x73, 0x68, 0x69,
910x6d, 0x6c, 0x00, 0x28, 0x62, 0x65, 0x77, 0x61, 0x72, 0x65, 910x6b, 0x61, 0x6b, 0x75, 0x2f, 0x33, 0x00, 0x17, 0x34, 0x33,
920x6d, 0x00, 0x60, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x29, 0x48, 920x00, 0xe0, 0x65, 0x62, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69,
930x00, 0x12, 0x34, 0x48, 0x00, 0x10, 0x73, 0x49, 0x00, 0xe0, 930x76, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x10, 0x00, 0xf0, 0x01,
940x65, 0x62, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 940x2f, 0x32, 0x30, 0x30, 0x34, 0x31, 0x30, 0x32, 0x34, 0x30,
950x2e, 0x6f, 0x72, 0x67, 0x10, 0x00, 0xf7, 0x01, 0x2f, 0x32, 950x30, 0x31, 0x34, 0x35, 0x39, 0x2f, 0x2b, 0x00, 0x03, 0x5d,
960x30, 0x30, 0x34, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, 0x31, 960x00, 0x02, 0x4d, 0x00, 0x30, 0x2e, 0x67, 0x72, 0x5d, 0x00,
970x34, 0x35, 0x39, 0x2f, 0x73, 0x00, 0x02, 0x63, 0x00, 0x30, 970x02, 0x0d, 0x00, 0x22, 0x2f, 0x73, 0x58, 0x00, 0xf8, 0x09,
980x2e, 0x67, 0x72, 0x73, 0x00, 0x02, 0x0d, 0x00, 0x21, 0x2f, 980x70, 0x61, 0x6c, 0x6d, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78,
990x73, 0x6e, 0x00, 0xb1, 0x2f, 0x70, 0x61, 0x6c, 0x6d, 0x2f, 990x2e, 0x68, 0x74, 0x6d, 0x6c, 0x2e, 0x65, 0x6e, 0x00, 0x00,
1000x69, 0x6e, 0x64, 0x65, 0x78, 0x79, 0x00, 0x98, 0x2e, 0x65, 1000x00, 0x38, 0x2e, 0x31, 0xb3, 0x03, 0x00, 0xe0, 0x02, 0x95,
1010x6e, 0x00, 0x00, 0x00, 0x38, 0x2e, 0x31, 0xb2, 0x03, 0x00, 1010x72, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00, 0x00, 0x54, 0x5f,
1020xf5, 0x02, 0x31, 0x72, 0x6f, 0x6c, 0xbb, 0x03, 0x15, 0x54, 1020x02, 0x92, 0x69, 0x73, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x65,
1030x74, 0x02, 0x92, 0x69, 0x73, 0x00, 0x70, 0x6c, 0x61, 0x79, 1030x64, 0x9e, 0x03, 0x00, 0x30, 0x01, 0xf0, 0x05, 0x6d, 0x6f,
1040x65, 0x64, 0xb3, 0x03, 0x00, 0x45, 0x01, 0xf0, 0x05, 0x6d, 1040x75, 0x73, 0x65, 0x00, 0x6f, 0x72, 0x00, 0x63, 0x75, 0x72,
1050x6f, 0x75, 0x73, 0x65, 0x00, 0x6f, 0x72, 0x00, 0x63, 0x75, 1050x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x73, 0xed, 0x00,
1060x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x73, 0x02, 1060xa1, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63,
1070x01, 0xa1, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 1070x6b, 0xcf, 0x01, 0x41, 0x65, 0x64, 0x67, 0x65, 0x99, 0x02,
1080x63, 0x6b, 0xe4, 0x01, 0x41, 0x65, 0x64, 0x67, 0x65, 0xae, 1080x21, 0x6f, 0x67, 0xf6, 0x02, 0x01, 0x70, 0x01, 0x70, 0x6f,
1090x02, 0x21, 0x6f, 0x67, 0x0b, 0x03, 0x01, 0x85, 0x01, 0x70, 1090x72, 0x00, 0x6f, 0x66, 0x66, 0x2c, 0x08, 0x00, 0x18, 0x6c,
1100x6f, 0x72, 0x00, 0x6f, 0x66, 0x66, 0x2c, 0x08, 0x00, 0x18, 1100x2f, 0x00, 0x60, 0x64, 0x00, 0x64, 0x72, 0x61, 0x67, 0x2f,
1110x6c, 0x2f, 0x00, 0x60, 0x64, 0x00, 0x64, 0x72, 0x61, 0x67, 1110x00, 0x40, 0x64, 0x72, 0x61, 0x77, 0x81, 0x01, 0x67, 0x65,
1120x2f, 0x00, 0x40, 0x64, 0x72, 0x61, 0x77, 0x96, 0x01, 0x67, 1120x6e, 0x74, 0x69, 0x72, 0x65, 0x37, 0x03, 0x10, 0x28, 0x34,
1130x65, 0x6e, 0x74, 0x69, 0x72, 0x65, 0x4c, 0x03, 0x10, 0x28, 1130x00, 0x44, 0x69, 0x6e, 0x65, 0x29, 0xb8, 0x01, 0x03, 0xd6,
1140x34, 0x00, 0x44, 0x69, 0x6e, 0x65, 0x29, 0xcd, 0x01, 0x03, 1140x03, 0x01, 0x88, 0x03, 0xc2, 0x67, 0x6f, 0x00, 0x28, 0x72,
1150xeb, 0x03, 0x01, 0x9d, 0x03, 0xc2, 0x67, 0x6f, 0x00, 0x28, 1150x65, 0x6d, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x7e, 0x00, 0x40,
1160x72, 0x65, 0x6d, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x7e, 0x00, 1160x78, 0x69, 0x73, 0x74, 0x0d, 0x00, 0x00, 0x87, 0x00, 0x11,
1170x40, 0x78, 0x69, 0x73, 0x74, 0x0d, 0x00, 0x00, 0x87, 0x00, 1170x73, 0xbd, 0x00, 0x22, 0x69, 0x6e, 0xdd, 0x03, 0x05, 0x53,
1180x11, 0x73, 0xbd, 0x00, 0x22, 0x69, 0x6e, 0xf2, 0x03, 0x05, 1180x00, 0x73, 0x29, 0x2e, 0x00, 0x52, 0x69, 0x67, 0x68, 0x86,
1190x53, 0x00, 0x73, 0x29, 0x2e, 0x00, 0x52, 0x69, 0x67, 0x68, 1190x00, 0x02, 0x3a, 0x00, 0x02, 0x89, 0x00, 0x10, 0x67, 0x0d,
1200x86, 0x00, 0x02, 0x3a, 0x00, 0x02, 0x89, 0x00, 0x10, 0x67, 1200x00, 0x40, 0x77, 0x69, 0x6c, 0x6c, 0x6e, 0x04, 0x21, 0x6f,
1210x0d, 0x00, 0x40, 0x77, 0x69, 0x6c, 0x6c, 0x83, 0x04, 0x21, 1210x77, 0x19, 0x02, 0x72, 0x74, 0x6f, 0x00, 0x65, 0x72, 0x61,
1220x6f, 0x77, 0x2e, 0x02, 0x72, 0x74, 0x6f, 0x00, 0x65, 0x72, 1220x73, 0x52, 0x04, 0x00, 0x2d, 0x01, 0x32, 0x65, 0x6e, 0x74,
1230x61, 0x73, 0x67, 0x04, 0x00, 0x2d, 0x01, 0x32, 0x65, 0x6e, 1230xbc, 0x02, 0x07, 0xa5, 0x00, 0x00, 0x68, 0x00, 0x91, 0x6f,
1240x74, 0xd1, 0x02, 0x07, 0xa5, 0x00, 0x00, 0x68, 0x00, 0x91, 1240x75, 0x74, 0x00, 0x61, 0x66, 0x66, 0x65, 0x63, 0x80, 0x00,
1250x6f, 0x75, 0x74, 0x00, 0x61, 0x66, 0x66, 0x65, 0x63, 0x80, 1250x00, 0xcc, 0x03, 0x01, 0x84, 0x00, 0x00, 0x23, 0x01, 0xf4,
1260x00, 0x00, 0xe1, 0x03, 0x01, 0x84, 0x00, 0x00, 0x23, 0x01, 1260x01, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69,
1270xf4, 0x01, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 1270x76, 0x65, 0x6c, 0x79, 0x2c, 0x00, 0x75, 0x4e, 0x00, 0x06,
1280x69, 0x76, 0x65, 0x6c, 0x79, 0x2c, 0x00, 0x75, 0x4e, 0x00, 1280x49, 0x01, 0x00, 0x67, 0x00, 0x42, 0x6d, 0x6f, 0x76, 0x65,
1290x06, 0x49, 0x01, 0x00, 0x67, 0x00, 0x42, 0x6d, 0x6f, 0x76, 1290x9a, 0x02, 0x31, 0x6f, 0x73, 0x69, 0x8f, 0x03, 0x30, 0x69,
1300x65, 0xaf, 0x02, 0x31, 0x6f, 0x73, 0x69, 0xa4, 0x03, 0x30, 1300x6e, 0x64, 0x56, 0x02, 0x91, 0x6f, 0x72, 0x00, 0x61, 0x72,
1310x69, 0x6e, 0x64, 0x6b, 0x02, 0x91, 0x6f, 0x72, 0x00, 0x61, 1310x6f, 0x75, 0x6e, 0x64, 0x1e, 0x00, 0xc0, 0x62, 0x6f, 0x61,
1320x72, 0x6f, 0x75, 0x6e, 0x64, 0x1e, 0x00, 0xc0, 0x62, 0x6f, 1320x72, 0x64, 0x2e, 0x00, 0x50, 0x72, 0x65, 0x73, 0x73, 0x6a,
1330x61, 0x72, 0x64, 0x2e, 0x00, 0x50, 0x72, 0x65, 0x73, 0x73, 1330x00, 0x20, 0x74, 0x68, 0x2f, 0x01, 0x40, 0x74, 0x75, 0x72,
1340x6a, 0x00, 0x20, 0x74, 0x68, 0x2f, 0x01, 0x40, 0x74, 0x75, 1340x6e, 0x4a, 0x00, 0x00, 0x0f, 0x00, 0x12, 0x6e, 0xbf, 0x00,
1350x72, 0x6e, 0x4a, 0x00, 0x00, 0x0f, 0x00, 0x12, 0x6e, 0xbf, 1350x14, 0x73, 0xc0, 0x00, 0x0f, 0x70, 0x00, 0x04, 0x01, 0x7b,
1360x00, 0x14, 0x73, 0xc0, 0x00, 0x0f, 0x70, 0x00, 0x04, 0x01, 1360x01, 0x08, 0xc6, 0x00, 0x00, 0xc2, 0x00, 0x42, 0x66, 0x72,
1370x7b, 0x01, 0x08, 0xc6, 0x00, 0x00, 0xc2, 0x00, 0x42, 0x66, 1370x6f, 0x6d, 0x30, 0x01, 0x04, 0x86, 0x00, 0x02, 0xdd, 0x04,
1380x72, 0x6f, 0x6d, 0x30, 0x01, 0x04, 0x86, 0x00, 0x02, 0xf2, 1380x1f, 0x70, 0x6f, 0x00, 0x04, 0x80, 0x61, 0x67, 0x61, 0x69,
1390x04, 0x1f, 0x70, 0x6f, 0x00, 0x04, 0x80, 0x61, 0x67, 0x61, 1390x6e, 0x00, 0x63, 0x6f, 0x0c, 0x04, 0x21, 0x74, 0x65, 0x9f,
1400x69, 0x6e, 0x00, 0x63, 0x6f, 0x21, 0x04, 0x21, 0x74, 0x65, 1400x03, 0x06, 0x52, 0x00, 0x35, 0x2e, 0x00, 0x55, 0x34, 0x00,
1410xb4, 0x03, 0x06, 0x52, 0x00, 0x35, 0x2e, 0x00, 0x55, 0x34, 1410x20, 0x73, 0x70, 0x50, 0x04, 0xa1, 0x62, 0x61, 0x72, 0x00,
1420x00, 0x20, 0x73, 0x70, 0x65, 0x04, 0xa1, 0x62, 0x61, 0x72, 1420x69, 0x6e, 0x73, 0x74, 0x65, 0x61, 0x04, 0x06, 0x0c, 0x4d,
1430x00, 0x69, 0x6e, 0x73, 0x74, 0x65, 0x61, 0x19, 0x06, 0x0c, 1430x00, 0x09, 0xb7, 0x00, 0x0f, 0x77, 0x01, 0x2a, 0x10, 0x2c,
1440x4d, 0x00, 0x09, 0xb7, 0x00, 0x0f, 0x77, 0x01, 0x2a, 0x10, 1440x0d, 0x04, 0x57, 0x61, 0x62, 0x6f, 0x76, 0x65, 0x2b, 0x01,
1450x2c, 0x22, 0x04, 0x57, 0x61, 0x62, 0x6f, 0x76, 0x65, 0x2b, 1450xf1, 0x01, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x00, 0x63,
1460x01, 0xf1, 0x01, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x00, 1460x61, 0x6e, 0x63, 0x65, 0x6c, 0x73, 0x00, 0x61, 0x03, 0x01,
1470x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x73, 0x00, 0x61, 0x03, 1470x00, 0xa1, 0x01, 0x11, 0x57, 0x35, 0x01, 0x08, 0x0b, 0x01,
1480x01, 0x00, 0xa1, 0x01, 0x11, 0x57, 0x35, 0x01, 0x08, 0x0b, 1480x13, 0x66, 0x79, 0x00, 0x10, 0x72, 0x14, 0x00, 0x02, 0xa4,
1490x01, 0x13, 0x66, 0x79, 0x00, 0x10, 0x72, 0x14, 0x00, 0x02, 1490x04, 0x25, 0x69, 0x73, 0xe8, 0x00, 0x20, 0x64, 0x2c, 0xd9,
1500xb9, 0x04, 0x25, 0x69, 0x73, 0xe8, 0x00, 0x20, 0x64, 0x2c, 1500x02, 0x01, 0x2a, 0x02, 0x90, 0x62, 0x65, 0x00, 0x73, 0x68,
1510xd9, 0x02, 0x01, 0x2a, 0x02, 0x90, 0x62, 0x65, 0x00, 0x73, 1510x61, 0x64, 0x65, 0x64, 0x48, 0x00, 0x42, 0x28, 0x41, 0x6c,
1520x68, 0x61, 0x64, 0x65, 0x64, 0x48, 0x00, 0x42, 0x28, 0x41, 1520x6c, 0x04, 0x06, 0x10, 0x63, 0x3b, 0x01, 0x10, 0x73, 0xb8,
1530x6c, 0x6c, 0x19, 0x06, 0x10, 0x63, 0x3b, 0x01, 0x10, 0x73, 1530x04, 0x61, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0xd1, 0x06,
1540xcd, 0x04, 0x61, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0xe6, 1540x21, 0x65, 0x63, 0xd7, 0x01, 0x30, 0x32, 0x2e, 0x31, 0x25,
1550x06, 0x21, 0x65, 0x63, 0xd7, 0x01, 0x30, 0x32, 0x2e, 0x31, 1550x06, 0x02, 0x8e, 0x05, 0xb1, 0x61, 0x76, 0x61, 0x69, 0x6c,
1560x3a, 0x06, 0x02, 0xa3, 0x05, 0xb1, 0x61, 0x76, 0x61, 0x69, 1560x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0x9d, 0x03, 0x18, 0x32,
1570x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0x9d, 0x03, 0x18, 1570x9d, 0x03, 0x93, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74,
1580x32, 0x9d, 0x03, 0x93, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 1580x65, 0x72, 0x9f, 0x03, 0x01, 0xe5, 0x05, 0x05, 0x14, 0x00,
1590x74, 0x65, 0x72, 0x9f, 0x03, 0x01, 0xfa, 0x05, 0x05, 0x14, 1590x02, 0x45, 0x00, 0x04, 0x40, 0x00, 0x04, 0xbb, 0x01, 0xf1,
1600x00, 0x02, 0x45, 0x00, 0x04, 0x40, 0x00, 0x04, 0xbb, 0x01, 1600x01, 0x65, 0x00, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d,
1610xf1, 0x01, 0x65, 0x00, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 1610x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x73, 0x00, 0x03,
1620x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x73, 0x00, 1620x3c, 0x03, 0xb1, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00,
1630x03, 0x3c, 0x03, 0xb1, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 1630x6d, 0x65, 0x6e, 0x75, 0xf7, 0x00, 0x80, 0x69, 0x64, 0x74,
1640x00, 0x6d, 0x65, 0x6e, 0x75, 0xf7, 0x00, 0x80, 0x69, 0x64, 1640x68, 0x2c, 0x00, 0x48, 0x65, 0x0f, 0x03, 0x61, 0x00, 0x00,
1650x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x0f, 0x03, 0x61, 0x00, 1650x00, 0x53, 0x69, 0x7a, 0xfb, 0x00, 0x00, 0x63, 0x03, 0x11,
1660x00, 0x00, 0x53, 0x69, 0x7a, 0xfb, 0x00, 0x00, 0x63, 0x03, 1660x2c, 0xb2, 0x00, 0x04, 0x69, 0x07, 0x70, 0x00, 0x00, 0x45,
1670x11, 0x2c, 0xb2, 0x00, 0x04, 0x7e, 0x07, 0x70, 0x00, 0x00, 1670x78, 0x70, 0x61, 0x6e, 0xdd, 0x05, 0x40, 0x20, 0x66, 0x61,
1680x45, 0x78, 0x70, 0x61, 0x6e, 0xf2, 0x05, 0x40, 0x20, 0x66, 1680x63, 0x93, 0x02, 0x03, 0x2f, 0x04, 0x10, 0x69, 0x48, 0x01,
1690x61, 0x63, 0x93, 0x02, 0x03, 0x2f, 0x04, 0x10, 0x69, 0x48, 1690x91, 0x6d, 0x65, 0x63, 0x68, 0x61, 0x6e, 0x69, 0x73, 0x6d,
1700x01, 0x91, 0x6d, 0x65, 0x63, 0x68, 0x61, 0x6e, 0x69, 0x73, 1700xa6, 0x06, 0x00, 0x0c, 0x00, 0x14, 0x67, 0xf8, 0x01, 0x35,
1710x6d, 0xbb, 0x06, 0x00, 0x0c, 0x00, 0x14, 0x67, 0xf8, 0x01, 1710x74, 0x79, 0x70, 0x54, 0x00, 0x15, 0x73, 0x0b, 0x06, 0x42,
1720x35, 0x74, 0x79, 0x70, 0x54, 0x00, 0x15, 0x73, 0x20, 0x06, 1720x64, 0x00, 0x62, 0x79, 0xec, 0x02, 0x90, 0x72, 0x6f, 0x67,
1730x42, 0x64, 0x00, 0x62, 0x79, 0xec, 0x02, 0x90, 0x72, 0x6f, 1730x72, 0x61, 0x6d, 0x2e, 0x00, 0x53, 0xee, 0x07, 0x60, 0x70,
1740x67, 0x72, 0x61, 0x6d, 0x2e, 0x00, 0x53, 0x03, 0x08, 0x60, 1740x65, 0x6f, 0x70, 0x6c, 0x65, 0x6d, 0x02, 0x34, 0x66, 0x65,
1750x70, 0x65, 0x6f, 0x70, 0x6c, 0x65, 0x6d, 0x02, 0x34, 0x66, 1750x72, 0x2c, 0x08, 0x03, 0x82, 0x07, 0x01, 0xa9, 0x03, 0x97,
1760x65, 0x72, 0x41, 0x08, 0x03, 0x97, 0x07, 0x01, 0xa9, 0x03, 1760x00, 0x66, 0x65, 0x77, 0x00, 0x6c, 0x61, 0x72, 0x67, 0x66,
1770x97, 0x00, 0x66, 0x65, 0x77, 0x00, 0x6c, 0x61, 0x72, 0x67, 1770x02, 0x01, 0xcd, 0x02, 0x00, 0x0e, 0x04, 0x07, 0x29, 0x00,
1780x66, 0x02, 0x01, 0xcd, 0x02, 0x00, 0x0e, 0x04, 0x07, 0x29, 1780x11, 0x6d, 0x5a, 0x06, 0x40, 0x6d, 0x61, 0x6c, 0x6c, 0x1a,
1790x00, 0x11, 0x6d, 0x6f, 0x06, 0x40, 0x6d, 0x61, 0x6c, 0x6c, 1790x00, 0x10, 0x73, 0x5f, 0x00, 0x01, 0x57, 0x02, 0x40, 0x63,
1800x1a, 0x00, 0x10, 0x73, 0x5f, 0x00, 0x01, 0x57, 0x02, 0x40, 1800x61, 0x6e, 0x00, 0x2f, 0x08, 0x19, 0x52, 0x3d, 0x00, 0x30,
1810x63, 0x61, 0x6e, 0x00, 0x44, 0x08, 0x19, 0x52, 0x3d, 0x00, 1810x65, 0x73, 0x73, 0x78, 0x04, 0x09, 0xad, 0x06, 0x22, 0x00,
1820x30, 0x65, 0x73, 0x73, 0x78, 0x04, 0x09, 0xc2, 0x06, 0x22, 1820x61, 0x40, 0x00, 0x22, 0x65, 0x72, 0x86, 0x00, 0x32, 0x74,
1830x00, 0x61, 0x40, 0x00, 0x22, 0x65, 0x72, 0x86, 0x00, 0x32, 1830x68, 0x61, 0x44, 0x01, 0x05, 0xb0, 0x06, 0x03, 0xf7, 0x05,
1840x74, 0x68, 0x61, 0x44, 0x01, 0x05, 0xc5, 0x06, 0x03, 0x0c, 1840x22, 0x65, 0x64, 0x22, 0x03, 0x01, 0x79, 0x03, 0x00, 0x4d,
1850x06, 0x22, 0x65, 0x64, 0x22, 0x03, 0x01, 0x79, 0x03, 0x00, 1850x00, 0x00, 0x29, 0x01, 0x10, 0x64, 0x20, 0x02, 0x60, 0x62,
1860x4d, 0x00, 0x00, 0x29, 0x01, 0x10, 0x64, 0x20, 0x02, 0x60, 1860x79, 0x00, 0x61, 0x64, 0x64, 0x8f, 0x00, 0x10, 0x72, 0xd7,
1870x62, 0x79, 0x00, 0x61, 0x64, 0x64, 0x8f, 0x00, 0x10, 0x72, 1870x02, 0x20, 0x61, 0x6e, 0xcc, 0x00, 0x41, 0x6c, 0x75, 0x6d,
1880xd7, 0x02, 0x20, 0x61, 0x6e, 0xcc, 0x00, 0x41, 0x6c, 0x75, 1880x6e, 0x51, 0x01, 0x00, 0xe9, 0x06, 0x72, 0x64, 0x65, 0x66,
1890x6d, 0x6e, 0x51, 0x01, 0x00, 0xfe, 0x06, 0x72, 0x64, 0x65, 1890x61, 0x75, 0x6c, 0x74, 0x34, 0x00, 0x01, 0x3a, 0x07, 0x03,
1900x66, 0x61, 0x75, 0x6c, 0x74, 0x34, 0x00, 0x01, 0x4f, 0x07, 1900x5d, 0x01, 0xd2, 0x6f, 0x66, 0x00, 0x7a, 0x65, 0x72, 0x6f,
1910x03, 0x5d, 0x01, 0xd2, 0x6f, 0x66, 0x00, 0x7a, 0x65, 0x72, 1910x00, 0x6d, 0x65, 0x61, 0x6e, 0x73, 0x90, 0x03, 0x07, 0xb3,
1920x6f, 0x00, 0x6d, 0x65, 0x61, 0x6e, 0x73, 0x90, 0x03, 0x07, 1920x00, 0x01, 0x79, 0x02, 0x10, 0x73, 0x80, 0x07, 0x09, 0xb0,
1930xb3, 0x00, 0x01, 0x79, 0x02, 0x10, 0x73, 0x95, 0x07, 0x09, 1930x00, 0x04, 0x5a, 0x09, 0x09, 0xa6, 0x00, 0x00, 0xee, 0x00,
1940xb0, 0x00, 0x04, 0x6f, 0x09, 0x09, 0xa6, 0x00, 0x00, 0xee, 1940x42, 0x66, 0x6f, 0x72, 0x2c, 0xe5, 0x04, 0x10, 0x6f, 0x36,
1950x00, 0x42, 0x66, 0x6f, 0x72, 0x2c, 0xe5, 0x04, 0x10, 0x6f, 1950x07, 0x10, 0x68, 0x93, 0x00, 0x30, 0x66, 0x75, 0x72, 0x4b,
1960x4b, 0x07, 0x10, 0x68, 0x93, 0x00, 0x30, 0x66, 0x75, 0x72, 1960x07, 0x42, 0x2e, 0x00, 0x49, 0x66, 0xce, 0x00, 0x02, 0x01,
1970x60, 0x07, 0x42, 0x2e, 0x00, 0x49, 0x66, 0xce, 0x00, 0x02, 1970x07, 0x0f, 0x8a, 0x00, 0x01, 0x91, 0x28, 0x73, 0x61, 0x79,
1980x16, 0x07, 0x0f, 0x8a, 0x00, 0x01, 0x91, 0x28, 0x73, 0x61, 1980x29, 0x00, 0x30, 0x2e, 0x35, 0xf6, 0x02, 0x07, 0x93, 0x00,
1990x79, 0x29, 0x00, 0x30, 0x2e, 0x35, 0xf6, 0x02, 0x07, 0x93, 1990x01, 0xe2, 0x08, 0x42, 0x64, 0x69, 0x6d, 0x65, 0x32, 0x00,
2000x00, 0x01, 0xf7, 0x08, 0x42, 0x64, 0x69, 0x6d, 0x65, 0x32, 2000x26, 0x6f, 0x66, 0xa1, 0x05, 0x04, 0x1c, 0x03, 0x02, 0x0e,
2010x00, 0x26, 0x6f, 0x66, 0xa1, 0x05, 0x04, 0x1c, 0x03, 0x02, 2010x01, 0x02, 0x31, 0x07, 0x43, 0x68, 0x61, 0x6c, 0x66, 0x31,
2020x0e, 0x01, 0x02, 0x46, 0x07, 0x43, 0x68, 0x61, 0x6c, 0x66, 2020x04, 0x70, 0x61, 0x73, 0x00, 0x62, 0x69, 0x67, 0x00, 0xa7,
2030x31, 0x04, 0x70, 0x61, 0x73, 0x00, 0x62, 0x69, 0x67, 0x00, 2030x07, 0x14, 0x72, 0xc3, 0x00, 0x01, 0x3d, 0x07, 0x60, 0x49,
2040xbc, 0x07, 0x14, 0x72, 0xc3, 0x00, 0x01, 0x52, 0x07, 0x60, 2040x6e, 0x00, 0x6f, 0x74, 0x68, 0x18, 0x09, 0x51, 0x6f, 0x72,
2050x49, 0x6e, 0x00, 0x6f, 0x74, 0x68, 0x2d, 0x09, 0x51, 0x6f, 2050x64, 0x73, 0x2c, 0x51, 0x00, 0x30, 0x69, 0x6e, 0x69, 0x9d,
2060x72, 0x64, 0x73, 0x2c, 0x51, 0x00, 0x30, 0x69, 0x6e, 0x69, 2060x01, 0x0a, 0x59, 0x00, 0x36, 0x32, 0x2f, 0x33, 0xe9, 0x00,
2070x9d, 0x01, 0x0a, 0x59, 0x00, 0x36, 0x32, 0x2f, 0x33, 0xe9, 2070x2b, 0x69, 0x6e, 0x8c, 0x00, 0x02, 0xef, 0x00, 0x0f, 0x85,
2080x00, 0x2b, 0x69, 0x6e, 0x8c, 0x00, 0x02, 0xef, 0x00, 0x0f, 2080x00, 0x01, 0x00, 0x22, 0x04, 0x21, 0x66, 0x75, 0x40, 0x01,
2090x85, 0x00, 0x01, 0x00, 0x22, 0x04, 0x21, 0x66, 0x75, 0x40, 2090x17, 0x7a, 0x42, 0x04, 0x24, 0x64, 0x64, 0x43, 0x06, 0x28,
2100x01, 0x17, 0x7a, 0x42, 0x04, 0x24, 0x64, 0x64, 0x43, 0x06, 2100x6d, 0x6f, 0x80, 0x06, 0x01, 0xab, 0x01, 0x31, 0x53, 0x65,
2110x28, 0x6d, 0x6f, 0x80, 0x06, 0x01, 0xab, 0x01, 0x31, 0x53, 2110x74, 0x5e, 0x04, 0x0f, 0x20, 0x01, 0x04, 0x03, 0x9d, 0x05,
2120x65, 0x74, 0x5e, 0x04, 0x0f, 0x20, 0x01, 0x04, 0x03, 0x9d, 2120x82, 0x30, 0x2e, 0x35, 0x00, 0x74, 0x65, 0x6e, 0x64, 0xcd,
2130x05, 0x82, 0x30, 0x2e, 0x35, 0x00, 0x74, 0x65, 0x6e, 0x64, 2130x05, 0x23, 0x61, 0x6b, 0x85, 0x0a, 0x00, 0x4f, 0x07, 0x01,
2140xcd, 0x05, 0x23, 0x61, 0x6b, 0x9a, 0x0a, 0x00, 0x4f, 0x07, 2140x54, 0x00, 0x92, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75,
2150x01, 0x54, 0x00, 0x92, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 2150x6c, 0x74, 0x9d, 0x00, 0x01, 0xfe, 0x03, 0x50, 0x28, 0x69,
2160x75, 0x6c, 0x74, 0x9d, 0x00, 0x01, 0xfe, 0x03, 0x50, 0x28, 2160x6e, 0x00, 0x6d, 0xb7, 0x06, 0xf0, 0x01, 0x70, 0x65, 0x72,
2170x69, 0x6e, 0x00, 0x6d, 0xb7, 0x06, 0xb0, 0x70, 0x65, 0x72, 2170x69, 0x65, 0x6e, 0x63, 0x65, 0x29, 0x00, 0x72, 0x65, 0x77,
2180x69, 0x65, 0x6e, 0x63, 0x65, 0x29, 0x00, 0x72, 0x1d, 0x08, 2180x61, 0x72, 0x64, 0x56, 0x03, 0x30, 0x6c, 0x65, 0x73, 0x42,
2190x10, 0x64, 0x56, 0x03, 0x30, 0x6c, 0x65, 0x73, 0x42, 0x04, 2190x04, 0x30, 0x64, 0x75, 0x63, 0x3a, 0x06, 0x01, 0x35, 0x00,
2200x30, 0x64, 0x75, 0x63, 0x3a, 0x06, 0x01, 0x35, 0x00, 0x01, 2200x01, 0x49, 0x00, 0x51, 0x69, 0x6e, 0x74, 0x75, 0x69, 0x13,
2210x49, 0x00, 0x51, 0x69, 0x6e, 0x74, 0x75, 0x69, 0x13, 0x00, 2210x00, 0x00, 0xa4, 0x07, 0x00, 0x99, 0x00, 0x59, 0x73, 0x74,
2220x00, 0xa4, 0x07, 0x00, 0x99, 0x00, 0x59, 0x73, 0x74, 0x79, 2220x79, 0x6c, 0x65, 0xcb, 0x01, 0xd0, 0x69, 0x74, 0x00, 0x74,
2230x6c, 0x65, 0xcb, 0x01, 0xd0, 0x69, 0x74, 0x00, 0x74, 0x6f, 2230x6f, 0x6f, 0x00, 0x68, 0x69, 0x67, 0x68, 0x2c, 0x00, 0xe4,
2240x6f, 0x00, 0x68, 0x69, 0x67, 0x68, 0x2c, 0x00, 0xe4, 0x00, 2240x00, 0x02, 0x08, 0x00, 0x03, 0x90, 0x00, 0x03, 0x3c, 0x02,
2250x02, 0x08, 0x00, 0x03, 0x90, 0x00, 0x03, 0x3c, 0x02, 0x30, 2250x30, 0x63, 0x61, 0x6e, 0x45, 0x09, 0x05, 0x43, 0x02, 0x01,
2260x63, 0x61, 0x6e, 0x5a, 0x09, 0x05, 0x43, 0x02, 0x01, 0x5e, 2260x5e, 0x00, 0x01, 0xe9, 0x02, 0x02, 0x69, 0x03, 0x0a, 0x63,
2270x00, 0x01, 0xe9, 0x02, 0x02, 0x69, 0x03, 0x0a, 0x63, 0x03, 2270x03, 0x51, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x00, 0x03,
2280x51, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x00, 0x03, 0xa5, 2280xa5, 0x07, 0x02, 0x27, 0x04, 0x03, 0xfc, 0x02, 0x02, 0x59,
2290x07, 0x02, 0x27, 0x04, 0x03, 0xfc, 0x02, 0x02, 0x59, 0x00, 2290x00, 0x50, 0x62, 0x65, 0x63, 0x6f, 0x6d, 0x2f, 0x00, 0x61,
2300x50, 0x62, 0x65, 0x63, 0x6f, 0x6d, 0x2f, 0x00, 0x61, 0x72, 2300x72, 0x69, 0x76, 0x69, 0x61, 0x6c, 0x39, 0x04, 0xf1, 0x02,
2310x69, 0x76, 0x69, 0x61, 0x6c, 0x39, 0x04, 0xf1, 0x02, 0x6e, 2310x6e, 0x73, 0x75, 0x72, 0x65, 0x20, 0x75, 0x6e, 0x69, 0x71,
2320x73, 0x75, 0x72, 0x65, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 2320x75, 0x65, 0x20, 0x73, 0x6f, 0x6c, 0x75, 0x92, 0x04, 0x60,
2330x65, 0x20, 0x73, 0x6f, 0x6c, 0x75, 0x92, 0x04, 0x60, 0x00, 2330x00, 0x00, 0x4e, 0x6f, 0x72, 0x6d, 0x73, 0x03, 0x1d, 0x2c,
2340x00, 0x4e, 0x6f, 0x72, 0x6d, 0x73, 0x03, 0x1d, 0x2c, 0xdb, 2340xdb, 0x02, 0x01, 0x3d, 0x01, 0x00, 0x36, 0x00, 0x02, 0x67,
2350x02, 0x01, 0x3d, 0x01, 0x00, 0x36, 0x00, 0x02, 0x67, 0x02, 2350x02, 0x01, 0x28, 0x04, 0x03, 0x81, 0x09, 0x21, 0x69, 0x74,
2360x01, 0x28, 0x04, 0x03, 0x96, 0x09, 0x21, 0x69, 0x74, 0x8b, 2360x8b, 0x06, 0x01, 0x0e, 0x06, 0x01, 0x51, 0x0c, 0x23, 0x6f,
2370x06, 0x01, 0x0e, 0x06, 0x01, 0x66, 0x0c, 0x23, 0x6f, 0x6e, 2370x6e, 0x94, 0x0b, 0x04, 0x5a, 0x00, 0x13, 0x2e, 0xa9, 0x0a,
2380xa9, 0x0b, 0x04, 0x5a, 0x00, 0x13, 0x2e, 0xbe, 0x0a, 0x12, 2380x12, 0x73, 0xbb, 0x08, 0x61, 0x61, 0x6d, 0x62, 0x69, 0x67,
2390x73, 0xbb, 0x08, 0x61, 0x61, 0x6d, 0x62, 0x69, 0x67, 0x75, 2390x75, 0xef, 0x0b, 0x13, 0x65, 0x95, 0x05, 0x00, 0x05, 0x04,
2400x04, 0x0c, 0x13, 0x65, 0x95, 0x05, 0x00, 0x05, 0x04, 0x1c, 2400x1c, 0x62, 0x95, 0x01, 0x06, 0x5f, 0x01, 0xd5, 0x73, 0x75,
2410x62, 0x95, 0x01, 0x06, 0x5f, 0x01, 0xd5, 0x73, 0x75, 0x62, 2410x62, 0x74, 0x6c, 0x65, 0x2c, 0x00, 0x73, 0x6f, 0x00, 0x69,
2420x74, 0x6c, 0x65, 0x2c, 0x00, 0x73, 0x6f, 0x00, 0x69, 0x66, 2420x66, 0x9a, 0x0a, 0x05, 0x3f, 0x04, 0x01, 0xae, 0x06, 0x32,
2430xaf, 0x0a, 0x05, 0x3f, 0x04, 0x01, 0xae, 0x06, 0x32, 0x6f, 2430x6f, 0x66, 0x66, 0x8d, 0x0b, 0x62, 0x66, 0x65, 0x61, 0x74,
2440x66, 0x66, 0xa2, 0x0b, 0x62, 0x66, 0x65, 0x61, 0x74, 0x75, 2440x75, 0x72, 0x9d, 0x01, 0x40, 0x72, 0x69, 0x73, 0x6b, 0x95,
2450x72, 0x9d, 0x01, 0x40, 0x72, 0x69, 0x73, 0x6b, 0x95, 0x00, 2450x00, 0x01, 0x2b, 0x02, 0x05, 0x77, 0x00, 0x03, 0xba, 0x00,
2460x01, 0x2b, 0x02, 0x05, 0x77, 0x00, 0x03, 0xba, 0x00, 0xb2, 2460xb2, 0x2e, 0x00, 0x41, 0x6c, 0x73, 0x6f, 0x2c, 0x00, 0x66,
2470x2e, 0x00, 0x41, 0x6c, 0x73, 0x6f, 0x2c, 0x00, 0x66, 0x69, 2470x69, 0x6e, 0x6b, 0x02, 0x24, 0x6c, 0x6c, 0xed, 0x07, 0x12,
2480x6e, 0x6b, 0x02, 0x24, 0x6c, 0x6c, 0xed, 0x07, 0x12, 0x73, 2480x73, 0x6d, 0x0a, 0x03, 0xc0, 0x00, 0x05, 0xa0, 0x00, 0x21,
2490x82, 0x0a, 0x03, 0xc0, 0x00, 0x05, 0xa0, 0x00, 0x21, 0x61, 2490x61, 0x6e, 0x97, 0x02, 0x00, 0x14, 0x00, 0x20, 0x61, 0x6c,
2500x6e, 0x97, 0x02, 0x00, 0x14, 0x00, 0x20, 0x61, 0x6c, 0x55, 2500x55, 0x05, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x63,
2510x05, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x63, 0x05, 2510x05, 0x01, 0x1c, 0x00, 0x10, 0x76, 0xc8, 0x06, 0x12, 0x64,
2520x01, 0x1c, 0x00, 0x10, 0x76, 0xc8, 0x06, 0x12, 0x64, 0xa9, 2520xa9, 0x09, 0x61, 0x72, 0x2e, 0x00, 0x54, 0x75, 0x72, 0xfc,
2530x09, 0x61, 0x72, 0x2e, 0x00, 0x54, 0x75, 0x72, 0xfc, 0x04, 2530x04, 0x05, 0x9c, 0x00, 0x03, 0xfc, 0x05, 0x01, 0xf4, 0x04,
2540x05, 0x9c, 0x00, 0x03, 0xfc, 0x05, 0x01, 0xf4, 0x04, 0x01, 2540x01, 0xf9, 0x0b, 0x74, 0x70, 0x65, 0x65, 0x64, 0x00, 0x75,
2550x0e, 0x0c, 0x74, 0x70, 0x65, 0x65, 0x64, 0x00, 0x75, 0x70, 2550x70, 0x55, 0x0b, 0x03, 0xf8, 0x01, 0x50, 0x69, 0x6f, 0x6e,
2560x6a, 0x0b, 0x03, 0xf8, 0x01, 0x50, 0x69, 0x6f, 0x6e, 0x2e, 2560x2e, 0x00,
2570x00,
258}; 257};
259 258
260const unsigned short help_text_len = 3535; 259const unsigned short help_text_len = 3536;
261const unsigned short help_text_words = 605; 260const unsigned short help_text_words = 603;
262const char quick_help_text[] = "Divide the grid into rectangles with areas equal to the numbers."; 261const char quick_help_text[] = "Divide the grid into rectangles with areas equal to the numbers.";
diff --git a/apps/plugins/puzzles/help/samegame.c b/apps/plugins/puzzles/help/samegame.c
index 5efe0ff4c3..87f7b2b3b9 100644
--- a/apps/plugins/puzzles/help/samegame.c
+++ b/apps/plugins/puzzles/help/samegame.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,185 +6,186 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 116, TEXT_CENTER | C_RED }, 9 { 117, TEXT_CENTER | C_RED },
10 { 229, TEXT_CENTER | C_RED }, 10 { 230, TEXT_CENTER | C_RED },
11 { 246, TEXT_UNDERLINE },
12 { 247, TEXT_UNDERLINE }, 11 { 247, TEXT_UNDERLINE },
13 { 257, TEXT_UNDERLINE }, 12 { 248, TEXT_UNDERLINE },
14 { 292, TEXT_UNDERLINE }, 13 { 258, TEXT_UNDERLINE },
15 { 342, TEXT_UNDERLINE }, 14 { 293, TEXT_UNDERLINE },
16 { 414, TEXT_UNDERLINE }, 15 { 343, TEXT_UNDERLINE },
16 { 415, TEXT_UNDERLINE },
17 LAST_STYLE_ITEM 17 LAST_STYLE_ITEM
18}; 18};
19 19
20/* orig 2470 comp 1634 ratio 0.661538 level 10 saved 836 */ 20/* orig 2492 comp 1641 ratio 0.658507 level 10 saved 851 */
21const char help_text[] = { 21const char help_text[] = {
220xf0, 0x03, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 220xf0, 0x03, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
230x31, 0x33, 0x3a, 0x20, 0x53, 0x61, 0x6d, 0x65, 0x20, 0x47, 230x31, 0x33, 0x3a, 0x20, 0x53, 0x61, 0x6d, 0x65, 0x20, 0x47,
240x05, 0x00, 0xf4, 0x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 240x05, 0x00, 0x2f, 0x00, 0x2d, 0x01, 0x00, 0x01, 0xf4, 0x20,
250x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x67, 0x72, 250x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76,
260x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 260x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f,
270x75, 0x72, 0x65, 0x64, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 270x66, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x65, 0x64,
280x65, 0x73, 0x2c, 0x00, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 280x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00,
290x79, 0x2b, 0x00, 0xf0, 0x1c, 0x74, 0x6f, 0x00, 0x63, 0x6c, 290x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x79, 0x2b, 0x00, 0xf0,
300x65, 0x61, 0x72, 0x00, 0x62, 0x79, 0x00, 0x68, 0x69, 0x67, 300x1c, 0x74, 0x6f, 0x00, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x00,
310x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x69, 0x6e, 0x67, 0x00, 310x62, 0x79, 0x00, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67,
320x63, 0x6f, 0x6e, 0x74, 0x69, 0x67, 0x75, 0x6f, 0x75, 0x73, 320x68, 0x74, 0x69, 0x6e, 0x67, 0x00, 0x63, 0x6f, 0x6e, 0x74,
330x00, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x00, 330x69, 0x67, 0x75, 0x6f, 0x75, 0x73, 0x00, 0x72, 0x65, 0x67,
340xdc, 0x6d, 0x6f, 0x72, 0x65, 0x00, 0x74, 0x68, 0x61, 0x6e, 340x69, 0x6f, 0x6e, 0x73, 0x50, 0x00, 0xdc, 0x6d, 0x6f, 0x72,
350x00, 0x6f, 0x6e, 0x65, 0x5e, 0x00, 0xc1, 0x3b, 0x00, 0x74, 350x65, 0x00, 0x74, 0x68, 0x61, 0x6e, 0x00, 0x6f, 0x6e, 0x65,
360x68, 0x65, 0x00, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x0b, 360x5e, 0x00, 0xc1, 0x3b, 0x00, 0x74, 0x68, 0x65, 0x00, 0x6c,
370x00, 0x02, 0x39, 0x00, 0x02, 0x6d, 0x00, 0x04, 0x5c, 0x00, 370x61, 0x72, 0x67, 0x65, 0x72, 0x0b, 0x00, 0x02, 0x39, 0x00,
380x11, 0x2c, 0x1a, 0x00, 0x01, 0x48, 0x00, 0x61, 0x70, 0x6f, 380x02, 0x6d, 0x00, 0x04, 0x5c, 0x00, 0x11, 0x2c, 0x1a, 0x00,
390x69, 0x6e, 0x74, 0x73, 0x1f, 0x00, 0x81, 0x67, 0x65, 0x74, 390x01, 0x48, 0x00, 0x61, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73,
400x00, 0x28, 0x61, 0x6e, 0x64, 0x1d, 0x00, 0x61, 0x66, 0x61, 400x1f, 0x00, 0x81, 0x67, 0x65, 0x74, 0x00, 0x28, 0x61, 0x6e,
410x73, 0x74, 0x65, 0x72, 0x18, 0x00, 0x02, 0x9c, 0x00, 0x00, 410x64, 0x1d, 0x00, 0x61, 0x66, 0x61, 0x73, 0x74, 0x65, 0x72,
420x15, 0x00, 0xcb, 0x61, 0x72, 0x65, 0x6e, 0x61, 0x29, 0x2e, 420x18, 0x00, 0x02, 0x9c, 0x00, 0x00, 0x15, 0x00, 0xcb, 0x61,
430x00, 0x00, 0x00, 0x49, 0x66, 0x1b, 0x00, 0x01, 0xed, 0x00, 430x72, 0x65, 0x6e, 0x61, 0x29, 0x2e, 0x00, 0x00, 0x00, 0x49,
440x00, 0x13, 0x00, 0x44, 0x77, 0x69, 0x6e, 0x2e, 0x1f, 0x00, 440x66, 0x1b, 0x00, 0x01, 0xed, 0x00, 0x00, 0x13, 0x00, 0x44,
450xf0, 0x01, 0x65, 0x6e, 0x64, 0x00, 0x75, 0x70, 0x00, 0x77, 450x77, 0x69, 0x6e, 0x2e, 0x1f, 0x00, 0xf0, 0x01, 0x65, 0x6e,
460x69, 0x74, 0x68, 0x00, 0x6e, 0x6f, 0x74, 0x68, 0xd4, 0x00, 460x64, 0x00, 0x75, 0x70, 0x00, 0x77, 0x69, 0x74, 0x68, 0x00,
470xa4, 0x62, 0x75, 0x74, 0x00, 0x73, 0x69, 0x6e, 0x67, 0x6c, 470x6e, 0x6f, 0x74, 0x68, 0xd4, 0x00, 0xa4, 0x62, 0x75, 0x74,
480x65, 0x10, 0x01, 0x61, 0x00, 0x28, 0x69, 0x2e, 0x65, 0x2e, 480x00, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x10, 0x01, 0x61,
490x94, 0x00, 0x11, 0x72, 0x64, 0x00, 0x32, 0x00, 0x6e, 0x6f, 490x00, 0x28, 0x69, 0x2e, 0x65, 0x2e, 0x94, 0x00, 0x11, 0x72,
500x9d, 0x00, 0x95, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x61, 0x62, 500x64, 0x00, 0x32, 0x00, 0x6e, 0x6f, 0x9d, 0x00, 0x95, 0x63,
510x6c, 0x65, 0xff, 0x00, 0x51, 0x6c, 0x65, 0x66, 0x74, 0x29, 510x6c, 0x69, 0x63, 0x6b, 0x61, 0x62, 0x6c, 0x65, 0xff, 0x00,
520x5c, 0x00, 0x40, 0x6c, 0x6f, 0x73, 0x65, 0x8a, 0x00, 0x50, 520x51, 0x6c, 0x65, 0x66, 0x74, 0x29, 0x5c, 0x00, 0x40, 0x6c,
530x52, 0x65, 0x6d, 0x6f, 0x76, 0x59, 0x00, 0x14, 0x61, 0xeb, 530x6f, 0x73, 0x65, 0x8a, 0x00, 0x50, 0x52, 0x65, 0x6d, 0x6f,
540x00, 0x63, 0x63, 0x61, 0x75, 0x73, 0x65, 0x73, 0xfd, 0x00, 540x76, 0x59, 0x00, 0x14, 0x61, 0xeb, 0x00, 0x63, 0x63, 0x61,
550x20, 0x73, 0x74, 0x33, 0x01, 0x05, 0xa2, 0x00, 0xf0, 0x06, 550x75, 0x73, 0x65, 0x73, 0xfd, 0x00, 0x20, 0x73, 0x74, 0x33,
560x74, 0x6f, 0x00, 0x73, 0x68, 0x75, 0x66, 0x66, 0x6c, 0x65, 560x01, 0x05, 0xa2, 0x00, 0xf0, 0x06, 0x74, 0x6f, 0x00, 0x73,
570x00, 0x75, 0x70, 0x3a, 0x00, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 570x68, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x00, 0x75, 0x70, 0x3a,
580x73, 0x4d, 0x01, 0x11, 0x74, 0x79, 0x00, 0xf3, 0x13, 0x73, 580x00, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x01, 0x11,
590x75, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x00, 0x77, 590x74, 0x79, 0x00, 0xf3, 0x13, 0x73, 0x75, 0x73, 0x70, 0x65,
600x69, 0x6c, 0x6c, 0x00, 0x66, 0x61, 0x6c, 0x6c, 0x00, 0x64, 600x6e, 0x64, 0x65, 0x64, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0x00,
610x6f, 0x77, 0x6e, 0x00, 0x28, 0x66, 0x69, 0x72, 0x73, 0x74, 610x66, 0x61, 0x6c, 0x6c, 0x00, 0x64, 0x6f, 0x77, 0x6e, 0x00,
620x29, 0x2c, 0x00, 0x20, 0x01, 0x70, 0x6e, 0x00, 0x65, 0x6d, 620x28, 0x66, 0x69, 0x72, 0x73, 0x74, 0x29, 0x2c, 0x00, 0x20,
630x70, 0x74, 0x79, 0x7e, 0x01, 0x41, 0x75, 0x6d, 0x6e, 0x73, 630x01, 0x70, 0x6e, 0x00, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x7e,
640x3d, 0x00, 0xb2, 0x66, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x00, 640x01, 0x41, 0x75, 0x6d, 0x6e, 0x73, 0x3d, 0x00, 0xb2, 0x66,
650x66, 0x72, 0x6f, 0x6d, 0x7d, 0x00, 0x00, 0x6b, 0x01, 0x00, 650x69, 0x6c, 0x6c, 0x65, 0x64, 0x00, 0x66, 0x72, 0x6f, 0x6d,
660xa3, 0x00, 0x00, 0x21, 0x02, 0x20, 0x00, 0x47, 0x05, 0x00, 660x7d, 0x00, 0x00, 0x6b, 0x01, 0x00, 0xa3, 0x00, 0x00, 0x37,
670x31, 0x77, 0x61, 0x73, 0xd5, 0x01, 0x61, 0x72, 0x69, 0x62, 670x02, 0x20, 0x00, 0x47, 0x05, 0x00, 0x31, 0x77, 0x61, 0x73,
680x75, 0x74, 0x65, 0x8f, 0x00, 0x40, 0x74, 0x68, 0x69, 0x73, 680xd5, 0x01, 0x61, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x8f,
690x47, 0x00, 0x40, 0x6c, 0x65, 0x63, 0x74, 0xbe, 0x00, 0xf0, 690x00, 0x40, 0x74, 0x68, 0x69, 0x73, 0x47, 0x00, 0x40, 0x6c,
700x00, 0x62, 0x79, 0x00, 0x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 700x65, 0x63, 0x74, 0xbe, 0x00, 0xf0, 0x00, 0x62, 0x79, 0x00,
710x48, 0x61, 0x72, 0x76, 0x65, 0x79, 0x40, 0x00, 0x47, 0x31, 710x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61, 0x72, 0x76,
720x33, 0x2e, 0x31, 0x66, 0x02, 0x01, 0x41, 0x00, 0x30, 0x6f, 720x65, 0x79, 0x40, 0x00, 0x47, 0x31, 0x33, 0x2e, 0x31, 0x7c,
730x6c, 0x73, 0x6f, 0x02, 0x10, 0x54, 0x3e, 0x00, 0x10, 0x67, 730x02, 0x01, 0x41, 0x00, 0x80, 0x6f, 0x6c, 0x73, 0x20, 0x00,
740x5b, 0x00, 0xd2, 0x63, 0x61, 0x6e, 0x00, 0x62, 0x65, 0x00, 740x00, 0x00, 0x54, 0x3e, 0x00, 0x10, 0x67, 0x5b, 0x00, 0xd2,
750x70, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x73, 0x01, 0x43, 0x65, 750x63, 0x61, 0x6e, 0x00, 0x62, 0x65, 0x00, 0x70, 0x6c, 0x61,
760x69, 0x74, 0x68, 0x06, 0x02, 0xb3, 0x6b, 0x65, 0x79, 0x62, 760x79, 0x65, 0x64, 0x73, 0x01, 0x43, 0x65, 0x69, 0x74, 0x68,
770x6f, 0x61, 0x72, 0x64, 0x00, 0x6f, 0x72, 0xfc, 0x01, 0x37, 770x06, 0x02, 0xb3, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72,
780x75, 0x73, 0x65, 0xc9, 0x01, 0x00, 0x58, 0x01, 0x11, 0x2d, 780x64, 0x00, 0x6f, 0x72, 0xfc, 0x01, 0x37, 0x75, 0x73, 0x65,
790x6f, 0x01, 0x80, 0x00, 0x61, 0x6e, 0x00, 0x75, 0x6e, 0x73, 790xc9, 0x01, 0x00, 0x58, 0x01, 0x11, 0x2d, 0x6f, 0x01, 0x80,
800x65, 0x90, 0x00, 0x23, 0x65, 0x64, 0x54, 0x01, 0x90, 0x2c, 800x00, 0x61, 0x6e, 0x00, 0x75, 0x6e, 0x73, 0x65, 0x90, 0x00,
810x00, 0x69, 0x74, 0x00, 0x62, 0x65, 0x63, 0x6f, 0x99, 0x00, 810x23, 0x65, 0x64, 0x54, 0x01, 0x90, 0x2c, 0x00, 0x69, 0x74,
820x05, 0x1c, 0x00, 0x92, 0x28, 0x70, 0x6f, 0x73, 0x73, 0x69, 820x00, 0x62, 0x65, 0x63, 0x6f, 0x99, 0x00, 0x05, 0x1c, 0x00,
830x62, 0x6c, 0x79, 0x08, 0x02, 0x00, 0x85, 0x01, 0x00, 0x5c, 830x92, 0x28, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x79,
840x00, 0x73, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x28, 840x08, 0x02, 0x00, 0x85, 0x01, 0x00, 0x5c, 0x00, 0x73, 0x63,
850x00, 0x4f, 0x69, 0x6f, 0x6e, 0x29, 0x69, 0x00, 0x03, 0x00, 850x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x28, 0x00, 0x4f, 0x69,
860x2c, 0x00, 0x0f, 0x68, 0x00, 0x01, 0x01, 0x7b, 0x01, 0x10, 860x6f, 0x6e, 0x29, 0x69, 0x00, 0x03, 0x00, 0x2c, 0x00, 0x0f,
870x62, 0xbd, 0x01, 0x56, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x94, 870x68, 0x00, 0x01, 0x01, 0x7b, 0x01, 0x10, 0x62, 0xbd, 0x01,
880x02, 0x0d, 0xce, 0x01, 0x03, 0xcb, 0x01, 0xd8, 0x64, 0x00, 880x56, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x94, 0x02, 0x0d, 0xce,
890x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x6c, 890x01, 0x03, 0xcb, 0x01, 0xd8, 0x64, 0x00, 0x69, 0x6d, 0x6d,
900x79, 0x6d, 0x00, 0x01, 0x82, 0x01, 0x0f, 0x6e, 0x00, 0x14, 900x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x6c, 0x79, 0x6d, 0x00,
910x06, 0xf4, 0x00, 0x11, 0x2e, 0x58, 0x01, 0x01, 0xc8, 0x00, 910x01, 0x82, 0x01, 0x0f, 0x6e, 0x00, 0x14, 0x06, 0xf4, 0x00,
920x30, 0x73, 0x6f, 0x72, 0x3b, 0x01, 0x41, 0x73, 0x00, 0x6d, 920x11, 0x2e, 0x58, 0x01, 0x01, 0xc8, 0x00, 0x30, 0x73, 0x6f,
930x6f, 0xd3, 0x03, 0x03, 0x13, 0x00, 0x65, 0x61, 0x72, 0x6f, 930x72, 0x3b, 0x01, 0x41, 0x73, 0x00, 0x6d, 0x6f, 0xd3, 0x03,
940x75, 0x6e, 0x64, 0x88, 0x00, 0x74, 0x2e, 0x00, 0x50, 0x72, 940x03, 0x13, 0x00, 0x65, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64,
950x65, 0x73, 0x73, 0x00, 0x01, 0x50, 0x53, 0x70, 0x61, 0x63, 950x88, 0x00, 0x74, 0x2e, 0x00, 0x50, 0x72, 0x65, 0x73, 0x73,
960x65, 0x69, 0x01, 0x43, 0x45, 0x6e, 0x74, 0x65, 0x40, 0x00, 960x00, 0x01, 0x50, 0x53, 0x70, 0x61, 0x63, 0x65, 0x69, 0x01,
970x40, 0x77, 0x68, 0x69, 0x6c, 0xb5, 0x03, 0x05, 0x56, 0x00, 970x43, 0x45, 0x6e, 0x74, 0x65, 0x40, 0x00, 0x40, 0x77, 0x68,
980x5f, 0x69, 0x73, 0x00, 0x69, 0x6e, 0x6c, 0x01, 0x02, 0x03, 980x69, 0x6c, 0xb5, 0x03, 0x05, 0x56, 0x00, 0x5f, 0x69, 0x73,
990xa6, 0x00, 0x74, 0x73, 0x00, 0x69, 0x74, 0x3b, 0x00, 0x70, 990x00, 0x69, 0x6e, 0x6c, 0x01, 0x02, 0x03, 0xa6, 0x00, 0x74,
1000x59, 0x00, 0x0b, 0x55, 0x00, 0x53, 0x61, 0x67, 0x61, 0x69, 1000x73, 0x00, 0x69, 0x74, 0x3b, 0x00, 0x70, 0x59, 0x00, 0x0b,
1010x6e, 0x22, 0x01, 0x10, 0x73, 0xc7, 0x00, 0x71, 0x61, 0x73, 1010x55, 0x00, 0x53, 0x61, 0x67, 0x61, 0x69, 0x6e, 0x22, 0x01,
1020x00, 0x61, 0x62, 0x6f, 0x76, 0xd4, 0x01, 0x42, 0x28, 0x41, 1020x10, 0x73, 0xc7, 0x00, 0x71, 0x61, 0x73, 0x00, 0x61, 0x62,
1030x6c, 0x6c, 0xb0, 0x03, 0x21, 0x63, 0x74, 0x36, 0x03, 0x70, 1030x6f, 0x76, 0xd4, 0x01, 0x42, 0x28, 0x41, 0x6c, 0x6c, 0xb0,
1040x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x29, 0x01, 0x00, 1040x03, 0x21, 0x63, 0x74, 0x36, 0x03, 0x70, 0x64, 0x65, 0x73,
1050x5f, 0x00, 0x02, 0x69, 0x02, 0x31, 0x32, 0x2e, 0x31, 0xb7, 1050x63, 0x72, 0x69, 0x62, 0x29, 0x01, 0x00, 0x5f, 0x00, 0x02,
1060x02, 0xa0, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0x61, 0x76, 0x61, 1060x69, 0x02, 0x31, 0x32, 0x2e, 0x31, 0xb7, 0x02, 0xa0, 0x61,
1070x69, 0x6c, 0x6a, 0x03, 0x22, 0x2e, 0x29, 0x71, 0x02, 0x17, 1070x6c, 0x73, 0x6f, 0x00, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x6a,
1080x32, 0x71, 0x02, 0x93, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 1080x03, 0x22, 0x2e, 0x29, 0x71, 0x02, 0x17, 0x32, 0x71, 0x02,
1090x74, 0x65, 0x72, 0x73, 0x02, 0x46, 0x65, 0x73, 0x65, 0x00, 1090x93, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72,
1100x14, 0x00, 0x02, 0x45, 0x00, 0x04, 0x40, 0x00, 0x06, 0xff, 1100x73, 0x02, 0x46, 0x65, 0x73, 0x65, 0x00, 0x14, 0x00, 0x02,
1110x02, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 1110x45, 0x00, 0x04, 0x40, 0x00, 0x06, 0xff, 0x02, 0xe1, 0x60,
1120x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x73, 0x00, 0x22, 0x6f, 1120x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27,
1130x6e, 0x1a, 0x00, 0xa0, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 1130x00, 0x6f, 0x70, 0x73, 0x00, 0x22, 0x6f, 0x6e, 0x1a, 0x00,
1140x6d, 0x65, 0x6e, 0x75, 0xaf, 0x00, 0x90, 0x57, 0x69, 0x64, 1140xa0, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e,
1150x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0xae, 0x01, 0x00, 0x2f, 1150x75, 0xaf, 0x00, 0x90, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c,
1160x03, 0x30, 0x69, 0x7a, 0x65, 0xe7, 0x01, 0x01, 0xe3, 0x01, 1160x00, 0x48, 0x65, 0xae, 0x01, 0x00, 0x2f, 0x03, 0x30, 0x69,
1170x24, 0x69, 0x6e, 0x27, 0x04, 0x00, 0x2b, 0x00, 0x72, 0x4e, 1170x7a, 0x65, 0xe7, 0x01, 0x01, 0xe3, 0x01, 0x24, 0x69, 0x6e,
1180x6f, 0x2e, 0x20, 0x6f, 0x66, 0x20, 0xf4, 0x04, 0x10, 0x73, 1180x27, 0x04, 0x00, 0x2b, 0x00, 0x72, 0x4e, 0x6f, 0x2e, 0x20,
1190x11, 0x00, 0x50, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x2e, 0x00, 1190x6f, 0x66, 0x20, 0xf4, 0x04, 0x10, 0x73, 0x11, 0x00, 0x50,
1200x51, 0x64, 0x69, 0x66, 0x66, 0x65, 0x78, 0x02, 0x04, 0x1e, 1200x75, 0x6d, 0x62, 0x65, 0x72, 0x2e, 0x00, 0x51, 0x64, 0x69,
1210x00, 0x22, 0x75, 0x73, 0x62, 0x03, 0x00, 0x98, 0x03, 0x05, 1210x66, 0x66, 0x65, 0x78, 0x02, 0x04, 0x1e, 0x00, 0x22, 0x75,
1220xac, 0x01, 0x16, 0x3b, 0xfb, 0x04, 0x03, 0x28, 0x00, 0x12, 1220x73, 0x62, 0x03, 0x00, 0x98, 0x03, 0x05, 0xac, 0x01, 0x16,
1230x2c, 0xf0, 0x04, 0x42, 0x65, 0x77, 0x65, 0x72, 0x38, 0x05, 1230x3b, 0xfb, 0x04, 0x03, 0x28, 0x00, 0x12, 0x2c, 0xf0, 0x04,
1240x08, 0x6c, 0x05, 0x02, 0x24, 0x00, 0x03, 0xf6, 0x03, 0x26, 1240x42, 0x65, 0x77, 0x65, 0x72, 0x38, 0x05, 0x08, 0x6c, 0x05,
1250x75, 0x73, 0x3d, 0x00, 0x00, 0x6f, 0x00, 0x50, 0x69, 0x63, 1250x02, 0x24, 0x00, 0x03, 0xf6, 0x03, 0x26, 0x75, 0x73, 0x3d,
1260x75, 0x6c, 0x74, 0x7d, 0x01, 0x21, 0x69, 0x73, 0x59, 0x04, 1260x00, 0x00, 0x6f, 0x00, 0x50, 0x69, 0x63, 0x75, 0x6c, 0x74,
1270xbb, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 1270x7d, 0x01, 0x21, 0x69, 0x73, 0x59, 0x04, 0xbb, 0x75, 0x63,
1280x6c, 0x79, 0x1a, 0x05, 0x01, 0x06, 0x04, 0x20, 0x63, 0x6f, 1280x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x1a,
1290x23, 0x03, 0xb3, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 1290x05, 0x01, 0x06, 0x04, 0x20, 0x63, 0x6f, 0x23, 0x03, 0xb3,
1300x00, 0x00, 0x00, 0x43, 0xc8, 0x03, 0x01, 0x26, 0x00, 0xf2, 1300x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x00, 0x00, 0x00,
1310x02, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x65, 0x00, 0x6d, 1310x43, 0xc8, 0x03, 0x01, 0x26, 0x00, 0xf2, 0x02, 0x70, 0x72,
1320x65, 0x63, 0x68, 0x61, 0x6e, 0x69, 0x73, 0x6d, 0xbf, 0x00, 1320x65, 0x63, 0x69, 0x73, 0x65, 0x00, 0x6d, 0x65, 0x63, 0x68,
1330x52, 0x66, 0x6f, 0x72, 0x00, 0x73, 0x39, 0x00, 0x30, 0x2e, 1330x61, 0x6e, 0x69, 0x73, 0x6d, 0xbf, 0x00, 0x52, 0x66, 0x6f,
1340x00, 0x57, 0xd5, 0x03, 0x00, 0x2d, 0x00, 0x40, 0x64, 0x65, 1340x72, 0x00, 0x73, 0x39, 0x00, 0x30, 0x2e, 0x00, 0x57, 0xd5,
1350x66, 0x61, 0x7b, 0x00, 0x02, 0x4b, 0x00, 0xf8, 0x02, 0x2c, 1350x03, 0x00, 0x2d, 0x00, 0x40, 0x64, 0x65, 0x66, 0x61, 0x7b,
1360x00, 0x60, 0x28, 0x6e, 0x2d, 0x32, 0x29, 0x5e, 0x32, 0x27, 1360x00, 0x02, 0x4b, 0x00, 0xf8, 0x02, 0x2c, 0x00, 0x60, 0x28,
1370x2c, 0x00, 0x6f, 0x6e, 0x6c, 0x79, 0xc1, 0x00, 0x46, 0x74, 1370x6e, 0x2d, 0x32, 0x29, 0x5e, 0x32, 0x27, 0x2c, 0x00, 0x6f,
1380x68, 0x72, 0x65, 0x6a, 0x05, 0x22, 0x6f, 0x72, 0xbe, 0x00, 1380x6e, 0x6c, 0x79, 0xc1, 0x00, 0x46, 0x74, 0x68, 0x72, 0x65,
1390x01, 0xf5, 0x02, 0x20, 0x73, 0x63, 0x0b, 0x00, 0x34, 0x61, 1390x6a, 0x05, 0x22, 0x6f, 0x72, 0xbe, 0x00, 0x01, 0xf5, 0x02,
1400x6e, 0x79, 0x05, 0x06, 0x00, 0x05, 0x05, 0x27, 0x6c, 0x6c, 1400x20, 0x73, 0x63, 0x0b, 0x00, 0x34, 0x61, 0x6e, 0x79, 0x05,
1410x68, 0x00, 0xb1, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 1410x06, 0x00, 0x05, 0x05, 0x27, 0x6c, 0x6c, 0x68, 0x00, 0xb1,
1420x74, 0x69, 0x76, 0x65, 0x64, 0x00, 0x10, 0x31, 0x64, 0x00, 1420x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76,
1430x05, 0x76, 0x00, 0x08, 0x66, 0x00, 0x25, 0x77, 0x6f, 0x64, 1430x65, 0x64, 0x00, 0x10, 0x31, 0x64, 0x00, 0x05, 0x76, 0x00,
1440x00, 0x03, 0x57, 0x00, 0x02, 0x55, 0x00, 0x52, 0x00, 0x65, 1440x08, 0x66, 0x00, 0x25, 0x77, 0x6f, 0x64, 0x00, 0x03, 0x57,
1450x61, 0x63, 0x68, 0x36, 0x05, 0x03, 0x94, 0x06, 0x04, 0x36, 1450x00, 0x02, 0x55, 0x00, 0x52, 0x00, 0x65, 0x61, 0x63, 0x68,
1460x00, 0x02, 0x27, 0x00, 0x31, 0x72, 0x65, 0x6c, 0x5f, 0x00, 1460x36, 0x05, 0x03, 0x94, 0x06, 0x04, 0x36, 0x00, 0x02, 0x27,
1470x28, 0x6c, 0x79, 0x8f, 0x06, 0x00, 0x2f, 0x01, 0xf2, 0x02, 1470x00, 0x31, 0x72, 0x65, 0x6c, 0x5f, 0x00, 0x28, 0x6c, 0x79,
1480x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x20, 0x73, 0x6f, 0x6c, 1480x8f, 0x06, 0x00, 0x2f, 0x01, 0xf2, 0x02, 0x45, 0x6e, 0x73,
1490x75, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0xd7, 0x03, 0x01, 1490x75, 0x72, 0x65, 0x20, 0x73, 0x6f, 0x6c, 0x75, 0x62, 0x69,
1500x2f, 0x05, 0x03, 0x4f, 0x02, 0x00, 0x77, 0x01, 0x30, 0x69, 1500x6c, 0x69, 0x74, 0x79, 0xd7, 0x03, 0x01, 0x2f, 0x05, 0x03,
1510x63, 0x6b, 0x23, 0x04, 0x09, 0x16, 0x01, 0xd0, 0x74, 0x61, 1510x4f, 0x02, 0x00, 0x77, 0x01, 0x30, 0x69, 0x63, 0x6b, 0x23,
1520x74, 0x65, 0x29, 0x2c, 0x00, 0x67, 0x65, 0x6e, 0x65, 0x72, 1520x04, 0x09, 0x16, 0x01, 0xd0, 0x74, 0x61, 0x74, 0x65, 0x29,
1530x61, 0x59, 0x03, 0x00, 0x83, 0x01, 0x15, 0x73, 0xea, 0x03, 1530x2c, 0x00, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x59, 0x03,
1540x82, 0x67, 0x75, 0x61, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x1e, 1540x00, 0x83, 0x01, 0x15, 0x73, 0xea, 0x03, 0x82, 0x67, 0x75,
1550x02, 0x02, 0xad, 0x07, 0x71, 0x74, 0x00, 0x6c, 0x65, 0x61, 1550x61, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x1e, 0x02, 0x02, 0xad,
1560x73, 0x74, 0x52, 0x07, 0x00, 0x73, 0x00, 0x00, 0x60, 0x00, 1560x07, 0x71, 0x74, 0x00, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x52,
1570x07, 0x49, 0x04, 0x60, 0x74, 0x75, 0x72, 0x6e, 0x00, 0x69, 1570x07, 0x00, 0x73, 0x00, 0x00, 0x60, 0x00, 0x07, 0x49, 0x04,
1580x7d, 0x04, 0x12, 0x66, 0x2f, 0x02, 0x01, 0x73, 0x05, 0x03, 1580x60, 0x74, 0x75, 0x72, 0x6e, 0x00, 0x69, 0x7d, 0x04, 0x12,
1590x61, 0x00, 0x22, 0x6f, 0x72, 0x5b, 0x00, 0x70, 0x6e, 0x6f, 1590x66, 0x2f, 0x02, 0x01, 0x73, 0x05, 0x03, 0x61, 0x00, 0x22,
1600x74, 0x00, 0x74, 0x72, 0x79, 0x55, 0x00, 0x05, 0x63, 0x00, 1600x6f, 0x72, 0x5b, 0x00, 0x70, 0x6e, 0x6f, 0x74, 0x00, 0x74,
1610x01, 0x4d, 0x00, 0x00, 0x17, 0x03, 0x01, 0x83, 0x00, 0x14, 1610x72, 0x79, 0x55, 0x00, 0x05, 0x63, 0x00, 0x01, 0x4d, 0x00,
1620x3b, 0x71, 0x04, 0xd0, 0x2c, 0x00, 0x68, 0x6f, 0x77, 0x65, 1620x00, 0x17, 0x03, 0x01, 0x83, 0x00, 0x14, 0x3b, 0x71, 0x04,
1630x76, 0x65, 0x72, 0x2c, 0x00, 0x73, 0x74, 0x3c, 0x00, 0x11, 1630xd0, 0x2c, 0x00, 0x68, 0x6f, 0x77, 0x65, 0x76, 0x65, 0x72,
1640x65, 0xee, 0x00, 0x02, 0x89, 0x06, 0x06, 0x08, 0x07, 0x05, 1640x2c, 0x00, 0x73, 0x74, 0x3c, 0x00, 0x11, 0x65, 0xee, 0x00,
1650x97, 0x00, 0x16, 0x32, 0xc2, 0x01, 0x11, 0x66, 0x53, 0x01, 1650x02, 0x89, 0x06, 0x06, 0x08, 0x07, 0x05, 0x97, 0x00, 0x16,
1660x04, 0x99, 0x02, 0x26, 0x6f, 0x6e, 0x0e, 0x05, 0x02, 0x3b, 1660x32, 0xc2, 0x01, 0x11, 0x66, 0x53, 0x01, 0x04, 0x99, 0x02,
1670x00, 0x00, 0xff, 0x00, 0x85, 0x72, 0x74, 0x00, 0x28, 0x73, 1670x26, 0x6f, 0x6e, 0x0e, 0x05, 0x02, 0x3b, 0x00, 0x00, 0xff,
1680x69, 0x6e, 0x63, 0x86, 0x08, 0x02, 0x0f, 0x06, 0x62, 0x78, 1680x00, 0x85, 0x72, 0x74, 0x00, 0x28, 0x73, 0x69, 0x6e, 0x63,
1690x61, 0x63, 0x74, 0x6c, 0x79, 0xe4, 0x00, 0x01, 0x4f, 0x00, 1690x86, 0x08, 0x02, 0x0f, 0x06, 0x62, 0x78, 0x61, 0x63, 0x74,
1700x00, 0x4e, 0x00, 0x74, 0x61, 0x00, 0x67, 0x69, 0x76, 0x65, 1700x6c, 0x79, 0xe4, 0x00, 0x01, 0x4f, 0x00, 0x00, 0x4e, 0x00,
1710x6e, 0x51, 0x00, 0x20, 0x69, 0x73, 0x48, 0x01, 0x40, 0x69, 1710x74, 0x61, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x51, 0x00,
1720x6e, 0x69, 0x74, 0x94, 0x01, 0x23, 0x69, 0x6e, 0xc0, 0x00, 1720x20, 0x69, 0x73, 0x48, 0x01, 0x40, 0x69, 0x6e, 0x69, 0x74,
1730x41, 0x29, 0x2e, 0x00, 0x47, 0x45, 0x01, 0x06, 0x55, 0x01, 1730x94, 0x01, 0x23, 0x69, 0x6e, 0xc0, 0x00, 0x41, 0x29, 0x2e,
1740x01, 0x54, 0x00, 0x08, 0x8f, 0x01, 0x50, 0x64, 0x69, 0x73, 1740x00, 0x47, 0x45, 0x01, 0x06, 0x55, 0x01, 0x01, 0x54, 0x00,
1750x61, 0x62, 0x8e, 0x05, 0x31, 0x6d, 0x61, 0x79, 0xe6, 0x06, 1750x08, 0x8f, 0x01, 0x50, 0x64, 0x69, 0x73, 0x61, 0x62, 0x8e,
1760x00, 0xa3, 0x04, 0x01, 0xd6, 0x01, 0x02, 0x57, 0x03, 0x43, 1760x05, 0x31, 0x6d, 0x61, 0x79, 0xe6, 0x06, 0x00, 0xa3, 0x04,
1770x61, 0x72, 0x65, 0x61, 0x55, 0x03, 0x05, 0xd7, 0x08, 0x02, 1770x01, 0xd6, 0x01, 0x02, 0x57, 0x03, 0x43, 0x61, 0x72, 0x65,
1780x76, 0x00, 0x10, 0x2c, 0xe7, 0x00, 0x11, 0x64, 0x40, 0x05, 1780x61, 0x55, 0x03, 0x05, 0xd7, 0x08, 0x02, 0x76, 0x00, 0x10,
1790xf1, 0x00, 0x6f, 0x00, 0x6f, 0x70, 0x70, 0x6f, 0x72, 0x74, 1790x2c, 0xe7, 0x00, 0x11, 0x64, 0x40, 0x05, 0xf1, 0x00, 0x6f,
1800x75, 0x6e, 0x69, 0x74, 0x69, 0x65, 0x73, 0x01, 0x03, 0x00, 1800x00, 0x6f, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x75, 0x6e, 0x69,
1810xb8, 0x08, 0x22, 0x65, 0x72, 0x32, 0x02, 0x11, 0x73, 0xc1, 1810x74, 0x69, 0x65, 0x73, 0x01, 0x03, 0x00, 0xb8, 0x08, 0x22,
1820x03, 0x11, 0x79, 0xef, 0x06, 0x01, 0xba, 0x04, 0x80, 0x74, 1820x65, 0x72, 0x32, 0x02, 0x11, 0x73, 0xc1, 0x03, 0x11, 0x79,
1830x61, 0x6b, 0x65, 0x00, 0x6c, 0x65, 0x73, 0x0c, 0x02, 0x21, 1830xef, 0x06, 0x01, 0xba, 0x04, 0x80, 0x74, 0x61, 0x6b, 0x65,
1840x6d, 0x65, 0x7d, 0x01, 0x90, 0x65, 0x6e, 0x65, 0x72, 0x61, 1840x00, 0x6c, 0x65, 0x73, 0x0c, 0x02, 0x21, 0x6d, 0x65, 0x7d,
1850x74, 0x65, 0x2e, 0x00, 1850x01, 0x90, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x2e,
1860x00,
186}; 187};
187 188
188const unsigned short help_text_len = 2470; 189const unsigned short help_text_len = 2492;
189const unsigned short help_text_words = 444; 190const unsigned short help_text_words = 445;
190const char quick_help_text[] = "Clear the grid by removing touching groups of the same colour squares."; 191const char quick_help_text[] = "Clear the grid by removing touching groups of the same colour squares.";
diff --git a/apps/plugins/puzzles/help/signpost.c b/apps/plugins/puzzles/help/signpost.c
index 6f89cbdd62..e38e42870c 100644
--- a/apps/plugins/puzzles/help/signpost.c
+++ b/apps/plugins/puzzles/help/signpost.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,208 +6,220 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 158, TEXT_CENTER | C_RED }, 9 { 159, TEXT_CENTER | C_RED },
10 { 495, TEXT_CENTER | C_RED }, 10 { 496, TEXT_CENTER | C_RED },
11 { 512, TEXT_UNDERLINE },
12 { 513, TEXT_UNDERLINE }, 11 { 513, TEXT_UNDERLINE },
13 { 523, TEXT_UNDERLINE }, 12 { 514, TEXT_UNDERLINE },
13 { 524, TEXT_UNDERLINE },
14 { 569, TEXT_CENTER | C_RED },
14 LAST_STYLE_ITEM 15 LAST_STYLE_ITEM
15}; 16};
16 17
17/* orig 3054 comp 1895 ratio 0.620498 level 10 saved 1159 */ 18/* orig 3255 comp 2009 ratio 0.617204 level 10 saved 1246 */
18const char help_text[] = { 19const char help_text[] = {
190xf3, 0x29, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 200xff, 0x08, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
200x33, 0x34, 0x3a, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x70, 0x6f, 210x33, 0x34, 0x3a, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x70, 0x6f,
210x73, 0x74, 0x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 220x73, 0x74, 0x20, 0x00, 0x2d, 0x01, 0x00, 0x00, 0xf3, 0x14,
220x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 230x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76,
230x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 240x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f,
240x65, 0x73, 0x3b, 0x00, 0x65, 0x61, 0x63, 0x68, 0x0e, 0x00, 250x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x3b,
250xf4, 0x23, 0x00, 0x28, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 260x00, 0x65, 0x61, 0x63, 0x68, 0x0e, 0x00, 0xf4, 0x23, 0x00,
260x00, 0x74, 0x68, 0x65, 0x00, 0x6c, 0x61, 0x73, 0x74, 0x00, 270x28, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x00, 0x74, 0x68,
270x6f, 0x6e, 0x65, 0x29, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 280x65, 0x00, 0x6c, 0x61, 0x73, 0x74, 0x00, 0x6f, 0x6e, 0x65,
280x69, 0x6e, 0x73, 0x00, 0x61, 0x6e, 0x00, 0x61, 0x72, 0x72, 290x29, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73,
290x6f, 0x77, 0x2c, 0x00, 0x61, 0x6e, 0x64, 0x00, 0x73, 0x6f, 300x00, 0x61, 0x6e, 0x00, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x2c,
300x6d, 0x65, 0x47, 0x00, 0x54, 0x00, 0x61, 0x6c, 0x73, 0x6f, 310x00, 0x61, 0x6e, 0x64, 0x00, 0x73, 0x6f, 0x6d, 0x65, 0x47,
310x29, 0x00, 0x90, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 320x00, 0x54, 0x00, 0x61, 0x6c, 0x73, 0x6f, 0x29, 0x00, 0x90,
320x73, 0x2e, 0x78, 0x00, 0xa1, 0x72, 0x00, 0x6a, 0x6f, 0x62, 330x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2e, 0x78,
330x00, 0x69, 0x73, 0x00, 0x74, 0x20, 0x00, 0x32, 0x6e, 0x65, 340x00, 0xa1, 0x72, 0x00, 0x6a, 0x6f, 0x62, 0x00, 0x69, 0x73,
340x63, 0x5f, 0x00, 0x04, 0x39, 0x00, 0x91, 0x74, 0x6f, 0x00, 350x00, 0x74, 0x20, 0x00, 0x32, 0x6e, 0x65, 0x63, 0x5f, 0x00,
350x66, 0x6f, 0x72, 0x6d, 0x00, 0x61, 0x3e, 0x00, 0x90, 0x69, 360x04, 0x39, 0x00, 0x91, 0x74, 0x6f, 0x00, 0x66, 0x6f, 0x72,
360x6e, 0x75, 0x6f, 0x75, 0x73, 0x00, 0x6c, 0x69, 0x7c, 0x00, 370x6d, 0x00, 0x61, 0x3e, 0x00, 0x90, 0x69, 0x6e, 0x75, 0x6f,
370x14, 0x66, 0x49, 0x00, 0xe1, 0x00, 0x73, 0x74, 0x61, 0x72, 380x75, 0x73, 0x00, 0x6c, 0x69, 0x7c, 0x00, 0x14, 0x66, 0x49,
380x74, 0x69, 0x6e, 0x67, 0x00, 0x61, 0x74, 0x00, 0x31, 0x7d, 390x00, 0xe1, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e,
390x00, 0x91, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x64, 0x00, 0x69, 400x67, 0x00, 0x61, 0x74, 0x00, 0x31, 0x7d, 0x00, 0x91, 0x6c,
400x6e, 0x4d, 0x00, 0x90, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 410x69, 0x6e, 0x6b, 0x65, 0x64, 0x00, 0x69, 0x6e, 0x4d, 0x00,
410x69, 0x6f, 0x6e, 0x35, 0x00, 0x00, 0x11, 0x00, 0x01, 0xa7, 420x90, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
420x00, 0x66, 0x73, 0x00, 0x2d, 0x00, 0x73, 0x6f, 0x10, 0x00, 430x35, 0x00, 0x00, 0x11, 0x00, 0x01, 0xa7, 0x00, 0x66, 0x73,
430x77, 0x00, 0x69, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x7f, 0x00, 440x00, 0x2d, 0x00, 0x73, 0x6f, 0x10, 0x00, 0x77, 0x00, 0x69,
440x51, 0x00, 0x77, 0x69, 0x74, 0x68, 0x10, 0x00, 0x02, 0x6a, 450x6e, 0x73, 0x69, 0x64, 0x65, 0x7f, 0x00, 0x51, 0x00, 0x77,
450x00, 0xd0, 0x00, 0x31, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0x00, 460x69, 0x74, 0x68, 0x10, 0x00, 0x02, 0x6a, 0x00, 0xd0, 0x00,
460x70, 0x6f, 0x69, 0x6e, 0x74, 0x9b, 0x00, 0x07, 0x2b, 0x00, 470x31, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0x00, 0x70, 0x6f, 0x69,
470x03, 0xdd, 0x00, 0x00, 0x86, 0x00, 0x07, 0x31, 0x00, 0x8f, 480x6e, 0x74, 0x9b, 0x00, 0x07, 0x2b, 0x00, 0x03, 0xdd, 0x00,
480x32, 0x2c, 0x00, 0x77, 0x68, 0x69, 0x63, 0x68, 0x38, 0x00, 490x00, 0x86, 0x00, 0x07, 0x31, 0x00, 0x8f, 0x32, 0x2c, 0x00,
490x1d, 0x97, 0x33, 0x2c, 0x00, 0x65, 0x74, 0x63, 0x2e, 0x00, 500x77, 0x68, 0x69, 0x63, 0x68, 0x38, 0x00, 0x1d, 0x97, 0x33,
500x45, 0x7e, 0x01, 0xf1, 0x0e, 0x63, 0x61, 0x6e, 0x00, 0x62, 510x2c, 0x00, 0x65, 0x74, 0x63, 0x2e, 0x00, 0x45, 0x7e, 0x01,
510x65, 0x00, 0x61, 0x6e, 0x79, 0x00, 0x64, 0x69, 0x73, 0x74, 520xf1, 0x0e, 0x63, 0x61, 0x6e, 0x00, 0x62, 0x65, 0x00, 0x61,
520x61, 0x6e, 0x63, 0x65, 0x00, 0x61, 0x77, 0x61, 0x79, 0x00, 530x6e, 0x79, 0x00, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63,
530x66, 0x72, 0x6f, 0x6d, 0x3d, 0x00, 0x50, 0x70, 0x72, 0x65, 540x65, 0x00, 0x61, 0x77, 0x61, 0x79, 0x00, 0x66, 0x72, 0x6f,
540x76, 0x69, 0x21, 0x01, 0xc0, 0x6f, 0x6e, 0x65, 0x2c, 0x00, 550x6d, 0x3d, 0x00, 0x50, 0x70, 0x72, 0x65, 0x76, 0x69, 0x21,
550x61, 0x73, 0x00, 0x6c, 0x6f, 0x6e, 0x67, 0x08, 0x00, 0x20, 560x01, 0xc0, 0x6f, 0x6e, 0x65, 0x2c, 0x00, 0x61, 0x73, 0x00,
560x69, 0x74, 0x63, 0x01, 0x00, 0x92, 0x01, 0x5f, 0x77, 0x68, 570x6c, 0x6f, 0x6e, 0x67, 0x08, 0x00, 0x20, 0x69, 0x74, 0x63,
570x65, 0x72, 0x65, 0x18, 0x01, 0x0b, 0x60, 0x2e, 0x00, 0x00, 580x01, 0x00, 0x92, 0x01, 0x5f, 0x77, 0x68, 0x65, 0x72, 0x65,
580x00, 0x42, 0x79, 0x99, 0x00, 0x31, 0x76, 0x65, 0x6e, 0x1e, 590x18, 0x01, 0x0b, 0x60, 0x2e, 0x00, 0x00, 0x00, 0x42, 0x79,
590x00, 0x00, 0x1b, 0x00, 0x52, 0x66, 0x69, 0x72, 0x73, 0x74, 600x99, 0x00, 0x31, 0x76, 0x65, 0x6e, 0x1e, 0x00, 0x00, 0x1b,
600x5c, 0x01, 0x00, 0xfa, 0x01, 0x04, 0x7b, 0x01, 0x00, 0x99, 610x00, 0x52, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5c, 0x01, 0x00,
610x00, 0x60, 0x73, 0x68, 0x6f, 0x77, 0x6e, 0x3b, 0x75, 0x00, 620xfa, 0x01, 0x04, 0x7b, 0x01, 0x00, 0x99, 0x00, 0x60, 0x73,
620x61, 0x00, 0x6f, 0x72, 0x00, 0x6d, 0x6f, 0x61, 0x00, 0x55, 630x68, 0x6f, 0x77, 0x6e, 0x3b, 0x75, 0x00, 0x61, 0x00, 0x6f,
630x74, 0x65, 0x72, 0x69, 0x6d, 0x27, 0x00, 0x32, 0x6d, 0x61, 640x72, 0x00, 0x6d, 0x6f, 0x61, 0x00, 0x55, 0x74, 0x65, 0x72,
640x79, 0x04, 0x02, 0x82, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 650x69, 0x6d, 0x27, 0x00, 0x32, 0x6d, 0x61, 0x79, 0x04, 0x02,
650x00, 0x61, 0xe6, 0x01, 0x50, 0x62, 0x65, 0x67, 0x69, 0x6e, 660x82, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x00, 0x61, 0xe6,
660xfc, 0x00, 0x00, 0x74, 0x00, 0x60, 0x43, 0x72, 0x65, 0x64, 670x01, 0x50, 0x62, 0x65, 0x67, 0x69, 0x6e, 0xfc, 0x00, 0x00,
670x69, 0x74, 0xef, 0x01, 0xf2, 0x00, 0x00, 0x74, 0x68, 0x69, 680x74, 0x00, 0x60, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0xef,
680x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x67, 690x01, 0xf2, 0x00, 0x00, 0x74, 0x68, 0x69, 0x73, 0x00, 0x70,
690x6f, 0x07, 0x02, 0xa0, 0x4a, 0x61, 0x6e, 0x6b, 0x6f, 0x00, 700x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x67, 0x6f, 0x07, 0x02,
700x5b, 0x31, 0x37, 0x5d, 0x54, 0x01, 0x60, 0x6f, 0x00, 0x63, 710xa0, 0x4a, 0x61, 0x6e, 0x6b, 0x6f, 0x00, 0x5b, 0x31, 0x37,
710x61, 0x6c, 0x6c, 0xd9, 0x00, 0xe2, 0x60, 0x50, 0x66, 0x65, 720x5d, 0x54, 0x01, 0x60, 0x6f, 0x00, 0x63, 0x61, 0x6c, 0x6c,
720x69, 0x6c, 0x70, 0x66, 0x61, 0x64, 0x27, 0x00, 0x28, 0x60, 730xd9, 0x00, 0xe2, 0x60, 0x50, 0x66, 0x65, 0x69, 0x6c, 0x70,
730xca, 0x01, 0x60, 0x70, 0x61, 0x74, 0x68, 0x27, 0x29, 0x55, 740x66, 0x61, 0x64, 0x27, 0x00, 0x28, 0x60, 0xca, 0x01, 0x60,
740x00, 0x04, 0xe7, 0x02, 0x41, 0x00, 0x77, 0x61, 0x73, 0x6c, 750x70, 0x61, 0x74, 0x68, 0x27, 0x29, 0x55, 0x00, 0x04, 0xfc,
750x01, 0x72, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x86, 760x02, 0x41, 0x00, 0x77, 0x61, 0x73, 0x6c, 0x01, 0x72, 0x72,
760x01, 0x10, 0x69, 0x14, 0x00, 0x23, 0x6c, 0x6c, 0x05, 0x01, 770x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x86, 0x01, 0x10, 0x69,
770xf0, 0x00, 0x62, 0x79, 0x00, 0x4a, 0x61, 0x6d, 0x65, 0x73, 780x14, 0x00, 0x23, 0x6c, 0x6c, 0x05, 0x01, 0xf0, 0x00, 0x62,
780x00, 0x48, 0x61, 0x72, 0x76, 0x65, 0x79, 0x3f, 0x00, 0x00, 790x79, 0x00, 0x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61,
790x6f, 0x00, 0x90, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 800x72, 0x76, 0x65, 0x79, 0x3f, 0x00, 0x00, 0x6f, 0x00, 0x90,
800x2f, 0x6a, 0x81, 0x00, 0xc5, 0x2e, 0x61, 0x74, 0x2f, 0x52, 810x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6a, 0x81,
810x61, 0x65, 0x74, 0x73, 0x65, 0x6c, 0x2f, 0x79, 0x00, 0xf6, 820x00, 0xc5, 0x2e, 0x61, 0x74, 0x2f, 0x52, 0x61, 0x65, 0x74,
820x02, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 830x73, 0x65, 0x6c, 0x2f, 0x79, 0x00, 0xf6, 0x02, 0x2f, 0x69,
830x6d, 0x00, 0x00, 0x00, 0x33, 0x34, 0x2e, 0x31, 0x5e, 0x03, 840x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x00, 0x00,
840x01, 0x73, 0x00, 0x30, 0x6f, 0x6c, 0x73, 0x67, 0x03, 0x75, 850x00, 0x33, 0x34, 0x2e, 0x31, 0x73, 0x03, 0x01, 0x73, 0x00,
850x54, 0x6f, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x94, 0x00, 0x55, 860xe5, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00, 0x00, 0x54, 0x6f,
860x2c, 0x00, 0x79, 0x6f, 0x75, 0xf6, 0x02, 0x06, 0xf2, 0x02, 870x00, 0x70, 0x6c, 0x61, 0x79, 0x94, 0x00, 0x55, 0x2c, 0x00,
870x60, 0x67, 0x65, 0x74, 0x68, 0x65, 0x72, 0x8f, 0x00, 0x50, 880x79, 0x6f, 0x75, 0xf6, 0x02, 0x06, 0xf2, 0x02, 0x60, 0x67,
880x64, 0x72, 0x61, 0x67, 0x67, 0x1b, 0x02, 0x01, 0xe3, 0x01, 890x65, 0x74, 0x68, 0x65, 0x72, 0x8f, 0x00, 0x50, 0x64, 0x72,
890x25, 0x6f, 0x6e, 0x36, 0x02, 0x60, 0x74, 0x6f, 0x00, 0x61, 900x61, 0x67, 0x67, 0x1b, 0x02, 0x01, 0xe3, 0x01, 0x25, 0x6f,
900x6e, 0x6f, 0x27, 0x00, 0x92, 0x2c, 0x00, 0x69, 0x6e, 0x64, 910x6e, 0x36, 0x02, 0x60, 0x74, 0x6f, 0x00, 0x61, 0x6e, 0x6f,
910x69, 0x63, 0x61, 0x74, 0x42, 0x02, 0x02, 0x59, 0x01, 0x11, 920x27, 0x00, 0x92, 0x2c, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x63,
920x79, 0x98, 0x01, 0x84, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x65, 930x61, 0x74, 0x42, 0x02, 0x02, 0x59, 0x01, 0x11, 0x79, 0x98,
930x6e, 0x74, 0xef, 0x01, 0xe6, 0x73, 0x65, 0x71, 0x75, 0x65, 940x01, 0x84, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x65, 0x6e, 0x74,
940x6e, 0x63, 0x65, 0x2e, 0x00, 0x44, 0x72, 0x61, 0x67, 0xdd, 950xef, 0x01, 0xe6, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63,
950x02, 0xb2, 0x6c, 0x65, 0x66, 0x74, 0x00, 0x62, 0x75, 0x74, 960x65, 0x2e, 0x00, 0x44, 0x72, 0x61, 0x67, 0xdd, 0x02, 0xb2,
960x74, 0x6f, 0x6e, 0x69, 0x00, 0x17, 0x61, 0x67, 0x00, 0xe0, 970x6c, 0x65, 0x66, 0x74, 0x00, 0x62, 0x75, 0x74, 0x74, 0x6f,
970x69, 0x74, 0x73, 0x00, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 980x6e, 0x69, 0x00, 0x17, 0x61, 0x67, 0x00, 0xe0, 0x69, 0x74,
980x73, 0x6f, 0x72, 0x2c, 0xe1, 0x01, 0x05, 0x38, 0x00, 0x4f, 990x73, 0x00, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f,
990x72, 0x69, 0x67, 0x68, 0x39, 0x00, 0x0b, 0x52, 0x70, 0x72, 1000x72, 0x2c, 0xe1, 0x01, 0x05, 0x38, 0x00, 0x4f, 0x72, 0x69,
1000x65, 0x64, 0x65, 0x3b, 0x00, 0x00, 0x4e, 0x01, 0x29, 0x49, 1010x67, 0x68, 0x39, 0x00, 0x0b, 0x52, 0x70, 0x72, 0x65, 0x64,
1010x66, 0xf2, 0x00, 0x05, 0xea, 0x00, 0x35, 0x74, 0x77, 0x6f, 1020x65, 0x3b, 0x00, 0x00, 0x4e, 0x01, 0x29, 0x49, 0x66, 0xf2,
1020xff, 0x00, 0x22, 0x69, 0x6e, 0x98, 0x01, 0x00, 0xd9, 0x02, 1030x00, 0x05, 0xea, 0x00, 0x35, 0x74, 0x77, 0x6f, 0xff, 0x00,
1030x00, 0x6e, 0x02, 0x01, 0x56, 0x02, 0x01, 0x9e, 0x02, 0x74, 1040x22, 0x69, 0x6e, 0x98, 0x01, 0x00, 0xd9, 0x02, 0x00, 0x6e,
1040x6d, 0x00, 0x68, 0x61, 0x73, 0x00, 0x61, 0x23, 0x03, 0x62, 1050x02, 0x01, 0x56, 0x02, 0x01, 0x9e, 0x02, 0x74, 0x6d, 0x00,
1050x69, 0x6e, 0x00, 0x69, 0x74, 0x2c, 0xb7, 0x02, 0x95, 0x70, 1060x68, 0x61, 0x73, 0x00, 0x61, 0x23, 0x03, 0x62, 0x69, 0x6e,
1060x70, 0x72, 0x6f, 0x70, 0x72, 0x69, 0x61, 0x74, 0x41, 0x03, 1070x00, 0x69, 0x74, 0x2c, 0xb7, 0x02, 0x95, 0x70, 0x70, 0x72,
1070x01, 0x70, 0x03, 0x03, 0x6d, 0x02, 0x03, 0xff, 0x00, 0x01, 1080x6f, 0x70, 0x72, 0x69, 0x61, 0x74, 0x41, 0x03, 0x01, 0x70,
1080x2f, 0x01, 0x03, 0x68, 0x00, 0x1d, 0x2e, 0x8c, 0x00, 0x72, 1090x03, 0x03, 0x6d, 0x02, 0x03, 0xff, 0x00, 0x01, 0x2f, 0x01,
1090x77, 0x6f, 0x00, 0x6e, 0x6f, 0x6e, 0x2d, 0x3f, 0x00, 0x24, 1100x03, 0x68, 0x00, 0x1d, 0x2e, 0x8c, 0x00, 0x72, 0x77, 0x6f,
1100x65, 0x64, 0x90, 0x00, 0x12, 0x2c, 0x4f, 0x01, 0x01, 0x4f, 1110x00, 0x6e, 0x6f, 0x6e, 0x2d, 0x3f, 0x00, 0x24, 0x65, 0x64,
1110x00, 0x00, 0x7d, 0x03, 0x50, 0x73, 0x73, 0x69, 0x67, 0x6e, 1120x90, 0x00, 0x12, 0x2c, 0x4f, 0x01, 0x01, 0x4f, 0x00, 0x00,
1120x3f, 0x02, 0x70, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 1130x7d, 0x03, 0x50, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x3f, 0x02,
1130xd7, 0x02, 0xf9, 0x01, 0x67, 0x65, 0x62, 0x72, 0x61, 0x69, 1140x70, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0xd7, 0x02,
1140x63, 0x00, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x00, 1150xf9, 0x01, 0x67, 0x65, 0x62, 0x72, 0x61, 0x69, 0x63, 0x00,
1150x32, 0x03, 0x8b, 0x6f, 0x63, 0x63, 0x61, 0x73, 0x69, 0x6f, 1160x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x3a, 0x00, 0x32, 0x03,
1160x6e, 0x49, 0x00, 0x01, 0x2c, 0x00, 0x71, 0x6c, 0x65, 0x64, 1170x8b, 0x6f, 0x63, 0x63, 0x61, 0x73, 0x69, 0x6f, 0x6e, 0x49,
1170x00, 0x60, 0x61, 0x27, 0xe8, 0x00, 0x52, 0x60, 0x61, 0x2b, 1180x00, 0x01, 0x2c, 0x00, 0x71, 0x6c, 0x65, 0x64, 0x00, 0x60,
1180x31, 0x27, 0x3a, 0x05, 0x73, 0x74, 0x68, 0x65, 0x6e, 0x00, 1190x61, 0x27, 0xe8, 0x00, 0x52, 0x60, 0x61, 0x2b, 0x31, 0x27,
1190x60, 0x62, 0x18, 0x00, 0x15, 0x62, 0x18, 0x00, 0x82, 0x73, 1200x3a, 0x05, 0x73, 0x74, 0x68, 0x65, 0x6e, 0x00, 0x60, 0x62,
1200x6f, 0x00, 0x6f, 0x6e, 0x2e, 0x00, 0x43, 0xb3, 0x00, 0x00, 1210x18, 0x00, 0x15, 0x62, 0x18, 0x00, 0x82, 0x73, 0x6f, 0x00,
1210xf0, 0x01, 0x01, 0x6c, 0x03, 0x04, 0x3a, 0x01, 0x24, 0x6f, 1220x6f, 0x6e, 0x2e, 0x00, 0x43, 0xb3, 0x00, 0x00, 0xf0, 0x01,
1220x6e, 0x5b, 0x04, 0x41, 0x65, 0x6e, 0x64, 0x73, 0xc5, 0x05, 1230x01, 0x6c, 0x03, 0x04, 0x3a, 0x01, 0x24, 0x6f, 0x6e, 0x5b,
1230x30, 0x75, 0x63, 0x68, 0x3a, 0x05, 0x10, 0x68, 0x76, 0x05, 1240x04, 0x41, 0x65, 0x6e, 0x64, 0x73, 0xc5, 0x05, 0x30, 0x75,
1240x01, 0x7a, 0x00, 0x52, 0x63, 0x61, 0x75, 0x73, 0x65, 0x4d, 1250x63, 0x68, 0x3a, 0x05, 0x10, 0x68, 0x76, 0x05, 0x01, 0x7a,
1250x01, 0x00, 0x3f, 0x03, 0x29, 0x74, 0x6f, 0x8c, 0x00, 0x05, 1260x00, 0x52, 0x63, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x01, 0x00,
1260xda, 0x01, 0x30, 0x73, 0x61, 0x6d, 0x17, 0x02, 0x31, 0x74, 1270x3f, 0x03, 0x29, 0x74, 0x6f, 0x8c, 0x00, 0x05, 0xda, 0x01,
1270x74, 0x65, 0xb8, 0x01, 0x10, 0x57, 0x91, 0x00, 0x00, 0x2e, 1280x30, 0x73, 0x61, 0x6d, 0x17, 0x02, 0x31, 0x74, 0x74, 0x65,
1280x01, 0x00, 0x2a, 0x02, 0x60, 0x2d, 0x63, 0x6c, 0x69, 0x63, 1290xb8, 0x01, 0x10, 0x57, 0x91, 0x00, 0x00, 0x2e, 0x01, 0x00,
1290x6b, 0x09, 0x02, 0x01, 0x00, 0x02, 0x03, 0x0f, 0x00, 0x25, 1300x2a, 0x02, 0x60, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x09,
1300x69, 0x6e, 0xfd, 0x01, 0x13, 0x2c, 0x55, 0x02, 0x38, 0x67, 1310x02, 0x01, 0x00, 0x02, 0x03, 0x0f, 0x00, 0x25, 0x69, 0x6e,
1310x61, 0x6c, 0xc7, 0x05, 0x04, 0x6a, 0x01, 0x11, 0x69, 0x02, 1320xfd, 0x01, 0x13, 0x2c, 0x55, 0x02, 0x38, 0x67, 0x61, 0x6c,
1320x05, 0x04, 0x08, 0x01, 0x01, 0x3c, 0x04, 0x10, 0x2e, 0x1d, 1330xc7, 0x05, 0x04, 0x6a, 0x01, 0x11, 0x69, 0x02, 0x05, 0x04,
1330x03, 0x07, 0x87, 0x05, 0x09, 0x75, 0x06, 0x01, 0xdd, 0x05, 1340x08, 0x01, 0x01, 0x3c, 0x04, 0x10, 0x2e, 0x1d, 0x03, 0x07,
1340x00, 0xcf, 0x00, 0x72, 0x66, 0x00, 0x62, 0x6c, 0x61, 0x63, 1350x87, 0x05, 0x09, 0x75, 0x06, 0x01, 0xdd, 0x05, 0x00, 0xcf,
1350x6b, 0x0c, 0x01, 0x01, 0x16, 0x04, 0x60, 0x67, 0x72, 0x65, 1360x00, 0x72, 0x66, 0x00, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x0c,
1360x79, 0x00, 0x6f, 0x08, 0x05, 0x09, 0xcb, 0x01, 0x2e, 0x68, 1370x01, 0x01, 0x16, 0x04, 0x60, 0x67, 0x72, 0x65, 0x79, 0x00,
1370x65, 0xc0, 0x02, 0x04, 0x85, 0x02, 0x59, 0x41, 0x6c, 0x73, 1380x6f, 0x08, 0x05, 0x09, 0xcb, 0x01, 0x2e, 0x68, 0x65, 0xc0,
1380x6f, 0x2c, 0x60, 0x00, 0x02, 0xa0, 0x05, 0x40, 0x6e, 0x65, 1390x02, 0x04, 0x85, 0x02, 0x59, 0x41, 0x6c, 0x73, 0x6f, 0x2c,
1390x65, 0x64, 0x5d, 0x02, 0x07, 0xb2, 0x02, 0x03, 0x6f, 0x02, 1400x60, 0x00, 0x02, 0xa0, 0x05, 0x40, 0x6e, 0x65, 0x65, 0x64,
1400x20, 0x73, 0x6d, 0x2a, 0x01, 0x25, 0x64, 0x6f, 0x47, 0x03, 1410x5d, 0x02, 0x07, 0xb2, 0x02, 0x03, 0x6f, 0x02, 0x20, 0x73,
1410x62, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x36, 0x03, 0x64, 1420x6d, 0x2a, 0x01, 0x25, 0x64, 0x6f, 0x47, 0x03, 0x62, 0x62,
1420x63, 0x6f, 0x72, 0x6e, 0x65, 0x72, 0xe5, 0x05, 0x86, 0x76, 1430x6f, 0x74, 0x74, 0x6f, 0x6d, 0x36, 0x03, 0x64, 0x63, 0x6f,
1430x61, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x73, 0x94, 0x00, 0x00, 1440x72, 0x6e, 0x65, 0x72, 0xe5, 0x05, 0x86, 0x76, 0x61, 0x6e,
1440x88, 0x06, 0x0b, 0x16, 0x03, 0x60, 0x2e, 0x00, 0x53, 0x6f, 1450x69, 0x73, 0x68, 0x65, 0x73, 0x94, 0x00, 0x00, 0x88, 0x06,
1450x00, 0x79, 0xfa, 0x06, 0x50, 0x61, 0x69, 0x6d, 0x00, 0x69, 1460x0b, 0x16, 0x03, 0x60, 0x2e, 0x00, 0x53, 0x6f, 0x00, 0x79,
1460x1c, 0x07, 0x39, 0x77, 0x61, 0x79, 0x23, 0x01, 0x19, 0x61, 1470xfa, 0x06, 0x50, 0x61, 0x69, 0x6d, 0x00, 0x69, 0x1c, 0x07,
1470x80, 0x06, 0x12, 0x61, 0xf8, 0x00, 0x03, 0x1e, 0x01, 0x2d, 1480x39, 0x77, 0x61, 0x79, 0x23, 0x01, 0x19, 0x61, 0x80, 0x06,
1480x74, 0x6f, 0x1f, 0x00, 0x42, 0x64, 0x6f, 0x74, 0x2e, 0x5f, 1490x12, 0x61, 0xf8, 0x00, 0x03, 0x1e, 0x01, 0x2d, 0x74, 0x6f,
1490x04, 0x52, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x23, 0x06, 0x00, 1500x1f, 0x00, 0x42, 0x64, 0x6f, 0x74, 0x2e, 0x5f, 0x04, 0x52,
1500x7a, 0x00, 0x11, 0x73, 0x4d, 0x05, 0x30, 0x61, 0x00, 0x70, 1510x72, 0x65, 0x6d, 0x6f, 0x76, 0x23, 0x06, 0x00, 0x7a, 0x00,
1510x1f, 0x07, 0x55, 0x63, 0x75, 0x6c, 0x61, 0x72, 0xca, 0x07, 1520x11, 0x73, 0x4d, 0x05, 0x30, 0x61, 0x00, 0x70, 0x1f, 0x07,
1520xa1, 0x62, 0x6f, 0x74, 0x68, 0x00, 0x69, 0x6e, 0x63, 0x6f, 1530x55, 0x63, 0x75, 0x6c, 0x61, 0x72, 0xca, 0x07, 0xa1, 0x62,
1530x6d, 0x38, 0x07, 0x00, 0x69, 0x03, 0x92, 0x75, 0x74, 0x67, 1540x6f, 0x74, 0x68, 0x00, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x38,
1540x6f, 0x69, 0x6e, 0x67, 0x29, 0x2c, 0xe7, 0x01, 0x10, 0x64, 1550x07, 0x00, 0x69, 0x03, 0x92, 0x75, 0x74, 0x67, 0x6f, 0x69,
1550x24, 0x04, 0x10, 0x69, 0x68, 0x07, 0x02, 0x1c, 0x06, 0x00, 1560x6e, 0x67, 0x29, 0x2c, 0xe7, 0x01, 0x10, 0x64, 0x24, 0x04,
1560x1a, 0x08, 0x18, 0x2e, 0x65, 0x00, 0x00, 0x86, 0x05, 0x22, 1570x10, 0x69, 0x68, 0x07, 0x02, 0x1c, 0x06, 0x00, 0x1a, 0x08,
1570x6c, 0x65, 0x5e, 0x02, 0x13, 0x2c, 0x0d, 0x02, 0x01, 0x35, 1580x18, 0x2e, 0x65, 0x00, 0x00, 0x86, 0x05, 0x22, 0x6c, 0x65,
1580x00, 0x00, 0x7f, 0x00, 0x03, 0x68, 0x00, 0x03, 0x33, 0x01, 1590x5e, 0x02, 0x13, 0x2c, 0x0d, 0x02, 0x01, 0x35, 0x00, 0x00,
1590x02, 0x82, 0x02, 0x0a, 0x4a, 0x00, 0x02, 0x77, 0x08, 0x00, 1600x7f, 0x00, 0x03, 0x68, 0x00, 0x03, 0x33, 0x01, 0x02, 0x82,
1600xd5, 0x06, 0x01, 0x19, 0x06, 0x03, 0x98, 0x02, 0x40, 0x00, 1610x02, 0x0a, 0x4a, 0x00, 0x02, 0x77, 0x08, 0x00, 0xd5, 0x06,
1610x63, 0x75, 0x72, 0x7c, 0x01, 0x22, 0x6b, 0x65, 0x13, 0x01, 1620x01, 0x19, 0x06, 0x03, 0x98, 0x02, 0x40, 0x00, 0x63, 0x75,
1620x02, 0x6b, 0x00, 0x55, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3c, 1630x72, 0x7c, 0x01, 0x22, 0x6b, 0x65, 0x13, 0x01, 0x02, 0x6b,
1630x00, 0x06, 0x56, 0x08, 0x02, 0xea, 0x07, 0x94, 0x65, 0x73, 1640x00, 0x55, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3c, 0x00, 0x06,
1640x2e, 0x00, 0x50, 0x72, 0x65, 0x73, 0x73, 0x45, 0x07, 0x80, 1650x56, 0x08, 0x02, 0xea, 0x07, 0x94, 0x65, 0x73, 0x2e, 0x00,
1650x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x00, 0x6b, 0x70, 0x03, 1660x50, 0x72, 0x65, 0x73, 0x73, 0x45, 0x07, 0x80, 0x72, 0x65,
1660x00, 0xbb, 0x02, 0x30, 0x6f, 0x76, 0x65, 0x07, 0x01, 0x0a, 1670x74, 0x75, 0x72, 0x6e, 0x00, 0x6b, 0x70, 0x03, 0x00, 0xbb,
1670x51, 0x02, 0x12, 0x61, 0x9d, 0x01, 0x50, 0x6f, 0x70, 0x65, 1680x02, 0x30, 0x6f, 0x76, 0x65, 0x07, 0x01, 0x0a, 0x51, 0x02,
1680x72, 0x61, 0xff, 0x05, 0x02, 0x58, 0x02, 0x1f, 0x70, 0x48, 1690x12, 0x61, 0x9d, 0x01, 0x50, 0x6f, 0x70, 0x65, 0x72, 0x61,
1690x00, 0x04, 0x4c, 0x61, 0x67, 0x61, 0x69, 0x49, 0x00, 0x01, 1700xff, 0x05, 0x02, 0x58, 0x02, 0x1f, 0x70, 0x48, 0x00, 0x04,
1700xc4, 0x02, 0x20, 0x66, 0x69, 0xf4, 0x01, 0x02, 0xf3, 0x02, 1710x4c, 0x61, 0x67, 0x61, 0x69, 0x49, 0x00, 0x01, 0xc4, 0x02,
1710x70, 0x69, 0x6e, 0x6b, 0x2c, 0x00, 0x69, 0x66, 0x5b, 0x03, 1720x20, 0x66, 0x69, 0xf4, 0x01, 0x02, 0xf3, 0x02, 0x70, 0x69,
1720x6b, 0x6f, 0x77, 0x61, 0x62, 0x6c, 0x65, 0x98, 0x00, 0x9f, 1730x6e, 0x6b, 0x2c, 0x00, 0x69, 0x66, 0x5b, 0x03, 0x6b, 0x6f,
1730x73, 0x70, 0x61, 0x63, 0x65, 0x00, 0x62, 0x61, 0x72, 0x49, 1740x77, 0x61, 0x62, 0x6c, 0x65, 0x98, 0x00, 0x9f, 0x73, 0x70,
1740x00, 0x01, 0x00, 0x0a, 0x03, 0x0d, 0xa8, 0x04, 0x12, 0x73, 1750x61, 0x63, 0x65, 0x00, 0x62, 0x61, 0x72, 0x49, 0x00, 0x01,
1750x34, 0x08, 0x01, 0x41, 0x00, 0x00, 0x3d, 0x02, 0x02, 0xa5, 1760x00, 0x0a, 0x03, 0x0d, 0xa8, 0x04, 0x12, 0x73, 0x34, 0x08,
1760x00, 0x01, 0x60, 0x00, 0x01, 0x60, 0x02, 0x06, 0x1f, 0x09, 1770x01, 0x41, 0x00, 0x00, 0x3d, 0x02, 0x02, 0xa5, 0x00, 0x01,
1770x72, 0x62, 0x61, 0x63, 0x6b, 0x77, 0x61, 0x72, 0xfb, 0x08, 1780x60, 0x00, 0x01, 0x60, 0x02, 0x06, 0x1f, 0x09, 0x72, 0x62,
1780x0e, 0xcc, 0x00, 0x07, 0x7c, 0x00, 0x02, 0xcb, 0x00, 0x10, 1790x61, 0x63, 0x6b, 0x77, 0x61, 0x72, 0xfb, 0x08, 0x0e, 0xcc,
1790x63, 0x40, 0x08, 0x21, 0x6c, 0x73, 0x6d, 0x05, 0x00, 0x8d, 1800x00, 0x07, 0x7c, 0x00, 0x02, 0xcb, 0x00, 0x10, 0x63, 0x40,
1800x01, 0x42, 0x28, 0x41, 0x6c, 0x6c, 0x4d, 0x05, 0x01, 0x0d, 1810x08, 0x21, 0x6c, 0x73, 0x6d, 0x05, 0x00, 0x8d, 0x01, 0x42,
1810x07, 0x92, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 1820x28, 0x41, 0x6c, 0x6c, 0x4d, 0x05, 0x01, 0x0d, 0x07, 0x92,
1820x62, 0x46, 0x09, 0x13, 0x73, 0x23, 0x07, 0x32, 0x32, 0x2e, 1830x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x46,
1830x31, 0x5b, 0x06, 0x01, 0xcc, 0x07, 0x41, 0x76, 0x61, 0x69, 1840x09, 0x13, 0x73, 0x23, 0x07, 0x32, 0x32, 0x2e, 0x31, 0x5b,
1840x6c, 0xe7, 0x00, 0x12, 0x29, 0xf8, 0x06, 0x16, 0x32, 0xf8, 1850x06, 0x01, 0xcc, 0x07, 0x41, 0x76, 0x61, 0x69, 0x6c, 0xe7,
1850x06, 0xb2, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 1860x00, 0x12, 0x29, 0xf8, 0x06, 0x16, 0x32, 0xf8, 0x06, 0xb2,
1860x72, 0x73, 0x20, 0xdd, 0x03, 0x36, 0x73, 0x65, 0x00, 0x14, 1870x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73,
1870x00, 0x02, 0x44, 0x00, 0x04, 0x3f, 0x00, 0x06, 0xc1, 0x08, 1880x20, 0xdd, 0x03, 0x36, 0x73, 0x65, 0x00, 0x14, 0x00, 0x02,
1880xe2, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 1890x44, 0x00, 0x04, 0x3f, 0x00, 0x06, 0xc1, 0x08, 0xe2, 0x60,
1890x2e, 0x27, 0x00, 0x6f, 0x70, 0x9a, 0x08, 0x12, 0x6e, 0x1a, 1900x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27,
1900x00, 0xa1, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 1910x00, 0x6f, 0x70, 0x9a, 0x08, 0x12, 0x6e, 0x1a, 0x00, 0xa1,
1910x6e, 0x75, 0x92, 0x04, 0x81, 0x69, 0x64, 0x74, 0x68, 0x2c, 1920x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75,
1920x00, 0x48, 0x65, 0x83, 0x06, 0x00, 0xe7, 0x07, 0x11, 0x7a, 1930x92, 0x04, 0x81, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48,
1930x27, 0x06, 0x01, 0x1f, 0x02, 0x24, 0x69, 0x6e, 0x3e, 0x01, 1940x65, 0x83, 0x06, 0x00, 0xe7, 0x07, 0x11, 0x7a, 0x27, 0x06,
1940x00, 0x2b, 0x00, 0x61, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x20, 1950x01, 0x1f, 0x02, 0x24, 0x69, 0x6e, 0x3e, 0x01, 0x00, 0x2b,
1950xf5, 0x01, 0x82, 0x2f, 0x65, 0x6e, 0x64, 0x20, 0x74, 0x6f, 1960x00, 0x61, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x20, 0xf5, 0x01,
1960x20, 0xb6, 0x03, 0x12, 0x73, 0x92, 0x06, 0x33, 0x74, 0x72, 1970x82, 0x2f, 0x65, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20, 0xb6,
1970x75, 0xb3, 0x04, 0x01, 0x24, 0x00, 0x01, 0x3a, 0x01, 0x27, 1980x03, 0x12, 0x73, 0x92, 0x06, 0x33, 0x74, 0x72, 0x75, 0xb3,
1980x65, 0x6e, 0x65, 0x02, 0x24, 0x72, 0x65, 0xa3, 0x03, 0x42, 1990x04, 0x01, 0x24, 0x00, 0x01, 0x3a, 0x01, 0x27, 0x65, 0x6e,
1990x70, 0x6c, 0x61, 0x63, 0x10, 0x01, 0x94, 0x6f, 0x70, 0x70, 2000x65, 0x02, 0x24, 0x72, 0x65, 0xa3, 0x03, 0x42, 0x70, 0x6c,
2000x6f, 0x73, 0x69, 0x74, 0x65, 0x00, 0x4b, 0x00, 0x17, 0x28, 2010x61, 0x63, 0x10, 0x01, 0x94, 0x6f, 0x70, 0x70, 0x6f, 0x73,
2010x41, 0x00, 0x02, 0x83, 0x04, 0x31, 0x74, 0x6f, 0x70, 0x49, 2020x69, 0x74, 0x65, 0x00, 0x4b, 0x00, 0x17, 0x28, 0x41, 0x00,
2020x03, 0x05, 0xd4, 0x05, 0x01, 0x56, 0x00, 0x28, 0x61, 0x74, 2030x02, 0x83, 0x04, 0x31, 0x74, 0x6f, 0x70, 0x49, 0x03, 0x05,
2030x44, 0x04, 0x01, 0x35, 0x03, 0x11, 0x29, 0x8d, 0x06, 0x5f, 2040xd4, 0x05, 0x01, 0x56, 0x00, 0x28, 0x61, 0x74, 0x44, 0x04,
2040x66, 0x61, 0x6c, 0x73, 0x65, 0x87, 0x00, 0x0c, 0x03, 0x80, 2050x01, 0x35, 0x03, 0x11, 0x29, 0x8d, 0x06, 0x5f, 0x66, 0x61,
2050x00, 0xf4, 0x03, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x6c, 2060x6c, 0x73, 0x65, 0x87, 0x00, 0x0c, 0x03, 0x80, 0x00, 0xf4,
2060x79, 0x00, 0x28, 0x61, 0x6c, 0x74, 0x68, 0x6f, 0x75, 0x67, 2070x03, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x6c, 0x79, 0x00,
2070x68, 0xa1, 0x00, 0x01, 0xd6, 0x03, 0x80, 0x73, 0x68, 0x6f, 2080x28, 0x61, 0x6c, 0x74, 0x68, 0x6f, 0x75, 0x67, 0x68, 0xa1,
2080x77, 0x6e, 0x29, 0x2e, 0x00, 2090x00, 0x01, 0xd6, 0x03, 0x01, 0x53, 0x05, 0x22, 0x29, 0x2e,
2100x93, 0x01, 0x16, 0x33, 0x93, 0x01, 0xb0, 0x75, 0x73, 0x65,
2110x72, 0x20, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x06, 0x08,
2120x01, 0x99, 0x01, 0x20, 0x4f, 0x6e, 0x55, 0x00, 0x10, 0x74,
2130x44, 0x02, 0x12, 0x73, 0x3e, 0x08, 0x80, 0x73, 0x75, 0x70,
2140x70, 0x6f, 0x72, 0x74, 0x00, 0x2e, 0x00, 0x17, 0x00, 0x2e,
2150x00, 0x12, 0x2c, 0x87, 0x01, 0x16, 0x50, 0x12, 0x00, 0x0d,
2160xa3, 0x01, 0x33, 0x47, 0x61, 0x6d, 0xa3, 0x01, 0x02, 0xd2,
2170x02, 0x34, 0x6c, 0x65, 0x74, 0x99, 0x05, 0x54, 0x66, 0x69,
2180x67, 0x75, 0x72, 0xdf, 0x00, 0x34, 0x79, 0x6c, 0x65, 0x71,
2190x0a, 0xf0, 0x01, 0x76, 0x69, 0x63, 0x74, 0x6f, 0x72, 0x79,
2200x00, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x2e, 0x00,
209}; 221};
210 222
211const unsigned short help_text_len = 3054; 223const unsigned short help_text_len = 3255;
212const unsigned short help_text_words = 566; 224const unsigned short help_text_words = 595;
213const char quick_help_text[] = "Connect the squares into a path following the arrows."; 225const char quick_help_text[] = "Connect the squares into a path following the arrows.";
diff --git a/apps/plugins/puzzles/help/singles.c b/apps/plugins/puzzles/help/singles.c
index 3f4ecd157b..f2bd1ae4d9 100644
--- a/apps/plugins/puzzles/help/singles.c
+++ b/apps/plugins/puzzles/help/singles.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,124 +6,147 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 122, TEXT_CENTER | C_RED }, 9 { 120, TEXT_CENTER | C_RED },
10 { 212, TEXT_CENTER | C_RED }, 10 { 232, TEXT_CENTER | C_RED },
11 { 229, TEXT_UNDERLINE }, 11 { 249, TEXT_UNDERLINE },
12 { 230, TEXT_UNDERLINE }, 12 { 250, TEXT_UNDERLINE },
13 { 240, TEXT_UNDERLINE }, 13 { 260, TEXT_UNDERLINE },
14 { 272, TEXT_CENTER | C_RED },
14 LAST_STYLE_ITEM 15 LAST_STYLE_ITEM
15}; 16};
16 17
17/* orig 1392 comp 1052 ratio 0.755747 level 10 saved 340 */ 18/* orig 1780 comp 1279 ratio 0.718539 level 10 saved 501 */
18const char help_text[] = { 19const char help_text[] = {
190xf3, 0x2d, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 200xfe, 0x07, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
200x33, 0x32, 0x3a, 0x20, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 210x33, 0x32, 0x3a, 0x20, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65,
210x73, 0x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 220x73, 0x20, 0x00, 0x2d, 0x01, 0x00, 0xf3, 0x19, 0x00, 0x00,
220x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 230x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00,
230x00, 0x6f, 0x66, 0x00, 0x77, 0x68, 0x69, 0x74, 0x65, 0x00, 240x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00,
240x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x61, 250x77, 0x68, 0x69, 0x74, 0x65, 0x00, 0x73, 0x71, 0x75, 0x61,
250x6c, 0x6c, 0x16, 0x00, 0xf0, 0x04, 0x63, 0x68, 0x00, 0x63, 260x72, 0x65, 0x73, 0x2c, 0x00, 0x61, 0x6c, 0x6c, 0x16, 0x00,
260x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x00, 0x6e, 0x75, 0x6d, 270xf0, 0x04, 0x63, 0x68, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61,
270x62, 0x65, 0x72, 0x73, 0x2e, 0x40, 0x00, 0xf0, 0x01, 0x72, 280x69, 0x6e, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73,
280x00, 0x74, 0x61, 0x73, 0x6b, 0x00, 0x69, 0x73, 0x00, 0x74, 290x2e, 0x40, 0x00, 0xf0, 0x01, 0x72, 0x00, 0x74, 0x61, 0x73,
290x6f, 0x00, 0x63, 0x6f, 0x6c, 0x12, 0x00, 0x40, 0x73, 0x6f, 300x6b, 0x00, 0x69, 0x73, 0x00, 0x74, 0x6f, 0x00, 0x63, 0x6f,
300x6d, 0x65, 0x36, 0x00, 0x25, 0x74, 0x68, 0x4a, 0x00, 0xf1, 310x6c, 0x12, 0x00, 0x40, 0x73, 0x6f, 0x6d, 0x65, 0x36, 0x00,
310x01, 0x00, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x00, 0x28, 0x72, 320x25, 0x74, 0x68, 0x4a, 0x00, 0xf1, 0x01, 0x00, 0x62, 0x6c,
320x65, 0x6d, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x1c, 0x00, 0x02, 330x61, 0x63, 0x6b, 0x00, 0x28, 0x72, 0x65, 0x6d, 0x6f, 0x76,
330x48, 0x00, 0x61, 0x29, 0x00, 0x73, 0x6f, 0x00, 0x61, 0x40, 340x69, 0x6e, 0x67, 0x1c, 0x00, 0x02, 0x48, 0x00, 0x61, 0x29,
340x00, 0x74, 0x73, 0x61, 0x74, 0x69, 0x73, 0x66, 0x79, 0x76, 350x00, 0x73, 0x6f, 0x00, 0x61, 0x40, 0x00, 0x74, 0x73, 0x61,
350x00, 0x00, 0x24, 0x00, 0x60, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 360x74, 0x69, 0x73, 0x66, 0x79, 0x76, 0x00, 0x00, 0x24, 0x00,
360x77, 0x32, 0x00, 0xf3, 0x03, 0x63, 0x6f, 0x6e, 0x64, 0x69, 370x60, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x32, 0x00, 0xf3,
370x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x00, 0x00, 0x00, 0x2d, 380x03, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
380x00, 0x4e, 0x6f, 0x41, 0x00, 0xf0, 0x15, 0x00, 0x6f, 0x63, 390x73, 0x3a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x4e, 0x6f, 0x41,
390x63, 0x75, 0x72, 0x73, 0x00, 0x6d, 0x6f, 0x72, 0x65, 0x00, 400x00, 0xf0, 0x15, 0x00, 0x6f, 0x63, 0x63, 0x75, 0x72, 0x73,
400x74, 0x68, 0x61, 0x6e, 0x00, 0x6f, 0x6e, 0x63, 0x65, 0x00, 410x00, 0x6d, 0x6f, 0x72, 0x65, 0x00, 0x74, 0x68, 0x61, 0x6e,
410x69, 0x6e, 0x00, 0x61, 0x6e, 0x79, 0x00, 0x72, 0x6f, 0x77, 420x00, 0x6f, 0x6e, 0x63, 0x65, 0x00, 0x69, 0x6e, 0x00, 0x61,
420x00, 0x6f, 0x72, 0x9b, 0x00, 0x44, 0x75, 0x6d, 0x6e, 0x2e, 430x6e, 0x79, 0x00, 0x72, 0x6f, 0x77, 0x00, 0x6f, 0x72, 0x9b,
430x3a, 0x00, 0x02, 0x8f, 0x00, 0x02, 0x9d, 0x00, 0x00, 0xbd, 440x00, 0x44, 0x75, 0x6d, 0x6e, 0x2e, 0x3a, 0x00, 0x02, 0x8f,
440x00, 0x50, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0xdf, 0x00, 0x30, 450x00, 0x02, 0x9d, 0x00, 0x00, 0xbd, 0x00, 0x50, 0x68, 0x6f,
450x6c, 0x6c, 0x79, 0x2f, 0x00, 0x61, 0x76, 0x65, 0x72, 0x74, 460x72, 0x69, 0x7a, 0xdf, 0x00, 0x30, 0x6c, 0x6c, 0x79, 0x2f,
460x69, 0x63, 0x0e, 0x00, 0x80, 0x61, 0x64, 0x6a, 0x61, 0x63, 470x00, 0x61, 0x76, 0x65, 0x72, 0x74, 0x69, 0x63, 0x0e, 0x00,
470x65, 0x6e, 0x74, 0xa1, 0x00, 0x00, 0x51, 0x00, 0x59, 0x6f, 480x80, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x65, 0x6e, 0x74, 0xa1,
480x74, 0x68, 0x65, 0x72, 0x41, 0x00, 0x02, 0x56, 0x00, 0xa0, 490x00, 0x00, 0x51, 0x00, 0x59, 0x6f, 0x74, 0x68, 0x65, 0x72,
490x54, 0x68, 0x65, 0x00, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 500x41, 0x00, 0x02, 0x56, 0x00, 0xa0, 0x54, 0x68, 0x65, 0x00,
500xae, 0x00, 0x09, 0x48, 0x01, 0x51, 0x00, 0x6d, 0x75, 0x73, 510x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0xae, 0x00, 0x09, 0x48,
510x74, 0xd6, 0x00, 0x81, 0x66, 0x6f, 0x72, 0x6d, 0x00, 0x6f, 520x01, 0x51, 0x00, 0x6d, 0x75, 0x73, 0x74, 0xd6, 0x00, 0x81,
520x6e, 0x65, 0x4c, 0x01, 0xf0, 0x10, 0x69, 0x67, 0x75, 0x6f, 530x66, 0x6f, 0x72, 0x6d, 0x00, 0x6f, 0x6e, 0x65, 0x4c, 0x01,
530x75, 0x73, 0x00, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x00, 540xf0, 0x10, 0x69, 0x67, 0x75, 0x6f, 0x75, 0x73, 0x00, 0x72,
540x28, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 550x65, 0x67, 0x69, 0x6f, 0x6e, 0x00, 0x28, 0x63, 0x6f, 0x6e,
550x00, 0x62, 0x79, 0x00, 0x65, 0x64, 0x67, 0x80, 0x01, 0x70, 560x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x00, 0x62, 0x79, 0x00,
560x6e, 0x6f, 0x74, 0x00, 0x6a, 0x75, 0x73, 0x7d, 0x00, 0x30, 570x65, 0x64, 0x67, 0x80, 0x01, 0x70, 0x6e, 0x6f, 0x74, 0x00,
570x75, 0x63, 0x68, 0x59, 0x00, 0xb0, 0x61, 0x74, 0x00, 0x63, 580x6a, 0x75, 0x73, 0x7d, 0x00, 0x30, 0x75, 0x63, 0x68, 0x59,
580x6f, 0x72, 0x6e, 0x65, 0x72, 0x73, 0x29, 0x78, 0x00, 0x60, 590x00, 0xb0, 0x61, 0x74, 0x00, 0x63, 0x6f, 0x72, 0x6e, 0x65,
590x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x58, 0x00, 0xf1, 0x01, 600x72, 0x73, 0x29, 0x78, 0x00, 0x60, 0x43, 0x72, 0x65, 0x64,
600x00, 0x74, 0x68, 0x69, 0x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 610x69, 0x74, 0x58, 0x00, 0xf1, 0x01, 0x00, 0x74, 0x68, 0x69,
610x6c, 0x65, 0x00, 0x67, 0x6f, 0x65, 0x52, 0x01, 0xf0, 0x02, 620x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x67,
620x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69, 0x00, 0x5b, 0x31, 0x35, 630x6f, 0x65, 0x52, 0x01, 0xf0, 0x02, 0x4e, 0x69, 0x6b, 0x6f,
630x5d, 0x00, 0x77, 0x68, 0x6f, 0x00, 0x63, 0x85, 0x00, 0x90, 640x6c, 0x69, 0x00, 0x5b, 0x31, 0x35, 0x5d, 0x00, 0x77, 0x68,
640x69, 0x74, 0x00, 0x48, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x41, 650x6f, 0x00, 0x63, 0x85, 0x00, 0x90, 0x69, 0x74, 0x00, 0x48,
650x00, 0x03, 0x0f, 0x02, 0x41, 0x00, 0x77, 0x61, 0x73, 0x95, 660x69, 0x74, 0x6f, 0x72, 0x69, 0x41, 0x00, 0x03, 0x23, 0x02,
660x00, 0x40, 0x72, 0x69, 0x62, 0x75, 0x84, 0x00, 0x22, 0x74, 670x41, 0x00, 0x77, 0x61, 0x73, 0x95, 0x00, 0x40, 0x72, 0x69,
670x6f, 0x51, 0x00, 0x60, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 680x62, 0x75, 0x84, 0x00, 0x22, 0x74, 0x6f, 0x51, 0x00, 0x60,
680x78, 0x01, 0x00, 0x97, 0x00, 0xc0, 0x4a, 0x61, 0x6d, 0x65, 690x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x78, 0x01, 0x00, 0x97,
690x73, 0x00, 0x48, 0x61, 0x72, 0x76, 0x65, 0x79, 0x3e, 0x00, 700x00, 0xc0, 0x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61,
700x01, 0x59, 0x00, 0xc1, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 710x72, 0x76, 0x65, 0x79, 0x3e, 0x00, 0x01, 0x59, 0x00, 0xd1,
710x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 0x70, 0x00, 0x82, 0x2e, 720x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77,
720x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6e, 0x2f, 0x8d, 0x00, 0x32, 730x77, 0x2e, 0x6e, 0x71, 0x00, 0xa2, 0x2e, 0x63, 0x6f, 0x2e,
730x73, 0x2f, 0x68, 0x6e, 0x00, 0xb1, 0x68, 0x74, 0x6d, 0x6c, 740x6a, 0x70, 0x2f, 0x65, 0x6e, 0x2f, 0x90, 0x00, 0x31, 0x73,
740x00, 0x28, 0x62, 0x65, 0x77, 0x61, 0x72, 0x20, 0x02, 0xd5, 750x2f, 0x68, 0x71, 0x00, 0x85, 0x2f, 0x00, 0x00, 0x00, 0x33,
750x46, 0x6c, 0x61, 0x73, 0x68, 0x29, 0x00, 0x00, 0x00, 0x33, 760x32, 0x2e, 0x31, 0x99, 0x02, 0x01, 0x72, 0x00, 0xf0, 0x02,
760x32, 0x2e, 0x31, 0x98, 0x02, 0x01, 0x85, 0x00, 0x21, 0x6f, 770x6f, 0x6c, 0x73, 0x20, 0x00, 0x00, 0x00, 0x4c, 0x65, 0x66,
770x6c, 0xa1, 0x02, 0xa0, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 780x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0xe8, 0x00, 0x10,
780x6c, 0x69, 0x63, 0x6b, 0xfb, 0x00, 0x10, 0x6f, 0xd2, 0x01, 790x6f, 0xbf, 0x01, 0x64, 0x00, 0x65, 0x6d, 0x70, 0x74, 0x79,
790x64, 0x00, 0x65, 0x6d, 0x70, 0x74, 0x79, 0xbb, 0x01, 0x44, 800xa8, 0x01, 0x44, 0x77, 0x69, 0x6c, 0x6c, 0x64, 0x02, 0x22,
800x77, 0x69, 0x6c, 0x6c, 0x77, 0x02, 0x22, 0x69, 0x74, 0x96, 810x69, 0x74, 0x83, 0x01, 0x30, 0x3b, 0x00, 0x6c, 0x37, 0x00,
810x01, 0x39, 0x3b, 0x00, 0x6c, 0x37, 0x00, 0x20, 0x61, 0x67, 820x15, 0x00, 0x38, 0x00, 0x20, 0x61, 0x67, 0xa3, 0x02, 0x01,
820xb5, 0x02, 0x01, 0x2a, 0x00, 0x42, 0x72, 0x65, 0x73, 0x74, 830x2b, 0x00, 0x42, 0x72, 0x65, 0x73, 0x74, 0x14, 0x02, 0x04,
830x26, 0x02, 0x04, 0x7e, 0x02, 0x67, 0x2e, 0x00, 0x52, 0x69, 840x6c, 0x02, 0x67, 0x2e, 0x00, 0x52, 0x69, 0x67, 0x68, 0x66,
840x67, 0x68, 0x2e, 0x00, 0x01, 0x28, 0x00, 0xf1, 0x05, 0x61, 850x00, 0x01, 0x28, 0x00, 0xf1, 0x05, 0x61, 0x64, 0x64, 0x00,
850x64, 0x64, 0x00, 0x61, 0x00, 0x63, 0x69, 0x72, 0x63, 0x6c, 860x61, 0x00, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x28,
860x65, 0x00, 0x28, 0x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x64, 870x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x52, 0x01, 0x72, 0x69,
870x01, 0x72, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0xc2, 880x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0xb0, 0x02, 0x20, 0x61,
880x02, 0x20, 0x61, 0x74, 0x25, 0x00, 0x30, 0x65, 0x6c, 0x6c, 890x74, 0x25, 0x00, 0x30, 0x65, 0x6c, 0x6c, 0x30, 0x02, 0xa1,
890x42, 0x02, 0xa1, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 900x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x65, 0x6c, 0x79,
900x65, 0x6c, 0x79, 0xb5, 0x01, 0x01, 0x8a, 0x00, 0x23, 0x29, 910xa3, 0x01, 0x01, 0x8b, 0x00, 0x45, 0x29, 0x2e, 0x00, 0x43,
910x2e, 0x65, 0x03, 0xb2, 0x63, 0x61, 0x6e, 0x00, 0x61, 0x6c, 920xbe, 0x00, 0x52, 0x75, 0x74, 0x73, 0x69, 0x64, 0x7b, 0x00,
920x73, 0x6f, 0x00, 0x75, 0x73, 0x7d, 0x00, 0x00, 0xb1, 0x02, 930x01, 0x5b, 0x03, 0x01, 0x69, 0x00, 0xad, 0x74, 0x6f, 0x67,
930x61, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0xa7, 0x01, 0x20, 940x67, 0x6c, 0x65, 0x00, 0x77, 0x68, 0x65, 0x44, 0x02, 0x00,
940x6d, 0x6f, 0x85, 0x03, 0x51, 0x72, 0x6f, 0x75, 0x6e, 0x64, 950x69, 0x01, 0x41, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x00, 0x14,
950x1f, 0x00, 0x00, 0x8e, 0x03, 0x74, 0x2e, 0x00, 0x50, 0x72, 960x68, 0x3b, 0x00, 0x03, 0x6a, 0x03, 0x00, 0x0d, 0x01, 0x50,
960x65, 0x73, 0x73, 0x2d, 0x03, 0x60, 0x72, 0x65, 0x74, 0x75, 970x74, 0x68, 0x65, 0x6d, 0x2c, 0x9b, 0x02, 0x71, 0x64, 0x69,
970x72, 0x6e, 0x9c, 0x02, 0x52, 0x73, 0x70, 0x61, 0x63, 0x65, 980x73, 0x70, 0x6c, 0x61, 0x79, 0x11, 0x00, 0x00, 0xe5, 0x02,
980x3b, 0x00, 0x01, 0xad, 0x00, 0x01, 0x18, 0x00, 0x14, 0x61, 990x72, 0x64, 0x61, 0x72, 0x6b, 0x00, 0x67, 0x72, 0x90, 0x01,
990x12, 0x01, 0x02, 0x99, 0x02, 0x2a, 0x6f, 0x72, 0xc4, 0x00, 1000x00, 0xd2, 0x03, 0xb2, 0x63, 0x61, 0x6e, 0x00, 0x61, 0x6c,
1000x40, 0x72, 0x65, 0x73, 0x70, 0xc6, 0x01, 0xb8, 0x76, 0x65, 1010x73, 0x6f, 0x00, 0x75, 0x73, 0x46, 0x00, 0x00, 0x1e, 0x03,
1010x6c, 0x79, 0x2c, 0x00, 0x61, 0x6e, 0x64, 0x00, 0x70, 0x5d, 1020x61, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x14, 0x02, 0x20,
1020x00, 0x3f, 0x6b, 0x65, 0x79, 0x27, 0x01, 0x0b, 0x00, 0x51, 1030x6d, 0x6f, 0xf2, 0x03, 0x55, 0x72, 0x6f, 0x75, 0x6e, 0x64,
1030x00, 0x01, 0xbc, 0x03, 0x03, 0xbf, 0x00, 0x01, 0x56, 0x00, 1040xa0, 0x00, 0x74, 0x2e, 0x00, 0x50, 0x72, 0x65, 0x73, 0x73,
1040x00, 0xde, 0x00, 0x41, 0x28, 0x41, 0x6c, 0x6c, 0x13, 0x00, 1050x9a, 0x03, 0x60, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x6e,
1050x11, 0x61, 0x24, 0x02, 0x00, 0x08, 0x01, 0x70, 0x73, 0x63, 1060x00, 0x52, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3b, 0x00, 0x02,
1060x72, 0x69, 0x62, 0x65, 0x64, 0x81, 0x03, 0x13, 0x73, 0x3a, 1070xc3, 0x00, 0x00, 0x18, 0x00, 0x14, 0x61, 0x92, 0x01, 0x02,
1070x02, 0x40, 0x32, 0x2e, 0x31, 0x00, 0x9d, 0x00, 0x01, 0x04, 1080xc2, 0x00, 0x2a, 0x6f, 0x72, 0x43, 0x01, 0x40, 0x72, 0x65,
1080x01, 0xa3, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 1090x73, 0x70, 0x33, 0x02, 0xb8, 0x76, 0x65, 0x6c, 0x79, 0x2c,
1090x65, 0x2e, 0xfc, 0x01, 0x15, 0x32, 0xfc, 0x01, 0x91, 0x70, 1100x00, 0x61, 0x6e, 0x64, 0x00, 0x70, 0x5d, 0x00, 0x3f, 0x6b,
1100x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0xfe, 0x01, 1110x65, 0x79, 0xa6, 0x01, 0x0b, 0x00, 0x51, 0x00, 0x01, 0x29,
1110x66, 0x54, 0x68, 0x65, 0x73, 0x65, 0x00, 0x14, 0x00, 0x02, 1120x04, 0x03, 0xbf, 0x00, 0x01, 0x56, 0x00, 0x00, 0xde, 0x00,
1120x43, 0x00, 0x04, 0x3e, 0x00, 0x51, 0x00, 0x66, 0x72, 0x6f, 1130x41, 0x28, 0x41, 0x6c, 0x6c, 0x13, 0x00, 0x11, 0x61, 0x91,
1130x6d, 0x7b, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 1140x02, 0x00, 0x87, 0x01, 0x70, 0x73, 0x63, 0x72, 0x69, 0x62,
1140x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x71, 0x00, 1150x65, 0x64, 0x09, 0x01, 0x13, 0x73, 0xa7, 0x02, 0x40, 0x32,
1150x22, 0x6f, 0x6e, 0x1a, 0x00, 0xa0, 0x54, 0x79, 0x70, 0x65, 1160x2e, 0x31, 0x00, 0x9d, 0x00, 0x01, 0x04, 0x01, 0xb2, 0x61,
1160x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xad, 0x00, 0x90, 0x57, 1170x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29,
1170x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0xf3, 0x01, 1180x7c, 0x02, 0x15, 0x32, 0x7c, 0x02, 0x91, 0x70, 0x61, 0x72,
1180x01, 0xfc, 0x02, 0x11, 0x7a, 0x89, 0x02, 0x01, 0xfd, 0x04, 1190x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x7e, 0x02, 0x66, 0x54,
1190x24, 0x69, 0x6e, 0xaf, 0x03, 0x00, 0x2b, 0x00, 0xa0, 0x44, 1200x68, 0x65, 0x73, 0x65, 0x00, 0x14, 0x00, 0x02, 0x43, 0x00,
1200x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x65, 1210x04, 0x3e, 0x00, 0x51, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x7b,
1210x03, 0x03, 0x93, 0x02, 0x01, 0x54, 0x00, 0x16, 0x64, 0x1a, 1220x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e,
1220x00, 0x03, 0xa4, 0x04, 0x60, 0x67, 0x65, 0x6e, 0x65, 0x72, 1230x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x71, 0x00, 0x22, 0x6f,
1230x61, 0x35, 0x03, 0x80, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 1240x6e, 0x1a, 0x00, 0xa0, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00,
1240x2e, 0x00, 1250x6d, 0x65, 0x6e, 0x75, 0xad, 0x00, 0x90, 0x57, 0x69, 0x64,
1260x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x72, 0x02, 0x01, 0x69,
1270x03, 0x11, 0x7a, 0x16, 0x05, 0x01, 0x0f, 0x02, 0x24, 0x69,
1280x6e, 0xf8, 0x01, 0x00, 0x2b, 0x00, 0xa0, 0x44, 0x69, 0x66,
1290x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0xd2, 0x03, 0x03,
1300x13, 0x03, 0x01, 0x54, 0x00, 0x16, 0x64, 0x1a, 0x00, 0x03,
1310x11, 0x05, 0x60, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0xa2,
1320x03, 0x02, 0x5b, 0x03, 0x12, 0x2e, 0xd7, 0x00, 0x15, 0x33,
1330xd7, 0x00, 0xf1, 0x00, 0x75, 0x73, 0x65, 0x72, 0x20, 0x70,
1340x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0xdd,
1350x00, 0x70, 0x4f, 0x6e, 0x00, 0x70, 0x6c, 0x61, 0x74, 0x7e,
1360x04, 0x12, 0x73, 0xcb, 0x02, 0x80, 0x73, 0x75, 0x70, 0x70,
1370x6f, 0x72, 0x74, 0x00, 0x2e, 0x00, 0x17, 0x00, 0x2e, 0x00,
1380x12, 0x2c, 0xcb, 0x00, 0x16, 0x50, 0x12, 0x00, 0x0d, 0xe7,
1390x00, 0x33, 0x47, 0x61, 0x6d, 0xe7, 0x00, 0x02, 0xc1, 0x01,
1400x70, 0x6c, 0x65, 0x74, 0x00, 0x79, 0x6f, 0x75, 0x3e, 0x04,
1410x56, 0x66, 0x69, 0x67, 0x75, 0x72, 0xe1, 0x02, 0x07, 0xbf,
1420x02, 0x0a, 0xec, 0x02, 0x00, 0x5c, 0x01, 0x50, 0x76, 0x69,
1430x73, 0x69, 0x62, 0xc0, 0x00, 0x8f, 0x55, 0x6e, 0x6c, 0x69,
1440x6b, 0x65, 0x00, 0x63, 0x3c, 0x03, 0x05, 0x12, 0x2c, 0x89,
1450x04, 0x01, 0x6c, 0x00, 0xf0, 0x08, 0x70, 0x65, 0x72, 0x73,
1460x69, 0x73, 0x74, 0x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65,
1470x6e, 0x00, 0x67, 0x61, 0x6d, 0x65, 0x73, 0x2e, 0x00,
125}; 148};
126 149
127const unsigned short help_text_len = 1392; 150const unsigned short help_text_len = 1780;
128const unsigned short help_text_words = 250; 151const unsigned short help_text_words = 309;
129const char quick_help_text[] = "Black out the right set of duplicate numbers."; 152const char quick_help_text[] = "Black out the right set of duplicate numbers.";
diff --git a/apps/plugins/puzzles/help/sixteen.c b/apps/plugins/puzzles/help/sixteen.c
index c3d52b6220..164be4ee4e 100644
--- a/apps/plugins/puzzles/help/sixteen.c
+++ b/apps/plugins/puzzles/help/sixteen.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,194 +6,195 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 113, TEXT_UNDERLINE }, 9 { 114, TEXT_UNDERLINE },
10 { 187, TEXT_CENTER | C_RED }, 10 { 188, TEXT_CENTER | C_RED },
11 { 321, TEXT_CENTER | C_RED }, 11 { 322, TEXT_CENTER | C_RED },
12 { 339, TEXT_UNDERLINE }, 12 { 340, TEXT_UNDERLINE },
13 { 341, TEXT_UNDERLINE }, 13 { 342, TEXT_UNDERLINE },
14 LAST_STYLE_ITEM 14 LAST_STYLE_ITEM
15}; 15};
16 16
17/* orig 2534 comp 1755 ratio 0.692581 level 6 saved 779 */ 17/* orig 2553 comp 1763 ratio 0.69056 level 6 saved 790 */
18const char help_text[] = { 18const char help_text[] = {
190xf0, 0x3b, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 190xfd, 0x06, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
200x36, 0x3a, 0x20, 0x53, 0x69, 0x78, 0x74, 0x65, 0x65, 0x6e, 200x36, 0x3a, 0x20, 0x53, 0x69, 0x78, 0x74, 0x65, 0x65, 0x6e,
210x20, 0x00, 0x00, 0x00, 0x41, 0x6e, 0x6f, 0x74, 0x68, 0x65, 210x20, 0x00, 0x2d, 0x01, 0x00, 0xf0, 0x28, 0x00, 0x00, 0x00,
220x72, 0x00, 0x73, 0x6c, 0x69, 0x64, 0x69, 0x6e, 0x67, 0x00, 220x41, 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x00, 0x73, 0x6c,
230x74, 0x69, 0x6c, 0x65, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 230x69, 0x64, 0x69, 0x6e, 0x67, 0x00, 0x74, 0x69, 0x6c, 0x65,
240x65, 0x2c, 0x00, 0x76, 0x69, 0x73, 0x75, 0x61, 0x6c, 0x6c, 240x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x2c, 0x00, 0x76,
250x79, 0x00, 0x73, 0x69, 0x6d, 0x69, 0x6c, 0x61, 0x72, 0x00, 250x69, 0x73, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x00, 0x73, 0x69,
260x74, 0x6f, 0x00, 0x46, 0x69, 0x66, 0x3c, 0x00, 0x72, 0x00, 260x6d, 0x69, 0x6c, 0x61, 0x72, 0x00, 0x74, 0x6f, 0x00, 0x46,
270x28, 0x73, 0x65, 0x65, 0x00, 0x63, 0x54, 0x00, 0xf0, 0x23, 270x69, 0x66, 0x4f, 0x00, 0x72, 0x00, 0x28, 0x73, 0x65, 0x65,
280x00, 0x35, 0x29, 0x00, 0x62, 0x75, 0x74, 0x00, 0x77, 0x69, 280x00, 0x63, 0x67, 0x00, 0xf0, 0x23, 0x00, 0x35, 0x29, 0x00,
290x74, 0x68, 0x00, 0x61, 0x00, 0x64, 0x69, 0x66, 0x66, 0x65, 290x62, 0x75, 0x74, 0x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x61,
300x72, 0x65, 0x6e, 0x74, 0x00, 0x74, 0x79, 0x70, 0x65, 0x00, 300x00, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74,
310x6f, 0x66, 0x00, 0x6d, 0x6f, 0x76, 0x65, 0x2e, 0x00, 0x54, 310x00, 0x74, 0x79, 0x70, 0x65, 0x00, 0x6f, 0x66, 0x00, 0x6d,
320x68, 0x69, 0x73, 0x00, 0x74, 0x69, 0x6d, 0x65, 0x2c, 0x00, 320x6f, 0x76, 0x65, 0x2e, 0x00, 0x54, 0x68, 0x69, 0x73, 0x00,
330x74, 0x00, 0xf0, 0x10, 0x65, 0x00, 0x69, 0x73, 0x00, 0x6e, 330x74, 0x69, 0x6d, 0x65, 0x2c, 0x00, 0x74, 0x00, 0xf0, 0x10,
340x6f, 0x00, 0x68, 0x6f, 0x6c, 0x65, 0x3a, 0x00, 0x61, 0x6c, 340x65, 0x00, 0x69, 0x73, 0x00, 0x6e, 0x6f, 0x00, 0x68, 0x6f,
350x6c, 0x00, 0x31, 0x36, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 350x6c, 0x65, 0x3a, 0x00, 0x61, 0x6c, 0x6c, 0x00, 0x31, 0x36,
360x65, 0x73, 0x00, 0x6f, 0x6e, 0x24, 0x00, 0xf4, 0x07, 0x00, 360x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x00, 0x6f,
370x67, 0x72, 0x69, 0x64, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 370x6e, 0x24, 0x00, 0xf4, 0x07, 0x00, 0x67, 0x72, 0x69, 0x64,
380x69, 0x6e, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x65, 380x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x00, 0x6e,
390x64, 0x25, 0x00, 0x61, 0x2e, 0x00, 0x59, 0x6f, 0x75, 0x72, 390x75, 0x6d, 0x62, 0x65, 0x72, 0x65, 0x64, 0x25, 0x00, 0x61,
400x5d, 0x00, 0x00, 0x4b, 0x00, 0xf0, 0x16, 0x74, 0x6f, 0x00, 400x2e, 0x00, 0x59, 0x6f, 0x75, 0x72, 0x5d, 0x00, 0x00, 0x4b,
410x73, 0x68, 0x69, 0x66, 0x74, 0x00, 0x61, 0x6e, 0x00, 0x65, 410x00, 0xf0, 0x16, 0x74, 0x6f, 0x00, 0x73, 0x68, 0x69, 0x66,
420x6e, 0x74, 0x69, 0x72, 0x65, 0x00, 0x72, 0x6f, 0x77, 0x00, 420x74, 0x00, 0x61, 0x6e, 0x00, 0x65, 0x6e, 0x74, 0x69, 0x72,
430x6c, 0x65, 0x66, 0x74, 0x00, 0x6f, 0x72, 0x00, 0x72, 0x69, 430x65, 0x00, 0x72, 0x6f, 0x77, 0x00, 0x6c, 0x65, 0x66, 0x74,
440x67, 0x68, 0x74, 0x2c, 0x0a, 0x00, 0x0c, 0x26, 0x00, 0x90, 440x00, 0x6f, 0x72, 0x00, 0x72, 0x69, 0x67, 0x68, 0x74, 0x2c,
450x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x00, 0x75, 0x70, 0x1d, 450x0a, 0x00, 0x0c, 0x26, 0x00, 0x90, 0x63, 0x6f, 0x6c, 0x75,
460x00, 0xb1, 0x64, 0x6f, 0x77, 0x6e, 0x3b, 0x00, 0x65, 0x76, 460x6d, 0x6e, 0x00, 0x75, 0x70, 0x1d, 0x00, 0xb1, 0x64, 0x6f,
470x65, 0x72, 0x79, 0xac, 0x00, 0xc1, 0x00, 0x79, 0x6f, 0x75, 470x77, 0x6e, 0x3b, 0x00, 0x65, 0x76, 0x65, 0x72, 0x79, 0xac,
480x00, 0x64, 0x6f, 0x00, 0x74, 0x68, 0x61, 0x74, 0xb8, 0x00, 480x00, 0xc1, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x64, 0x6f, 0x00,
490x02, 0x23, 0x01, 0x00, 0x16, 0x00, 0x02, 0x48, 0x00, 0x36, 490x74, 0x68, 0x61, 0x74, 0xb8, 0x00, 0x02, 0x23, 0x01, 0x00,
500x6f, 0x66, 0x66, 0xab, 0x00, 0xd1, 0x72, 0x65, 0x2d, 0x61, 500x16, 0x00, 0x02, 0x48, 0x00, 0x36, 0x6f, 0x66, 0x66, 0xab,
510x70, 0x70, 0x65, 0x61, 0x72, 0x73, 0x00, 0x61, 0x74, 0x17, 510x00, 0xd1, 0x72, 0x65, 0x2d, 0x61, 0x70, 0x70, 0x65, 0x61,
520x00, 0x02, 0x5f, 0x01, 0x52, 0x65, 0x6e, 0x64, 0x00, 0x6f, 520x72, 0x73, 0x00, 0x61, 0x74, 0x17, 0x00, 0x02, 0x5f, 0x01,
530x28, 0x00, 0x31, 0x73, 0x61, 0x6d, 0x99, 0x00, 0x32, 0x2c, 530x52, 0x65, 0x6e, 0x64, 0x00, 0x6f, 0x28, 0x00, 0x31, 0x73,
540x00, 0x69, 0xe4, 0x00, 0x42, 0x73, 0x70, 0x61, 0x63, 0x51, 540x61, 0x6d, 0x99, 0x00, 0x32, 0x2c, 0x00, 0x69, 0xe4, 0x00,
550x00, 0xf5, 0x0e, 0x6a, 0x75, 0x73, 0x74, 0x00, 0x76, 0x61, 550x42, 0x73, 0x70, 0x61, 0x63, 0x51, 0x00, 0xf5, 0x0e, 0x6a,
560x63, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x00, 0x54, 0x6f, 0x00, 560x75, 0x73, 0x74, 0x00, 0x76, 0x61, 0x63, 0x61, 0x74, 0x65,
570x77, 0x69, 0x6e, 0x2c, 0x00, 0x61, 0x72, 0x72, 0x61, 0x6e, 570x64, 0x2e, 0x00, 0x54, 0x6f, 0x00, 0x77, 0x69, 0x6e, 0x2c,
580x67, 0x65, 0x7c, 0x00, 0x60, 0x73, 0x00, 0x69, 0x6e, 0x74, 580x00, 0x61, 0x72, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x7c, 0x00,
590x6f, 0x0e, 0x01, 0xf4, 0x06, 0x65, 0x72, 0x69, 0x63, 0x61, 590x60, 0x73, 0x00, 0x69, 0x6e, 0x74, 0x6f, 0x0e, 0x01, 0xf4,
600x6c, 0x00, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x00, 0x28, 0x31, 600x06, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x00, 0x6f, 0x72,
610x2c, 0x32, 0x2c, 0x33, 0x2c, 0x34, 0x3b, 0x01, 0x32, 0x74, 610x64, 0x65, 0x72, 0x00, 0x28, 0x31, 0x2c, 0x32, 0x2c, 0x33,
620x6f, 0x70, 0x67, 0x00, 0xb4, 0x31, 0x33, 0x2c, 0x31, 0x34, 620x2c, 0x34, 0x3b, 0x01, 0x32, 0x74, 0x6f, 0x70, 0x67, 0x00,
630x2c, 0x31, 0x35, 0x2c, 0x31, 0x36, 0x1c, 0x00, 0xd0, 0x62, 630xb4, 0x31, 0x33, 0x2c, 0x31, 0x34, 0x2c, 0x31, 0x35, 0x2c,
640x6f, 0x74, 0x74, 0x6f, 0x6d, 0x29, 0x2e, 0x00, 0x57, 0x68, 640x31, 0x36, 0x1c, 0x00, 0xd0, 0x62, 0x6f, 0x74, 0x74, 0x6f,
650x65, 0x6e, 0x7b, 0x00, 0x84, 0x27, 0x76, 0x65, 0x00, 0x64, 650x6d, 0x29, 0x2e, 0x00, 0x57, 0x68, 0x65, 0x6e, 0x7b, 0x00,
660x6f, 0x6e, 0x65, 0xe7, 0x00, 0x70, 0x72, 0x79, 0x00, 0x70, 660x84, 0x27, 0x76, 0x65, 0x00, 0x64, 0x6f, 0x6e, 0x65, 0xe7,
670x6c, 0x61, 0x79, 0x12, 0x02, 0x27, 0x6f, 0x6e, 0xd1, 0x01, 670x00, 0x70, 0x72, 0x79, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x12,
680x30, 0x73, 0x69, 0x7a, 0x9d, 0x01, 0x11, 0x66, 0xee, 0x00, 680x02, 0x27, 0x6f, 0x6e, 0xd1, 0x01, 0x30, 0x73, 0x69, 0x7a,
690x70, 0x2e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x6d, 0x58, 0x01, 690x9d, 0x01, 0x11, 0x66, 0xee, 0x00, 0x70, 0x2e, 0x00, 0x00,
700x30, 0x00, 0x68, 0x61, 0x85, 0x01, 0x90, 0x6e, 0x76, 0x65, 700x00, 0x49, 0x00, 0x6d, 0x58, 0x01, 0x30, 0x00, 0x68, 0x61,
710x6e, 0x74, 0x65, 0x64, 0x00, 0x74, 0xea, 0x01, 0x10, 0x67, 710x85, 0x01, 0x90, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x65, 0x64,
720xe9, 0x00, 0x60, 0x6d, 0x79, 0x73, 0x65, 0x6c, 0x66, 0x39, 720x00, 0x74, 0xea, 0x01, 0x10, 0x67, 0xe9, 0x00, 0x60, 0x6d,
730x01, 0xf0, 0x03, 0x6f, 0x75, 0x67, 0x68, 0x00, 0x6f, 0x6e, 730x79, 0x73, 0x65, 0x6c, 0x66, 0x39, 0x01, 0xf0, 0x03, 0x6f,
740x6c, 0x79, 0x00, 0x62, 0x79, 0x00, 0x61, 0x63, 0x63, 0x69, 740x75, 0x67, 0x68, 0x00, 0x6f, 0x6e, 0x6c, 0x79, 0x00, 0x62,
750x64, 0x51, 0x00, 0xf4, 0x03, 0x69, 0x66, 0x00, 0x73, 0x6f, 750x79, 0x00, 0x61, 0x63, 0x63, 0x69, 0x64, 0x51, 0x00, 0xf4,
760x00, 0x28, 0x61, 0x6e, 0x64, 0x00, 0x49, 0x27, 0x6d, 0x00, 760x03, 0x69, 0x66, 0x00, 0x73, 0x6f, 0x00, 0x28, 0x61, 0x6e,
770x73, 0x75, 0x72, 0x33, 0x01, 0x64, 0x70, 0x65, 0x6f, 0x70, 770x64, 0x00, 0x49, 0x27, 0x6d, 0x00, 0x73, 0x75, 0x72, 0x33,
780x6c, 0x65, 0x59, 0x00, 0x50, 0x64, 0x65, 0x70, 0x65, 0x6e, 780x01, 0x64, 0x70, 0x65, 0x6f, 0x70, 0x6c, 0x65, 0x59, 0x00,
790x32, 0x00, 0x26, 0x6c, 0x79, 0x67, 0x00, 0x63, 0x69, 0x74, 790x50, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x32, 0x00, 0x26, 0x6c,
800x29, 0x2e, 0x00, 0x49, 0x5c, 0x00, 0xe0, 0x74, 0x00, 0x49, 800x79, 0x67, 0x00, 0x63, 0x69, 0x74, 0x29, 0x2e, 0x00, 0x49,
810x00, 0x77, 0x61, 0x73, 0x00, 0x69, 0x6d, 0x69, 0x74, 0x61, 810x5c, 0x00, 0xe0, 0x74, 0x00, 0x49, 0x00, 0x77, 0x61, 0x73,
820x74, 0xba, 0x00, 0xf1, 0x08, 0x61, 0x00, 0x73, 0x63, 0x72, 820x00, 0x69, 0x6d, 0x69, 0x74, 0x61, 0x74, 0xba, 0x00, 0xf1,
830x65, 0x65, 0x6e, 0x73, 0x61, 0x76, 0x65, 0x72, 0x00, 0x49, 830x08, 0x61, 0x00, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73,
840x27, 0x64, 0x00, 0x73, 0x65, 0x65, 0x6e, 0x2c, 0xab, 0x02, 840x61, 0x76, 0x65, 0x72, 0x00, 0x49, 0x27, 0x64, 0x00, 0x73,
850x12, 0x49, 0x59, 0x00, 0x61, 0x61, 0x00, 0x66, 0x65, 0x65, 850x65, 0x65, 0x6e, 0x2c, 0xab, 0x02, 0x12, 0x49, 0x59, 0x00,
860x6c, 0xf9, 0x02, 0x13, 0x68, 0xb1, 0x01, 0x08, 0x34, 0x00, 860x61, 0x61, 0x00, 0x66, 0x65, 0x65, 0x6c, 0xf9, 0x02, 0x13,
870x02, 0xdc, 0x00, 0x32, 0x61, 0x63, 0x74, 0x07, 0x03, 0x01, 870x68, 0xb1, 0x01, 0x08, 0x34, 0x00, 0x02, 0xdc, 0x00, 0x32,
880x33, 0x00, 0x10, 0x62, 0xfe, 0x02, 0x14, 0x61, 0x08, 0x03, 880x61, 0x63, 0x74, 0x07, 0x03, 0x01, 0x33, 0x00, 0x10, 0x62,
890x11, 0x2d, 0xe3, 0x02, 0x02, 0x31, 0x03, 0x31, 0x00, 0x72, 890xfe, 0x02, 0x14, 0x61, 0x08, 0x03, 0x11, 0x2d, 0xe3, 0x02,
900x61, 0xba, 0x00, 0x42, 0x74, 0x68, 0x61, 0x6e, 0x03, 0x01, 900x02, 0x31, 0x03, 0x31, 0x00, 0x72, 0x61, 0xba, 0x00, 0x42,
910x20, 0x73, 0x6c, 0x41, 0x00, 0x27, 0x6c, 0x79, 0x42, 0x01, 910x74, 0x68, 0x61, 0x6e, 0x03, 0x01, 0x20, 0x73, 0x6c, 0x41,
920x82, 0x6b, 0x69, 0x6e, 0x64, 0x2e, 0x00, 0x53, 0x6f, 0x21, 920x00, 0x27, 0x6c, 0x79, 0x42, 0x01, 0x82, 0x6b, 0x69, 0x6e,
930x00, 0x02, 0x61, 0x00, 0x12, 0x62, 0xdd, 0x01, 0x02, 0x80, 930x64, 0x2e, 0x00, 0x53, 0x6f, 0x21, 0x00, 0x02, 0x61, 0x00,
940x01, 0x00, 0x8d, 0x00, 0x54, 0x69, 0x6e, 0x00, 0x6d, 0x79, 940x12, 0x62, 0xdd, 0x01, 0x02, 0x80, 0x01, 0x00, 0x8d, 0x00,
950x56, 0x00, 0xf2, 0x19, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 950x54, 0x69, 0x6e, 0x00, 0x6d, 0x79, 0x56, 0x00, 0xf2, 0x19,
960x74, 0x69, 0x6f, 0x6e, 0x00, 0x77, 0x68, 0x69, 0x63, 0x68, 960x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
970x00, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 970x00, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x72, 0x65, 0x70,
980x73, 0x00, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x76, 0x69, 980x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x73, 0x00, 0x63, 0x72,
990x74, 0x79, 0x00, 0x6f, 0x34, 0x00, 0x39, 0x61, 0x72, 0x74, 990x65, 0x61, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x00, 0x6f,
1000x88, 0x00, 0x01, 0x54, 0x02, 0xb0, 0x65, 0x6e, 0x67, 0x69, 1000x34, 0x00, 0x39, 0x61, 0x72, 0x74, 0x88, 0x00, 0x01, 0x54,
1010x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0xb5, 0x01, 0x35, 1010x02, 0xb0, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72,
1020x36, 0x2e, 0x31, 0x04, 0x04, 0x00, 0x5d, 0x03, 0x40, 0x72, 1020x69, 0x6e, 0x67, 0xb5, 0x01, 0x35, 0x36, 0x2e, 0x31, 0x17,
1030x6f, 0x6c, 0x73, 0x0d, 0x04, 0xa3, 0x4c, 0x65, 0x66, 0x74, 1030x04, 0x00, 0x5d, 0x03, 0xf3, 0x03, 0x72, 0x6f, 0x6c, 0x73,
1040x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0xf9, 0x01, 0x20, 0x61, 1040x20, 0x00, 0x00, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63,
1050x6e, 0x7e, 0x02, 0x72, 0x6f, 0x77, 0x00, 0x77, 0x69, 0x6c, 1050x6c, 0x69, 0x63, 0x6b, 0xf9, 0x01, 0x20, 0x61, 0x6e, 0x7e,
1060x6c, 0x69, 0x03, 0x00, 0xa9, 0x00, 0xa2, 0x61, 0x70, 0x70, 1060x02, 0x72, 0x6f, 0x77, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0x69,
1070x72, 0x6f, 0x70, 0x72, 0x69, 0x61, 0x74, 0x63, 0x03, 0x24, 1070x03, 0x00, 0xa9, 0x00, 0xa2, 0x61, 0x70, 0x70, 0x72, 0x6f,
1080x6f, 0x72, 0x44, 0x03, 0x03, 0xd3, 0x02, 0x33, 0x64, 0x69, 1080x70, 0x72, 0x69, 0x61, 0x74, 0x63, 0x03, 0x24, 0x6f, 0x72,
1090x72, 0xb2, 0x00, 0x43, 0x69, 0x6e, 0x64, 0x69, 0xd0, 0x02, 1090x44, 0x03, 0x03, 0xd3, 0x02, 0x33, 0x64, 0x69, 0x72, 0xb2,
1100x10, 0x52, 0xec, 0x00, 0x06, 0x5f, 0x00, 0x06, 0x53, 0x00, 1100x00, 0x43, 0x69, 0x6e, 0x64, 0x69, 0xd0, 0x02, 0x10, 0x52,
1110x24, 0x69, 0x74, 0x38, 0x00, 0x77, 0x6f, 0x70, 0x70, 0x6f, 1110xec, 0x00, 0x06, 0x5f, 0x00, 0x06, 0x53, 0x00, 0x24, 0x69,
1120x73, 0x69, 0x74, 0x41, 0x00, 0x00, 0xaf, 0x00, 0x60, 0x41, 1120x74, 0x38, 0x00, 0x77, 0x6f, 0x70, 0x70, 0x6f, 0x73, 0x69,
1130x6c, 0x74, 0x65, 0x72, 0x6e, 0xe8, 0x00, 0x72, 0x65, 0x6c, 1130x74, 0x41, 0x00, 0x00, 0xaf, 0x00, 0x60, 0x41, 0x6c, 0x74,
1140x79, 0x2c, 0x00, 0x75, 0x73, 0x86, 0x00, 0xa1, 0x63, 0x75, 1140x65, 0x72, 0x6e, 0xe8, 0x00, 0x72, 0x65, 0x6c, 0x79, 0x2c,
1150x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0xfc, 0x03, 1150x00, 0x75, 0x73, 0x86, 0x00, 0xa1, 0x63, 0x75, 0x72, 0x73,
1160x05, 0x9e, 0x00, 0x01, 0x43, 0x00, 0x07, 0x7c, 0x00, 0x91, 1160x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0xfc, 0x03, 0x05, 0x9e,
1170x6f, 0x72, 0x00, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x1e, 1170x00, 0x01, 0x43, 0x00, 0x07, 0x7c, 0x00, 0x91, 0x6f, 0x72,
1180x00, 0x31, 0x65, 0x64, 0x67, 0x93, 0x04, 0x04, 0xb3, 0x03, 1180x00, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x1e, 0x00, 0x31,
1190x20, 0x2c, 0x00, 0x7c, 0x02, 0x04, 0x54, 0x00, 0x60, 0x72, 1190x65, 0x64, 0x67, 0x93, 0x04, 0x04, 0xb3, 0x03, 0x20, 0x2c,
1200x65, 0x74, 0x75, 0x72, 0x6e, 0x54, 0x00, 0x09, 0x53, 0x00, 1200x00, 0x7c, 0x02, 0x04, 0x54, 0x00, 0x60, 0x72, 0x65, 0x74,
1210x4f, 0x72, 0x6f, 0x77, 0x2f, 0xe2, 0x00, 0x10, 0x10, 0x00, 1210x75, 0x72, 0x6e, 0x54, 0x00, 0x09, 0x53, 0x00, 0x4f, 0x72,
1220x91, 0x04, 0x20, 0x00, 0x63, 0x36, 0x01, 0x27, 0x6c, 0x73, 1220x6f, 0x77, 0x2f, 0xe2, 0x00, 0x10, 0x10, 0x00, 0x91, 0x04,
1230x3f, 0x00, 0x02, 0xb6, 0x03, 0x02, 0x33, 0x00, 0x79, 0x6c, 1230x20, 0x00, 0x63, 0x36, 0x01, 0x27, 0x6c, 0x73, 0x3f, 0x00,
1240x79, 0x2e, 0x00, 0x4d, 0x6f, 0x76, 0xc3, 0x00, 0x10, 0x6f, 1240x02, 0xb6, 0x03, 0x02, 0x33, 0x00, 0x79, 0x6c, 0x79, 0x2e,
1250xd0, 0x03, 0x11, 0x61, 0x27, 0x00, 0x10, 0x2c, 0x0f, 0x05, 1250x00, 0x4d, 0x6f, 0x76, 0xc3, 0x00, 0x10, 0x6f, 0xd0, 0x03,
1260x32, 0x64, 0x00, 0x43, 0x96, 0x01, 0x01, 0x9c, 0x00, 0x00, 1260x11, 0x61, 0x27, 0x00, 0x10, 0x2c, 0x0f, 0x05, 0x32, 0x64,
1270xed, 0x01, 0x16, 0x73, 0x8b, 0x01, 0x0c, 0x9c, 0x00, 0x01, 1270x00, 0x43, 0x96, 0x01, 0x01, 0x9c, 0x00, 0x00, 0xed, 0x01,
1280x8f, 0x04, 0x20, 0x75, 0x6e, 0x03, 0x04, 0x07, 0x53, 0x00, 1280x16, 0x73, 0x8b, 0x01, 0x0c, 0x9c, 0x00, 0x01, 0x8f, 0x04,
1290x00, 0x39, 0x00, 0x1b, 0x6d, 0x67, 0x00, 0x52, 0x61, 0x6c, 1290x20, 0x75, 0x6e, 0x03, 0x04, 0x07, 0x53, 0x00, 0x00, 0x39,
1300x6f, 0x6e, 0x67, 0xa5, 0x05, 0x04, 0x39, 0x00, 0x43, 0x2e, 1300x00, 0x1b, 0x6d, 0x67, 0x00, 0x52, 0x61, 0x6c, 0x6f, 0x6e,
1310x00, 0x4f, 0x72, 0x73, 0x00, 0x11, 0x53, 0xce, 0x04, 0x04, 1310x67, 0xa5, 0x05, 0x04, 0x39, 0x00, 0x43, 0x2e, 0x00, 0x4f,
1320x5a, 0x00, 0x01, 0xa9, 0x03, 0x06, 0x26, 0x00, 0x10, 0x50, 1320x72, 0x73, 0x00, 0x11, 0x53, 0xce, 0x04, 0x04, 0x5a, 0x00,
1330x84, 0x00, 0x00, 0xb6, 0x01, 0x20, 0x45, 0x6e, 0xf0, 0x05, 1330x01, 0xa9, 0x03, 0x06, 0x26, 0x00, 0x10, 0x50, 0x84, 0x00,
1340x91, 0x73, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x73, 1340x00, 0xb6, 0x01, 0x20, 0x45, 0x6e, 0xf0, 0x05, 0x91, 0x73,
1350x3b, 0x00, 0x00, 0x18, 0x00, 0x00, 0x37, 0x05, 0x05, 0xb6, 1350x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x3b, 0x00,
1360x00, 0x12, 0x28, 0xb3, 0x00, 0x02, 0x2c, 0x00, 0x20, 0x61, 1360x00, 0x18, 0x00, 0x00, 0x37, 0x05, 0x05, 0xb6, 0x00, 0x12,
1370x67, 0xbc, 0x05, 0xc0, 0x74, 0x6f, 0x00, 0x72, 0x65, 0x6c, 1370x28, 0xb3, 0x00, 0x02, 0x2c, 0x00, 0x20, 0x61, 0x67, 0xbc,
1380x65, 0x61, 0x73, 0x65, 0x29, 0x2c, 0xc7, 0x02, 0x00, 0x66, 1380x05, 0xc0, 0x74, 0x6f, 0x00, 0x72, 0x65, 0x6c, 0x65, 0x61,
1390x06, 0x04, 0x54, 0x00, 0x11, 0x53, 0x01, 0x05, 0x0f, 0x54, 1390x73, 0x65, 0x29, 0x2c, 0xc7, 0x02, 0x00, 0x66, 0x06, 0x04,
1400x00, 0x04, 0x01, 0x65, 0x05, 0x00, 0x5b, 0x01, 0x42, 0x28, 1400x54, 0x00, 0x11, 0x53, 0x01, 0x05, 0x0f, 0x54, 0x00, 0x04,
1410x41, 0x6c, 0x6c, 0x7e, 0x02, 0x01, 0x78, 0x01, 0x90, 0x73, 1410x01, 0x65, 0x05, 0x00, 0x5b, 0x01, 0x42, 0x28, 0x41, 0x6c,
1420x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x08, 0x04, 1420x6c, 0x7e, 0x02, 0x01, 0x78, 0x01, 0x90, 0x73, 0x00, 0x64,
1430x33, 0x6e, 0x00, 0x73, 0x8e, 0x01, 0x72, 0x32, 0x2e, 0x31, 1430x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x08, 0x04, 0x33, 0x6e,
1440x00, 0x61, 0x72, 0x65, 0x81, 0x01, 0xb1, 0x61, 0x76, 0x61, 1440x00, 0x73, 0x8e, 0x01, 0x72, 0x32, 0x2e, 0x31, 0x00, 0x61,
1450x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0xf6, 0x02, 1450x72, 0x65, 0x81, 0x01, 0xb1, 0x61, 0x76, 0x61, 0x69, 0x6c,
1460x15, 0x32, 0xf6, 0x02, 0x91, 0x70, 0x61, 0x72, 0x61, 0x6d, 1460x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0xf6, 0x02, 0x15, 0x32,
1470x65, 0x74, 0x65, 0x72, 0xf8, 0x02, 0x10, 0x54, 0x36, 0x02, 1470xf6, 0x02, 0x91, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74,
1480x05, 0x12, 0x00, 0x06, 0x37, 0x00, 0x51, 0x00, 0x66, 0x72, 1480x65, 0x72, 0xf8, 0x02, 0x10, 0x54, 0x36, 0x02, 0x05, 0x12,
1490x6f, 0x6d, 0x74, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 1490x00, 0x06, 0x37, 0x00, 0x51, 0x00, 0x66, 0x72, 0x6f, 0x6d,
1500x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x6a, 1500x74, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d,
1510x00, 0x03, 0x4b, 0x05, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 1510x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x6a, 0x00, 0x03,
1520x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0x79, 0x00, 0xb1, 0x3a, 1520x4b, 0x05, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00,
1530x00, 0x00, 0x00, 0x2d, 0x00, 0x57, 0x69, 0x64, 0x74, 0x68, 1530x6d, 0x65, 0x6e, 0x75, 0x79, 0x00, 0xb1, 0x3a, 0x00, 0x00,
1540x84, 0x01, 0x22, 0x48, 0x65, 0x77, 0x06, 0x02, 0xba, 0x03, 1540x00, 0x2d, 0x00, 0x57, 0x69, 0x64, 0x74, 0x68, 0x84, 0x01,
1550x00, 0x9a, 0x00, 0x00, 0x10, 0x05, 0x70, 0x2d, 0x65, 0x78, 1550x22, 0x48, 0x65, 0x77, 0x06, 0x02, 0xba, 0x03, 0x00, 0x9a,
1560x70, 0x6c, 0x61, 0x6e, 0x9c, 0x02, 0x21, 0x79, 0x2e, 0x32, 1560x00, 0x00, 0x10, 0x05, 0x70, 0x2d, 0x65, 0x78, 0x70, 0x6c,
1570x00, 0x05, 0x39, 0x02, 0x40, 0x73, 0x6b, 0x00, 0x66, 0xac, 1570x61, 0x6e, 0x9c, 0x02, 0x21, 0x79, 0x2e, 0x32, 0x00, 0x05,
1580x01, 0x20, 0x00, 0x6c, 0xc9, 0x04, 0x00, 0xed, 0x06, 0x41, 1580x39, 0x02, 0x40, 0x73, 0x6b, 0x00, 0x66, 0xac, 0x01, 0x20,
1590x68, 0x75, 0x66, 0x66, 0xa3, 0x04, 0x51, 0x6f, 0x70, 0x65, 1590x00, 0x6c, 0xc9, 0x04, 0x00, 0xed, 0x06, 0x41, 0x68, 0x75,
1600x72, 0x61, 0x7c, 0x00, 0x20, 0x74, 0x6f, 0x34, 0x04, 0x98, 1600x66, 0x66, 0xa3, 0x04, 0x51, 0x6f, 0x70, 0x65, 0x72, 0x61,
1610x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x64, 0x2e, 1610x7c, 0x00, 0x20, 0x74, 0x6f, 0x34, 0x04, 0x98, 0x70, 0x65,
1620x07, 0xe3, 0x2e, 0x00, 0x42, 0x79, 0x00, 0x64, 0x65, 0x66, 1620x72, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x64, 0x2e, 0x07, 0xe3,
1630x61, 0x75, 0x6c, 0x74, 0x2c, 0x00, 0xf0, 0x00, 0x02, 0x6d, 1630x2e, 0x00, 0x42, 0x79, 0x00, 0x64, 0x65, 0x66, 0x61, 0x75,
1640x03, 0x02, 0x4a, 0x00, 0x16, 0x65, 0xae, 0x06, 0x00, 0x38, 1640x6c, 0x74, 0x2c, 0x00, 0xf0, 0x00, 0x02, 0x6d, 0x03, 0x02,
1650x01, 0x10, 0x75, 0x97, 0x00, 0x42, 0x00, 0x77, 0x61, 0x79, 1650x4a, 0x00, 0x16, 0x65, 0xae, 0x06, 0x00, 0x38, 0x01, 0x10,
1660x02, 0x05, 0x34, 0x61, 0x6e, 0x79, 0x71, 0x06, 0x11, 0x6d, 1660x75, 0x97, 0x00, 0x42, 0x00, 0x77, 0x61, 0x79, 0x02, 0x05,
1670xa0, 0x05, 0xf1, 0x00, 0x73, 0x00, 0x61, 0x62, 0x6f, 0x75, 1670x34, 0x61, 0x6e, 0x79, 0x71, 0x06, 0x11, 0x6d, 0xa0, 0x05,
1680x74, 0x00, 0x61, 0x73, 0x00, 0x70, 0x72, 0x6f, 0x62, 0x17, 1680xf1, 0x00, 0x73, 0x00, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x00,
1690x01, 0x21, 0x61, 0x73, 0x28, 0x00, 0x01, 0xa8, 0x05, 0x15, 1690x61, 0x73, 0x00, 0x70, 0x72, 0x6f, 0x62, 0x17, 0x01, 0x21,
1700x2e, 0xbb, 0x00, 0x82, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 1700x61, 0x73, 0x28, 0x00, 0x01, 0xa8, 0x05, 0x15, 0x2e, 0xbb,
1710x64, 0x65, 0xda, 0x04, 0x93, 0x62, 0x79, 0x00, 0x72, 0x65, 1710x00, 0x82, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
1720x71, 0x75, 0x65, 0x73, 0x8b, 0x05, 0x73, 0x70, 0x72, 0x65, 1720xda, 0x04, 0x93, 0x62, 0x79, 0x00, 0x72, 0x65, 0x71, 0x75,
1730x63, 0x69, 0x73, 0x65, 0xc5, 0x07, 0x00, 0x82, 0x03, 0x06, 1730x65, 0x73, 0x8b, 0x05, 0x73, 0x70, 0x72, 0x65, 0x63, 0x69,
1740xd9, 0x00, 0x00, 0x72, 0x02, 0x1c, 0x73, 0xd5, 0x00, 0x71, 1740x73, 0x65, 0xc5, 0x07, 0x00, 0x82, 0x03, 0x06, 0xd9, 0x00,
1750x2e, 0x00, 0x54, 0x79, 0x70, 0x69, 0x63, 0x79, 0x05, 0x10, 1750x00, 0x72, 0x02, 0x1c, 0x73, 0xd5, 0x00, 0x71, 0x2e, 0x00,
1760x79, 0xe8, 0x07, 0x31, 0x61, 0x69, 0x6d, 0xe7, 0x07, 0x21, 1760x54, 0x79, 0x70, 0x69, 0x63, 0x79, 0x05, 0x10, 0x79, 0xe8,
1770x68, 0x65, 0x01, 0x01, 0x10, 0x64, 0xad, 0x01, 0x33, 0x6d, 1770x07, 0x31, 0x61, 0x69, 0x6d, 0xe7, 0x07, 0x21, 0x68, 0x65,
1780x69, 0x6e, 0xf5, 0x03, 0x03, 0x5f, 0x00, 0x3f, 0x73, 0x65, 1780x01, 0x01, 0x10, 0x64, 0xad, 0x01, 0x33, 0x6d, 0x69, 0x6e,
1790x74, 0x5c, 0x00, 0x01, 0x00, 0x8b, 0x01, 0x00, 0x37, 0x06, 1790xf5, 0x03, 0x03, 0x5f, 0x00, 0x3f, 0x73, 0x65, 0x74, 0x5c,
1800x11, 0x72, 0xe4, 0x05, 0x50, 0x6d, 0x00, 0x65, 0x78, 0x61, 1800x00, 0x01, 0x00, 0x8b, 0x01, 0x00, 0x37, 0x06, 0x11, 0x72,
1810x8b, 0x03, 0x32, 0x2c, 0x00, 0x73, 0xda, 0x07, 0x01, 0x7f, 1810xe4, 0x05, 0x50, 0x6d, 0x00, 0x65, 0x78, 0x61, 0x8b, 0x03,
1820x07, 0x40, 0x61, 0x6e, 0x73, 0x77, 0x49, 0x07, 0x40, 0x73, 1820x32, 0x2c, 0x00, 0x73, 0xda, 0x07, 0x01, 0x7f, 0x07, 0x40,
1830x61, 0x79, 0x29, 0x1a, 0x06, 0x41, 0x6f, 0x75, 0x72, 0x2d, 1830x61, 0x6e, 0x73, 0x77, 0x49, 0x07, 0x40, 0x73, 0x61, 0x79,
1840x0d, 0x03, 0x04, 0x39, 0x01, 0x03, 0xe0, 0x08, 0x07, 0x19, 1840x29, 0x1a, 0x06, 0x41, 0x6f, 0x75, 0x72, 0x2d, 0x0d, 0x03,
1850x00, 0x32, 0x6f, 0x6c, 0x75, 0xa6, 0x04, 0x46, 0x4e, 0x6f, 1850x04, 0x39, 0x01, 0x03, 0xe0, 0x08, 0x07, 0x19, 0x00, 0x32,
1860x74, 0x65, 0x44, 0x06, 0x43, 0x6d, 0x6f, 0x72, 0x65, 0x7a, 1860x6f, 0x6c, 0x75, 0xa6, 0x04, 0x46, 0x4e, 0x6f, 0x74, 0x65,
1870x00, 0x01, 0x59, 0x00, 0x02, 0xd5, 0x01, 0x16, 0x2c, 0x1c, 1870x44, 0x06, 0x43, 0x6d, 0x6f, 0x72, 0x65, 0x7a, 0x00, 0x01,
1880x00, 0x40, 0x6c, 0x69, 0x6b, 0x65, 0xca, 0x06, 0x12, 0x74, 1880x59, 0x00, 0x02, 0xd5, 0x01, 0x16, 0x2c, 0x1c, 0x00, 0x40,
1890xd2, 0x00, 0x25, 0x61, 0x74, 0x4b, 0x00, 0x76, 0x73, 0x00, 1890x6c, 0x69, 0x6b, 0x65, 0xca, 0x06, 0x12, 0x74, 0xd2, 0x00,
1900x73, 0x68, 0x6f, 0x72, 0x74, 0x47, 0x06, 0xf2, 0x00, 0x65, 1900x25, 0x61, 0x74, 0x4b, 0x00, 0x76, 0x73, 0x00, 0x73, 0x68,
1910x00, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0x6c, 0x65, 1910x6f, 0x72, 0x74, 0x47, 0x06, 0xf2, 0x00, 0x65, 0x00, 0x74,
1920x6e, 0x67, 0x74, 0x68, 0xcb, 0x01, 0x01, 0xa6, 0x04, 0x00, 1920x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0x6c, 0x65, 0x6e, 0x67,
1930x97, 0x01, 0x03, 0x35, 0x01, 0x90, 0x6f, 0x73, 0x73, 0x69, 1930x74, 0x68, 0xcb, 0x01, 0x01, 0xa6, 0x04, 0x00, 0x97, 0x01,
1940x62, 0x6c, 0x65, 0x2e, 0x00, 1940x03, 0x35, 0x01, 0x90, 0x6f, 0x73, 0x73, 0x69, 0x62, 0x6c,
1950x65, 0x2e, 0x00,
195}; 196};
196 197
197const unsigned short help_text_len = 2534; 198const unsigned short help_text_len = 2553;
198const unsigned short help_text_words = 453; 199const unsigned short help_text_words = 454;
199const char quick_help_text[] = "Slide a row at a time to arrange the tiles into order."; 200const char quick_help_text[] = "Slide a row at a time to arrange the tiles into order.";
diff --git a/apps/plugins/puzzles/help/slant.c b/apps/plugins/puzzles/help/slant.c
index ad4363825e..1a8168fb3b 100644
--- a/apps/plugins/puzzles/help/slant.c
+++ b/apps/plugins/puzzles/help/slant.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,184 +6,197 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 125, TEXT_CENTER | C_RED }, 9 { 126, TEXT_CENTER | C_RED },
10 { 328, TEXT_CENTER | C_RED }, 10 { 329, TEXT_CENTER | C_RED },
11 { 345, TEXT_UNDERLINE },
12 { 346, TEXT_UNDERLINE }, 11 { 346, TEXT_UNDERLINE },
13 { 356, TEXT_UNDERLINE }, 12 { 347, TEXT_UNDERLINE },
14 { 379, TEXT_UNDERLINE }, 13 { 357, TEXT_UNDERLINE },
14 { 380, TEXT_UNDERLINE },
15 { 447, TEXT_CENTER | C_RED },
15 LAST_STYLE_ITEM 16 LAST_STYLE_ITEM
16}; 17};
17 18
18/* orig 2378 comp 1650 ratio 0.69386 level 10 saved 728 */ 19/* orig 2582 comp 1767 ratio 0.684353 level 10 saved 815 */
19const char help_text[] = { 20const char help_text[] = {
200xf0, 0x21, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 210xfc, 0x05, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
210x32, 0x30, 0x3a, 0x20, 0x53, 0x6c, 0x61, 0x6e, 0x74, 0x20, 220x32, 0x30, 0x3a, 0x20, 0x53, 0x6c, 0x61, 0x6e, 0x74, 0x20,
220x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 230x00, 0x2d, 0x01, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x59,
230x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 240x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00,
240x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2e, 250x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71,
250x1c, 0x00, 0xf3, 0x1e, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 260x75, 0x61, 0x72, 0x65, 0x73, 0x2e, 0x1c, 0x00, 0xf3, 0x1e,
260x69, 0x73, 0x00, 0x74, 0x6f, 0x00, 0x64, 0x72, 0x61, 0x77, 270x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 0x69, 0x73, 0x00, 0x74,
270x00, 0x61, 0x00, 0x64, 0x69, 0x61, 0x67, 0x6f, 0x6e, 0x61, 280x6f, 0x00, 0x64, 0x72, 0x61, 0x77, 0x00, 0x61, 0x00, 0x64,
280x6c, 0x00, 0x6c, 0x69, 0x6e, 0x65, 0x00, 0x74, 0x68, 0x72, 290x69, 0x61, 0x67, 0x6f, 0x6e, 0x61, 0x6c, 0x00, 0x6c, 0x69,
290x6f, 0x75, 0x67, 0x68, 0x00, 0x65, 0x61, 0x63, 0x68, 0x3a, 300x6e, 0x65, 0x00, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68,
300x00, 0xf2, 0x07, 0x2c, 0x00, 0x61, 0x6e, 0x64, 0x00, 0x63, 310x00, 0x65, 0x61, 0x63, 0x68, 0x3a, 0x00, 0xf2, 0x07, 0x2c,
310x68, 0x6f, 0x6f, 0x73, 0x65, 0x00, 0x77, 0x68, 0x69, 0x63, 320x00, 0x61, 0x6e, 0x64, 0x00, 0x63, 0x68, 0x6f, 0x6f, 0x73,
320x68, 0x00, 0x77, 0x61, 0x79, 0x22, 0x00, 0x01, 0x34, 0x00, 330x65, 0x00, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x77, 0x61,
330x10, 0x73, 0x7d, 0x00, 0xfa, 0x24, 0x73, 0x00, 0x73, 0x6f, 340x79, 0x22, 0x00, 0x01, 0x34, 0x00, 0x10, 0x73, 0x8f, 0x00,
340x00, 0x74, 0x68, 0x61, 0x74, 0x00, 0x74, 0x68, 0x65, 0x00, 350xfa, 0x24, 0x73, 0x00, 0x73, 0x6f, 0x00, 0x74, 0x68, 0x61,
350x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x00, 360x74, 0x00, 0x74, 0x68, 0x65, 0x00, 0x66, 0x6f, 0x6c, 0x6c,
360x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 370x6f, 0x77, 0x69, 0x6e, 0x67, 0x00, 0x63, 0x6f, 0x6e, 0x64,
370x00, 0x61, 0x72, 0x65, 0x00, 0x6d, 0x65, 0x74, 0x3a, 0x00, 380x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x61, 0x72, 0x65,
380x00, 0x00, 0x2d, 0x00, 0x54, 0x68, 0x65, 0x7b, 0x00, 0xf1, 390x00, 0x6d, 0x65, 0x74, 0x3a, 0x00, 0x00, 0x00, 0x2d, 0x00,
390x05, 0x73, 0x00, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x00, 0x66, 400x54, 0x68, 0x65, 0x7b, 0x00, 0xf1, 0x05, 0x73, 0x00, 0x6e,
400x6f, 0x72, 0x6d, 0x00, 0x61, 0x00, 0x6c, 0x6f, 0x6f, 0x70, 410x65, 0x76, 0x65, 0x72, 0x00, 0x66, 0x6f, 0x72, 0x6d, 0x00,
410x2e, 0x2a, 0x00, 0xf2, 0x1e, 0x41, 0x6e, 0x79, 0x00, 0x70, 420x61, 0x00, 0x6c, 0x6f, 0x6f, 0x70, 0x2e, 0x2a, 0x00, 0xf2,
420x6f, 0x69, 0x6e, 0x74, 0x00, 0x77, 0x69, 0x74, 0x68, 0x00, 430x1e, 0x41, 0x6e, 0x79, 0x00, 0x70, 0x6f, 0x69, 0x6e, 0x74,
430x61, 0x00, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x64, 0x00, 440x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x61, 0x00, 0x63, 0x69,
440x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x00, 0x68, 0x61, 0x73, 450x72, 0x63, 0x6c, 0x65, 0x64, 0x00, 0x6e, 0x75, 0x6d, 0x62,
450x00, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x65, 0x6c, 0x79, 460x65, 0x72, 0x00, 0x68, 0x61, 0x73, 0x00, 0x70, 0x72, 0x65,
460x83, 0x00, 0x43, 0x6d, 0x61, 0x6e, 0x79, 0x55, 0x00, 0x40, 470x63, 0x69, 0x73, 0x65, 0x6c, 0x79, 0x83, 0x00, 0x43, 0x6d,
470x6d, 0x65, 0x65, 0x74, 0x88, 0x00, 0xf1, 0x02, 0x61, 0x74, 480x61, 0x6e, 0x79, 0x55, 0x00, 0x40, 0x6d, 0x65, 0x65, 0x74,
480x00, 0x69, 0x74, 0x2e, 0x00, 0x28, 0x54, 0x68, 0x75, 0x73, 490x88, 0x00, 0xf1, 0x02, 0x61, 0x74, 0x00, 0x69, 0x74, 0x2e,
490x2c, 0x00, 0x61, 0x00, 0x34, 0x06, 0x01, 0x90, 0x68, 0x65, 500x00, 0x28, 0x54, 0x68, 0x75, 0x73, 0x2c, 0x00, 0x61, 0x00,
500x00, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x65, 0x29, 0x01, 0xfe, 510x34, 0x06, 0x01, 0x90, 0x68, 0x65, 0x00, 0x63, 0x65, 0x6e,
510x0e, 0x61, 0x00, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x00, 0x73, 520x74, 0x72, 0x65, 0x29, 0x01, 0xfe, 0x0e, 0x61, 0x00, 0x63,
520x68, 0x61, 0x70, 0x65, 0x2c, 0x00, 0x77, 0x68, 0x65, 0x72, 530x72, 0x6f, 0x73, 0x73, 0x00, 0x73, 0x68, 0x61, 0x70, 0x65,
530x65, 0x61, 0x73, 0x00, 0x61, 0x00, 0x7a, 0x65, 0x72, 0x6f, 540x2c, 0x00, 0x77, 0x68, 0x65, 0x72, 0x65, 0x61, 0x73, 0x00,
540x2f, 0x00, 0x01, 0x3b, 0x01, 0x42, 0x6d, 0x6f, 0x6e, 0x64, 550x61, 0x00, 0x7a, 0x65, 0x72, 0x6f, 0x2f, 0x00, 0x01, 0x3b,
550x31, 0x00, 0xc0, 0x00, 0x2d, 0x00, 0x6f, 0x72, 0x00, 0x72, 560x01, 0x42, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x00, 0xc0, 0x00,
560x61, 0x74, 0x68, 0x65, 0x72, 0x61, 0x00, 0x7a, 0x70, 0x61, 570x2d, 0x00, 0x6f, 0x72, 0x00, 0x72, 0x61, 0x74, 0x68, 0x65,
570x72, 0x74, 0x69, 0x61, 0x6c, 0x25, 0x00, 0x94, 0x2c, 0x00, 580x72, 0x61, 0x00, 0x7a, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61,
580x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x56, 0x00, 0x33, 590x6c, 0x25, 0x00, 0x94, 0x2c, 0x00, 0x62, 0x65, 0x63, 0x61,
590x63, 0x61, 0x6e, 0xf8, 0x00, 0x91, 0x61, 0x70, 0x70, 0x65, 600x75, 0x73, 0x65, 0x56, 0x00, 0x33, 0x63, 0x61, 0x6e, 0xf8,
600x61, 0x72, 0x00, 0x69, 0x6e, 0x67, 0x00, 0x51, 0x6d, 0x69, 610x00, 0x91, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x00, 0x69,
610x64, 0x64, 0x6c, 0x67, 0x00, 0x00, 0x0e, 0x00, 0x01, 0xcb, 620x6e, 0x67, 0x00, 0x51, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x67,
620x01, 0x04, 0x3a, 0x00, 0x01, 0xe2, 0x00, 0xe0, 0x77, 0x6f, 630x00, 0x00, 0x0e, 0x00, 0x01, 0xcb, 0x01, 0x04, 0x3a, 0x00,
630x75, 0x6c, 0x64, 0x00, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 640x01, 0xe2, 0x00, 0xe0, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x00,
640x61, 0x74, 0xf9, 0x00, 0x04, 0x57, 0x00, 0x01, 0x39, 0x01, 650x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0xf9, 0x00,
650xa0, 0x29, 0x00, 0x00, 0x00, 0x43, 0x72, 0x65, 0x64, 0x69, 660x04, 0x57, 0x00, 0x01, 0x39, 0x01, 0xa0, 0x29, 0x00, 0x00,
660x74, 0x50, 0x01, 0xf1, 0x01, 0x00, 0x74, 0x68, 0x69, 0x73, 670x00, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x50, 0x01, 0xf1,
670x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x67, 0x6f, 680x01, 0x00, 0x74, 0x68, 0x69, 0x73, 0x00, 0x70, 0x75, 0x7a,
680x65, 0xff, 0x01, 0xa0, 0x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69, 690x7a, 0x6c, 0x65, 0x00, 0x67, 0x6f, 0x65, 0xff, 0x01, 0xa0,
690x00, 0x5b, 0x38, 0x5d, 0x67, 0x01, 0xf1, 0x01, 0x5b, 0x38, 700x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69, 0x00, 0x5b, 0x38, 0x5d,
700x5d, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 710x67, 0x01, 0xf1, 0x02, 0x5b, 0x38, 0x5d, 0x00, 0x68, 0x74,
710x77, 0x77, 0x2e, 0x6e, 0x1d, 0x00, 0xa2, 0x2e, 0x63, 0x6f, 720x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
720x2e, 0x6a, 0x70, 0x2f, 0x6a, 0x61, 0x2f, 0x3c, 0x00, 0xf0, 730x6e, 0x1e, 0x00, 0xa2, 0x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70,
730x0e, 0x73, 0x2f, 0x67, 0x6f, 0x6b, 0x69, 0x67, 0x65, 0x6e, 740x2f, 0x6a, 0x61, 0x2f, 0x3d, 0x00, 0xf0, 0x0f, 0x73, 0x2f,
740x5f, 0x6e, 0x61, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x28, 0x69, 750x67, 0x6f, 0x6b, 0x69, 0x67, 0x65, 0x6e, 0x5f, 0x6e, 0x61,
750x6e, 0x00, 0x4a, 0x61, 0x70, 0x61, 0x6e, 0x65, 0x73, 0x65, 760x6e, 0x61, 0x6d, 0x65, 0x2f, 0x00, 0x28, 0x69, 0x6e, 0x00,
760x73, 0x00, 0x43, 0x32, 0x30, 0x2e, 0x31, 0x8c, 0x02, 0x80, 770x4a, 0x61, 0x70, 0x61, 0x6e, 0x65, 0x73, 0x65, 0x75, 0x00,
770x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x95, 0x02, 780x43, 0x32, 0x30, 0x2e, 0x31, 0xa0, 0x02, 0xf0, 0x07, 0x63,
780xa0, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 790x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00,
790x6b, 0x8a, 0x01, 0xa3, 0x69, 0x6e, 0x00, 0x61, 0x00, 0x62, 800x00, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63,
800x6c, 0x61, 0x6e, 0x6b, 0x61, 0x02, 0xa0, 0x00, 0x77, 0x69, 810x6b, 0x8c, 0x01, 0xa3, 0x69, 0x6e, 0x00, 0x61, 0x00, 0x62,
810x6c, 0x6c, 0x00, 0x70, 0x6c, 0x61, 0x63, 0xc0, 0x00, 0x10, 820x6c, 0x61, 0x6e, 0x6b, 0x63, 0x02, 0xa0, 0x00, 0x77, 0x69,
820x5c, 0x21, 0x00, 0x52, 0x69, 0x74, 0x00, 0x28, 0x61, 0x5e, 830x6c, 0x6c, 0x00, 0x70, 0x6c, 0x61, 0x63, 0xc2, 0x00, 0x10,
840x5c, 0x21, 0x00, 0x52, 0x69, 0x74, 0x00, 0x28, 0x61, 0x60,
830x02, 0x40, 0x6c, 0x65, 0x61, 0x6e, 0x37, 0x00, 0x10, 0x74, 850x02, 0x40, 0x6c, 0x65, 0x61, 0x6e, 0x37, 0x00, 0x10, 0x74,
840x5f, 0x02, 0x00, 0x0f, 0x00, 0xc1, 0x66, 0x74, 0x2c, 0x00, 860x61, 0x02, 0x00, 0x0f, 0x00, 0xc1, 0x66, 0x74, 0x2c, 0x00,
850x69, 0x2e, 0x65, 0x2e, 0x00, 0x72, 0x75, 0x6e, 0x1a, 0x00, 870x69, 0x2e, 0x65, 0x2e, 0x00, 0x72, 0x75, 0x6e, 0x1a, 0x00,
860x41, 0x66, 0x72, 0x6f, 0x6d, 0x1c, 0x00, 0x31, 0x74, 0x6f, 880x41, 0x66, 0x72, 0x6f, 0x6d, 0x1c, 0x00, 0x31, 0x74, 0x6f,
870x70, 0x20, 0x00, 0x04, 0x37, 0x01, 0x03, 0x5f, 0x00, 0x03, 890x70, 0x20, 0x00, 0x04, 0x39, 0x01, 0x03, 0x5f, 0x00, 0x03,
880x3a, 0x00, 0xf0, 0x01, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 900x3a, 0x00, 0xf0, 0x01, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d,
890x00, 0x72, 0x69, 0x67, 0x68, 0x74, 0x29, 0x2e, 0x00, 0x52, 910x00, 0x72, 0x69, 0x67, 0x68, 0x74, 0x29, 0x2e, 0x00, 0x52,
900x08, 0x00, 0x0f, 0x96, 0x00, 0x16, 0x14, 0x2f, 0x96, 0x00, 920x08, 0x00, 0x0f, 0x96, 0x00, 0x16, 0x14, 0x2f, 0x96, 0x00,
910x0b, 0x8f, 0x00, 0x01, 0x4e, 0x00, 0x1b, 0x2c, 0x8b, 0x00, 930x0b, 0x8f, 0x00, 0x01, 0x4e, 0x00, 0x1b, 0x2c, 0x8b, 0x00,
920x22, 0x6f, 0x70, 0x18, 0x00, 0x00, 0x25, 0x00, 0x03, 0x76, 940x22, 0x6f, 0x70, 0x18, 0x00, 0x00, 0x25, 0x00, 0x03, 0x76,
930x00, 0x00, 0x97, 0x00, 0x20, 0x29, 0x2e, 0x96, 0x01, 0x63, 950x00, 0x00, 0x97, 0x00, 0x20, 0x29, 0x2e, 0x98, 0x01, 0x63,
940x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x43, 0x00, 0x01, 0x7f, 960x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x43, 0x00, 0x01, 0x7f,
950x00, 0x30, 0x00, 0x65, 0x69, 0x35, 0x02, 0x72, 0x00, 0x62, 970x00, 0x30, 0x00, 0x65, 0x69, 0x37, 0x02, 0x72, 0x00, 0x62,
960x75, 0x74, 0x74, 0x6f, 0x6e, 0x78, 0x00, 0xd2, 0x63, 0x79, 980x75, 0x74, 0x74, 0x6f, 0x6e, 0x78, 0x00, 0xd2, 0x63, 0x79,
970x63, 0x6c, 0x65, 0x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 990x63, 0x6c, 0x65, 0x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65,
980x6e, 0xdd, 0x00, 0xc5, 0x68, 0x72, 0x65, 0x65, 0x00, 0x70, 1000x6e, 0xdd, 0x00, 0xc5, 0x68, 0x72, 0x65, 0x65, 0x00, 0x70,
990x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0xdc, 0x00, 0x00, 0x67, 1010x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0xdc, 0x00, 0x00, 0x67,
1000x01, 0x62, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x00, 0xd9, 0x02, 1020x01, 0x62, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x00, 0xdb, 0x02,
1010x85, 0x69, 0x66, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x6c, 0x72, 1030x85, 0x69, 0x66, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x6c, 0x72,
1020x01, 0xbe, 0x00, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 1040x01, 0xbe, 0x00, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65,
1030x64, 0x6c, 0x79, 0xe4, 0x00, 0x00, 0xd2, 0x00, 0x02, 0x6f, 1050x64, 0x6c, 0x79, 0xe4, 0x00, 0x00, 0xd2, 0x00, 0x02, 0x6f,
1040x00, 0x52, 0x68, 0x61, 0x6e, 0x67, 0x65, 0xbf, 0x00, 0x02, 1060x00, 0x52, 0x68, 0x61, 0x6e, 0x67, 0x65, 0xbf, 0x00, 0x02,
1050x21, 0x00, 0x40, 0x74, 0x6f, 0x00, 0x5c, 0x05, 0x00, 0x51, 1070x21, 0x00, 0x40, 0x74, 0x6f, 0x00, 0x5c, 0x05, 0x00, 0x51,
1060x2f, 0x00, 0x62, 0x61, 0x63, 0x0f, 0x00, 0x01, 0x18, 0x00, 1080x2f, 0x00, 0x62, 0x61, 0x63, 0x0f, 0x00, 0x01, 0x18, 0x00,
1070x02, 0x0d, 0x04, 0x03, 0x66, 0x00, 0x01, 0xe5, 0x00, 0x0e, 1090x02, 0x0f, 0x04, 0x03, 0x66, 0x00, 0x01, 0xe5, 0x00, 0x0e,
1080x67, 0x00, 0x07, 0x7b, 0x01, 0x0f, 0x5d, 0x00, 0x07, 0x12, 1100x67, 0x00, 0x07, 0x7b, 0x01, 0x0f, 0x5d, 0x00, 0x07, 0x12,
1090x2f, 0x62, 0x00, 0x09, 0x5d, 0x00, 0x01, 0x9f, 0x03, 0x50, 1110x2f, 0x62, 0x00, 0x09, 0x5d, 0x00, 0x01, 0xa1, 0x03, 0x50,
1100x65, 0x72, 0x65, 0x66, 0x6f, 0x76, 0x04, 0x00, 0x62, 0x00, 1120x65, 0x72, 0x65, 0x66, 0x6f, 0x78, 0x04, 0x00, 0x62, 0x00,
1110x00, 0x1f, 0x03, 0x42, 0x70, 0x6c, 0x61, 0x79, 0x06, 0x03, 1130x00, 0x21, 0x03, 0x42, 0x70, 0x6c, 0x61, 0x79, 0x08, 0x03,
1120x00, 0x73, 0x02, 0x50, 0x65, 0x6e, 0x74, 0x69, 0x72, 0xf0, 1140x90, 0x61, 0x6d, 0x65, 0x00, 0x65, 0x6e, 0x74, 0x69, 0x72,
1130x02, 0x01, 0x0d, 0x04, 0x34, 0x6f, 0x6e, 0x65, 0x37, 0x01, 1150xf2, 0x02, 0x01, 0x0f, 0x04, 0x34, 0x6f, 0x6e, 0x65, 0x37,
1140x03, 0x94, 0x00, 0x71, 0x6e, 0x65, 0x65, 0x64, 0x00, 0x74, 1160x01, 0x03, 0x94, 0x00, 0x71, 0x6e, 0x65, 0x65, 0x64, 0x00,
1150x6f, 0x02, 0x03, 0x13, 0x59, 0x42, 0x00, 0x52, 0x61, 0x6c, 1170x74, 0x6f, 0x04, 0x03, 0x13, 0x59, 0x42, 0x00, 0x52, 0x61,
1160x73, 0x6f, 0x00, 0x3b, 0x03, 0xc1, 0x65, 0x00, 0x63, 0x75, 1180x6c, 0x73, 0x6f, 0x00, 0x3d, 0x03, 0xc1, 0x65, 0x00, 0x63,
1170x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x07, 0x03, 1190x75, 0x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x09,
1180x20, 0x6d, 0x6f, 0x2d, 0x05, 0x55, 0x72, 0x6f, 0x75, 0x6e, 1200x03, 0x20, 0x6d, 0x6f, 0x2f, 0x05, 0x55, 0x72, 0x6f, 0x75,
1190x64, 0x6b, 0x03, 0x71, 0x2e, 0x00, 0x50, 0x72, 0x65, 0x73, 1210x6e, 0x64, 0x6d, 0x03, 0x71, 0x2e, 0x00, 0x50, 0x72, 0x65,
1200x73, 0xa4, 0x01, 0x00, 0xe4, 0x01, 0x50, 0x65, 0x74, 0x75, 1220x73, 0x73, 0xa4, 0x01, 0x00, 0xe4, 0x01, 0x50, 0x65, 0x74,
1210x72, 0x6e, 0xde, 0x03, 0x20, 0x73, 0x70, 0x0e, 0x02, 0x01, 1230x75, 0x72, 0x6e, 0xe0, 0x03, 0x20, 0x73, 0x70, 0x0e, 0x02,
1220x3b, 0x00, 0x0b, 0xb4, 0x02, 0x20, 0x6f, 0x72, 0x25, 0x02, 1240x01, 0x3b, 0x00, 0x0b, 0xb4, 0x02, 0x20, 0x6f, 0x72, 0x25,
1230xe2, 0x2c, 0x00, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, 0x74, 1250x02, 0xe2, 0x2c, 0x00, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63,
1240x69, 0x76, 0x65, 0x6c, 0x79, 0x2c, 0x01, 0x01, 0x29, 0x00, 1260x74, 0x69, 0x76, 0x65, 0x6c, 0x79, 0x2c, 0x01, 0x01, 0x29,
1250x43, 0x74, 0x68, 0x65, 0x6e, 0xd4, 0x01, 0x50, 0x74, 0x68, 1270x00, 0x43, 0x74, 0x68, 0x65, 0x6e, 0xd4, 0x01, 0x50, 0x74,
1260x65, 0x6d, 0x00, 0x57, 0x04, 0x5a, 0x62, 0x6f, 0x76, 0x65, 1280x68, 0x65, 0x6d, 0x00, 0x59, 0x04, 0x5a, 0x62, 0x6f, 0x76,
1270x2e, 0xa4, 0x00, 0x10, 0x70, 0x77, 0x00, 0x20, 0x00, 0x2f, 1290x65, 0x2e, 0xa4, 0x00, 0x10, 0x70, 0x77, 0x00, 0x20, 0x00,
1280x4e, 0x00, 0x01, 0x7d, 0x01, 0x06, 0x7e, 0x02, 0x00, 0x12, 1300x2f, 0x4e, 0x00, 0x01, 0x7d, 0x01, 0x06, 0x7e, 0x02, 0x00,
1290x00, 0x0c, 0x5e, 0x00, 0xa1, 0x69, 0x6e, 0x64, 0x65, 0x70, 1310x12, 0x00, 0x0c, 0x5e, 0x00, 0xa1, 0x69, 0x6e, 0x64, 0x65,
1300x65, 0x6e, 0x64, 0x65, 0x6e, 0xf2, 0x02, 0x20, 0x77, 0x68, 1320x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0xf2, 0x02, 0x20, 0x77,
1310xe4, 0x04, 0x81, 0x73, 0x00, 0x61, 0x6c, 0x72, 0x65, 0x61, 1330x68, 0xe6, 0x04, 0x81, 0x73, 0x00, 0x61, 0x6c, 0x72, 0x65,
1320x64, 0xee, 0x01, 0x07, 0xf0, 0x00, 0x02, 0x91, 0x01, 0x62, 1340x61, 0x64, 0xee, 0x01, 0x07, 0xf0, 0x00, 0x02, 0x91, 0x01,
1330x2e, 0x00, 0x42, 0x61, 0x63, 0x6b, 0xc7, 0x00, 0x20, 0x72, 1350x62, 0x2e, 0x00, 0x42, 0x61, 0x63, 0x6b, 0xc7, 0x00, 0x20,
1340x65, 0xfc, 0x00, 0x24, 0x73, 0x00, 0x2c, 0x05, 0x06, 0x48, 1360x72, 0x65, 0xfc, 0x00, 0x24, 0x73, 0x00, 0x2e, 0x05, 0x06,
1350x03, 0x0b, 0x33, 0x00, 0x42, 0x00, 0x00, 0x28, 0x41, 0xc4, 1370x48, 0x03, 0x0b, 0x33, 0x00, 0x42, 0x00, 0x00, 0x28, 0x41,
1360x00, 0x32, 0x00, 0x61, 0x63, 0xcb, 0x05, 0x90, 0x64, 0x65, 1380xc4, 0x00, 0x32, 0x00, 0x61, 0x63, 0xcd, 0x05, 0x90, 0x64,
1370x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x66, 0x00, 0x21, 1390x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x66, 0x00,
1380x73, 0x65, 0x16, 0x00, 0x41, 0x00, 0x32, 0x2e, 0x31, 0xe4, 1400x21, 0x73, 0x65, 0x16, 0x00, 0x41, 0x00, 0x32, 0x2e, 0x31,
1390x05, 0x01, 0xcb, 0x00, 0xa3, 0x61, 0x76, 0x61, 0x69, 0x6c, 1410xe6, 0x05, 0x01, 0xcb, 0x00, 0xa3, 0x61, 0x76, 0x61, 0x69,
1400x61, 0x62, 0x6c, 0x65, 0x2e, 0x19, 0x04, 0x13, 0x32, 0x19, 1420x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x19, 0x04, 0x13, 0x32,
1410x04, 0x91, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 1430x19, 0x04, 0x91, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74,
1420x72, 0x1b, 0x04, 0x66, 0x54, 0x68, 0x65, 0x73, 0x65, 0x00, 1440x65, 0x72, 0x1b, 0x04, 0x66, 0x54, 0x68, 0x65, 0x73, 0x65,
1430x14, 0x00, 0x02, 0x41, 0x00, 0x04, 0x3c, 0x00, 0x06, 0x93, 1450x00, 0x14, 0x00, 0x02, 0x41, 0x00, 0x04, 0x3c, 0x00, 0x06,
1440x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 1460x93, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d,
1450x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x6f, 0x00, 0x22, 0x6f, 1470x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x6f, 0x00, 0x22,
1460x6e, 0x1a, 0x00, 0xa0, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 1480x6f, 0x6e, 0x1a, 0x00, 0xa0, 0x54, 0x79, 0x70, 0x65, 0x27,
1470x6d, 0x65, 0x6e, 0x75, 0xab, 0x00, 0x91, 0x57, 0x69, 0x64, 1490x00, 0x6d, 0x65, 0x6e, 0x75, 0xab, 0x00, 0x91, 0x57, 0x69,
1480x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x81, 0x03, 0x51, 0x00, 1500x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x81, 0x03, 0x51,
1490x00, 0x53, 0x69, 0x7a, 0x47, 0x05, 0x01, 0x43, 0x05, 0x26, 1510x00, 0x00, 0x53, 0x69, 0x7a, 0x49, 0x05, 0x01, 0x45, 0x05,
1500x69, 0x6e, 0x0e, 0x07, 0xc3, 0x00, 0x00, 0x44, 0x69, 0x66, 1520x26, 0x69, 0x6e, 0x10, 0x07, 0xc3, 0x00, 0x00, 0x44, 0x69,
1510x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x98, 0x03, 0x00, 1530x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x98, 0x03,
1520xb0, 0x04, 0x01, 0x54, 0x00, 0x16, 0x64, 0x1a, 0x00, 0x04, 1540x00, 0xb0, 0x04, 0x01, 0x54, 0x00, 0x16, 0x64, 0x1a, 0x00,
1530x82, 0x05, 0x40, 0x65, 0x6e, 0x65, 0x72, 0xe0, 0x02, 0x03, 1550x04, 0x84, 0x05, 0x40, 0x65, 0x6e, 0x65, 0x72, 0xe0, 0x02,
1540x47, 0x05, 0xf2, 0x00, 0x2e, 0x00, 0x41, 0x74, 0x00, 0x48, 1560x03, 0x49, 0x05, 0xf2, 0x00, 0x2e, 0x00, 0x41, 0x74, 0x00,
1550x61, 0x72, 0x64, 0x00, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0xae, 1570x48, 0x61, 0x72, 0x64, 0x00, 0x6c, 0x65, 0x76, 0x65, 0x6c,
1560x02, 0x20, 0x61, 0x72, 0x56, 0x01, 0x61, 0x71, 0x75, 0x69, 1580xae, 0x02, 0x20, 0x61, 0x72, 0x56, 0x01, 0x61, 0x71, 0x75,
1570x72, 0x65, 0x64, 0x62, 0x07, 0x63, 0x6f, 0x00, 0x64, 0x65, 1590x69, 0x72, 0x65, 0x64, 0x64, 0x07, 0x63, 0x6f, 0x00, 0x64,
1580x64, 0x75, 0x34, 0x01, 0x50, 0x62, 0x61, 0x73, 0x65, 0x64, 1600x65, 0x64, 0x75, 0x34, 0x01, 0x50, 0x62, 0x61, 0x73, 0x65,
1590xb6, 0x00, 0x81, 0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65, 0x64, 1610x64, 0xb6, 0x00, 0x81, 0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65,
1600x67, 0x98, 0x00, 0x41, 0x72, 0x65, 0x6c, 0x61, 0x20, 0x00, 1620x64, 0x67, 0x98, 0x00, 0x41, 0x72, 0x65, 0x6c, 0x61, 0x20,
1610x45, 0x68, 0x69, 0x70, 0x73, 0xf1, 0x03, 0x03, 0xa6, 0x00, 1630x00, 0x45, 0x68, 0x69, 0x70, 0x73, 0xf1, 0x03, 0x03, 0xa6,
1620x03, 0x4f, 0x06, 0x00, 0xf3, 0x05, 0x00, 0x22, 0x02, 0x30, 1640x00, 0x03, 0x51, 0x06, 0x00, 0xf5, 0x05, 0x00, 0x22, 0x02,
1630x77, 0x61, 0x79, 0x23, 0x00, 0x01, 0xcf, 0x06, 0x10, 0x62, 1650x30, 0x77, 0x61, 0x79, 0x23, 0x00, 0x01, 0xd1, 0x06, 0x10,
1640x4b, 0x02, 0x03, 0x60, 0x00, 0x02, 0xd9, 0x02, 0x55, 0x65, 1660x62, 0x4b, 0x02, 0x03, 0x60, 0x00, 0x02, 0xd9, 0x02, 0x55,
1650x78, 0x61, 0x63, 0x74, 0x11, 0x04, 0x00, 0x5c, 0x00, 0x25, 1670x65, 0x78, 0x61, 0x63, 0x74, 0x11, 0x04, 0x00, 0x5c, 0x00,
1660x6f, 0x6e, 0x89, 0x03, 0xf0, 0x00, 0x61, 0x74, 0x00, 0x61, 1680x25, 0x6f, 0x6e, 0x89, 0x03, 0xf0, 0x00, 0x61, 0x74, 0x00,
1670x00, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x00, 0x28, 0x46, 0x6f, 1690x61, 0x00, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x00, 0x28, 0x46,
1680x72, 0x2d, 0x00, 0x33, 0x6d, 0x70, 0x6c, 0x66, 0x03, 0x11, 1700x6f, 0x72, 0x2d, 0x00, 0x33, 0x6d, 0x70, 0x6c, 0x66, 0x03,
1690x6d, 0x2c, 0x01, 0x00, 0x97, 0x00, 0x03, 0xc2, 0x07, 0x25, 1710x11, 0x6d, 0x2c, 0x01, 0x00, 0x97, 0x00, 0x03, 0xc4, 0x07,
1700x77, 0x6f, 0x82, 0x00, 0x01, 0xdd, 0x07, 0x04, 0x4c, 0x02, 1720x25, 0x77, 0x6f, 0x82, 0x00, 0x01, 0xdf, 0x07, 0x04, 0x4c,
1710x30, 0x73, 0x61, 0x6d, 0x1d, 0x01, 0x12, 0x72, 0xf1, 0x01, 1730x02, 0x30, 0x73, 0x61, 0x6d, 0x1d, 0x01, 0x12, 0x72, 0xf1,
1720x55, 0x2c, 0x00, 0x65, 0x76, 0x65, 0x79, 0x03, 0x83, 0x64, 1740x01, 0x55, 0x2c, 0x00, 0x65, 0x76, 0x65, 0x79, 0x03, 0x83,
1730x6f, 0x6e, 0x27, 0x74, 0x00, 0x79, 0x65, 0x49, 0x00, 0x01, 1750x64, 0x6f, 0x6e, 0x27, 0x74, 0x00, 0x79, 0x65, 0x49, 0x00,
1740x8e, 0x02, 0x01, 0x4e, 0x00, 0x05, 0x30, 0x00, 0x32, 0x00, 1760x01, 0x8e, 0x02, 0x01, 0x4e, 0x00, 0x05, 0x30, 0x00, 0x32,
1750x69, 0x73, 0x13, 0x03, 0x01, 0x8f, 0x06, 0x02, 0x75, 0x00, 1770x00, 0x69, 0x73, 0x13, 0x03, 0x01, 0x91, 0x06, 0x02, 0x75,
1760x21, 0x65, 0x6e, 0xca, 0x00, 0x00, 0x41, 0x00, 0x06, 0xce, 1780x00, 0x21, 0x65, 0x6e, 0xca, 0x00, 0x00, 0x41, 0x00, 0x06,
1770x00, 0x62, 0x73, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0xe7, 0x00, 1790xce, 0x00, 0x62, 0x73, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0xe7,
1780x60, 0x6f, 0x75, 0x74, 0x00, 0x73, 0x74, 0x44, 0x03, 0x11, 1800x00, 0x60, 0x6f, 0x75, 0x74, 0x00, 0x73, 0x74, 0x44, 0x03,
1790x6f, 0x0b, 0x01, 0x04, 0xc0, 0x01, 0x30, 0x29, 0x00, 0x45, 1810x11, 0x6f, 0x0b, 0x01, 0x04, 0xc0, 0x01, 0x30, 0x29, 0x00,
1800x7d, 0x00, 0x1a, 0x61, 0x86, 0x01, 0x91, 0x67, 0x75, 0x65, 1820x45, 0x7d, 0x00, 0x1a, 0x61, 0x86, 0x01, 0x91, 0x67, 0x75,
1810x73, 0x73, 0x77, 0x6f, 0x72, 0x6b, 0x68, 0x00, 0x00, 0x5d, 1830x65, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x6b, 0x68, 0x00, 0x00,
1820x04, 0x32, 0x74, 0x72, 0x61, 0xe1, 0x05, 0x21, 0x73, 0x68, 1840x5d, 0x04, 0x32, 0x74, 0x72, 0x61, 0xe1, 0x05, 0x21, 0x73,
1830x33, 0x07, 0x02, 0x6d, 0x07, 0xe0, 0x62, 0x65, 0x00, 0x6e, 1850x68, 0x35, 0x07, 0x02, 0x6f, 0x07, 0xd2, 0x62, 0x65, 0x00,
1840x65, 0x63, 0x65, 0x73, 0x73, 0x61, 0x72, 0x79, 0x2e, 0x00, 1860x6e, 0x65, 0x63, 0x65, 0x73, 0x73, 0x61, 0x72, 0x79, 0x2e,
1870xa0, 0x02, 0x13, 0x33, 0xa0, 0x02, 0xf1, 0x00, 0x75, 0x73,
1880x65, 0x72, 0x20, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65,
1890x6e, 0x63, 0x65, 0xa6, 0x02, 0x11, 0x4f, 0x86, 0x04, 0x10,
1900x74, 0x9d, 0x08, 0x12, 0x73, 0xd5, 0x00, 0x80, 0x73, 0x75,
1910x70, 0x70, 0x6f, 0x72, 0x74, 0x00, 0x2e, 0x00, 0x17, 0x00,
1920x2e, 0x00, 0x12, 0x2c, 0x94, 0x02, 0x16, 0x50, 0x12, 0x00,
1930x0d, 0xb0, 0x02, 0x33, 0x47, 0x61, 0x6d, 0xb0, 0x02, 0x02,
1940x1c, 0x04, 0x32, 0x6c, 0x65, 0x74, 0xec, 0x04, 0x78, 0x6f,
1950x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x67, 0x09, 0x06, 0x98,
1960x04, 0x44, 0x6d, 0x6f, 0x75, 0x73, 0xec, 0x04, 0x80, 0x73,
1970x00, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x00,
185}; 198};
186 199
187const unsigned short help_text_len = 2378; 200const unsigned short help_text_len = 2582;
188const unsigned short help_text_words = 444; 201const unsigned short help_text_words = 474;
189const char quick_help_text[] = "Draw a maze of slanting lines that matches the clues."; 202const char quick_help_text[] = "Draw a maze of slanting lines that matches the clues.";
diff --git a/apps/plugins/puzzles/help/solo.c b/apps/plugins/puzzles/help/solo.c
index 6ebeec86c0..ceb05fa70e 100644
--- a/apps/plugins/puzzles/help/solo.c
+++ b/apps/plugins/puzzles/help/solo.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,382 +6,381 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 360, TEXT_UNDERLINE }, 9 { 361, TEXT_UNDERLINE },
10 { 390, TEXT_CENTER | C_RED }, 10 { 388, TEXT_CENTER | C_RED },
11 { 446, TEXT_UNDERLINE }, 11 { 444, TEXT_UNDERLINE },
12 { 674, TEXT_CENTER | C_RED }, 12 { 672, TEXT_CENTER | C_RED },
13 { 1059, TEXT_UNDERLINE }, 13 { 1057, TEXT_UNDERLINE },
14 LAST_STYLE_ITEM 14 LAST_STYLE_ITEM
15}; 15};
16 16
17/* orig 6263 comp 3635 ratio 0.580393 level 10 saved 2628 */ 17/* orig 6259 comp 3626 ratio 0.579326 level 10 saved 2633 */
18const char help_text[] = { 18const char help_text[] = {
190xf0, 0x53, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 190xfb, 0x04, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
200x31, 0x31, 0x3a, 0x20, 0x53, 0x6f, 0x6c, 0x6f, 0x20, 0x00, 200x31, 0x31, 0x3a, 0x20, 0x53, 0x6f, 0x6c, 0x6f, 0x20, 0x00,
210x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 210x2d, 0x01, 0x00, 0xf0, 0x42, 0x00, 0x00, 0x00, 0x59, 0x6f,
220x00, 0x61, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x00, 220x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x73,
230x67, 0x72, 0x69, 0x64, 0x2c, 0x00, 0x77, 0x68, 0x69, 0x63, 230x71, 0x75, 0x61, 0x72, 0x65, 0x00, 0x67, 0x72, 0x69, 0x64,
240x68, 0x00, 0x69, 0x73, 0x00, 0x64, 0x69, 0x76, 0x69, 0x64, 240x2c, 0x00, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x69, 0x73,
250x65, 0x64, 0x00, 0x69, 0x6e, 0x74, 0x6f, 0x00, 0x61, 0x73, 250x00, 0x64, 0x69, 0x76, 0x69, 0x64, 0x65, 0x64, 0x00, 0x69,
260x00, 0x6d, 0x61, 0x6e, 0x79, 0x00, 0x65, 0x71, 0x75, 0x61, 260x6e, 0x74, 0x6f, 0x00, 0x61, 0x73, 0x00, 0x6d, 0x61, 0x6e,
270x6c, 0x6c, 0x79, 0x00, 0x73, 0x69, 0x7a, 0x65, 0x64, 0x00, 270x79, 0x00, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x00,
280x73, 0x75, 0x62, 0x2d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 280x73, 0x69, 0x7a, 0x65, 0x64, 0x00, 0x73, 0x75, 0x62, 0x2d,
290x21, 0x00, 0x22, 0x74, 0x68, 0x44, 0x00, 0xf4, 0x00, 0x00, 290x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x21, 0x00, 0x22, 0x74,
300x68, 0x61, 0x73, 0x00, 0x72, 0x6f, 0x77, 0x73, 0x2e, 0x00, 300x68, 0x44, 0x00, 0xf4, 0x00, 0x00, 0x68, 0x61, 0x73, 0x00,
310x45, 0x61, 0x63, 0x68, 0x5f, 0x00, 0xc1, 0x6d, 0x75, 0x73, 310x72, 0x6f, 0x77, 0x73, 0x2e, 0x00, 0x45, 0x61, 0x63, 0x68,
320x74, 0x00, 0x62, 0x65, 0x00, 0x66, 0x69, 0x6c, 0x6c, 0x57, 320x5f, 0x00, 0xc1, 0x6d, 0x75, 0x73, 0x74, 0x00, 0x62, 0x65,
330x00, 0xf1, 0x08, 0x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x61, 330x00, 0x66, 0x69, 0x6c, 0x6c, 0x57, 0x00, 0xf1, 0x08, 0x00,
340x00, 0x64, 0x69, 0x67, 0x69, 0x74, 0x00, 0x66, 0x72, 0x6f, 340x77, 0x69, 0x74, 0x68, 0x00, 0x61, 0x00, 0x64, 0x69, 0x67,
350x6d, 0x00, 0x31, 0x00, 0x74, 0x6f, 0x48, 0x00, 0x00, 0x60, 350x69, 0x74, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x00, 0x31, 0x00,
360x00, 0x35, 0x00, 0x6f, 0x66, 0x54, 0x00, 0x10, 0x2c, 0x30, 360x74, 0x6f, 0x48, 0x00, 0x00, 0x60, 0x00, 0x35, 0x00, 0x6f,
370x00, 0x30, 0x73, 0x75, 0x63, 0x30, 0x00, 0xf0, 0x03, 0x77, 370x66, 0x54, 0x00, 0x10, 0x2c, 0x30, 0x00, 0x30, 0x73, 0x75,
380x61, 0x79, 0x00, 0x74, 0x68, 0x61, 0x74, 0x00, 0x00, 0x00, 380x63, 0x30, 0x00, 0xf0, 0x03, 0x77, 0x61, 0x79, 0x00, 0x74,
390x2d, 0x00, 0x65, 0x76, 0x65, 0x72, 0x79, 0x6e, 0x00, 0xf1, 390x68, 0x61, 0x74, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x65, 0x76,
400x0d, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 400x65, 0x72, 0x79, 0x6e, 0x00, 0xf1, 0x0d, 0x00, 0x63, 0x6f,
410x00, 0x6f, 0x6e, 0x6c, 0x79, 0x00, 0x6f, 0x6e, 0x65, 0x00, 410x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x00, 0x6f, 0x6e, 0x6c,
420x6f, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x4b, 420x79, 0x00, 0x6f, 0x6e, 0x65, 0x00, 0x6f, 0x63, 0x63, 0x75,
430x00, 0x10, 0x65, 0x8c, 0x00, 0x02, 0x6c, 0x00, 0x06, 0x39, 430x72, 0x72, 0x65, 0x6e, 0x63, 0x4b, 0x00, 0x10, 0x65, 0x8c,
440x00, 0x6f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x3c, 0x00, 440x00, 0x02, 0x6c, 0x00, 0x06, 0x39, 0x00, 0x6f, 0x63, 0x6f,
450x23, 0x01, 0xfa, 0x00, 0x0f, 0x3b, 0x00, 0x18, 0x11, 0x2e, 450x6c, 0x75, 0x6d, 0x6e, 0x3c, 0x00, 0x23, 0x01, 0xfa, 0x00,
460x3c, 0x00, 0x70, 0x28, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 460x0f, 0x3b, 0x00, 0x18, 0x11, 0x2e, 0x3c, 0x00, 0x70, 0x28,
470x46, 0x01, 0xf2, 0x02, 0x2c, 0x00, 0x62, 0x79, 0x00, 0x64, 470x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x01, 0xf2, 0x02,
480x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x6f, 0x66, 0x66, 480x2c, 0x00, 0x62, 0x79, 0x00, 0x64, 0x65, 0x66, 0x61, 0x75,
490x29, 0x2d, 0x00, 0x03, 0xf7, 0x00, 0x02, 0x37, 0x01, 0xf0, 490x6c, 0x74, 0x00, 0x6f, 0x66, 0x66, 0x29, 0x2d, 0x00, 0x03,
500x01, 0x27, 0x73, 0x00, 0x74, 0x77, 0x6f, 0x00, 0x6d, 0x61, 500xf7, 0x00, 0x02, 0x37, 0x01, 0xf0, 0x01, 0x27, 0x73, 0x00,
510x69, 0x6e, 0x00, 0x64, 0x69, 0x61, 0x67, 0x3a, 0x00, 0x1f, 510x74, 0x77, 0x6f, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x64,
520x73, 0x75, 0x00, 0x1c, 0x00, 0xeb, 0x01, 0x01, 0xe1, 0x01, 520x69, 0x61, 0x67, 0x3a, 0x00, 0x1f, 0x73, 0x75, 0x00, 0x1c,
530x85, 0x69, 0x76, 0x65, 0x6e, 0x00, 0x73, 0x6f, 0x6d, 0x5b, 530x00, 0xeb, 0x01, 0x01, 0xe1, 0x01, 0x85, 0x69, 0x76, 0x65,
540x01, 0x61, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0xbe, 0x01, 540x6e, 0x00, 0x73, 0x6f, 0x6d, 0x5b, 0x01, 0x61, 0x6e, 0x75,
550xf0, 0x00, 0x63, 0x6c, 0x75, 0x65, 0x73, 0x3b, 0x00, 0x79, 550x6d, 0x62, 0x65, 0x72, 0xbe, 0x01, 0xf0, 0x00, 0x63, 0x6c,
560x6f, 0x75, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x02, 0x02, 0x81, 560x75, 0x65, 0x73, 0x3b, 0x00, 0x79, 0x6f, 0x75, 0x72, 0x00,
570x74, 0x6f, 0x00, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2b, 0x00, 570x61, 0x69, 0x6d, 0x02, 0x02, 0x81, 0x74, 0x6f, 0x00, 0x70,
580x4c, 0x72, 0x65, 0x73, 0x74, 0x37, 0x00, 0x90, 0x63, 0x6f, 580x6c, 0x61, 0x63, 0x65, 0x2b, 0x00, 0x4c, 0x72, 0x65, 0x73,
590x72, 0x72, 0x65, 0x63, 0x74, 0x6c, 0x79, 0x66, 0x00, 0x51, 590x74, 0x37, 0x00, 0x90, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63,
600x55, 0x6e, 0x64, 0x65, 0x72, 0x1f, 0x00, 0x04, 0xd3, 0x00, 600x74, 0x6c, 0x79, 0x66, 0x00, 0x51, 0x55, 0x6e, 0x64, 0x65,
610x92, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2c, 610x72, 0x1f, 0x00, 0x04, 0xd3, 0x00, 0x92, 0x73, 0x65, 0x74,
620xd0, 0x00, 0x07, 0x2d, 0x02, 0x24, 0x72, 0x65, 0x16, 0x02, 620x74, 0x69, 0x6e, 0x67, 0x73, 0x2c, 0xd0, 0x00, 0x07, 0x2d,
630x30, 0x6f, 0x72, 0x00, 0x43, 0x00, 0xa7, 0x61, 0x6e, 0x67, 630x02, 0x24, 0x72, 0x65, 0x16, 0x02, 0x30, 0x6f, 0x72, 0x00,
640x75, 0x6c, 0x61, 0x72, 0x2e, 0x00, 0x54, 0x40, 0x00, 0x53, 640x43, 0x00, 0xa7, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x61, 0x72,
650x70, 0x75, 0x7a, 0x7a, 0x6c, 0x0c, 0x02, 0xf3, 0x05, 0x69, 650x2e, 0x00, 0x54, 0x40, 0x00, 0x53, 0x70, 0x75, 0x7a, 0x7a,
660x73, 0x00, 0x33, 0x78, 0x33, 0x00, 0x28, 0x61, 0x00, 0x39, 660x6c, 0x0c, 0x02, 0xf3, 0x05, 0x69, 0x73, 0x00, 0x33, 0x78,
670x78, 0x39, 0x00, 0x61, 0x63, 0x74, 0x75, 0x61, 0x6c, 0x1a, 670x33, 0x00, 0x28, 0x61, 0x00, 0x39, 0x78, 0x39, 0x00, 0x61,
680x02, 0x09, 0xa9, 0x02, 0x41, 0x6e, 0x69, 0x6e, 0x65, 0x2a, 680x63, 0x74, 0x75, 0x61, 0x6c, 0x1a, 0x02, 0x09, 0xa9, 0x02,
690x00, 0x02, 0x6b, 0x00, 0x21, 0x29, 0x2e, 0xfe, 0x00, 0xf1, 690x41, 0x6e, 0x69, 0x6e, 0x65, 0x2a, 0x00, 0x02, 0x6b, 0x00,
700x00, 0x63, 0x61, 0x6e, 0x00, 0x61, 0x6c, 0x73, 0x6f, 0x00, 700x21, 0x29, 0x2e, 0xfe, 0x00, 0xf1, 0x00, 0x63, 0x61, 0x6e,
710x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x00, 0x12, 0x73, 710x00, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0x73, 0x65, 0x6c, 0x65,
720x80, 0x02, 0x07, 0x7e, 0x00, 0x13, 0x00, 0x9f, 0x00, 0x70, 720x63, 0x74, 0x53, 0x00, 0x12, 0x73, 0x80, 0x02, 0x07, 0x7e,
730x69, 0x6e, 0x73, 0x74, 0x65, 0x61, 0x64, 0xee, 0x00, 0x04, 730x00, 0x13, 0x00, 0x9f, 0x00, 0x70, 0x69, 0x6e, 0x73, 0x74,
740xa6, 0x00, 0x43, 0x6e, 0x65, 0x73, 0x2c, 0x80, 0x02, 0x32, 740x65, 0x61, 0x64, 0xee, 0x00, 0x04, 0xa6, 0x00, 0x43, 0x6e,
750x73, 0x00, 0x32, 0x89, 0x00, 0x32, 0x36, 0x78, 0x36, 0xf0, 750x65, 0x73, 0x2c, 0x80, 0x02, 0x32, 0x73, 0x00, 0x32, 0x89,
760x02, 0x09, 0x81, 0x00, 0x76, 0x73, 0x69, 0x78, 0x00, 0x33, 760x00, 0x32, 0x36, 0x78, 0x36, 0xf0, 0x02, 0x09, 0x81, 0x00,
770x78, 0x32, 0x80, 0x00, 0xb0, 0x41, 0x6c, 0x74, 0x65, 0x72, 770x76, 0x73, 0x69, 0x78, 0x00, 0x33, 0x78, 0x32, 0x80, 0x00,
780x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0xf3, 0x01, 0x13, 0x79, 780xb0, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69,
790x8f, 0x00, 0x03, 0x8a, 0x00, 0xd1, 0x60, 0x6a, 0x69, 0x67, 790x76, 0x65, 0xf3, 0x01, 0x13, 0x79, 0x8f, 0x00, 0x03, 0x8a,
800x73, 0x61, 0x77, 0x27, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0xe6, 800x00, 0xd1, 0x60, 0x6a, 0x69, 0x67, 0x73, 0x61, 0x77, 0x27,
810x02, 0x02, 0x81, 0x03, 0x0f, 0x32, 0x01, 0x00, 0xe0, 0x61, 810x00, 0x6d, 0x6f, 0x64, 0x65, 0xe6, 0x02, 0x02, 0x81, 0x03,
820x72, 0x62, 0x69, 0x74, 0x72, 0x61, 0x72, 0x79, 0x00, 0x73, 820x0f, 0x32, 0x01, 0x00, 0xe0, 0x61, 0x72, 0x62, 0x69, 0x74,
830x68, 0x61, 0x70, 0xc0, 0x00, 0x21, 0x68, 0x69, 0xe7, 0x01, 830x72, 0x61, 0x72, 0x79, 0x00, 0x73, 0x68, 0x61, 0x70, 0xc0,
840xf1, 0x00, 0x66, 0x66, 0x65, 0x72, 0x00, 0x62, 0x65, 0x74, 840x00, 0x21, 0x68, 0x69, 0xe7, 0x01, 0xf1, 0x00, 0x66, 0x66,
850x77, 0x65, 0x65, 0x6e, 0x00, 0x69, 0x6e, 0x8f, 0x00, 0x00, 850x65, 0x72, 0x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e,
860x1f, 0x01, 0x02, 0x40, 0x01, 0x10, 0x73, 0x9d, 0x01, 0xf1, 860x00, 0x69, 0x6e, 0x8f, 0x00, 0x00, 0x1f, 0x01, 0x02, 0x40,
870x02, 0x41, 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x00, 0x61, 870x01, 0x10, 0x73, 0x9d, 0x01, 0xf1, 0x02, 0x41, 0x6e, 0x6f,
880x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x70, 0x00, 880x74, 0x68, 0x65, 0x72, 0x00, 0x61, 0x76, 0x61, 0x69, 0x6c,
890x00, 0x56, 0x01, 0x20, 0x60, 0x6b, 0x90, 0x03, 0xb3, 0x72, 890x61, 0x62, 0x6c, 0x65, 0x70, 0x00, 0x00, 0x56, 0x01, 0x20,
900x27, 0x2e, 0x00, 0x49, 0x6e, 0x00, 0x74, 0x68, 0x69, 0x73, 900x60, 0x6b, 0x90, 0x03, 0xb3, 0x72, 0x27, 0x2e, 0x00, 0x49,
910x8a, 0x00, 0x01, 0x10, 0x02, 0x01, 0x78, 0x00, 0x33, 0x6e, 910x6e, 0x00, 0x74, 0x68, 0x69, 0x73, 0x8a, 0x00, 0x01, 0x10,
920x6f, 0x74, 0x3b, 0x02, 0x21, 0x69, 0x6e, 0x98, 0x00, 0x40, 920x02, 0x01, 0x78, 0x00, 0x33, 0x6e, 0x6f, 0x74, 0x3b, 0x02,
930x66, 0x6f, 0x72, 0x6d, 0x1d, 0x01, 0x02, 0xca, 0x03, 0x33, 930x21, 0x69, 0x6e, 0x98, 0x00, 0x40, 0x66, 0x6f, 0x72, 0x6d,
940x2d, 0x69, 0x6e, 0x27, 0x01, 0x24, 0x73, 0x3b, 0x3b, 0x01, 940x1d, 0x01, 0x02, 0xca, 0x03, 0x33, 0x2d, 0x69, 0x6e, 0x27,
950x16, 0x2c, 0x0d, 0x04, 0x0c, 0x4a, 0x04, 0x91, 0x60, 0x63, 950x01, 0x24, 0x73, 0x3b, 0x3b, 0x01, 0x16, 0x2c, 0x0d, 0x04,
960x61, 0x67, 0x65, 0x73, 0x27, 0x00, 0x62, 0x7d, 0x03, 0x81, 960x0c, 0x4a, 0x04, 0x91, 0x60, 0x63, 0x61, 0x67, 0x65, 0x73,
970x6f, 0x75, 0x72, 0x65, 0x64, 0x00, 0x6c, 0x69, 0x60, 0x01, 970x27, 0x00, 0x62, 0x7d, 0x03, 0x81, 0x6f, 0x75, 0x72, 0x65,
980x30, 0x61, 0x6e, 0x64, 0x5c, 0x00, 0x02, 0xbe, 0x02, 0x00, 980x64, 0x00, 0x6c, 0x69, 0x60, 0x01, 0x30, 0x61, 0x6e, 0x64,
990x27, 0x00, 0x02, 0x46, 0x00, 0x91, 0x61, 0x6d, 0x65, 0x00, 990x5c, 0x00, 0x02, 0xbe, 0x02, 0x00, 0x27, 0x00, 0x02, 0x46,
1000x74, 0x65, 0x6c, 0x6c, 0x73, 0x3c, 0x01, 0x10, 0x77, 0xfa, 1000x00, 0x91, 0x61, 0x6d, 0x65, 0x00, 0x74, 0x65, 0x6c, 0x6c,
1010x03, 0x02, 0x1e, 0x01, 0x01, 0x85, 0x00, 0x32, 0x61, 0x6c, 1010x73, 0x3c, 0x01, 0x10, 0x77, 0xfa, 0x03, 0x02, 0x1e, 0x01,
1020x6c, 0x75, 0x02, 0x00, 0xee, 0x02, 0x00, 0xbc, 0x01, 0x02, 1020x01, 0x85, 0x00, 0x32, 0x61, 0x6c, 0x6c, 0x75, 0x02, 0x00,
1030x1c, 0x04, 0x01, 0x3f, 0x00, 0x90, 0x73, 0x68, 0x6f, 0x75, 1030xee, 0x02, 0x00, 0xbc, 0x01, 0x02, 0x1c, 0x04, 0x01, 0x3f,
1040x6c, 0x64, 0x00, 0x62, 0x65, 0x86, 0x01, 0x63, 0x73, 0x6f, 1040x00, 0x90, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x00, 0x62,
1050x2c, 0x00, 0x6e, 0x6f, 0xc6, 0x03, 0xe0, 0x6d, 0x61, 0x79, 1050x65, 0x86, 0x01, 0x63, 0x73, 0x6f, 0x2c, 0x00, 0x6e, 0x6f,
1060x00, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x00, 0x6d, 0x6f, 1060xc6, 0x03, 0xe0, 0x6d, 0x61, 0x79, 0x00, 0x61, 0x70, 0x70,
1070x72, 0x69, 0x00, 0x40, 0x61, 0x6e, 0x00, 0x6f, 0x3e, 0x03, 1070x65, 0x61, 0x72, 0x00, 0x6d, 0x6f, 0x72, 0x69, 0x00, 0x40,
1080x00, 0x15, 0x02, 0x41, 0x69, 0x6e, 0x00, 0x61, 0x42, 0x00, 1080x61, 0x6e, 0x00, 0x6f, 0x3e, 0x03, 0x00, 0x15, 0x02, 0x41,
1090x31, 0x2c, 0x00, 0x65, 0xf8, 0x00, 0x02, 0xf7, 0x02, 0x01, 1090x69, 0x6e, 0x00, 0x61, 0x42, 0x00, 0x31, 0x2c, 0x00, 0x65,
1100x54, 0x00, 0x62, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x65, 0xee, 1100xf8, 0x00, 0x02, 0xf7, 0x02, 0x01, 0x54, 0x00, 0x62, 0x63,
1110x04, 0xa1, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x69, 1110x72, 0x6f, 0x73, 0x73, 0x65, 0xee, 0x04, 0xa1, 0x62, 0x6f,
1120x65, 0x73, 0x75, 0x03, 0x30, 0x78, 0x69, 0x73, 0xf0, 0x02, 1120x75, 0x6e, 0x64, 0x61, 0x72, 0x69, 0x65, 0x73, 0x75, 0x03,
1130x71, 0x00, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x78, 0x01, 1130x30, 0x78, 0x69, 0x73, 0xf0, 0x02, 0x71, 0x00, 0x72, 0x65,
1140x21, 0x49, 0x66, 0xb5, 0x00, 0x03, 0xed, 0x01, 0x19, 0x61, 1140x67, 0x69, 0x6f, 0x6e, 0x78, 0x01, 0x21, 0x49, 0x66, 0xb5,
1150xd3, 0x02, 0x02, 0xbf, 0x01, 0x87, 0x72, 0x65, 0x71, 0x75, 1150x00, 0x03, 0xed, 0x01, 0x19, 0x61, 0xd3, 0x02, 0x02, 0xbf,
1160x69, 0x72, 0x65, 0x73, 0x88, 0x00, 0x13, 0x39, 0xcd, 0x00, 1160x01, 0x87, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73,
1170x02, 0x46, 0x01, 0x42, 0x61, 0x64, 0x64, 0x69, 0x32, 0x04, 1170x88, 0x00, 0x13, 0x39, 0xcd, 0x00, 0x02, 0x46, 0x01, 0x42,
1180x04, 0xe4, 0x00, 0x40, 0x77, 0x69, 0x6c, 0x6c, 0x4a, 0x05, 1180x61, 0x64, 0x64, 0x69, 0x32, 0x04, 0x04, 0xe4, 0x00, 0x40,
1190x40, 0x6c, 0x65, 0x74, 0x74, 0x87, 0x03, 0x03, 0x96, 0x03, 1190x77, 0x69, 0x6c, 0x6c, 0x4a, 0x05, 0x40, 0x6c, 0x65, 0x74,
1200xb0, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x62, 0x65, 0x74, 0x2e, 1200x74, 0x87, 0x03, 0x03, 0x96, 0x03, 0xb0, 0x61, 0x6c, 0x70,
1210x00, 0x46, 0x45, 0x01, 0x50, 0x78, 0x61, 0x6d, 0x70, 0x6c, 1210x68, 0x61, 0x62, 0x65, 0x74, 0x2e, 0x00, 0x46, 0x45, 0x01,
1220x53, 0x02, 0x09, 0x83, 0x00, 0x30, 0x33, 0x78, 0x34, 0x2d, 1220x50, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x53, 0x02, 0x09, 0x83,
1230x00, 0x18, 0x6e, 0x34, 0x01, 0x02, 0x89, 0x00, 0x20, 0x67, 1230x00, 0x30, 0x33, 0x78, 0x34, 0x2d, 0x00, 0x18, 0x6e, 0x34,
1240x6f, 0x3d, 0x01, 0x01, 0x00, 0x04, 0x01, 0xb9, 0x01, 0x04, 1240x01, 0x02, 0x89, 0x00, 0x20, 0x67, 0x6f, 0x3d, 0x01, 0x01,
1250x66, 0x00, 0x01, 0x94, 0x05, 0xf1, 0x01, 0x39, 0x2c, 0x00, 1250x00, 0x04, 0x01, 0xb9, 0x01, 0x04, 0x66, 0x00, 0x01, 0x94,
1260x70, 0x6c, 0x75, 0x73, 0x00, 0x60, 0x61, 0x27, 0x2c, 0x00, 1260x05, 0xf1, 0x01, 0x39, 0x2c, 0x00, 0x70, 0x6c, 0x75, 0x73,
1270x60, 0x62, 0x27, 0xac, 0x01, 0x30, 0x60, 0x63, 0x27, 0xb1, 1270x00, 0x60, 0x61, 0x27, 0x2c, 0x00, 0x60, 0x62, 0x27, 0xac,
1280x03, 0x20, 0x69, 0x73, 0xd1, 0x02, 0x21, 0x6e, 0x6f, 0xde, 1280x01, 0x30, 0x60, 0x63, 0x27, 0xb1, 0x03, 0x20, 0x69, 0x73,
1290x05, 0x02, 0x67, 0x00, 0x12, 0x65, 0xc9, 0x01, 0x02, 0x5b, 1290xd1, 0x02, 0x21, 0x6e, 0x6f, 0xde, 0x05, 0x02, 0x67, 0x00,
1300x02, 0x08, 0x88, 0x02, 0xb2, 0x49, 0x00, 0x66, 0x69, 0x72, 1300x12, 0x65, 0xc9, 0x01, 0x02, 0x5b, 0x02, 0x08, 0x88, 0x02,
1310x73, 0x74, 0x00, 0x73, 0x61, 0x77, 0x6d, 0x02, 0x03, 0x11, 1310xb2, 0x49, 0x00, 0x66, 0x69, 0x72, 0x73, 0x74, 0x00, 0x73,
1320x01, 0xf2, 0x0d, 0x69, 0x6e, 0x00, 0x4e, 0x69, 0x6b, 0x6f, 1320x61, 0x77, 0x6d, 0x02, 0x03, 0x11, 0x01, 0xf2, 0x0d, 0x69,
1330x6c, 0x69, 0x00, 0x5b, 0x35, 0x5d, 0x2c, 0x00, 0x61, 0x6c, 1330x6e, 0x00, 0x4e, 0x69, 0x6b, 0x6f, 0x6c, 0x69, 0x00, 0x5b,
1340x74, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x00, 0x69, 0x74, 0x27, 1340x35, 0x5d, 0x2c, 0x00, 0x61, 0x6c, 0x74, 0x68, 0x6f, 0x75,
1350x73, 0xba, 0x03, 0x10, 0x62, 0xdd, 0x02, 0x30, 0x70, 0x6f, 1350x67, 0x68, 0x00, 0x69, 0x74, 0x27, 0x73, 0xba, 0x03, 0x10,
1360x70, 0xa9, 0x03, 0x40, 0x69, 0x73, 0x65, 0x64, 0x41, 0x02, 1360x62, 0xdd, 0x02, 0x30, 0x70, 0x6f, 0x70, 0xa9, 0x03, 0x40,
1370xf0, 0x00, 0x76, 0x61, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x00, 1370x69, 0x73, 0x65, 0x64, 0x41, 0x02, 0xf0, 0x00, 0x76, 0x61,
1380x6e, 0x65, 0x77, 0x73, 0x70, 0x61, 0x70, 0x0c, 0x01, 0x15, 1380x72, 0x69, 0x6f, 0x75, 0x73, 0x00, 0x6e, 0x65, 0x77, 0x73,
1390x75, 0x86, 0x04, 0x10, 0x6e, 0x38, 0x02, 0x80, 0x60, 0x53, 1390x70, 0x61, 0x70, 0x0c, 0x01, 0x15, 0x75, 0x86, 0x04, 0x10,
1400x75, 0x64, 0x6f, 0x6b, 0x75, 0x27, 0x68, 0x04, 0x50, 0x60, 1400x6e, 0x38, 0x02, 0x80, 0x60, 0x53, 0x75, 0x64, 0x6f, 0x6b,
1410x53, 0x75, 0x00, 0x44, 0x0d, 0x00, 0xf1, 0x01, 0x2e, 0x00, 1410x75, 0x27, 0x68, 0x04, 0x50, 0x60, 0x53, 0x75, 0x00, 0x44,
1420x48, 0x6f, 0x77, 0x61, 0x72, 0x64, 0x00, 0x47, 0x61, 0x72, 1420x0d, 0x00, 0xf1, 0x01, 0x2e, 0x00, 0x48, 0x6f, 0x77, 0x61,
1430x6e, 0x73, 0x00, 0x69, 0x50, 0x05, 0x40, 0x73, 0x69, 0x64, 1430x72, 0x64, 0x00, 0x47, 0x61, 0x72, 0x6e, 0x73, 0x00, 0x69,
1440x65, 0x8c, 0x02, 0x20, 0x74, 0x68, 0x8e, 0x00, 0x64, 0x76, 1440x50, 0x05, 0x40, 0x73, 0x69, 0x64, 0x65, 0x8c, 0x02, 0x20,
1450x65, 0x6e, 0x74, 0x6f, 0x72, 0x5a, 0x01, 0x00, 0x12, 0x03, 1450x74, 0x68, 0x8e, 0x00, 0x64, 0x76, 0x65, 0x6e, 0x74, 0x6f,
1460x25, 0x72, 0x6e, 0xf8, 0x02, 0x00, 0x13, 0x00, 0x02, 0xb8, 1460x72, 0x5a, 0x01, 0x00, 0x12, 0x03, 0x25, 0x72, 0x6e, 0xf8,
1470x00, 0x02, 0xb4, 0x02, 0x63, 0x69, 0x74, 0x00, 0x77, 0x61, 1470x02, 0x00, 0x13, 0x00, 0x02, 0xb8, 0x00, 0x02, 0xb4, 0x02,
1480x73, 0xda, 0x00, 0x72, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 1480x63, 0x69, 0x74, 0x00, 0x77, 0x61, 0x73, 0xda, 0x00, 0x72,
1490x68, 0xe2, 0x06, 0xd2, 0x44, 0x65, 0x6c, 0x6c, 0x20, 0x50, 1490x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0xe2, 0x06, 0xd2,
1500x65, 0x6e, 0x63, 0x69, 0x6c, 0x20, 0x50, 0x06, 0x01, 0xd0, 1500x44, 0x65, 0x6c, 0x6c, 0x20, 0x50, 0x65, 0x6e, 0x63, 0x69,
1510x20, 0x61, 0x6e, 0x64, 0x20, 0x57, 0x6f, 0x72, 0x64, 0x20, 1510x6c, 0x20, 0x50, 0x06, 0x01, 0xd0, 0x20, 0x61, 0x6e, 0x64,
1520x47, 0x61, 0x6d, 0x15, 0x01, 0x12, 0x41, 0xfa, 0x01, 0xf5, 1520x20, 0x57, 0x6f, 0x72, 0x64, 0x20, 0x47, 0x61, 0x6d, 0x15,
1530x03, 0x65, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x65, 1530x01, 0x12, 0x41, 0xfa, 0x01, 0xf5, 0x03, 0x65, 0x6c, 0x61,
1540x00, 0x74, 0x72, 0x65, 0x61, 0x74, 0x6d, 0x65, 0x6e, 0x6f, 1540x62, 0x6f, 0x72, 0x61, 0x74, 0x65, 0x00, 0x74, 0x72, 0x65,
1550x05, 0x7a, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x7b, 1550x61, 0x74, 0x6d, 0x65, 0x6e, 0x6f, 0x05, 0x7a, 0x68, 0x69,
1560x00, 0x01, 0x45, 0x04, 0x00, 0x4f, 0x07, 0x00, 0x84, 0x02, 1560x73, 0x74, 0x6f, 0x72, 0x79, 0x7b, 0x00, 0x01, 0x45, 0x04,
1570xf0, 0x02, 0x00, 0x6f, 0x6e, 0x00, 0x57, 0x69, 0x6b, 0x69, 1570x00, 0x4f, 0x07, 0x00, 0x84, 0x02, 0xf0, 0x02, 0x00, 0x6f,
1580x70, 0x65, 0x64, 0x69, 0x61, 0x00, 0x5b, 0x36, 0x5d, 0x6c, 1580x6e, 0x00, 0x57, 0x69, 0x6b, 0x69, 0x70, 0x65, 0x64, 0x69,
1590x01, 0xf1, 0x01, 0x5b, 0x35, 0x5d, 0x00, 0x68, 0x74, 0x74, 1590x61, 0x00, 0x5b, 0x36, 0x5d, 0x6c, 0x01, 0xf1, 0x02, 0x5b,
1600x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 0x60, 1600x35, 0x5d, 0x00, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f,
1610x01, 0xa3, 0x2e, 0x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f, 0x65, 1610x2f, 0x77, 0x77, 0x77, 0x2e, 0x6e, 0x61, 0x01, 0xa3, 0x2e,
1620x6e, 0x2f, 0x96, 0x01, 0x21, 0x2f, 0x73, 0x22, 0x01, 0xc1, 1620x63, 0x6f, 0x2e, 0x6a, 0x70, 0x2f, 0x65, 0x6e, 0x2f, 0x97,
1630x2e, 0x68, 0x74, 0x6d, 0x6c, 0x00, 0x28, 0x62, 0x65, 0x77, 1630x01, 0x21, 0x2f, 0x73, 0x23, 0x01, 0x10, 0x2f, 0x32, 0x00,
1640x61, 0x72, 0x1f, 0x06, 0x60, 0x46, 0x6c, 0x61, 0x73, 0x68, 1640x12, 0x36, 0x32, 0x00, 0x74, 0x3a, 0x2f, 0x2f, 0x65, 0x6e,
1650x29, 0x47, 0x00, 0x15, 0x36, 0x47, 0x00, 0x44, 0x65, 0x6e, 1650x2e, 0x77, 0x51, 0x00, 0x50, 0x2e, 0x6f, 0x72, 0x67, 0x2f,
1660x2e, 0x77, 0x66, 0x00, 0x50, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 1660x0e, 0x00, 0x12, 0x2f, 0x4e, 0x01, 0x72, 0x00, 0x00, 0x00,
1670x0e, 0x00, 0x12, 0x2f, 0x63, 0x01, 0x72, 0x00, 0x00, 0x00, 1670x31, 0x31, 0x2e, 0x31, 0x5c, 0x08, 0x00, 0x8b, 0x06, 0x91,
1680x31, 0x31, 0x2e, 0x31, 0x60, 0x08, 0x00, 0xa0, 0x06, 0x40, 1680x72, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00, 0x00, 0x54, 0x31,
1690x72, 0x6f, 0x6c, 0x73, 0x69, 0x08, 0x11, 0x54, 0x46, 0x06, 1690x06, 0x20, 0x79, 0x00, 0x19, 0x00, 0xe3, 0x2c, 0x00, 0x73,
1700x20, 0x79, 0x00, 0x19, 0x00, 0xe3, 0x2c, 0x00, 0x73, 0x69, 1700x69, 0x6d, 0x70, 0x6c, 0x79, 0x00, 0x63, 0x6c, 0x69, 0x63,
1710x6d, 0x70, 0x6c, 0x79, 0x00, 0x63, 0x6c, 0x69, 0x63, 0x6b, 1710x6b, 0x47, 0x01, 0x21, 0x75, 0x73, 0xeb, 0x01, 0x01, 0x4a,
1720x5c, 0x01, 0x21, 0x75, 0x73, 0x00, 0x02, 0x01, 0x5f, 0x08, 1720x08, 0x44, 0x6d, 0x70, 0x74, 0x79, 0x60, 0x05, 0x00, 0x46,
1730x44, 0x6d, 0x70, 0x74, 0x79, 0x75, 0x05, 0x00, 0x5b, 0x01, 1730x01, 0x02, 0x96, 0x02, 0x35, 0x79, 0x70, 0x65, 0x13, 0x08,
1740x02, 0xab, 0x02, 0x35, 0x79, 0x70, 0x65, 0x28, 0x08, 0x23, 1740x23, 0x6f, 0x72, 0xe3, 0x02, 0x22, 0x00, 0x6f, 0xb0, 0x02,
1750x6f, 0x72, 0xf8, 0x02, 0x22, 0x00, 0x6f, 0xc5, 0x02, 0x50, 1750x50, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0xb9, 0x01, 0x21, 0x74,
1760x6b, 0x65, 0x79, 0x62, 0x6f, 0xce, 0x01, 0x21, 0x74, 0x6f, 1760x6f, 0x7d, 0x04, 0x02, 0xeb, 0x03, 0x02, 0x44, 0x00, 0x14,
1770x92, 0x04, 0x02, 0x00, 0x04, 0x02, 0x44, 0x00, 0x14, 0x2e, 1770x2e, 0x6c, 0x03, 0x30, 0x6d, 0x61, 0x6b, 0x43, 0x00, 0x8f,
1780x81, 0x03, 0x30, 0x6d, 0x61, 0x6b, 0x43, 0x00, 0x8f, 0x6d, 1780x6d, 0x69, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x2c, 0x80, 0x00,
1790x69, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x2c, 0x80, 0x00, 0x01, 1790x01, 0x02, 0xe4, 0x01, 0x03, 0xbe, 0x06, 0x08, 0x84, 0x00,
1800x02, 0xf9, 0x01, 0x03, 0xd3, 0x06, 0x08, 0x84, 0x00, 0x81, 1800x81, 0x70, 0x72, 0x65, 0x73, 0x73, 0x00, 0x53, 0x70, 0xf5,
1810x70, 0x72, 0x65, 0x73, 0x73, 0x00, 0x53, 0x70, 0x0a, 0x07, 1810x06, 0x40, 0x6f, 0x00, 0x63, 0x6c, 0x21, 0x04, 0x50, 0x69,
1820x40, 0x6f, 0x00, 0x63, 0x6c, 0x36, 0x04, 0x50, 0x69, 0x74, 1820x74, 0x00, 0x61, 0x67, 0x80, 0x07, 0x62, 0x28, 0x6f, 0x72,
1830x00, 0x61, 0x67, 0x95, 0x07, 0x62, 0x28, 0x6f, 0x72, 0x00, 1830x00, 0x75, 0x73, 0x96, 0x04, 0xd7, 0x55, 0x6e, 0x64, 0x6f,
1840x75, 0x73, 0xab, 0x04, 0xd7, 0x55, 0x6e, 0x64, 0x6f, 0x00, 1840x00, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x29, 0xea,
1850x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x29, 0xff, 0x03, 1850x03, 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x2d, 0x74, 0x00,
1860x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x2d, 0x74, 0x00, 0x01, 1860x01, 0x47, 0x04, 0x0f, 0xe2, 0x00, 0x04, 0x02, 0x43, 0x07,
1870x5c, 0x04, 0x0f, 0xe2, 0x00, 0x04, 0x02, 0x58, 0x07, 0x12, 1870x12, 0x2c, 0xc2, 0x00, 0x02, 0x0d, 0x00, 0x05, 0x72, 0x03,
1880x2c, 0xc2, 0x00, 0x02, 0x0d, 0x00, 0x05, 0x87, 0x03, 0x52, 1880x52, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x41, 0x02, 0x06, 0x09,
1890x65, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x02, 0x06, 0x1e, 0x08, 1890x08, 0x00, 0x79, 0x06, 0x41, 0x61, 0x00, 0x60, 0x70, 0x4d,
1900x00, 0x8e, 0x06, 0x41, 0x61, 0x00, 0x60, 0x70, 0x62, 0x02, 1900x02, 0x66, 0x00, 0x6d, 0x61, 0x72, 0x6b, 0x27, 0xdc, 0x06,
1910x66, 0x00, 0x6d, 0x61, 0x72, 0x6b, 0x27, 0xf1, 0x06, 0x01, 1910x01, 0xc9, 0x09, 0x07, 0x1b, 0x00, 0x11, 0x73, 0x7f, 0x03,
1920xde, 0x09, 0x07, 0x1b, 0x00, 0x11, 0x73, 0x94, 0x03, 0x76, 1920x76, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0xb0, 0x07,
1930x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0xc5, 0x07, 0x04, 1930x04, 0x51, 0x00, 0x00, 0x1a, 0x03, 0x04, 0x36, 0x01, 0x12,
1940x51, 0x00, 0x00, 0x2f, 0x03, 0x04, 0x36, 0x01, 0x12, 0x53, 1940x53, 0xbb, 0x05, 0x04, 0x53, 0x08, 0x00, 0xc0, 0x04, 0x06,
1950xd0, 0x05, 0x04, 0x68, 0x08, 0x00, 0xd5, 0x04, 0x06, 0xed, 1950xd8, 0x05, 0x05, 0xe9, 0x07, 0x02, 0xe0, 0x03, 0x01, 0x89,
1960x05, 0x05, 0xfe, 0x07, 0x02, 0xf5, 0x03, 0x01, 0x9e, 0x03, 1960x03, 0x03, 0x29, 0x00, 0x09, 0x6f, 0x00, 0x10, 0x2e, 0xfd,
1970x03, 0x29, 0x00, 0x09, 0x6f, 0x00, 0x10, 0x2e, 0xfd, 0x01, 1970x01, 0x04, 0xac, 0x05, 0x40, 0x70, 0x61, 0x79, 0x73, 0x6a,
1980x04, 0xc1, 0x05, 0x40, 0x70, 0x61, 0x79, 0x73, 0x7f, 0x05, 1980x05, 0x50, 0x61, 0x74, 0x74, 0x65, 0x6e, 0xba, 0x04, 0x01,
1990x50, 0x61, 0x74, 0x74, 0x65, 0x6e, 0xcf, 0x04, 0x01, 0x5e, 1990x49, 0x08, 0x07, 0x2e, 0x00, 0x40, 0x2c, 0x00, 0x73, 0x6f,
2000x08, 0x07, 0x2e, 0x00, 0x40, 0x2c, 0x00, 0x73, 0x6f, 0xb5, 2000xa0, 0x04, 0x00, 0x3a, 0x08, 0x02, 0xd0, 0x05, 0x00, 0x3a,
2010x04, 0x00, 0x4f, 0x08, 0x02, 0xe5, 0x05, 0x00, 0x3a, 0x01, 2010x01, 0x03, 0x5a, 0x01, 0x11, 0x6d, 0xbb, 0x00, 0x50, 0x69,
2020x03, 0x5a, 0x01, 0x11, 0x6d, 0xbb, 0x00, 0x50, 0x69, 0x73, 2020x73, 0x00, 0x75, 0x70, 0x38, 0x00, 0x45, 0x79, 0x6f, 0x75,
2030x00, 0x75, 0x70, 0x38, 0x00, 0x45, 0x79, 0x6f, 0x75, 0x3a, 2030x3a, 0x34, 0x07, 0x05, 0x23, 0x00, 0x00, 0x61, 0x0a, 0x30,
2040x49, 0x07, 0x05, 0x23, 0x00, 0x00, 0x76, 0x0a, 0x30, 0x65, 2040x65, 0x6d, 0x69, 0xec, 0x03, 0x12, 0x73, 0x43, 0x01, 0x81,
2050x6d, 0x69, 0x01, 0x04, 0x12, 0x73, 0x43, 0x01, 0x81, 0x61, 2050x61, 0x00, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0xc8, 0x07,
2060x00, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0xdd, 0x07, 0x03, 2060x03, 0x32, 0x01, 0x41, 0x6e, 0x65, 0x65, 0x64, 0xc6, 0x08,
2070x32, 0x01, 0x41, 0x6e, 0x65, 0x65, 0x64, 0xdb, 0x08, 0x10, 2070x10, 0x62, 0xbf, 0x08, 0x10, 0x2d, 0x12, 0x05, 0x42, 0x69,
2080x62, 0xd4, 0x08, 0x10, 0x2d, 0x27, 0x05, 0x42, 0x69, 0x6e, 2080x6e, 0x65, 0x64, 0xe8, 0x05, 0x00, 0x54, 0x00, 0x42, 0x6b,
2090x65, 0x64, 0xfd, 0x05, 0x00, 0x54, 0x00, 0x42, 0x6b, 0x6e, 2090x6e, 0x6f, 0x77, 0x7e, 0x03, 0x4b, 0x61, 0x62, 0x6f, 0x75,
2100x6f, 0x77, 0x93, 0x03, 0x4b, 0x61, 0x62, 0x6f, 0x75, 0x45, 2100x45, 0x00, 0x04, 0xa2, 0x01, 0x2f, 0x6f, 0x72, 0x80, 0x00,
2110x00, 0x04, 0xa2, 0x01, 0x2f, 0x6f, 0x72, 0x80, 0x00, 0x02, 2110x02, 0x55, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x93, 0x03, 0x5a,
2120x55, 0x6c, 0x69, 0x73, 0x74, 0x73, 0xa8, 0x03, 0x5a, 0x6f, 2120x6f, 0x73, 0x73, 0x69, 0x62, 0x6a, 0x01, 0x14, 0x61, 0x70,
2130x73, 0x73, 0x69, 0x62, 0x6a, 0x01, 0x14, 0x61, 0x85, 0x09, 2130x09, 0x01, 0x8d, 0x00, 0x01, 0x48, 0x00, 0x50, 0x61, 0x6e,
2140x01, 0x8d, 0x00, 0x01, 0x48, 0x00, 0x50, 0x61, 0x6e, 0x79, 2140x79, 0x74, 0x68, 0x62, 0x01, 0x32, 0x65, 0x6c, 0x73, 0x82,
2150x74, 0x68, 0x62, 0x01, 0x32, 0x65, 0x6c, 0x73, 0x82, 0x00, 2150x00, 0xa2, 0x66, 0x65, 0x65, 0x6c, 0x00, 0x6c, 0x69, 0x6b,
2160xa2, 0x66, 0x65, 0x65, 0x6c, 0x00, 0x6c, 0x69, 0x6b, 0x65, 2160x65, 0x2e, 0x3f, 0x03, 0x41, 0x65, 0x72, 0x61, 0x73, 0x93,
2170x2e, 0x3f, 0x03, 0x41, 0x65, 0x72, 0x61, 0x73, 0xa8, 0x0b, 2170x0b, 0x49, 0x69, 0x6e, 0x67, 0x6c, 0xd3, 0x01, 0x1c, 0x2c,
2180x49, 0x69, 0x6e, 0x67, 0x6c, 0xd3, 0x01, 0x1c, 0x2c, 0x5b, 2180x5b, 0x02, 0x08, 0x1b, 0x02, 0x22, 0x6e, 0x64, 0x58, 0x02,
2190x02, 0x08, 0x1b, 0x02, 0x22, 0x6e, 0x64, 0x58, 0x02, 0x05, 2190x05, 0xde, 0x01, 0x03, 0x52, 0x02, 0x01, 0xb8, 0x02, 0x01,
2200xde, 0x01, 0x03, 0x52, 0x02, 0x01, 0xb8, 0x02, 0x01, 0x15, 2200x00, 0x08, 0x2a, 0x6c, 0x6c, 0x20, 0x02, 0x09, 0x9c, 0x02,
2210x08, 0x2a, 0x6c, 0x6c, 0x20, 0x02, 0x09, 0x9c, 0x02, 0x22, 2210x22, 0x72, 0x65, 0x79, 0x00, 0x30, 0x64, 0x00, 0x77, 0xa3,
2220x72, 0x65, 0x79, 0x00, 0x30, 0x64, 0x00, 0x77, 0xa3, 0x02, 2220x02, 0x00, 0x99, 0x00, 0x34, 0x6c, 0x65, 0x66, 0x6c, 0x00,
2230x00, 0x99, 0x00, 0x34, 0x6c, 0x65, 0x66, 0x6c, 0x00, 0x05, 2230x05, 0x5e, 0x00, 0x18, 0x61, 0x14, 0x01, 0x0f, 0x2a, 0x00,
2240x5e, 0x00, 0x18, 0x61, 0x14, 0x01, 0x0f, 0x2a, 0x00, 0x05, 2240x05, 0x02, 0x43, 0x03, 0x10, 0x73, 0x43, 0x03, 0x36, 0x2e,
2250x02, 0x43, 0x03, 0x10, 0x73, 0x43, 0x03, 0x36, 0x2e, 0x00, 2250x00, 0x52, 0xb3, 0x00, 0x00, 0xf7, 0x00, 0x05, 0x20, 0x00,
2260x52, 0xb3, 0x00, 0x00, 0xf7, 0x00, 0x05, 0x20, 0x00, 0x00, 2260x00, 0x0d, 0x00, 0x01, 0x23, 0x00, 0x02, 0xf4, 0x02, 0x01,
2270x0d, 0x00, 0x01, 0x23, 0x00, 0x02, 0xf4, 0x02, 0x01, 0x58, 2270x58, 0x02, 0x02, 0xfb, 0x00, 0x0c, 0x56, 0x02, 0x0b, 0x3e,
2280x02, 0x02, 0xfb, 0x00, 0x0c, 0x56, 0x02, 0x0b, 0x53, 0x09, 2280x09, 0x04, 0x7f, 0x03, 0x60, 0x63, 0x75, 0x72, 0x73, 0x6f,
2290x04, 0x7f, 0x03, 0x60, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 2290x72, 0x11, 0x04, 0x01, 0xe1, 0x01, 0x32, 0x6d, 0x6f, 0x76,
2300x11, 0x04, 0x01, 0xe1, 0x01, 0x32, 0x6d, 0x6f, 0x76, 0x18, 2300x18, 0x00, 0x00, 0x38, 0x00, 0x31, 0x00, 0x61, 0x72, 0x14,
2310x00, 0x00, 0x38, 0x00, 0x31, 0x00, 0x61, 0x72, 0x29, 0x05, 2310x05, 0x04, 0x83, 0x08, 0x34, 0x2e, 0x00, 0x50, 0x74, 0x00,
2320x04, 0x98, 0x08, 0x34, 0x2e, 0x00, 0x50, 0x74, 0x00, 0x02, 2320x02, 0xc9, 0x0a, 0x40, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x00,
2330xde, 0x0a, 0x40, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x00, 0x86, 2330x86, 0x00, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x73, 0x3a,
2340x00, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x73, 0x3a, 0x00, 2340x00, 0x11, 0x28, 0x86, 0x0c, 0x82, 0x61, 0x00, 0x6e, 0x6f,
2350x11, 0x28, 0x9b, 0x0c, 0x82, 0x61, 0x00, 0x6e, 0x6f, 0x72, 2350x72, 0x6d, 0x61, 0x6c, 0x14, 0x00, 0x00, 0xfe, 0x0c, 0x08,
2360x6d, 0x61, 0x6c, 0x14, 0x00, 0x00, 0x13, 0x0d, 0x08, 0x97, 2360x97, 0x00, 0x24, 0x29, 0x2c, 0x12, 0x01, 0x01, 0xd3, 0x00,
2370x00, 0x24, 0x29, 0x2c, 0x12, 0x01, 0x01, 0xd3, 0x00, 0x04, 2370x04, 0x6b, 0x01, 0x20, 0x69, 0x6e, 0xb5, 0x02, 0x0f, 0xbb,
2380x6b, 0x01, 0x20, 0x69, 0x6e, 0xb5, 0x02, 0x0f, 0xbb, 0x03, 2380x03, 0x03, 0x03, 0x0e, 0x00, 0x80, 0x61, 0x70, 0x70, 0x72,
2390x03, 0x03, 0x0e, 0x00, 0x80, 0x61, 0x70, 0x70, 0x72, 0x6f, 2390x6f, 0x70, 0x72, 0x69, 0xe5, 0x05, 0x44, 0x77, 0x61, 0x79,
2400x70, 0x72, 0x69, 0xfa, 0x05, 0x44, 0x77, 0x61, 0x79, 0x3b, 2400x3b, 0x44, 0x00, 0x01, 0x8c, 0x01, 0x21, 0x30, 0x00, 0x5e,
2410x44, 0x00, 0x01, 0x8c, 0x01, 0x21, 0x30, 0x00, 0x5e, 0x04, 2410x04, 0x04, 0xa6, 0x00, 0x02, 0x1e, 0x01, 0x23, 0x62, 0x61,
2420x04, 0xa6, 0x00, 0x02, 0x1e, 0x01, 0x23, 0x62, 0x61, 0x16, 2420x16, 0x04, 0x02, 0x8a, 0x04, 0x14, 0x61, 0x3d, 0x0d, 0x04,
2430x04, 0x02, 0x8a, 0x04, 0x14, 0x61, 0x52, 0x0d, 0x04, 0xbd, 2430xbd, 0x03, 0x43, 0x00, 0x00, 0x28, 0x41, 0x00, 0x09, 0x30,
2440x03, 0x43, 0x00, 0x00, 0x28, 0x41, 0x15, 0x09, 0x30, 0x61, 2440x61, 0x63, 0x74, 0x75, 0x08, 0x82, 0x00, 0x64, 0x65, 0x73,
2450x63, 0x74, 0x8a, 0x08, 0x82, 0x00, 0x64, 0x65, 0x73, 0x63, 2450x63, 0x72, 0x69, 0x62, 0x84, 0x00, 0x31, 0x73, 0x65, 0x63,
2460x72, 0x69, 0x62, 0x84, 0x00, 0x31, 0x73, 0x65, 0x63, 0x81, 2460x81, 0x03, 0x32, 0x32, 0x2e, 0x31, 0x43, 0x0a, 0x00, 0x69,
2470x03, 0x32, 0x32, 0x2e, 0x31, 0x58, 0x0a, 0x00, 0x69, 0x01, 2470x01, 0x05, 0x04, 0x0a, 0x22, 0x2e, 0x29, 0xca, 0x05, 0x12,
2480x05, 0x19, 0x0a, 0x22, 0x2e, 0x29, 0xca, 0x05, 0x12, 0x32, 2480x32, 0xca, 0x05, 0x60, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65,
2490xca, 0x05, 0x60, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x67, 2490x52, 0x08, 0x00, 0xcc, 0x05, 0x00, 0x13, 0x00, 0x00, 0x5d,
2500x08, 0x00, 0xcc, 0x05, 0x00, 0x13, 0x00, 0x00, 0x72, 0x09, 2500x09, 0x22, 0x6f, 0x77, 0x78, 0x09, 0x11, 0x74, 0xfa, 0x03,
2510x22, 0x6f, 0x77, 0x8d, 0x09, 0x11, 0x74, 0xfa, 0x03, 0x40, 2510x40, 0x66, 0x69, 0x67, 0x75, 0xa7, 0x08, 0x10, 0x77, 0x4b,
2520x66, 0x69, 0x67, 0x75, 0xbc, 0x08, 0x10, 0x77, 0x60, 0x0b, 2520x0b, 0x00, 0x31, 0x00, 0x10, 0x74, 0x46, 0x08, 0x41, 0x6d,
2530x00, 0x31, 0x00, 0x10, 0x74, 0x5b, 0x08, 0x41, 0x6d, 0x65, 2530x65, 0x6e, 0x73, 0x7d, 0x00, 0x0a, 0xa2, 0x06, 0x01, 0x47,
2540x6e, 0x73, 0x7d, 0x00, 0x0a, 0xb7, 0x06, 0x01, 0x5c, 0x08, 2540x08, 0x03, 0xbb, 0x05, 0xc7, 0x60, 0x54, 0x79, 0x70, 0x65,
2550x03, 0xbb, 0x05, 0xc7, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 2550x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0x3a, 0x44, 0x0c, 0x00,
2560x00, 0x6d, 0x65, 0x6e, 0x75, 0x3a, 0x59, 0x0c, 0x00, 0x32, 2560x32, 0x00, 0x02, 0x84, 0x0d, 0x03, 0x00, 0x0a, 0x0a, 0x1b,
2570x00, 0x02, 0x99, 0x0d, 0x03, 0x15, 0x0a, 0x0a, 0x1b, 0x00, 2570x00, 0x00, 0x46, 0x0e, 0x12, 0x2c, 0x38, 0x0a, 0x06, 0x17,
2580x00, 0x5b, 0x0e, 0x12, 0x2c, 0x4d, 0x0a, 0x06, 0x2c, 0x0b, 2580x0b, 0x01, 0x0c, 0x0d, 0x0b, 0x5c, 0x0a, 0x47, 0x2e, 0x00,
2590x01, 0x21, 0x0d, 0x0b, 0x71, 0x0a, 0x47, 0x2e, 0x00, 0x28, 2590x28, 0x54, 0x37, 0x0e, 0x13, 0x61, 0x9d, 0x0d, 0x25, 0x69,
2600x54, 0x4c, 0x0e, 0x13, 0x61, 0xb2, 0x0d, 0x25, 0x69, 0x73, 2600x73, 0xd0, 0x07, 0x23, 0x72, 0x73, 0xf6, 0x0c, 0x5f, 0x69,
2610xe5, 0x07, 0x23, 0x72, 0x73, 0x0b, 0x0d, 0x5f, 0x69, 0x73, 2610x73, 0x3a, 0x00, 0x66, 0x21, 0x09, 0x07, 0x14, 0x32, 0x90,
2620x3a, 0x00, 0x66, 0x36, 0x09, 0x07, 0x14, 0x32, 0x90, 0x00, 2620x00, 0x01, 0x8f, 0x00, 0x13, 0x33, 0x83, 0x00, 0x01, 0x93,
2630x01, 0x8f, 0x00, 0x13, 0x33, 0x83, 0x00, 0x01, 0xa8, 0x0a, 2630x0a, 0x03, 0x76, 0x0c, 0x02, 0x5b, 0x00, 0x01, 0x97, 0x01,
2640x03, 0x8b, 0x0c, 0x02, 0x5b, 0x00, 0x01, 0x97, 0x01, 0x01, 2640x01, 0x78, 0x05, 0x19, 0x33, 0x32, 0x00, 0x12, 0x32, 0xfb,
2650x78, 0x05, 0x19, 0x33, 0x32, 0x00, 0x12, 0x32, 0x10, 0x0f, 2650x0e, 0x16, 0x29, 0x13, 0x06, 0x14, 0x74, 0x80, 0x06, 0xd2,
2660x16, 0x29, 0x13, 0x06, 0x14, 0x74, 0x80, 0x06, 0xd2, 0x60, 2660x60, 0x58, 0x27, 0x00, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x62,
2670x58, 0x27, 0x00, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x62, 0x6f, 2670x6f, 0x78, 0x2c, 0x61, 0x01, 0x02, 0xff, 0x02, 0x10, 0x70,
2680x78, 0x2c, 0x61, 0x01, 0x02, 0xff, 0x02, 0x10, 0x70, 0x28, 2680x28, 0x07, 0x00, 0x22, 0x00, 0x04, 0x1c, 0x0e, 0x61, 0x00,
2690x07, 0x00, 0x22, 0x00, 0x04, 0x31, 0x0e, 0x61, 0x00, 0x65, 2690x65, 0x78, 0x74, 0x72, 0x61, 0x97, 0x08, 0x50, 0x74, 0x72,
2700x78, 0x74, 0x72, 0x61, 0xac, 0x08, 0x50, 0x74, 0x72, 0x61, 2700x61, 0x69, 0x6e, 0xf2, 0x0a, 0x03, 0xf7, 0x0a, 0x0e, 0x0e,
2710x69, 0x6e, 0x07, 0x0b, 0x03, 0x0c, 0x0b, 0x0e, 0x23, 0x0e, 2710x0e, 0x08, 0x28, 0x0f, 0x0a, 0xa3, 0x05, 0x01, 0x19, 0x0e,
2720x08, 0x3d, 0x0f, 0x0a, 0xa3, 0x05, 0x01, 0x2e, 0x0e, 0x13, 2720x13, 0x66, 0xaf, 0x0e, 0x03, 0x0f, 0x0e, 0x11, 0x28, 0xb1,
2730x66, 0xc4, 0x0e, 0x03, 0x24, 0x0e, 0x11, 0x28, 0xc6, 0x09, 2730x09, 0x21, 0x69, 0x73, 0x08, 0x0e, 0x51, 0x74, 0x69, 0x6d,
2740x21, 0x69, 0x73, 0x1d, 0x0e, 0x51, 0x74, 0x69, 0x6d, 0x65, 2740x65, 0x73, 0x07, 0x05, 0x10, 0x6e, 0xd4, 0x04, 0x03, 0x2e,
2750x73, 0x07, 0x05, 0x10, 0x6e, 0xd4, 0x04, 0x03, 0x43, 0x09, 2750x09, 0x30, 0x2d, 0x58, 0x27, 0x3d, 0x02, 0x06, 0x56, 0x09,
2760x30, 0x2d, 0x58, 0x27, 0x3d, 0x02, 0x06, 0x6b, 0x09, 0x2b, 2760x2b, 0x2e, 0x29, 0x1d, 0x0c, 0x06, 0xdc, 0x02, 0x00, 0x83,
2770x2e, 0x29, 0x32, 0x0c, 0x06, 0xdc, 0x02, 0x00, 0x98, 0x0e, 2770x0e, 0x0f, 0x98, 0x00, 0x05, 0x04, 0xd0, 0x06, 0x40, 0x73,
2780x0f, 0x98, 0x00, 0x05, 0x04, 0xd0, 0x06, 0x40, 0x73, 0x68, 2780x68, 0x61, 0x64, 0xb5, 0x02, 0x10, 0x6c, 0x0e, 0x04, 0x00,
2790x61, 0x64, 0xb5, 0x02, 0x10, 0x6c, 0x0e, 0x04, 0x00, 0x52, 2790x3d, 0x10, 0x12, 0x6f, 0xcf, 0x00, 0x05, 0x83, 0x05, 0x01,
2800x10, 0x12, 0x6f, 0xcf, 0x00, 0x05, 0x83, 0x05, 0x01, 0xfb, 2800xe6, 0x09, 0x20, 0x65, 0x6e, 0x94, 0x02, 0x2f, 0x64, 0x2e,
2810x09, 0x20, 0x65, 0x6e, 0x94, 0x02, 0x2f, 0x64, 0x2e, 0x39, 2810x39, 0x01, 0x01, 0x13, 0x4a, 0x25, 0x0d, 0x0f, 0x3e, 0x01,
2820x01, 0x01, 0x13, 0x4a, 0x3a, 0x0d, 0x0f, 0x3e, 0x01, 0x01, 2820x01, 0x41, 0x67, 0x65, 0x6e, 0x65, 0x88, 0x02, 0x73, 0x72,
2830x41, 0x67, 0x65, 0x6e, 0x65, 0x88, 0x02, 0x73, 0x72, 0x61, 2830x61, 0x6e, 0x64, 0x6f, 0x6d, 0x6c, 0x1f, 0x0d, 0x08, 0x9e,
2840x6e, 0x64, 0x6f, 0x6d, 0x6c, 0x34, 0x0d, 0x08, 0xb3, 0x10, 2840x10, 0x1e, 0x2e, 0xbf, 0x00, 0x08, 0x43, 0x0e, 0x03, 0x8f,
2850x1e, 0x2e, 0xbf, 0x00, 0x08, 0x58, 0x0e, 0x03, 0xa4, 0x0b, 2850x0b, 0x03, 0xae, 0x00, 0x00, 0x36, 0x08, 0x13, 0x6e, 0x36,
2860x03, 0xae, 0x00, 0x00, 0x36, 0x08, 0x13, 0x6e, 0x36, 0x06, 2860x06, 0x01, 0xcd, 0x02, 0x5d, 0x72, 0x6f, 0x64, 0x75, 0x63,
2870x01, 0xcd, 0x02, 0x5d, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x11, 2870xfc, 0x0e, 0x0b, 0xea, 0x03, 0x22, 0x60, 0x43, 0x04, 0x02,
2880x0f, 0x0b, 0xea, 0x03, 0x22, 0x60, 0x43, 0x04, 0x02, 0x03, 2880x03, 0x1a, 0x0b, 0x30, 0x52, 0x6f, 0x77, 0xe4, 0x0c, 0x41,
2890x2f, 0x0b, 0x30, 0x52, 0x6f, 0x77, 0xf9, 0x0c, 0x41, 0x6f, 2890x6f, 0x78, 0x65, 0x73, 0xd4, 0x0e, 0x00, 0x05, 0x04, 0x01,
2900x78, 0x65, 0x73, 0xe9, 0x0e, 0x00, 0x05, 0x04, 0x01, 0x15, 2900x15, 0x07, 0x50, 0x72, 0x65, 0x61, 0x73, 0x6f, 0xe5, 0x0d,
2910x07, 0x50, 0x72, 0x65, 0x61, 0x73, 0x6f, 0xfa, 0x0d, 0x34, 2910x34, 0x79, 0x00, 0x79, 0x82, 0x11, 0x22, 0x74, 0x6f, 0x4e,
2920x79, 0x00, 0x79, 0x97, 0x11, 0x22, 0x74, 0x6f, 0x4e, 0x00, 2920x00, 0x06, 0x4d, 0x04, 0x10, 0x67, 0x03, 0x0a, 0x22, 0x65,
2930x06, 0x4d, 0x04, 0x10, 0x67, 0x18, 0x0a, 0x22, 0x65, 0x72, 2930x72, 0x0f, 0x0c, 0x10, 0x31, 0x64, 0x00, 0x42, 0x62, 0x6f,
2940x24, 0x0c, 0x10, 0x31, 0x64, 0x00, 0x42, 0x62, 0x6f, 0x74, 2940x74, 0x68, 0x50, 0x00, 0x22, 0x3b, 0x00, 0x0e, 0x01, 0x02,
2950x68, 0x50, 0x00, 0x22, 0x3b, 0x00, 0x0e, 0x01, 0x02, 0xd7, 2950xc2, 0x0d, 0x21, 0x68, 0x61, 0x57, 0x00, 0x07, 0x2a, 0x02,
2960x0d, 0x21, 0x68, 0x61, 0x57, 0x00, 0x07, 0x2a, 0x02, 0x03, 2960x03, 0x90, 0x01, 0x05, 0xd9, 0x00, 0x05, 0xa4, 0x0a, 0x00,
2970x90, 0x01, 0x05, 0xd9, 0x00, 0x05, 0xb9, 0x0a, 0x00, 0xc2, 2970xc2, 0x06, 0x01, 0xcf, 0x0c, 0x20, 0x62, 0x65, 0xd2, 0x04,
2980x06, 0x01, 0xe4, 0x0c, 0x20, 0x62, 0x65, 0xd2, 0x04, 0x26, 2980x26, 0x72, 0x69, 0x28, 0x06, 0x2a, 0x69, 0x66, 0x8e, 0x06,
2990x72, 0x69, 0x28, 0x06, 0x2a, 0x69, 0x66, 0x8e, 0x06, 0x3f, 2990x3f, 0x00, 0x69, 0x74, 0x88, 0x01, 0x02, 0x12, 0x4b, 0x2c,
3000x00, 0x69, 0x74, 0x88, 0x01, 0x02, 0x12, 0x4b, 0x41, 0x0e, 3000x0e, 0x0f, 0x88, 0x01, 0x0b, 0x10, 0x61, 0xf9, 0x0f, 0x00,
3010x0f, 0x88, 0x01, 0x0b, 0x10, 0x61, 0x0e, 0x10, 0x00, 0x2f, 3010x2f, 0x01, 0x00, 0xdc, 0x03, 0x00, 0xed, 0x0d, 0x04, 0x55,
3020x01, 0x00, 0xdc, 0x03, 0x00, 0x02, 0x0e, 0x04, 0x6a, 0x12, 3020x12, 0x2e, 0x61, 0x72, 0xa5, 0x01, 0x00, 0x9c, 0x00, 0x41,
3030x2e, 0x61, 0x72, 0xa5, 0x01, 0x00, 0x9c, 0x00, 0x41, 0x64, 3030x64, 0x72, 0x61, 0x77, 0x5d, 0x0e, 0x00, 0x84, 0x0d, 0x20,
3040x72, 0x61, 0x77, 0x72, 0x0e, 0x00, 0x99, 0x0d, 0x20, 0x75, 3040x75, 0x74, 0x0e, 0x0e, 0x02, 0xc5, 0x03, 0x02, 0xdb, 0x0e,
3050x74, 0x23, 0x0e, 0x02, 0xc5, 0x03, 0x02, 0xf0, 0x0e, 0x00, 3050x00, 0x0a, 0x0b, 0x02, 0x2b, 0x0e, 0x03, 0x51, 0x12, 0x02,
3060x1f, 0x0b, 0x02, 0x40, 0x0e, 0x03, 0x66, 0x12, 0x02, 0x8a, 3060x8a, 0x01, 0x24, 0x73, 0x65, 0x69, 0x0d, 0x06, 0x0f, 0x11,
3070x01, 0x24, 0x73, 0x65, 0x7e, 0x0d, 0x06, 0x24, 0x11, 0x51, 3070x51, 0x61, 0x00, 0x73, 0x6d, 0x61, 0x74, 0x0c, 0x00, 0xbf,
3080x61, 0x00, 0x73, 0x6d, 0x61, 0x89, 0x0c, 0x00, 0xd4, 0x0e, 3080x0e, 0x03, 0x77, 0x00, 0x20, 0x73, 0x68, 0xc4, 0x04, 0x05,
3090x03, 0x77, 0x00, 0x20, 0x73, 0x68, 0xc4, 0x04, 0x05, 0x05, 3090xf0, 0x0c, 0x0c, 0x39, 0x0e, 0x04, 0xc8, 0x02, 0x13, 0x69,
3100x0d, 0x0c, 0x4e, 0x0e, 0x04, 0xc8, 0x02, 0x13, 0x69, 0x23, 3100x23, 0x02, 0x02, 0x55, 0x00, 0x04, 0x38, 0x11, 0x05, 0x3a,
3110x02, 0x02, 0x55, 0x00, 0x04, 0x4d, 0x11, 0x05, 0x4f, 0x10, 3110x10, 0x07, 0xfd, 0x04, 0x22, 0x68, 0x65, 0x10, 0x07, 0x00,
3120x07, 0xfd, 0x04, 0x22, 0x68, 0x65, 0x10, 0x07, 0x00, 0x35, 3120x20, 0x10, 0x71, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x79,
3130x10, 0x71, 0x79, 0x6d, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x65, 3130x65, 0x00, 0x05, 0x21, 0x0f, 0x04, 0x0b, 0x01, 0x16, 0x64,
3140x00, 0x05, 0x36, 0x0f, 0x04, 0x0b, 0x01, 0x16, 0x64, 0x10, 3140xfb, 0x0c, 0x10, 0x4d, 0x66, 0x08, 0x05, 0x2e, 0x00, 0x00,
3150x0d, 0x10, 0x4d, 0x66, 0x08, 0x05, 0x2e, 0x00, 0x00, 0xa4, 3150xa4, 0x0a, 0x17, 0x73, 0x2b, 0x05, 0x60, 0x73, 0x00, 0x6c,
3160x0a, 0x17, 0x73, 0x2b, 0x05, 0x60, 0x73, 0x00, 0x6c, 0x6f, 3160x6f, 0x6f, 0x6b, 0x1c, 0x07, 0x30, 0x74, 0x74, 0x69, 0xcd,
3170x6f, 0x6b, 0x1c, 0x07, 0x30, 0x74, 0x74, 0x69, 0xe2, 0x0f, 3170x0f, 0x13, 0x75, 0xa3, 0x0e, 0x00, 0x7a, 0x00, 0x01, 0xd1,
3180x13, 0x75, 0xb8, 0x0e, 0x00, 0x7a, 0x00, 0x01, 0xd1, 0x0a, 3180x0a, 0x01, 0x77, 0x08, 0x60, 0x65, 0x61, 0x73, 0x69, 0x65,
3190x01, 0x77, 0x08, 0x60, 0x65, 0x61, 0x73, 0x69, 0x65, 0x72, 3190x72, 0x5a, 0x0b, 0x13, 0x6e, 0x96, 0x11, 0x05, 0x52, 0x00,
3200x5a, 0x0b, 0x13, 0x6e, 0xab, 0x11, 0x05, 0x52, 0x00, 0x06, 3200x06, 0x01, 0x02, 0x01, 0xae, 0x09, 0x00, 0xe2, 0x04, 0x22,
3210x01, 0x02, 0x01, 0xae, 0x09, 0x00, 0xe2, 0x04, 0x22, 0x63, 3210x63, 0x65, 0xdc, 0x08, 0x02, 0xca, 0x0f, 0x01, 0x4b, 0x02,
3220x65, 0xdc, 0x08, 0x02, 0xdf, 0x0f, 0x01, 0x4b, 0x02, 0x60, 3220x60, 0x6e, 0x65, 0x63, 0x65, 0x73, 0x73, 0x43, 0x10, 0x02,
3230x6e, 0x65, 0x63, 0x65, 0x73, 0x73, 0x58, 0x10, 0x02, 0xe0, 3230xe0, 0x02, 0x00, 0x8d, 0x07, 0x70, 0x65, 0x6e, 0x74, 0x2e,
3240x02, 0x00, 0x8d, 0x07, 0x70, 0x65, 0x6e, 0x74, 0x2e, 0x00, 3240x00, 0x43, 0x6f, 0x0c, 0x05, 0x63, 0x74, 0x65, 0x6c, 0x79,
3250x43, 0x6f, 0x0c, 0x05, 0x63, 0x74, 0x65, 0x6c, 0x79, 0x00, 3250x00, 0x61, 0x54, 0x00, 0x25, 0x69, 0x63, 0x9d, 0x00, 0x02,
3260x61, 0x54, 0x00, 0x25, 0x69, 0x63, 0x9d, 0x00, 0x02, 0xa6, 3260xa6, 0x02, 0x00, 0xfa, 0x0f, 0x86, 0x72, 0x65, 0x65, 0x64,
3270x02, 0x00, 0x0f, 0x10, 0x86, 0x72, 0x65, 0x65, 0x64, 0x6f, 3270x6f, 0x6d, 0x00, 0x74, 0x64, 0x04, 0x00, 0xf9, 0x0c, 0x24,
3280x6d, 0x00, 0x74, 0x64, 0x04, 0x00, 0x0e, 0x0d, 0x24, 0x65, 3280x65, 0x77, 0x2f, 0x10, 0x15, 0x73, 0x0b, 0x09, 0x00, 0x41,
3290x77, 0x44, 0x10, 0x15, 0x73, 0x0b, 0x09, 0x00, 0x41, 0x01, 3290x01, 0x23, 0x46, 0x69, 0xe8, 0x12, 0x04, 0x41, 0x09, 0x0a,
3300x23, 0x46, 0x69, 0xfd, 0x12, 0x04, 0x41, 0x09, 0x0a, 0x45, 3300x45, 0x01, 0x00, 0xdf, 0x01, 0x00, 0x6d, 0x09, 0x15, 0x74,
3310x01, 0x00, 0xdf, 0x01, 0x00, 0x6d, 0x09, 0x15, 0x74, 0xf0, 3310xdb, 0x0c, 0x0f, 0x39, 0x01, 0x00, 0x16, 0x44, 0x25, 0x00,
3320x0c, 0x0f, 0x39, 0x01, 0x00, 0x16, 0x44, 0x25, 0x00, 0x52, 3320x52, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x94, 0x10, 0x42, 0x6a,
3330x6c, 0x65, 0x76, 0x65, 0x6c, 0xa9, 0x10, 0x42, 0x6a, 0x75, 3330x75, 0x64, 0x67, 0x04, 0x0e, 0x01, 0x0e, 0x08, 0x01, 0xbe,
3340x64, 0x67, 0x19, 0x0e, 0x01, 0x0e, 0x08, 0x01, 0xbe, 0x00, 3340x00, 0x26, 0x78, 0x69, 0x49, 0x00, 0x82, 0x74, 0x65, 0x63,
3350x26, 0x78, 0x69, 0x49, 0x00, 0x82, 0x74, 0x65, 0x63, 0x68, 3350x68, 0x6e, 0x69, 0x71, 0x75, 0x9a, 0x0f, 0x42, 0x64, 0x65,
3360x6e, 0x69, 0x71, 0x75, 0xaf, 0x0f, 0x42, 0x64, 0x65, 0x64, 3360x64, 0x75, 0x09, 0x07, 0x03, 0x6e, 0x0f, 0x01, 0x42, 0x0c,
3370x75, 0x09, 0x07, 0x03, 0x83, 0x0f, 0x01, 0x42, 0x0c, 0x57, 3370x57, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x85, 0x01, 0x12, 0x3a,
3380x73, 0x6f, 0x6c, 0x76, 0x65, 0x85, 0x01, 0x12, 0x3a, 0xe6, 3380xe6, 0x05, 0x01, 0x66, 0x00, 0x06, 0x97, 0x0f, 0x12, 0x61,
3390x05, 0x01, 0x66, 0x00, 0x06, 0xac, 0x0f, 0x12, 0x61, 0x68, 3390x68, 0x03, 0x23, 0x6f, 0x66, 0xbb, 0x03, 0x00, 0xa1, 0x07,
3400x03, 0x23, 0x6f, 0x66, 0xbb, 0x03, 0x00, 0xa1, 0x07, 0x02, 3400x02, 0x58, 0x02, 0x11, 0x77, 0x7b, 0x03, 0x17, 0x74, 0x55,
3410x58, 0x02, 0x11, 0x77, 0x7b, 0x03, 0x17, 0x74, 0x55, 0x01, 3410x01, 0x23, 0x69, 0x6e, 0x32, 0x04, 0x21, 0x65, 0x76, 0x98,
3420x23, 0x69, 0x6e, 0x32, 0x04, 0x21, 0x65, 0x76, 0xad, 0x0e, 3420x0e, 0x31, 0x6f, 0x6e, 0x65, 0x7b, 0x04, 0x06, 0x56, 0x0a,
3430x31, 0x6f, 0x6e, 0x65, 0x7b, 0x04, 0x06, 0x56, 0x0a, 0x10, 3430x10, 0x2c, 0x9f, 0x03, 0x1d, 0x64, 0xd3, 0x00, 0x83, 0x60,
3440x2c, 0x9f, 0x03, 0x1d, 0x64, 0xd3, 0x00, 0x83, 0x60, 0x54, 3440x54, 0x72, 0x69, 0x76, 0x69, 0x61, 0x6c, 0x3e, 0x04, 0x70,
3450x72, 0x69, 0x76, 0x69, 0x61, 0x6c, 0x3e, 0x04, 0x70, 0x42, 3450x42, 0x61, 0x73, 0x69, 0x63, 0x27, 0x00, 0xb2, 0x11, 0x06,
3460x61, 0x73, 0x69, 0x63, 0x27, 0x00, 0xc7, 0x11, 0x06, 0x98, 3460x98, 0x04, 0x05, 0xaf, 0x09, 0x04, 0x4d, 0x01, 0x01, 0x02,
3470x04, 0x05, 0xaf, 0x09, 0x04, 0x4d, 0x01, 0x01, 0x02, 0x0d, 3470x0d, 0x06, 0x47, 0x15, 0x03, 0x33, 0x0a, 0x04, 0xfa, 0x09,
3480x06, 0x5c, 0x15, 0x03, 0x33, 0x0a, 0x04, 0xfa, 0x09, 0x12, 3480x12, 0x74, 0xe1, 0x02, 0x22, 0x69, 0x6d, 0x80, 0x03, 0x10,
3490x74, 0xe1, 0x02, 0x22, 0x69, 0x6d, 0x80, 0x03, 0x10, 0x65, 3490x65, 0xbe, 0x00, 0x00, 0x16, 0x00, 0x20, 0x60, 0x49, 0x6b,
3500xbe, 0x00, 0x00, 0x16, 0x00, 0x20, 0x60, 0x49, 0x6b, 0x04, 3500x04, 0x30, 0x6d, 0x65, 0x64, 0x87, 0x08, 0x13, 0x27, 0xee,
3510x30, 0x6d, 0x65, 0x64, 0x87, 0x08, 0x13, 0x27, 0xee, 0x00, 3510x00, 0x20, 0x61, 0x6e, 0x26, 0x11, 0x42, 0x79, 0x6f, 0x6e,
3520x20, 0x61, 0x6e, 0x3b, 0x11, 0x42, 0x79, 0x6f, 0x6e, 0x64, 3520x64, 0x64, 0x11, 0x05, 0xdc, 0x06, 0x13, 0x74, 0x7f, 0x02,
3530x79, 0x11, 0x05, 0xdc, 0x06, 0x13, 0x74, 0x7f, 0x02, 0x01, 3530x01, 0xc2, 0x00, 0x26, 0x61, 0x6c, 0x4a, 0x01, 0x13, 0x73,
3540xc2, 0x00, 0x26, 0x61, 0x6c, 0x4a, 0x01, 0x13, 0x73, 0x33, 3540x33, 0x0b, 0x01, 0x85, 0x02, 0x02, 0xef, 0x03, 0x04, 0x49,
3550x0b, 0x01, 0x85, 0x02, 0x02, 0xef, 0x03, 0x04, 0x49, 0x03, 3550x03, 0x05, 0xc6, 0x04, 0x13, 0x63, 0x7e, 0x11, 0x13, 0x00,
3560x05, 0xc6, 0x04, 0x13, 0x63, 0x93, 0x11, 0x13, 0x00, 0x3c, 3560x3c, 0x0d, 0x07, 0x2c, 0x00, 0x04, 0x46, 0x05, 0x02, 0xac,
3570x0d, 0x07, 0x2c, 0x00, 0x04, 0x46, 0x05, 0x02, 0xc1, 0x11, 3570x11, 0x07, 0x28, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x39, 0x13,
3580x07, 0x28, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x4e, 0x13, 0x52, 3580x52, 0x74, 0x00, 0x60, 0x55, 0x6e, 0x76, 0x01, 0x00, 0x1b,
3590x74, 0x00, 0x60, 0x55, 0x6e, 0x76, 0x01, 0x00, 0x1b, 0x06, 3590x06, 0x03, 0xad, 0x00, 0x03, 0x94, 0x11, 0x13, 0x74, 0xc7,
3600x03, 0xad, 0x00, 0x03, 0xa9, 0x11, 0x13, 0x74, 0xc7, 0x06, 3600x06, 0x00, 0x82, 0x01, 0x20, 0x65, 0x6e, 0x2d, 0x10, 0x02,
3610x00, 0x82, 0x01, 0x20, 0x65, 0x6e, 0x42, 0x10, 0x02, 0xe9, 3610xe9, 0x04, 0x05, 0xc0, 0x00, 0x10, 0x65, 0xc4, 0x0f, 0x02,
3620x04, 0x05, 0xc0, 0x00, 0x10, 0x65, 0xd9, 0x0f, 0x02, 0xc3, 3620xae, 0x16, 0x09, 0xcb, 0x00, 0x86, 0x61, 0x00, 0x67, 0x75,
3630x16, 0x09, 0xcb, 0x00, 0x86, 0x61, 0x00, 0x67, 0x75, 0x65, 3630x65, 0x73, 0x73, 0x2c, 0x93, 0x0d, 0x70, 0x62, 0x61, 0x63,
3640x73, 0x73, 0x2c, 0x93, 0x0d, 0x70, 0x62, 0x61, 0x63, 0x6b, 3640x6b, 0x74, 0x72, 0x61, 0x30, 0x08, 0x10, 0x66, 0x29, 0x05,
3650x74, 0x72, 0x61, 0x30, 0x08, 0x10, 0x66, 0x29, 0x05, 0x00, 3650x00, 0x20, 0x0a, 0x10, 0x73, 0x8a, 0x04, 0x03, 0x26, 0x03,
3660x20, 0x0a, 0x10, 0x73, 0x8a, 0x04, 0x03, 0x26, 0x03, 0x50, 3660x50, 0x77, 0x72, 0x6f, 0x6e, 0x67, 0xd0, 0x02, 0x12, 0x47,
3670x77, 0x72, 0x6f, 0x6e, 0x67, 0xd0, 0x02, 0x12, 0x47, 0x9f, 3670x9f, 0x02, 0x00, 0x03, 0x02, 0x05, 0xc4, 0x01, 0x05, 0x25,
3680x02, 0x00, 0x03, 0x02, 0x05, 0xc4, 0x01, 0x05, 0x25, 0x03, 3680x03, 0x00, 0x8f, 0x00, 0x56, 0x74, 0x73, 0x65, 0x6c, 0x66,
3690x00, 0x8f, 0x00, 0x56, 0x74, 0x73, 0x65, 0x6c, 0x66, 0x1c, 3690x1c, 0x00, 0x1b, 0x3a, 0x5c, 0x08, 0x03, 0x90, 0x07, 0x02,
3700x00, 0x1b, 0x3a, 0x5c, 0x08, 0x03, 0x90, 0x07, 0x02, 0xe9, 3700xd4, 0x0f, 0x10, 0x67, 0x90, 0x13, 0x0d, 0x0b, 0x02, 0x03,
3710x0f, 0x10, 0x67, 0xa5, 0x13, 0x0d, 0x0b, 0x02, 0x03, 0x52, 3710x52, 0x05, 0x2b, 0x6d, 0x61, 0xb6, 0x00, 0x01, 0x7e, 0x17,
3720x05, 0x2b, 0x6d, 0x61, 0xb6, 0x00, 0x01, 0x93, 0x17, 0x00, 3720x00, 0x52, 0x0d, 0x31, 0x6d, 0x70, 0x74, 0xc8, 0x01, 0x16,
3730x52, 0x0d, 0x31, 0x6d, 0x70, 0x74, 0xc8, 0x01, 0x16, 0x67, 3730x67, 0x8c, 0x00, 0x05, 0x57, 0x12, 0x30, 0x62, 0x65, 0x66,
3740x8c, 0x00, 0x05, 0x6c, 0x12, 0x30, 0x62, 0x65, 0x66, 0xf1, 3740xf1, 0x03, 0x00, 0x4e, 0x17, 0x41, 0x69, 0x6e, 0x64, 0x73,
3750x03, 0x00, 0x63, 0x17, 0x41, 0x69, 0x6e, 0x64, 0x73, 0x70, 3750x70, 0x00, 0x10, 0x68, 0x30, 0x0f, 0x02, 0x21, 0x01, 0x22,
3760x00, 0x10, 0x68, 0x30, 0x0f, 0x02, 0x21, 0x01, 0x22, 0x00, 3760x00, 0x66, 0xcc, 0x0c, 0x31, 0x2e, 0x00, 0x42, 0xa5, 0x02,
3770x66, 0xcc, 0x0c, 0x31, 0x2e, 0x00, 0x42, 0xa5, 0x02, 0x23, 3770x23, 0x70, 0x61, 0x0a, 0x03, 0xc1, 0x77, 0x61, 0x69, 0x74,
3780x70, 0x61, 0x0a, 0x03, 0xc1, 0x77, 0x61, 0x69, 0x74, 0x2c, 3780x2c, 0x00, 0x65, 0x73, 0x70, 0x65, 0x63, 0x69, 0x31, 0x01,
3790x00, 0x65, 0x73, 0x70, 0x65, 0x63, 0x69, 0x31, 0x01, 0x26, 3790x26, 0x69, 0x66, 0x9e, 0x06, 0x0a, 0xfe, 0x04, 0x95, 0x64,
3800x69, 0x66, 0x9e, 0x06, 0x0a, 0xfe, 0x04, 0x95, 0x64, 0x00, 3800x00, 0x61, 0x00, 0x6c, 0x61, 0x72, 0x67, 0x65, 0xcb, 0x12,
3810x61, 0x00, 0x6c, 0x61, 0x72, 0x67, 0x65, 0xe0, 0x12, 0x50, 3810x50, 0x69, 0x7a, 0x65, 0x2e, 0x00,
3820x69, 0x7a, 0x65, 0x2e, 0x00,
383}; 382};
384 383
385const unsigned short help_text_len = 6263; 384const unsigned short help_text_len = 6259;
386const unsigned short help_text_words = 1155; 385const unsigned short help_text_words = 1153;
387const char quick_help_text[] = "Fill in the grid so that each row, column and square block contains one of every digit."; 386const char quick_help_text[] = "Fill in the grid so that each row, column and square block contains one of every digit.";
diff --git a/apps/plugins/puzzles/help/tents.c b/apps/plugins/puzzles/help/tents.c
index f0617fefd4..11eeaef435 100644
--- a/apps/plugins/puzzles/help/tents.c
+++ b/apps/plugins/puzzles/help/tents.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,160 +6,161 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 102, TEXT_UNDERLINE }, 9 { 103, TEXT_UNDERLINE },
10 { 160, TEXT_CENTER | C_RED }, 10 { 161, TEXT_CENTER | C_RED },
11 { 190, TEXT_UNDERLINE }, 11 { 191, TEXT_UNDERLINE },
12 { 207, TEXT_UNDERLINE }, 12 { 208, TEXT_UNDERLINE },
13 { 342, TEXT_CENTER | C_RED }, 13 { 343, TEXT_CENTER | C_RED },
14 { 359, TEXT_UNDERLINE },
15 { 360, TEXT_UNDERLINE }, 14 { 360, TEXT_UNDERLINE },
16 { 370, TEXT_UNDERLINE }, 15 { 361, TEXT_UNDERLINE },
16 { 371, TEXT_UNDERLINE },
17 LAST_STYLE_ITEM 17 LAST_STYLE_ITEM
18}; 18};
19 19
20/* orig 2140 comp 1385 ratio 0.647196 level 10 saved 755 */ 20/* orig 2158 comp 1394 ratio 0.645968 level 10 saved 764 */
21const char help_text[] = { 21const char help_text[] = {
220xf0, 0x26, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 220xfc, 0x05, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
230x32, 0x35, 0x3a, 0x20, 0x54, 0x65, 0x6e, 0x74, 0x73, 0x20, 230x32, 0x35, 0x3a, 0x20, 0x54, 0x65, 0x6e, 0x74, 0x73, 0x20,
240x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 240x00, 0x2d, 0x01, 0x00, 0xf0, 0x14, 0x00, 0x00, 0x00, 0x59,
250x65, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 250x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00,
260x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 260x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71,
270x00, 0x73, 0x6f, 0x6d, 0x65, 0x11, 0x00, 0xf0, 0x05, 0x77, 270x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x73, 0x6f, 0x6d,
280x68, 0x69, 0x63, 0x68, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 280x65, 0x11, 0x00, 0xf0, 0x05, 0x77, 0x68, 0x69, 0x63, 0x68,
290x69, 0x6e, 0x00, 0x74, 0x72, 0x65, 0x65, 0x73, 0x2e, 0x39, 290x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x00, 0x74,
300x00, 0xf0, 0x04, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 0x69, 300x72, 0x65, 0x65, 0x73, 0x2e, 0x39, 0x00, 0xf0, 0x04, 0x72,
310x73, 0x00, 0x74, 0x6f, 0x00, 0x70, 0x6c, 0x61, 0x63, 0x65, 310x00, 0x61, 0x69, 0x6d, 0x00, 0x69, 0x73, 0x00, 0x74, 0x6f,
320x00, 0x74, 0x57, 0x00, 0x35, 0x00, 0x69, 0x6e, 0x3b, 0x00, 320x00, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x00, 0x74, 0x69, 0x00,
330xd6, 0x74, 0x68, 0x65, 0x00, 0x72, 0x65, 0x6d, 0x61, 0x69, 330x35, 0x00, 0x69, 0x6e, 0x3b, 0x00, 0xd6, 0x74, 0x68, 0x65,
340x6e, 0x69, 0x6e, 0x67, 0x5a, 0x00, 0x00, 0x22, 0x00, 0xe1, 340x00, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67,
350x75, 0x63, 0x68, 0x00, 0x61, 0x00, 0x77, 0x61, 0x79, 0x00, 350x5a, 0x00, 0x00, 0x22, 0x00, 0xe1, 0x75, 0x63, 0x68, 0x00,
360x74, 0x68, 0x61, 0x74, 0x2a, 0x00, 0x60, 0x66, 0x6f, 0x6c, 360x61, 0x00, 0x77, 0x61, 0x79, 0x00, 0x74, 0x68, 0x61, 0x74,
370x6c, 0x6f, 0x77, 0x2a, 0x00, 0xf1, 0x0e, 0x63, 0x6f, 0x6e, 370x2a, 0x00, 0x60, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x2a,
380x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x00, 0x61, 0x72, 380x00, 0xf1, 0x0e, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69,
390x65, 0x00, 0x6d, 0x65, 0x74, 0x3a, 0x00, 0x00, 0x00, 0x2d, 390x6f, 0x6e, 0x73, 0x00, 0x61, 0x72, 0x65, 0x00, 0x6d, 0x65,
400x00, 0x54, 0x68, 0x65, 0x72, 0x65, 0x13, 0x00, 0xf3, 0x00, 400x74, 0x3a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x54, 0x68, 0x65,
410x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 0x79, 0x00, 0x61, 0x73, 410x72, 0x65, 0x13, 0x00, 0xf3, 0x00, 0x65, 0x78, 0x61, 0x63,
420x00, 0x6d, 0x61, 0x6e, 0x79, 0x7b, 0x00, 0x24, 0x61, 0x73, 420x74, 0x6c, 0x79, 0x00, 0x61, 0x73, 0x00, 0x6d, 0x61, 0x6e,
430xa0, 0x00, 0x03, 0x2e, 0x00, 0x04, 0x18, 0x00, 0x22, 0x6e, 430x79, 0x7b, 0x00, 0x24, 0x61, 0x73, 0xa0, 0x00, 0x03, 0x2e,
440x64, 0x19, 0x00, 0xff, 0x03, 0x00, 0x63, 0x61, 0x6e, 0x00, 440x00, 0x04, 0x18, 0x00, 0x22, 0x6e, 0x64, 0x19, 0x00, 0xff,
450x62, 0x65, 0x00, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 450x03, 0x00, 0x63, 0x61, 0x6e, 0x00, 0x62, 0x65, 0x00, 0x6d,
460x00, 0x75, 0x70, 0x8d, 0x00, 0x01, 0x41, 0x65, 0x61, 0x63, 460x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x00, 0x75, 0x70, 0x8d,
470x68, 0x3a, 0x00, 0x00, 0xde, 0x00, 0x42, 0x64, 0x69, 0x72, 470x00, 0x01, 0x41, 0x65, 0x61, 0x63, 0x68, 0x3a, 0x00, 0x00,
480x65, 0x6b, 0x00, 0x40, 0x64, 0x6a, 0x61, 0x63, 0x15, 0x00, 480xde, 0x00, 0x42, 0x64, 0x69, 0x72, 0x65, 0x6b, 0x00, 0x40,
490x60, 0x28, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x10, 0x01, 0xd0, 490x64, 0x6a, 0x61, 0x63, 0x15, 0x00, 0x60, 0x28, 0x68, 0x6f,
500x6c, 0x6c, 0x79, 0x00, 0x6f, 0x72, 0x00, 0x76, 0x65, 0x72, 500x72, 0x69, 0x7a, 0x10, 0x01, 0xd0, 0x6c, 0x6c, 0x79, 0x00,
510x74, 0x69, 0x63, 0x0e, 0x00, 0xf0, 0x01, 0x2c, 0x00, 0x62, 510x6f, 0x72, 0x00, 0x76, 0x65, 0x72, 0x74, 0x69, 0x63, 0x0e,
520x75, 0x74, 0x00, 0x6e, 0x6f, 0x74, 0x00, 0x64, 0x69, 0x61, 520x00, 0xf0, 0x01, 0x2c, 0x00, 0x62, 0x75, 0x74, 0x00, 0x6e,
530x67, 0x6f, 0x6e, 0x14, 0x00, 0x10, 0x29, 0x21, 0x01, 0x62, 530x6f, 0x74, 0x00, 0x64, 0x69, 0x61, 0x67, 0x6f, 0x6e, 0x14,
540x69, 0x74, 0x73, 0x00, 0x6f, 0x77, 0x3f, 0x01, 0xc2, 0x2e, 540x00, 0x10, 0x29, 0x21, 0x01, 0x62, 0x69, 0x74, 0x73, 0x00,
550x00, 0x48, 0x6f, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2c, 0x00, 550x6f, 0x77, 0x3f, 0x01, 0xc2, 0x2e, 0x00, 0x48, 0x6f, 0x77,
560x61, 0x67, 0x00, 0x30, 0x6d, 0x61, 0x79, 0x96, 0x00, 0x05, 560x65, 0x76, 0x65, 0x72, 0x2c, 0x00, 0x61, 0x67, 0x00, 0x30,
570x62, 0x00, 0x83, 0x74, 0x6f, 0x00, 0x6f, 0x74, 0x68, 0x65, 570x6d, 0x61, 0x79, 0x96, 0x00, 0x05, 0x62, 0x00, 0x83, 0x74,
580x72, 0xb5, 0x00, 0x70, 0x61, 0x73, 0x00, 0x77, 0x65, 0x6c, 580x6f, 0x00, 0x6f, 0x74, 0x68, 0x65, 0x72, 0xb5, 0x00, 0x70,
590x6c, 0x08, 0x00, 0x03, 0x48, 0x00, 0x02, 0xe1, 0x00, 0x64, 590x61, 0x73, 0x00, 0x77, 0x65, 0x6c, 0x6c, 0x08, 0x00, 0x03,
600x4e, 0x6f, 0x00, 0x74, 0x77, 0x6f, 0xe4, 0x00, 0x17, 0x72, 600x48, 0x00, 0x02, 0xe1, 0x00, 0x64, 0x4e, 0x6f, 0x00, 0x74,
610x41, 0x00, 0x08, 0xa2, 0x00, 0x17, 0x2c, 0xa0, 0x00, 0x46, 610x77, 0x6f, 0xe4, 0x00, 0x17, 0x72, 0x41, 0x00, 0x08, 0xa2,
620x00, 0x6f, 0x72, 0x20, 0x9a, 0x00, 0x06, 0x27, 0x01, 0x61, 620x00, 0x17, 0x2c, 0xa0, 0x00, 0x46, 0x00, 0x6f, 0x72, 0x20,
630x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0xb3, 0x01, 0x04, 0xc4, 630x9a, 0x00, 0x06, 0x27, 0x01, 0x61, 0x6e, 0x75, 0x6d, 0x62,
640x01, 0x01, 0x05, 0x01, 0x41, 0x72, 0x6f, 0x77, 0x2c, 0x3e, 640x65, 0x72, 0xb3, 0x01, 0x04, 0xc4, 0x01, 0x01, 0x05, 0x01,
650x01, 0x04, 0x11, 0x00, 0x73, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 650x41, 0x72, 0x6f, 0x77, 0x2c, 0x3e, 0x01, 0x04, 0x11, 0x00,
660x6e, 0x2c, 0x41, 0x01, 0x35, 0x73, 0x00, 0x74, 0x3d, 0x00, 660x73, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x2c, 0x41, 0x01,
670xd1, 0x73, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x00, 0x72, 670x35, 0x73, 0x00, 0x74, 0x3d, 0x00, 0xd1, 0x73, 0x00, 0x67,
680x6f, 0x75, 0x6e, 0x64, 0x18, 0x00, 0x54, 0x73, 0x69, 0x64, 680x69, 0x76, 0x65, 0x6e, 0x00, 0x72, 0x6f, 0x75, 0x6e, 0x64,
690x65, 0x73, 0x07, 0x02, 0x00, 0x5f, 0x02, 0x00, 0x70, 0x00, 690x18, 0x00, 0x54, 0x73, 0x69, 0x64, 0x65, 0x73, 0x07, 0x02,
700xb4, 0x54, 0x68, 0x69, 0x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 700x00, 0x5f, 0x02, 0x00, 0x70, 0x00, 0xb4, 0x54, 0x68, 0x69,
710x6c, 0x65, 0x8d, 0x01, 0x11, 0x66, 0x32, 0x00, 0x00, 0x88, 710x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x8d, 0x01,
720x01, 0x00, 0x15, 0x01, 0x22, 0x61, 0x6c, 0x4e, 0x02, 0x41, 720x11, 0x66, 0x32, 0x00, 0x00, 0x88, 0x01, 0x00, 0x15, 0x01,
730x73, 0x00, 0x6f, 0x6e, 0x3a, 0x00, 0x82, 0x49, 0x6e, 0x74, 730x22, 0x61, 0x6c, 0x4e, 0x02, 0x41, 0x73, 0x00, 0x6f, 0x6e,
740x65, 0x72, 0x6e, 0x65, 0x74, 0x89, 0x00, 0xa1, 0x77, 0x61, 740x3a, 0x00, 0x82, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
750x73, 0x00, 0x62, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x27, 0x01, 750x74, 0x89, 0x00, 0xa1, 0x77, 0x61, 0x73, 0x00, 0x62, 0x72,
760x50, 0x6d, 0x79, 0x00, 0x61, 0x74, 0xb4, 0x00, 0xf0, 0x28, 760x6f, 0x75, 0x67, 0x68, 0x27, 0x01, 0x50, 0x6d, 0x79, 0x00,
770x69, 0x6f, 0x6e, 0x00, 0x62, 0x79, 0x00, 0x65, 0x2d, 0x6d, 770x61, 0x74, 0xb4, 0x00, 0xf0, 0x28, 0x69, 0x6f, 0x6e, 0x00,
780x61, 0x69, 0x6c, 0x2e, 0x00, 0x49, 0x00, 0x64, 0x6f, 0x6e, 780x62, 0x79, 0x00, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
790x27, 0x74, 0x00, 0x6b, 0x6e, 0x6f, 0x77, 0x00, 0x77, 0x68, 790x00, 0x49, 0x00, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x00, 0x6b,
800x6f, 0x00, 0x49, 0x00, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 800x6e, 0x6f, 0x77, 0x00, 0x77, 0x68, 0x6f, 0x00, 0x49, 0x00,
810x00, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x00, 0x66, 0x6f, 810x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x00, 0x63, 0x72, 0x65,
820x72, 0x00, 0x69, 0x6e, 0x76, 0x3a, 0x00, 0x50, 0x6e, 0x67, 820x64, 0x69, 0x74, 0x00, 0x66, 0x6f, 0x72, 0x00, 0x69, 0x6e,
830x00, 0x69, 0x74, 0x9c, 0x00, 0x43, 0x32, 0x35, 0x2e, 0x31, 830x76, 0x3a, 0x00, 0x50, 0x6e, 0x67, 0x00, 0x69, 0x74, 0x9c,
840x1c, 0x03, 0x00, 0xef, 0x02, 0x31, 0x72, 0x6f, 0x6c, 0x25, 840x00, 0x43, 0x32, 0x35, 0x2e, 0x31, 0x2e, 0x03, 0x00, 0xef,
850x03, 0xa1, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 850x02, 0xf1, 0x03, 0x72, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00,
860x63, 0x6b, 0x2b, 0x00, 0x93, 0x6e, 0x00, 0x61, 0x00, 0x62, 860x00, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63,
870x6c, 0x61, 0x6e, 0x6b, 0xd1, 0x02, 0x43, 0x00, 0x77, 0x69, 870x6b, 0x2b, 0x00, 0x93, 0x6e, 0x00, 0x61, 0x00, 0x62, 0x6c,
880x6c, 0xb4, 0x00, 0x04, 0xd0, 0x01, 0x21, 0x69, 0x6e, 0x52, 880x61, 0x6e, 0x6b, 0xd1, 0x02, 0x43, 0x00, 0x77, 0x69, 0x6c,
890x00, 0x7f, 0x52, 0x69, 0x67, 0x68, 0x74, 0x2d, 0x00, 0x3b, 890xb4, 0x00, 0x04, 0xd0, 0x01, 0x21, 0x69, 0x6e, 0x52, 0x00,
900x00, 0x0d, 0x30, 0x63, 0x6f, 0x6c, 0x4e, 0x03, 0x80, 0x69, 900x7f, 0x52, 0x69, 0x67, 0x68, 0x74, 0x2d, 0x00, 0x3b, 0x00,
910x74, 0x00, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x03, 0x41, 910x0d, 0x30, 0x63, 0x6f, 0x6c, 0x4e, 0x03, 0x80, 0x69, 0x74,
920x64, 0x69, 0x63, 0x61, 0x99, 0x00, 0x01, 0x90, 0x02, 0x31, 920x00, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x03, 0x41, 0x64,
930x79, 0x6f, 0x75, 0xdf, 0x01, 0x60, 0x73, 0x75, 0x72, 0x65, 930x69, 0x63, 0x61, 0x99, 0x00, 0x01, 0x90, 0x02, 0x31, 0x79,
940x00, 0x69, 0x96, 0x02, 0x00, 0xdb, 0x00, 0x02, 0x6c, 0x00, 940x6f, 0x75, 0xdf, 0x01, 0x60, 0x73, 0x75, 0x72, 0x65, 0x00,
950x34, 0x2e, 0x00, 0x43, 0x5f, 0x00, 0x21, 0x65, 0x69, 0x34, 950x69, 0x96, 0x02, 0x00, 0xdb, 0x00, 0x02, 0x6c, 0x00, 0x34,
960x02, 0x61, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x6d, 0x00, 960x2e, 0x00, 0x43, 0x5f, 0x00, 0x21, 0x65, 0x69, 0x34, 0x02,
970xaa, 0x6e, 0x00, 0x6f, 0x63, 0x63, 0x75, 0x70, 0x69, 0x65, 970x61, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x6d, 0x00, 0xaa,
980x64, 0x71, 0x00, 0x43, 0x6c, 0x65, 0x61, 0x72, 0xf4, 0x00, 980x6e, 0x00, 0x6f, 0x63, 0x63, 0x75, 0x70, 0x69, 0x65, 0x64,
990x21, 0x49, 0x66, 0x5f, 0x00, 0x92, 0x64, 0x72, 0x61, 0x67, 990x71, 0x00, 0x43, 0x6c, 0x65, 0x61, 0x72, 0xf4, 0x00, 0x21,
1000x00, 0x77, 0x69, 0x74, 0x68, 0xb4, 0x03, 0x00, 0xb9, 0x00, 1000x49, 0x66, 0x5f, 0x00, 0x92, 0x64, 0x72, 0x61, 0x67, 0x00,
1010x04, 0x49, 0x00, 0x70, 0x61, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 1010x77, 0x69, 0x74, 0x68, 0xb4, 0x03, 0x00, 0xb9, 0x00, 0x04,
1020x61, 0x0c, 0x02, 0x00, 0xed, 0x02, 0x04, 0x02, 0x02, 0x00, 1020x49, 0x00, 0x70, 0x61, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x61,
1030xac, 0x01, 0x1a, 0x79, 0xce, 0x00, 0x23, 0x69, 0x6e, 0xf2, 1030x0c, 0x02, 0x00, 0xed, 0x02, 0x04, 0x02, 0x02, 0x00, 0xac,
1040x03, 0x10, 0x67, 0x8e, 0x01, 0x00, 0x57, 0x00, 0x52, 0x63, 1040x01, 0x1a, 0x79, 0xce, 0x00, 0x23, 0x69, 0x6e, 0xf2, 0x03,
1050x6f, 0x76, 0x65, 0x72, 0x75, 0x00, 0x94, 0x62, 0x65, 0x00, 1050x10, 0x67, 0x8e, 0x01, 0x00, 0x57, 0x00, 0x52, 0x63, 0x6f,
1060x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0xe6, 0x00, 0x00, 0xce, 1060x76, 0x65, 0x72, 0x75, 0x00, 0x94, 0x62, 0x65, 0x00, 0x74,
1070x01, 0x14, 0x6e, 0xe9, 0x02, 0x03, 0x1c, 0x04, 0x05, 0x2b, 1070x75, 0x72, 0x6e, 0x65, 0x64, 0xe6, 0x00, 0x00, 0xce, 0x01,
1080x00, 0xb1, 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 1080x14, 0x6e, 0xe9, 0x02, 0x03, 0x1c, 0x04, 0x05, 0x2b, 0x00,
1090x2e, 0x00, 0x28, 0x32, 0x02, 0x91, 0x69, 0x73, 0x00, 0x75, 1090xb1, 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x2e,
1100x73, 0x65, 0x66, 0x75, 0x6c, 0xb9, 0x01, 0x01, 0xc1, 0x00, 1100x00, 0x28, 0x32, 0x02, 0x91, 0x69, 0x73, 0x00, 0x75, 0x73,
1110x02, 0x1f, 0x01, 0x04, 0x61, 0x04, 0x12, 0x64, 0xbf, 0x02, 1110x65, 0x66, 0x75, 0x6c, 0xb9, 0x01, 0x01, 0xc1, 0x00, 0x02,
1120x03, 0xa7, 0x00, 0x54, 0x6e, 0x63, 0x65, 0x00, 0x79, 0xdc, 1120x1f, 0x01, 0x04, 0x61, 0x04, 0x12, 0x64, 0xbf, 0x02, 0x03,
1130x04, 0x01, 0x9b, 0x01, 0x51, 0x64, 0x00, 0x61, 0x6c, 0x6c, 1130xa7, 0x00, 0x54, 0x6e, 0x63, 0x65, 0x00, 0x79, 0xdc, 0x04,
1140x3f, 0x03, 0x01, 0xe2, 0x02, 0x23, 0x2e, 0x29, 0xfe, 0x04, 1140x01, 0x9b, 0x01, 0x51, 0x64, 0x00, 0x61, 0x6c, 0x6c, 0x3f,
1150x20, 0x63, 0x61, 0xe2, 0x00, 0x20, 0x73, 0x6f, 0x5f, 0x00, 1150x03, 0x01, 0xe2, 0x02, 0x23, 0x2e, 0x29, 0xfe, 0x04, 0x20,
1160x01, 0x4f, 0x00, 0xb1, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 1160x63, 0x61, 0xe2, 0x00, 0x20, 0x73, 0x6f, 0x5f, 0x00, 0x01,
1170x00, 0x6b, 0x65, 0x79, 0x73, 0x61, 0x02, 0x10, 0x6f, 0x1e, 1170x4f, 0x00, 0xb1, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x00,
1180x05, 0x06, 0xd5, 0x02, 0x02, 0xc8, 0x02, 0x56, 0x50, 0x72, 1180x6b, 0x65, 0x79, 0x73, 0x61, 0x02, 0x10, 0x6f, 0x1e, 0x05,
1190x65, 0x73, 0x73, 0x81, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x32, 1190x06, 0xd5, 0x02, 0x02, 0xc8, 0x02, 0x56, 0x50, 0x72, 0x65,
1200x00, 0x11, 0x00, 0xef, 0x00, 0x8f, 0x61, 0x6e, 0x00, 0x65, 1200x73, 0x73, 0x81, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x32, 0x00,
1210x6d, 0x70, 0x74, 0x79, 0x20, 0x02, 0x06, 0x02, 0xfc, 0x00, 1210x11, 0x00, 0xef, 0x00, 0x8f, 0x61, 0x6e, 0x00, 0x65, 0x6d,
1220x18, 0x70, 0x44, 0x00, 0x20, 0x73, 0x70, 0x1f, 0x00, 0x3e, 1220x70, 0x74, 0x79, 0x20, 0x02, 0x06, 0x02, 0xfc, 0x00, 0x18,
1230x62, 0x61, 0x72, 0x43, 0x00, 0x0f, 0x28, 0x02, 0x05, 0x14, 1230x70, 0x44, 0x00, 0x20, 0x73, 0x70, 0x1f, 0x00, 0x3e, 0x62,
1240x3b, 0xf1, 0x01, 0x00, 0x79, 0x00, 0x07, 0xd8, 0x01, 0x0e, 1240x61, 0x72, 0x43, 0x00, 0x0f, 0x28, 0x02, 0x05, 0x14, 0x3b,
1250xf6, 0x01, 0x00, 0x71, 0x04, 0x20, 0x6c, 0x64, 0x6b, 0x00, 1250xf1, 0x01, 0x00, 0x79, 0x00, 0x07, 0xd8, 0x01, 0x0e, 0xf6,
1260x5e, 0x53, 0x68, 0x69, 0x66, 0x74, 0x7e, 0x00, 0x08, 0xf4, 1260x01, 0x00, 0x71, 0x04, 0x20, 0x6c, 0x64, 0x6b, 0x00, 0x5e,
1270x00, 0x08, 0x6b, 0x00, 0x08, 0x84, 0x00, 0x12, 0x73, 0x76, 1270x53, 0x68, 0x69, 0x66, 0x74, 0x7e, 0x00, 0x08, 0xf4, 0x00,
1280x00, 0x06, 0x4c, 0x00, 0x12, 0x43, 0x23, 0x03, 0x0f, 0x4e, 1280x08, 0x6b, 0x00, 0x08, 0x84, 0x00, 0x12, 0x73, 0x76, 0x00,
1290x00, 0x17, 0x01, 0x40, 0x00, 0x5b, 0x00, 0x62, 0x6f, 0x74, 1290x06, 0x4c, 0x00, 0x12, 0x43, 0x23, 0x03, 0x0f, 0x4e, 0x00,
1300x68, 0x59, 0x00, 0x00, 0x42, 0x00, 0x06, 0x01, 0x02, 0x12, 1300x17, 0x01, 0x40, 0x00, 0x5b, 0x00, 0x62, 0x6f, 0x74, 0x68,
1310x74, 0x7c, 0x05, 0x01, 0xc5, 0x05, 0x41, 0x28, 0x41, 0x6c, 1310x59, 0x00, 0x00, 0x42, 0x00, 0x06, 0x01, 0x02, 0x12, 0x74,
1320x6c, 0x54, 0x00, 0x22, 0x61, 0x63, 0x0f, 0x06, 0x83, 0x64, 1320x7c, 0x05, 0x01, 0xc5, 0x05, 0x41, 0x28, 0x41, 0x6c, 0x6c,
1330x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x30, 0x04, 0x11, 1330x54, 0x00, 0x22, 0x61, 0x63, 0x0f, 0x06, 0x83, 0x64, 0x65,
1340x63, 0xf8, 0x03, 0x32, 0x32, 0x2e, 0x31, 0xff, 0x04, 0x00, 1340x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x30, 0x04, 0x11, 0x63,
1350xc8, 0x01, 0xb2, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 1350xf8, 0x03, 0x32, 0x32, 0x2e, 0x31, 0xff, 0x04, 0x00, 0xc8,
1360x6c, 0x65, 0x2e, 0x29, 0xd3, 0x03, 0x13, 0x32, 0xd3, 0x03, 1360x01, 0xb2, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c,
1370xb1, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 1370x65, 0x2e, 0x29, 0xd3, 0x03, 0x13, 0x32, 0xd3, 0x03, 0xb1,
1380x73, 0x20, 0x88, 0x04, 0x46, 0x65, 0x73, 0x65, 0x00, 0x14, 1380x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73,
1390x00, 0x02, 0x41, 0x00, 0x04, 0x3c, 0x00, 0x51, 0x00, 0x66, 1390x20, 0x88, 0x04, 0x46, 0x65, 0x73, 0x65, 0x00, 0x14, 0x00,
1400x72, 0x6f, 0x6d, 0x79, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 1400x02, 0x41, 0x00, 0x04, 0x3c, 0x00, 0x51, 0x00, 0x66, 0x72,
1410x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 1410x6f, 0x6d, 0x79, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74,
1420x6f, 0x00, 0x03, 0x98, 0x04, 0xb0, 0x60, 0x54, 0x79, 0x70, 1420x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x6f,
1430x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xab, 0x00, 0x91, 1430x00, 0x03, 0x98, 0x04, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65,
1440x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x3c, 1440x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xab, 0x00, 0x91, 0x57,
1450x03, 0x51, 0x00, 0x00, 0x53, 0x69, 0x7a, 0x04, 0x07, 0x01, 1450x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x3c, 0x03,
1460x58, 0x07, 0x24, 0x69, 0x6e, 0xe1, 0x00, 0x00, 0x2b, 0x00, 1460x51, 0x00, 0x00, 0x53, 0x69, 0x7a, 0x04, 0x07, 0x01, 0x58,
1470xc4, 0x44, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 1470x07, 0x24, 0x69, 0x6e, 0xe1, 0x00, 0x00, 0x2b, 0x00, 0xc4,
1480x79, 0x00, 0x00, 0x47, 0x01, 0x02, 0x4b, 0x05, 0x16, 0x64, 1480x44, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79,
1490x1a, 0x00, 0x04, 0x38, 0x05, 0x83, 0x65, 0x6e, 0x65, 0x72, 1490x00, 0x00, 0x47, 0x01, 0x02, 0x4b, 0x05, 0x16, 0x64, 0x1a,
1500x61, 0x74, 0x65, 0x64, 0x35, 0x05, 0x57, 0x2e, 0x00, 0x4d, 1500x00, 0x04, 0x38, 0x05, 0x83, 0x65, 0x6e, 0x65, 0x72, 0x61,
1510x6f, 0x72, 0x29, 0x00, 0x03, 0x17, 0x00, 0x70, 0x73, 0x00, 1510x74, 0x65, 0x64, 0x35, 0x05, 0x57, 0x2e, 0x00, 0x4d, 0x6f,
1520x72, 0x65, 0x71, 0x75, 0x69, 0x2d, 0x07, 0x00, 0x1f, 0x00, 1520x72, 0x29, 0x00, 0x03, 0x17, 0x00, 0x70, 0x73, 0x00, 0x72,
1530xc2, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x00, 0x64, 1530x65, 0x71, 0x75, 0x69, 0x2d, 0x07, 0x00, 0x1f, 0x00, 0xc2,
1540x65, 0x64, 0x75, 0x3a, 0x01, 0x02, 0x9a, 0x06, 0x21, 0x61, 1540x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x00, 0x64, 0x65,
1550x74, 0xab, 0x01, 0x20, 0x65, 0x6e, 0xa5, 0x06, 0x15, 0x6e, 1550x64, 0x75, 0x3a, 0x01, 0x02, 0x9a, 0x06, 0x21, 0x61, 0x74,
1560xa4, 0x07, 0x06, 0xf8, 0x00, 0x07, 0x81, 0x00, 0x55, 0x6c, 1560xab, 0x01, 0x20, 0x65, 0x6e, 0xa5, 0x06, 0x15, 0x6e, 0xa4,
1570x65, 0x76, 0x65, 0x6c, 0x58, 0x00, 0xb0, 0x73, 0x00, 0x67, 1570x07, 0x06, 0xf8, 0x00, 0x07, 0x81, 0x00, 0x55, 0x6c, 0x65,
1580x75, 0x65, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x6b, 0x06, 0x04, 1580x76, 0x65, 0x6c, 0x58, 0x00, 0xb0, 0x73, 0x00, 0x67, 0x75,
1590xe0, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x6b, 1590x65, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x6b, 0x06, 0x04, 0xe0,
1600x69, 0x6e, 0x67, 0x2e, 0x00, 1600x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x69,
1610x6e, 0x67, 0x2e, 0x00,
161}; 162};
162 163
163const unsigned short help_text_len = 2140; 164const unsigned short help_text_len = 2158;
164const unsigned short help_text_words = 400; 165const unsigned short help_text_words = 401;
165const char quick_help_text[] = "Place a tent next to each tree."; 166const char quick_help_text[] = "Place a tent next to each tree.";
diff --git a/apps/plugins/puzzles/help/towers.c b/apps/plugins/puzzles/help/towers.c
index 7b27064659..b41fb7a432 100644
--- a/apps/plugins/puzzles/help/towers.c
+++ b/apps/plugins/puzzles/help/towers.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,239 +6,261 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 216, TEXT_CENTER | C_RED }, 9 { 217, TEXT_CENTER | C_RED },
10 { 291, TEXT_UNDERLINE }, 10 { 292, TEXT_UNDERLINE },
11 { 588, TEXT_CENTER | C_RED }, 11 { 589, TEXT_CENTER | C_RED },
12 { 605, TEXT_UNDERLINE }, 12 { 606, TEXT_UNDERLINE },
13 { 637, TEXT_UNDERLINE }, 13 { 638, TEXT_UNDERLINE },
14 { 677, TEXT_CENTER | C_RED },
14 LAST_STYLE_ITEM 15 LAST_STYLE_ITEM
15}; 16};
16 17
17/* orig 3541 comp 2203 ratio 0.622141 level 10 saved 1338 */ 18/* orig 3906 comp 2412 ratio 0.617512 level 10 saved 1494 */
18const char help_text[] = { 19const char help_text[] = {
190xf4, 0x26, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 200xfd, 0x06, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
200x33, 0x31, 0x3a, 0x20, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73, 210x33, 0x31, 0x3a, 0x20, 0x54, 0x6f, 0x77, 0x65, 0x72, 0x73,
210x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 220x20, 0x00, 0x2d, 0x01, 0x00, 0xf4, 0x13, 0x00, 0x00, 0x00,
220x76, 0x65, 0x00, 0x61, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 230x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61,
230x65, 0x00, 0x67, 0x72, 0x69, 0x64, 0x2e, 0x00, 0x4f, 0x6e, 240x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x00, 0x67, 0x72,
240x00, 0x65, 0x61, 0x63, 0x68, 0x15, 0x00, 0x52, 0x6f, 0x66, 250x69, 0x64, 0x2e, 0x00, 0x4f, 0x6e, 0x00, 0x65, 0x61, 0x63,
250x00, 0x74, 0x68, 0x1c, 0x00, 0xf0, 0x03, 0x00, 0x79, 0x6f, 260x68, 0x15, 0x00, 0x52, 0x6f, 0x66, 0x00, 0x74, 0x68, 0x1c,
260x75, 0x00, 0x63, 0x61, 0x6e, 0x00, 0x62, 0x75, 0x69, 0x6c, 270x00, 0xf0, 0x03, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x63, 0x61,
270x64, 0x00, 0x61, 0x00, 0x74, 0x4d, 0x00, 0xf1, 0x14, 0x2c, 280x6e, 0x00, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x00, 0x61, 0x00,
280x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x69, 0x74, 0x73, 0x00, 290x74, 0x60, 0x00, 0xf1, 0x14, 0x2c, 0x00, 0x77, 0x69, 0x74,
290x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x00, 0x72, 0x61, 0x6e, 300x68, 0x00, 0x69, 0x74, 0x73, 0x00, 0x68, 0x65, 0x69, 0x67,
300x67, 0x69, 0x6e, 0x67, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x00, 310x68, 0x74, 0x00, 0x72, 0x61, 0x6e, 0x67, 0x69, 0x6e, 0x67,
310x31, 0x00, 0x74, 0x6f, 0x42, 0x00, 0x39, 0x73, 0x69, 0x7a, 320x00, 0x66, 0x72, 0x6f, 0x6d, 0x00, 0x31, 0x00, 0x74, 0x6f,
320x4e, 0x00, 0x81, 0x2e, 0x00, 0x41, 0x72, 0x6f, 0x75, 0x6e, 330x42, 0x00, 0x39, 0x73, 0x69, 0x7a, 0x4e, 0x00, 0x81, 0x2e,
330x64, 0x11, 0x00, 0x3a, 0x65, 0x64, 0x67, 0x6b, 0x00, 0x00, 340x00, 0x41, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x11, 0x00, 0x3a,
340x7b, 0x00, 0xf2, 0x04, 0x73, 0x6f, 0x6d, 0x65, 0x00, 0x6e, 350x65, 0x64, 0x67, 0x6b, 0x00, 0x00, 0x7b, 0x00, 0xf2, 0x04,
350x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x00, 0x63, 0x6c, 0x75, 360x73, 0x6f, 0x6d, 0x65, 0x00, 0x6e, 0x75, 0x6d, 0x65, 0x72,
360x65, 0x73, 0x2e, 0xb8, 0x00, 0x90, 0x72, 0x00, 0x74, 0x61, 370x69, 0x63, 0x00, 0x63, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0xb8,
370x73, 0x6b, 0x00, 0x69, 0x73, 0x5c, 0x00, 0x09, 0x8d, 0x00, 380x00, 0x90, 0x72, 0x00, 0x74, 0x61, 0x73, 0x6b, 0x00, 0x69,
380x93, 0x00, 0x6f, 0x6e, 0x00, 0x65, 0x76, 0x65, 0x72, 0x79, 390x73, 0x5c, 0x00, 0x09, 0x8d, 0x00, 0x93, 0x00, 0x6f, 0x6e,
390xbf, 0x00, 0xf0, 0x0c, 0x2c, 0x00, 0x69, 0x6e, 0x00, 0x73, 400x00, 0x65, 0x76, 0x65, 0x72, 0x79, 0xbf, 0x00, 0xf0, 0x0c,
400x75, 0x63, 0x68, 0x00, 0x61, 0x00, 0x77, 0x61, 0x79, 0x00, 410x2c, 0x00, 0x69, 0x6e, 0x00, 0x73, 0x75, 0x63, 0x68, 0x00,
410x74, 0x68, 0x61, 0x74, 0x3a, 0x00, 0x00, 0x00, 0x2d, 0x00, 420x61, 0x00, 0x77, 0x61, 0x79, 0x00, 0x74, 0x68, 0x61, 0x74,
420x45, 0xe4, 0x00, 0xc3, 0x72, 0x6f, 0x77, 0x00, 0x63, 0x6f, 430x3a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x45, 0xe4, 0x00, 0xc3,
430x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x38, 0x00, 0x84, 0x70, 440x72, 0x6f, 0x77, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
440x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0xcd, 0x00, 0x25, 450x6e, 0x73, 0x38, 0x00, 0x84, 0x70, 0x6f, 0x73, 0x73, 0x69,
450x6f, 0x66, 0x5a, 0x00, 0x26, 0x63, 0x65, 0x3a, 0x00, 0x6f, 460x62, 0x6c, 0x65, 0xcd, 0x00, 0x25, 0x6f, 0x66, 0x5a, 0x00,
460x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x3d, 0x00, 0x24, 0x08, 470x26, 0x63, 0x65, 0x3a, 0x00, 0x6f, 0x63, 0x6f, 0x6c, 0x75,
470xd4, 0x00, 0xa1, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 480x6d, 0x6e, 0x3d, 0x00, 0x24, 0x08, 0xd4, 0x00, 0xa1, 0x00,
480x62, 0x65, 0x73, 0xfd, 0x00, 0x65, 0x6e, 0x75, 0x6d, 0x62, 490x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x73, 0xfd,
490x65, 0x72, 0x39, 0x00, 0x11, 0x73, 0xb2, 0x00, 0x02, 0x75, 500x00, 0x65, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x39, 0x00,
500x01, 0x91, 0x65, 0x00, 0x73, 0x65, 0x65, 0x6e, 0x00, 0x69, 510x11, 0x73, 0xb2, 0x00, 0x02, 0x75, 0x01, 0x91, 0x65, 0x00,
510x66, 0x88, 0x01, 0x74, 0x6c, 0x6f, 0x6f, 0x6b, 0x00, 0x69, 520x73, 0x65, 0x65, 0x6e, 0x00, 0x69, 0x66, 0x88, 0x01, 0x74,
520x6e, 0x5d, 0x01, 0x02, 0xad, 0x01, 0x01, 0x72, 0x01, 0x01, 530x6c, 0x6f, 0x6f, 0x6b, 0x00, 0x69, 0x6e, 0x5d, 0x01, 0x02,
530x32, 0x00, 0xf0, 0x01, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 540xad, 0x01, 0x01, 0x72, 0x01, 0x01, 0x32, 0x00, 0xf0, 0x01,
540x69, 0x6f, 0x6e, 0x2c, 0x00, 0x61, 0x73, 0x73, 0x75, 0x6d, 550x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2c,
550x90, 0x01, 0x01, 0x19, 0x00, 0x74, 0x73, 0x68, 0x6f, 0x72, 560x00, 0x61, 0x73, 0x73, 0x75, 0x6d, 0x90, 0x01, 0x01, 0x19,
560x74, 0x65, 0x72, 0x5f, 0x00, 0x00, 0x36, 0x00, 0x50, 0x68, 570x00, 0x74, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x5f,
570x69, 0x64, 0x64, 0x65, 0x61, 0x00, 0x20, 0x68, 0x69, 0x8f, 580x00, 0x00, 0x36, 0x00, 0x50, 0x68, 0x69, 0x64, 0x64, 0x65,
580x01, 0x31, 0x61, 0x6c, 0x6c, 0xb2, 0x00, 0x00, 0x6f, 0x01, 590x61, 0x00, 0x20, 0x68, 0x69, 0x8f, 0x01, 0x31, 0x61, 0x6c,
590xa2, 0x46, 0x6f, 0x72, 0x00, 0x65, 0x78, 0x61, 0x6d, 0x70, 600x6c, 0xb2, 0x00, 0x00, 0x6f, 0x01, 0xa2, 0x46, 0x6f, 0x72,
600x6c, 0x4b, 0x01, 0x51, 0x61, 0x00, 0x35, 0x78, 0x35, 0xa2, 610x00, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x4b, 0x01, 0x51,
610x01, 0x32, 0x2c, 0x00, 0x61, 0xc0, 0x00, 0xf3, 0x04, 0x6d, 620x61, 0x00, 0x35, 0x78, 0x35, 0xa2, 0x01, 0x32, 0x2c, 0x00,
620x61, 0x72, 0x6b, 0x65, 0x64, 0x00, 0x60, 0x35, 0x27, 0x00, 630x61, 0xc0, 0x00, 0xf3, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x65,
630x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0xb6, 0x00, 640x64, 0x00, 0x60, 0x35, 0x27, 0x00, 0x69, 0x6e, 0x64, 0x69,
640x00, 0x99, 0x00, 0x43, 0x66, 0x69, 0x76, 0x65, 0x04, 0x01, 650x63, 0x61, 0x74, 0x65, 0xb6, 0x00, 0x00, 0x99, 0x00, 0x43,
650x02, 0x14, 0x01, 0xd0, 0x73, 0x00, 0x6d, 0x75, 0x73, 0x74, 660x66, 0x69, 0x76, 0x65, 0x04, 0x01, 0x02, 0x14, 0x01, 0xd0,
660x00, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x53, 0x00, 0x70, 670x73, 0x00, 0x6d, 0x75, 0x73, 0x74, 0x00, 0x61, 0x70, 0x70,
670x69, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, 0xa1, 0x00, 0xf1, 680x65, 0x61, 0x72, 0x53, 0x00, 0x70, 0x69, 0x6e, 0x63, 0x72,
680x01, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x00, 0x28, 0x6f, 0x74, 690x65, 0x61, 0x73, 0xa1, 0x00, 0xf1, 0x01, 0x6f, 0x72, 0x64,
690x68, 0x65, 0x72, 0x77, 0x69, 0x73, 0x65, 0xe9, 0x00, 0x90, 700x65, 0x72, 0x00, 0x28, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x77,
700x77, 0x6f, 0x75, 0x6c, 0x64, 0x00, 0x6e, 0x6f, 0x74, 0x02, 710x69, 0x73, 0x65, 0xe9, 0x00, 0x90, 0x77, 0x6f, 0x75, 0x6c,
710x01, 0x30, 0x61, 0x62, 0x6c, 0x4f, 0x00, 0x00, 0x0a, 0x01, 720x64, 0x00, 0x6e, 0x6f, 0x74, 0x02, 0x01, 0x30, 0x61, 0x62,
720x47, 0x00, 0x61, 0x6c, 0x6c, 0x5f, 0x00, 0x70, 0x73, 0x29, 730x6c, 0x4f, 0x00, 0x00, 0x0a, 0x01, 0x47, 0x00, 0x61, 0x6c,
730x2c, 0x00, 0x77, 0x68, 0x65, 0x4b, 0x00, 0x0c, 0x9a, 0x00, 740x6c, 0x5f, 0x00, 0x70, 0x73, 0x29, 0x2c, 0x00, 0x77, 0x68,
740x1f, 0x31, 0x9a, 0x00, 0x02, 0x01, 0xe8, 0x00, 0x23, 0x73, 750x65, 0x4b, 0x00, 0x0c, 0x9a, 0x00, 0x1f, 0x31, 0x9a, 0x00,
750x74, 0x9d, 0x00, 0x10, 0x28, 0x13, 0x00, 0x25, 0x6f, 0x6e, 760x02, 0x01, 0xe8, 0x00, 0x23, 0x73, 0x74, 0x9d, 0x00, 0x10,
760x35, 0x00, 0x22, 0x35, 0x29, 0xa8, 0x00, 0x30, 0x63, 0x6f, 770x28, 0x13, 0x00, 0x25, 0x6f, 0x6e, 0x35, 0x00, 0x22, 0x35,
770x6d, 0xc5, 0x00, 0x30, 0x72, 0x73, 0x74, 0x7c, 0x02, 0x51, 780x29, 0xa8, 0x00, 0x30, 0x63, 0x6f, 0x6d, 0xc5, 0x00, 0x30,
780x49, 0x6e, 0x00, 0x68, 0x61, 0xa5, 0x00, 0xf2, 0x03, 0x6f, 790x72, 0x73, 0x74, 0x7c, 0x02, 0x51, 0x49, 0x6e, 0x00, 0x68,
790x72, 0x00, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x00, 0x70, 800x61, 0xa5, 0x00, 0xf2, 0x03, 0x6f, 0x72, 0x00, 0x6c, 0x61,
800x75, 0x7a, 0x7a, 0x6c, 0x65, 0x73, 0x2c, 0xaf, 0x02, 0x03, 810x72, 0x67, 0x65, 0x72, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c,
810x57, 0x01, 0x41, 0x77, 0x69, 0x6c, 0x6c, 0xb2, 0x01, 0xc1, 820x65, 0x73, 0x2c, 0xaf, 0x02, 0x03, 0x57, 0x01, 0x41, 0x77,
820x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x00, 0x66, 830x69, 0x6c, 0x6c, 0xb2, 0x01, 0xc1, 0x70, 0x65, 0x63, 0x69,
830x6f, 0x72, 0xcf, 0x00, 0x92, 0x61, 0x73, 0x00, 0x77, 0x65, 840x66, 0x69, 0x65, 0x64, 0x00, 0x66, 0x6f, 0x72, 0xcf, 0x00,
840x6c, 0x6c, 0x00, 0x61, 0xf0, 0x01, 0x01, 0xd7, 0x02, 0x1a, 850x92, 0x61, 0x73, 0x00, 0x77, 0x65, 0x6c, 0x6c, 0x00, 0x61,
850x00, 0x09, 0x03, 0x52, 0x2c, 0x00, 0x61, 0x6e, 0x64, 0x4f, 860xf0, 0x01, 0x01, 0xd7, 0x02, 0x1a, 0x00, 0x09, 0x03, 0x52,
860x00, 0x01, 0x18, 0x03, 0x02, 0x24, 0x00, 0x30, 0x6d, 0x61, 870x2c, 0x00, 0x61, 0x6e, 0x64, 0x4f, 0x00, 0x01, 0x18, 0x03,
870x79, 0x52, 0x00, 0x30, 0x6d, 0x69, 0x73, 0x2c, 0x01, 0x00, 880x02, 0x24, 0x00, 0x30, 0x6d, 0x61, 0x79, 0x52, 0x00, 0x30,
880x8e, 0x00, 0x43, 0x54, 0x68, 0x69, 0x73, 0x7f, 0x00, 0x03, 890x6d, 0x69, 0x73, 0x2c, 0x01, 0x00, 0x8e, 0x00, 0x43, 0x54,
890x50, 0x01, 0x10, 0x73, 0x00, 0x03, 0x00, 0x47, 0x00, 0x60, 900x68, 0x69, 0x73, 0x7f, 0x00, 0x03, 0x50, 0x01, 0x10, 0x73,
900x77, 0x65, 0x62, 0x00, 0x75, 0x6e, 0xa9, 0x00, 0xb0, 0x76, 910x00, 0x03, 0x00, 0x47, 0x00, 0x60, 0x77, 0x65, 0x62, 0x00,
910x61, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x00, 0x6e, 0x61, 0x6d, 920x75, 0x6e, 0xa9, 0x00, 0xb0, 0x76, 0x61, 0x72, 0x69, 0x6f,
920xa5, 0x00, 0xf2, 0x21, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 930x75, 0x73, 0x00, 0x6e, 0x61, 0x6d, 0xa5, 0x00, 0xf2, 0x21,
930x75, 0x6c, 0x61, 0x72, 0x6c, 0x79, 0x00, 0x60, 0x53, 0x6b, 940x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x75, 0x6c, 0x61, 0x72,
940x79, 0x73, 0x63, 0x72, 0x61, 0x70, 0x65, 0x72, 0x73, 0x27, 950x6c, 0x79, 0x00, 0x60, 0x53, 0x6b, 0x79, 0x73, 0x63, 0x72,
950x2c, 0x00, 0x62, 0x75, 0x74, 0x00, 0x49, 0x00, 0x64, 0x6f, 960x61, 0x70, 0x65, 0x72, 0x73, 0x27, 0x2c, 0x00, 0x62, 0x75,
960x6e, 0x27, 0x74, 0x00, 0x6b, 0x6e, 0x6f, 0x77, 0x00, 0x77, 970x74, 0x00, 0x49, 0x00, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x00,
970x68, 0x6f, 0xfc, 0x00, 0xb1, 0x00, 0x69, 0x6e, 0x76, 0x65, 980x6b, 0x6e, 0x6f, 0x77, 0x00, 0x77, 0x68, 0x6f, 0xfc, 0x00,
980x6e, 0x74, 0x65, 0x64, 0x00, 0x69, 0x08, 0x01, 0x44, 0x33, 990xb1, 0x00, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x65, 0x64,
990x31, 0x2e, 0x31, 0x4b, 0x04, 0x00, 0x03, 0x03, 0x31, 0x72, 1000x00, 0x69, 0x08, 0x01, 0x44, 0x33, 0x31, 0x2e, 0x31, 0x5e,
1000x6f, 0x6c, 0x54, 0x04, 0x12, 0x54, 0xfe, 0x00, 0x40, 0x73, 1010x04, 0x00, 0x03, 0x03, 0x50, 0x72, 0x6f, 0x6c, 0x73, 0x20,
1010x68, 0x61, 0x72, 0xb2, 0x00, 0x00, 0x78, 0x03, 0x21, 0x6f, 1020x92, 0x00, 0x02, 0xfe, 0x00, 0x40, 0x73, 0x68, 0x61, 0x72,
1020x66, 0x1b, 0x04, 0x03, 0x26, 0x00, 0x72, 0x00, 0x73, 0x79, 1030xb2, 0x00, 0x00, 0x78, 0x03, 0x21, 0x6f, 0x66, 0x1b, 0x04,
1030x73, 0x74, 0x65, 0x6d, 0x33, 0x04, 0xd1, 0x53, 0x6f, 0x6c, 1040x03, 0x26, 0x00, 0x72, 0x00, 0x73, 0x79, 0x73, 0x74, 0x65,
1040x6f, 0x2c, 0x00, 0x55, 0x6e, 0x65, 0x71, 0x75, 0x61, 0x6c, 1050x6d, 0x33, 0x04, 0xd1, 0x53, 0x6f, 0x6c, 0x6f, 0x2c, 0x00,
1050xf4, 0x00, 0x51, 0x4b, 0x65, 0x65, 0x6e, 0x2e, 0x48, 0x00, 1060x55, 0x6e, 0x65, 0x71, 0x75, 0x61, 0x6c, 0xf4, 0x00, 0x51,
1060x53, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x50, 0x00, 0xe1, 0x2c, 1070x4b, 0x65, 0x65, 0x6e, 0x2e, 0x48, 0x00, 0x53, 0x00, 0x70,
1070x00, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x79, 0x00, 0x63, 0x6c, 1080x6c, 0x61, 0x79, 0x50, 0x00, 0xe1, 0x2c, 0x00, 0x73, 0x69,
1080x69, 0x63, 0x6b, 0xe0, 0x00, 0x51, 0x6d, 0x6f, 0x75, 0x73, 1090x6d, 0x70, 0x6c, 0x79, 0x00, 0x63, 0x6c, 0x69, 0x63, 0x6b,
1090x65, 0x91, 0x02, 0x84, 0x6e, 0x79, 0x00, 0x65, 0x6d, 0x70, 1100xe0, 0x00, 0x51, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x91, 0x02,
1100x74, 0x79, 0x03, 0x03, 0x12, 0x61, 0x49, 0x01, 0x50, 0x6e, 1110x84, 0x6e, 0x79, 0x00, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x03,
1110x00, 0x74, 0x79, 0x70, 0xdc, 0x04, 0x54, 0x64, 0x69, 0x67, 1120x03, 0x12, 0x61, 0x49, 0x01, 0x50, 0x6e, 0x00, 0x74, 0x79,
1120x69, 0x74, 0x17, 0x01, 0x80, 0x6b, 0x65, 0x79, 0x62, 0x6f, 1130x70, 0xdc, 0x04, 0x54, 0x64, 0x69, 0x67, 0x69, 0x74, 0x17,
1130x61, 0x72, 0x64, 0x43, 0x02, 0x10, 0x66, 0xa3, 0x01, 0x02, 1140x01, 0x80, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64,
1140x13, 0x03, 0x02, 0x3a, 0x00, 0x01, 0x94, 0x00, 0x05, 0x48, 1150x43, 0x02, 0x10, 0x66, 0xa3, 0x01, 0x02, 0x13, 0x03, 0x02,
1150x04, 0x03, 0x8c, 0x04, 0x43, 0x69, 0x76, 0x65, 0x6e, 0xba, 1160x3a, 0x00, 0x01, 0x94, 0x00, 0x05, 0x48, 0x04, 0x03, 0x8c,
1160x02, 0x32, 0x2e, 0x00, 0x49, 0x7b, 0x03, 0x30, 0x6d, 0x61, 1170x04, 0x43, 0x69, 0x76, 0x65, 0x6e, 0xba, 0x02, 0x32, 0x2e,
1170x6b, 0x5a, 0x00, 0x8e, 0x6d, 0x69, 0x73, 0x74, 0x61, 0x6b, 1180x00, 0x49, 0x7b, 0x03, 0x30, 0x6d, 0x61, 0x6b, 0x5a, 0x00,
1180x65, 0x2c, 0x97, 0x00, 0x02, 0x6d, 0x00, 0x50, 0x69, 0x6e, 1190x8e, 0x6d, 0x69, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x2c, 0x97,
1190x63, 0x6f, 0x72, 0x86, 0x03, 0x08, 0x9b, 0x00, 0xa1, 0x70, 1200x00, 0x02, 0x6d, 0x00, 0x50, 0x69, 0x6e, 0x63, 0x6f, 0x72,
1200x72, 0x65, 0x73, 0x73, 0x00, 0x53, 0x70, 0x61, 0x63, 0xc8, 1210x86, 0x03, 0x08, 0x9b, 0x00, 0xa1, 0x70, 0x72, 0x65, 0x73,
1210x02, 0x21, 0x63, 0x6c, 0x06, 0x03, 0xc0, 0x74, 0x00, 0x61, 1220x73, 0x00, 0x53, 0x70, 0x61, 0x63, 0xc8, 0x02, 0x21, 0x63,
1220x67, 0x61, 0x69, 0x6e, 0x00, 0x28, 0x6f, 0x72, 0x00, 0x42, 1230x6c, 0x06, 0x03, 0xc0, 0x74, 0x00, 0x61, 0x67, 0x61, 0x69,
1230x00, 0x00, 0x3f, 0x00, 0xd1, 0x55, 0x6e, 0x64, 0x6f, 0x00, 1240x6e, 0x00, 0x28, 0x6f, 0x72, 0x00, 0x42, 0x00, 0x00, 0x3f,
1240x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x29, 0x7d, 0x02, 1250x00, 0xd1, 0x55, 0x6e, 0x64, 0x6f, 0x00, 0x66, 0x65, 0x61,
1250x02, 0x7e, 0x00, 0x10, 0x72, 0x8c, 0x00, 0x12, 0x2d, 0x74, 1260x74, 0x75, 0x72, 0x65, 0x29, 0x7d, 0x02, 0x02, 0x7e, 0x00,
1260x00, 0x01, 0x92, 0x03, 0x0f, 0xf9, 0x00, 0x04, 0x02, 0x4a, 1270x10, 0x72, 0x8c, 0x00, 0x12, 0x2d, 0x74, 0x00, 0x01, 0x92,
1270x04, 0x12, 0x2c, 0xe3, 0x00, 0x03, 0x57, 0x04, 0x04, 0x97, 1280x03, 0x0f, 0xf9, 0x00, 0x04, 0x02, 0x4a, 0x04, 0x12, 0x2c,
1280x02, 0x00, 0xcc, 0x01, 0x10, 0x72, 0xce, 0x01, 0x18, 0x6e, 1290xe3, 0x00, 0x03, 0x57, 0x04, 0x04, 0x97, 0x02, 0x00, 0xcc,
1290x3e, 0x04, 0x01, 0x3a, 0x03, 0x71, 0x60, 0x70, 0x65, 0x6e, 1300x01, 0x10, 0x72, 0xce, 0x01, 0x18, 0x6e, 0x3e, 0x04, 0x01,
1300x63, 0x69, 0x6c, 0x08, 0x03, 0x43, 0x27, 0x2e, 0x00, 0x59, 1310x3a, 0x03, 0x71, 0x60, 0x70, 0x65, 0x6e, 0x63, 0x69, 0x6c,
1310xf3, 0x05, 0x01, 0x2a, 0x06, 0x07, 0x1b, 0x00, 0x11, 0x73, 1320x08, 0x03, 0x43, 0x27, 0x2e, 0x00, 0x59, 0xf3, 0x05, 0x01,
1320xd1, 0x02, 0x74, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 1330x2a, 0x06, 0x07, 0x1b, 0x00, 0x11, 0x73, 0xd1, 0x02, 0x74,
1330xb7, 0x04, 0x15, 0x73, 0x51, 0x00, 0x24, 0x61, 0x6d, 0x56, 1340x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0xb7, 0x04, 0x15,
1340x00, 0x34, 0x2e, 0x00, 0x41, 0x60, 0x00, 0x03, 0x2d, 0x05, 1350x73, 0x51, 0x00, 0x24, 0x61, 0x6d, 0x56, 0x00, 0x34, 0x2e,
1350x00, 0xea, 0x03, 0x04, 0x67, 0x01, 0x30, 0x63, 0x61, 0x6e, 1360x00, 0x41, 0x60, 0x00, 0x03, 0x2d, 0x05, 0x00, 0xea, 0x03,
1360xda, 0x03, 0x44, 0x61, 0x6c, 0x73, 0x6f, 0x1f, 0x00, 0x09, 1370x04, 0x67, 0x01, 0x30, 0x63, 0x61, 0x6e, 0xda, 0x03, 0x44,
1370x66, 0x00, 0x02, 0xe7, 0x02, 0x30, 0x65, 0x00, 0x67, 0x51, 1380x61, 0x6c, 0x73, 0x6f, 0x1f, 0x00, 0x09, 0x66, 0x00, 0x02,
1380x00, 0xd0, 0x70, 0x61, 0x79, 0x73, 0x00, 0x6e, 0x6f, 0x00, 1390xe7, 0x02, 0x30, 0x65, 0x00, 0x67, 0x51, 0x00, 0xd0, 0x70,
1390x61, 0x74, 0x74, 0x65, 0x6e, 0xdc, 0x04, 0x00, 0x42, 0x01, 1400x61, 0x79, 0x73, 0x00, 0x6e, 0x6f, 0x00, 0x61, 0x74, 0x74,
1400x08, 0x2e, 0x00, 0x00, 0x84, 0x03, 0x00, 0xaf, 0x04, 0x60, 1410x65, 0x6e, 0xdc, 0x04, 0x00, 0x42, 0x01, 0x08, 0x2e, 0x00,
1410x63, 0x74, 0x6c, 0x79, 0x00, 0x77, 0xf8, 0x00, 0x00, 0x31, 1420x00, 0x84, 0x03, 0x00, 0xaf, 0x04, 0x60, 0x63, 0x74, 0x6c,
1420x01, 0x03, 0x51, 0x01, 0x11, 0x6d, 0xb2, 0x00, 0x50, 0x69, 1430x79, 0x00, 0x77, 0xf8, 0x00, 0x00, 0x31, 0x01, 0x03, 0x51,
1430x73, 0x00, 0x75, 0x70, 0x38, 0x00, 0x45, 0x79, 0x6f, 0x75, 1440x01, 0x11, 0x6d, 0xb2, 0x00, 0x50, 0x69, 0x73, 0x00, 0x75,
1440x3a, 0xd1, 0x06, 0x05, 0x23, 0x00, 0x95, 0x61, 0x73, 0x00, 1450x70, 0x38, 0x00, 0x45, 0x79, 0x6f, 0x75, 0x3a, 0xd1, 0x06,
1450x72, 0x65, 0x6d, 0x69, 0x6e, 0x64, 0x7b, 0x05, 0x17, 0x61, 1460x05, 0x23, 0x00, 0x95, 0x61, 0x73, 0x00, 0x72, 0x65, 0x6d,
1460x33, 0x03, 0x04, 0xc9, 0x00, 0x42, 0x6e, 0x65, 0x65, 0x64, 1470x69, 0x6e, 0x64, 0x7b, 0x05, 0x17, 0x61, 0x33, 0x03, 0x04,
1470x7c, 0x06, 0x50, 0x65, 0x00, 0x72, 0x65, 0x2d, 0x21, 0x05, 1480xc9, 0x00, 0x42, 0x6e, 0x65, 0x65, 0x64, 0x7c, 0x06, 0x50,
1480x42, 0x69, 0x6e, 0x65, 0x64, 0xe6, 0x05, 0x00, 0x54, 0x00, 1490x65, 0x00, 0x72, 0x65, 0x2d, 0x21, 0x05, 0x42, 0x69, 0x6e,
1490x01, 0x3e, 0x03, 0x30, 0x6d, 0x6f, 0x72, 0xb1, 0x04, 0x2b, 1500x65, 0x64, 0xe6, 0x05, 0x00, 0x54, 0x00, 0x01, 0x3e, 0x03,
1500x6f, 0x75, 0x45, 0x00, 0x04, 0x99, 0x01, 0x2f, 0x6f, 0x72, 1510x30, 0x6d, 0x6f, 0x72, 0xb1, 0x04, 0x2b, 0x6f, 0x75, 0x45,
1510x80, 0x00, 0x02, 0x54, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x80, 1520x00, 0x04, 0x99, 0x01, 0x2f, 0x6f, 0x72, 0x80, 0x00, 0x02,
1520x02, 0x05, 0x51, 0x06, 0x07, 0x61, 0x01, 0x13, 0x61, 0x96, 1530x54, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x80, 0x02, 0x05, 0x51,
1530x02, 0x04, 0xe2, 0x06, 0x20, 0x6f, 0x72, 0x06, 0x03, 0x20, 1540x06, 0x07, 0x61, 0x01, 0x13, 0x61, 0x96, 0x02, 0x04, 0xe2,
1540x74, 0x68, 0x58, 0x01, 0x23, 0x65, 0x6c, 0x36, 0x05, 0x93, 1550x06, 0x20, 0x6f, 0x72, 0x06, 0x03, 0x20, 0x74, 0x68, 0x58,
1550x66, 0x65, 0x65, 0x6c, 0x00, 0x6c, 0x69, 0x6b, 0x65, 0x4f, 1560x01, 0x23, 0x65, 0x6c, 0x36, 0x05, 0x93, 0x66, 0x65, 0x65,
1560x03, 0x41, 0x65, 0x72, 0x61, 0x73, 0xeb, 0x07, 0x49, 0x69, 1570x6c, 0x00, 0x6c, 0x69, 0x6b, 0x65, 0x4f, 0x03, 0x41, 0x65,
1570x6e, 0x67, 0x6c, 0xca, 0x01, 0x1c, 0x2c, 0x52, 0x02, 0x08, 1580x72, 0x61, 0x73, 0xeb, 0x07, 0x49, 0x69, 0x6e, 0x67, 0x6c,
1580x12, 0x02, 0x22, 0x6e, 0x64, 0x4f, 0x02, 0x05, 0xd5, 0x01, 1590xca, 0x01, 0x1c, 0x2c, 0x52, 0x02, 0x08, 0x12, 0x02, 0x22,
1590x03, 0x49, 0x02, 0x01, 0xaf, 0x02, 0x00, 0x5b, 0x00, 0x3a, 1600x6e, 0x64, 0x4f, 0x02, 0x05, 0xd5, 0x01, 0x03, 0x49, 0x02,
1600x41, 0x6c, 0x6c, 0x17, 0x02, 0x09, 0x93, 0x02, 0x22, 0x72, 1610x01, 0xaf, 0x02, 0x00, 0x5b, 0x00, 0x3a, 0x41, 0x6c, 0x6c,
1610x65, 0x79, 0x00, 0x10, 0x64, 0x9b, 0x05, 0x12, 0x6e, 0xb8, 1620x17, 0x02, 0x09, 0x93, 0x02, 0x22, 0x72, 0x65, 0x79, 0x00,
1620x06, 0x24, 0x65, 0x66, 0x6c, 0x00, 0x05, 0x5e, 0x00, 0x18, 1630x10, 0x64, 0x9b, 0x05, 0x12, 0x6e, 0xb8, 0x06, 0x24, 0x65,
1630x61, 0x14, 0x01, 0x0f, 0x2a, 0x00, 0x05, 0x02, 0x3a, 0x03, 1640x66, 0x6c, 0x00, 0x05, 0x5e, 0x00, 0x18, 0x61, 0x14, 0x01,
1640x10, 0x73, 0x3a, 0x03, 0x36, 0x2e, 0x00, 0x52, 0xb3, 0x00, 1650x0f, 0x2a, 0x00, 0x05, 0x02, 0x3a, 0x03, 0x10, 0x73, 0x3a,
1650x01, 0x4f, 0x02, 0x04, 0x20, 0x00, 0x00, 0x0d, 0x00, 0x01, 1660x03, 0x36, 0x2e, 0x00, 0x52, 0xb3, 0x00, 0x01, 0x4f, 0x02,
1660x23, 0x00, 0x02, 0xeb, 0x02, 0x01, 0x58, 0x02, 0x02, 0xfb, 1670x04, 0x20, 0x00, 0x00, 0x0d, 0x00, 0x01, 0x23, 0x00, 0x02,
1670x00, 0x0c, 0x56, 0x02, 0x12, 0x41, 0xc2, 0x02, 0x02, 0x84, 1680xeb, 0x02, 0x01, 0x58, 0x02, 0x02, 0xfb, 0x00, 0x0c, 0x56,
1680x04, 0x01, 0x8a, 0x05, 0x50, 0x75, 0x72, 0x73, 0x6f, 0x72, 1690x02, 0x12, 0x41, 0xc2, 0x02, 0x02, 0x84, 0x04, 0x01, 0x8a,
1690x23, 0x04, 0x14, 0x73, 0x70, 0x07, 0x22, 0x75, 0x73, 0x24, 1700x05, 0x50, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x23, 0x04, 0x14,
1700x03, 0x61, 0x63, 0x6f, 0x6e, 0x6a, 0x75, 0x6e, 0x4f, 0x07, 1710x73, 0x70, 0x07, 0x22, 0x75, 0x73, 0x24, 0x03, 0x61, 0x63,
1710x02, 0x26, 0x04, 0x00, 0x30, 0x00, 0x02, 0x59, 0x04, 0x01, 1720x6f, 0x6e, 0x6a, 0x75, 0x6e, 0x4f, 0x07, 0x02, 0x26, 0x04,
1720x2f, 0x00, 0x01, 0x91, 0x06, 0x15, 0x74, 0xa4, 0x01, 0x2b, 1730x00, 0x30, 0x00, 0x02, 0x59, 0x04, 0x01, 0x2f, 0x00, 0x01,
1730x6f, 0x72, 0x6e, 0x00, 0x3d, 0x55, 0x73, 0x65, 0x63, 0x00, 1740x91, 0x06, 0x15, 0x74, 0xa4, 0x01, 0x2b, 0x6f, 0x72, 0x6e,
1740x51, 0x74, 0x6f, 0x00, 0x6d, 0x6f, 0x7e, 0x09, 0x51, 0x68, 1750x00, 0x3d, 0x55, 0x73, 0x65, 0x63, 0x00, 0x51, 0x74, 0x6f,
1750x69, 0x67, 0x68, 0x6c, 0x2f, 0x08, 0x16, 0x61, 0x08, 0x06, 1760x00, 0x6d, 0x6f, 0x7e, 0x09, 0x51, 0x68, 0x69, 0x67, 0x68,
1760x03, 0x63, 0x07, 0x2a, 0x6e, 0x64, 0xc8, 0x04, 0x22, 0x74, 1770x6c, 0x2f, 0x08, 0x16, 0x61, 0x08, 0x06, 0x03, 0x63, 0x07,
1770x6f, 0xbc, 0x03, 0x00, 0x33, 0x04, 0x03, 0xab, 0x01, 0x05, 1780x2a, 0x6e, 0x64, 0xc8, 0x04, 0x22, 0x74, 0x6f, 0xbc, 0x03,
1780x3f, 0x00, 0x25, 0x65, 0x64, 0x73, 0x03, 0x14, 0x50, 0x0c, 1790x00, 0x33, 0x04, 0x03, 0xab, 0x01, 0x05, 0x3f, 0x00, 0x25,
1790x01, 0x50, 0x72, 0x65, 0x74, 0x75, 0x72, 0x28, 0x03, 0x5a, 1800x65, 0x64, 0x73, 0x03, 0x14, 0x50, 0x0c, 0x01, 0x50, 0x72,
1800x67, 0x67, 0x6c, 0x65, 0x73, 0x30, 0x00, 0x02, 0x3e, 0x08, 1810x65, 0x74, 0x75, 0x72, 0x28, 0x03, 0x5a, 0x67, 0x67, 0x6c,
1810x51, 0x61, 0x00, 0x6d, 0x6f, 0x64, 0xb4, 0x04, 0x55, 0x77, 1820x65, 0x73, 0x30, 0x00, 0x02, 0x3e, 0x08, 0x51, 0x61, 0x00,
1820x68, 0x69, 0x63, 0x68, 0x93, 0x02, 0x02, 0x67, 0x00, 0x20, 1830x6d, 0x6f, 0x64, 0xb4, 0x04, 0x55, 0x77, 0x68, 0x69, 0x63,
1830x6f, 0x72, 0x10, 0x03, 0x2e, 0x6f, 0x76, 0x40, 0x01, 0x05, 1840x68, 0x93, 0x02, 0x02, 0x67, 0x00, 0x20, 0x6f, 0x72, 0x10,
1840x63, 0x00, 0x12, 0x4d, 0x6b, 0x01, 0x01, 0x4f, 0x05, 0x01, 1850x03, 0x2e, 0x6f, 0x76, 0x40, 0x01, 0x05, 0x63, 0x00, 0x12,
1850xfd, 0x01, 0x41, 0x66, 0x75, 0x6c, 0x6c, 0x10, 0x01, 0x2d, 1860x4d, 0x6b, 0x01, 0x01, 0x4f, 0x05, 0x01, 0xfd, 0x01, 0x41,
1860x6f, 0x66, 0x1b, 0x02, 0x08, 0x9c, 0x09, 0x03, 0xa9, 0x08, 1870x66, 0x75, 0x6c, 0x6c, 0x10, 0x01, 0x2d, 0x6f, 0x66, 0x1b,
1870x31, 0x6f, 0x65, 0x73, 0xde, 0x07, 0x03, 0x8c, 0x0a, 0x10, 1880x02, 0x08, 0x9c, 0x09, 0x03, 0xa9, 0x08, 0x31, 0x6f, 0x65,
1880x6d, 0x03, 0x04, 0x02, 0xed, 0x00, 0x23, 0x69, 0x6e, 0x6f, 1890x73, 0xde, 0x07, 0x03, 0x8c, 0x0a, 0x10, 0x6d, 0x03, 0x04,
1890x06, 0x38, 0x4c, 0x65, 0x66, 0xed, 0x01, 0x02, 0xde, 0x07, 1900x02, 0xed, 0x00, 0x23, 0x69, 0x6e, 0x6f, 0x06, 0x38, 0x4c,
1900x01, 0x76, 0x00, 0x00, 0x59, 0x00, 0x01, 0x3f, 0x05, 0x30, 1910x65, 0x66, 0xed, 0x01, 0x02, 0xde, 0x07, 0x01, 0x76, 0x00,
1910x73, 0x00, 0x64, 0xbe, 0x07, 0x60, 0x28, 0x67, 0x72, 0x65, 1920x00, 0x59, 0x00, 0x01, 0x3f, 0x05, 0x30, 0x73, 0x00, 0x64,
1920x79, 0x00, 0xf1, 0x05, 0x31, 0x75, 0x74, 0x29, 0x4f, 0x02, 1930xbe, 0x07, 0x60, 0x28, 0x67, 0x72, 0x65, 0x79, 0x00, 0xf1,
1930x24, 0x75, 0x6e, 0x24, 0x00, 0x10, 0x69, 0x8a, 0x06, 0x00, 1940x05, 0x31, 0x75, 0x74, 0x29, 0x4f, 0x02, 0x24, 0x75, 0x6e,
1940x01, 0x04, 0x73, 0x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 1950x24, 0x00, 0x10, 0x69, 0x8a, 0x06, 0x00, 0x01, 0x04, 0x73,
1950xeb, 0x07, 0x60, 0x2e, 0x00, 0x48, 0x6f, 0x6c, 0x64, 0x59, 1960x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0xeb, 0x07, 0x60,
1960x00, 0x13, 0x43, 0xa4, 0x06, 0x00, 0x17, 0x02, 0x4a, 0x68, 1970x2e, 0x00, 0x48, 0x6f, 0x6c, 0x64, 0x59, 0x00, 0x13, 0x43,
1970x69, 0x66, 0x74, 0x57, 0x02, 0x50, 0x61, 0x6e, 0x00, 0x61, 1980xa4, 0x06, 0x00, 0x17, 0x02, 0x4a, 0x68, 0x69, 0x66, 0x74,
1980x72, 0x31, 0x0a, 0x31, 0x6b, 0x65, 0x79, 0x5a, 0x03, 0x01, 1990x57, 0x02, 0x50, 0x61, 0x6e, 0x00, 0x61, 0x72, 0x31, 0x0a,
1990xa2, 0x08, 0x02, 0xda, 0x00, 0x00, 0x86, 0x06, 0x01, 0x95, 2000x31, 0x6b, 0x65, 0x79, 0x5a, 0x03, 0x01, 0xa2, 0x08, 0x02,
2000x00, 0x27, 0x69, 0x6e, 0x37, 0x06, 0x05, 0x84, 0x09, 0x00, 2010xda, 0x00, 0x00, 0x86, 0x06, 0x01, 0x95, 0x00, 0x27, 0x69,
2010xc4, 0x00, 0x10, 0x28, 0x2a, 0x03, 0x00, 0x1c, 0x00, 0x11, 2020x6e, 0x37, 0x06, 0x05, 0x84, 0x09, 0x00, 0xc4, 0x00, 0x10,
2020x61, 0x13, 0x00, 0x15, 0x73, 0xf8, 0x09, 0x11, 0x64, 0xa3, 2030x28, 0x2a, 0x03, 0x00, 0x1c, 0x00, 0x11, 0x61, 0x13, 0x00,
2030x0a, 0x12, 0x65, 0x5e, 0x02, 0x31, 0x32, 0x2e, 0x31, 0x36, 2040x15, 0x73, 0xf8, 0x09, 0x11, 0x64, 0xa3, 0x0a, 0x12, 0x65,
2040x03, 0x01, 0xb9, 0x02, 0x50, 0x61, 0x76, 0x61, 0x69, 0x6c, 2050x5e, 0x02, 0x31, 0x32, 0x2e, 0x31, 0x36, 0x03, 0x01, 0xb9,
2050xf2, 0x08, 0x22, 0x2e, 0x29, 0x74, 0x07, 0x14, 0x32, 0x74, 2060x02, 0x50, 0x61, 0x76, 0x61, 0x69, 0x6c, 0xf2, 0x08, 0x22,
2060x07, 0x73, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0xca, 2070x2e, 0x29, 0x74, 0x07, 0x14, 0x32, 0x74, 0x07, 0x71, 0x70,
2070x0b, 0x30, 0x54, 0x68, 0x65, 0xe1, 0x02, 0x05, 0x14, 0x00, 2080x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0xdd, 0x0b, 0x01, 0x21,
2080x02, 0x42, 0x00, 0x04, 0x3d, 0x00, 0x04, 0x15, 0x0a, 0xf1, 2090x05, 0x00, 0xe1, 0x02, 0x05, 0x14, 0x00, 0x02, 0x42, 0x00,
2090x01, 0x65, 0x00, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 2100x04, 0x3d, 0x00, 0x04, 0x15, 0x0a, 0xf1, 0x01, 0x65, 0x00,
2100x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x70, 0x00, 0x03, 2110x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e,
2110x18, 0x07, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 2120x27, 0x00, 0x6f, 0x70, 0x70, 0x00, 0x03, 0x18, 0x07, 0xb0,
2120x6d, 0x65, 0x6e, 0x75, 0xac, 0x00, 0x51, 0x47, 0x72, 0x69, 2130x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e,
2130x64, 0x20, 0xb0, 0x0b, 0x33, 0x00, 0x00, 0x53, 0xc2, 0x08, 2140x75, 0xac, 0x00, 0x51, 0x47, 0x72, 0x69, 0x64, 0x20, 0xb0,
2140x1f, 0x73, 0xc5, 0x0b, 0x04, 0x11, 0x4c, 0xc8, 0x05, 0x32, 2150x0b, 0x33, 0x00, 0x00, 0x53, 0xc2, 0x08, 0x1f, 0x73, 0xc5,
2150x6c, 0x69, 0x6d, 0x5c, 0x01, 0x68, 0x33, 0x3b, 0x00, 0x75, 2160x0b, 0x04, 0x11, 0x4c, 0xc8, 0x05, 0x32, 0x6c, 0x69, 0x6d,
2160x70, 0x70, 0x12, 0x00, 0x74, 0x39, 0x00, 0x28, 0x62, 0x65, 2170x5c, 0x01, 0x68, 0x33, 0x3b, 0x00, 0x75, 0x70, 0x70, 0x12,
2170x63, 0x61, 0xd7, 0x06, 0x20, 0x75, 0x73, 0xbe, 0x02, 0x00, 2180x00, 0x74, 0x39, 0x00, 0x28, 0x62, 0x65, 0x63, 0x61, 0xd7,
2180x5d, 0x02, 0x11, 0x66, 0xa7, 0x03, 0x01, 0xde, 0x09, 0x21, 2190x06, 0x20, 0x75, 0x73, 0xbe, 0x02, 0x00, 0x5d, 0x02, 0x11,
2190x62, 0x65, 0x68, 0x09, 0x01, 0x32, 0x05, 0x40, 0x64, 0x69, 2200x66, 0xa7, 0x03, 0x01, 0xde, 0x09, 0x21, 0x62, 0x65, 0x68,
2200x66, 0x66, 0x2a, 0x05, 0x12, 0x74, 0x6b, 0x03, 0x11, 0x60, 2210x09, 0x01, 0x32, 0x05, 0x40, 0x64, 0x69, 0x66, 0x66, 0x2a,
2210x0c, 0x02, 0x70, 0x73, 0x27, 0x00, 0x62, 0x69, 0x67, 0x67, 2220x05, 0x12, 0x74, 0x6b, 0x03, 0x11, 0x60, 0x0c, 0x02, 0x70,
2220xb8, 0x0a, 0x61, 0x68, 0x61, 0x6e, 0x00, 0x39, 0x21, 0x12, 2230x73, 0x27, 0x00, 0x62, 0x69, 0x67, 0x67, 0xb8, 0x0a, 0x61,
2230x07, 0x14, 0x44, 0x2b, 0x00, 0x34, 0x79, 0x00, 0x00, 0xbe, 2240x68, 0x61, 0x6e, 0x00, 0x39, 0x21, 0x12, 0x07, 0x14, 0x44,
2240x01, 0x13, 0x73, 0x9d, 0x03, 0x05, 0x1a, 0x00, 0x04, 0xae, 2250x2b, 0x00, 0x34, 0x79, 0x00, 0x00, 0xbe, 0x01, 0x13, 0x73,
2250x00, 0x50, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x25, 0x03, 0x02, 2260x9d, 0x03, 0x05, 0x1a, 0x00, 0x04, 0xae, 0x00, 0x50, 0x65,
2260x32, 0x09, 0x70, 0x2e, 0x00, 0x41, 0x74, 0x00, 0x55, 0x6e, 2270x6e, 0x65, 0x72, 0x61, 0x25, 0x03, 0x02, 0x32, 0x09, 0x70,
2270x30, 0x0a, 0x21, 0x6f, 0x6e, 0x28, 0x01, 0x53, 0x6c, 0x65, 2280x2e, 0x00, 0x41, 0x74, 0x00, 0x55, 0x6e, 0x30, 0x0a, 0x21,
2280x76, 0x65, 0x6c, 0xc7, 0x09, 0x72, 0x62, 0x61, 0x63, 0x6b, 2290x6f, 0x6e, 0x28, 0x01, 0x53, 0x6c, 0x65, 0x76, 0x65, 0x6c,
2290x74, 0x72, 0x61, 0x71, 0x02, 0x04, 0x36, 0x07, 0x82, 0x72, 2300xc7, 0x09, 0x72, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61,
2300x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x2a, 0x09, 0x01, 2310x71, 0x02, 0x04, 0x36, 0x07, 0x82, 0x72, 0x65, 0x71, 0x75,
2310x0f, 0x01, 0x31, 0x6f, 0x6c, 0x75, 0x48, 0x01, 0x21, 0x73, 2320x69, 0x72, 0x65, 0x64, 0x2a, 0x09, 0x01, 0x0f, 0x01, 0x31,
2320x68, 0xc8, 0x00, 0x23, 0x73, 0x74, 0x2b, 0x00, 0x71, 0x75, 2330x6f, 0x6c, 0x75, 0x48, 0x01, 0x21, 0x73, 0x68, 0xc8, 0x00,
2330x6e, 0x69, 0x71, 0x75, 0x65, 0x2e, 0xbc, 0x06, 0x33, 0x72, 2340x23, 0x73, 0x74, 0x2b, 0x00, 0x71, 0x75, 0x6e, 0x69, 0x71,
2340x65, 0x6d, 0xf6, 0x06, 0x01, 0x62, 0x00, 0x14, 0x73, 0x48, 2350x75, 0x65, 0x2e, 0xbc, 0x06, 0x33, 0x72, 0x65, 0x6d, 0xf6,
2350x00, 0x07, 0xfa, 0x0a, 0x00, 0xdc, 0x08, 0x10, 0x6f, 0x65, 2360x06, 0x01, 0x62, 0x00, 0x14, 0x73, 0x48, 0x00, 0x07, 0xfa,
2360x0b, 0x22, 0x78, 0x00, 0x91, 0x00, 0x01, 0xaf, 0x0b, 0x00, 2370x0a, 0x00, 0xdc, 0x08, 0x10, 0x6f, 0x65, 0x0b, 0x22, 0x78,
2370x02, 0x02, 0x30, 0x6f, 0x69, 0x64, 0x1a, 0x03, 0x03, 0x10, 2380x00, 0x91, 0x00, 0x01, 0xaf, 0x0b, 0x00, 0x02, 0x02, 0x30,
2380x00, 0xb0, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 2390x6f, 0x69, 0x64, 0x1a, 0x03, 0x03, 0x10, 0x00, 0x05, 0x97,
2390x6b, 0x2e, 0x00, 2400x00, 0x03, 0x85, 0x09, 0x14, 0x33, 0x11, 0x02, 0x00, 0x56,
2410x01, 0xb1, 0x20, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65,
2420x6e, 0x63, 0x65, 0x17, 0x02, 0x20, 0x4f, 0x6e, 0x45, 0x09,
2430x63, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0xe9, 0x08, 0x62,
2440x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x84, 0x01, 0x07, 0x2e,
2450x00, 0x12, 0x2c, 0x05, 0x02, 0x16, 0x50, 0x12, 0x00, 0x0d,
2460x21, 0x02, 0x33, 0x47, 0x61, 0x6d, 0x21, 0x02, 0x02, 0x0f,
2470x01, 0x32, 0x6c, 0x65, 0x74, 0x2b, 0x04, 0x73, 0x6f, 0x6e,
2480x66, 0x69, 0x67, 0x75, 0x72, 0x23, 0x06, 0x36, 0x74, 0x79,
2490x6c, 0x20, 0x02, 0x20, 0x61, 0x6d, 0x89, 0x01, 0x10, 0x73,
2500xca, 0x09, 0x05, 0x3c, 0x09, 0x02, 0x5e, 0x0a, 0x00, 0x3f,
2510x03, 0x02, 0x85, 0x0b, 0xf1, 0x01, 0x68, 0x72, 0x65, 0x65,
2520x2d, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
2530x61, 0x6c, 0x8e, 0x04, 0x50, 0x2c, 0x00, 0x73, 0x65, 0x6c,
2540x12, 0x03, 0x72, 0x6e, 0x67, 0x00, 0x60, 0x32, 0x44, 0x27,
2550x73, 0x00, 0x61, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x17,
2560x01, 0x02, 0x11, 0x0a, 0x24, 0x65, 0x72, 0x5f, 0x00, 0x03,
2570x79, 0x00, 0x05, 0xc5, 0x04, 0x07, 0xdd, 0x0c, 0xa0, 0x73,
2580x68, 0x6f, 0x77, 0x6e, 0x00, 0x62, 0x79, 0x00, 0x6a, 0xcf,
2590x0b, 0x42, 0x77, 0x72, 0x69, 0x74, 0x0b, 0x0d, 0x24, 0x65,
2600x69, 0x92, 0x0c, 0x07, 0xf4, 0x06, 0x50, 0x61, 0x72, 0x65,
2610x2e, 0x00,
240}; 262};
241 263
242const unsigned short help_text_len = 3541; 264const unsigned short help_text_len = 3906;
243const unsigned short help_text_words = 674; 265const unsigned short help_text_words = 732;
244const char quick_help_text[] = "Complete the latin square of towers in accordance with the clues."; 266const char quick_help_text[] = "Complete the latin square of towers in accordance with the clues.";
diff --git a/apps/plugins/puzzles/help/tracks.c b/apps/plugins/puzzles/help/tracks.c
index dc1bd011fa..fae974619a 100644
--- a/apps/plugins/puzzles/help/tracks.c
+++ b/apps/plugins/puzzles/help/tracks.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,27 +6,28 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 86, TEXT_CENTER | C_RED }, 9 { 88, TEXT_CENTER | C_RED },
10 { 207, TEXT_CENTER | C_RED }, 10 { 209, TEXT_CENTER | C_RED },
11 { 224, TEXT_UNDERLINE }, 11 { 226, TEXT_UNDERLINE },
12 { 225, TEXT_UNDERLINE }, 12 { 227, TEXT_UNDERLINE },
13 { 236, TEXT_UNDERLINE }, 13 { 238, TEXT_UNDERLINE },
14 { 268, TEXT_UNDERLINE }, 14 { 270, TEXT_UNDERLINE },
15 LAST_STYLE_ITEM 15 LAST_STYLE_ITEM
16}; 16};
17 17
18/* orig 1862 comp 1274 ratio 0.684211 level 10 saved 588 */ 18/* orig 1917 comp 1289 ratio 0.672405 level 10 saved 628 */
19const char help_text[] = { 19const char help_text[] = {
200xf0, 0x2c, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 200xf0, 0x02, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
210x34, 0x30, 0x3a, 0x20, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x73, 210x34, 0x30, 0x3a, 0x20, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x06,
220x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x61, 0x72, 220x00, 0x6f, 0x63, 0x6b, 0x73, 0x20, 0x00, 0x2d, 0x01, 0x00,
230x65, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 230x04, 0xf0, 0x19, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00,
240x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 240x61, 0x72, 0x65, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x00,
250x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x73, 0x6f, 0x6d, 250x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00,
260x65, 0x11, 0x00, 0x51, 0x77, 0x68, 0x69, 0x63, 0x68, 0x2b, 260x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x73,
270x00, 0xf1, 0x04, 0x66, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x00, 270x6f, 0x6d, 0x65, 0x11, 0x00, 0x51, 0x77, 0x68, 0x69, 0x63,
280x77, 0x69, 0x74, 0x68, 0x00, 0x74, 0x72, 0x61, 0x69, 0x6e, 280x68, 0x2b, 0x00, 0xd0, 0x66, 0x69, 0x6c, 0x6c, 0x65, 0x64,
290x00, 0x74, 0x4f, 0x00, 0x11, 0x2e, 0x4d, 0x00, 0xf2, 0x05, 290x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x74, 0x68, 0x00, 0x21,
300x00, 0x74, 0x68, 0x00, 0x11, 0x2e, 0x4d, 0x00, 0xf2, 0x05,
300x6e, 0x65, 0x65, 0x64, 0x00, 0x74, 0x6f, 0x00, 0x63, 0x6f, 310x6e, 0x65, 0x65, 0x64, 0x00, 0x74, 0x6f, 0x00, 0x63, 0x6f,
310x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x00, 0x74, 0x68, 0x65, 320x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x00, 0x74, 0x68, 0x65,
320x21, 0x00, 0x70, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x00, 0x41, 330x21, 0x00, 0x70, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x00, 0x41,
@@ -49,104 +50,104 @@ const char help_text[] = {
490x00, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x2c, 0x1c, 0x00, 0x06, 500x00, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x2c, 0x1c, 0x00, 0x06,
500xd7, 0x00, 0xf1, 0x05, 0x6d, 0x61, 0x79, 0x00, 0x6e, 0x6f, 510xd7, 0x00, 0xf1, 0x05, 0x6d, 0x61, 0x79, 0x00, 0x6e, 0x6f,
510x74, 0x00, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x00, 0x69, 0x74, 520x74, 0x00, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x00, 0x69, 0x74,
520x73, 0x65, 0x6c, 0x66, 0x5a, 0x00, 0x01, 0x16, 0x01, 0x32, 530x73, 0x65, 0x6c, 0x66, 0x5a, 0x00, 0x01, 0x1c, 0x01, 0x02,
530x00, 0x77, 0x61, 0xd1, 0x00, 0x40, 0x72, 0x69, 0x62, 0x75, 540x84, 0x01, 0x32, 0x00, 0x77, 0x61, 0xd7, 0x00, 0x40, 0x72,
540xa2, 0x00, 0x01, 0x95, 0x00, 0x20, 0x69, 0x73, 0xed, 0x00, 550x69, 0x62, 0x75, 0xa8, 0x00, 0x01, 0x9b, 0x00, 0x20, 0x69,
550xf0, 0x08, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 560x73, 0xf3, 0x00, 0xf0, 0x08, 0x6c, 0x65, 0x63, 0x74, 0x69,
560x62, 0x79, 0x00, 0x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 570x6f, 0x6e, 0x00, 0x62, 0x79, 0x00, 0x4a, 0x61, 0x6d, 0x65,
570x61, 0x72, 0x76, 0x65, 0x79, 0x3d, 0x00, 0x44, 0x34, 0x30, 580x73, 0x00, 0x48, 0x61, 0x72, 0x76, 0x65, 0x79, 0x43, 0x00,
580x2e, 0x31, 0xa7, 0x01, 0x01, 0x3e, 0x00, 0x21, 0x6f, 0x6c, 590x4a, 0x34, 0x30, 0x2e, 0x31, 0xcc, 0x01, 0x01, 0x44, 0x00,
590xb0, 0x01, 0xf4, 0x15, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 600xf4, 0x1c, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00, 0x00, 0x4c,
600x6c, 0x69, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x00, 0x6f, 0x6e, 610x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x69,
610x00, 0x61, 0x6e, 0x00, 0x65, 0x64, 0x67, 0x65, 0x00, 0x62, 620x6e, 0x67, 0x00, 0x6f, 0x6e, 0x00, 0x61, 0x6e, 0x00, 0x65,
620x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x00, 0x74, 0x77, 0x6f, 630x64, 0x67, 0x65, 0x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65,
630xbd, 0x01, 0x7a, 0x00, 0x61, 0x64, 0x64, 0x73, 0x00, 0x61, 640x6e, 0x00, 0x74, 0x77, 0x6f, 0xc9, 0x01, 0x7a, 0x00, 0x61,
640x34, 0x01, 0x06, 0x29, 0x00, 0x28, 0x68, 0x65, 0x2d, 0x00, 650x64, 0x64, 0x73, 0x00, 0x61, 0x40, 0x01, 0x06, 0x29, 0x00,
650x30, 0x2e, 0x00, 0x52, 0xf8, 0x00, 0x0f, 0x5c, 0x00, 0x02, 660x28, 0x68, 0x65, 0x2d, 0x00, 0x30, 0x2e, 0x00, 0x52, 0x04,
660x03, 0x48, 0x00, 0x02, 0xe1, 0x00, 0x12, 0x6f, 0x3b, 0x00, 670x01, 0x0f, 0x5c, 0x00, 0x02, 0x03, 0x48, 0x00, 0x02, 0xed,
670x00, 0x19, 0x00, 0x14, 0x2c, 0x79, 0x01, 0x00, 0x30, 0x00, 680x00, 0x12, 0x6f, 0x3b, 0x00, 0x00, 0x19, 0x00, 0x14, 0x2c,
680x23, 0x6e, 0x6f, 0x69, 0x00, 0xa1, 0x69, 0x73, 0x00, 0x70, 690x85, 0x01, 0x00, 0x30, 0x00, 0x23, 0x6e, 0x6f, 0x69, 0x00,
690x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0xfd, 0x01, 0x3d, 0x72, 700xa1, 0x69, 0x73, 0x00, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62,
700x65, 0x2e, 0xb8, 0x00, 0x10, 0x69, 0x6b, 0x02, 0x02, 0x79, 710x6c, 0x09, 0x02, 0x3d, 0x72, 0x65, 0x2e, 0xb8, 0x00, 0x10,
710x00, 0x05, 0x5d, 0x00, 0x54, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 720x69, 0x77, 0x02, 0x02, 0x79, 0x00, 0x05, 0x5d, 0x00, 0x54,
720x51, 0x00, 0x70, 0x6f, 0x72, 0x00, 0x73, 0x68, 0x6f, 0x77, 730x6f, 0x6c, 0x6f, 0x75, 0x72, 0x51, 0x00, 0x70, 0x6f, 0x72,
730x2c, 0x00, 0x01, 0x27, 0x02, 0x82, 0x79, 0x6f, 0x75, 0x00, 740x00, 0x73, 0x68, 0x6f, 0x77, 0x2c, 0x00, 0x01, 0x33, 0x02,
740x6b, 0x6e, 0x6f, 0x77, 0x13, 0x02, 0x02, 0x39, 0x00, 0x45, 750x82, 0x79, 0x6f, 0x75, 0x00, 0x6b, 0x6e, 0x6f, 0x77, 0x1f,
750x6d, 0x75, 0x73, 0x74, 0x2b, 0x02, 0x03, 0xe6, 0x00, 0x30, 760x02, 0x02, 0x39, 0x00, 0x45, 0x6d, 0x75, 0x73, 0x74, 0x37,
760x2c, 0x00, 0x65, 0xc8, 0x02, 0x21, 0x69, 0x66, 0x32, 0x00, 770x02, 0x03, 0xe6, 0x00, 0x30, 0x2c, 0x00, 0x65, 0xd4, 0x02,
770x52, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x38, 0x00, 0x02, 0xbf, 780x21, 0x69, 0x66, 0x32, 0x00, 0x52, 0x64, 0x6f, 0x6e, 0x27,
780x02, 0x00, 0xb5, 0x00, 0x00, 0xa3, 0x01, 0x02, 0xcb, 0x00, 790x74, 0x38, 0x00, 0x02, 0xcb, 0x02, 0x00, 0xb5, 0x00, 0x00,
790x6d, 0x65, 0x73, 0x00, 0x79, 0x65, 0x74, 0xf9, 0x00, 0x0e, 800xaf, 0x01, 0x02, 0xcb, 0x00, 0x6d, 0x65, 0x73, 0x00, 0x79,
800x9d, 0x00, 0x04, 0xdb, 0x01, 0x06, 0xed, 0x00, 0x15, 0x69, 810x65, 0x74, 0xf9, 0x00, 0x0e, 0x9d, 0x00, 0x04, 0xe7, 0x01,
810x7a, 0x00, 0x16, 0x73, 0xf9, 0x00, 0x03, 0x62, 0x01, 0x05, 820x06, 0xed, 0x00, 0x15, 0x69, 0x7a, 0x00, 0x16, 0x73, 0xf9,
820xef, 0x00, 0x32, 0x00, 0x6f, 0x72, 0x74, 0x02, 0x60, 0x2d, 830x00, 0x03, 0x62, 0x01, 0x05, 0xef, 0x00, 0x32, 0x00, 0x6f,
830x64, 0x72, 0x61, 0x67, 0x67, 0x38, 0x00, 0x04, 0x7d, 0x01, 840x72, 0x80, 0x02, 0x60, 0x2d, 0x64, 0x72, 0x61, 0x67, 0x67,
840x05, 0xa2, 0x01, 0x20, 0x6c, 0x6c, 0xfd, 0x02, 0x00, 0xad, 850x38, 0x00, 0x04, 0x7d, 0x01, 0x05, 0xa2, 0x01, 0x20, 0x6c,
850x00, 0x86, 0x74, 0x6f, 0x00, 0x6c, 0x61, 0x79, 0x00, 0x61, 860x6c, 0x09, 0x03, 0x00, 0xad, 0x00, 0x86, 0x74, 0x6f, 0x00,
860x83, 0x02, 0x31, 0x6c, 0x69, 0x6e, 0x7b, 0x03, 0x32, 0x69, 870x6c, 0x61, 0x79, 0x00, 0x61, 0x8f, 0x02, 0x31, 0x6c, 0x69,
870x73, 0x2d, 0x61, 0x00, 0x20, 0x6f, 0x72, 0x0c, 0x00, 0x33, 880x6e, 0x87, 0x03, 0x32, 0x69, 0x73, 0x2d, 0x61, 0x00, 0x20,
880x6e, 0x6f, 0x74, 0x10, 0x00, 0x05, 0x2d, 0x01, 0xd1, 0x73, 890x6f, 0x72, 0x0c, 0x00, 0x33, 0x6e, 0x6f, 0x74, 0x10, 0x00,
890x2c, 0x00, 0x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x00, 0x66, 900x05, 0x2d, 0x01, 0xd1, 0x73, 0x2c, 0x00, 0x75, 0x73, 0x65,
900x6f, 0x72, 0xa1, 0x03, 0x03, 0xc9, 0x00, 0x01, 0x5b, 0x03, 910x66, 0x75, 0x6c, 0x00, 0x66, 0x6f, 0x72, 0xad, 0x03, 0x03,
910x25, 0x6f, 0x72, 0x5a, 0x03, 0x85, 0x74, 0x6f, 0x00, 0x6d, 920xc9, 0x00, 0x01, 0x67, 0x03, 0x25, 0x6f, 0x72, 0x66, 0x03,
920x61, 0x74, 0x63, 0x68, 0x25, 0x03, 0x00, 0xad, 0x00, 0x41, 930x85, 0x74, 0x6f, 0x00, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x31,
930x28, 0x41, 0x6c, 0x6c, 0x11, 0x00, 0x11, 0x61, 0x8f, 0x02, 940x03, 0x00, 0xad, 0x00, 0x41, 0x28, 0x41, 0x6c, 0x6c, 0x11,
940x92, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 950x00, 0x11, 0x61, 0x95, 0x02, 0x92, 0x73, 0x00, 0x64, 0x65,
950x4f, 0x03, 0x13, 0x73, 0xa5, 0x02, 0x41, 0x32, 0x2e, 0x31, 960x73, 0x63, 0x72, 0x69, 0x62, 0x5b, 0x03, 0x13, 0x73, 0xab,
960x00, 0x13, 0x01, 0xf2, 0x00, 0x6c, 0x73, 0x6f, 0x00, 0x61, 970x02, 0x41, 0x32, 0x2e, 0x31, 0x00, 0x13, 0x01, 0xf2, 0x00,
970x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 980x6c, 0x73, 0x6f, 0x00, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,
980xad, 0x02, 0x14, 0x32, 0xad, 0x02, 0xb2, 0x70, 0x61, 0x72, 990x62, 0x6c, 0x65, 0x2e, 0x29, 0xb3, 0x02, 0x1a, 0x32, 0xb3,
990x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x5e, 0x03, 1000x02, 0xb2, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
1000x36, 0x73, 0x65, 0x00, 0x14, 0x00, 0x02, 0x42, 0x00, 0x04, 1010x72, 0x73, 0x20, 0x70, 0x03, 0x36, 0x73, 0x65, 0x00, 0x14,
1010x3d, 0x00, 0x02, 0x12, 0x04, 0x00, 0x7a, 0x00, 0xe1, 0x60, 1020x00, 0x02, 0x48, 0x00, 0x04, 0x43, 0x00, 0x02, 0x24, 0x04,
1020x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 1030x00, 0x80, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f,
1030x00, 0x6f, 0x70, 0x70, 0x00, 0x03, 0x68, 0x02, 0xb0, 0x60, 1040x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x76, 0x00,
1040x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 1050x03, 0x6e, 0x02, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27,
1050xac, 0x00, 0x91, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 1060x00, 0x6d, 0x65, 0x6e, 0x75, 0xb2, 0x00, 0x91, 0x57, 0x69,
1060x48, 0x65, 0x22, 0x01, 0x68, 0x00, 0x00, 0x53, 0x69, 0x7a, 1070x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x28, 0x01, 0x68,
1070x65, 0xd3, 0x03, 0x00, 0x93, 0x02, 0x06, 0xd3, 0x02, 0xf3, 1080x00, 0x00, 0x53, 0x69, 0x7a, 0x65, 0xe5, 0x03, 0x00, 0x99,
1080x01, 0x00, 0x00, 0x44, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 1090x02, 0x06, 0xd9, 0x02, 0xf3, 0x01, 0x00, 0x00, 0x44, 0x69,
1090x6c, 0x74, 0x79, 0x00, 0x00, 0x00, 0x43, 0x49, 0x03, 0x01, 1100x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x00, 0x00,
1100x2e, 0x00, 0x16, 0x64, 0x1a, 0x00, 0x04, 0x40, 0x00, 0x41, 1110x00, 0x43, 0x4f, 0x03, 0x01, 0x2e, 0x00, 0x16, 0x64, 0x1a,
1110x65, 0x6e, 0x65, 0x72, 0x46, 0x04, 0xf3, 0x0b, 0x70, 0x75, 1120x00, 0x04, 0x40, 0x00, 0x41, 0x65, 0x6e, 0x65, 0x72, 0x58,
1120x7a, 0x7a, 0x6c, 0x65, 0x3a, 0x00, 0x61, 0x74, 0x00, 0x54, 1130x04, 0xf3, 0x0b, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x3a,
1130x72, 0x69, 0x63, 0x6b, 0x79, 0x00, 0x6c, 0x65, 0x76, 0x65, 1140x00, 0x61, 0x74, 0x00, 0x54, 0x72, 0x69, 0x63, 0x6b, 0x79,
1140x6c, 0x2c, 0x00, 0x79, 0x2f, 0x05, 0x82, 0x72, 0x65, 0x71, 1150x00, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2c, 0x00, 0x79, 0x41,
1150x75, 0x69, 0x72, 0x65, 0x64, 0x51, 0x01, 0xc3, 0x6b, 0x65, 1160x05, 0x82, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64,
1160x00, 0x6d, 0x6f, 0x72, 0x65, 0x00, 0x64, 0x65, 0x64, 0x75, 1170x57, 0x01, 0xc3, 0x6b, 0x65, 0x00, 0x6d, 0x6f, 0x72, 0x65,
1170x43, 0x01, 0x60, 0x72, 0x65, 0x67, 0x61, 0x72, 0x64, 0x86, 1180x00, 0x64, 0x65, 0x64, 0x75, 0x49, 0x01, 0x60, 0x72, 0x65,
1180x01, 0x36, 0x64, 0x69, 0x73, 0x0d, 0x00, 0x52, 0x6d, 0x6f, 1190x67, 0x61, 0x72, 0x64, 0x8c, 0x01, 0x36, 0x64, 0x69, 0x73,
1190x76, 0x65, 0x73, 0xd3, 0x02, 0x91, 0x77, 0x6f, 0x75, 0x6c, 1200x0d, 0x00, 0x52, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0xd9, 0x02,
1200x64, 0x00, 0x6c, 0x65, 0x61, 0x45, 0x00, 0x25, 0x69, 0x6d, 1210x91, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x00, 0x6c, 0x65, 0x61,
1210x34, 0x03, 0x01, 0x6d, 0x02, 0xa2, 0x69, 0x6e, 0x67, 0x73, 1220x45, 0x00, 0x25, 0x69, 0x6d, 0x3a, 0x03, 0x01, 0x73, 0x02,
1220x00, 0x6c, 0x61, 0x74, 0x65, 0x72, 0xc6, 0x00, 0x11, 0x73, 1230xa2, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x6c, 0x61, 0x74, 0x65,
1230x2a, 0x02, 0x00, 0x0b, 0x04, 0xb2, 0x73, 0x65, 0x63, 0x75, 1240x72, 0xc6, 0x00, 0x11, 0x73, 0x30, 0x02, 0x00, 0x11, 0x04,
1240x74, 0x69, 0x76, 0x65, 0x20, 0x31, 0x20, 0xe6, 0x04, 0x07, 1250xb2, 0x73, 0x65, 0x63, 0x75, 0x74, 0x69, 0x76, 0x65, 0x20,
1250xd8, 0x00, 0x30, 0x77, 0x68, 0x65, 0x72, 0x03, 0x01, 0xce, 1260x31, 0x20, 0xf8, 0x04, 0x07, 0xd8, 0x00, 0x30, 0x77, 0x68,
1260x00, 0x03, 0x7f, 0x04, 0x35, 0x67, 0x61, 0x6d, 0xda, 0x00, 1270x65, 0x78, 0x03, 0x01, 0xce, 0x00, 0x09, 0x91, 0x04, 0x35,
1270x00, 0x57, 0x01, 0x71, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 1280x67, 0x61, 0x6d, 0xe0, 0x00, 0x00, 0x5d, 0x01, 0x71, 0x70,
1280x73, 0xfb, 0x03, 0x50, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x14, 1290x65, 0x72, 0x6d, 0x69, 0x74, 0x73, 0x07, 0x04, 0x50, 0x61,
1290x04, 0x0f, 0x27, 0x02, 0x00, 0x81, 0x68, 0x61, 0x76, 0x65, 1300x64, 0x6a, 0x61, 0x63, 0x20, 0x04, 0x0f, 0x33, 0x02, 0x00,
1300x00, 0x61, 0x00, 0x31, 0x26, 0x02, 0x10, 0x2c, 0x1d, 0x00, 1310x81, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x31, 0x32,
1310x05, 0x3a, 0x00, 0x02, 0xb3, 0x05, 0x06, 0x30, 0x00, 0x04, 1320x02, 0x10, 0x2c, 0x1d, 0x00, 0x05, 0x3a, 0x00, 0x02, 0xcb,
1320x40, 0x01, 0x01, 0x95, 0x02, 0xbd, 0x27, 0x73, 0x00, 0x65, 1330x05, 0x06, 0x30, 0x00, 0x04, 0x46, 0x01, 0x01, 0xa1, 0x02,
1330x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x47, 0x00, 0xc2, 1340xbd, 0x27, 0x73, 0x00, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69,
1340x2e, 0x00, 0x42, 0x79, 0x00, 0x64, 0x65, 0x66, 0x61, 0x75, 1350x6e, 0x74, 0x47, 0x00, 0xc2, 0x2e, 0x00, 0x42, 0x79, 0x00,
1350x6c, 0x74, 0x05, 0x05, 0x21, 0x69, 0x73, 0x3b, 0x05, 0x02, 1360x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x17, 0x05, 0x21,
1360x5b, 0x00, 0x60, 0x74, 0x65, 0x64, 0x2c, 0x00, 0x74, 0x5d, 1370x69, 0x73, 0x53, 0x05, 0x02, 0x5b, 0x00, 0x60, 0x74, 0x65,
1370x02, 0x86, 0x6f, 0x69, 0x64, 0x00, 0x6c, 0x6f, 0x6e, 0x67, 1380x64, 0x2c, 0x00, 0x74, 0x69, 0x02, 0x86, 0x6f, 0x69, 0x64,
1380x0c, 0x03, 0x30, 0x62, 0x6f, 0x72, 0x40, 0x01, 0x05, 0xf9, 1390x00, 0x6c, 0x6f, 0x6e, 0x67, 0x18, 0x03, 0x30, 0x62, 0x6f,
1390x05, 0x05, 0x0b, 0x06, 0x00, 0x8c, 0x05, 0x01, 0x82, 0x01, 1400x72, 0x46, 0x01, 0x05, 0x11, 0x06, 0x05, 0x23, 0x06, 0x00,
1400x01, 0xc2, 0x01, 0x01, 0x46, 0x05, 0x01, 0x8c, 0x01, 0x71, 1410xa4, 0x05, 0x01, 0x88, 0x01, 0x01, 0xc8, 0x01, 0x01, 0x58,
1410x74, 0x77, 0x69, 0x64, 0x64, 0x6c, 0x79, 0x20, 0x00, 0x70, 1420x05, 0x01, 0x92, 0x01, 0x71, 0x74, 0x77, 0x69, 0x64, 0x64,
1420x69, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x73, 0xba, 0x03, 0x32, 1430x6c, 0x79, 0x20, 0x00, 0x70, 0x69, 0x6e, 0x74, 0x65, 0x72,
1430x2e, 0x00, 0x49, 0x1c, 0x04, 0x22, 0x77, 0x61, 0xa1, 0x00, 1440x65, 0x73, 0xc6, 0x03, 0x32, 0x2e, 0x00, 0x49, 0x28, 0x04,
1440x00, 0x18, 0x00, 0x22, 0x6f, 0x72, 0x3f, 0x00, 0x02, 0x83, 1450x22, 0x77, 0x61, 0xa1, 0x00, 0x00, 0x18, 0x00, 0x22, 0x6f,
1450x01, 0xb2, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2c, 0x00, 0x74, 1460x72, 0x3f, 0x00, 0x02, 0x89, 0x01, 0xb2, 0x69, 0x6c, 0x69,
1460x75, 0x72, 0x6e, 0xa5, 0x00, 0x03, 0x91, 0x02, 0x50, 0x6f, 1470x74, 0x79, 0x2c, 0x00, 0x74, 0x75, 0x72, 0x6e, 0xa5, 0x00,
1470x66, 0x66, 0x2e, 0x00, 1480x03, 0x97, 0x02, 0x50, 0x6f, 0x66, 0x66, 0x2e, 0x00,
148}; 149};
149 150
150const unsigned short help_text_len = 1862; 151const unsigned short help_text_len = 1917;
151const unsigned short help_text_words = 336; 152const unsigned short help_text_words = 339;
152const char quick_help_text[] = "Fill in the railway track according to the clues."; 153const char quick_help_text[] = "Fill in the railway track according to the clues.";
diff --git a/apps/plugins/puzzles/help/twiddle.c b/apps/plugins/puzzles/help/twiddle.c
index 48efbc10ad..1a989237b0 100644
--- a/apps/plugins/puzzles/help/twiddle.c
+++ b/apps/plugins/puzzles/help/twiddle.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,202 +6,203 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 137, TEXT_CENTER | C_RED }, 9 { 138, TEXT_CENTER | C_RED },
10 { 297, TEXT_CENTER | C_RED }, 10 { 298, TEXT_CENTER | C_RED },
11 LAST_STYLE_ITEM 11 LAST_STYLE_ITEM
12}; 12};
13 13
14/* orig 2926 comp 1866 ratio 0.637731 level 10 saved 1060 */ 14/* orig 2945 comp 1873 ratio 0.635993 level 10 saved 1072 */
15const char help_text[] = { 15const char help_text[] = {
160xf3, 0x07, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 160xfd, 0x06, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
170x37, 0x3a, 0x20, 0x54, 0x77, 0x69, 0x64, 0x64, 0x6c, 0x65, 170x37, 0x3a, 0x20, 0x54, 0x77, 0x69, 0x64, 0x64, 0x6c, 0x65,
180x20, 0x00, 0x00, 0x00, 0x0b, 0x00, 0xf2, 0x34, 0x00, 0x69, 180x20, 0x00, 0x2d, 0x01, 0x00, 0x33, 0x00, 0x00, 0x00, 0x1e,
190x73, 0x00, 0x61, 0x00, 0x74, 0x69, 0x6c, 0x65, 0x2d, 0x72, 190x00, 0xf2, 0x34, 0x00, 0x69, 0x73, 0x00, 0x61, 0x00, 0x74,
200x65, 0x61, 0x72, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x6d, 0x65, 200x69, 0x6c, 0x65, 0x2d, 0x72, 0x65, 0x61, 0x72, 0x72, 0x61,
210x6e, 0x74, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x2c, 210x6e, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x70, 0x75,
220x00, 0x76, 0x69, 0x73, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x00, 220x7a, 0x7a, 0x6c, 0x65, 0x2c, 0x00, 0x76, 0x69, 0x73, 0x75,
230x73, 0x69, 0x6d, 0x69, 0x6c, 0x61, 0x72, 0x00, 0x74, 0x6f, 230x61, 0x6c, 0x6c, 0x79, 0x00, 0x73, 0x69, 0x6d, 0x69, 0x6c,
240x00, 0x53, 0x69, 0x78, 0x74, 0x65, 0x65, 0x6e, 0x00, 0x28, 240x61, 0x72, 0x00, 0x74, 0x6f, 0x00, 0x53, 0x69, 0x78, 0x74,
250x73, 0x65, 0x65, 0x00, 0x63, 0x5f, 0x00, 0xf0, 0x11, 0x00, 250x65, 0x65, 0x6e, 0x00, 0x28, 0x73, 0x65, 0x65, 0x00, 0x63,
260x36, 0x29, 0x3a, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x61, 0x72, 260x72, 0x00, 0xf0, 0x11, 0x00, 0x36, 0x29, 0x3a, 0x00, 0x79,
270x65, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 270x6f, 0x75, 0x00, 0x61, 0x72, 0x65, 0x00, 0x67, 0x69, 0x76,
280x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 280x65, 0x6e, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00,
290x75, 0x17, 0x00, 0x00, 0x67, 0x00, 0xf0, 0x11, 0x73, 0x2c, 290x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x17, 0x00, 0x00, 0x67,
300x00, 0x65, 0x61, 0x63, 0x68, 0x00, 0x63, 0x6f, 0x6e, 0x74, 300x00, 0xf0, 0x11, 0x73, 0x2c, 0x00, 0x65, 0x61, 0x63, 0x68,
310x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x00, 0x61, 0x00, 0x6e, 310x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e,
320x75, 0x6d, 0x62, 0x65, 0x72, 0x2c, 0x00, 0x61, 0x6e, 0x64, 320x67, 0x00, 0x61, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
330x44, 0x00, 0x50, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x9a, 0x00, 330x2c, 0x00, 0x61, 0x6e, 0x64, 0x44, 0x00, 0x50, 0x72, 0x00,
340x33, 0x74, 0x6f, 0x00, 0x94, 0x00, 0x43, 0x00, 0x74, 0x68, 340x61, 0x69, 0x6d, 0x9a, 0x00, 0x33, 0x74, 0x6f, 0x00, 0x94,
350x65, 0x27, 0x00, 0x40, 0x73, 0x00, 0x69, 0x6e, 0x19, 0x00, 350x00, 0x43, 0x00, 0x74, 0x68, 0x65, 0x27, 0x00, 0x40, 0x73,
360x50, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x40, 0x00, 0xf4, 0x02, 360x00, 0x69, 0x6e, 0x19, 0x00, 0x50, 0x73, 0x63, 0x65, 0x6e,
370x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x00, 0x00, 0x00, 0x49, 370x64, 0x40, 0x00, 0xf4, 0x02, 0x6f, 0x72, 0x64, 0x65, 0x72,
380x6e, 0x00, 0x62, 0x61, 0x73, 0x69, 0x63, 0xdd, 0x00, 0x12, 380x2e, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x00, 0x62, 0x61, 0x73,
390x2c, 0x4d, 0x00, 0x43, 0x6d, 0x6f, 0x76, 0x65, 0x4e, 0x00, 390x69, 0x63, 0xdd, 0x00, 0x12, 0x2c, 0x4d, 0x00, 0x43, 0x6d,
400x84, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x00, 0x61, 0x92, 400x6f, 0x76, 0x65, 0x4e, 0x00, 0x84, 0x72, 0x6f, 0x74, 0x61,
410x00, 0x50, 0x67, 0x72, 0x6f, 0x75, 0x70, 0xa2, 0x00, 0x10, 410x74, 0x65, 0x00, 0x61, 0x92, 0x00, 0x50, 0x67, 0x72, 0x6f,
420x66, 0x29, 0x00, 0x01, 0xa0, 0x00, 0x60, 0x00, 0x61, 0x62, 420x75, 0x70, 0xa2, 0x00, 0x10, 0x66, 0x29, 0x00, 0x01, 0xa0,
430x6f, 0x75, 0x74, 0x70, 0x00, 0xf0, 0x0f, 0x69, 0x72, 0x00, 430x00, 0x60, 0x00, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x70, 0x00,
440x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x00, 0x63, 0x65, 0x6e, 440xf0, 0x0f, 0x69, 0x72, 0x00, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
450x74, 0x72, 0x65, 0x2e, 0x00, 0x28, 0x4f, 0x72, 0x69, 0x65, 450x6e, 0x00, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x65, 0x2e, 0x00,
460x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x00, 0xf1, 460x28, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69,
470x03, 0x6e, 0x6f, 0x74, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x69, 470x6f, 0x6e, 0x52, 0x00, 0xf1, 0x03, 0x6e, 0x6f, 0x74, 0x00,
480x66, 0x69, 0x63, 0x61, 0x6e, 0x74, 0x00, 0x69, 0x6e, 0xa8, 480x73, 0x69, 0x67, 0x6e, 0x69, 0x66, 0x69, 0x63, 0x61, 0x6e,
490x00, 0x02, 0x85, 0x00, 0x04, 0x42, 0x01, 0x81, 0x61, 0x6c, 490x74, 0x00, 0x69, 0x6e, 0xa8, 0x00, 0x02, 0x85, 0x00, 0x04,
500x74, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x1e, 0x01, 0xf5, 0x1b, 500x42, 0x01, 0x81, 0x61, 0x6c, 0x74, 0x68, 0x6f, 0x75, 0x67,
510x63, 0x61, 0x6e, 0x00, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 510x68, 0x1e, 0x01, 0xf5, 0x1b, 0x63, 0x61, 0x6e, 0x00, 0x73,
520x00, 0x69, 0x74, 0x2e, 0x29, 0x00, 0x4f, 0x6e, 0x00, 0x6d, 520x65, 0x6c, 0x65, 0x63, 0x74, 0x00, 0x69, 0x74, 0x2e, 0x29,
530x6f, 0x72, 0x65, 0x00, 0x61, 0x64, 0x76, 0x61, 0x6e, 0x63, 530x00, 0x4f, 0x6e, 0x00, 0x6d, 0x6f, 0x72, 0x65, 0x00, 0x61,
540x65, 0x64, 0x00, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 540x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x00, 0x73, 0x65,
550x73, 0x2c, 0x2f, 0x00, 0x05, 0xb4, 0x00, 0x6d, 0x6c, 0x61, 550x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2c, 0x2f, 0x00, 0x05,
560x72, 0x67, 0x65, 0x72, 0xbb, 0x00, 0x01, 0xb6, 0x00, 0x01, 560xb4, 0x00, 0x6d, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0xbb,
570xff, 0x00, 0xd0, 0x00, 0x66, 0x69, 0x72, 0x73, 0x74, 0x00, 570x00, 0x01, 0xb6, 0x00, 0x01, 0xff, 0x00, 0xd0, 0x00, 0x66,
580x73, 0x61, 0x77, 0x00, 0x74, 0x68, 0xf1, 0x00, 0x30, 0x79, 580x69, 0x72, 0x73, 0x74, 0x00, 0x73, 0x61, 0x77, 0x00, 0x74,
590x70, 0x65, 0x22, 0x00, 0x02, 0x8a, 0x00, 0x04, 0x9e, 0x00, 590x68, 0xf1, 0x00, 0x30, 0x79, 0x70, 0x65, 0x22, 0x00, 0x02,
600xf2, 0x13, 0x47, 0x61, 0x6d, 0x65, 0x43, 0x75, 0x62, 0x65, 600x8a, 0x00, 0x04, 0x9e, 0x00, 0xf2, 0x13, 0x47, 0x61, 0x6d,
610x00, 0x67, 0x61, 0x6d, 0x65, 0x00, 0x60, 0x4d, 0x65, 0x74, 610x65, 0x43, 0x75, 0x62, 0x65, 0x00, 0x67, 0x61, 0x6d, 0x65,
620x72, 0x6f, 0x69, 0x64, 0x00, 0x50, 0x72, 0x69, 0x6d, 0x65, 620x00, 0x60, 0x4d, 0x65, 0x74, 0x72, 0x6f, 0x69, 0x64, 0x00,
630x00, 0x32, 0x27, 0x2e, 0x00, 0x49, 0x28, 0x00, 0xd0, 0x4d, 630x50, 0x72, 0x69, 0x6d, 0x65, 0x00, 0x32, 0x27, 0x2e, 0x00,
640x61, 0x69, 0x6e, 0x00, 0x47, 0x79, 0x72, 0x6f, 0x00, 0x43, 640x49, 0x28, 0x00, 0xd0, 0x4d, 0x61, 0x69, 0x6e, 0x00, 0x47,
650x68, 0x61, 0x79, 0x01, 0x02, 0x41, 0x00, 0x21, 0x61, 0x74, 650x79, 0x72, 0x6f, 0x00, 0x43, 0x68, 0x61, 0x79, 0x01, 0x02,
660x39, 0x00, 0x10, 0x2c, 0x24, 0x00, 0x13, 0x72, 0x40, 0x02, 660x41, 0x00, 0x21, 0x61, 0x74, 0x39, 0x00, 0x10, 0x2c, 0x24,
670x03, 0x61, 0x00, 0x00, 0xb2, 0x00, 0x50, 0x73, 0x6f, 0x6c, 670x00, 0x13, 0x72, 0x40, 0x02, 0x03, 0x61, 0x00, 0x00, 0xb2,
680x76, 0x65, 0x6b, 0x01, 0xf2, 0x05, 0x75, 0x6e, 0x6c, 0x6f, 680x00, 0x50, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x6b, 0x01, 0xf2,
690x63, 0x6b, 0x00, 0x61, 0x00, 0x64, 0x6f, 0x6f, 0x72, 0x2c, 690x05, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x00, 0x61, 0x00,
700x00, 0x77, 0x68, 0x69, 0x63, 0x68, 0x2e, 0x00, 0xb1, 0x73, 700x64, 0x6f, 0x6f, 0x72, 0x2c, 0x00, 0x77, 0x68, 0x69, 0x63,
710x70, 0x65, 0x63, 0x69, 0x61, 0x6c, 0x00, 0x63, 0x61, 0x73, 710x68, 0x2e, 0x00, 0xb1, 0x73, 0x70, 0x65, 0x63, 0x69, 0x61,
720x9f, 0x00, 0x03, 0xae, 0x01, 0xd2, 0x2e, 0x00, 0x49, 0x00, 720x6c, 0x00, 0x63, 0x61, 0x73, 0x9f, 0x00, 0x03, 0xae, 0x01,
730x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x64, 0xc1, 730xd2, 0x2e, 0x00, 0x49, 0x00, 0x64, 0x65, 0x76, 0x65, 0x6c,
740x00, 0x01, 0xa2, 0x00, 0x20, 0x61, 0x73, 0x4a, 0x02, 0x82, 740x6f, 0x70, 0x65, 0x64, 0xc1, 0x00, 0x01, 0xa2, 0x00, 0x20,
750x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x69, 0x73, 0x7c, 0x01, 750x61, 0x73, 0x4a, 0x02, 0x82, 0x65, 0x6e, 0x65, 0x72, 0x61,
760x22, 0x6f, 0x66, 0x8a, 0x00, 0x02, 0x79, 0x00, 0x00, 0xfd, 760x6c, 0x69, 0x73, 0x7c, 0x01, 0x22, 0x6f, 0x66, 0x8a, 0x00,
770x00, 0x35, 0x37, 0x2e, 0x31, 0xdf, 0x02, 0x00, 0x5c, 0x02, 770x02, 0x79, 0x00, 0x00, 0xfd, 0x00, 0x35, 0x37, 0x2e, 0x31,
780x41, 0x72, 0x6f, 0x6c, 0x73, 0xe8, 0x02, 0x66, 0x6f, 0x00, 780xf2, 0x02, 0x00, 0x5c, 0x02, 0x50, 0x72, 0x6f, 0x6c, 0x73,
790x70, 0x6c, 0x61, 0x79, 0x13, 0x02, 0x51, 0x63, 0x6c, 0x69, 790x20, 0xe8, 0x02, 0x66, 0x6f, 0x00, 0x70, 0x6c, 0x61, 0x79,
800x63, 0x6b, 0xe1, 0x00, 0x45, 0x6d, 0x6f, 0x75, 0x73, 0x16, 800x13, 0x02, 0x51, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0xe1, 0x00,
810x01, 0x02, 0xe3, 0x01, 0x02, 0x59, 0x00, 0x1a, 0x65, 0x64, 810x45, 0x6d, 0x6f, 0x75, 0x73, 0x16, 0x01, 0x02, 0xe3, 0x01,
820x01, 0x00, 0xd7, 0x00, 0x46, 0x77, 0x69, 0x73, 0x68, 0x41, 820x02, 0x59, 0x00, 0x1a, 0x65, 0x64, 0x01, 0x00, 0xd7, 0x00,
830x02, 0x05, 0x24, 0x01, 0x02, 0xea, 0x01, 0x32, 0x6d, 0x6f, 830x46, 0x77, 0x69, 0x73, 0x68, 0x41, 0x02, 0x05, 0x24, 0x01,
840x64, 0x6c, 0x02, 0x06, 0xac, 0x01, 0x33, 0x32, 0x78, 0x32, 840x02, 0xea, 0x01, 0x32, 0x6d, 0x6f, 0x64, 0x6c, 0x02, 0x06,
850x45, 0x00, 0x04, 0xfb, 0x00, 0x51, 0x6d, 0x65, 0x61, 0x6e, 850xac, 0x01, 0x33, 0x32, 0x78, 0x32, 0x45, 0x00, 0x04, 0xfb,
860x73, 0x25, 0x00, 0x22, 0x68, 0x61, 0x22, 0x01, 0x02, 0x8a, 860x00, 0x51, 0x6d, 0x65, 0x61, 0x6e, 0x73, 0x25, 0x00, 0x22,
870x00, 0xf1, 0x04, 0x61, 0x74, 0x00, 0x61, 0x00, 0x63, 0x6f, 870x68, 0x61, 0x22, 0x01, 0x02, 0x8a, 0x00, 0xf1, 0x04, 0x61,
880x72, 0x6e, 0x65, 0x72, 0x00, 0x70, 0x6f, 0x69, 0x6e, 0x74, 880x74, 0x00, 0x61, 0x00, 0x63, 0x6f, 0x72, 0x6e, 0x65, 0x72,
890x00, 0x77, 0x59, 0x01, 0x07, 0x92, 0x02, 0x43, 0x6d, 0x65, 890x00, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x00, 0x77, 0x59, 0x01,
900x65, 0x74, 0xe0, 0x02, 0x0a, 0x2d, 0x02, 0x00, 0x79, 0x00, 900x07, 0x92, 0x02, 0x43, 0x6d, 0x65, 0x65, 0x74, 0xe0, 0x02,
910x02, 0x54, 0x00, 0x82, 0x6d, 0x69, 0x67, 0x68, 0x74, 0x00, 910x0a, 0x2d, 0x02, 0x00, 0x79, 0x00, 0x02, 0x54, 0x00, 0x82,
920x62, 0x65, 0x82, 0x00, 0x00, 0x16, 0x03, 0xa4, 0x33, 0x78, 920x6d, 0x69, 0x67, 0x68, 0x74, 0x00, 0x62, 0x65, 0x82, 0x00,
930x33, 0x00, 0x6f, 0x72, 0x00, 0x65, 0x76, 0x65, 0x36, 0x00, 930x00, 0x16, 0x03, 0xa4, 0x33, 0x78, 0x33, 0x00, 0x6f, 0x72,
940x11, 0x74, 0xea, 0x03, 0x53, 0x6d, 0x65, 0x3b, 0x00, 0x69, 940x00, 0x65, 0x76, 0x65, 0x36, 0x00, 0x11, 0x74, 0xea, 0x03,
950xe6, 0x00, 0x2c, 0x69, 0x7a, 0xf2, 0x00, 0x60, 0x69, 0x73, 950x53, 0x6d, 0x65, 0x3b, 0x00, 0x69, 0xe6, 0x00, 0x2c, 0x69,
960x00, 0x6f, 0x64, 0x64, 0x12, 0x00, 0x12, 0x6e, 0xcf, 0x01, 960x7a, 0xf2, 0x00, 0x60, 0x69, 0x73, 0x00, 0x6f, 0x64, 0x64,
970x53, 0x69, 0x6d, 0x70, 0x6c, 0x79, 0xab, 0x00, 0x0a, 0x2b, 970x12, 0x00, 0x12, 0x6e, 0xcf, 0x01, 0x53, 0x69, 0x6d, 0x70,
980x01, 0x00, 0x9c, 0x00, 0x0b, 0x3e, 0x00, 0x01, 0x2a, 0x01, 980x6c, 0x79, 0xab, 0x00, 0x0a, 0x2b, 0x01, 0x00, 0x9c, 0x00,
990x00, 0x09, 0x03, 0x07, 0x2a, 0x01, 0x30, 0x00, 0x00, 0x43, 990x0b, 0x3e, 0x00, 0x01, 0x2a, 0x01, 0x00, 0x09, 0x03, 0x07,
1000x3d, 0x00, 0x00, 0x93, 0x00, 0x41, 0x77, 0x69, 0x74, 0x68, 1000x2a, 0x01, 0x30, 0x00, 0x00, 0x43, 0x3d, 0x00, 0x00, 0x93,
1010x2f, 0x00, 0x43, 0x6c, 0x65, 0x66, 0x74, 0x7f, 0x01, 0x54, 1010x00, 0x41, 0x77, 0x69, 0x74, 0x68, 0x2f, 0x00, 0x43, 0x6c,
1020x62, 0x75, 0x74, 0x74, 0x6f, 0xe5, 0x02, 0x11, 0x73, 0x1e, 1020x65, 0x66, 0x74, 0x7f, 0x01, 0x54, 0x62, 0x75, 0x74, 0x74,
1030x00, 0x02, 0x76, 0x01, 0x50, 0x61, 0x6e, 0x74, 0x69, 0x63, 1030x6f, 0xe5, 0x02, 0x11, 0x73, 0x1e, 0x00, 0x02, 0x76, 0x01,
1040x43, 0x02, 0x5f, 0x77, 0x69, 0x73, 0x65, 0x2e, 0x45, 0x00, 1040x50, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x43, 0x02, 0x5f, 0x77,
1050x00, 0x12, 0x72, 0xf3, 0x00, 0x0a, 0x40, 0x00, 0x37, 0x69, 1050x69, 0x73, 0x65, 0x2e, 0x45, 0x00, 0x00, 0x12, 0x72, 0xf3,
1060x74, 0x00, 0x35, 0x00, 0x33, 0x00, 0x00, 0x59, 0x45, 0x03, 1060x00, 0x0a, 0x40, 0x00, 0x37, 0x69, 0x74, 0x00, 0x35, 0x00,
1070x42, 0x61, 0x6c, 0x73, 0x6f, 0x09, 0x04, 0x95, 0x61, 0x6e, 1070x33, 0x00, 0x00, 0x59, 0x45, 0x03, 0x42, 0x61, 0x6c, 0x73,
1080x00, 0x6f, 0x75, 0x74, 0x6c, 0x69, 0x6e, 0xb6, 0x00, 0x51, 1080x6f, 0x09, 0x04, 0x95, 0x61, 0x6e, 0x00, 0x6f, 0x75, 0x74,
1090x61, 0x72, 0x6f, 0x75, 0x6e, 0xf4, 0x00, 0x02, 0xb1, 0x04, 1090x6c, 0x69, 0x6e, 0xb6, 0x00, 0x51, 0x61, 0x72, 0x6f, 0x75,
1100x05, 0x62, 0x00, 0xcb, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 1100x6e, 0xf4, 0x00, 0x02, 0xb1, 0x04, 0x05, 0x62, 0x00, 0xcb,
1110x00, 0x6b, 0x65, 0x79, 0x73, 0x3b, 0x25, 0x01, 0x05, 0x3f, 1110x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x00, 0x6b, 0x65, 0x79,
1120x01, 0x20, 0x61, 0x62, 0x55, 0x00, 0x10, 0x28, 0xf0, 0x01, 1120x73, 0x3b, 0x25, 0x01, 0x05, 0x3f, 0x01, 0x20, 0x61, 0x62,
1130xb0, 0x62, 0x79, 0x00, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 1130x55, 0x00, 0x10, 0x28, 0xf0, 0x01, 0xb0, 0x62, 0x79, 0x00,
1140x74, 0x2c, 0x7a, 0x01, 0x02, 0xaf, 0x03, 0x80, 0x29, 0x2e, 1140x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2c, 0x7a, 0x01,
1150x00, 0x50, 0x72, 0x65, 0x73, 0x73, 0xbb, 0x00, 0x01, 0xb6, 1150x02, 0xaf, 0x03, 0x80, 0x29, 0x2e, 0x00, 0x50, 0x72, 0x65,
1160x00, 0x50, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x54, 0x00, 0x00, 1160x73, 0x73, 0xbb, 0x00, 0x01, 0xb6, 0x00, 0x50, 0x65, 0x74,
1170x24, 0x00, 0x40, 0x73, 0x70, 0x61, 0x63, 0x46, 0x02, 0x64, 1170x75, 0x72, 0x6e, 0x54, 0x00, 0x00, 0x24, 0x00, 0x40, 0x73,
1180x72, 0x00, 0x77, 0x69, 0x6c, 0x6c, 0x3f, 0x02, 0x03, 0x7c, 1180x70, 0x61, 0x63, 0x46, 0x02, 0x64, 0x72, 0x00, 0x77, 0x69,
1190x00, 0x10, 0x72, 0x88, 0x05, 0x04, 0xa4, 0x00, 0x08, 0x0e, 1190x6c, 0x6c, 0x3f, 0x02, 0x03, 0x7c, 0x00, 0x10, 0x72, 0x88,
1200x01, 0x00, 0x3a, 0x00, 0x06, 0x0d, 0x00, 0x20, 0x72, 0x65, 1200x05, 0x04, 0xa4, 0x00, 0x08, 0x0e, 0x01, 0x00, 0x3a, 0x00,
1210x51, 0x03, 0x60, 0x74, 0x69, 0x76, 0x65, 0x6c, 0x79, 0xf3, 1210x06, 0x0d, 0x00, 0x20, 0x72, 0x65, 0x51, 0x03, 0x60, 0x74,
1220x00, 0x41, 0x28, 0x41, 0x6c, 0x6c, 0x43, 0x00, 0x20, 0x61, 1220x69, 0x76, 0x65, 0x6c, 0x79, 0xf3, 0x00, 0x41, 0x28, 0x41,
1230x63, 0x2c, 0x03, 0xd0, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 1230x6c, 0x6c, 0x43, 0x00, 0x20, 0x61, 0x63, 0x2c, 0x03, 0xd0,
1240x72, 0x69, 0x62, 0x65, 0x64, 0x00, 0x69, 0x7d, 0x04, 0x11, 1240x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
1250x63, 0x42, 0x03, 0x31, 0x32, 0x2e, 0x31, 0xab, 0x05, 0x01, 1250x64, 0x00, 0x69, 0x7d, 0x04, 0x11, 0x63, 0x42, 0x03, 0x31,
1260x19, 0x01, 0xb1, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 1260x32, 0x2e, 0x31, 0xab, 0x05, 0x01, 0x19, 0x01, 0xb1, 0x61,
1270x6c, 0x65, 0x2e, 0x29, 0x4b, 0x03, 0x15, 0x32, 0x4b, 0x03, 1270x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29,
1280xa8, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 1280x4b, 0x03, 0x15, 0x32, 0x4b, 0x03, 0xb7, 0x70, 0x61, 0x72,
1290x73, 0x35, 0x06, 0x50, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x7b, 1290x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x35, 0x06,
1300x02, 0x30, 0x73, 0x65, 0x76, 0x97, 0x03, 0x00, 0xce, 0x05, 1300x50, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x7b, 0x02, 0x30, 0x73,
1310x53, 0x66, 0x69, 0x67, 0x75, 0x72, 0x9e, 0x03, 0x12, 0x70, 1310x65, 0x76, 0x97, 0x03, 0x00, 0xce, 0x05, 0x53, 0x66, 0x69,
1320x79, 0x00, 0x31, 0x76, 0x69, 0x61, 0x89, 0x00, 0x83, 0x60, 1320x67, 0x75, 0x72, 0x9e, 0x03, 0x12, 0x70, 0x79, 0x00, 0x31,
1330x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x27, 0x19, 0x00, 0x32, 1330x76, 0x69, 0x61, 0x89, 0x00, 0x83, 0x60, 0x43, 0x75, 0x73,
1340x00, 0x6f, 0x6e, 0x17, 0x00, 0xf5, 0x00, 0x54, 0x79, 0x70, 1340x74, 0x6f, 0x6d, 0x27, 0x19, 0x00, 0x32, 0x00, 0x6f, 0x6e,
1350x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0x3a, 0x00, 0x00, 1350x17, 0x00, 0xf5, 0x00, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00,
1360x00, 0x2d, 0xad, 0x01, 0x04, 0x4e, 0x00, 0x02, 0x0a, 0x01, 1360x6d, 0x65, 0x6e, 0x75, 0x3a, 0x00, 0x00, 0x00, 0x2d, 0xad,
1370x51, 0x77, 0x69, 0x64, 0x74, 0x68, 0x1b, 0x06, 0x21, 0x68, 1370x01, 0x04, 0x4e, 0x00, 0x02, 0x0a, 0x01, 0x51, 0x77, 0x69,
1380x65, 0xf3, 0x01, 0x03, 0x74, 0x02, 0x03, 0x75, 0x04, 0x00, 1380x64, 0x74, 0x68, 0x1b, 0x06, 0x21, 0x68, 0x65, 0xf3, 0x01,
1390xb3, 0x01, 0x1f, 0x2e, 0x3f, 0x00, 0x08, 0x04, 0xe5, 0x02, 1390x03, 0x74, 0x02, 0x03, 0x75, 0x04, 0x00, 0xb3, 0x01, 0x1f,
1400x03, 0x49, 0x01, 0x11, 0x62, 0x96, 0x04, 0x01, 0x3d, 0x04, 1400x2e, 0x3f, 0x00, 0x08, 0x04, 0xe5, 0x02, 0x03, 0x49, 0x01,
1410x04, 0x34, 0x02, 0x05, 0x19, 0x03, 0x0a, 0x47, 0x00, 0x52, 1410x11, 0x62, 0x96, 0x04, 0x01, 0x3d, 0x04, 0x04, 0x34, 0x02,
1420x61, 0x73, 0x6b, 0x00, 0x66, 0x42, 0x03, 0x25, 0x72, 0x79, 1420x05, 0x19, 0x03, 0x0a, 0x47, 0x00, 0x52, 0x61, 0x73, 0x6b,
1430xfb, 0x01, 0x16, 0x6e, 0x28, 0x02, 0x20, 0x74, 0x6f, 0x71, 1430x00, 0x66, 0x42, 0x03, 0x25, 0x72, 0x79, 0xfb, 0x01, 0x16,
1440x03, 0x30, 0x64, 0x69, 0x73, 0x70, 0x03, 0x40, 0x75, 0x69, 1440x6e, 0x28, 0x02, 0x20, 0x74, 0x6f, 0x71, 0x03, 0x30, 0x64,
1450x73, 0x68, 0x42, 0x01, 0x20, 0x00, 0x28, 0x20, 0x00, 0x03, 1450x69, 0x73, 0x70, 0x03, 0x40, 0x75, 0x69, 0x73, 0x68, 0x42,
1460x08, 0x02, 0x11, 0x29, 0x09, 0x02, 0x1b, 0x79, 0x51, 0x00, 1460x01, 0x20, 0x00, 0x28, 0x20, 0x00, 0x03, 0x08, 0x02, 0x11,
1470x12, 0x61, 0x56, 0x03, 0x57, 0x69, 0x66, 0x69, 0x65, 0x64, 1470x29, 0x09, 0x02, 0x1b, 0x79, 0x51, 0x00, 0x12, 0x61, 0x56,
1480x9c, 0x05, 0x02, 0x27, 0x04, 0x02, 0x56, 0x05, 0x05, 0x7d, 1480x03, 0x57, 0x69, 0x66, 0x69, 0x65, 0x64, 0x9c, 0x05, 0x02,
1490x04, 0x10, 0x73, 0xbb, 0x00, 0x30, 0x69, 0x64, 0x65, 0xff, 1490x27, 0x04, 0x02, 0x56, 0x05, 0x05, 0x7d, 0x04, 0x10, 0x73,
1500x01, 0x24, 0x61, 0x6c, 0x02, 0x07, 0x05, 0x80, 0x04, 0x0e, 1500xbb, 0x00, 0x30, 0x69, 0x64, 0x65, 0xff, 0x01, 0x24, 0x61,
1510x49, 0x00, 0x08, 0x3f, 0x07, 0x48, 0x6a, 0x75, 0x73, 0x74, 1510x6c, 0x02, 0x07, 0x05, 0x80, 0x04, 0x0e, 0x49, 0x00, 0x08,
1520x44, 0x07, 0x13, 0x61, 0x19, 0x02, 0x13, 0x31, 0x43, 0x07, 1520x3f, 0x07, 0x48, 0x6a, 0x75, 0x73, 0x74, 0x44, 0x07, 0x13,
1530x00, 0x0c, 0x00, 0x02, 0x33, 0x06, 0x45, 0x72, 0x6f, 0x77, 1530x61, 0x19, 0x02, 0x13, 0x31, 0x43, 0x07, 0x00, 0x0c, 0x00,
1540x2c, 0x1f, 0x00, 0x17, 0x32, 0x1f, 0x00, 0x63, 0x73, 0x65, 1540x02, 0x33, 0x06, 0x45, 0x72, 0x6f, 0x77, 0x2c, 0x1f, 0x00,
1550x63, 0x6f, 0x6e, 0x64, 0x20, 0x00, 0x8f, 0x6e, 0x64, 0x00, 1550x17, 0x32, 0x1f, 0x00, 0x63, 0x73, 0x65, 0x63, 0x6f, 0x6e,
1560x73, 0x6f, 0x00, 0x6f, 0x6e, 0x6f, 0x01, 0x05, 0x30, 0x77, 1560x64, 0x20, 0x00, 0x8f, 0x6e, 0x64, 0x00, 0x73, 0x6f, 0x00,
1570x68, 0x65, 0xbf, 0x00, 0x01, 0x39, 0x00, 0x17, 0x6f, 0x2a, 1570x6f, 0x6e, 0x6f, 0x01, 0x05, 0x30, 0x77, 0x68, 0x65, 0xbf,
1580x07, 0x24, 0x6f, 0x66, 0xc9, 0x04, 0x32, 0x61, 0x74, 0x74, 1580x00, 0x01, 0x39, 0x00, 0x17, 0x6f, 0x2a, 0x07, 0x24, 0x6f,
1590xbf, 0x00, 0x12, 0x66, 0x2c, 0x08, 0x04, 0x12, 0x01, 0x14, 1590x66, 0xc9, 0x04, 0x32, 0x61, 0x74, 0x74, 0xbf, 0x00, 0x12,
1600x6e, 0x30, 0x00, 0x24, 0x62, 0x6c, 0xd9, 0x01, 0x03, 0x28, 1600x66, 0x2c, 0x08, 0x04, 0x12, 0x01, 0x14, 0x6e, 0x30, 0x00,
1610x08, 0x01, 0x66, 0x04, 0x01, 0x1d, 0x03, 0x01, 0x37, 0x05, 1610x24, 0x62, 0x6c, 0xd9, 0x01, 0x03, 0x28, 0x08, 0x01, 0x66,
1620xf0, 0x01, 0x61, 0x00, 0x74, 0x72, 0x69, 0x61, 0x6e, 0x67, 1620x04, 0x01, 0x1d, 0x03, 0x01, 0x37, 0x05, 0xf0, 0x01, 0x61,
1630x6c, 0x65, 0x00, 0x64, 0x72, 0x61, 0x77, 0x6e, 0x39, 0x01, 1630x00, 0x74, 0x72, 0x69, 0x61, 0x6e, 0x67, 0x6c, 0x65, 0x00,
1640x44, 0x69, 0x74, 0x2e, 0x00, 0xf4, 0x02, 0x04, 0x1e, 0x00, 1640x64, 0x72, 0x61, 0x77, 0x6e, 0x39, 0x01, 0x44, 0x69, 0x74,
1650x51, 0x73, 0x00, 0x6d, 0x75, 0x73, 0x11, 0x05, 0x01, 0x54, 1650x2e, 0x00, 0xf4, 0x02, 0x04, 0x1e, 0x00, 0x51, 0x73, 0x00,
1660x05, 0x00, 0x7e, 0x03, 0x71, 0x75, 0x70, 0x77, 0x61, 0x72, 1660x6d, 0x75, 0x73, 0x11, 0x05, 0x01, 0x54, 0x05, 0x00, 0x7e,
1670x64, 0x73, 0x7a, 0x05, 0x77, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 1670x03, 0x71, 0x75, 0x70, 0x77, 0x61, 0x72, 0x64, 0x73, 0x7a,
1680x74, 0x65, 0x48, 0x02, 0x0e, 0xfc, 0x01, 0x02, 0xab, 0x01, 1680x05, 0x77, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48,
1690x50, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x98, 0x07, 0x51, 0x68, 1690x02, 0x0e, 0xfc, 0x01, 0x02, 0xab, 0x01, 0x50, 0x6c, 0x69,
1700x75, 0x66, 0x66, 0x6c, 0x6f, 0x08, 0x23, 0x70, 0x65, 0xe8, 1700x6d, 0x69, 0x74, 0x98, 0x07, 0x51, 0x68, 0x75, 0x66, 0x66,
1710x02, 0x02, 0x01, 0x02, 0x94, 0x70, 0x65, 0x72, 0x66, 0x6f, 1710x6c, 0x6f, 0x08, 0x23, 0x70, 0x65, 0xe8, 0x02, 0x02, 0x01,
1720x72, 0x6d, 0x65, 0x64, 0xd8, 0x02, 0x02, 0x92, 0x02, 0x17, 1720x02, 0x94, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x65,
1730x42, 0x0e, 0x04, 0x04, 0x38, 0x03, 0x01, 0xc8, 0x00, 0x02, 1730x64, 0xd8, 0x02, 0x02, 0x92, 0x02, 0x17, 0x42, 0x0e, 0x04,
1740x4a, 0x00, 0x16, 0x65, 0x48, 0x02, 0x00, 0x9a, 0x04, 0x11, 1740x04, 0x38, 0x03, 0x01, 0xc8, 0x00, 0x02, 0x4a, 0x00, 0x16,
1750x75, 0xfb, 0x01, 0x00, 0x8a, 0x02, 0x38, 0x6e, 0x79, 0x00, 1750x65, 0x48, 0x02, 0x00, 0x9a, 0x04, 0x11, 0x75, 0xfb, 0x01,
1760x88, 0x09, 0x14, 0x69, 0x91, 0x08, 0x20, 0x61, 0x73, 0x77, 1760x00, 0x8a, 0x02, 0x38, 0x6e, 0x79, 0x00, 0x88, 0x09, 0x14,
1770x03, 0x11, 0x62, 0x22, 0x01, 0x21, 0x61, 0x73, 0x28, 0x00, 1770x69, 0x91, 0x08, 0x20, 0x61, 0x73, 0x77, 0x03, 0x11, 0x62,
1780x10, 0x6f, 0x6e, 0x01, 0x15, 0x2e, 0xb5, 0x00, 0x82, 0x6f, 1780x22, 0x01, 0x21, 0x61, 0x73, 0x28, 0x00, 0x10, 0x6f, 0x6e,
1790x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x3c, 0x07, 0x81, 1790x01, 0x15, 0x2e, 0xb5, 0x00, 0x82, 0x6f, 0x76, 0x65, 0x72,
1800x62, 0x79, 0x00, 0x72, 0x65, 0x71, 0x75, 0x65, 0x9e, 0x02, 1800x72, 0x69, 0x64, 0x65, 0x3c, 0x07, 0x81, 0x62, 0x79, 0x00,
1810x00, 0xa4, 0x07, 0x54, 0x72, 0x65, 0x63, 0x69, 0x73, 0x45, 1810x72, 0x65, 0x71, 0x75, 0x65, 0x9e, 0x02, 0x00, 0xa4, 0x07,
1820x09, 0x01, 0x12, 0x03, 0x05, 0xd3, 0x00, 0x00, 0x19, 0x05, 1820x54, 0x72, 0x65, 0x63, 0x69, 0x73, 0x45, 0x09, 0x01, 0x12,
1830x1c, 0x73, 0xcf, 0x00, 0x71, 0x2e, 0x00, 0x54, 0x79, 0x70, 1830x03, 0x05, 0xd3, 0x00, 0x00, 0x19, 0x05, 0x1c, 0x73, 0xcf,
1840x69, 0x63, 0xfd, 0x09, 0x09, 0x95, 0x09, 0x21, 0x68, 0x65, 1840x00, 0x71, 0x2e, 0x00, 0x54, 0x79, 0x70, 0x69, 0x63, 0xfd,
1850xfb, 0x00, 0x10, 0x64, 0x17, 0x04, 0x33, 0x6d, 0x69, 0x6e, 1850x09, 0x09, 0x95, 0x09, 0x21, 0x68, 0x65, 0xfb, 0x00, 0x10,
1860x46, 0x01, 0x03, 0x5f, 0x00, 0x3e, 0x73, 0x65, 0x74, 0x5c, 1860x64, 0x17, 0x04, 0x33, 0x6d, 0x69, 0x6e, 0x46, 0x01, 0x03,
1870x00, 0x00, 0xaf, 0x00, 0x00, 0x7e, 0x04, 0x31, 0x76, 0x65, 1870x5f, 0x00, 0x3e, 0x73, 0x65, 0x74, 0x5c, 0x00, 0x00, 0xaf,
1880x72, 0x5a, 0x09, 0xa0, 0x6d, 0x00, 0x65, 0x78, 0x61, 0x63, 1880x00, 0x00, 0x7e, 0x04, 0x31, 0x76, 0x65, 0x72, 0x5a, 0x09,
1890x74, 0x6c, 0x79, 0x2c, 0xfd, 0x00, 0x01, 0xf8, 0x00, 0x01, 1890xa0, 0x6d, 0x00, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 0x79,
1900x0f, 0x02, 0xd1, 0x6e, 0x73, 0x77, 0x65, 0x72, 0x00, 0x28, 1900x2c, 0xfd, 0x00, 0x01, 0xf8, 0x00, 0x01, 0x0f, 0x02, 0xd1,
1910x73, 0x61, 0x79, 0x29, 0x00, 0x61, 0x02, 0x07, 0x11, 0x2d, 1910x6e, 0x73, 0x77, 0x65, 0x72, 0x00, 0x28, 0x73, 0x61, 0x79,
1920xb4, 0x05, 0x04, 0x33, 0x01, 0x01, 0x9a, 0x05, 0x09, 0x19, 1920x29, 0x00, 0x61, 0x02, 0x07, 0x11, 0x2d, 0xb4, 0x05, 0x04,
1930x00, 0x50, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x92, 0x02, 0x21, 1930x33, 0x01, 0x01, 0x9a, 0x05, 0x09, 0x19, 0x00, 0x50, 0x6f,
1940x4e, 0x6f, 0xcf, 0x01, 0x11, 0x61, 0x60, 0x00, 0x02, 0xf1, 1940x6c, 0x75, 0x74, 0x69, 0x92, 0x02, 0x21, 0x4e, 0x6f, 0xcf,
1950x06, 0x02, 0x7a, 0x00, 0x07, 0x68, 0x02, 0x16, 0x2c, 0x1c, 1950x01, 0x11, 0x61, 0x60, 0x00, 0x02, 0xf1, 0x06, 0x02, 0x7a,
1960x00, 0x81, 0x6c, 0x69, 0x6b, 0x65, 0x6c, 0x79, 0x00, 0x69, 1960x00, 0x07, 0x68, 0x02, 0x16, 0x2c, 0x1c, 0x00, 0x81, 0x6c,
1970x61, 0x01, 0x01, 0x37, 0x00, 0x04, 0x4b, 0x00, 0x71, 0x73, 1970x69, 0x6b, 0x65, 0x6c, 0x79, 0x00, 0x69, 0x61, 0x01, 0x01,
1980x00, 0x73, 0x68, 0x6f, 0x72, 0x74, 0xc7, 0x02, 0x22, 0x61, 1980x37, 0x00, 0x04, 0x4b, 0x00, 0x71, 0x73, 0x00, 0x73, 0x68,
1990x6e, 0x55, 0x02, 0x00, 0xca, 0x05, 0x82, 0x74, 0x00, 0x6c, 1990x6f, 0x72, 0x74, 0xc7, 0x02, 0x22, 0x61, 0x6e, 0x55, 0x02,
2000x65, 0x6e, 0x67, 0x74, 0x68, 0xc5, 0x01, 0x01, 0xc5, 0x05, 2000x00, 0xca, 0x05, 0x82, 0x74, 0x00, 0x6c, 0x65, 0x6e, 0x67,
2010x01, 0x28, 0x0a, 0x12, 0x6f, 0x65, 0x02, 0x80, 0x73, 0x73, 2010x74, 0x68, 0xc5, 0x01, 0x01, 0xc5, 0x05, 0x01, 0x28, 0x0a,
2020x69, 0x62, 0x6c, 0x65, 0x2e, 0x00, 2020x12, 0x6f, 0x65, 0x02, 0x80, 0x73, 0x73, 0x69, 0x62, 0x6c,
2030x65, 0x2e, 0x00,
203}; 204};
204 205
205const unsigned short help_text_len = 2926; 206const unsigned short help_text_len = 2945;
206const unsigned short help_text_words = 548; 207const unsigned short help_text_words = 549;
207const char quick_help_text[] = "Rotate the tiles around themselves to arrange them into order."; 208const char quick_help_text[] = "Rotate the tiles around themselves to arrange them into order.";
diff --git a/apps/plugins/puzzles/help/undead.c b/apps/plugins/puzzles/help/undead.c
index c08801003a..2ad886cd0d 100644
--- a/apps/plugins/puzzles/help/undead.c
+++ b/apps/plugins/puzzles/help/undead.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,230 +6,246 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 202, TEXT_CENTER | C_RED }, 9 { 203, TEXT_CENTER | C_RED },
10 { 282, TEXT_UNDERLINE }, 10 { 291, TEXT_UNDERLINE },
11 { 576, TEXT_CENTER | C_RED }, 11 { 591, TEXT_CENTER | C_RED },
12 { 593, TEXT_UNDERLINE }, 12 { 608, TEXT_UNDERLINE },
13 { 594, TEXT_UNDERLINE }, 13 { 609, TEXT_UNDERLINE },
14 { 604, TEXT_UNDERLINE }, 14 { 619, TEXT_UNDERLINE },
15 { 631, TEXT_CENTER | C_RED },
15 LAST_STYLE_ITEM 16 LAST_STYLE_ITEM
16}; 17};
17 18
18/* orig 3286 comp 2109 ratio 0.641814 level 10 saved 1177 */ 19/* orig 3574 comp 2258 ratio 0.631785 level 10 saved 1316 */
19const char help_text[] = { 20const char help_text[] = {
200xf0, 0x2c, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 210xfd, 0x06, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
210x33, 0x37, 0x3a, 0x20, 0x55, 0x6e, 0x64, 0x65, 0x61, 0x64, 220x33, 0x37, 0x3a, 0x20, 0x55, 0x6e, 0x64, 0x65, 0x61, 0x64,
220x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x61, 0x72, 230x20, 0x00, 0x2d, 0x01, 0x00, 0xf0, 0x19, 0x00, 0x00, 0x00,
230x65, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 240x59, 0x6f, 0x75, 0x00, 0x61, 0x72, 0x65, 0x00, 0x67, 0x69,
240x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 250x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64,
250x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x73, 0x6f, 0x6d, 260x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65,
260x65, 0x11, 0x00, 0xf3, 0x16, 0x77, 0x68, 0x69, 0x63, 0x68, 270x73, 0x2c, 0x00, 0x73, 0x6f, 0x6d, 0x65, 0x11, 0x00, 0xf3,
270x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x00, 0x64, 280x16, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x63, 0x6f, 0x6e,
280x69, 0x61, 0x67, 0x6f, 0x6e, 0x61, 0x6c, 0x00, 0x6d, 0x69, 290x74, 0x61, 0x69, 0x6e, 0x00, 0x64, 0x69, 0x61, 0x67, 0x6f,
290x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x00, 0x45, 0x76, 0x65, 300x6e, 0x61, 0x6c, 0x00, 0x6d, 0x69, 0x72, 0x72, 0x6f, 0x72,
300x72, 0x79, 0x37, 0x00, 0x03, 0x2d, 0x00, 0x83, 0x69, 0x73, 310x73, 0x2e, 0x00, 0x45, 0x76, 0x65, 0x72, 0x79, 0x37, 0x00,
310x00, 0x6e, 0x6f, 0x74, 0x00, 0x61, 0x25, 0x00, 0xf1, 0x08, 320x03, 0x2d, 0x00, 0x83, 0x69, 0x73, 0x00, 0x6e, 0x6f, 0x74,
320x00, 0x6d, 0x75, 0x73, 0x74, 0x00, 0x62, 0x65, 0x00, 0x66, 330x00, 0x61, 0x25, 0x00, 0xf1, 0x08, 0x00, 0x6d, 0x75, 0x73,
330x69, 0x6c, 0x6c, 0x65, 0x64, 0x00, 0x77, 0x69, 0x74, 0x68, 340x74, 0x00, 0x62, 0x65, 0x00, 0x66, 0x69, 0x6c, 0x6c, 0x65,
340x00, 0x6f, 0x6e, 0x5e, 0x00, 0xb0, 0x74, 0x68, 0x72, 0x65, 350x64, 0x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x6f, 0x6e, 0x5e,
350x65, 0x00, 0x74, 0x79, 0x70, 0x65, 0x73, 0x0f, 0x00, 0x11, 360x00, 0xb0, 0x74, 0x68, 0x72, 0x65, 0x65, 0x00, 0x74, 0x79,
360x75, 0xa0, 0x00, 0x90, 0x00, 0x6d, 0x6f, 0x6e, 0x73, 0x74, 370x70, 0x65, 0x73, 0x0f, 0x00, 0x11, 0x75, 0xb3, 0x00, 0x90,
370x65, 0x72, 0x3a, 0x98, 0x00, 0xf2, 0x12, 0x68, 0x6f, 0x73, 380x00, 0x6d, 0x6f, 0x6e, 0x73, 0x74, 0x65, 0x72, 0x3a, 0x98,
380x74, 0x2c, 0x00, 0x61, 0x00, 0x76, 0x61, 0x6d, 0x70, 0x69, 390x00, 0xf2, 0x12, 0x68, 0x6f, 0x73, 0x74, 0x2c, 0x00, 0x61,
390x72, 0x65, 0x2c, 0x00, 0x6f, 0x72, 0x00, 0x61, 0x00, 0x7a, 400x00, 0x76, 0x61, 0x6d, 0x70, 0x69, 0x72, 0x65, 0x2c, 0x00,
400x6f, 0x6d, 0x62, 0x69, 0x65, 0x2e, 0x00, 0x00, 0x00, 0x56, 410x6f, 0x72, 0x00, 0x61, 0x00, 0x7a, 0x6f, 0x6d, 0x62, 0x69,
410x18, 0x00, 0x50, 0x73, 0x00, 0x63, 0x61, 0x6e, 0x65, 0x00, 420x65, 0x2e, 0x00, 0x00, 0x00, 0x56, 0x18, 0x00, 0x50, 0x73,
420x30, 0x73, 0x65, 0x65, 0xa7, 0x00, 0xb1, 0x72, 0x65, 0x63, 430x00, 0x63, 0x61, 0x6e, 0x65, 0x00, 0x30, 0x73, 0x65, 0x65,
430x74, 0x6c, 0x79, 0x2c, 0x00, 0x62, 0x75, 0x74, 0xe8, 0x00, 440xa7, 0x00, 0xb1, 0x72, 0x65, 0x63, 0x74, 0x6c, 0x79, 0x2c,
440x80, 0x69, 0x6e, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0xa4, 450x00, 0x62, 0x75, 0x74, 0xe8, 0x00, 0x80, 0x69, 0x6e, 0x76,
450x00, 0xf6, 0x00, 0x65, 0x6e, 0x00, 0x72, 0x65, 0x66, 0x6c, 460x69, 0x73, 0x69, 0x62, 0x6c, 0xa4, 0x00, 0xf6, 0x00, 0x65,
460x65, 0x63, 0x74, 0x65, 0x64, 0x00, 0x69, 0x6e, 0xcc, 0x00, 470x6e, 0x00, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x65,
470x10, 0x47, 0x6d, 0x00, 0x11, 0x73, 0x30, 0x00, 0xf0, 0x08, 480x64, 0x00, 0x69, 0x6e, 0xcc, 0x00, 0x10, 0x47, 0x6d, 0x00,
480x74, 0x68, 0x65, 0x00, 0x6f, 0x70, 0x70, 0x6f, 0x73, 0x69, 490x11, 0x73, 0x30, 0x00, 0xf0, 0x08, 0x74, 0x68, 0x65, 0x00,
490x74, 0x65, 0x00, 0x77, 0x61, 0x79, 0x00, 0x72, 0x6f, 0x75, 500x6f, 0x70, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x00, 0x77,
500x6e, 0x64, 0x3a, 0x18, 0x00, 0x19, 0x79, 0x6b, 0x00, 0x06, 510x61, 0x79, 0x00, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3a, 0x18,
510x40, 0x00, 0x0f, 0x6d, 0x00, 0x06, 0x95, 0x6c, 0x6f, 0x6f, 520x00, 0x19, 0x79, 0x6b, 0x00, 0x06, 0x40, 0x00, 0x0f, 0x6d,
520x6b, 0x65, 0x64, 0x00, 0x61, 0x74, 0x98, 0x00, 0x31, 0x2e, 530x00, 0x06, 0x95, 0x6c, 0x6f, 0x6f, 0x6b, 0x65, 0x64, 0x00,
530x00, 0x5a, 0xc1, 0x00, 0x02, 0x6c, 0x00, 0x04, 0x2d, 0x00, 540x61, 0x74, 0x98, 0x00, 0x31, 0x2e, 0x00, 0x5a, 0xc1, 0x00,
540xd7, 0x62, 0x79, 0x00, 0x61, 0x6e, 0x79, 0x00, 0x6d, 0x65, 550x02, 0x6c, 0x00, 0x04, 0x2d, 0x00, 0xd7, 0x62, 0x79, 0x00,
550x61, 0x6e, 0x73, 0x2e, 0xa4, 0x01, 0x91, 0x61, 0x6c, 0x73, 560x61, 0x6e, 0x79, 0x00, 0x6d, 0x65, 0x61, 0x6e, 0x73, 0x2e,
560x6f, 0x00, 0x74, 0x6f, 0x6c, 0x64, 0x96, 0x00, 0xc0, 0x74, 570xa4, 0x01, 0x91, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0x74, 0x6f,
570x6f, 0x74, 0x61, 0x6c, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 580x6c, 0x64, 0x96, 0x00, 0xc0, 0x74, 0x6f, 0x74, 0x61, 0x6c,
580x72, 0x34, 0x01, 0x41, 0x65, 0x61, 0x63, 0x68, 0x42, 0x01, 590x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x34, 0x01, 0x41,
590x00, 0x0d, 0x00, 0x03, 0x3a, 0x01, 0x00, 0x96, 0x00, 0x00, 600x65, 0x61, 0x63, 0x68, 0x42, 0x01, 0x00, 0x0d, 0x00, 0x03,
600x2c, 0x00, 0x00, 0xd6, 0x01, 0x30, 0x2e, 0x00, 0x41, 0x40, 610x3a, 0x01, 0x00, 0x96, 0x00, 0x00, 0x2c, 0x00, 0x00, 0xd6,
610x00, 0x11, 0x61, 0xc1, 0x00, 0x01, 0x16, 0x00, 0x33, 0x65, 620x01, 0x30, 0x2e, 0x00, 0x41, 0x40, 0x00, 0x11, 0x61, 0xc1,
620x64, 0x67, 0x7d, 0x01, 0x12, 0x65, 0xf8, 0x01, 0x01, 0xbb, 630x00, 0x01, 0x16, 0x00, 0x33, 0x65, 0x64, 0x67, 0x7d, 0x01,
630x01, 0x63, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x59, 0x00, 640x12, 0x65, 0xf8, 0x01, 0x01, 0xbb, 0x01, 0x63, 0x72, 0x69,
640x24, 0x73, 0x2c, 0xcc, 0x01, 0xd1, 0x6e, 0x64, 0x69, 0x63, 650x74, 0x74, 0x65, 0x6e, 0x59, 0x00, 0x24, 0x73, 0x2c, 0xcc,
650x61, 0x74, 0x65, 0x00, 0x68, 0x6f, 0x77, 0x00, 0x6d, 0x9f, 660x01, 0xd1, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00,
660x00, 0x02, 0x63, 0x00, 0x1a, 0x73, 0x06, 0x01, 0x51, 0x66, 670x68, 0x6f, 0x77, 0x00, 0x6d, 0x9f, 0x00, 0x02, 0x63, 0x00,
670x00, 0x79, 0x6f, 0x75, 0xea, 0x00, 0x57, 0x00, 0x69, 0x6e, 680x1a, 0x73, 0x06, 0x01, 0x51, 0x66, 0x00, 0x79, 0x6f, 0x75,
680x74, 0x6f, 0x5c, 0x00, 0xa0, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 690xea, 0x00, 0x57, 0x00, 0x69, 0x6e, 0x74, 0x6f, 0x5c, 0x00,
690x61, 0x00, 0x72, 0x6f, 0x77, 0xbb, 0x01, 0xf1, 0x0b, 0x63, 700xa0, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x61, 0x00, 0x72, 0x6f,
700x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x00, 0x73, 0x74, 0x61, 0x72, 710x77, 0xbb, 0x01, 0xf1, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d,
710x74, 0x69, 0x6e, 0x67, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x00, 720x6e, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67,
720x74, 0x68, 0x61, 0x74, 0x00, 0x6c, 0x01, 0x9d, 0x69, 0x6f, 730x00, 0x66, 0x72, 0x6f, 0x6d, 0x00, 0x74, 0x68, 0x61, 0x74,
730x6e, 0x2e, 0x00, 0x28, 0x54, 0x68, 0x65, 0x6a, 0x02, 0x01, 740x00, 0x6c, 0x01, 0x9d, 0x69, 0x6f, 0x6e, 0x2e, 0x00, 0x28,
740xa5, 0x00, 0x03, 0xb7, 0x01, 0xf1, 0x05, 0x69, 0x76, 0x65, 750x54, 0x68, 0x65, 0x6a, 0x02, 0x01, 0xa5, 0x00, 0x03, 0xb7,
750x00, 0x6f, 0x6e, 0x00, 0x62, 0x6f, 0x74, 0x68, 0x00, 0x73, 760x01, 0xf1, 0x05, 0x69, 0x76, 0x65, 0x00, 0x6f, 0x6e, 0x00,
760x69, 0x64, 0x65, 0x73, 0x2e, 0x00, 0x49, 0x81, 0x00, 0x17, 770x62, 0x6f, 0x74, 0x68, 0x00, 0x73, 0x69, 0x64, 0x65, 0x73,
770x72, 0xd9, 0x01, 0x22, 0x6c, 0x69, 0x63, 0x02, 0xd1, 0x73, 780x2e, 0x00, 0x49, 0x81, 0x00, 0x17, 0x72, 0xd9, 0x01, 0x22,
780x69, 0x67, 0x68, 0x74, 0x00, 0x63, 0x72, 0x6f, 0x73, 0x73, 790x6c, 0x69, 0x63, 0x02, 0xd1, 0x73, 0x69, 0x67, 0x68, 0x74,
790x65, 0x73, 0x98, 0x00, 0x45, 0x73, 0x61, 0x6d, 0x65, 0x2a, 800x00, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x65, 0x73, 0x98, 0x00,
800x01, 0x21, 0x6d, 0x6f, 0xee, 0x01, 0x81, 0x61, 0x6e, 0x00, 810x45, 0x73, 0x61, 0x6d, 0x65, 0x2a, 0x01, 0x21, 0x6d, 0x6f,
810x6f, 0x6e, 0x63, 0x65, 0x2c, 0x21, 0x00, 0x03, 0x5d, 0x01, 820xee, 0x01, 0x81, 0x61, 0x6e, 0x00, 0x6f, 0x6e, 0x63, 0x65,
820xd3, 0x77, 0x69, 0x6c, 0x6c, 0x00, 0x63, 0x6f, 0x75, 0x6e, 830x2c, 0x21, 0x00, 0x03, 0x5d, 0x01, 0xd3, 0x77, 0x69, 0x6c,
830x74, 0x00, 0x69, 0x74, 0x68, 0x01, 0x30, 0x69, 0x6d, 0x65, 840x6c, 0x00, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x69, 0x74,
840x0d, 0x00, 0x24, 0x69, 0x73, 0xb6, 0x01, 0x11, 0x2c, 0xec, 850x68, 0x01, 0x30, 0x69, 0x6d, 0x65, 0x0d, 0x00, 0x24, 0x69,
850x02, 0x10, 0x6a, 0xe3, 0x02, 0x00, 0x41, 0x00, 0xf2, 0x01, 860x73, 0xb6, 0x01, 0x11, 0x2c, 0xec, 0x02, 0x10, 0x6a, 0xe3,
860x2e, 0x29, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x73, 0x00, 870x02, 0x00, 0x41, 0x00, 0xf2, 0x01, 0x2e, 0x29, 0x00, 0x00,
870x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x9a, 0x01, 0x30, 0x77, 880x00, 0x54, 0x68, 0x69, 0x73, 0x00, 0x70, 0x75, 0x7a, 0x7a,
880x61, 0x73, 0x15, 0x02, 0x20, 0x65, 0x6e, 0x99, 0x00, 0xf1, 890x6c, 0x65, 0x9a, 0x01, 0x30, 0x77, 0x61, 0x73, 0x15, 0x02,
890x01, 0x62, 0x79, 0x00, 0x44, 0x61, 0x76, 0x69, 0x64, 0x00, 900x20, 0x65, 0x6e, 0x99, 0x00, 0xf1, 0x01, 0x62, 0x79, 0x00,
900x4d, 0x69, 0x6c, 0x6c, 0x61, 0x72, 0x2c, 0xf6, 0x02, 0x12, 910x44, 0x61, 0x76, 0x69, 0x64, 0x00, 0x4d, 0x69, 0x6c, 0x6c,
910x72, 0x79, 0x00, 0x00, 0x9a, 0x00, 0x41, 0x60, 0x48, 0x61, 920x61, 0x72, 0x2c, 0xf6, 0x02, 0x12, 0x72, 0x79, 0x00, 0x00,
920x75, 0x29, 0x00, 0x12, 0x4d, 0x3f, 0x03, 0xf3, 0x03, 0x4d, 930x9a, 0x00, 0x41, 0x60, 0x48, 0x61, 0x75, 0x29, 0x00, 0x12,
930x61, 0x7a, 0x65, 0x27, 0x2e, 0x00, 0x53, 0x65, 0x65, 0x00, 940x4d, 0x3f, 0x03, 0xf3, 0x03, 0x4d, 0x61, 0x7a, 0x65, 0x27,
940x5b, 0x32, 0x30, 0x5d, 0x00, 0x66, 0x6f, 0xb6, 0x00, 0x61, 950x2e, 0x00, 0x53, 0x65, 0x65, 0x00, 0x5b, 0x32, 0x30, 0x5d,
950x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x2b, 0x02, 0x02, 0xd9, 960x00, 0x66, 0x6f, 0xb6, 0x00, 0x61, 0x64, 0x65, 0x74, 0x61,
960x03, 0x01, 0x68, 0x00, 0x00, 0xab, 0x03, 0x40, 0x72, 0x69, 970x69, 0x6c, 0x2b, 0x02, 0x02, 0xec, 0x03, 0x01, 0x68, 0x00,
970x62, 0x75, 0x42, 0x00, 0x01, 0x89, 0x01, 0x20, 0x69, 0x73, 980x00, 0xab, 0x03, 0x40, 0x72, 0x69, 0x62, 0x75, 0x42, 0x00,
980x76, 0x01, 0x01, 0x38, 0x01, 0x20, 0x6f, 0x6e, 0x7e, 0x00, 990x01, 0x89, 0x01, 0x20, 0x69, 0x73, 0x76, 0x01, 0x01, 0x38,
990xd0, 0x53, 0x74, 0x65, 0x66, 0x66, 0x65, 0x6e, 0x00, 0x42, 1000x01, 0x20, 0x6f, 0x6e, 0x7e, 0x00, 0xd0, 0x53, 0x74, 0x65,
1000x61, 0x75, 0x65, 0x72, 0x3e, 0x00, 0x01, 0x57, 0x00, 0xf4, 1010x66, 0x66, 0x65, 0x6e, 0x00, 0x42, 0x61, 0x75, 0x65, 0x72,
1010x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 1020x3e, 0x00, 0x01, 0x57, 0x00, 0xf4, 0x29, 0x68, 0x74, 0x74,
1020x77, 0x2e, 0x6a, 0x61, 0x6e, 0x6b, 0x6f, 0x2e, 0x61, 0x74, 1030x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6a, 0x61,
1030x2f, 0x52, 0x61, 0x65, 0x74, 0x73, 0x65, 0x6c, 0x2f, 0x53, 1040x6e, 0x6b, 0x6f, 0x2e, 0x61, 0x74, 0x2f, 0x52, 0x61, 0x65,
1040x70, 0x75, 0x6b, 0x73, 0x63, 0x68, 0x6c, 0x6f, 0x73, 0x73, 1050x74, 0x73, 0x65, 0x6c, 0x2f, 0x53, 0x70, 0x75, 0x6b, 0x73,
1050x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 1060x63, 0x68, 0x6c, 0x6f, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x64,
1060x00, 0x00, 0x00, 0x33, 0x37, 0x2e, 0x31, 0x55, 0x04, 0x01, 1070x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x00, 0x00, 0x00, 0x33,
1070x78, 0x00, 0x46, 0x6f, 0x6c, 0x73, 0x20, 0x8f, 0x00, 0xe3, 1080x37, 0x2e, 0x31, 0x68, 0x04, 0x01, 0x78, 0x00, 0x46, 0x6f,
1080x68, 0x61, 0x73, 0x00, 0x61, 0x00, 0x73, 0x69, 0x6d, 0x69, 1090x6c, 0x73, 0x20, 0x8f, 0x00, 0xe3, 0x68, 0x61, 0x73, 0x00,
1090x6c, 0x61, 0x72, 0x00, 0x21, 0x00, 0x70, 0x00, 0x73, 0x79, 1100x61, 0x00, 0x73, 0x69, 0x6d, 0x69, 0x6c, 0x61, 0x72, 0x00,
1100x73, 0x74, 0x65, 0x6d, 0x9c, 0x00, 0xf0, 0x08, 0x53, 0x6f, 1110x21, 0x00, 0x70, 0x00, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d,
1110x6c, 0x6f, 0x2c, 0x00, 0x55, 0x6e, 0x65, 0x71, 0x75, 0x61, 1120x9c, 0x00, 0xf0, 0x08, 0x53, 0x6f, 0x6c, 0x6f, 0x2c, 0x00,
1120x6c, 0x00, 0x61, 0x6e, 0x64, 0x00, 0x4b, 0x65, 0x65, 0x6e, 1130x55, 0x6e, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x00, 0x61, 0x6e,
1130x2e, 0x42, 0x01, 0x63, 0x6f, 0x00, 0x70, 0x6c, 0x61, 0x79, 1140x64, 0x00, 0x4b, 0x65, 0x65, 0x6e, 0x2e, 0x42, 0x01, 0x63,
1140x49, 0x00, 0x71, 0x2c, 0x00, 0x63, 0x6c, 0x69, 0x63, 0x6b, 1150x6f, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x49, 0x00, 0x71, 0x2c,
1150x23, 0x01, 0x40, 0x6d, 0x6f, 0x75, 0x73, 0x62, 0x03, 0x01, 1160x00, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x23, 0x01, 0x40, 0x6d,
1160x2b, 0x03, 0x45, 0x65, 0x6d, 0x70, 0x74, 0x7d, 0x04, 0x12, 1170x6f, 0x75, 0x73, 0x62, 0x03, 0x01, 0x2b, 0x03, 0x45, 0x65,
1170x61, 0xdf, 0x02, 0x12, 0x6e, 0x73, 0x01, 0x60, 0x61, 0x00, 1180x6d, 0x70, 0x74, 0x7d, 0x04, 0x12, 0x61, 0xdf, 0x02, 0x12,
1180x6c, 0x65, 0x74, 0x74, 0x23, 0x03, 0x02, 0x0b, 0x03, 0x84, 1190x6e, 0x73, 0x01, 0x60, 0x61, 0x00, 0x6c, 0x65, 0x74, 0x74,
1190x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0xd2, 0x02, 1200x23, 0x03, 0x15, 0x72, 0x2d, 0x03, 0x02, 0x15, 0x03, 0x84,
1200x00, 0x7d, 0x02, 0x01, 0x4f, 0x03, 0x0a, 0x3a, 0x03, 0x51, 1210x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0xdc, 0x02,
1210x3a, 0x00, 0x60, 0x47, 0x27, 0x63, 0x01, 0x05, 0x7c, 0x04, 1220x00, 0x87, 0x02, 0x01, 0x59, 0x03, 0x0a, 0x44, 0x03, 0x50,
1220x24, 0x60, 0x56, 0x11, 0x00, 0x08, 0x84, 0x04, 0x24, 0x60, 1230x3a, 0x00, 0x60, 0x47, 0x27, 0x3e, 0x00, 0x31, 0x60, 0x31,
1230x5a, 0x16, 0x00, 0x04, 0x8c, 0x04, 0x12, 0x49, 0x04, 0x03, 1240x27, 0x74, 0x01, 0x05, 0x8d, 0x04, 0x22, 0x60, 0x56, 0x18,
1240x41, 0x6d, 0x61, 0x6b, 0x65, 0xfc, 0x04, 0x5e, 0x73, 0x74, 1250x00, 0x14, 0x32, 0x18, 0x00, 0x08, 0x9c, 0x04, 0x22, 0x60,
1250x61, 0x6b, 0x65, 0xbb, 0x00, 0x03, 0x9b, 0x03, 0x50, 0x69, 1260x5a, 0x1d, 0x00, 0x14, 0x33, 0x1d, 0x00, 0x04, 0xab, 0x04,
1260x6e, 0x63, 0x6f, 0x72, 0x0e, 0x04, 0x08, 0xbf, 0x00, 0xb0, 1270x12, 0x49, 0x23, 0x03, 0x41, 0x6d, 0x61, 0x6b, 0x65, 0x1b,
1270x70, 0x72, 0x65, 0x73, 0x73, 0x00, 0x53, 0x70, 0x61, 0x63, 1280x05, 0x5e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0xda, 0x00, 0x03,
1280x65, 0x20, 0x01, 0x50, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x6f, 1290xba, 0x03, 0x50, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x2d, 0x04,
1290x02, 0x20, 0x61, 0x67, 0x7d, 0x05, 0x62, 0x28, 0x6f, 0x72, 1300x08, 0xde, 0x00, 0xb0, 0x70, 0x72, 0x65, 0x73, 0x73, 0x00,
1300x00, 0x75, 0x73, 0x9c, 0x04, 0xd0, 0x55, 0x6e, 0x64, 0x6f, 1310x53, 0x70, 0x61, 0x63, 0x65, 0x3f, 0x01, 0x50, 0x63, 0x6c,
1310x00, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x29, 0x32, 1320x65, 0x61, 0x72, 0x8e, 0x02, 0x20, 0x61, 0x67, 0x9c, 0x05,
1320x01, 0x03, 0x7e, 0x00, 0x10, 0x72, 0xee, 0x02, 0x12, 0x2d, 1330x62, 0x28, 0x6f, 0x72, 0x00, 0x75, 0x73, 0xbb, 0x04, 0xd0,
1330x74, 0x00, 0x00, 0x25, 0x01, 0x0f, 0x1d, 0x01, 0x0b, 0x02, 1340x55, 0x6e, 0x64, 0x6f, 0x00, 0x66, 0x65, 0x61, 0x74, 0x75,
1340xef, 0x02, 0x01, 0x89, 0x00, 0x50, 0x73, 0x70, 0x6f, 0x6e, 1350x72, 0x65, 0x29, 0x51, 0x01, 0x03, 0x7e, 0x00, 0x10, 0x72,
1350x64, 0x15, 0x01, 0x04, 0x19, 0x03, 0x01, 0xfe, 0x02, 0x00, 1360x0d, 0x03, 0x12, 0x2d, 0x74, 0x00, 0x00, 0x44, 0x01, 0x0f,
1360xe0, 0x03, 0x31, 0x68, 0x6f, 0x77, 0xe7, 0x04, 0xb3, 0x72, 1370x3c, 0x01, 0x15, 0x02, 0x18, 0x03, 0x01, 0x93, 0x00, 0x50,
1370x65, 0x64, 0x75, 0x63, 0x65, 0x64, 0x00, 0x73, 0x69, 0x7a, 1380x73, 0x70, 0x6f, 0x6e, 0x64, 0x34, 0x01, 0x04, 0x42, 0x03,
1380xc6, 0x00, 0x14, 0x61, 0xbd, 0x00, 0x21, 0x2c, 0x00, 0xea, 1390x01, 0x27, 0x03, 0x00, 0x09, 0x04, 0x31, 0x68, 0x6f, 0x77,
1390x01, 0xe1, 0x60, 0x70, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x00, 1400x10, 0x05, 0xb3, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x64,
1400x6d, 0x61, 0x72, 0x6b, 0x27, 0x2e, 0xc0, 0x04, 0x00, 0x25, 1410x00, 0x73, 0x69, 0x7a, 0xd0, 0x00, 0x14, 0x61, 0xc7, 0x00,
1410x04, 0x57, 0x68, 0x61, 0x76, 0x65, 0x00, 0x1b, 0x00, 0x12, 1420x21, 0x2c, 0x00, 0x13, 0x02, 0xe1, 0x60, 0x70, 0x65, 0x6e,
1420x73, 0xc3, 0x02, 0x65, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 1430x63, 0x69, 0x6c, 0x00, 0x6d, 0x61, 0x72, 0x6b, 0x27, 0x2e,
1430x8a, 0x03, 0x00, 0x22, 0x03, 0x06, 0x9f, 0x03, 0x02, 0x58, 1440xe9, 0x04, 0x00, 0x4e, 0x04, 0x57, 0x68, 0x61, 0x76, 0x65,
1440x00, 0x34, 0x2e, 0x00, 0x41, 0xc1, 0x00, 0x03, 0x82, 0x06, 1450x00, 0x1b, 0x00, 0x12, 0x73, 0xec, 0x02, 0x65, 0x75, 0x6c,
1450x11, 0x69, 0x4d, 0x04, 0x51, 0x66, 0x75, 0x6c, 0x6c, 0x2d, 1460x74, 0x69, 0x70, 0x6c, 0xb3, 0x03, 0x00, 0x4b, 0x03, 0x06,
1460x88, 0x00, 0x04, 0xae, 0x00, 0x31, 0x63, 0x61, 0x6e, 0x74, 1470xc8, 0x03, 0x02, 0x58, 0x00, 0x34, 0x2e, 0x00, 0x41, 0xcb,
1470x06, 0x00, 0xeb, 0x04, 0x04, 0xad, 0x06, 0x08, 0x73, 0x00, 1480x00, 0x03, 0xab, 0x06, 0x11, 0x69, 0x76, 0x04, 0x51, 0x66,
1480x01, 0x55, 0x02, 0x00, 0x94, 0x04, 0x00, 0x5d, 0x00, 0x30, 1490x75, 0x6c, 0x6c, 0x2d, 0x88, 0x00, 0x04, 0xae, 0x00, 0x31,
1490x70, 0x61, 0x79, 0xa3, 0x06, 0x20, 0x00, 0x61, 0xf2, 0x04, 1500x63, 0x61, 0x6e, 0x9d, 0x06, 0x00, 0x14, 0x05, 0x04, 0xd6,
1500x01, 0x16, 0x03, 0x29, 0x74, 0x6f, 0x2e, 0x00, 0x00, 0xff, 1510x06, 0x08, 0x73, 0x00, 0x01, 0x7e, 0x02, 0x00, 0xbd, 0x04,
1510x06, 0x40, 0x00, 0x65, 0x78, 0x61, 0xac, 0x05, 0x20, 0x00, 1520x00, 0x5d, 0x00, 0x30, 0x70, 0x61, 0x79, 0xcc, 0x06, 0x20,
1520x77, 0xe8, 0x00, 0x00, 0x5c, 0x01, 0x03, 0x7c, 0x01, 0x11, 1530x00, 0x61, 0x1b, 0x05, 0x01, 0x3f, 0x03, 0x29, 0x74, 0x6f,
1530x6d, 0xbf, 0x00, 0x50, 0x69, 0x73, 0x00, 0x75, 0x70, 0x38, 1540x2e, 0x00, 0x00, 0x28, 0x07, 0x40, 0x00, 0x65, 0x78, 0x61,
1540x00, 0x63, 0x79, 0x6f, 0x75, 0x3a, 0x00, 0x79, 0xeb, 0x00, 1550xd5, 0x05, 0x20, 0x00, 0x77, 0xe8, 0x00, 0x00, 0x66, 0x01,
1550x05, 0x23, 0x00, 0x70, 0x61, 0x73, 0x00, 0x72, 0x65, 0x6d, 1560x03, 0x86, 0x01, 0x11, 0x6d, 0xbf, 0x00, 0x50, 0x69, 0x73,
1560x69, 0xda, 0x03, 0x12, 0x73, 0x2a, 0x01, 0x30, 0x61, 0x00, 1570x00, 0x75, 0x70, 0x38, 0x00, 0x63, 0x79, 0x6f, 0x75, 0x3a,
1570x70, 0xf4, 0x04, 0x20, 0x63, 0x75, 0x0c, 0x03, 0x03, 0xd5, 1580x00, 0x79, 0xeb, 0x00, 0x05, 0x23, 0x00, 0x70, 0x61, 0x73,
1580x00, 0x50, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x45, 0x00, 0x10, 1590x00, 0x72, 0x65, 0x6d, 0x69, 0x03, 0x04, 0x12, 0x73, 0x2a,
1590x62, 0xdc, 0x04, 0x91, 0x2d, 0x65, 0x78, 0x61, 0x6d, 0x69, 1600x01, 0x30, 0x61, 0x00, 0x70, 0x1d, 0x05, 0x20, 0x63, 0x75,
1600x6e, 0x65, 0x64, 0x4a, 0x04, 0x01, 0x54, 0x00, 0x42, 0x6b, 1610x35, 0x03, 0x03, 0xd5, 0x00, 0x50, 0x6e, 0x65, 0x65, 0x64,
1610x6e, 0x6f, 0x77, 0xed, 0x03, 0x4b, 0x61, 0x62, 0x6f, 0x75, 1620x73, 0x45, 0x00, 0x10, 0x62, 0x05, 0x05, 0x91, 0x2d, 0x65,
1620x45, 0x00, 0x03, 0xfc, 0x00, 0x01, 0x8f, 0x02, 0x0f, 0x81, 1630x78, 0x61, 0x6d, 0x69, 0x6e, 0x65, 0x64, 0x73, 0x04, 0x01,
1630x00, 0x01, 0x20, 0x6c, 0x69, 0xce, 0x06, 0x03, 0xe9, 0x05, 1640x54, 0x00, 0x42, 0x6b, 0x6e, 0x6f, 0x77, 0x16, 0x04, 0x4b,
1640x32, 0x70, 0x6f, 0x73, 0x66, 0x06, 0x07, 0x23, 0x06, 0x13, 1650x61, 0x62, 0x6f, 0x75, 0x45, 0x00, 0x03, 0xfc, 0x00, 0x01,
1650x61, 0xff, 0x07, 0x04, 0xc5, 0x01, 0x20, 0x6f, 0x72, 0x56, 1660xa0, 0x02, 0x0f, 0x81, 0x00, 0x01, 0x20, 0x6c, 0x69, 0xf7,
1660x03, 0x20, 0x74, 0x68, 0x65, 0x01, 0x32, 0x65, 0x6c, 0x73, 1670x06, 0x03, 0x12, 0x06, 0x32, 0x70, 0x6f, 0x73, 0x8f, 0x06,
1670x83, 0x00, 0x93, 0x66, 0x65, 0x65, 0x6c, 0x00, 0x6c, 0x69, 1680x07, 0x4c, 0x06, 0x13, 0x61, 0x28, 0x08, 0x04, 0xc5, 0x01,
1680x6b, 0x65, 0x98, 0x03, 0x51, 0x65, 0x72, 0x61, 0x73, 0x65, 1690x20, 0x6f, 0x72, 0x7f, 0x03, 0x20, 0x74, 0x68, 0x65, 0x01,
1690xd7, 0x03, 0x39, 0x6e, 0x67, 0x6c, 0xd8, 0x01, 0x1c, 0x2c, 1700x32, 0x65, 0x6c, 0x73, 0x83, 0x00, 0x93, 0x66, 0x65, 0x65,
1700x7e, 0x02, 0x01, 0xce, 0x01, 0x07, 0x80, 0x02, 0x00, 0x7b, 1710x6c, 0x00, 0x6c, 0x69, 0x6b, 0x65, 0xc1, 0x03, 0x51, 0x65,
1710x02, 0x05, 0xe2, 0x01, 0x03, 0x9f, 0x03, 0x01, 0xdb, 0x02, 1720x72, 0x61, 0x73, 0x65, 0x00, 0x04, 0x39, 0x6e, 0x67, 0x6c,
1720x00, 0x5b, 0x00, 0x3a, 0x41, 0x6c, 0x6c, 0x25, 0x02, 0x09, 1730xd8, 0x01, 0x1c, 0x2c, 0x88, 0x02, 0x01, 0xce, 0x01, 0x07,
1730xbf, 0x02, 0x22, 0x72, 0x65, 0x79, 0x00, 0x12, 0x64, 0x53, 1740x8a, 0x02, 0x00, 0x85, 0x02, 0x05, 0xe2, 0x01, 0x0d, 0xc8,
1740x07, 0x01, 0x6d, 0x06, 0x24, 0x65, 0x66, 0x6c, 0x00, 0x05, 1750x03, 0x01, 0xef, 0x02, 0x00, 0x65, 0x00, 0x3a, 0x41, 0x6c,
1750x5e, 0x00, 0x15, 0x61, 0xdf, 0x00, 0x04, 0xe1, 0x02, 0x2f, 1760x6c, 0x2f, 0x02, 0x09, 0xd3, 0x02, 0x22, 0x72, 0x65, 0x83,
1760x6f, 0x72, 0x32, 0x00, 0x06, 0x07, 0x6e, 0x03, 0x31, 0x2e, 1770x00, 0x12, 0x64, 0x86, 0x07, 0x01, 0xa0, 0x06, 0x24, 0x65,
1770x00, 0x52, 0xbb, 0x00, 0x02, 0xae, 0x03, 0x01, 0x65, 0x02, 1780x66, 0x76, 0x00, 0x05, 0x68, 0x00, 0x15, 0x61, 0xe9, 0x00,
1780x04, 0x21, 0x00, 0x00, 0x0d, 0x00, 0x11, 0x73, 0x92, 0x03, 1790x02, 0x69, 0x00, 0x01, 0xde, 0x00, 0x0f, 0x32, 0x00, 0x05,
1790x01, 0x12, 0x03, 0x01, 0x62, 0x02, 0x02, 0x04, 0x01, 0x0c, 1800x07, 0x82, 0x03, 0x31, 0x2e, 0x00, 0x52, 0xc5, 0x00, 0x02,
1800x60, 0x02, 0x12, 0x41, 0xd9, 0x02, 0x02, 0xd6, 0x04, 0x01, 1810xc2, 0x03, 0x01, 0x6f, 0x02, 0x04, 0x21, 0x00, 0x00, 0x0d,
1810x59, 0x03, 0x50, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x7b, 0x04, 1820x00, 0x11, 0x73, 0xa6, 0x03, 0x01, 0x1c, 0x03, 0x01, 0x6c,
1820x05, 0x2e, 0x07, 0x22, 0x75, 0x73, 0x74, 0x08, 0x62, 0x63, 1830x02, 0x02, 0x0e, 0x01, 0x0c, 0x6a, 0x02, 0x12, 0x41, 0xe3,
1830x6f, 0x6e, 0x6a, 0x75, 0x6e, 0x93, 0x05, 0x01, 0x11, 0x09, 1840x02, 0x02, 0x09, 0x05, 0x01, 0x63, 0x03, 0x50, 0x75, 0x72,
1840x25, 0x74, 0x68, 0x13, 0x01, 0x01, 0x30, 0x00, 0x11, 0x74, 1850x73, 0x6f, 0x72, 0xa4, 0x04, 0x05, 0x61, 0x07, 0x22, 0x75,
1850x02, 0x05, 0x17, 0x63, 0x1f, 0x03, 0x2b, 0x6f, 0x72, 0x72, 1860x73, 0xa7, 0x08, 0x62, 0x63, 0x6f, 0x6e, 0x6a, 0x75, 0x6e,
1860x00, 0x3d, 0x55, 0x73, 0x65, 0x67, 0x00, 0x60, 0x74, 0x6f, 1870xc6, 0x05, 0x01, 0x44, 0x09, 0x25, 0x74, 0x68, 0x1d, 0x01,
1870x00, 0x6d, 0x6f, 0x76, 0x09, 0x01, 0x51, 0x68, 0x69, 0x67, 1880x01, 0x30, 0x00, 0x11, 0x74, 0x35, 0x05, 0x17, 0x63, 0x29,
1880x68, 0x6c, 0xfc, 0x06, 0x07, 0xfb, 0x07, 0x00, 0x93, 0x07, 1890x03, 0x2b, 0x6f, 0x72, 0x72, 0x00, 0x3d, 0x55, 0x73, 0x65,
1890x1f, 0x2c, 0x2f, 0x01, 0x07, 0x00, 0x3f, 0x00, 0x00, 0xa5, 1900x67, 0x00, 0x60, 0x74, 0x6f, 0x00, 0x6d, 0x6f, 0x76, 0x09,
1900x06, 0x01, 0x75, 0x04, 0x03, 0xc1, 0x01, 0x05, 0x48, 0x00, 1910x01, 0x51, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x2f, 0x07, 0x07,
1910x25, 0x65, 0x64, 0x96, 0x03, 0x14, 0x50, 0x19, 0x01, 0x50, 1920x2e, 0x08, 0x00, 0xc6, 0x07, 0x1f, 0x2c, 0x2f, 0x01, 0x07,
1920x72, 0x65, 0x74, 0x75, 0x72, 0x3f, 0x03, 0x5a, 0x67, 0x67, 1930x07, 0x98, 0x01, 0x30, 0x74, 0x6f, 0x00, 0xe2, 0x06, 0x01,
1930x6c, 0x65, 0x73, 0x30, 0x00, 0x02, 0x09, 0x08, 0x00, 0x63, 1940x93, 0x04, 0x03, 0xd5, 0x01, 0x05, 0x52, 0x00, 0x25, 0x65,
1940x00, 0x11, 0x64, 0x30, 0x04, 0x02, 0x51, 0x08, 0x04, 0xa9, 1950x64, 0xaa, 0x03, 0x14, 0x50, 0x23, 0x01, 0x50, 0x72, 0x65,
1950x02, 0x02, 0x67, 0x00, 0x20, 0x6f, 0x72, 0x27, 0x03, 0x1b, 1960x74, 0x75, 0x72, 0x53, 0x03, 0x5a, 0x67, 0x67, 0x6c, 0x65,
1960x6f, 0x20, 0x04, 0x07, 0xd0, 0x04, 0x60, 0x70, 0x72, 0x65, 1970x73, 0x30, 0x00, 0x02, 0x46, 0x08, 0x00, 0x6d, 0x00, 0x11,
1970x66, 0x65, 0x72, 0x0b, 0x01, 0x23, 0x69, 0x6e, 0xa5, 0x00, 1980x64, 0x44, 0x04, 0x02, 0x8e, 0x08, 0x04, 0xbd, 0x02, 0x02,
1980x05, 0xd3, 0x02, 0x81, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x62, 1990x67, 0x00, 0x10, 0x6f, 0xef, 0x07, 0x2b, 0x6d, 0x6f, 0x34,
1990x65, 0x74, 0x2b, 0x05, 0x26, 0x75, 0x74, 0xdb, 0x02, 0x51, 2000x04, 0x07, 0xee, 0x04, 0x60, 0x70, 0x72, 0x65, 0x66, 0x65,
2000x70, 0x69, 0x63, 0x74, 0x75, 0xc6, 0x0a, 0x04, 0x6e, 0x00, 2010x72, 0x15, 0x01, 0x23, 0x69, 0x6e, 0xaf, 0x00, 0x05, 0xe7,
2010x02, 0xeb, 0x01, 0x31, 0x60, 0x41, 0x27, 0x13, 0x07, 0x01, 2020x02, 0x81, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x62, 0x65, 0x74,
2020xae, 0x00, 0x50, 0x00, 0x62, 0x65, 0x74, 0x77, 0xbc, 0x08, 2030x49, 0x05, 0x26, 0x75, 0x74, 0xef, 0x02, 0x51, 0x70, 0x69,
2030x00, 0xe1, 0x04, 0x04, 0x0e, 0x06, 0x05, 0x6d, 0x01, 0x29, 2040x63, 0x74, 0x75, 0x03, 0x0b, 0x04, 0x6e, 0x00, 0x02, 0xf5,
2040x61, 0x73, 0x79, 0x01, 0x07, 0x24, 0x00, 0x02, 0x5b, 0x03, 2050x01, 0x31, 0x60, 0x41, 0x27, 0x50, 0x07, 0x01, 0xae, 0x00,
2050x02, 0x8a, 0x00, 0x00, 0xa9, 0x00, 0x15, 0x4c, 0x55, 0x02, 2060x50, 0x00, 0x62, 0x65, 0x74, 0x77, 0xf9, 0x08, 0x00, 0xf5,
2060x02, 0x9c, 0x04, 0x33, 0x63, 0x6c, 0x75, 0x2b, 0x02, 0x00, 2070x04, 0x04, 0x41, 0x06, 0x05, 0x77, 0x01, 0x29, 0x61, 0x73,
2070xcc, 0x00, 0x01, 0xbe, 0x05, 0x30, 0x73, 0x00, 0x64, 0xf0, 2080x83, 0x01, 0x07, 0x24, 0x00, 0x02, 0x6f, 0x03, 0x02, 0x8a,
2080x0a, 0x50, 0x28, 0x67, 0x72, 0x65, 0x79, 0x11, 0x00, 0x41, 2090x00, 0x00, 0xa9, 0x00, 0x15, 0x4c, 0x5f, 0x02, 0x02, 0xb0,
2090x6f, 0x75, 0x74, 0x29, 0x9a, 0x02, 0x24, 0x75, 0x6e, 0x24, 2100x04, 0x33, 0x63, 0x6c, 0x75, 0x35, 0x02, 0x00, 0xcc, 0x00,
2100x00, 0x23, 0x69, 0x66, 0x57, 0x08, 0x71, 0x61, 0x6c, 0x72, 2110x01, 0xdc, 0x05, 0x30, 0x73, 0x00, 0x64, 0x2d, 0x0b, 0x50,
2110x65, 0x61, 0x64, 0x79, 0x3d, 0x00, 0x20, 0x65, 0x64, 0x61, 2120x28, 0x67, 0x72, 0x65, 0x79, 0x11, 0x00, 0x41, 0x6f, 0x75,
2120x00, 0x10, 0x28, 0x1a, 0x03, 0x01, 0xf0, 0x00, 0x01, 0x2f, 2130x74, 0x29, 0xa4, 0x02, 0x24, 0x75, 0x6e, 0x24, 0x00, 0x23,
2130x02, 0x92, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 2140x69, 0x66, 0x94, 0x08, 0x71, 0x61, 0x6c, 0x72, 0x65, 0x61,
2140x62, 0x49, 0x02, 0x13, 0x73, 0xd8, 0x07, 0x36, 0x32, 0x2e, 2150x64, 0x79, 0x3d, 0x00, 0x20, 0x65, 0x64, 0x61, 0x00, 0x10,
2150x31, 0x2d, 0x0a, 0x82, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 2160x28, 0x24, 0x03, 0x01, 0xf0, 0x00, 0x01, 0x39, 0x02, 0x92,
2160x62, 0x6c, 0x8f, 0x08, 0x44, 0x33, 0x37, 0x2e, 0x32, 0xa6, 2170x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x53,
2170x07, 0x60, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0xbc, 0x00, 2180x02, 0x13, 0x73, 0x15, 0x08, 0x36, 0x32, 0x2e, 0x31, 0x6a,
2180x12, 0x20, 0x12, 0x05, 0x00, 0xc8, 0x02, 0x05, 0x14, 0x00, 2190x0a, 0x82, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c,
2190x02, 0x42, 0x00, 0x04, 0x3d, 0x00, 0x04, 0x9d, 0x09, 0xf1, 2200xcc, 0x08, 0x44, 0x33, 0x37, 0x2e, 0x32, 0xe3, 0x07, 0x60,
2200x01, 0x65, 0x00, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 2210x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0xbc, 0x00, 0x12, 0x20,
2210x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x70, 0x00, 0x03, 2220x26, 0x05, 0x00, 0xd2, 0x02, 0x05, 0x14, 0x00, 0x02, 0x42,
2220x57, 0x07, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 2230x00, 0x04, 0x3d, 0x00, 0x04, 0xda, 0x09, 0xf1, 0x01, 0x65,
2230x6d, 0x65, 0x6e, 0x75, 0xac, 0x00, 0x91, 0x57, 0x69, 0x64, 2240x00, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e,
2240x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x01, 0x02, 0x51, 0x00, 2250x2e, 0x27, 0x00, 0x6f, 0x70, 0x70, 0x00, 0x03, 0x8a, 0x07,
2250x00, 0x53, 0x69, 0x7a, 0x5e, 0x07, 0x01, 0x0b, 0x0a, 0x14, 2260xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65,
2260x69, 0x6a, 0x04, 0x01, 0x38, 0x01, 0x40, 0x44, 0x69, 0x66, 2270x6e, 0x75, 0xac, 0x00, 0x91, 0x57, 0x69, 0x64, 0x74, 0x68,
2270x66, 0xc9, 0x04, 0x63, 0x74, 0x79, 0x00, 0x00, 0x00, 0x43, 2280x2c, 0x00, 0x48, 0x65, 0x01, 0x02, 0x51, 0x00, 0x00, 0x53,
2280x3d, 0x08, 0x01, 0x54, 0x00, 0x16, 0x64, 0x1a, 0x00, 0x04, 2290x69, 0x7a, 0x91, 0x07, 0x01, 0x48, 0x0a, 0x14, 0x69, 0x7e,
2290xa6, 0x0a, 0x50, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x82, 0x02, 2300x04, 0x01, 0x38, 0x01, 0x40, 0x44, 0x69, 0x66, 0x66, 0xdd,
2300x80, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x2e, 0x00, 2310x04, 0x63, 0x74, 0x79, 0x00, 0x00, 0x00, 0x43, 0x7a, 0x08,
2320x01, 0x54, 0x00, 0x16, 0x64, 0x1a, 0x00, 0x04, 0xe3, 0x0a,
2330x50, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x82, 0x02, 0x02, 0x93,
2340x09, 0x12, 0x2e, 0xd6, 0x00, 0x14, 0x33, 0xd6, 0x00, 0x52,
2350x75, 0x73, 0x65, 0x72, 0x20, 0x2b, 0x02, 0x41, 0x65, 0x6e,
2360x63, 0x65, 0xdc, 0x00, 0x20, 0x4f, 0x6e, 0x36, 0x02, 0x63,
2370x74, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0xc0, 0x06, 0x70, 0x75,
2380x70, 0x70, 0x6f, 0x72, 0x74, 0x00, 0x2e, 0x00, 0x17, 0x00,
2390x2e, 0x00, 0x12, 0x2c, 0xca, 0x00, 0x16, 0x50, 0x12, 0x00,
2400x0d, 0xe6, 0x00, 0x33, 0x47, 0x61, 0x6d, 0xe6, 0x00, 0x02,
2410xdb, 0x01, 0x32, 0x6c, 0x65, 0x74, 0x5c, 0x02, 0x71, 0x6f,
2420x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x27, 0x0c, 0x44, 0x74,
2430x68, 0x65, 0x72, 0x38, 0x09, 0x10, 0x75, 0xaa, 0x0a, 0x05,
2440xb0, 0x02, 0x06, 0x93, 0x02, 0x00, 0x80, 0x02, 0x20, 0x72,
2450x65, 0x8f, 0x02, 0xe0, 0x65, 0x6e, 0x74, 0x00, 0x6d, 0x6f,
2460x6e, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x00,
231}; 247};
232 248
233const unsigned short help_text_len = 3286; 249const unsigned short help_text_len = 3574;
234const unsigned short help_text_words = 614; 250const unsigned short help_text_words = 660;
235const char quick_help_text[] = "Place ghosts, vampires and zombies so that the right numbers of them can be seen in mirrors."; 251const char quick_help_text[] = "Place ghosts, vampires and zombies so that the right numbers of them can be seen in mirrors.";
diff --git a/apps/plugins/puzzles/help/unequal.c b/apps/plugins/puzzles/help/unequal.c
index 8885d70c33..445fd7d544 100644
--- a/apps/plugins/puzzles/help/unequal.c
+++ b/apps/plugins/puzzles/help/unequal.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,255 +6,255 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 239, TEXT_CENTER | C_RED }, 9 { 240, TEXT_CENTER | C_RED },
10 { 306, TEXT_UNDERLINE }, 10 { 307, TEXT_UNDERLINE },
11 { 631, TEXT_CENTER | C_RED }, 11 { 632, TEXT_CENTER | C_RED },
12 { 648, TEXT_UNDERLINE }, 12 { 649, TEXT_UNDERLINE },
13 { 660, TEXT_UNDERLINE }, 13 { 661, TEXT_UNDERLINE },
14 { 668, TEXT_UNDERLINE }, 14 { 669, TEXT_UNDERLINE },
15 LAST_STYLE_ITEM 15 LAST_STYLE_ITEM
16}; 16};
17 17
18/* orig 3934 comp 2352 ratio 0.597865 level 10 saved 1582 */ 18/* orig 3954 comp 2358 ratio 0.596358 level 10 saved 1596 */
19const char help_text[] = { 19const char help_text[] = {
200xf4, 0x24, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 200xfe, 0x07, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
210x32, 0x37, 0x3a, 0x20, 0x55, 0x6e, 0x65, 0x71, 0x75, 0x61, 210x32, 0x37, 0x3a, 0x20, 0x55, 0x6e, 0x65, 0x71, 0x75, 0x61,
220x6c, 0x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 220x6c, 0x20, 0x00, 0x2d, 0x01, 0x00, 0xf4, 0x10, 0x00, 0x00,
230x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x73, 0x71, 0x75, 0x61, 230x00, 0x59, 0x6f, 0x75, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00,
240x72, 0x65, 0x00, 0x67, 0x72, 0x69, 0x64, 0x3b, 0x00, 0x65, 240x61, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x00, 0x67,
250x61, 0x63, 0x68, 0x12, 0x00, 0xf1, 0x1a, 0x6d, 0x61, 0x79, 250x72, 0x69, 0x64, 0x3b, 0x00, 0x65, 0x61, 0x63, 0x68, 0x12,
260x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x00, 0x61, 260x00, 0xf1, 0x1a, 0x6d, 0x61, 0x79, 0x00, 0x63, 0x6f, 0x6e,
270x00, 0x64, 0x69, 0x67, 0x69, 0x74, 0x00, 0x66, 0x72, 0x6f, 270x74, 0x61, 0x69, 0x6e, 0x00, 0x61, 0x00, 0x64, 0x69, 0x67,
280x6d, 0x00, 0x31, 0x00, 0x74, 0x6f, 0x00, 0x74, 0x68, 0x65, 280x69, 0x74, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x00, 0x31, 0x00,
290x00, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x6f, 0x66, 0x0c, 0x00, 290x74, 0x6f, 0x00, 0x74, 0x68, 0x65, 0x00, 0x73, 0x69, 0x7a,
300x00, 0x40, 0x00, 0xa3, 0x2c, 0x00, 0x61, 0x6e, 0x64, 0x00, 300x65, 0x00, 0x6f, 0x66, 0x0c, 0x00, 0x00, 0x40, 0x00, 0xa3,
310x73, 0x6f, 0x6d, 0x65, 0x44, 0x00, 0x12, 0x73, 0x65, 0x00, 310x2c, 0x00, 0x61, 0x6e, 0x64, 0x00, 0x73, 0x6f, 0x6d, 0x65,
320x30, 0x63, 0x6c, 0x75, 0x2d, 0x00, 0xb0, 0x67, 0x6e, 0x73, 320x44, 0x00, 0x12, 0x73, 0x65, 0x00, 0x30, 0x63, 0x6c, 0x75,
330x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x33, 0x00, 330x2d, 0x00, 0xb0, 0x67, 0x6e, 0x73, 0x00, 0x62, 0x65, 0x74,
340x20, 0x6d, 0x2e, 0x87, 0x00, 0x80, 0x72, 0x00, 0x61, 0x69, 340x77, 0x65, 0x65, 0x6e, 0x33, 0x00, 0x20, 0x6d, 0x2e, 0x87,
350x6d, 0x00, 0x69, 0x73, 0x54, 0x00, 0xe5, 0x66, 0x75, 0x6c, 350x00, 0x80, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 0x69, 0x73,
360x6c, 0x79, 0x00, 0x70, 0x6f, 0x70, 0x75, 0x6c, 0x61, 0x74, 360x54, 0x00, 0xe5, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x00, 0x70,
370x65, 0x57, 0x00, 0xf0, 0x0f, 0x00, 0x77, 0x69, 0x74, 0x68, 370x6f, 0x70, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x57, 0x00, 0xf0,
380x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x00, 0x73, 380x0f, 0x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x6e, 0x75, 0x6d,
390x75, 0x63, 0x68, 0x00, 0x74, 0x68, 0x61, 0x74, 0x3a, 0x00, 390x62, 0x65, 0x72, 0x73, 0x00, 0x73, 0x75, 0x63, 0x68, 0x00,
400x00, 0x00, 0x2d, 0x00, 0x45, 0xb2, 0x00, 0x34, 0x72, 0x6f, 400x74, 0x68, 0x61, 0x74, 0x3a, 0x00, 0x00, 0x00, 0x2d, 0x00,
410x77, 0xab, 0x00, 0xf1, 0x05, 0x73, 0x00, 0x6f, 0x6e, 0x6c, 410x45, 0xb2, 0x00, 0x34, 0x72, 0x6f, 0x77, 0xab, 0x00, 0xf1,
420x79, 0x00, 0x6f, 0x6e, 0x65, 0x00, 0x6f, 0x63, 0x63, 0x75, 420x05, 0x73, 0x00, 0x6f, 0x6e, 0x6c, 0x79, 0x00, 0x6f, 0x6e,
430x72, 0x72, 0x65, 0x6e, 0x63, 0xa5, 0x00, 0x01, 0xdb, 0x00, 430x65, 0x00, 0x6f, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
440x02, 0xc6, 0x00, 0x05, 0x38, 0x00, 0x6f, 0x63, 0x6f, 0x6c, 440x63, 0xa5, 0x00, 0x01, 0xdb, 0x00, 0x02, 0xc6, 0x00, 0x05,
450x75, 0x6d, 0x6e, 0x3b, 0x00, 0x1d, 0x31, 0x41, 0x6c, 0x6c, 450x38, 0x00, 0x6f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x3b,
460x9c, 0x00, 0x07, 0xd7, 0x00, 0x00, 0x30, 0x01, 0xf1, 0x03, 460x00, 0x1d, 0x31, 0x41, 0x6c, 0x6c, 0x9c, 0x00, 0x07, 0xd7,
470x73, 0x61, 0x74, 0x69, 0x73, 0x66, 0x69, 0x65, 0x64, 0x2e, 470x00, 0x00, 0x30, 0x01, 0xf1, 0x03, 0x73, 0x61, 0x74, 0x69,
480x00, 0x00, 0x00, 0x54, 0x68, 0x65, 0x72, 0x65, 0x17, 0x00, 480x73, 0x66, 0x69, 0x65, 0x64, 0x2e, 0x00, 0x00, 0x00, 0x54,
490xf3, 0x0b, 0x74, 0x77, 0x6f, 0x00, 0x6d, 0x6f, 0x64, 0x65, 490x68, 0x65, 0x72, 0x65, 0x17, 0x00, 0xf3, 0x0b, 0x74, 0x77,
500x73, 0x00, 0x66, 0x6f, 0x72, 0x00, 0x74, 0x68, 0x69, 0x73, 500x6f, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0x73, 0x00, 0x66, 0x6f,
510x00, 0x67, 0x61, 0x6d, 0x65, 0x2c, 0x00, 0x60, 0x90, 0x01, 510x72, 0x00, 0x74, 0x68, 0x69, 0x73, 0x00, 0x67, 0x61, 0x6d,
520x11, 0x27, 0x36, 0x01, 0xa0, 0x60, 0x41, 0x64, 0x6a, 0x61, 520x65, 0x2c, 0x00, 0x60, 0xa4, 0x01, 0x11, 0x27, 0x36, 0x01,
530x63, 0x65, 0x6e, 0x74, 0x27, 0x3f, 0x00, 0x27, 0x49, 0x6e, 530xa0, 0x60, 0x41, 0x64, 0x6a, 0x61, 0x63, 0x65, 0x6e, 0x74,
540x1f, 0x00, 0x00, 0x3e, 0x00, 0x1e, 0x2c, 0x72, 0x00, 0x00, 540x27, 0x3f, 0x00, 0x27, 0x49, 0x6e, 0x1f, 0x00, 0x00, 0x3e,
550x1d, 0x01, 0xf1, 0x0e, 0x65, 0x61, 0x74, 0x65, 0x72, 0x2d, 550x00, 0x1e, 0x2c, 0x72, 0x00, 0x00, 0x1d, 0x01, 0xf1, 0x0e,
560x74, 0x68, 0x61, 0x6e, 0x00, 0x73, 0x79, 0x6d, 0x62, 0x6f, 560x65, 0x61, 0x74, 0x65, 0x72, 0x2d, 0x74, 0x68, 0x61, 0x6e,
570x6c, 0x73, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 570x00, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x00, 0x69,
580x69, 0x6e, 0x67, 0xca, 0x00, 0x02, 0x89, 0x01, 0x50, 0x27, 580x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6e, 0x67, 0xca,
590x73, 0x00, 0x76, 0x61, 0x3d, 0x00, 0x24, 0x69, 0x73, 0x36, 590x00, 0x02, 0x89, 0x01, 0x50, 0x27, 0x73, 0x00, 0x76, 0x61,
600x00, 0x11, 0x00, 0x36, 0x00, 0xf0, 0x01, 0x69, 0x74, 0x73, 600x3d, 0x00, 0x24, 0x69, 0x73, 0x36, 0x00, 0x11, 0x00, 0x36,
610x00, 0x6e, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6f, 0x75, 0x72, 610x00, 0xf0, 0x01, 0x69, 0x74, 0x73, 0x00, 0x6e, 0x65, 0x69,
620x27, 0x73, 0x2e, 0x7a, 0x00, 0x01, 0xa4, 0x00, 0x00, 0x75, 620x67, 0x68, 0x62, 0x6f, 0x75, 0x72, 0x27, 0x73, 0x2e, 0x7a,
630x00, 0x81, 0x00, 0x6e, 0x6f, 0x74, 0x00, 0x61, 0x6c, 0x6c, 630x00, 0x01, 0xa4, 0x00, 0x00, 0x75, 0x00, 0x81, 0x00, 0x6e,
640x78, 0x00, 0x11, 0x73, 0x11, 0x02, 0xf0, 0x18, 0x62, 0x65, 640x6f, 0x74, 0x00, 0x61, 0x6c, 0x6c, 0x78, 0x00, 0x11, 0x73,
650x00, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x2c, 0x00, 650x11, 0x02, 0xf0, 0x18, 0x62, 0x65, 0x00, 0x76, 0x69, 0x73,
660x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x75, 0x6c, 0x61, 0x72, 660x69, 0x62, 0x6c, 0x65, 0x2c, 0x00, 0x70, 0x61, 0x72, 0x74,
670x6c, 0x79, 0x00, 0x61, 0x74, 0x00, 0x68, 0x69, 0x67, 0x68, 670x69, 0x63, 0x75, 0x6c, 0x61, 0x72, 0x6c, 0x79, 0x00, 0x61,
680x65, 0x72, 0x00, 0x64, 0x69, 0x66, 0x66, 0x17, 0x00, 0x94, 680x74, 0x00, 0x68, 0x69, 0x67, 0x68, 0x65, 0x72, 0x00, 0x64,
690x74, 0x79, 0x00, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x73, 0xd1, 690x69, 0x66, 0x66, 0x17, 0x00, 0x94, 0x74, 0x79, 0x00, 0x6c,
700x00, 0x05, 0xe2, 0x00, 0x0f, 0xd2, 0x00, 0x07, 0x3f, 0x62, 700x65, 0x76, 0x65, 0x6c, 0x73, 0xd1, 0x00, 0x05, 0xe2, 0x00,
710x61, 0x72, 0xc2, 0x00, 0x10, 0x90, 0x6e, 0x75, 0x6d, 0x65, 710x0f, 0xd2, 0x00, 0x07, 0x3f, 0x62, 0x61, 0x72, 0xc2, 0x00,
720x72, 0x69, 0x63, 0x61, 0x6c, 0x78, 0x00, 0x03, 0x55, 0x00, 720x10, 0x90, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
730x61, 0x00, 0x28, 0x69, 0x2e, 0x65, 0x2e, 0x31, 0x00, 0x03, 730x6c, 0x78, 0x00, 0x03, 0x55, 0x00, 0x61, 0x00, 0x28, 0x69,
740x88, 0x00, 0x21, 0x6f, 0x72, 0x0e, 0x00, 0x6f, 0x6c, 0x6f, 740x2e, 0x65, 0x2e, 0x31, 0x00, 0x03, 0x88, 0x00, 0x21, 0x6f,
750x77, 0x65, 0x72, 0x29, 0xee, 0x00, 0x00, 0x0b, 0xec, 0x00, 750x72, 0x0e, 0x00, 0x6f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x29,
760x06, 0xe8, 0x00, 0x20, 0x61, 0x72, 0x0e, 0x00, 0x44, 0x77, 760xee, 0x00, 0x00, 0x0b, 0xec, 0x00, 0x06, 0xe8, 0x00, 0x20,
770x61, 0x79, 0x73, 0xec, 0x00, 0x54, 0x3a, 0x00, 0x61, 0x62, 770x61, 0x72, 0x0e, 0x00, 0x44, 0x77, 0x61, 0x79, 0x73, 0xec,
780x73, 0x0e, 0x02, 0x10, 0x61, 0xa6, 0x00, 0xb1, 0x00, 0x74, 780x00, 0x54, 0x3a, 0x00, 0x61, 0x62, 0x73, 0x0e, 0x02, 0x10,
790x68, 0x75, 0x73, 0x00, 0x6d, 0x65, 0x61, 0x6e, 0x73, 0x8d, 790x61, 0xa6, 0x00, 0xb1, 0x00, 0x74, 0x68, 0x75, 0x73, 0x00,
800x02, 0x2f, 0x00, 0x61, 0xa8, 0x00, 0x00, 0xa1, 0x64, 0x65, 800x6d, 0x65, 0x61, 0x6e, 0x73, 0x8d, 0x02, 0x2f, 0x00, 0x61,
810x66, 0x69, 0x6e, 0x69, 0x74, 0x65, 0x6c, 0x79, 0x4a, 0x01, 810xa8, 0x00, 0x00, 0xa1, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69,
820x0f, 0xb7, 0x00, 0x02, 0x22, 0x74, 0x6f, 0x40, 0x00, 0x09, 820x74, 0x65, 0x6c, 0x79, 0x4a, 0x01, 0x0f, 0xb7, 0x00, 0x02,
830x85, 0x01, 0x02, 0x30, 0x01, 0x50, 0x54, 0x72, 0x69, 0x76, 830x22, 0x74, 0x6f, 0x40, 0x00, 0x09, 0x85, 0x01, 0x02, 0x30,
840x69, 0x01, 0x02, 0x0c, 0x52, 0x01, 0xa0, 0x00, 0x28, 0x61, 840x01, 0x50, 0x54, 0x72, 0x69, 0x76, 0x69, 0x01, 0x02, 0x0c,
850x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x8e, 0x01, 0x11, 850x52, 0x01, 0xa0, 0x00, 0x28, 0x61, 0x76, 0x61, 0x69, 0x6c,
860x61, 0x49, 0x01, 0x81, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 860x61, 0x62, 0x6c, 0x8e, 0x01, 0x11, 0x61, 0x49, 0x01, 0x81,
870x6d, 0x27, 0x5d, 0x02, 0xf1, 0x00, 0x00, 0x74, 0x79, 0x70, 870x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x27, 0x5d, 0x02,
880x65, 0x00, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 880xf1, 0x00, 0x00, 0x74, 0x79, 0x70, 0x65, 0x00, 0x73, 0x65,
890x29, 0x6b, 0x01, 0x03, 0x8f, 0x02, 0x2b, 0x6e, 0x6f, 0x37, 890x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x29, 0x6b, 0x01, 0x03,
900x02, 0x01, 0x7c, 0x01, 0x1c, 0x69, 0x70, 0x02, 0x11, 0x3b, 900x8f, 0x02, 0x2b, 0x6e, 0x6f, 0x37, 0x02, 0x01, 0x7c, 0x01,
910x55, 0x00, 0x63, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x9e, 910x1c, 0x69, 0x70, 0x02, 0x11, 0x3b, 0x55, 0x00, 0x63, 0x70,
920x03, 0x42, 0x73, 0x6f, 0x6c, 0x76, 0x95, 0x03, 0x10, 0x4c, 920x75, 0x7a, 0x7a, 0x6c, 0x65, 0x9e, 0x03, 0x42, 0x73, 0x6f,
930x9d, 0x01, 0x04, 0x27, 0x04, 0x00, 0x34, 0x03, 0x00, 0xb2, 930x6c, 0x76, 0x95, 0x03, 0x10, 0x4c, 0x9d, 0x01, 0x04, 0x27,
940x00, 0x21, 0x41, 0x74, 0x1c, 0x00, 0x31, 0x74, 0x69, 0x6d, 940x04, 0x00, 0x34, 0x03, 0x00, 0xb2, 0x00, 0x21, 0x41, 0x74,
950x26, 0x01, 0x30, 0x77, 0x72, 0x69, 0xc2, 0x01, 0x02, 0xe6, 950x1c, 0x00, 0x31, 0x74, 0x69, 0x6d, 0x26, 0x01, 0x30, 0x77,
960x01, 0x0a, 0x5c, 0x00, 0x02, 0x33, 0x04, 0x27, 0x69, 0x73, 960x72, 0x69, 0xc2, 0x01, 0x02, 0xe6, 0x01, 0x0a, 0x5c, 0x00,
970x5f, 0x00, 0x60, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0xf2, 970x02, 0x33, 0x04, 0x27, 0x69, 0x73, 0x5f, 0x00, 0x60, 0x61,
980x01, 0x21, 0x69, 0x6e, 0x32, 0x00, 0xf1, 0x06, 0x47, 0x75, 980x70, 0x70, 0x65, 0x61, 0x72, 0xf2, 0x01, 0x21, 0x69, 0x6e,
990x61, 0x72, 0x64, 0x69, 0x61, 0x6e, 0x00, 0x77, 0x65, 0x65, 990x32, 0x00, 0xf1, 0x06, 0x47, 0x75, 0x61, 0x72, 0x64, 0x69,
1000x6b, 0x6c, 0x79, 0x00, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x1a, 1000x61, 0x6e, 0x00, 0x77, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x00,
1010x00, 0x10, 0x6e, 0xe0, 0x00, 0xa1, 0x60, 0x46, 0x75, 0x74, 1010x75, 0x6e, 0x64, 0x65, 0x72, 0x1a, 0x00, 0x10, 0x6e, 0xe0,
1020x6f, 0x73, 0x68, 0x69, 0x6b, 0x69, 0x2f, 0x03, 0x03, 0x5f, 1020x00, 0xa1, 0x60, 0x46, 0x75, 0x74, 0x6f, 0x73, 0x68, 0x69,
1030x00, 0x41, 0x00, 0x77, 0x61, 0x73, 0xcd, 0x03, 0x72, 0x72, 1030x6b, 0x69, 0x2f, 0x03, 0x03, 0x5f, 0x00, 0x41, 0x00, 0x77,
1040x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x5d, 0x01, 0x20, 0x69, 1040x61, 0x73, 0xcd, 0x03, 0x72, 0x72, 0x69, 0x62, 0x75, 0x74,
1050x73, 0xe8, 0x03, 0x00, 0x0b, 0x01, 0xf1, 0x03, 0x69, 0x6f, 1050x65, 0x64, 0x5d, 0x01, 0x20, 0x69, 0x73, 0xe8, 0x03, 0x00,
1060x6e, 0x00, 0x62, 0x79, 0x00, 0x4a, 0x61, 0x6d, 0x65, 0x73, 1060x0b, 0x01, 0xf1, 0x03, 0x69, 0x6f, 0x6e, 0x00, 0x62, 0x79,
1070x00, 0x48, 0x61, 0x72, 0x76, 0x65, 0xba, 0x00, 0x45, 0x32, 1070x00, 0x4a, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61, 0x72,
1080x37, 0x2e, 0x31, 0x1d, 0x05, 0x01, 0x3f, 0x00, 0x47, 0x6f, 1080x76, 0x65, 0xba, 0x00, 0x45, 0x32, 0x37, 0x2e, 0x31, 0x31,
1090x6c, 0x73, 0x20, 0x57, 0x00, 0x21, 0x73, 0x68, 0xcc, 0x04, 1090x05, 0x01, 0x3f, 0x00, 0x47, 0x6f, 0x6c, 0x73, 0x20, 0x57,
1100x10, 0x6d, 0x7a, 0x04, 0x21, 0x6f, 0x66, 0x46, 0x02, 0x03, 1100x00, 0x21, 0x73, 0x68, 0xcc, 0x04, 0x10, 0x6d, 0x7a, 0x04,
1110x27, 0x00, 0x72, 0x00, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 1110x21, 0x6f, 0x66, 0x46, 0x02, 0x03, 0x27, 0x00, 0x72, 0x00,
1120xa2, 0x04, 0x41, 0x53, 0x6f, 0x6c, 0x6f, 0xfc, 0x03, 0x64, 1120x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0xa2, 0x04, 0x41, 0x53,
1130x6f, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x3f, 0x00, 0xe1, 0x2c, 1130x6f, 0x6c, 0x6f, 0xfc, 0x03, 0x64, 0x6f, 0x00, 0x70, 0x6c,
1140x00, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x79, 0x00, 0x63, 0x6c, 1140x61, 0x79, 0x3f, 0x00, 0xe1, 0x2c, 0x00, 0x73, 0x69, 0x6d,
1150x69, 0x63, 0x6b, 0xc4, 0x00, 0x60, 0x6d, 0x6f, 0x75, 0x73, 1150x70, 0x6c, 0x79, 0x00, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0xc4,
1160x65, 0x00, 0x58, 0x05, 0x84, 0x6e, 0x79, 0x00, 0x65, 0x6d, 1160x00, 0x60, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x00, 0x58, 0x05,
1170x70, 0x74, 0x79, 0x4e, 0x01, 0x00, 0x0b, 0x04, 0x42, 0x74, 1170x84, 0x6e, 0x79, 0x00, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x4e,
1180x68, 0x65, 0x6e, 0xc2, 0x01, 0x04, 0x77, 0x05, 0x70, 0x6f, 1180x01, 0x00, 0x0b, 0x04, 0x42, 0x74, 0x68, 0x65, 0x6e, 0xc2,
1190x72, 0x00, 0x6c, 0x65, 0x74, 0x74, 0xd5, 0x02, 0x02, 0x1f, 1190x01, 0x04, 0x77, 0x05, 0x70, 0x6f, 0x72, 0x00, 0x6c, 0x65,
1200x01, 0x81, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 1200x74, 0x74, 0xd5, 0x02, 0x02, 0x1f, 0x01, 0x81, 0x6b, 0x65,
1210x36, 0x05, 0x32, 0x69, 0x6c, 0x6c, 0x44, 0x02, 0x02, 0x44, 1210x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x36, 0x05, 0x32, 0x69,
1220x00, 0xc0, 0x2e, 0x00, 0x49, 0x66, 0x00, 0x79, 0x6f, 0x75, 1220x6c, 0x6c, 0x44, 0x02, 0x02, 0x44, 0x00, 0xc0, 0x2e, 0x00,
1230x00, 0x6d, 0x61, 0x6b, 0x43, 0x00, 0x8e, 0x6d, 0x69, 0x73, 1230x49, 0x66, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x6d, 0x61, 0x6b,
1240x74, 0x61, 0x6b, 0x65, 0x2c, 0x80, 0x00, 0x02, 0x4c, 0x00, 1240x43, 0x00, 0x8e, 0x6d, 0x69, 0x73, 0x74, 0x61, 0x6b, 0x65,
1250x98, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 1250x2c, 0x80, 0x00, 0x02, 0x4c, 0x00, 0x98, 0x69, 0x6e, 0x63,
1260x84, 0x00, 0xb0, 0x70, 0x72, 0x65, 0x73, 0x73, 0x00, 0x53, 1260x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x84, 0x00, 0xb0, 0x70,
1270x70, 0x61, 0x63, 0x65, 0x64, 0x00, 0xb0, 0x63, 0x6c, 0x65, 1270x72, 0x65, 0x73, 0x73, 0x00, 0x53, 0x70, 0x61, 0x63, 0x65,
1280x61, 0x72, 0x00, 0x69, 0x74, 0x00, 0x61, 0x67, 0x0f, 0x06, 1280x64, 0x00, 0xb0, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x00, 0x69,
1290x62, 0x28, 0x6f, 0x72, 0x00, 0x75, 0x73, 0x0d, 0x02, 0xd1, 1290x74, 0x00, 0x61, 0x67, 0x0f, 0x06, 0x62, 0x28, 0x6f, 0x72,
1300x55, 0x6e, 0x64, 0x6f, 0x00, 0x66, 0x65, 0x61, 0x74, 0x75, 1300x00, 0x75, 0x73, 0x0d, 0x02, 0xd1, 0x55, 0x6e, 0x64, 0x6f,
1310x72, 0x65, 0x29, 0xbb, 0x02, 0x02, 0x7e, 0x00, 0x62, 0x72, 1310x00, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x29, 0xbb,
1320x69, 0x67, 0x68, 0x74, 0x2d, 0x74, 0x00, 0x01, 0x42, 0x06, 1320x02, 0x02, 0x7e, 0x00, 0x62, 0x72, 0x69, 0x67, 0x68, 0x74,
1330x0f, 0xe2, 0x00, 0x04, 0x02, 0xd8, 0x05, 0x13, 0x2c, 0x06, 1330x2d, 0x74, 0x00, 0x01, 0x42, 0x06, 0x0f, 0xe2, 0x00, 0x04,
1340x03, 0x01, 0x0d, 0x00, 0x20, 0x00, 0x77, 0xd3, 0x00, 0xa4, 1340x02, 0xd8, 0x05, 0x13, 0x2c, 0x06, 0x03, 0x01, 0x0d, 0x00,
1350x62, 0x65, 0x00, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 1350x20, 0x00, 0x77, 0xd3, 0x00, 0xa4, 0x62, 0x65, 0x00, 0x65,
1360xaa, 0x00, 0x04, 0x42, 0x00, 0xf1, 0x03, 0x73, 0x00, 0x61, 1360x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0xaa, 0x00, 0x04, 0x42,
1370x00, 0x60, 0x70, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x00, 0x6d, 1370x00, 0xf1, 0x03, 0x73, 0x00, 0x61, 0x00, 0x60, 0x70, 0x65,
1380x61, 0x72, 0x6b, 0x27, 0x2e, 0xd1, 0x06, 0x32, 0x63, 0x61, 1380x6e, 0x63, 0x69, 0x6c, 0x00, 0x6d, 0x61, 0x72, 0x6b, 0x27,
1390x6e, 0x70, 0x06, 0x07, 0x1b, 0x00, 0x02, 0x76, 0x05, 0x85, 1390x2e, 0xd1, 0x06, 0x32, 0x63, 0x61, 0x6e, 0x70, 0x06, 0x07,
1400x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x45, 0x06, 1400x1b, 0x00, 0x02, 0x76, 0x05, 0x85, 0x6d, 0x75, 0x6c, 0x74,
1410x04, 0x51, 0x00, 0x00, 0x4c, 0x02, 0x04, 0x36, 0x01, 0x13, 1410x69, 0x70, 0x6c, 0x65, 0x45, 0x06, 0x04, 0x51, 0x00, 0x00,
1420x53, 0xb3, 0x06, 0x03, 0x0e, 0x06, 0x00, 0x8d, 0x02, 0x00, 1420x4c, 0x02, 0x04, 0x36, 0x01, 0x13, 0x53, 0xb3, 0x06, 0x03,
1430x5b, 0x01, 0x55, 0x65, 0x64, 0x2d, 0x69, 0x6e, 0x39, 0x00, 1430x0e, 0x06, 0x00, 0x8d, 0x02, 0x00, 0x5b, 0x01, 0x55, 0x65,
1440x32, 0x63, 0x61, 0x6e, 0x15, 0x05, 0x25, 0x73, 0x6f, 0x1d, 1440x64, 0x2d, 0x69, 0x6e, 0x39, 0x00, 0x32, 0x63, 0x61, 0x6e,
1450x07, 0x08, 0x6f, 0x00, 0x03, 0xfc, 0x05, 0x02, 0x86, 0x03, 1450x15, 0x05, 0x25, 0x73, 0x6f, 0x1d, 0x07, 0x08, 0x6f, 0x00,
1460x10, 0x70, 0x43, 0x04, 0x81, 0x6e, 0x6f, 0x00, 0x61, 0x74, 1460x03, 0xfc, 0x05, 0x02, 0x86, 0x03, 0x10, 0x70, 0x43, 0x04,
1470x74, 0x65, 0x6e, 0x7e, 0x02, 0x29, 0x74, 0x6f, 0x2e, 0x00, 1470x81, 0x6e, 0x6f, 0x00, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x7e,
1480xe0, 0x2c, 0x00, 0x73, 0x6f, 0x00, 0x65, 0x78, 0x61, 0x63, 1480x02, 0x29, 0x74, 0x6f, 0x2e, 0x00, 0xe0, 0x2c, 0x00, 0x73,
1490x74, 0x6c, 0x79, 0x00, 0x77, 0x01, 0x01, 0x00, 0x3a, 0x01, 1490x6f, 0x00, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 0x79, 0x00,
1500x03, 0x5a, 0x01, 0x11, 0x6d, 0xbb, 0x00, 0x50, 0x69, 0x73, 1500x77, 0x01, 0x01, 0x00, 0x3a, 0x01, 0x03, 0x5a, 0x01, 0x11,
1510x00, 0x75, 0x70, 0x38, 0x00, 0x63, 0x79, 0x6f, 0x75, 0x3a, 1510x6d, 0xbb, 0x00, 0x50, 0x69, 0x73, 0x00, 0x75, 0x70, 0x38,
1520x00, 0x79, 0xe7, 0x00, 0x05, 0x23, 0x00, 0x70, 0x61, 0x73, 1520x00, 0x63, 0x79, 0x6f, 0x75, 0x3a, 0x00, 0x79, 0xe7, 0x00,
1530x00, 0x72, 0x65, 0x6d, 0x69, 0x1e, 0x03, 0x05, 0x89, 0x04, 1530x05, 0x23, 0x00, 0x70, 0x61, 0x73, 0x00, 0x72, 0x65, 0x6d,
1540x06, 0x98, 0x05, 0x04, 0x32, 0x01, 0x41, 0x6e, 0x65, 0x65, 1540x69, 0x1e, 0x03, 0x05, 0x89, 0x04, 0x06, 0x98, 0x05, 0x04,
1550x64, 0xc4, 0x03, 0xf0, 0x01, 0x62, 0x65, 0x00, 0x72, 0x65, 1550x32, 0x01, 0x41, 0x6e, 0x65, 0x65, 0x64, 0xc4, 0x03, 0xf0,
1560x2d, 0x65, 0x78, 0x61, 0x6d, 0x69, 0x6e, 0x65, 0x64, 0x00, 1560x01, 0x62, 0x65, 0x00, 0x72, 0x65, 0x2d, 0x65, 0x78, 0x61,
1570x6f, 0xd3, 0x04, 0x00, 0x54, 0x00, 0x70, 0x6b, 0x6e, 0x6f, 1570x6d, 0x69, 0x6e, 0x65, 0x64, 0x00, 0x6f, 0xd3, 0x04, 0x00,
1580x77, 0x00, 0x6d, 0x6f, 0x5d, 0x01, 0x3b, 0x62, 0x6f, 0x75, 1580x54, 0x00, 0x70, 0x6b, 0x6e, 0x6f, 0x77, 0x00, 0x6d, 0x6f,
1590x45, 0x00, 0x04, 0xa2, 0x01, 0x2f, 0x6f, 0x72, 0x80, 0x00, 1590x5d, 0x01, 0x3b, 0x62, 0x6f, 0x75, 0x45, 0x00, 0x04, 0xa2,
1600x02, 0x54, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x07, 0x08, 0x31, 1600x01, 0x2f, 0x6f, 0x72, 0x80, 0x00, 0x02, 0x54, 0x6c, 0x69,
1610x70, 0x6f, 0x73, 0x32, 0x05, 0x08, 0x6a, 0x01, 0x64, 0x61, 1610x73, 0x74, 0x73, 0x07, 0x08, 0x31, 0x70, 0x6f, 0x73, 0x32,
1620x00, 0x67, 0x69, 0x76, 0x65, 0x31, 0x04, 0x01, 0x48, 0x00, 1620x05, 0x08, 0x6a, 0x01, 0x64, 0x61, 0x00, 0x67, 0x69, 0x76,
1630x50, 0x61, 0x6e, 0x79, 0x74, 0x68, 0x62, 0x01, 0x32, 0x65, 1630x65, 0x31, 0x04, 0x01, 0x48, 0x00, 0x50, 0x61, 0x6e, 0x79,
1640x6c, 0x73, 0x82, 0x00, 0x93, 0x66, 0x65, 0x65, 0x6c, 0x00, 1640x74, 0x68, 0x62, 0x01, 0x32, 0x65, 0x6c, 0x73, 0x82, 0x00,
1650x6c, 0x69, 0x6b, 0x65, 0x42, 0x03, 0x41, 0x65, 0x72, 0x61, 1650x93, 0x66, 0x65, 0x65, 0x6c, 0x00, 0x6c, 0x69, 0x6b, 0x65,
1660x73, 0x9f, 0x08, 0x49, 0x69, 0x6e, 0x67, 0x6c, 0xd3, 0x01, 1660x42, 0x03, 0x41, 0x65, 0x72, 0x61, 0x73, 0x9f, 0x08, 0x49,
1670x1c, 0x2c, 0x5b, 0x02, 0x08, 0x1b, 0x02, 0x22, 0x6e, 0x64, 1670x69, 0x6e, 0x67, 0x6c, 0xd3, 0x01, 0x1c, 0x2c, 0x5b, 0x02,
1680x58, 0x02, 0x05, 0xde, 0x01, 0x03, 0x52, 0x02, 0x01, 0xb8, 1680x08, 0x1b, 0x02, 0x22, 0x6e, 0x64, 0x58, 0x02, 0x05, 0xde,
1690x02, 0x01, 0xa7, 0x04, 0x2a, 0x6c, 0x6c, 0x20, 0x02, 0x09, 1690x01, 0x03, 0x52, 0x02, 0x01, 0xb8, 0x02, 0x01, 0xa7, 0x04,
1700x9c, 0x02, 0x22, 0x72, 0x65, 0x79, 0x00, 0x30, 0x64, 0x00, 1700x2a, 0x6c, 0x6c, 0x20, 0x02, 0x09, 0x9c, 0x02, 0x22, 0x72,
1710x77, 0xa3, 0x02, 0x00, 0x99, 0x00, 0x34, 0x6c, 0x65, 0x66, 1710x65, 0x79, 0x00, 0x30, 0x64, 0x00, 0x77, 0xa3, 0x02, 0x00,
1720x6c, 0x00, 0x05, 0x5e, 0x00, 0x18, 0x61, 0x14, 0x01, 0x0f, 1720x99, 0x00, 0x34, 0x6c, 0x65, 0x66, 0x6c, 0x00, 0x05, 0x5e,
1730x2a, 0x00, 0x05, 0x02, 0x43, 0x03, 0x10, 0x73, 0x43, 0x03, 1730x00, 0x18, 0x61, 0x14, 0x01, 0x0f, 0x2a, 0x00, 0x05, 0x02,
1740x36, 0x2e, 0x00, 0x52, 0xb3, 0x00, 0x00, 0xf7, 0x00, 0x05, 1740x43, 0x03, 0x10, 0x73, 0x43, 0x03, 0x36, 0x2e, 0x00, 0x52,
1750x20, 0x00, 0x00, 0x0d, 0x00, 0x01, 0x23, 0x00, 0x02, 0xf4, 1750xb3, 0x00, 0x00, 0xf7, 0x00, 0x05, 0x20, 0x00, 0x00, 0x0d,
1760x02, 0x01, 0x58, 0x02, 0x02, 0xfb, 0x00, 0x0c, 0x56, 0x02, 1760x00, 0x01, 0x23, 0x00, 0x02, 0xf4, 0x02, 0x01, 0x58, 0x02,
1770x12, 0x41, 0xcb, 0x02, 0x00, 0x65, 0x04, 0x03, 0x3b, 0x07, 1770x02, 0xfb, 0x00, 0x0c, 0x56, 0x02, 0x12, 0x41, 0xcb, 0x02,
1780x50, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x0b, 0x04, 0x01, 0x97, 1780x00, 0x65, 0x04, 0x03, 0x3b, 0x07, 0x50, 0x75, 0x72, 0x73,
1790x02, 0x00, 0xdc, 0x01, 0x22, 0x75, 0x73, 0x2d, 0x03, 0x62, 1790x6f, 0x72, 0x0b, 0x04, 0x01, 0x97, 0x02, 0x00, 0xdc, 0x01,
1800x63, 0x6f, 0x6e, 0x6a, 0x75, 0x6e, 0xf1, 0x04, 0x01, 0x9b, 1800x22, 0x75, 0x73, 0x2d, 0x03, 0x62, 0x63, 0x6f, 0x6e, 0x6a,
1810x04, 0x00, 0x30, 0x00, 0x02, 0x4b, 0x04, 0x01, 0x2f, 0x00, 1810x75, 0x6e, 0xf1, 0x04, 0x01, 0x9b, 0x04, 0x00, 0x30, 0x00,
1820x00, 0xce, 0x05, 0x25, 0x65, 0x74, 0xa4, 0x01, 0x2b, 0x6f, 1820x02, 0x4b, 0x04, 0x01, 0x2f, 0x00, 0x00, 0xce, 0x05, 0x25,
1830x72, 0x6e, 0x00, 0x04, 0x4e, 0x03, 0x01, 0x8f, 0x00, 0x04, 1830x65, 0x74, 0xa4, 0x01, 0x2b, 0x6f, 0x72, 0x6e, 0x00, 0x04,
1840xe9, 0x03, 0x30, 0x60, 0x4d, 0x27, 0x3e, 0x00, 0x00, 0x3d, 1840x4e, 0x03, 0x01, 0x8f, 0x00, 0x04, 0xe9, 0x03, 0x30, 0x60,
1850x00, 0x51, 0x61, 0x75, 0x74, 0x6f, 0x2d, 0x78, 0x04, 0x54, 1850x4d, 0x27, 0x3e, 0x00, 0x00, 0x3d, 0x00, 0x51, 0x61, 0x75,
1860x65, 0x76, 0x65, 0x72, 0x79, 0xda, 0x06, 0xc1, 0x00, 0x68, 1860x74, 0x6f, 0x2d, 0x78, 0x04, 0x54, 0x65, 0x76, 0x65, 0x72,
1870x69, 0x6e, 0x74, 0x2c, 0x00, 0x72, 0x65, 0x61, 0x64, 0x79, 1870x79, 0xda, 0x06, 0xc1, 0x00, 0x68, 0x69, 0x6e, 0x74, 0x2c,
1880xad, 0x00, 0x72, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x61, 0x6c, 1880x00, 0x72, 0x65, 0x61, 0x64, 0x79, 0xad, 0x00, 0x72, 0x72,
1890xa6, 0x02, 0x61, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x33, 1890x65, 0x6d, 0x6f, 0x76, 0x61, 0x6c, 0xa6, 0x02, 0x61, 0x71,
1900x01, 0x01, 0x4f, 0x00, 0x15, 0x48, 0x4f, 0x00, 0x26, 0x64, 1900x75, 0x69, 0x72, 0x65, 0x64, 0x33, 0x01, 0x01, 0x4f, 0x00,
1910x6f, 0xb0, 0x01, 0x23, 0x62, 0x75, 0x5e, 0x03, 0x22, 0x74, 1910x15, 0x48, 0x4f, 0x00, 0x26, 0x64, 0x6f, 0xb0, 0x01, 0x23,
1920x6f, 0x3f, 0x00, 0x02, 0x9a, 0x07, 0x71, 0x6f, 0x62, 0x76, 1920x62, 0x75, 0x5e, 0x03, 0x22, 0x74, 0x6f, 0x3f, 0x00, 0x02,
1930x69, 0x6f, 0x75, 0x73, 0x62, 0x00, 0x12, 0x73, 0xc8, 0x01, 1930x9a, 0x07, 0x71, 0x6f, 0x62, 0x76, 0x69, 0x6f, 0x75, 0x73,
1940xc5, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 1940x62, 0x00, 0x12, 0x73, 0xc8, 0x01, 0xc5, 0x74, 0x65, 0x72,
1950x6c, 0x79, 0x2c, 0xa5, 0x00, 0x08, 0x15, 0x01, 0x10, 0x74, 1950x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x6c, 0x79, 0x2c, 0xa5,
1960x79, 0x09, 0x03, 0xb3, 0x06, 0x00, 0xd9, 0x00, 0x75, 0x00, 1960x00, 0x08, 0x15, 0x01, 0x10, 0x74, 0x79, 0x09, 0x03, 0xb3,
1970x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x58, 0x0a, 0x34, 0x2e, 1970x06, 0x00, 0xd9, 0x00, 0x75, 0x00, 0x61, 0x72, 0x6f, 0x75,
1980x00, 0x50, 0x83, 0x01, 0x20, 0x74, 0x68, 0x19, 0x03, 0x43, 1980x6e, 0x64, 0x58, 0x0a, 0x34, 0x2e, 0x00, 0x50, 0x83, 0x01,
1990x74, 0x75, 0x72, 0x6e, 0x94, 0x00, 0x56, 0x67, 0x67, 0x6c, 1990x20, 0x74, 0x68, 0x19, 0x03, 0x43, 0x74, 0x75, 0x72, 0x6e,
2000x65, 0x73, 0x3a, 0x00, 0x11, 0x28, 0xf9, 0x0a, 0x72, 0x61, 2000x94, 0x00, 0x56, 0x67, 0x67, 0x6c, 0x65, 0x73, 0x3a, 0x00,
2010x00, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x27, 0x01, 0x01, 0x08, 2010x11, 0x28, 0xf9, 0x0a, 0x72, 0x61, 0x00, 0x6e, 0x6f, 0x72,
2020x01, 0x08, 0x38, 0x01, 0x24, 0x29, 0x2c, 0x21, 0x02, 0x01, 2020x6d, 0x61, 0x27, 0x01, 0x01, 0x08, 0x01, 0x08, 0x38, 0x01,
2030xe2, 0x01, 0x04, 0x7a, 0x02, 0x20, 0x69, 0x6e, 0xc4, 0x03, 2030x24, 0x29, 0x2c, 0x21, 0x02, 0x01, 0xe2, 0x01, 0x04, 0x7a,
2040x0f, 0xca, 0x04, 0x03, 0x03, 0x0e, 0x00, 0x80, 0x61, 0x70, 2040x02, 0x20, 0x69, 0x6e, 0xc4, 0x03, 0x0f, 0xca, 0x04, 0x03,
2050x70, 0x72, 0x6f, 0x70, 0x72, 0x69, 0xf5, 0x0a, 0x44, 0x77, 2050x03, 0x0e, 0x00, 0x80, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70,
2060x61, 0x79, 0x3b, 0x44, 0x00, 0x01, 0x9b, 0x02, 0x21, 0x30, 2060x72, 0x69, 0xf5, 0x0a, 0x44, 0x77, 0x61, 0x79, 0x3b, 0x44,
2070x00, 0x6d, 0x05, 0x04, 0xa6, 0x00, 0x02, 0x2d, 0x02, 0x23, 2070x00, 0x01, 0x9b, 0x02, 0x21, 0x30, 0x00, 0x6d, 0x05, 0x04,
2080x62, 0x61, 0x25, 0x05, 0x02, 0x99, 0x05, 0x13, 0x61, 0xaa, 2080xa6, 0x00, 0x02, 0x2d, 0x02, 0x23, 0x62, 0x61, 0x25, 0x05,
2090x04, 0x05, 0xcc, 0x04, 0x58, 0x00, 0x00, 0x4c, 0x65, 0x66, 2090x02, 0x99, 0x05, 0x13, 0x61, 0xaa, 0x04, 0x05, 0xcc, 0x04,
2100x70, 0x02, 0x02, 0x69, 0x09, 0x01, 0x33, 0x00, 0x01, 0xbd, 2100x58, 0x00, 0x00, 0x4c, 0x65, 0x66, 0x70, 0x02, 0x02, 0x69,
2110x00, 0x20, 0x69, 0x74, 0x95, 0x01, 0x10, 0x64, 0x21, 0x09, 2110x09, 0x01, 0x33, 0x00, 0x01, 0xbd, 0x00, 0x20, 0x69, 0x74,
2120x60, 0x28, 0x67, 0x72, 0x65, 0x79, 0x00, 0x66, 0x06, 0x41, 2120x95, 0x01, 0x10, 0x64, 0x21, 0x09, 0x60, 0x28, 0x67, 0x72,
2130x75, 0x74, 0x29, 0x2c, 0x6e, 0x00, 0x14, 0x6e, 0x24, 0x00, 2130x65, 0x79, 0x00, 0x66, 0x06, 0x41, 0x75, 0x74, 0x29, 0x2c,
2140x10, 0x69, 0xee, 0x06, 0x01, 0xa1, 0x07, 0x12, 0x6c, 0xd6, 2140x6e, 0x00, 0x14, 0x6e, 0x24, 0x00, 0x10, 0x69, 0xee, 0x06,
2150x01, 0x00, 0x19, 0x00, 0x00, 0xe2, 0x0a, 0x40, 0x48, 0x6f, 2150x01, 0xa1, 0x07, 0x12, 0x6c, 0xd6, 0x01, 0x00, 0x19, 0x00,
2160x6c, 0x64, 0x59, 0x00, 0x13, 0x43, 0x08, 0x07, 0x00, 0x9a, 2160x00, 0xe2, 0x0a, 0x40, 0x48, 0x6f, 0x6c, 0x64, 0x59, 0x00,
2170x02, 0x4a, 0x68, 0x69, 0x66, 0x74, 0xda, 0x02, 0x00, 0x43, 2170x13, 0x43, 0x08, 0x07, 0x00, 0x9a, 0x02, 0x4a, 0x68, 0x69,
2180x02, 0x10, 0x72, 0x9d, 0x0b, 0x00, 0x55, 0x01, 0x00, 0xdd, 2180x66, 0x74, 0xda, 0x02, 0x00, 0x43, 0x02, 0x10, 0x72, 0x9d,
2190x03, 0x43, 0x77, 0x69, 0x73, 0x65, 0x78, 0x03, 0x00, 0xfb, 2190x0b, 0x00, 0x55, 0x01, 0x00, 0xdd, 0x03, 0x43, 0x77, 0x69,
2200x06, 0x01, 0x95, 0x00, 0x0a, 0x0b, 0x09, 0x05, 0xc3, 0x01, 2200x73, 0x65, 0x78, 0x03, 0x00, 0xfb, 0x06, 0x01, 0x95, 0x00,
2210x03, 0x1c, 0x01, 0x02, 0x3b, 0x04, 0x32, 0x64, 0x69, 0x72, 2210x0a, 0x0b, 0x09, 0x05, 0xc3, 0x01, 0x03, 0x1c, 0x01, 0x02,
2220xc0, 0x07, 0x00, 0xdb, 0x00, 0x14, 0x28, 0x81, 0x0b, 0x11, 2220x3b, 0x04, 0x32, 0x64, 0x69, 0x72, 0xc0, 0x07, 0x00, 0xdb,
2230x61, 0x13, 0x00, 0x00, 0x68, 0x09, 0x52, 0x73, 0x63, 0x72, 2230x00, 0x14, 0x28, 0x81, 0x0b, 0x11, 0x61, 0x13, 0x00, 0x00,
2240x69, 0x62, 0x5f, 0x01, 0x13, 0x73, 0xe9, 0x07, 0x33, 0x32, 2240x68, 0x09, 0x52, 0x73, 0x63, 0x72, 0x69, 0x62, 0x5f, 0x01,
2250x2e, 0x31, 0xca, 0x09, 0x35, 0x73, 0x6f, 0x00, 0x30, 0x09, 2250x13, 0x73, 0xe9, 0x07, 0x33, 0x32, 0x2e, 0x31, 0xca, 0x09,
2260x22, 0x2e, 0x29, 0xf1, 0x07, 0x15, 0x32, 0xf1, 0x07, 0xb2, 2260x35, 0x73, 0x6f, 0x00, 0x30, 0x09, 0x22, 0x2e, 0x29, 0xf1,
2270x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 2270x07, 0x15, 0x32, 0xf1, 0x07, 0xb2, 0x70, 0x61, 0x72, 0x61,
2280x20, 0xbc, 0x05, 0x00, 0x7c, 0x03, 0x05, 0x14, 0x00, 0x02, 2280x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0xbc, 0x05, 0x00,
2290x43, 0x00, 0x05, 0x6e, 0x09, 0x01, 0x07, 0x02, 0x07, 0x6f, 2290x7c, 0x03, 0x05, 0x14, 0x00, 0x02, 0x43, 0x00, 0x05, 0x6e,
2300x09, 0x71, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x71, 2300x09, 0x01, 0x07, 0x02, 0x07, 0x6f, 0x09, 0x71, 0x2e, 0x2e,
2310x00, 0x03, 0x9b, 0x07, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 2310x2e, 0x27, 0x00, 0x6f, 0x70, 0x71, 0x00, 0x03, 0x9b, 0x07,
2320x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xad, 0x00, 0x10, 0x4d, 2320xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65,
2330xf1, 0x08, 0x03, 0x07, 0x00, 0x28, 0x6f, 0x66, 0x56, 0x09, 2330x6e, 0x75, 0xad, 0x00, 0x10, 0x4d, 0xf1, 0x08, 0x03, 0x07,
2340x16, 0x28, 0x16, 0x09, 0x27, 0x6f, 0x72, 0x1e, 0x0b, 0x00, 2340x00, 0x28, 0x6f, 0x66, 0x56, 0x09, 0x16, 0x28, 0x16, 0x09,
2350xa2, 0x00, 0x94, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x28, 0x73, 2350x27, 0x6f, 0x72, 0x1e, 0x0b, 0x00, 0xa2, 0x00, 0x94, 0x53,
2360x2a, 0x73, 0x0d, 0x00, 0x00, 0x3c, 0x00, 0x02, 0xb4, 0x02, 2360x69, 0x7a, 0x65, 0x20, 0x28, 0x73, 0x2a, 0x73, 0x0d, 0x00,
2370x36, 0x00, 0x00, 0x44, 0x0f, 0x0a, 0x14, 0x00, 0x81, 0x01, 2370x00, 0x3c, 0x00, 0x02, 0xb4, 0x02, 0x36, 0x00, 0x00, 0x44,
2380x02, 0xac, 0x02, 0x07, 0x29, 0x0a, 0x04, 0x97, 0x0d, 0x50, 2380x0f, 0x0a, 0x14, 0x00, 0x81, 0x01, 0x02, 0xac, 0x02, 0x07,
2390x65, 0x6e, 0x65, 0x72, 0x61, 0x0c, 0x09, 0x02, 0x76, 0x00, 2390x29, 0x0a, 0x04, 0x97, 0x0d, 0x50, 0x65, 0x6e, 0x65, 0x72,
2400x10, 0x2e, 0xa8, 0x09, 0x03, 0x59, 0x0a, 0x02, 0x4d, 0x0a, 2400x61, 0x0c, 0x09, 0x02, 0x76, 0x00, 0x10, 0x2e, 0xa8, 0x09,
2410x0f, 0x1d, 0x0a, 0x0e, 0x0f, 0x0b, 0x0a, 0x1d, 0x50, 0x41, 2410x03, 0x59, 0x0a, 0x02, 0x4d, 0x0a, 0x0f, 0x1d, 0x0a, 0x0e,
2420x74, 0x00, 0x52, 0x65, 0xc5, 0x01, 0x34, 0x69, 0x76, 0x65, 2420x0f, 0x0b, 0x0a, 0x1d, 0x50, 0x41, 0x74, 0x00, 0x52, 0x65,
2430xb0, 0x0a, 0x01, 0x59, 0x0d, 0x0f, 0xb5, 0x0a, 0x1b, 0x82, 2430xc5, 0x01, 0x34, 0x69, 0x76, 0x65, 0xb0, 0x0a, 0x01, 0x59,
2440x00, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0xc1, 0x02, 2440x0d, 0x0f, 0xb5, 0x0a, 0x1b, 0x82, 0x00, 0x62, 0x61, 0x63,
2450x04, 0x12, 0x08, 0x06, 0x47, 0x04, 0x00, 0x29, 0x04, 0x01, 2450x6b, 0x74, 0x72, 0x61, 0xc1, 0x02, 0x04, 0x12, 0x08, 0x06,
2460x11, 0x03, 0x31, 0x6f, 0x6c, 0x75, 0x80, 0x01, 0x93, 0x73, 2460x47, 0x04, 0x00, 0x29, 0x04, 0x01, 0x11, 0x03, 0x31, 0x6f,
2470x68, 0x6f, 0x75, 0x6c, 0x64, 0x00, 0x73, 0x74, 0x2b, 0x00, 2470x6c, 0x75, 0x80, 0x01, 0x93, 0x73, 0x68, 0x6f, 0x75, 0x6c,
2480x71, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x2e, 0x8f, 0x07, 2480x64, 0x00, 0x73, 0x74, 0x2b, 0x00, 0x71, 0x75, 0x6e, 0x69,
2490x02, 0x89, 0x0c, 0x00, 0x1f, 0x02, 0x04, 0x81, 0x0e, 0x03, 2490x71, 0x75, 0x65, 0x2e, 0x8f, 0x07, 0x02, 0x89, 0x0c, 0x00,
2500x49, 0x00, 0x00, 0xfe, 0x08, 0x31, 0x72, 0x65, 0x61, 0x66, 2500x1f, 0x02, 0x04, 0x81, 0x0e, 0x03, 0x49, 0x00, 0x00, 0xfe,
2510x06, 0x00, 0xef, 0x0e, 0x60, 0x6d, 0x70, 0x6c, 0x65, 0x78, 2510x08, 0x31, 0x72, 0x65, 0x61, 0x66, 0x06, 0x00, 0xef, 0x0e,
2520x00, 0x12, 0x00, 0x21, 0x6f, 0x6e, 0x73, 0x03, 0x00, 0x3c, 2520x60, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x00, 0x12, 0x00, 0x21,
2530x02, 0x30, 0x6f, 0x69, 0x64, 0x59, 0x08, 0x03, 0x10, 0x00, 2530x6f, 0x6e, 0x73, 0x03, 0x00, 0x3c, 0x02, 0x30, 0x6f, 0x69,
2540xb0, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x6b, 2540x64, 0x59, 0x08, 0x03, 0x10, 0x00, 0xb0, 0x62, 0x61, 0x63,
2550x2e, 0x00, 2550x6b, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x2e, 0x00,
256}; 256};
257 257
258const unsigned short help_text_len = 3934; 258const unsigned short help_text_len = 3954;
259const unsigned short help_text_words = 730; 259const unsigned short help_text_words = 731;
260const char quick_help_text[] = "Complete the latin square in accordance with the > signs."; 260const char quick_help_text[] = "Complete the latin square in accordance with the > signs.";
diff --git a/apps/plugins/puzzles/help/unruly.c b/apps/plugins/puzzles/help/unruly.c
index b098642a72..39249c5949 100644
--- a/apps/plugins/puzzles/help/unruly.c
+++ b/apps/plugins/puzzles/help/unruly.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,142 +6,143 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 99, TEXT_CENTER | C_RED }, 9 { 100, TEXT_CENTER | C_RED },
10 { 221, TEXT_CENTER | C_RED }, 10 { 222, TEXT_CENTER | C_RED },
11 { 238, TEXT_UNDERLINE },
12 { 239, TEXT_UNDERLINE }, 11 { 239, TEXT_UNDERLINE },
13 { 266, TEXT_UNDERLINE }, 12 { 240, TEXT_UNDERLINE },
14 { 278, TEXT_UNDERLINE }, 13 { 267, TEXT_UNDERLINE },
14 { 279, TEXT_UNDERLINE },
15 LAST_STYLE_ITEM 15 LAST_STYLE_ITEM
16}; 16};
17 17
18/* orig 1688 comp 1225 ratio 0.725711 level 10 saved 463 */ 18/* orig 1707 comp 1231 ratio 0.721148 level 10 saved 476 */
19const char help_text[] = { 19const char help_text[] = {
200xf0, 0x4d, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 200xfd, 0x06, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
210x33, 0x38, 0x3a, 0x20, 0x55, 0x6e, 0x72, 0x75, 0x6c, 0x79, 210x33, 0x38, 0x3a, 0x20, 0x55, 0x6e, 0x72, 0x75, 0x6c, 0x79,
220x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x61, 0x72, 220x20, 0x00, 0x2d, 0x01, 0x00, 0xf0, 0x3a, 0x00, 0x00, 0x00,
230x65, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 230x59, 0x6f, 0x75, 0x00, 0x61, 0x72, 0x65, 0x00, 0x67, 0x69,
240x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 240x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64,
250x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x77, 0x68, 0x69, 250x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65,
260x63, 0x68, 0x00, 0x79, 0x6f, 0x75, 0x00, 0x6d, 0x75, 0x73, 260x73, 0x2c, 0x00, 0x77, 0x68, 0x69, 0x63, 0x68, 0x00, 0x79,
270x74, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x00, 0x65, 270x6f, 0x75, 0x00, 0x6d, 0x75, 0x73, 0x74, 0x00, 0x63, 0x6f,
280x69, 0x74, 0x68, 0x65, 0x72, 0x00, 0x62, 0x6c, 0x61, 0x63, 280x6c, 0x6f, 0x75, 0x72, 0x00, 0x65, 0x69, 0x74, 0x68, 0x65,
290x6b, 0x00, 0x6f, 0x72, 0x26, 0x00, 0x84, 0x74, 0x65, 0x2e, 290x72, 0x00, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x00, 0x6f, 0x72,
300x00, 0x53, 0x6f, 0x6d, 0x65, 0x3b, 0x00, 0x01, 0x57, 0x00, 300x26, 0x00, 0x84, 0x74, 0x65, 0x2e, 0x00, 0x53, 0x6f, 0x6d,
310xf1, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 310x65, 0x3b, 0x00, 0x01, 0x57, 0x00, 0xf1, 0x0c, 0x70, 0x72,
320x00, 0x61, 0x73, 0x00, 0x63, 0x6c, 0x75, 0x65, 0x73, 0x3b, 320x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x00, 0x61, 0x73, 0x00,
330x00, 0x74, 0x68, 0x65, 0x00, 0x72, 0x65, 0x73, 0x74, 0x20, 330x63, 0x6c, 0x75, 0x65, 0x73, 0x3b, 0x00, 0x74, 0x68, 0x65,
340x00, 0x81, 0x6c, 0x65, 0x66, 0x74, 0x00, 0x66, 0x6f, 0x72, 340x00, 0x72, 0x65, 0x73, 0x74, 0x20, 0x00, 0x81, 0x6c, 0x65,
350x61, 0x00, 0xf0, 0x09, 0x74, 0x6f, 0x00, 0x66, 0x69, 0x6c, 350x66, 0x74, 0x00, 0x66, 0x6f, 0x72, 0x61, 0x00, 0xf0, 0x09,
360x6c, 0x00, 0x69, 0x6e, 0x2e, 0x00, 0x45, 0x61, 0x63, 0x68, 360x74, 0x6f, 0x00, 0x66, 0x69, 0x6c, 0x6c, 0x00, 0x69, 0x6e,
370x00, 0x72, 0x6f, 0x77, 0x00, 0x61, 0x6e, 0x64, 0x75, 0x00, 370x2e, 0x00, 0x45, 0x61, 0x63, 0x68, 0x00, 0x72, 0x6f, 0x77,
380x34, 0x75, 0x6d, 0x6e, 0x81, 0x00, 0x51, 0x6e, 0x74, 0x61, 380x00, 0x61, 0x6e, 0x64, 0x75, 0x00, 0x34, 0x75, 0x6d, 0x6e,
390x69, 0x6e, 0x47, 0x00, 0xb0, 0x73, 0x61, 0x6d, 0x65, 0x00, 390x81, 0x00, 0x51, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x47, 0x00,
400x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0xb4, 0x00, 0x02, 0x8e, 400xb0, 0x73, 0x61, 0x6d, 0x65, 0x00, 0x6e, 0x75, 0x6d, 0x62,
410x00, 0x00, 0x31, 0x00, 0x01, 0x8f, 0x00, 0x06, 0xc4, 0x00, 410x65, 0x72, 0xb4, 0x00, 0x02, 0x8e, 0x00, 0x00, 0x31, 0x00,
420x00, 0x13, 0x00, 0x21, 0x6e, 0x6f, 0x4f, 0x00, 0x25, 0x6f, 420x01, 0x8f, 0x00, 0x06, 0xc4, 0x00, 0x00, 0x13, 0x00, 0x21,
430x72, 0x4e, 0x00, 0x27, 0x61, 0x79, 0x4d, 0x00, 0x30, 0x72, 430x6e, 0x6f, 0x4f, 0x00, 0x25, 0x6f, 0x72, 0x4e, 0x00, 0x27,
440x65, 0x65, 0x0e, 0x00, 0x76, 0x73, 0x65, 0x63, 0x75, 0x74, 440x61, 0x79, 0x4d, 0x00, 0x30, 0x72, 0x65, 0x65, 0x0e, 0x00,
450x69, 0x76, 0xc5, 0x00, 0x26, 0x6f, 0x66, 0x6a, 0x00, 0x02, 450x76, 0x73, 0x65, 0x63, 0x75, 0x74, 0x69, 0x76, 0xc5, 0x00,
460xfc, 0x00, 0xf1, 0x2d, 0x2e, 0x00, 0x00, 0x00, 0x54, 0x68, 460x26, 0x6f, 0x66, 0x6a, 0x00, 0x02, 0xfc, 0x00, 0xf1, 0x2d,
470x69, 0x73, 0x00, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 470x2e, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x73, 0x00, 0x70,
480x74, 0x79, 0x70, 0x65, 0x00, 0x77, 0x61, 0x73, 0x00, 0x69, 480x75, 0x7a, 0x7a, 0x6c, 0x65, 0x00, 0x74, 0x79, 0x70, 0x65,
490x6e, 0x76, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x00, 0x62, 0x79, 490x00, 0x77, 0x61, 0x73, 0x00, 0x69, 0x6e, 0x76, 0x65, 0x6e,
500x00, 0x41, 0x64, 0x6f, 0x6c, 0x66, 0x6f, 0x00, 0x5a, 0x61, 500x74, 0x65, 0x64, 0x00, 0x62, 0x79, 0x00, 0x41, 0x64, 0x6f,
510x6e, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x2c, 0x00, 0x75, 510x6c, 0x66, 0x6f, 0x00, 0x5a, 0x61, 0x6e, 0x65, 0x6c, 0x6c,
520x6e, 0x64, 0x65, 0x72, 0x4c, 0x00, 0x10, 0x6e, 0x4c, 0x00, 520x61, 0x74, 0x69, 0x2c, 0x00, 0x75, 0x6e, 0x64, 0x65, 0x72,
530xf1, 0x09, 0x60, 0x54, 0x6f, 0x68, 0x75, 0x00, 0x77, 0x61, 530x4c, 0x00, 0x10, 0x6e, 0x4c, 0x00, 0xf1, 0x09, 0x60, 0x54,
540x00, 0x56, 0x6f, 0x68, 0x75, 0x27, 0x2e, 0x00, 0x53, 0x65, 540x6f, 0x68, 0x75, 0x00, 0x77, 0x61, 0x00, 0x56, 0x6f, 0x68,
550x65, 0x00, 0x5b, 0x32, 0x31, 0x5d, 0x0d, 0x01, 0xc0, 0x6d, 550x75, 0x27, 0x2e, 0x00, 0x53, 0x65, 0x65, 0x00, 0x5b, 0x32,
560x6f, 0x72, 0x65, 0x00, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 560x31, 0x5d, 0x0d, 0x01, 0xc0, 0x6d, 0x6f, 0x72, 0x65, 0x00,
570x73, 0x6f, 0x00, 0x02, 0xaf, 0x01, 0x01, 0x65, 0x00, 0x00, 570x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x6f, 0x00, 0x02,
580xb2, 0x00, 0x40, 0x72, 0x69, 0x62, 0x75, 0x68, 0x00, 0x60, 580xc2, 0x01, 0x01, 0x65, 0x00, 0x00, 0xb2, 0x00, 0x40, 0x72,
590x74, 0x6f, 0x00, 0x74, 0x68, 0x69, 0x14, 0x00, 0x80, 0x6c, 590x69, 0x62, 0x75, 0x68, 0x00, 0x60, 0x74, 0x6f, 0x00, 0x74,
600x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x7b, 0x00, 0xe0, 600x68, 0x69, 0x14, 0x00, 0x80, 0x6c, 0x6c, 0x65, 0x63, 0x74,
610x4c, 0x65, 0x6e, 0x6e, 0x61, 0x72, 0x64, 0x00, 0x53, 0x70, 610x69, 0x6f, 0x6e, 0x7b, 0x00, 0xe0, 0x4c, 0x65, 0x6e, 0x6e,
620x72, 0x6f, 0x6e, 0x67, 0x3f, 0x00, 0x01, 0x58, 0x00, 0xf0, 620x61, 0x72, 0x64, 0x00, 0x53, 0x70, 0x72, 0x6f, 0x6e, 0x67,
630x0d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 630x3f, 0x00, 0x01, 0x58, 0x00, 0xf0, 0x0d, 0x68, 0x74, 0x74,
640x77, 0x2e, 0x6a, 0x61, 0x6e, 0x6b, 0x6f, 0x2e, 0x61, 0x74, 640x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6a, 0x61,
650x2f, 0x52, 0x61, 0x65, 0x74, 0x73, 0x65, 0x6c, 0x2f, 0x8c, 650x6e, 0x6b, 0x6f, 0x2e, 0x61, 0x74, 0x2f, 0x52, 0x61, 0x65,
660x00, 0x40, 0x2d, 0x57, 0x61, 0x2d, 0x8c, 0x00, 0xf4, 0x02, 660x74, 0x73, 0x65, 0x6c, 0x2f, 0x8c, 0x00, 0x40, 0x2d, 0x57,
670x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 670x61, 0x2d, 0x8c, 0x00, 0xf4, 0x02, 0x2f, 0x69, 0x6e, 0x64,
680x00, 0x00, 0x00, 0x33, 0x38, 0x2e, 0x31, 0x2d, 0x02, 0x01, 680x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x00, 0x00, 0x00, 0x33,
690x7a, 0x00, 0x40, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x01, 0x63, 690x38, 0x2e, 0x31, 0x40, 0x02, 0x01, 0x7a, 0x00, 0x40, 0x6f,
700x6f, 0x00, 0x70, 0x6c, 0x61, 0x79, 0x99, 0x00, 0x71, 0x2c, 700x6c, 0x73, 0x20, 0x00, 0x01, 0x63, 0x6f, 0x00, 0x70, 0x6c,
710x00, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0xdd, 0x00, 0x70, 0x6d, 710x61, 0x79, 0x99, 0x00, 0x71, 0x2c, 0x00, 0x63, 0x6c, 0x69,
720x6f, 0x75, 0x73, 0x65, 0x00, 0x69, 0x4b, 0x02, 0x02, 0x43, 720x63, 0x6b, 0xdd, 0x00, 0x70, 0x6d, 0x6f, 0x75, 0x73, 0x65,
730x01, 0x00, 0xa6, 0x00, 0xa5, 0x63, 0x68, 0x61, 0x6e, 0x67, 730x00, 0x69, 0x4b, 0x02, 0x02, 0x43, 0x01, 0x00, 0xa6, 0x00,
740x65, 0x00, 0x69, 0x74, 0x73, 0x44, 0x01, 0x51, 0x4c, 0x65, 740xa5, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x69, 0x74,
750x66, 0x74, 0x2d, 0x37, 0x00, 0xc4, 0x69, 0x6e, 0x67, 0x00, 750x73, 0x44, 0x01, 0x51, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x37,
760x61, 0x6e, 0x00, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x34, 0x00, 760x00, 0xc4, 0x69, 0x6e, 0x67, 0x00, 0x61, 0x6e, 0x00, 0x65,
770x10, 0x77, 0x07, 0x02, 0x72, 0x74, 0x75, 0x72, 0x6e, 0x00, 770x6d, 0x70, 0x74, 0x79, 0x34, 0x00, 0x10, 0x77, 0x07, 0x02,
780x69, 0x74, 0xd7, 0x01, 0x02, 0xc5, 0x01, 0x47, 0x72, 0x69, 780x72, 0x74, 0x75, 0x72, 0x6e, 0x00, 0x69, 0x74, 0xd7, 0x01,
790x67, 0x68, 0x37, 0x00, 0x09, 0x27, 0x00, 0x03, 0x83, 0x02, 790x02, 0xc5, 0x01, 0x47, 0x72, 0x69, 0x67, 0x68, 0x37, 0x00,
800x55, 0x4b, 0x65, 0x65, 0x70, 0x00, 0x22, 0x00, 0x05, 0xbc, 800x09, 0x27, 0x00, 0x03, 0x83, 0x02, 0x55, 0x4b, 0x65, 0x65,
810x01, 0x61, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x8d, 0x00, 810x70, 0x00, 0x22, 0x00, 0x05, 0xbc, 0x01, 0x61, 0x62, 0x75,
820x40, 0x79, 0x63, 0x6c, 0x65, 0xf2, 0x01, 0x41, 0x6f, 0x75, 820x74, 0x74, 0x6f, 0x6e, 0x8d, 0x00, 0x40, 0x79, 0x63, 0x6c,
830x67, 0x68, 0x21, 0x00, 0x02, 0xfe, 0x01, 0xf1, 0x00, 0x70, 830x65, 0xf2, 0x01, 0x41, 0x6f, 0x75, 0x67, 0x68, 0x21, 0x00,
840x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x00, 0x73, 0x74, 840x02, 0xfe, 0x01, 0xf1, 0x00, 0x70, 0x6f, 0x73, 0x73, 0x69,
850x61, 0x74, 0x65, 0x73, 0x89, 0x01, 0x24, 0x74, 0x68, 0x0a, 850x62, 0x6c, 0x65, 0x00, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73,
860x02, 0x42, 0x2e, 0x00, 0x49, 0x66, 0x06, 0x03, 0x52, 0x69, 860x89, 0x01, 0x24, 0x74, 0x68, 0x0a, 0x02, 0x42, 0x2e, 0x00,
870x64, 0x64, 0x6c, 0x65, 0x84, 0x00, 0x09, 0xe8, 0x00, 0x22, 870x49, 0x66, 0x06, 0x03, 0x52, 0x69, 0x64, 0x64, 0x6c, 0x65,
880x69, 0x74, 0x90, 0x00, 0x11, 0x62, 0xdf, 0x02, 0x20, 0x65, 880x84, 0x00, 0x09, 0xe8, 0x00, 0x22, 0x69, 0x74, 0x90, 0x00,
890x74, 0x6c, 0x00, 0x01, 0xd5, 0x00, 0x13, 0x2e, 0x67, 0x03, 890x11, 0x62, 0xdf, 0x02, 0x20, 0x65, 0x74, 0x6c, 0x00, 0x01,
900x90, 0x63, 0x61, 0x6e, 0x00, 0x61, 0x6c, 0x73, 0x6f, 0x00, 900xd5, 0x00, 0x13, 0x2e, 0x67, 0x03, 0x90, 0x63, 0x61, 0x6e,
910x22, 0x01, 0x00, 0x5a, 0x00, 0xb0, 0x63, 0x75, 0x72, 0x73, 910x00, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0x22, 0x01, 0x00, 0x5a,
920x6f, 0x72, 0x00, 0x6b, 0x65, 0x79, 0x73, 0x2d, 0x00, 0xb1, 920x00, 0xb0, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x00, 0x6b,
930x6d, 0x6f, 0x76, 0x65, 0x00, 0x61, 0x72, 0x6f, 0x75, 0x6e, 930x65, 0x79, 0x73, 0x2d, 0x00, 0xb1, 0x6d, 0x6f, 0x76, 0x65,
940x64, 0x1f, 0x00, 0x00, 0x8b, 0x03, 0x74, 0x2e, 0x00, 0x50, 940x00, 0x61, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x1f, 0x00, 0x00,
950x72, 0x65, 0x73, 0x73, 0xcb, 0x00, 0x21, 0x72, 0x65, 0xee, 950x8b, 0x03, 0x74, 0x2e, 0x00, 0x50, 0x72, 0x65, 0x73, 0x73,
960x00, 0x82, 0x6f, 0x72, 0x00, 0x73, 0x70, 0x61, 0x63, 0x65, 960xcb, 0x00, 0x21, 0x72, 0x65, 0xee, 0x00, 0x82, 0x6f, 0x72,
970x3b, 0x00, 0x06, 0x06, 0x01, 0x0c, 0x47, 0x01, 0x0a, 0x9f, 970x00, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3b, 0x00, 0x06, 0x06,
980x03, 0x00, 0x97, 0x00, 0x30, 0x70, 0x65, 0x63, 0xdf, 0x02, 980x01, 0x0c, 0x47, 0x01, 0x0a, 0x9f, 0x03, 0x00, 0x97, 0x00,
990x52, 0x6c, 0x79, 0x00, 0x28, 0x61, 0x67, 0x00, 0x15, 0x6e, 990x30, 0x70, 0x65, 0x63, 0xdf, 0x02, 0x52, 0x6c, 0x79, 0x00,
1000x11, 0x01, 0x04, 0xe1, 0x02, 0x28, 0x73, 0x00, 0x5f, 0x03, 1000x28, 0x61, 0x67, 0x00, 0x15, 0x6e, 0x11, 0x01, 0x04, 0xe1,
1010x30, 0x77, 0x61, 0x79, 0xbd, 0x03, 0x06, 0xdc, 0x01, 0x02, 1010x02, 0x28, 0x73, 0x00, 0x5f, 0x03, 0x30, 0x77, 0x61, 0x79,
1020x4a, 0x01, 0x22, 0x73, 0x29, 0x92, 0x01, 0x14, 0x70, 0x9f, 1020xbd, 0x03, 0x06, 0xdc, 0x01, 0x02, 0x4a, 0x01, 0x22, 0x73,
1030x00, 0x42, 0x42, 0x61, 0x63, 0x6b, 0x95, 0x00, 0x01, 0x90, 1030x29, 0x92, 0x01, 0x14, 0x70, 0x9f, 0x00, 0x42, 0x42, 0x61,
1040x00, 0x02, 0x03, 0x01, 0x08, 0x05, 0x02, 0x05, 0x0c, 0x01, 1040x63, 0x6b, 0x95, 0x00, 0x01, 0x90, 0x00, 0x02, 0x03, 0x01,
1050x41, 0x28, 0x41, 0x6c, 0x6c, 0x50, 0x00, 0x11, 0x61, 0xb4, 1050x08, 0x05, 0x02, 0x05, 0x0c, 0x01, 0x41, 0x28, 0x41, 0x6c,
1060x02, 0xb0, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 1060x6c, 0x50, 0x00, 0x11, 0x61, 0xb4, 0x02, 0xb0, 0x73, 0x00,
1070x62, 0x65, 0x64, 0x79, 0x00, 0x13, 0x73, 0xca, 0x02, 0x31, 1070x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x79,
1080x32, 0x2e, 0x31, 0x22, 0x04, 0x01, 0x32, 0x01, 0xb2, 0x61, 1080x00, 0x13, 0x73, 0xca, 0x02, 0x31, 0x32, 0x2e, 0x31, 0x22,
1090x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 1090x04, 0x01, 0x32, 0x01, 0xb2, 0x61, 0x76, 0x61, 0x69, 0x6c,
1100x96, 0x02, 0x14, 0x32, 0x96, 0x02, 0x92, 0x70, 0x61, 0x72, 1100x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0x96, 0x02, 0x14, 0x32,
1110x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x98, 0x02, 0x56, 0x68, 1110x96, 0x02, 0x92, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74,
1120x65, 0x73, 0x65, 0x00, 0x14, 0x00, 0x02, 0x42, 0x00, 0x04, 1120x65, 0x72, 0x98, 0x02, 0x56, 0x68, 0x65, 0x73, 0x65, 0x00,
1130x3d, 0x00, 0x51, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x7a, 0x00, 1130x14, 0x00, 0x02, 0x42, 0x00, 0x04, 0x3d, 0x00, 0x51, 0x00,
1140xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 1140x66, 0x72, 0x6f, 0x6d, 0x7a, 0x00, 0xe1, 0x60, 0x43, 0x75,
1150x2e, 0x27, 0x00, 0x6f, 0x70, 0x70, 0x00, 0x22, 0x6f, 0x6e, 1150x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f,
1160x1a, 0x00, 0xa0, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 1160x70, 0x70, 0x00, 0x22, 0x6f, 0x6e, 0x1a, 0x00, 0xa0, 0x54,
1170x65, 0x6e, 0x75, 0xac, 0x00, 0x90, 0x57, 0x69, 0x64, 0x74, 1170x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xac,
1180x68, 0x2c, 0x00, 0x48, 0x65, 0x79, 0x02, 0x70, 0x00, 0x00, 1180x00, 0x90, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48,
1190x00, 0x53, 0x69, 0x7a, 0x65, 0x14, 0x04, 0x01, 0x27, 0x05, 1190x65, 0x79, 0x02, 0x70, 0x00, 0x00, 0x00, 0x53, 0x69, 0x7a,
1200x24, 0x69, 0x6e, 0x27, 0x04, 0x60, 0x2e, 0x00, 0x28, 0x4e, 1200x65, 0x14, 0x04, 0x01, 0x27, 0x05, 0x24, 0x69, 0x6e, 0x27,
1210x6f, 0x74, 0x45, 0x01, 0x22, 0x61, 0x74, 0xa9, 0x01, 0x26, 1210x04, 0x60, 0x2e, 0x00, 0x28, 0x4e, 0x6f, 0x74, 0x45, 0x01,
1220x75, 0x6c, 0x3d, 0x04, 0x30, 0x67, 0x61, 0x6d, 0x7d, 0x01, 1220x22, 0x61, 0x74, 0xa9, 0x01, 0x26, 0x75, 0x6c, 0x3d, 0x04,
1230x30, 0x71, 0x75, 0x69, 0x94, 0x01, 0x22, 0x6f, 0x74, 0x76, 1230x30, 0x67, 0x61, 0x6d, 0x7d, 0x01, 0x30, 0x71, 0x75, 0x69,
1240x02, 0x10, 0x77, 0x5b, 0x00, 0x01, 0x44, 0x01, 0x12, 0x68, 1240x94, 0x01, 0x22, 0x6f, 0x74, 0x76, 0x02, 0x10, 0x77, 0x5b,
1250x5e, 0x00, 0x20, 0x74, 0x6f, 0x3c, 0x02, 0x10, 0x65, 0x88, 1250x00, 0x01, 0x44, 0x01, 0x12, 0x68, 0x5e, 0x00, 0x20, 0x74,
1260x05, 0x02, 0xd4, 0x04, 0x11, 0x73, 0xee, 0x00, 0xe3, 0x44, 1260x6f, 0x3c, 0x02, 0x10, 0x65, 0x88, 0x05, 0x02, 0xd4, 0x04,
1270x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x00, 1270x11, 0x73, 0xee, 0x00, 0xe3, 0x44, 0x69, 0x66, 0x66, 0x69,
1280x00, 0x00, 0x43, 0x85, 0x03, 0x01, 0x42, 0x00, 0x16, 0x64, 1280x63, 0x75, 0x6c, 0x74, 0x79, 0x00, 0x00, 0x00, 0x43, 0x85,
1290x1a, 0x00, 0x04, 0x6a, 0x00, 0x50, 0x65, 0x6e, 0x65, 0x72, 1290x03, 0x01, 0x42, 0x00, 0x16, 0x64, 0x1a, 0x00, 0x04, 0x6a,
1300x61, 0x1c, 0x04, 0x02, 0x9d, 0x04, 0x02, 0x3d, 0x04, 0xe2, 1300x00, 0x50, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x1c, 0x04, 0x02,
1310x69, 0x71, 0x75, 0x65, 0x20, 0x72, 0x6f, 0x77, 0x73, 0x20, 1310x9d, 0x04, 0x02, 0x3d, 0x04, 0xe2, 0x69, 0x71, 0x75, 0x65,
1320x61, 0x6e, 0x64, 0x20, 0xff, 0x04, 0x30, 0x73, 0x00, 0x00, 1320x20, 0x72, 0x6f, 0x77, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20,
1330xd2, 0x02, 0x20, 0x65, 0x6e, 0x19, 0x01, 0x20, 0x64, 0x2c, 1330xff, 0x04, 0x30, 0x73, 0x00, 0x00, 0xd2, 0x02, 0x20, 0x65,
1340x1f, 0x05, 0x21, 0x74, 0x77, 0x23, 0x05, 0x03, 0xb9, 0x05, 1340x6e, 0x19, 0x01, 0x20, 0x64, 0x2c, 0x1f, 0x05, 0x21, 0x74,
1350x53, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x66, 0x04, 0xc6, 0x68, 1350x77, 0x23, 0x05, 0x03, 0xb9, 0x05, 0x53, 0x65, 0x72, 0x6d,
1360x61, 0x76, 0x65, 0x00, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 1360x69, 0x74, 0x66, 0x04, 0xc6, 0x68, 0x61, 0x76, 0x65, 0x00,
1370x79, 0x1a, 0x02, 0x72, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 1370x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 0x79, 0x1a, 0x02, 0x72,
1380x6e, 0x08, 0x02, 0x83, 0x6c, 0x69, 0x6b, 0x65, 0x77, 0x69, 1380x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x08, 0x02, 0x83,
1390x73, 0x65, 0x5e, 0x05, 0x00, 0x12, 0x01, 0x15, 0x41, 0xc0, 1390x6c, 0x69, 0x6b, 0x65, 0x77, 0x69, 0x73, 0x65, 0x5e, 0x05,
1400x05, 0x14, 0x61, 0x74, 0x05, 0x20, 0x63, 0x61, 0x78, 0x05, 1400x00, 0x12, 0x01, 0x15, 0x41, 0xc0, 0x05, 0x14, 0x61, 0x74,
1410xe0, 0x74, 0x63, 0x68, 0x2c, 0x00, 0x74, 0x68, 0x6f, 0x75, 1410x05, 0x20, 0x63, 0x61, 0x78, 0x05, 0xe0, 0x74, 0x63, 0x68,
1420x67, 0x68, 0x2e, 0x29, 0x00, 1420x2c, 0x00, 0x74, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x2e, 0x29,
1430x00,
143}; 144};
144 145
145const unsigned short help_text_len = 1688; 146const unsigned short help_text_len = 1707;
146const unsigned short help_text_words = 305; 147const unsigned short help_text_words = 306;
147const char quick_help_text[] = "Fill in the black and white grid to avoid runs of three."; 148const char quick_help_text[] = "Fill in the black and white grid to avoid runs of three.";
diff --git a/apps/plugins/puzzles/help/untangle.c b/apps/plugins/puzzles/help/untangle.c
index f7f5c05f24..64ebdfb364 100644
--- a/apps/plugins/puzzles/help/untangle.c
+++ b/apps/plugins/puzzles/help/untangle.c
@@ -1,4 +1,4 @@
1/* auto-generated on Dec 7 2020 by genhelp.sh */ 1/* auto-generated on Jul 22 2024 by genhelp.sh */
2/* help text is compressed using LZ4; see compress.c for details */ 2/* help text is compressed using LZ4; see compress.c for details */
3/* DO NOT EDIT! */ 3/* DO NOT EDIT! */
4 4
@@ -6,79 +6,95 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 64, TEXT_CENTER | C_RED }, 9 { 65, TEXT_CENTER | C_RED },
10 { 100, TEXT_CENTER | C_RED }, 10 { 136, TEXT_CENTER | C_RED },
11 { 119, TEXT_UNDERLINE }, 11 { 155, TEXT_UNDERLINE },
12 LAST_STYLE_ITEM 12 LAST_STYLE_ITEM
13}; 13};
14 14
15/* orig 751 comp 627 ratio 0.834887 level 4 saved 124 */ 15/* orig 974 comp 787 ratio 0.808008 level 4 saved 187 */
16const char help_text[] = { 16const char help_text[] = {
170xf0, 0x2f, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 170xff, 0x08, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
180x31, 0x38, 0x3a, 0x20, 0x55, 0x6e, 0x74, 0x61, 0x6e, 0x67, 180x31, 0x38, 0x3a, 0x20, 0x55, 0x6e, 0x74, 0x61, 0x6e, 0x67,
190x6c, 0x65, 0x20, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 190x6c, 0x65, 0x20, 0x00, 0x2d, 0x01, 0x00, 0x00, 0xf0, 0x1a,
200x61, 0x72, 0x65, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x00, 200x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 0x61, 0x72, 0x65,
210x61, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x00, 0x6f, 210x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 0x6e,
220x66, 0x00, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x2c, 0x00, 220x75, 0x6d, 0x62, 0x65, 0x72, 0x00, 0x6f, 0x66, 0x00, 0x70,
230x73, 0x6f, 0x6d, 0x65, 0x10, 0x00, 0xf1, 0x15, 0x77, 0x68, 230x6f, 0x69, 0x6e, 0x74, 0x73, 0x2c, 0x00, 0x73, 0x6f, 0x6d,
240x69, 0x63, 0x68, 0x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x6c, 240x65, 0x10, 0x00, 0xf1, 0x15, 0x77, 0x68, 0x69, 0x63, 0x68,
250x69, 0x6e, 0x65, 0x73, 0x00, 0x64, 0x72, 0x61, 0x77, 0x6e, 250x00, 0x68, 0x61, 0x76, 0x65, 0x00, 0x6c, 0x69, 0x6e, 0x65,
260x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x00, 0x74, 260x73, 0x00, 0x64, 0x72, 0x61, 0x77, 0x6e, 0x00, 0x62, 0x65,
270x68, 0x65, 0x6d, 0x2e, 0x4f, 0x00, 0x80, 0x63, 0x61, 0x6e, 270x74, 0x77, 0x65, 0x65, 0x6e, 0x00, 0x74, 0x68, 0x65, 0x6d,
280x00, 0x6d, 0x6f, 0x76, 0x65, 0x13, 0x00, 0x03, 0x46, 0x00, 280x2e, 0x4f, 0x00, 0x80, 0x63, 0x61, 0x6e, 0x00, 0x6d, 0x6f,
290xf8, 0x1c, 0x00, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x00, 0x61, 290x76, 0x65, 0x13, 0x00, 0x03, 0x46, 0x00, 0xf8, 0x1c, 0x00,
300x72, 0x62, 0x69, 0x74, 0x72, 0x61, 0x72, 0x69, 0x6c, 0x79, 300x61, 0x62, 0x6f, 0x75, 0x74, 0x00, 0x61, 0x72, 0x62, 0x69,
310x3b, 0x00, 0x79, 0x6f, 0x75, 0x72, 0x00, 0x61, 0x69, 0x6d, 310x74, 0x72, 0x61, 0x72, 0x69, 0x6c, 0x79, 0x3b, 0x00, 0x79,
320x00, 0x69, 0x73, 0x00, 0x74, 0x6f, 0x00, 0x70, 0x6f, 0x73, 320x6f, 0x75, 0x72, 0x00, 0x61, 0x69, 0x6d, 0x00, 0x69, 0x73,
330x69, 0x74, 0x69, 0x6f, 0x6e, 0x36, 0x00, 0xa1, 0x73, 0x6f, 330x00, 0x74, 0x6f, 0x00, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69,
340x00, 0x74, 0x68, 0x61, 0x74, 0x00, 0x6e, 0x6f, 0x73, 0x00, 340x6f, 0x6e, 0x36, 0x00, 0xa1, 0x73, 0x6f, 0x00, 0x74, 0x68,
350xf2, 0x1c, 0x00, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x65, 0x73, 350x61, 0x74, 0x00, 0x6e, 0x6f, 0x73, 0x00, 0xf2, 0x1c, 0x00,
360x00, 0x61, 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2e, 0x00, 360x63, 0x72, 0x6f, 0x73, 0x73, 0x65, 0x73, 0x00, 0x61, 0x6e,
370x00, 0x00, 0x49, 0x00, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 370x6f, 0x74, 0x68, 0x65, 0x72, 0x2e, 0x00, 0x00, 0x00, 0x49,
380x61, 0x6c, 0x6c, 0x79, 0x00, 0x73, 0x61, 0x77, 0x00, 0x74, 380x00, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x6c,
390x68, 0x69, 0x73, 0x00, 0x69, 0x47, 0x00, 0x40, 0x66, 0x6f, 390x79, 0x00, 0x73, 0x61, 0x77, 0x00, 0x74, 0x68, 0x69, 0x73,
400x72, 0x6d, 0xbb, 0x00, 0xf0, 0x2b, 0x61, 0x00, 0x46, 0x6c, 400x00, 0x69, 0x47, 0x00, 0x40, 0x66, 0x6f, 0x72, 0x6d, 0xbb,
410x61, 0x73, 0x68, 0x00, 0x67, 0x61, 0x6d, 0x65, 0x00, 0x63, 410x00, 0xf0, 0x2b, 0x61, 0x00, 0x46, 0x6c, 0x61, 0x73, 0x68,
420x61, 0x6c, 0x6c, 0x65, 0x64, 0x00, 0x50, 0x6c, 0x61, 0x6e, 420x00, 0x67, 0x61, 0x6d, 0x65, 0x00, 0x63, 0x61, 0x6c, 0x6c,
430x61, 0x72, 0x69, 0x74, 0x79, 0x00, 0x5b, 0x37, 0x5d, 0x2c, 430x65, 0x64, 0x00, 0x50, 0x6c, 0x61, 0x6e, 0x61, 0x72, 0x69,
440x00, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x00, 0x62, 440x74, 0x79, 0x00, 0x5b, 0x37, 0x5d, 0x2c, 0x00, 0x77, 0x72,
450x79, 0x00, 0x4a, 0x6f, 0x68, 0x6e, 0x00, 0x54, 0x61, 0x6e, 450x69, 0x74, 0x74, 0x65, 0x6e, 0x00, 0x62, 0x79, 0x00, 0x4a,
460x74, 0x61, 0x6c, 0x6f, 0x63, 0x00, 0xc4, 0x5b, 0x37, 0x5d, 460x6f, 0x68, 0x6e, 0x00, 0x54, 0x61, 0x6e, 0x74, 0x61, 0x6c,
470x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x35, 470x6f, 0x63, 0x00, 0xc4, 0x5b, 0x37, 0x5d, 0x00, 0x68, 0x74,
480x00, 0xb6, 0x2e, 0x6e, 0x65, 0x74, 0x00, 0x00, 0x00, 0x31, 480x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x35, 0x00, 0xb6, 0x2e,
490x38, 0x2e, 0x31, 0x4f, 0x01, 0x80, 0x63, 0x6f, 0x6e, 0x74, 490x6e, 0x65, 0x74, 0x00, 0x00, 0x00, 0x31, 0x38, 0x2e, 0x31,
500x72, 0x6f, 0x6c, 0x73, 0x58, 0x01, 0x22, 0x54, 0x6f, 0x04, 500x64, 0x01, 0xe2, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
510x01, 0x12, 0x61, 0xcc, 0x00, 0xf1, 0x03, 0x2c, 0x00, 0x63, 510x73, 0x20, 0x00, 0x00, 0x00, 0x54, 0x6f, 0x04, 0x01, 0x12,
520x6c, 0x69, 0x63, 0x6b, 0x00, 0x6f, 0x6e, 0x00, 0x69, 0x74, 520x61, 0xcc, 0x00, 0xf1, 0x03, 0x2c, 0x00, 0x63, 0x6c, 0x69,
530x00, 0x77, 0x69, 0x74, 0x68, 0xa1, 0x00, 0xf0, 0x06, 0x6c, 530x63, 0x6b, 0x00, 0x6f, 0x6e, 0x00, 0x69, 0x74, 0x00, 0x77,
540x65, 0x66, 0x74, 0x00, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x00, 540x69, 0x74, 0x68, 0xa1, 0x00, 0xf0, 0x06, 0x6c, 0x65, 0x66,
550x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x00, 0x61, 0x6e, 0x64, 550x74, 0x00, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x00, 0x62, 0x75,
560x59, 0x01, 0x10, 0x67, 0x27, 0x00, 0x40, 0x69, 0x6e, 0x74, 560x74, 0x74, 0x6f, 0x6e, 0x00, 0x61, 0x6e, 0x64, 0x59, 0x01,
570x6f, 0x93, 0x01, 0x25, 0x65, 0x77, 0x1e, 0x01, 0x00, 0x90, 570x10, 0x67, 0x27, 0x00, 0x40, 0x69, 0x6e, 0x74, 0x6f, 0x93,
580x00, 0x41, 0x28, 0x41, 0x6c, 0x6c, 0x3e, 0x00, 0x20, 0x61, 580x01, 0x25, 0x65, 0x77, 0x1e, 0x01, 0x00, 0x90, 0x00, 0xf0,
590x63, 0x13, 0x00, 0xb0, 0x73, 0x00, 0x64, 0x65, 0x73, 0x63, 590x11, 0x54, 0x68, 0x65, 0x00, 0x63, 0x75, 0x72, 0x73, 0x6f,
600x72, 0x69, 0x62, 0x65, 0x64, 0xf8, 0x00, 0x21, 0x73, 0x65, 600x72, 0x00, 0x6b, 0x65, 0x79, 0x73, 0x00, 0x6d, 0x61, 0x79,
610x16, 0x00, 0x41, 0x00, 0x32, 0x2e, 0x31, 0xd9, 0x01, 0xf2, 610x00, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0x62, 0x65, 0x00, 0x75,
620x01, 0x61, 0x6c, 0x73, 0x6f, 0x00, 0x61, 0x76, 0x61, 0x69, 620x73, 0x65, 0x64, 0x4e, 0x01, 0xf7, 0x01, 0x6e, 0x61, 0x76,
630x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0xb6, 0x00, 0x16, 630x69, 0x67, 0x61, 0x74, 0x65, 0x00, 0x61, 0x6d, 0x6f, 0x6e,
640x32, 0xb6, 0x00, 0x92, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 640x67, 0x73, 0x74, 0x56, 0x01, 0xa1, 0x2e, 0x00, 0x50, 0x72,
650x74, 0x65, 0x72, 0xb8, 0x00, 0x40, 0x68, 0x65, 0x72, 0x65, 650x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x15, 0x00, 0x41, 0x45,
660x93, 0x01, 0x95, 0x6f, 0x6e, 0x6c, 0x79, 0x00, 0x6f, 0x6e, 660x6e, 0x74, 0x65, 0x49, 0x00, 0xc1, 0x00, 0x77, 0x69, 0x6c,
670x65, 0x00, 0x20, 0x00, 0x06, 0x46, 0x00, 0x51, 0x00, 0x66, 670x6c, 0x00, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x83, 0x00,
680x72, 0x6f, 0x6d, 0x83, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 680x14, 0x67, 0x23, 0x00, 0xf2, 0x07, 0x63, 0x75, 0x72, 0x72,
690x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 690x65, 0x6e, 0x74, 0x6c, 0x79, 0x2d, 0x00, 0x68, 0x69, 0x67,
700x79, 0x00, 0x03, 0xc3, 0x01, 0xf1, 0x01, 0x60, 0x54, 0x79, 700x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x4f, 0x00,
710x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0x3a, 0x00, 710x07, 0x4e, 0x00, 0xc2, 0x54, 0x61, 0x62, 0x00, 0x6f, 0x72,
720x00, 0x00, 0x4e, 0x58, 0x02, 0x43, 0x20, 0x6f, 0x66, 0x20, 720x00, 0x53, 0x70, 0x61, 0x63, 0x65, 0x4d, 0x00, 0x40, 0x63,
730xdc, 0x01, 0x33, 0x00, 0x00, 0x43, 0x2f, 0x01, 0x01, 0x2f, 730x79, 0x63, 0x6c, 0x07, 0x02, 0x99, 0x72, 0x6f, 0x75, 0x67,
740x00, 0x31, 0x73, 0x69, 0x7a, 0x66, 0x02, 0x01, 0xfe, 0x01, 740x68, 0x00, 0x61, 0x6c, 0x6c, 0x87, 0x00, 0x43, 0x00, 0x00,
750x60, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x2c, 0x8c, 0x01, 0xa1, 750x28, 0x41, 0x13, 0x00, 0x20, 0x61, 0x63, 0xdd, 0x00, 0xb0,
760x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, 760x73, 0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
770x1a, 0x00, 0x0c, 0x9e, 0x02, 0x04, 0xe9, 0x01, 0xf0, 0x02, 770x64, 0xc2, 0x01, 0x21, 0x73, 0x65, 0x16, 0x00, 0x41, 0x00,
780x32, 0x2e, 0x31, 0xa3, 0x02, 0x01, 0xe4, 0x00, 0xb2, 0x61,
790x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29,
800x80, 0x01, 0x16, 0x32, 0x80, 0x01, 0x92, 0x70, 0x61, 0x72,
810x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x82, 0x01, 0x40, 0x68,
820x65, 0x72, 0x65, 0x5d, 0x02, 0x95, 0x6f, 0x6e, 0x6c, 0x79,
830x00, 0x6f, 0x6e, 0x65, 0x00, 0x20, 0x00, 0x06, 0x46, 0x00,
840x51, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x83, 0x00, 0xe1, 0x60,
850x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27,
860x00, 0x6f, 0x70, 0x79, 0x00, 0x03, 0x8d, 0x02, 0xf1, 0x01,
870x60, 0x54, 0x79, 0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e,
880x75, 0x3a, 0x00, 0x00, 0x00, 0x4e, 0x22, 0x03, 0x43, 0x20,
890x6f, 0x66, 0x20, 0xa6, 0x02, 0x33, 0x00, 0x00, 0x43, 0xf9,
900x01, 0x01, 0x2f, 0x00, 0x31, 0x73, 0x69, 0x7a, 0x30, 0x03,
910x01, 0xeb, 0x00, 0x60, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x2c,
920x56, 0x02, 0x74, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79,
930x54, 0x01, 0x0c, 0x68, 0x03, 0x04, 0xb3, 0x02, 0xf0, 0x02,
780x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x00, 940x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x00,
790x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x00, 950x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x00,
80}; 96};
81 97
82const unsigned short help_text_len = 751; 98const unsigned short help_text_len = 974;
83const unsigned short help_text_words = 138; 99const unsigned short help_text_words = 174;
84const char quick_help_text[] = "Reposition the points so that the lines do not cross."; 100const char quick_help_text[] = "Reposition the points so that the lines do not cross.";
diff --git a/apps/plugins/puzzles/rbcompat.h b/apps/plugins/puzzles/rbcompat.h
index 9069c1e659..f37ac8068e 100644
--- a/apps/plugins/puzzles/rbcompat.h
+++ b/apps/plugins/puzzles/rbcompat.h
@@ -34,6 +34,8 @@ int sscanf_wrapper(const char *ibuf, const char *fmt, ...);
34double atof_wrapper(const char *s); 34double atof_wrapper(const char *s);
35double acos_wrapper(double x); 35double acos_wrapper(double x);
36 36
37#define NO_TGMATH_H
38
37#define acos acos_wrapper 39#define acos acos_wrapper
38#define atan atan_wrapper 40#define atan atan_wrapper
39#define atan2 atan2_wrapper 41#define atan2 atan2_wrapper
diff --git a/apps/plugins/puzzles/resync.sh b/apps/plugins/puzzles/resync.sh
index 76679971a4..384fc79d1f 100755
--- a/apps/plugins/puzzles/resync.sh
+++ b/apps/plugins/puzzles/resync.sh
@@ -19,7 +19,7 @@ then
19fi 19fi
20 20
21echo "=== POTENTIALLY DANGEROUS OPERATION ===" 21echo "=== POTENTIALLY DANGEROUS OPERATION ==="
22echo "Are you sure you want to remove all files in src/?" 22echo "Are you sure you want to remove all files in src/ and help/?"
23echo -n "If so, type \"yes\" in all caps: " 23echo -n "If so, type \"yes\" in all caps: "
24read ans 24read ans
25if [ "YES" == $ans ] 25if [ "YES" == $ans ]
@@ -30,8 +30,9 @@ then
30 rm -rf src 30 rm -rf src
31 echo "[2/5] Copying new sources" 31 echo "[2/5] Copying new sources"
32 mkdir src 32 mkdir src
33 cp -r "$1"/{*.c,*.h,*.R,*.but,LICENCE,README} src 33 cp -r "$1"/{*.c,*.h,*.but,LICENCE,README,CMakeLists.txt} src
34 echo "[3/5] Regenerating help" 34 echo "[3/5] Regenerating help"
35 rm -rf help
35 ./genhelp.sh 36 ./genhelp.sh
36 37
37 echo "[4/5] Staging for commit" 38 echo "[4/5] Staging for commit"
diff --git a/apps/plugins/puzzles/rockbox.c b/apps/plugins/puzzles/rockbox.c
index 263a19f421..c95e8a8356 100644
--- a/apps/plugins/puzzles/rockbox.c
+++ b/apps/plugins/puzzles/rockbox.c
@@ -163,6 +163,11 @@
163 * cases by waiting until a key has been released before we 163 * cases by waiting until a key has been released before we
164 * send the input keystroke(s) to the game. 164 * send the input keystroke(s) to the game.
165 * 165 *
166 * e) Key repeat
167 *
168 * In some games, we would like to send repeated key events to
169 * allow long drags. Currently, this is only used in Untangle.
170 *
166 * 5) Game configuration and preset management 171 * 5) Game configuration and preset management
167 * 172 *
168 * The backend games specify a hierarchy of user-adjustable game 173 * The backend games specify a hierarchy of user-adjustable game
@@ -1211,7 +1216,7 @@ static void zoom_filltriangle(int x1, int y1,
1211} 1216}
1212 1217
1213/* Should probably refactor this */ 1218/* Should probably refactor this */
1214static void rb_draw_poly(void *handle, int *coords, int npoints, 1219static void rb_draw_poly(void *handle, const int *coords, int npoints,
1215 int fillcolor, int outlinecolor) 1220 int fillcolor, int outlinecolor)
1216{ 1221{
1217 if(!zoom_enabled) 1222 if(!zoom_enabled)
@@ -2268,7 +2273,7 @@ static void zoom(void)
2268 zoom_clipl = 0; 2273 zoom_clipl = 0;
2269 zoom_clipr = zoom_w; 2274 zoom_clipr = zoom_w;
2270 2275
2271 midend_size(me, &zoom_w, &zoom_h, true); 2276 midend_size(me, &zoom_w, &zoom_h, true, 1.0);
2272 2277
2273 /* Allocating the framebuffer will mostly likely grab the 2278 /* Allocating the framebuffer will mostly likely grab the
2274 * audiobuffer, which will make impossible to load new fonts, and 2279 * audiobuffer, which will make impossible to load new fonts, and
@@ -2634,10 +2639,10 @@ const char *config_formatter(int sel, void *data, char *buf, size_t len)
2634 return buf; 2639 return buf;
2635} 2640}
2636 2641
2637static bool config_menu(void) 2642static bool config_menu_core(int which)
2638{ 2643{
2639 char *title; 2644 char *title;
2640 config_item *config = midend_get_config(me, CFG_SETTINGS, &title); 2645 config_item *config = midend_get_config(me, which, &title);
2641 2646
2642 rb->lcd_setfont(cur_font = FONT_UI); 2647 rb->lcd_setfont(cur_font = FONT_UI);
2643 2648
@@ -2689,7 +2694,7 @@ static bool config_menu(void)
2689 old_str = dupstr(old.u.string.sval); 2694 old_str = dupstr(old.u.string.sval);
2690 2695
2691 bool freed_str = do_configure_item(config, pos); 2696 bool freed_str = do_configure_item(config, pos);
2692 const char *err = midend_set_config(me, CFG_SETTINGS, config); 2697 const char *err = midend_set_config(me, which, config);
2693 2698
2694 if(err) 2699 if(err)
2695 { 2700 {
@@ -2728,6 +2733,16 @@ done:
2728 return success; 2733 return success;
2729} 2734}
2730 2735
2736static bool config_menu(void)
2737{
2738 return config_menu_core(CFG_SETTINGS);
2739}
2740
2741static bool preferences_menu(void)
2742{
2743 return config_menu_core(CFG_PREFS);
2744}
2745
2731static const char *preset_formatter(int sel, void *data, char *buf, size_t len) 2746static const char *preset_formatter(int sel, void *data, char *buf, size_t len)
2732{ 2747{
2733 struct preset_menu *menu = data; 2748 struct preset_menu *menu = data;
@@ -3108,8 +3123,9 @@ static int pause_menu(void)
3108 "Game Type", // 10 3123 "Game Type", // 10
3109 "Debug Menu", // 11 3124 "Debug Menu", // 11
3110 "Configure Game", // 12 3125 "Configure Game", // 12
3111 "Quit without Saving", // 13 3126 "Preferences", // 13
3112 "Quit"); // 14 3127 "Quit without Saving", // 14
3128 "Quit"); // 15
3113 3129
3114#if defined(FOR_REAL) && defined(DEBUG_MENU) 3130#if defined(FOR_REAL) && defined(DEBUG_MENU)
3115 help_times = 0; 3131 help_times = 0;
@@ -3190,9 +3206,13 @@ static int pause_menu(void)
3190 quit = true; 3206 quit = true;
3191 } 3207 }
3192 break; 3208 break;
3193 case 13: 3209 case 13:
3194 return -2; 3210 preferences_menu();
3211 // do not go straight into game.
3212 break;
3195 case 14: 3213 case 14:
3214 return -2;
3215 case 15:
3196 return -3; 3216 return -3;
3197 default: 3217 default:
3198 break; 3218 break;
@@ -3217,7 +3237,7 @@ static void fix_size(void)
3217 rb->lcd_setfont(cur_font = FONT_UI); 3237 rb->lcd_setfont(cur_font = FONT_UI);
3218 rb->lcd_getstringsize("X", NULL, &h_x); 3238 rb->lcd_getstringsize("X", NULL, &h_x);
3219 h -= h_x; 3239 h -= h_x;
3220 midend_size(me, &w, &h, true); 3240 midend_size(me, &w, &h, true, 1.0);
3221} 3241}
3222 3242
3223static void init_tlsf(void) 3243static void init_tlsf(void)
@@ -3277,32 +3297,39 @@ static bool string_in_list(const char *target, const char **list)
3277static void tune_input(const char *name) 3297static void tune_input(const char *name)
3278{ 3298{
3279 static const char *want_spacebar[] = { 3299 static const char *want_spacebar[] = {
3300 "Black Box",
3301 "Bridges",
3302 "Galaxies",
3303 "Keen",
3280 "Magnets", 3304 "Magnets",
3281 "Map", 3305 "Map",
3282 "Mines", 3306 "Mines",
3283 "Palisade", 3307 "Palisade",
3308 "Pattern",
3284 "Rectangles", 3309 "Rectangles",
3310 "Signpost",
3311 "Singles",
3312 "Solo",
3313 "Tents",
3314 "Towers",
3315 "Unequal",
3316 "Group",
3285 NULL 3317 NULL
3286 }; 3318 };
3287 3319
3288 /* these get a spacebar on long click - you must also add to the 3320 /* these get a spacebar on long click - this implicitly enables
3289 * falling_edge list below! */ 3321 * falling-edge button events (see below)! */
3290 input_settings.want_spacebar = string_in_list(name, want_spacebar); 3322 input_settings.want_spacebar = string_in_list(name, want_spacebar);
3291 3323
3292 static const char *falling_edge[] = { 3324 static const char *falling_edge[] = {
3293 "Inertia", 3325 "Inertia",
3294 "Magnets",
3295 "Map",
3296 "Mines",
3297 "Palisade",
3298 "Rectangles",
3299 NULL 3326 NULL
3300 }; 3327 };
3301 3328
3302 /* wait until a key is released to send an action (useful for 3329 /* wait until a key is released to send an action (useful for
3303 * chording in Inertia; must be enabled if the game needs a 3330 * chording in Inertia; must be enabled if the game needs a
3304 * spacebar) */ 3331 * spacebar) */
3305 input_settings.falling_edge = string_in_list(name, falling_edge); 3332 input_settings.falling_edge = string_in_list(name, falling_edge) || input_settings.want_spacebar;
3306 3333
3307 /* For want_spacebar to work, events must be sent on the falling 3334 /* For want_spacebar to work, events must be sent on the falling
3308 * edge */ 3335 * edge */
@@ -3691,8 +3718,9 @@ static void puzzles_main(void)
3691 "Playback Control", // 4 3718 "Playback Control", // 4
3692 "Game Type", // 5 3719 "Game Type", // 5
3693 "Configure Game", // 6 3720 "Configure Game", // 6
3694 "Quit without Saving", // 7 3721 "Preferences", // 7
3695 "Quit"); // 8 3722 "Quit without Saving", // 8
3723 "Quit"); // 9
3696 3724
3697 bool quit = false; 3725 bool quit = false;
3698 int sel = 0; 3726 int sel = 0;
@@ -3738,11 +3766,14 @@ static void puzzles_main(void)
3738 goto game_loop; 3766 goto game_loop;
3739 } 3767 }
3740 break; 3768 break;
3741 case 8: 3769 case 7:
3770 preferences_menu();
3771 break;
3772 case 9:
3742 if(load_success) 3773 if(load_success)
3743 save_game(); 3774 save_game();
3744 /* fall through */ 3775 /* fall through */
3745 case 7: 3776 case 8:
3746 /* we don't care about freeing anything because tlsf will 3777 /* we don't care about freeing anything because tlsf will
3747 * be wiped out the next time around */ 3778 * be wiped out the next time around */
3748 return; 3779 return;
diff --git a/apps/plugins/puzzles/src/CMakeLists.txt b/apps/plugins/puzzles/src/CMakeLists.txt
new file mode 100644
index 0000000000..4153efc246
--- /dev/null
+++ b/apps/plugins/puzzles/src/CMakeLists.txt
@@ -0,0 +1,287 @@
1cmake_minimum_required(VERSION 3.5)
2
3project(puzzles
4 LANGUAGES C)
5
6include(cmake/setup.cmake)
7
8add_library(core_obj OBJECT
9 combi.c divvy.c drawing.c dsf.c findloop.c grid.c latin.c
10 laydomino.c loopgen.c malloc.c matching.c midend.c misc.c penrose.c
11 penrose-legacy.c ps.c random.c sort.c tdq.c tree234.c version.c
12 ${platform_common_sources})
13add_library(core $<TARGET_OBJECTS:core_obj>)
14add_library(common $<TARGET_OBJECTS:core_obj> hat.c spectre.c)
15
16include_directories(${CMAKE_CURRENT_SOURCE_DIR})
17
18puzzle(blackbox
19 DISPLAYNAME "Black Box"
20 DESCRIPTION "Ball-finding puzzle"
21 OBJECTIVE "Find the hidden balls in the box by bouncing laser beams \
22off them.")
23
24puzzle(bridges
25 DISPLAYNAME "Bridges"
26 DESCRIPTION "Bridge-placing puzzle"
27 OBJECTIVE "Connect all the islands with a network of bridges.")
28
29puzzle(cube
30 DISPLAYNAME "Cube"
31 DESCRIPTION "Rolling cube puzzle"
32 OBJECTIVE "Pick up all the blue squares by rolling the cube over them.")
33
34puzzle(dominosa
35 DISPLAYNAME "Dominosa"
36 DESCRIPTION "Domino tiling puzzle"
37 OBJECTIVE "Tile the rectangle with a full set of dominoes.")
38solver(dominosa)
39
40puzzle(fifteen
41 DISPLAYNAME "Fifteen"
42 DESCRIPTION "Sliding block puzzle"
43 OBJECTIVE "Slide the tiles around to arrange them into order.")
44solver(fifteen)
45
46puzzle(filling
47 DISPLAYNAME "Filling"
48 DESCRIPTION "Polyomino puzzle"
49 OBJECTIVE "Mark every square with the area of its containing region.")
50solver(filling)
51
52puzzle(flip
53 DISPLAYNAME "Flip"
54 DESCRIPTION "Tile inversion puzzle"
55 OBJECTIVE "Flip groups of squares to light them all up at once.")
56
57puzzle(flood
58 DISPLAYNAME "Flood"
59 DESCRIPTION "Flood-filling puzzle"
60 OBJECTIVE "Turn the grid the same colour in as few flood fills as possible.")
61
62puzzle(galaxies
63 DISPLAYNAME "Galaxies"
64 DESCRIPTION "Symmetric polyomino puzzle"
65 OBJECTIVE "Divide the grid into rotationally symmetric regions each \
66centred on a dot.")
67solver(galaxies)
68cliprogram(galaxiespicture galaxies.c
69 COMPILE_DEFINITIONS STANDALONE_PICTURE_GENERATOR)
70guiprogram(galaxieseditor galaxies.c
71 COMPILE_DEFINITIONS EDITOR)
72
73puzzle(guess
74 DISPLAYNAME "Guess"
75 DESCRIPTION "Combination-guessing puzzle"
76 OBJECTIVE "Guess the hidden combination of colours.")
77
78puzzle(inertia
79 DISPLAYNAME "Inertia"
80 DESCRIPTION "Gem-collecting puzzle"
81 OBJECTIVE "Collect all the gems without running into any of the mines.")
82
83puzzle(keen
84 DISPLAYNAME "Keen"
85 DESCRIPTION "Arithmetic Latin square puzzle"
86 OBJECTIVE "Complete the latin square in accordance with the \
87arithmetic clues.")
88solver(keen latin.c)
89
90puzzle(lightup
91 DISPLAYNAME "Light Up"
92 DESCRIPTION "Light-bulb placing puzzle"
93 OBJECTIVE "Place bulbs to light up all the squares.")
94solver(lightup)
95
96puzzle(loopy
97 DISPLAYNAME "Loopy"
98 DESCRIPTION "Loop-drawing puzzle"
99 OBJECTIVE "Draw a single closed loop, given clues about number of \
100adjacent edges.")
101solver(loopy)
102
103puzzle(magnets
104 DISPLAYNAME "Magnets"
105 DESCRIPTION "Magnet-placing puzzle"
106 OBJECTIVE "Place magnets to satisfy the clues and avoid like poles \
107touching.")
108solver(magnets)
109
110puzzle(map
111 DISPLAYNAME "Map"
112 DESCRIPTION "Map-colouring puzzle"
113 OBJECTIVE "Colour the map so that adjacent regions are never the \
114same colour.")
115solver(map)
116
117puzzle(mines
118 DISPLAYNAME "Mines"
119 DESCRIPTION "Mine-finding puzzle"
120 OBJECTIVE "Find all the mines without treading on any of them.")
121cliprogram(mineobfusc mines.c COMPILE_DEFINITIONS STANDALONE_OBFUSCATOR)
122
123puzzle(mosaic
124 DISPLAYNAME "Mosaic"
125 DESCRIPTION "Grid-filling puzzle"
126 OBJECTIVE "Fill in the grid given clues about number of \
127nearby black squares.")
128
129puzzle(net
130 # The Windows Net shouldn't be called 'net.exe', since Windows
131 # already has a reasonably important utility program by that name!
132 WINDOWS_EXE_NAME netgame
133
134 DISPLAYNAME "Net"
135 DESCRIPTION "Network jigsaw puzzle"
136 OBJECTIVE "Rotate each tile to reassemble the network.")
137
138puzzle(netslide
139 DISPLAYNAME "Netslide"
140 DESCRIPTION "Toroidal sliding network puzzle"
141 OBJECTIVE "Slide a row at a time to reassemble the network.")
142
143puzzle(nullgame)
144
145puzzle(palisade
146 DISPLAYNAME "Palisade"
147 DESCRIPTION "Grid-division puzzle"
148 OBJECTIVE "Divide the grid into equal-sized areas in accordance with\
149 the clues.")
150
151puzzle(pattern
152 DISPLAYNAME "Pattern"
153 DESCRIPTION "Pattern puzzle"
154 OBJECTIVE "Fill in the pattern in the grid, given only the lengths \
155of runs of black squares.")
156solver(pattern)
157cliprogram(patternpicture pattern.c
158 COMPILE_DEFINITIONS STANDALONE_PICTURE_GENERATOR)
159
160puzzle(pearl
161 DISPLAYNAME "Pearl"
162 DESCRIPTION "Loop-drawing puzzle"
163 OBJECTIVE "Draw a single closed loop, given clues about corner and \
164straight squares.")
165solver(pearl)
166cliprogram(pearlbench pearl.c COMPILE_DEFINITIONS STANDALONE_SOLVER)
167
168puzzle(pegs
169 DISPLAYNAME "Pegs"
170 DESCRIPTION "Peg solitaire puzzle"
171 OBJECTIVE "Jump pegs over each other to remove all but one.")
172
173puzzle(range
174 DISPLAYNAME "Range"
175 DESCRIPTION "Visible-distance puzzle"
176 OBJECTIVE "Place black squares to limit the visible distance from \
177each numbered cell.")
178
179puzzle(rect
180 DISPLAYNAME "Rectangles"
181 DESCRIPTION "Rectangles puzzle"
182 OBJECTIVE "Divide the grid into rectangles with areas equal to the \
183numbers.")
184
185puzzle(samegame
186 DISPLAYNAME "Same Game"
187 DESCRIPTION "Block-clearing puzzle"
188 OBJECTIVE "Clear the grid by removing touching groups of the same \
189colour squares.")
190
191puzzle(signpost
192 DISPLAYNAME "Signpost"
193 DESCRIPTION "Square-connecting puzzle"
194 OBJECTIVE "Connect the squares into a path following the arrows.")
195solver(signpost)
196
197puzzle(singles
198 DISPLAYNAME "Singles"
199 DESCRIPTION "Number-removing puzzle"
200 OBJECTIVE "Black out the right set of duplicate numbers.")
201solver(singles)
202
203puzzle(sixteen
204 DISPLAYNAME "Sixteen"
205 DESCRIPTION "Toroidal sliding block puzzle"
206 OBJECTIVE "Slide a row at a time to arrange the tiles into order.")
207
208puzzle(slant
209 DISPLAYNAME "Slant"
210 DESCRIPTION "Maze-drawing puzzle"
211 OBJECTIVE "Draw a maze of slanting lines that matches the clues.")
212solver(slant)
213
214puzzle(solo
215 DISPLAYNAME "Solo"
216 DESCRIPTION "Number placement puzzle"
217 OBJECTIVE "Fill in the grid so that each row, column and square \
218block contains one of every digit.")
219solver(solo)
220
221puzzle(tents
222 DISPLAYNAME "Tents"
223 DESCRIPTION "Tent-placing puzzle"
224 OBJECTIVE "Place a tent next to each tree.")
225solver(tents)
226
227puzzle(towers
228 DISPLAYNAME "Towers"
229 DESCRIPTION "Tower-placing Latin square puzzle"
230 OBJECTIVE "Complete the latin square of towers in accordance with \
231the clues.")
232solver(towers latin.c)
233
234puzzle(tracks
235 DISPLAYNAME "Tracks"
236 DESCRIPTION "Path-finding railway track puzzle"
237 OBJECTIVE "Fill in the railway track according to the clues.")
238solver(tracks)
239
240puzzle(twiddle
241 DISPLAYNAME "Twiddle"
242 DESCRIPTION "Rotational sliding block puzzle"
243 OBJECTIVE "Rotate the tiles around themselves to arrange them into order.")
244
245puzzle(undead
246 DISPLAYNAME "Undead"
247 DESCRIPTION "Monster-placing puzzle"
248 OBJECTIVE "Place ghosts, vampires and zombies so that the right \
249numbers of them can be seen in mirrors.")
250
251puzzle(unequal
252 DISPLAYNAME "Unequal"
253 DESCRIPTION "Latin square puzzle"
254 OBJECTIVE "Complete the latin square in accordance with the > signs.")
255solver(unequal latin.c)
256
257puzzle(unruly
258 DISPLAYNAME "Unruly"
259 DESCRIPTION "Black and white grid puzzle"
260 OBJECTIVE "Fill in the black and white grid to avoid runs of three.")
261solver(unruly)
262
263puzzle(untangle
264 DISPLAYNAME "Untangle"
265 DESCRIPTION "Planar graph layout puzzle"
266 OBJECTIVE "Reposition the points so that the lines do not cross.")
267
268add_subdirectory(unfinished)
269add_subdirectory(auxiliary)
270
271if(build_cli_programs)
272 write_generated_games_header()
273 include(CheckFunctionExists)
274 check_function_exists(HF_ITER HAVE_HF_ITER)
275 set(WITH_LIBFUZZER OFF
276 CACHE BOOL "Build fuzzpuzz using Clang's libFuzzer")
277 cliprogram(fuzzpuzz fuzzpuzz.c list.c ${puzzle_sources}
278 COMPILE_DEFINITIONS COMBINED $<$<BOOL:${WITH_LIBFUZZER}>:OMIT_MAIN>
279 $<$<BOOL:${HAVE_HF_ITER}>:HAVE_HF_ITER>)
280 target_include_directories(fuzzpuzz PRIVATE ${generated_include_dir})
281 if(WITH_LIBFUZZER)
282 target_compile_options(fuzzpuzz PRIVATE -fsanitize=fuzzer)
283 set_target_properties(fuzzpuzz PROPERTIES LINK_FLAGS -fsanitize=fuzzer)
284 endif()
285endif()
286
287build_extras()
diff --git a/apps/plugins/puzzles/src/LICENCE b/apps/plugins/puzzles/src/LICENCE
index 85f67ba795..d33dae80af 100644
--- a/apps/plugins/puzzles/src/LICENCE
+++ b/apps/plugins/puzzles/src/LICENCE
@@ -1,9 +1,9 @@
1This software is copyright (c) 2004-2014 Simon Tatham. 1This software is copyright (c) 2004-2024 Simon Tatham.
2 2
3Portions copyright Richard Boulton, James Harvey, Mike Pinna, Jonas 3Portions copyright Richard Boulton, James Harvey, Mike Pinna, Jonas
4Kölker, Dariusz Olszewski, Michael Schierl, Lambros Lambrou, Bernd 4Kölker, Dariusz Olszewski, Michael Schierl, Lambros Lambrou, Bernd
5Schmidt, Steffen Bauer, Lennard Sprong, Rogier Goossens, Michael 5Schmidt, Steffen Bauer, Lennard Sprong, Rogier Goossens, Michael
6Quevillon and Asher Gordon. 6Quevillon, Asher Gordon, Didi Kohen and Ben Harris.
7 7
8Permission is hereby granted, free of charge, to any person 8Permission is hereby granted, free of charge, to any person
9obtaining a copy of this software and associated documentation files 9obtaining a copy of this software and associated documentation files
diff --git a/apps/plugins/puzzles/src/README b/apps/plugins/puzzles/src/README
index 00830126e8..dd76edc19b 100644
--- a/apps/plugins/puzzles/src/README
+++ b/apps/plugins/puzzles/src/README
@@ -2,48 +2,12 @@ This is the README accompanying the source code to Simon Tatham's
2puzzle collection. The collection's web site is at 2puzzle collection. The collection's web site is at
3<https://www.chiark.greenend.org.uk/~sgtatham/puzzles/>. 3<https://www.chiark.greenend.org.uk/~sgtatham/puzzles/>.
4 4
5If you've obtained the source code by downloading a .tar.gz archive 5The puzzle collection is built using CMake <https://cmake.org/>. To
6from the Puzzles web site, you should find several Makefiles in the 6compile in the simplest way (on any of Linux, Windows or Mac), run
7source code. However, if you've checked the source code out from the 7these commands in the source directory:
8Puzzles git repository, you won't find the Makefiles: they're
9automatically generated by `mkfiles.pl', so run that to create them.
10 8
11The Makefiles include: 9 cmake .
12 10 cmake --build .
13 - `Makefile.am', together with the static `configure.ac', is intended
14 as input to automake. Run `mkauto.sh' to turn these into a
15 configure script and Makefile.in, after which you can then run
16 `./configure' to create an actual Unix Makefile.
17
18 - `Makefile.vc' should work under MS Visual C++ on Windows. Run
19 'nmake /f Makefile.vc' in a Visual Studio command prompt.
20
21 - `Makefile.cyg' should work under Cygwin / MinGW. With appropriate
22 tweaks and setting of TOOLPATH, it should work for both compiling
23 on Windows and cross-compiling on Unix.
24
25 - `Makefile.osx' should work under Mac OS X, provided the Xcode
26 tools are installed. It builds a single monolithic OS X
27 application capable of running any of the puzzles, or even more
28 than one of them at a time.
29
30 - `Makefile.wce' should work under MS eMbedded Visual C++ on
31 Windows and the Pocket PC SDK; it builds Pocket PC binaries.
32
33Many of these Makefiles build a program called `nullgame' in
34addition to the actual game binaries. This program doesn't do
35anything; it's just a template for people to start from when adding
36a new game to the collection, and it's compiled every time to ensure
37that it _does_ compile and link successfully (because otherwise it
38wouldn't be much use as a template). Once it's built, you can run it
39if you really want to (but it's very boring), and then you should
40ignore it.
41
42DO NOT EDIT THE MAKEFILES DIRECTLY, if you plan to send any changes
43back to the maintainer. The makefiles are generated automatically by
44the Perl script `mkfiles.pl' from the file `Recipe' and the various
45.R files. If you need to change the makefiles as part of a patch,
46you should change Recipe, *.R, and/or mkfiles.pl.
47 11
48The manual is provided in Windows Help format for the Windows build; 12The manual is provided in Windows Help format for the Windows build;
49in text format for anyone who needs it; and in HTML for the Mac OS X 13in text format for anyone who needs it; and in HTML for the Mac OS X
diff --git a/apps/plugins/puzzles/src/blackbox.R b/apps/plugins/puzzles/src/blackbox.R
deleted file mode 100644
index 116225206d..0000000000
--- a/apps/plugins/puzzles/src/blackbox.R
+++ /dev/null
@@ -1,19 +0,0 @@
1# -*- makefile -*-
2
3blackbox : [X] GTK COMMON blackbox blackbox-icon|no-icon
4
5blackbox : [G] WINDOWS COMMON blackbox blackbox.res|noicon.res
6
7ALL += blackbox[COMBINED]
8
9!begin am gtk
10GAMES += blackbox
11!end
12
13!begin >list.c
14 A(blackbox) \
15!end
16
17!begin >gamedesc.txt
18blackbox:blackbox.exe:Black Box:Ball-finding puzzle:Find the hidden balls in the box by bouncing laser beams off them.
19!end
diff --git a/apps/plugins/puzzles/src/blackbox.c b/apps/plugins/puzzles/src/blackbox.c
index a9c1f88261..ab8e382d0a 100644
--- a/apps/plugins/puzzles/src/blackbox.c
+++ b/apps/plugins/puzzles/src/blackbox.c
@@ -7,7 +7,11 @@
7#include <string.h> 7#include <string.h>
8#include <assert.h> 8#include <assert.h>
9#include <ctype.h> 9#include <ctype.h>
10#include <math.h> 10#ifdef NO_TGMATH_H
11# include <math.h>
12#else
13# include <tgmath.h>
14#endif
11 15
12#include "puzzles.h" 16#include "puzzles.h"
13 17
@@ -192,12 +196,14 @@ static const char *validate_params(const game_params *params, bool full)
192 * types, and could be worked around if required. */ 196 * types, and could be worked around if required. */
193 if (params->w > 255 || params->h > 255) 197 if (params->w > 255 || params->h > 255)
194 return "Widths and heights greater than 255 are not supported"; 198 return "Widths and heights greater than 255 are not supported";
199 if (params->minballs < 0)
200 return "Negative number of balls";
201 if (params->minballs < 1)
202 return "Number of balls must be at least one";
195 if (params->minballs > params->maxballs) 203 if (params->minballs > params->maxballs)
196 return "Minimum number of balls may not be greater than maximum"; 204 return "Minimum number of balls may not be greater than maximum";
197 if (params->minballs >= params->w * params->h) 205 if (params->minballs >= params->w * params->h)
198 return "Too many balls to fit in grid"; 206 return "Too many balls to fit in grid";
199 if (params->minballs < 1)
200 return "Number of balls must be at least one";
201 return NULL; 207 return NULL;
202} 208}
203 209
@@ -307,7 +313,7 @@ struct game_state {
307 313
308#define GRID(s,x,y) ((s)->grid[(y)*((s)->w+2) + (x)]) 314#define GRID(s,x,y) ((s)->grid[(y)*((s)->w+2) + (x)])
309 315
310#define RANGECHECK(s,x) ((x) >= 0 && (x) <= (s)->nlasers) 316#define RANGECHECK(s,x) ((x) >= 0 && (x) < (s)->nlasers)
311 317
312/* specify numbers because they must match array indexes. */ 318/* specify numbers because they must match array indexes. */
313enum { DIR_UP = 0, DIR_RIGHT = 1, DIR_DOWN = 2, DIR_LEFT = 3 }; 319enum { DIR_UP = 0, DIR_RIGHT = 1, DIR_DOWN = 2, DIR_LEFT = 3 };
@@ -468,16 +474,6 @@ static char *solve_game(const game_state *state, const game_state *currstate,
468 return dupstr("S"); 474 return dupstr("S");
469} 475}
470 476
471static bool game_can_format_as_text_now(const game_params *params)
472{
473 return true;
474}
475
476static char *game_text_format(const game_state *state)
477{
478 return NULL;
479}
480
481struct game_ui { 477struct game_ui {
482 int flash_laserno; 478 int flash_laserno;
483 int errors; 479 int errors;
@@ -495,7 +491,7 @@ static game_ui *new_ui(const game_state *state)
495 ui->newmove = false; 491 ui->newmove = false;
496 492
497 ui->cur_x = ui->cur_y = 1; 493 ui->cur_x = ui->cur_y = 1;
498 ui->cur_visible = false; 494 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
499 495
500 ui->flash_laser = 0; 496 ui->flash_laser = 0;
501 497
@@ -517,7 +513,8 @@ static char *encode_ui(const game_ui *ui)
517 return dupstr(buf); 513 return dupstr(buf);
518} 514}
519 515
520static void decode_ui(game_ui *ui, const char *encoding) 516static void decode_ui(game_ui *ui, const char *encoding,
517 const game_state *state)
521{ 518{
522 sscanf(encoding, "E%d", &ui->errors); 519 sscanf(encoding, "E%d", &ui->errors);
523} 520}
@@ -534,6 +531,41 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
534 ui->newmove = false; 531 ui->newmove = false;
535} 532}
536 533
534static const char *current_key_label(const game_ui *ui,
535 const game_state *state, int button)
536{
537 if (IS_CURSOR_SELECT(button) && ui->cur_visible && !state->reveal) {
538 int gx = ui->cur_x, gy = ui->cur_y, rangeno = -1;
539 if (gx == 0 && gy == 0 && button == CURSOR_SELECT) return "Check";
540 if (gx >= 1 && gx <= state->w && gy >= 1 && gy <= state->h) {
541 /* Cursor somewhere in the arena. */
542 if (button == CURSOR_SELECT && !(GRID(state, gx,gy) & BALL_LOCK))
543 return (GRID(state, gx, gy) & BALL_GUESS) ? "Clear" : "Ball";
544 if (button == CURSOR_SELECT2)
545 return (GRID(state, gx, gy) & BALL_LOCK) ? "Unlock" : "Lock";
546 }
547 if (grid2range(state, gx, gy, &rangeno)) {
548 if (button == CURSOR_SELECT &&
549 state->exits[rangeno] == LASER_EMPTY)
550 return "Fire";
551 if (button == CURSOR_SELECT2) {
552 int n = 0;
553 /* Row or column lock or unlock. */
554 if (gy == 0 || gy > state->h) { /* Column lock */
555 for (gy = 1; gy <= state->h; gy++)
556 n += !!(GRID(state, gx, gy) & BALL_LOCK);
557 return n > state->h/2 ? "Unlock" : "Lock";
558 } else { /* Row lock */
559 for (gx = 1; gx <= state->w; gx++)
560 n += !!(GRID(state, gx, gy) & BALL_LOCK);
561 return n > state->w/2 ? "Unlock" : "Lock";
562 }
563 }
564 }
565 }
566 return "";
567}
568
537#define OFFSET(gx,gy,o) do { \ 569#define OFFSET(gx,gy,o) do { \
538 int off = (4 + (o) % 4) % 4; \ 570 int off = (4 + (o) % 4) % 4; \
539 (gx) += offsets[off].x; \ 571 (gx) += offsets[off].x; \
@@ -875,7 +907,7 @@ done:
875#define TILE_SIZE (ds->tilesize) 907#define TILE_SIZE (ds->tilesize)
876 908
877#define TODRAW(x) ((TILE_SIZE * (x)) + (TILE_SIZE / 2)) 909#define TODRAW(x) ((TILE_SIZE * (x)) + (TILE_SIZE / 2))
878#define FROMDRAW(x) (((x) - (TILE_SIZE / 2)) / TILE_SIZE) 910#define FROMDRAW(x) (((x) + (TILE_SIZE / 2)) / TILE_SIZE - 1)
879 911
880#define CAN_REVEAL(state) ((state)->nguesses >= (state)->minballs && \ 912#define CAN_REVEAL(state) ((state)->nguesses >= (state)->minballs && \
881 (state)->nguesses <= (state)->maxballs && \ 913 (state)->nguesses <= (state)->maxballs && \
@@ -900,7 +932,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
900 if (IS_CURSOR_MOVE(button)) { 932 if (IS_CURSOR_MOVE(button)) {
901 int cx = ui->cur_x, cy = ui->cur_y; 933 int cx = ui->cur_x, cy = ui->cur_y;
902 934
903 move_cursor(button, &cx, &cy, state->w+2, state->h+2, false); 935 move_cursor(button, &cx, &cy, state->w+2, state->h+2, false, NULL);
904 if ((cx == 0 && cy == 0 && !CAN_REVEAL(state)) || 936 if ((cx == 0 && cy == 0 && !CAN_REVEAL(state)) ||
905 (cx == 0 && cy == state->h+1) || 937 (cx == 0 && cy == state->h+1) ||
906 (cx == state->w+1 && cy == 0) || 938 (cx == state->w+1 && cy == 0) ||
@@ -909,7 +941,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
909 ui->cur_x = cx; 941 ui->cur_x = cx;
910 ui->cur_y = cy; 942 ui->cur_y = cy;
911 ui->cur_visible = true; 943 ui->cur_visible = true;
912 return UI_UPDATE; 944 return MOVE_UI_UPDATE;
913 } 945 }
914 946
915 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { 947 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
@@ -919,7 +951,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
919 wouldflash = 1; 951 wouldflash = 1;
920 } else if (button == LEFT_RELEASE) { 952 } else if (button == LEFT_RELEASE) {
921 ui->flash_laser = 0; 953 ui->flash_laser = 0;
922 return UI_UPDATE; 954 return MOVE_UI_UPDATE;
923 } else if (IS_CURSOR_SELECT(button)) { 955 } else if (IS_CURSOR_SELECT(button)) {
924 if (ui->cur_visible) { 956 if (ui->cur_visible) {
925 gx = ui->cur_x; 957 gx = ui->cur_x;
@@ -928,7 +960,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
928 wouldflash = 2; 960 wouldflash = 2;
929 } else { 961 } else {
930 ui->cur_visible = true; 962 ui->cur_visible = true;
931 return UI_UPDATE; 963 return MOVE_UI_UPDATE;
932 } 964 }
933 /* Fix up 'button' for the below logic. */ 965 /* Fix up 'button' for the below logic. */
934 if (button == CURSOR_SELECT2) button = RIGHT_BUTTON; 966 if (button == CURSOR_SELECT2) button = RIGHT_BUTTON;
@@ -977,9 +1009,9 @@ static char *interpret_move(const game_state *state, game_ui *ui,
977 return nullret; 1009 return nullret;
978 ui->flash_laserno = rangeno; 1010 ui->flash_laserno = rangeno;
979 ui->flash_laser = wouldflash; 1011 ui->flash_laser = wouldflash;
980 nullret = UI_UPDATE; 1012 nullret = MOVE_UI_UPDATE;
981 if (state->exits[rangeno] != LASER_EMPTY) 1013 if (state->exits[rangeno] != LASER_EMPTY)
982 return UI_UPDATE; 1014 return MOVE_UI_UPDATE;
983 sprintf(buf, "F%d", rangeno); 1015 sprintf(buf, "F%d", rangeno);
984 break; 1016 break;
985 1017
@@ -1034,10 +1066,10 @@ static game_state *execute_move(const game_state *from, const char *move)
1034 1066
1035 case 'F': 1067 case 'F':
1036 sscanf(move+1, "%d", &rangeno); 1068 sscanf(move+1, "%d", &rangeno);
1037 if (ret->exits[rangeno] != LASER_EMPTY)
1038 goto badmove;
1039 if (!RANGECHECK(ret, rangeno)) 1069 if (!RANGECHECK(ret, rangeno))
1040 goto badmove; 1070 goto badmove;
1071 if (ret->exits[rangeno] != LASER_EMPTY)
1072 goto badmove;
1041 fire_laser(ret, rangeno); 1073 fire_laser(ret, rangeno);
1042 break; 1074 break;
1043 1075
@@ -1119,7 +1151,7 @@ static void game_get_cursor_location(const game_ui *ui,
1119 */ 1151 */
1120 1152
1121static void game_compute_size(const game_params *params, int tilesize, 1153static void game_compute_size(const game_params *params, int tilesize,
1122 int *x, int *y) 1154 const game_ui *ui, int *x, int *y)
1123{ 1155{
1124 /* Border is ts/2, to make things easier. 1156 /* Border is ts/2, to make things easier.
1125 * Thus we have (width) + 2 (firing range*2) + 1 (border*2) tiles 1157 * Thus we have (width) + 2 (firing range*2) + 1 (border*2) tiles
@@ -1379,10 +1411,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1379 int x0 = TODRAW(0)-1, y0 = TODRAW(0)-1; 1411 int x0 = TODRAW(0)-1, y0 = TODRAW(0)-1;
1380 int x1 = TODRAW(state->w+2), y1 = TODRAW(state->h+2); 1412 int x1 = TODRAW(state->w+2), y1 = TODRAW(state->h+2);
1381 1413
1382 draw_rect(dr, 0, 0,
1383 TILE_SIZE * (state->w+3), TILE_SIZE * (state->h+3),
1384 COL_BACKGROUND);
1385
1386 /* clockwise around the outline starting at pt behind (1,1). */ 1414 /* clockwise around the outline starting at pt behind (1,1). */
1387 draw_line(dr, x0+ts, y0+ts, x0+ts, y0, COL_HIGHLIGHT); 1415 draw_line(dr, x0+ts, y0+ts, x0+ts, y0, COL_HIGHLIGHT);
1388 draw_line(dr, x0+ts, y0, x1-ts, y0, COL_HIGHLIGHT); 1416 draw_line(dr, x0+ts, y0, x1-ts, y0, COL_HIGHLIGHT);
@@ -1429,14 +1457,14 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1429 int outline = (ui->cur_visible && ui->cur_x == 0 && ui->cur_y == 0) 1457 int outline = (ui->cur_visible && ui->cur_x == 0 && ui->cur_y == 0)
1430 ? COL_CURSOR : COL_BALL; 1458 ? COL_CURSOR : COL_BALL;
1431 clip(dr, TODRAW(0)-1, TODRAW(0)-1, TILE_SIZE+1, TILE_SIZE+1); 1459 clip(dr, TODRAW(0)-1, TODRAW(0)-1, TILE_SIZE+1, TILE_SIZE+1);
1432 draw_circle(dr, TODRAW(0) + ds->crad, TODRAW(0) + ds->crad, ds->crad, 1460 draw_circle(dr, TODRAW(0) + ds->crad-1, TODRAW(0) + ds->crad-1, ds->crad-1,
1433 outline, outline); 1461 outline, outline);
1434 draw_circle(dr, TODRAW(0) + ds->crad, TODRAW(0) + ds->crad, ds->crad-2, 1462 draw_circle(dr, TODRAW(0) + ds->crad-1, TODRAW(0) + ds->crad-1, ds->crad-3,
1435 COL_BUTTON, COL_BUTTON); 1463 COL_BUTTON, COL_BUTTON);
1436 unclip(dr); 1464 unclip(dr);
1437 } else { 1465 } else {
1438 draw_rect(dr, TODRAW(0)-1, TODRAW(0)-1, 1466 draw_rect(dr, TODRAW(0)-1, TODRAW(0)-1,
1439 TILE_SIZE+1, TILE_SIZE+1, COL_BACKGROUND); 1467 TILE_SIZE, TILE_SIZE, COL_BACKGROUND);
1440 } 1468 }
1441 draw_update(dr, TODRAW(0), TODRAW(0), TILE_SIZE, TILE_SIZE); 1469 draw_update(dr, TODRAW(0), TODRAW(0), TILE_SIZE, TILE_SIZE);
1442 ds->reveal = state->reveal; 1470 ds->reveal = state->reveal;
@@ -1509,19 +1537,6 @@ static int game_status(const game_state *state)
1509 return 0; 1537 return 0;
1510} 1538}
1511 1539
1512static bool game_timing_state(const game_state *state, game_ui *ui)
1513{
1514 return true;
1515}
1516
1517static void game_print_size(const game_params *params, float *x, float *y)
1518{
1519}
1520
1521static void game_print(drawing *dr, const game_state *state, int tilesize)
1522{
1523}
1524
1525#ifdef COMBINED 1540#ifdef COMBINED
1526#define thegame blackbox 1541#define thegame blackbox
1527#endif 1542#endif
@@ -1542,13 +1557,15 @@ const struct game thegame = {
1542 dup_game, 1557 dup_game,
1543 free_game, 1558 free_game,
1544 true, solve_game, 1559 true, solve_game,
1545 false, game_can_format_as_text_now, game_text_format, 1560 false, NULL, NULL, /* can_format_as_text_now, text_format */
1561 NULL, NULL, /* get_prefs, set_prefs */
1546 new_ui, 1562 new_ui,
1547 free_ui, 1563 free_ui,
1548 encode_ui, 1564 encode_ui,
1549 decode_ui, 1565 decode_ui,
1550 NULL, /* game_request_keys */ 1566 NULL, /* game_request_keys */
1551 game_changed_state, 1567 game_changed_state,
1568 current_key_label,
1552 interpret_move, 1569 interpret_move,
1553 execute_move, 1570 execute_move,
1554 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 1571 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -1560,9 +1577,9 @@ const struct game thegame = {
1560 game_flash_length, 1577 game_flash_length,
1561 game_get_cursor_location, 1578 game_get_cursor_location,
1562 game_status, 1579 game_status,
1563 false, false, game_print_size, game_print, 1580 false, false, NULL, NULL, /* print_size, print */
1564 true, /* wants_statusbar */ 1581 true, /* wants_statusbar */
1565 false, game_timing_state, 1582 false, NULL, /* timing_state */
1566 REQUIRE_RBUTTON, /* flags */ 1583 REQUIRE_RBUTTON, /* flags */
1567}; 1584};
1568 1585
diff --git a/apps/plugins/puzzles/src/bridges.R b/apps/plugins/puzzles/src/bridges.R
deleted file mode 100644
index 75df309152..0000000000
--- a/apps/plugins/puzzles/src/bridges.R
+++ /dev/null
@@ -1,21 +0,0 @@
1# -*- makefile -*-
2
3BRIDGES_EXTRA = dsf findloop
4
5bridges : [X] GTK COMMON bridges BRIDGES_EXTRA bridges-icon|no-icon
6
7bridges : [G] WINDOWS COMMON bridges BRIDGES_EXTRA bridges.res|noicon.res
8
9ALL += bridges[COMBINED] BRIDGES_EXTRA
10
11!begin am gtk
12GAMES += bridges
13!end
14
15!begin >list.c
16 A(bridges) \
17!end
18
19!begin >gamedesc.txt
20bridges:bridges.exe:Bridges:Bridge-placing puzzle:Connect all the islands with a network of bridges.
21!end
diff --git a/apps/plugins/puzzles/src/bridges.c b/apps/plugins/puzzles/src/bridges.c
index 83086c9761..7e87764d6d 100644
--- a/apps/plugins/puzzles/src/bridges.c
+++ b/apps/plugins/puzzles/src/bridges.c
@@ -72,11 +72,15 @@
72#include <string.h> 72#include <string.h>
73#include <assert.h> 73#include <assert.h>
74#include <ctype.h> 74#include <ctype.h>
75#include <math.h> 75#include <limits.h>
76#ifdef NO_TGMATH_H
77# include <math.h>
78#else
79# include <tgmath.h>
80#endif
76 81
77#include "puzzles.h" 82#include "puzzles.h"
78 83
79/* Turn this on for hints about which lines are considered possibilities. */
80#undef DRAW_GRID 84#undef DRAW_GRID
81 85
82/* --- structures for params, state, etc. --- */ 86/* --- structures for params, state, etc. --- */
@@ -134,8 +138,8 @@ struct game_params {
134typedef unsigned int grid_type; /* change me later if we invent > 16 bits of flags. */ 138typedef unsigned int grid_type; /* change me later if we invent > 16 bits of flags. */
135 139
136struct solver_state { 140struct solver_state {
137 int *dsf, *comptspaces; 141 DSF *dsf, *tmpdsf;
138 int *tmpdsf, *tmpcompspaces; 142 int *comptspaces, *tmpcompspaces;
139 int refcount; 143 int refcount;
140}; 144};
141 145
@@ -183,7 +187,7 @@ struct game_state {
183 187
184#define GRIDCOUNT(s,x,y,f) ((GRID(s,x,y) & (f)) ? (INDEX(s,lines,x,y)) : 0) 188#define GRIDCOUNT(s,x,y,f) ((GRID(s,x,y) & (f)) ? (INDEX(s,lines,x,y)) : 0)
185 189
186#define WITHIN2(x,min,max) ((x) >= (min) && (x) < (max)) 190#define WITHIN2(x,min,max) ((x) >= (min) && (x) <= (max))
187#define WITHIN(x,min,max) ((min) > (max) ? \ 191#define WITHIN(x,min,max) ((min) > (max) ? \
188 WITHIN2(x,max,min) : WITHIN2(x,min,max)) 192 WITHIN2(x,max,min) : WITHIN2(x,min,max))
189 193
@@ -803,6 +807,8 @@ static const char *validate_params(const game_params *params, bool full)
803{ 807{
804 if (params->w < 3 || params->h < 3) 808 if (params->w < 3 || params->h < 3)
805 return "Width and height must be at least 3"; 809 return "Width and height must be at least 3";
810 if (params->w > INT_MAX / params->h)
811 return "Width times height must not be unreasonably large";
806 if (params->maxb < 1 || params->maxb > MAX_BRIDGES) 812 if (params->maxb < 1 || params->maxb > MAX_BRIDGES)
807 return "Too many bridges."; 813 return "Too many bridges.";
808 if (full) { 814 if (full) {
@@ -1133,13 +1139,13 @@ static bool map_hasloops(game_state *state, bool mark)
1133 1139
1134static void map_group(game_state *state) 1140static void map_group(game_state *state)
1135{ 1141{
1136 int i, wh = state->w*state->h, d1, d2; 1142 int i, d1, d2;
1137 int x, y, x2, y2; 1143 int x, y, x2, y2;
1138 int *dsf = state->solver->dsf; 1144 DSF *dsf = state->solver->dsf;
1139 struct island *is, *is_join; 1145 struct island *is, *is_join;
1140 1146
1141 /* Initialise dsf. */ 1147 /* Initialise dsf. */
1142 dsf_init(dsf, wh); 1148 dsf_reinit(dsf);
1143 1149
1144 /* For each island, find connected islands right or down 1150 /* For each island, find connected islands right or down
1145 * and merge the dsf for the island squares as well as the 1151 * and merge the dsf for the island squares as well as the
@@ -1160,7 +1166,7 @@ static void map_group(game_state *state)
1160 if (!is_join) continue; 1166 if (!is_join) continue;
1161 1167
1162 d2 = DINDEX(is_join->x, is_join->y); 1168 d2 = DINDEX(is_join->x, is_join->y);
1163 if (dsf_canonify(dsf,d1) == dsf_canonify(dsf,d2)) { 1169 if (dsf_equivalent(dsf, d1, d2)) {
1164 ; /* we have a loop. See comment in map_hasloops. */ 1170 ; /* we have a loop. See comment in map_hasloops. */
1165 /* However, we still want to merge all squares joining 1171 /* However, we still want to merge all squares joining
1166 * this side-that-makes-a-loop. */ 1172 * this side-that-makes-a-loop. */
@@ -1180,7 +1186,8 @@ static void map_group(game_state *state)
1180static bool map_group_check(game_state *state, int canon, bool warn, 1186static bool map_group_check(game_state *state, int canon, bool warn,
1181 int *nislands_r) 1187 int *nislands_r)
1182{ 1188{
1183 int *dsf = state->solver->dsf, nislands = 0; 1189 DSF *dsf = state->solver->dsf;
1190 int nislands = 0;
1184 int x, y, i; 1191 int x, y, i;
1185 bool allfull = true; 1192 bool allfull = true;
1186 struct island *is; 1193 struct island *is;
@@ -1212,7 +1219,8 @@ static bool map_group_check(game_state *state, int canon, bool warn,
1212 1219
1213static bool map_group_full(game_state *state, int *ngroups_r) 1220static bool map_group_full(game_state *state, int *ngroups_r)
1214{ 1221{
1215 int *dsf = state->solver->dsf, ngroups = 0; 1222 DSF *dsf = state->solver->dsf;
1223 int ngroups = 0;
1216 int i; 1224 int i;
1217 bool anyfull = false; 1225 bool anyfull = false;
1218 struct island *is; 1226 struct island *is;
@@ -1267,7 +1275,8 @@ static void map_clear(game_state *state)
1267static void solve_join(struct island *is, int direction, int n, bool is_max) 1275static void solve_join(struct island *is, int direction, int n, bool is_max)
1268{ 1276{
1269 struct island *is_orth; 1277 struct island *is_orth;
1270 int d1, d2, *dsf = is->state->solver->dsf; 1278 int d1, d2;
1279 DSF *dsf = is->state->solver->dsf;
1271 game_state *state = is->state; /* for DINDEX */ 1280 game_state *state = is->state; /* for DINDEX */
1272 1281
1273 is_orth = INDEX(is->state, gridi, 1282 is_orth = INDEX(is->state, gridi,
@@ -1281,7 +1290,7 @@ static void solve_join(struct island *is, int direction, int n, bool is_max)
1281 if (n > 0 && !is_max) { 1290 if (n > 0 && !is_max) {
1282 d1 = DINDEX(is->x, is->y); 1291 d1 = DINDEX(is->x, is->y);
1283 d2 = DINDEX(is_orth->x, is_orth->y); 1292 d2 = DINDEX(is_orth->x, is_orth->y);
1284 if (dsf_canonify(dsf, d1) != dsf_canonify(dsf, d2)) 1293 if (!dsf_equivalent(dsf, d1, d2))
1285 dsf_merge(dsf, d1, d2); 1294 dsf_merge(dsf, d1, d2);
1286 } 1295 }
1287} 1296}
@@ -1382,7 +1391,8 @@ static bool solve_island_stage1(struct island *is, bool *didsth_r)
1382static bool solve_island_checkloop(struct island *is, int direction) 1391static bool solve_island_checkloop(struct island *is, int direction)
1383{ 1392{
1384 struct island *is_orth; 1393 struct island *is_orth;
1385 int *dsf = is->state->solver->dsf, d1, d2; 1394 DSF *dsf = is->state->solver->dsf;
1395 int d1, d2;
1386 game_state *state = is->state; 1396 game_state *state = is->state;
1387 1397
1388 if (is->state->allowloops) 1398 if (is->state->allowloops)
@@ -1399,7 +1409,7 @@ static bool solve_island_checkloop(struct island *is, int direction)
1399 1409
1400 d1 = DINDEX(is->x, is->y); 1410 d1 = DINDEX(is->x, is->y);
1401 d2 = DINDEX(is_orth->x, is_orth->y); 1411 d2 = DINDEX(is_orth->x, is_orth->y);
1402 if (dsf_canonify(dsf, d1) == dsf_canonify(dsf, d2)) { 1412 if (dsf_equivalent(dsf, d1, d2)) {
1403 /* two islands are connected already; don't join them. */ 1413 /* two islands are connected already; don't join them. */
1404 return true; 1414 return true;
1405 } 1415 }
@@ -1457,7 +1467,8 @@ static bool solve_island_stage2(struct island *is, bool *didsth_r)
1457static bool solve_island_subgroup(struct island *is, int direction) 1467static bool solve_island_subgroup(struct island *is, int direction)
1458{ 1468{
1459 struct island *is_join; 1469 struct island *is_join;
1460 int nislands, *dsf = is->state->solver->dsf; 1470 int nislands;
1471 DSF *dsf = is->state->solver->dsf;
1461 game_state *state = is->state; 1472 game_state *state = is->state;
1462 1473
1463 debug(("..checking subgroups.\n")); 1474 debug(("..checking subgroups.\n"));
@@ -1520,7 +1531,6 @@ static bool solve_island_stage3(struct island *is, bool *didsth_r)
1520{ 1531{
1521 int i, n, x, y, missing, spc, curr, maxb; 1532 int i, n, x, y, missing, spc, curr, maxb;
1522 bool didsth = false; 1533 bool didsth = false;
1523 int wh = is->state->w * is->state->h;
1524 struct solver_state *ss = is->state->solver; 1534 struct solver_state *ss = is->state->solver;
1525 1535
1526 assert(didsth_r); 1536 assert(didsth_r);
@@ -1544,7 +1554,7 @@ static bool solve_island_stage3(struct island *is, bool *didsth_r)
1544 maxb = -1; 1554 maxb = -1;
1545 /* We have to squirrel the dsf away and restore it afterwards; 1555 /* We have to squirrel the dsf away and restore it afterwards;
1546 * it is additive only, and can't be removed from. */ 1556 * it is additive only, and can't be removed from. */
1547 memcpy(ss->tmpdsf, ss->dsf, wh*sizeof(int)); 1557 dsf_copy(ss->tmpdsf, ss->dsf);
1548 for (n = curr+1; n <= curr+spc; n++) { 1558 for (n = curr+1; n <= curr+spc; n++) {
1549 solve_join(is, i, n, false); 1559 solve_join(is, i, n, false);
1550 map_update_possibles(is->state); 1560 map_update_possibles(is->state);
@@ -1560,7 +1570,7 @@ static bool solve_island_stage3(struct island *is, bool *didsth_r)
1560 } 1570 }
1561 } 1571 }
1562 solve_join(is, i, curr, false); /* put back to before. */ 1572 solve_join(is, i, curr, false); /* put back to before. */
1563 memcpy(ss->dsf, ss->tmpdsf, wh*sizeof(int)); 1573 dsf_copy(ss->dsf, ss->tmpdsf);
1564 1574
1565 if (maxb != -1) { 1575 if (maxb != -1) {
1566 /*debug_state(is->state);*/ 1576 /*debug_state(is->state);*/
@@ -1629,7 +1639,7 @@ static bool solve_island_stage3(struct island *is, bool *didsth_r)
1629 is->adj.points[j].dx ? G_LINEH : G_LINEV); 1639 is->adj.points[j].dx ? G_LINEH : G_LINEV);
1630 if (before[i] != 0) continue; /* this idea is pointless otherwise */ 1640 if (before[i] != 0) continue; /* this idea is pointless otherwise */
1631 1641
1632 memcpy(ss->tmpdsf, ss->dsf, wh*sizeof(int)); 1642 dsf_copy(ss->tmpdsf, ss->dsf);
1633 1643
1634 for (j = 0; j < is->adj.npoints; j++) { 1644 for (j = 0; j < is->adj.npoints; j++) {
1635 spc = island_adjspace(is, true, missing, j); 1645 spc = island_adjspace(is, true, missing, j);
@@ -1644,7 +1654,7 @@ static bool solve_island_stage3(struct island *is, bool *didsth_r)
1644 1654
1645 for (j = 0; j < is->adj.npoints; j++) 1655 for (j = 0; j < is->adj.npoints; j++)
1646 solve_join(is, j, before[j], false); 1656 solve_join(is, j, before[j], false);
1647 memcpy(ss->dsf, ss->tmpdsf, wh*sizeof(int)); 1657 dsf_copy(ss->dsf, ss->tmpdsf);
1648 1658
1649 if (got) { 1659 if (got) {
1650 debug(("island at (%d,%d) must connect in direction (%d,%d) to" 1660 debug(("island at (%d,%d) must connect in direction (%d,%d) to"
@@ -1763,8 +1773,8 @@ static game_state *new_state(const game_params *params)
1763 ret->completed = false; 1773 ret->completed = false;
1764 1774
1765 ret->solver = snew(struct solver_state); 1775 ret->solver = snew(struct solver_state);
1766 ret->solver->dsf = snew_dsf(wh); 1776 ret->solver->dsf = dsf_new(wh);
1767 ret->solver->tmpdsf = snewn(wh, int); 1777 ret->solver->tmpdsf = dsf_new(wh);
1768 1778
1769 ret->solver->refcount = 1; 1779 ret->solver->refcount = 1;
1770 1780
@@ -1813,8 +1823,8 @@ static game_state *dup_game(const game_state *state)
1813static void free_game(game_state *state) 1823static void free_game(game_state *state)
1814{ 1824{
1815 if (--state->solver->refcount <= 0) { 1825 if (--state->solver->refcount <= 0) {
1816 sfree(state->solver->dsf); 1826 dsf_free(state->solver->dsf);
1817 sfree(state->solver->tmpdsf); 1827 dsf_free(state->solver->tmpdsf);
1818 sfree(state->solver); 1828 sfree(state->solver);
1819 } 1829 }
1820 1830
@@ -2004,28 +2014,38 @@ generated:
2004 2014
2005static const char *validate_desc(const game_params *params, const char *desc) 2015static const char *validate_desc(const game_params *params, const char *desc)
2006{ 2016{
2007 int i, wh = params->w * params->h; 2017 int i, j, wh = params->w * params->h, nislands = 0;
2018 bool *last_row = snewn(params->w, bool);
2008 2019
2020 memset(last_row, 0, params->w * sizeof(bool));
2009 for (i = 0; i < wh; i++) { 2021 for (i = 0; i < wh; i++) {
2010 if (*desc >= '1' && *desc <= '9') 2022 if ((*desc >= '1' && *desc <= '9') || (*desc >= 'A' && *desc <= 'G')) {
2011 /* OK */; 2023 nislands++;
2012 else if (*desc >= 'a' && *desc <= 'z') 2024 /* Look for other islands to the left and above. */
2025 if ((i % params->w > 0 && last_row[i % params->w - 1]) ||
2026 last_row[i % params->w]) {
2027 sfree(last_row);
2028 return "Game description contains joined islands";
2029 }
2030 last_row[i % params->w] = true;
2031 } else if (*desc >= 'a' && *desc <= 'z') {
2032 for (j = 0; j < *desc - 'a' + 1; j++)
2033 last_row[(i + j) % params->w] = false;
2013 i += *desc - 'a'; /* plus the i++ */ 2034 i += *desc - 'a'; /* plus the i++ */
2014 else if (*desc >= 'A' && *desc <= 'G') 2035 } else if (!*desc) {
2015 /* OK */; 2036 sfree(last_row);
2016 else if (*desc == 'V' || *desc == 'W' ||
2017 *desc == 'X' || *desc == 'Y' ||
2018 *desc == 'H' || *desc == 'I' ||
2019 *desc == 'J' || *desc == 'K')
2020 /* OK */;
2021 else if (!*desc)
2022 return "Game description shorter than expected"; 2037 return "Game description shorter than expected";
2023 else 2038 } else {
2039 sfree(last_row);
2024 return "Game description contains unexpected character"; 2040 return "Game description contains unexpected character";
2041 }
2025 desc++; 2042 desc++;
2026 } 2043 }
2044 sfree(last_row);
2027 if (*desc || i > wh) 2045 if (*desc || i > wh)
2028 return "Game description longer than expected"; 2046 return "Game description longer than expected";
2047 if (nislands < 2)
2048 return "Game description has too few islands";
2029 2049
2030 return NULL; 2050 return NULL;
2031} 2051}
@@ -2105,32 +2125,47 @@ static char *ui_cancel_drag(game_ui *ui)
2105 ui->dragx_src = ui->dragy_src = -1; 2125 ui->dragx_src = ui->dragy_src = -1;
2106 ui->dragx_dst = ui->dragy_dst = -1; 2126 ui->dragx_dst = ui->dragy_dst = -1;
2107 ui->dragging = false; 2127 ui->dragging = false;
2108 return UI_UPDATE; 2128 return MOVE_UI_UPDATE;
2109} 2129}
2110 2130
2111static game_ui *new_ui(const game_state *state) 2131static game_ui *new_ui(const game_state *state)
2112{ 2132{
2113 game_ui *ui = snew(game_ui); 2133 game_ui *ui = snew(game_ui);
2114 ui_cancel_drag(ui); 2134 ui_cancel_drag(ui);
2115 ui->cur_x = state->islands[0].x; 2135 if (state != NULL) {
2116 ui->cur_y = state->islands[0].y; 2136 ui->cur_x = state->islands[0].x;
2117 ui->cur_visible = false; 2137 ui->cur_y = state->islands[0].y;
2138 }
2139 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
2118 ui->show_hints = false; 2140 ui->show_hints = false;
2119 return ui; 2141 return ui;
2120} 2142}
2121 2143
2122static void free_ui(game_ui *ui) 2144static config_item *get_prefs(game_ui *ui)
2123{ 2145{
2124 sfree(ui); 2146 config_item *ret;
2147
2148 ret = snewn(2, config_item);
2149
2150 ret[0].name = "Show possible bridge locations";
2151 ret[0].kw = "show-hints";
2152 ret[0].type = C_BOOLEAN;
2153 ret[0].u.boolean.bval = ui->show_hints;
2154
2155 ret[1].name = NULL;
2156 ret[1].type = C_END;
2157
2158 return ret;
2125} 2159}
2126 2160
2127static char *encode_ui(const game_ui *ui) 2161static void set_prefs(game_ui *ui, const config_item *cfg)
2128{ 2162{
2129 return NULL; 2163 ui->show_hints = cfg[0].u.boolean.bval;
2130} 2164}
2131 2165
2132static void decode_ui(game_ui *ui, const char *encoding) 2166static void free_ui(game_ui *ui)
2133{ 2167{
2168 sfree(ui);
2134} 2169}
2135 2170
2136static void game_changed_state(game_ui *ui, const game_state *oldstate, 2171static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -2138,6 +2173,20 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
2138{ 2173{
2139} 2174}
2140 2175
2176static const char *current_key_label(const game_ui *ui,
2177 const game_state *state, int button)
2178{
2179 if (IS_CURSOR_SELECT(button)) {
2180 if (!ui->cur_visible)
2181 return ""; /* Actually shows cursor. */
2182 if (ui->dragging || button == CURSOR_SELECT2)
2183 return "Finished";
2184 if (GRID(state, ui->cur_x, ui->cur_y) & G_ISLAND)
2185 return "Select";
2186 }
2187 return "";
2188}
2189
2141struct game_drawstate { 2190struct game_drawstate {
2142 int tilesize; 2191 int tilesize;
2143 int w, h; 2192 int w, h;
@@ -2307,7 +2356,7 @@ static char *update_drag_dst(const game_state *state, game_ui *ui,
2307 /*debug(("update_drag src (%d,%d) d(%d,%d) dst (%d,%d)\n", 2356 /*debug(("update_drag src (%d,%d) d(%d,%d) dst (%d,%d)\n",
2308 ui->dragx_src, ui->dragy_src, dx, dy, 2357 ui->dragx_src, ui->dragy_src, dx, dy,
2309 ui->dragx_dst, ui->dragy_dst));*/ 2358 ui->dragx_dst, ui->dragy_dst));*/
2310 return UI_UPDATE; 2359 return MOVE_UI_UPDATE;
2311} 2360}
2312 2361
2313static char *finish_drag(const game_state *state, game_ui *ui) 2362static char *finish_drag(const game_state *state, game_ui *ui)
@@ -2342,15 +2391,15 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2342 char buf[80], *ret; 2391 char buf[80], *ret;
2343 grid_type ggrid = INGRID(state,gx,gy) ? GRID(state,gx,gy) : 0; 2392 grid_type ggrid = INGRID(state,gx,gy) ? GRID(state,gx,gy) : 0;
2344 bool shift = button & MOD_SHFT, control = button & MOD_CTRL; 2393 bool shift = button & MOD_SHFT, control = button & MOD_CTRL;
2345 button &= ~MOD_MASK; 2394 button = STRIP_BUTTON_MODIFIERS(button);
2346 2395
2347 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { 2396 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
2348 if (!INGRID(state, gx, gy)) return NULL; 2397 if (!INGRID(state, gx, gy)) return MOVE_UNUSED;
2349 ui->cur_visible = false; 2398 ui->cur_visible = false;
2350 if (ggrid & G_ISLAND) { 2399 if (ggrid & G_ISLAND) {
2351 ui->dragx_src = gx; 2400 ui->dragx_src = gx;
2352 ui->dragy_src = gy; 2401 ui->dragy_src = gy;
2353 return UI_UPDATE; 2402 return MOVE_UI_UPDATE;
2354 } else 2403 } else
2355 return ui_cancel_drag(ui); 2404 return ui_cancel_drag(ui);
2356 } else if (button == LEFT_DRAG || button == RIGHT_DRAG) { 2405 } else if (button == LEFT_DRAG || button == RIGHT_DRAG) {
@@ -2364,7 +2413,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2364 /* cancel a drag when we go back to the starting point */ 2413 /* cancel a drag when we go back to the starting point */
2365 ui->dragx_dst = -1; 2414 ui->dragx_dst = -1;
2366 ui->dragy_dst = -1; 2415 ui->dragy_dst = -1;
2367 return UI_UPDATE; 2416 return MOVE_UI_UPDATE;
2368 } 2417 }
2369 } else if (button == LEFT_RELEASE || button == RIGHT_RELEASE) { 2418 } else if (button == LEFT_RELEASE || button == RIGHT_RELEASE) {
2370 if (ui->dragging) { 2419 if (ui->dragging) {
@@ -2375,8 +2424,8 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2375 return ui_cancel_drag(ui); 2424 return ui_cancel_drag(ui);
2376 } 2425 }
2377 ui_cancel_drag(ui); 2426 ui_cancel_drag(ui);
2378 if (!INGRID(state, gx, gy)) return NULL; 2427 if (!INGRID(state, gx, gy)) return MOVE_UNUSED;
2379 if (!(GRID(state, gx, gy) & G_ISLAND)) return NULL; 2428 if (!(GRID(state, gx, gy) & G_ISLAND)) return MOVE_NO_EFFECT;
2380 sprintf(buf, "M%d,%d", gx, gy); 2429 sprintf(buf, "M%d,%d", gx, gy);
2381 return dupstr(buf); 2430 return dupstr(buf);
2382 } 2431 }
@@ -2397,9 +2446,9 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2397 if (ui->dragging) { 2446 if (ui->dragging) {
2398 int nx = ui->cur_x, ny = ui->cur_y; 2447 int nx = ui->cur_x, ny = ui->cur_y;
2399 2448
2400 move_cursor(button, &nx, &ny, state->w, state->h, false); 2449 move_cursor(button, &nx, &ny, state->w, state->h, false, NULL);
2401 if (nx == ui->cur_x && ny == ui->cur_y) 2450 if (nx == ui->cur_x && ny == ui->cur_y)
2402 return NULL; 2451 return MOVE_NO_EFFECT;
2403 update_drag_dst(state, ui, ds, 2452 update_drag_dst(state, ui, ds,
2404 COORD(nx)+TILE_SIZE/2, 2453 COORD(nx)+TILE_SIZE/2,
2405 COORD(ny)+TILE_SIZE/2); 2454 COORD(ny)+TILE_SIZE/2);
@@ -2451,19 +2500,19 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2451 2500
2452 if (!dingrid) break; 2501 if (!dingrid) break;
2453 } 2502 }
2454 if (!oingrid) return UI_UPDATE; 2503 if (!oingrid) return MOVE_UI_UPDATE;
2455 } 2504 }
2456 /* not reached */ 2505 /* not reached */
2457 2506
2458found: 2507found:
2459 ui->cur_x = nx; 2508 ui->cur_x = nx;
2460 ui->cur_y = ny; 2509 ui->cur_y = ny;
2461 return UI_UPDATE; 2510 return MOVE_UI_UPDATE;
2462 } 2511 }
2463 } else if (IS_CURSOR_SELECT(button)) { 2512 } else if (IS_CURSOR_SELECT(button)) {
2464 if (!ui->cur_visible) { 2513 if (!ui->cur_visible) {
2465 ui->cur_visible = true; 2514 ui->cur_visible = true;
2466 return UI_UPDATE; 2515 return MOVE_UI_UPDATE;
2467 } 2516 }
2468 if (ui->dragging || button == CURSOR_SELECT2) { 2517 if (ui->dragging || button == CURSOR_SELECT2) {
2469 ui_cancel_drag(ui); 2518 ui_cancel_drag(ui);
@@ -2471,7 +2520,7 @@ found:
2471 sprintf(buf, "M%d,%d", ui->cur_x, ui->cur_y); 2520 sprintf(buf, "M%d,%d", ui->cur_x, ui->cur_y);
2472 return dupstr(buf); 2521 return dupstr(buf);
2473 } else 2522 } else
2474 return UI_UPDATE; 2523 return MOVE_UI_UPDATE;
2475 } else { 2524 } else {
2476 grid_type v = GRID(state, ui->cur_x, ui->cur_y); 2525 grid_type v = GRID(state, ui->cur_x, ui->cur_y);
2477 if (v & G_ISLAND) { 2526 if (v & G_ISLAND) {
@@ -2480,7 +2529,7 @@ found:
2480 ui->dragy_src = ui->cur_y; 2529 ui->dragy_src = ui->cur_y;
2481 ui->dragx_dst = ui->dragy_dst = -1; 2530 ui->dragx_dst = ui->dragy_dst = -1;
2482 ui->drag_is_noline = (button == CURSOR_SELECT2); 2531 ui->drag_is_noline = (button == CURSOR_SELECT2);
2483 return UI_UPDATE; 2532 return MOVE_UI_UPDATE;
2484 } 2533 }
2485 } 2534 }
2486 } else if ((button >= '0' && button <= '9') || 2535 } else if ((button >= '0' && button <= '9') ||
@@ -2498,7 +2547,7 @@ found:
2498 2547
2499 if (!ui->cur_visible) { 2548 if (!ui->cur_visible) {
2500 ui->cur_visible = true; 2549 ui->cur_visible = true;
2501 return UI_UPDATE; 2550 return MOVE_UI_UPDATE;
2502 } 2551 }
2503 2552
2504 for (i = 0; i < state->n_islands; ++i) { 2553 for (i = 0; i < state->n_islands; ++i) {
@@ -2525,15 +2574,15 @@ found:
2525 if (best_x != -1 && best_y != -1) { 2574 if (best_x != -1 && best_y != -1) {
2526 ui->cur_x = best_x; 2575 ui->cur_x = best_x;
2527 ui->cur_y = best_y; 2576 ui->cur_y = best_y;
2528 return UI_UPDATE; 2577 return MOVE_UI_UPDATE;
2529 } else 2578 } else
2530 return NULL; 2579 return MOVE_NO_EFFECT;
2531 } else if (button == 'g' || button == 'G') { 2580 } else if (button == 'g' || button == 'G') {
2532 ui->show_hints = !ui->show_hints; 2581 ui->show_hints = !ui->show_hints;
2533 return UI_UPDATE; 2582 return MOVE_UI_UPDATE;
2534 } 2583 }
2535 2584
2536 return NULL; 2585 return MOVE_UNUSED;
2537} 2586}
2538 2587
2539static game_state *execute_move(const game_state *state, const char *move) 2588static game_state *execute_move(const game_state *state, const char *move)
@@ -2557,6 +2606,8 @@ static game_state *execute_move(const game_state *state, const char *move)
2557 goto badmove; 2606 goto badmove;
2558 if (!INGRID(ret, x1, y1) || !INGRID(ret, x2, y2)) 2607 if (!INGRID(ret, x1, y1) || !INGRID(ret, x2, y2))
2559 goto badmove; 2608 goto badmove;
2609 /* Precisely one co-ordinate must differ between islands. */
2610 if ((x1 != x2) + (y1 != y2) != 1) goto badmove;
2560 is1 = INDEX(ret, gridi, x1, y1); 2611 is1 = INDEX(ret, gridi, x1, y1);
2561 is2 = INDEX(ret, gridi, x2, y2); 2612 is2 = INDEX(ret, gridi, x2, y2);
2562 if (!is1 || !is2) goto badmove; 2613 if (!is1 || !is2) goto badmove;
@@ -2568,6 +2619,7 @@ static game_state *execute_move(const game_state *state, const char *move)
2568 goto badmove; 2619 goto badmove;
2569 if (!INGRID(ret, x1, y1) || !INGRID(ret, x2, y2)) 2620 if (!INGRID(ret, x1, y1) || !INGRID(ret, x2, y2))
2570 goto badmove; 2621 goto badmove;
2622 if ((x1 != x2) + (y1 != y2) != 1) goto badmove;
2571 is1 = INDEX(ret, gridi, x1, y1); 2623 is1 = INDEX(ret, gridi, x1, y1);
2572 is2 = INDEX(ret, gridi, x2, y2); 2624 is2 = INDEX(ret, gridi, x2, y2);
2573 if (!is1 || !is2) goto badmove; 2625 if (!is1 || !is2) goto badmove;
@@ -2636,7 +2688,7 @@ static char *solve_game(const game_state *state, const game_state *currstate,
2636 */ 2688 */
2637 2689
2638static void game_compute_size(const game_params *params, int tilesize, 2690static void game_compute_size(const game_params *params, int tilesize,
2639 int *x, int *y) 2691 const game_ui *ui, int *x, int *y)
2640{ 2692{
2641 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2693 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2642 struct { int tilesize; } ads, *ds = &ads; 2694 struct { int tilesize; } ads, *ds = &ads;
@@ -2987,9 +3039,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2987 3039
2988 /* Clear screen, if required. */ 3040 /* Clear screen, if required. */
2989 if (!ds->started) { 3041 if (!ds->started) {
2990 draw_rect(dr, 0, 0,
2991 TILE_SIZE * ds->w + 2 * BORDER,
2992 TILE_SIZE * ds->h + 2 * BORDER, COL_BACKGROUND);
2993#ifdef DRAW_GRID 3042#ifdef DRAW_GRID
2994 draw_rect_outline(dr, 3043 draw_rect_outline(dr,
2995 COORD(0)-1, COORD(0)-1, 3044 COORD(0)-1, COORD(0)-1,
@@ -3177,22 +3226,19 @@ static int game_status(const game_state *state)
3177 return state->completed ? +1 : 0; 3226 return state->completed ? +1 : 0;
3178} 3227}
3179 3228
3180static bool game_timing_state(const game_state *state, game_ui *ui) 3229static void game_print_size(const game_params *params, const game_ui *ui,
3181{ 3230 float *x, float *y)
3182 return true;
3183}
3184
3185static void game_print_size(const game_params *params, float *x, float *y)
3186{ 3231{
3187 int pw, ph; 3232 int pw, ph;
3188 3233
3189 /* 10mm squares by default. */ 3234 /* 10mm squares by default. */
3190 game_compute_size(params, 1000, &pw, &ph); 3235 game_compute_size(params, 1000, ui, &pw, &ph);
3191 *x = pw / 100.0F; 3236 *x = pw / 100.0F;
3192 *y = ph / 100.0F; 3237 *y = ph / 100.0F;
3193} 3238}
3194 3239
3195static void game_print(drawing *dr, const game_state *state, int ts) 3240static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
3241 int ts)
3196{ 3242{
3197 int ink = print_mono_colour(dr, 0); 3243 int ink = print_mono_colour(dr, 0);
3198 int paper = print_mono_colour(dr, 1); 3244 int paper = print_mono_colour(dr, 1);
@@ -3266,12 +3312,14 @@ const struct game thegame = {
3266 free_game, 3312 free_game,
3267 true, solve_game, 3313 true, solve_game,
3268 true, game_can_format_as_text_now, game_text_format, 3314 true, game_can_format_as_text_now, game_text_format,
3315 get_prefs, set_prefs,
3269 new_ui, 3316 new_ui,
3270 free_ui, 3317 free_ui,
3271 encode_ui, 3318 NULL, /* encode_ui */
3272 decode_ui, 3319 NULL, /* decode_ui */
3273 NULL, /* game_request_keys */ 3320 NULL, /* game_request_keys */
3274 game_changed_state, 3321 game_changed_state,
3322 current_key_label,
3275 interpret_move, 3323 interpret_move,
3276 execute_move, 3324 execute_move,
3277 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 3325 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -3285,7 +3333,7 @@ const struct game thegame = {
3285 game_status, 3333 game_status,
3286 true, false, game_print_size, game_print, 3334 true, false, game_print_size, game_print,
3287 false, /* wants_statusbar */ 3335 false, /* wants_statusbar */
3288 false, game_timing_state, 3336 false, NULL, /* timing_state */
3289 REQUIRE_RBUTTON, /* flags */ 3337 REQUIRE_RBUTTON, /* flags */
3290}; 3338};
3291 3339
diff --git a/apps/plugins/puzzles/src/combi.c b/apps/plugins/puzzles/src/combi.c
index 3460183c9c..132d74027e 100644
--- a/apps/plugins/puzzles/src/combi.c
+++ b/apps/plugins/puzzles/src/combi.c
@@ -71,40 +71,3 @@ void free_combi(combi_ctx *combi)
71 sfree(combi->a); 71 sfree(combi->a);
72 sfree(combi); 72 sfree(combi);
73} 73}
74
75/* compile this with:
76 * gcc -o combi.exe -DSTANDALONE_COMBI_TEST combi.c malloc.c
77 */
78#ifdef STANDALONE_COMBI_TEST
79
80#include <stdio.h>
81
82void fatal(const char *fmt, ...)
83{
84 abort();
85}
86
87int main(int argc, char *argv[])
88{
89 combi_ctx *c;
90 int i, r, n;
91
92 if (argc < 3) {
93 fprintf(stderr, "Usage: combi R N\n");
94 exit(1);
95 }
96
97 r = atoi(argv[1]); n = atoi(argv[2]);
98 c = new_combi(r, n);
99 printf("combi %d of %d, %d elements.\n", c->r, c->n, c->total);
100
101 while (next_combi(c)) {
102 for (i = 0; i < c->r; i++) {
103 printf("%d ", c->a[i]);
104 }
105 printf("\n");
106 }
107 free_combi(c);
108}
109
110#endif
diff --git a/apps/plugins/puzzles/src/cube.R b/apps/plugins/puzzles/src/cube.R
deleted file mode 100644
index 85b081ec76..0000000000
--- a/apps/plugins/puzzles/src/cube.R
+++ /dev/null
@@ -1,19 +0,0 @@
1# -*- makefile -*-
2
3cube : [X] GTK COMMON cube cube-icon|no-icon
4
5cube : [G] WINDOWS COMMON cube cube.res|noicon.res
6
7ALL += cube[COMBINED]
8
9!begin am gtk
10GAMES += cube
11!end
12
13!begin >list.c
14 A(cube) \
15!end
16
17!begin >gamedesc.txt
18cube:cube.exe:Cube:Rolling cube puzzle:Pick up all the blue squares by rolling the cube over them.
19!end
diff --git a/apps/plugins/puzzles/src/cube.c b/apps/plugins/puzzles/src/cube.c
index 8c8c46faed..08788cbd65 100644
--- a/apps/plugins/puzzles/src/cube.c
+++ b/apps/plugins/puzzles/src/cube.c
@@ -7,7 +7,11 @@
7#include <string.h> 7#include <string.h>
8#include <assert.h> 8#include <assert.h>
9#include <ctype.h> 9#include <ctype.h>
10#include <math.h> 10#ifdef NO_TGMATH_H
11# include <math.h>
12#else
13# include <tgmath.h>
14#endif
11 15
12#include "puzzles.h" 16#include "puzzles.h"
13 17
@@ -171,7 +175,7 @@ enum { LEFT, RIGHT, UP, DOWN, UP_LEFT, UP_RIGHT, DOWN_LEFT, DOWN_RIGHT };
171 (ra)[0] = rx; (ra)[1] = ry; (ra)[2] = rz; \ 175 (ra)[0] = rx; (ra)[1] = ry; (ra)[2] = rz; \
172} while (0) 176} while (0)
173 177
174#define APPROXEQ(x,y) ( SQ(x-y) < 0.1 ) 178#define APPROXEQ(x,y) ( SQ(x-y) < 0.1F )
175 179
176struct grid_square { 180struct grid_square {
177 float x, y; 181 float x, y;
@@ -202,8 +206,8 @@ struct game_grid {
202}; 206};
203 207
204#define SET_SQUARE(state, i, val) \ 208#define SET_SQUARE(state, i, val) \
205 ((state)->bluemask[(i)/32] &= ~(1 << ((i)%32)), \ 209 ((state)->bluemask[(i)/32] &= ~(1UL << ((i)%32)), \
206 (state)->bluemask[(i)/32] |= ((!!val) << ((i)%32))) 210 (state)->bluemask[(i)/32] |= ((unsigned long)(!!val) << ((i)%32)))
207#define GET_SQUARE(state, i) \ 211#define GET_SQUARE(state, i) \
208 (((state)->bluemask[(i)/32] >> ((i)%32)) & 1) 212 (((state)->bluemask[(i)/32] >> ((i)%32)) & 1)
209 213
@@ -542,12 +546,38 @@ static const char *validate_params(const game_params *params, bool full)
542 if (params->solid < 0 || params->solid >= lenof(solids)) 546 if (params->solid < 0 || params->solid >= lenof(solids))
543 return "Unrecognised solid type"; 547 return "Unrecognised solid type";
544 548
549 if (params->d1 < 0 || params->d2 < 0)
550 return "Grid dimensions may not be negative";
551
545 if (solids[params->solid]->order == 4) { 552 if (solids[params->solid]->order == 4) {
546 if (params->d1 <= 1 || params->d2 <= 1) 553 if (params->d1 <= 1 || params->d2 <= 1)
547 return "Both grid dimensions must be greater than one"; 554 return "Both grid dimensions must be greater than one";
555 if (params->d2 > INT_MAX / params->d1)
556 return "Grid area must not be unreasonably large";
548 } else { 557 } else {
549 if (params->d1 <= 0 && params->d2 <= 0) 558 if (params->d1 <= 0 && params->d2 <= 0)
550 return "At least one grid dimension must be greater than zero"; 559 return "At least one grid dimension must be greater than zero";
560
561 /*
562 * Check whether d1^2 + d2^2 + 4 d1 d2 > INT_MAX, without overflow:
563 *
564 * First check d1^2 doesn't overflow by itself.
565 *
566 * Then check d2^2 doesn't exceed the remaining space between
567 * d1^2 and INT_MAX.
568 *
569 * If that's all OK then we know both d1 and d2 are
570 * individually less than the square root of INT_MAX, so we
571 * can safely multiply them and compare against the
572 * _remaining_ space.
573 */
574 if ((params->d1 > 0 && params->d1 > INT_MAX / params->d1) ||
575 (params->d2 > 0 &&
576 params->d2 > (INT_MAX - params->d1*params->d1) / params->d2) ||
577 (params->d2 > 0 &&
578 params->d1*params->d2 > (INT_MAX - params->d1*params->d1 -
579 params->d2*params->d2) / params->d2))
580 return "Grid area must not be unreasonably large";
551 } 581 }
552 582
553 for (i = 0; i < 4; i++) 583 for (i = 0; i < 4; i++)
@@ -761,7 +791,7 @@ static bool align_poly(const struct solid *solid, struct grid_square *sq,
761 dist += SQ(solid->vertices[i*3+1] * flip - sq->points[j*2+1] + sq->y); 791 dist += SQ(solid->vertices[i*3+1] * flip - sq->points[j*2+1] + sq->y);
762 dist += SQ(solid->vertices[i*3+2] - zmin); 792 dist += SQ(solid->vertices[i*3+2] - zmin);
763 793
764 if (dist < 0.1) { 794 if (dist < 0.1F) {
765 matches++; 795 matches++;
766 index = i; 796 index = i;
767 } 797 }
@@ -811,7 +841,7 @@ static struct solid *transform_poly(const struct solid *solid, bool flip,
811 */ 841 */
812 vx = ret->vertices[key1*3+0] - ret->vertices[key0*3+0]; 842 vx = ret->vertices[key1*3+0] - ret->vertices[key0*3+0];
813 vy = ret->vertices[key1*3+1] - ret->vertices[key0*3+1]; 843 vy = ret->vertices[key1*3+1] - ret->vertices[key0*3+1];
814 assert(APPROXEQ(vx*vx + vy*vy, 1.0)); 844 assert(APPROXEQ(vx*vx + vy*vy, 1.0F));
815 845
816 vmatrix[0] = vx; vmatrix[3] = vy; vmatrix[6] = 0; 846 vmatrix[0] = vx; vmatrix[3] = vy; vmatrix[6] = 0;
817 vmatrix[1] = -vy; vmatrix[4] = vx; vmatrix[7] = 0; 847 vmatrix[1] = -vy; vmatrix[4] = vx; vmatrix[7] = 0;
@@ -999,22 +1029,6 @@ static void free_game(game_state *state)
999 sfree(state); 1029 sfree(state);
1000} 1030}
1001 1031
1002static char *solve_game(const game_state *state, const game_state *currstate,
1003 const char *aux, const char **error)
1004{
1005 return NULL;
1006}
1007
1008static bool game_can_format_as_text_now(const game_params *params)
1009{
1010 return true;
1011}
1012
1013static char *game_text_format(const game_state *state)
1014{
1015 return NULL;
1016}
1017
1018static game_ui *new_ui(const game_state *state) 1032static game_ui *new_ui(const game_state *state)
1019{ 1033{
1020 return NULL; 1034 return NULL;
@@ -1024,15 +1038,6 @@ static void free_ui(game_ui *ui)
1024{ 1038{
1025} 1039}
1026 1040
1027static char *encode_ui(const game_ui *ui)
1028{
1029 return NULL;
1030}
1031
1032static void decode_ui(game_ui *ui, const char *encoding)
1033{
1034}
1035
1036static void game_changed_state(game_ui *ui, const game_state *oldstate, 1041static void game_changed_state(game_ui *ui, const game_state *oldstate,
1037 const game_state *newstate) 1042 const game_state *newstate)
1038{ 1043{
@@ -1081,11 +1086,11 @@ static int find_move_dest(const game_state *from, int direction,
1081 for (j = 0; j < from->grid->squares[i].npoints; j++) { 1086 for (j = 0; j < from->grid->squares[i].npoints; j++) {
1082 dist = (SQ(from->grid->squares[i].points[j*2] - points[0]) + 1087 dist = (SQ(from->grid->squares[i].points[j*2] - points[0]) +
1083 SQ(from->grid->squares[i].points[j*2+1] - points[1])); 1088 SQ(from->grid->squares[i].points[j*2+1] - points[1]));
1084 if (dist < 0.1) 1089 if (dist < 0.1F)
1085 dkey[match++] = j; 1090 dkey[match++] = j;
1086 dist = (SQ(from->grid->squares[i].points[j*2] - points[2]) + 1091 dist = (SQ(from->grid->squares[i].points[j*2] - points[2]) +
1087 SQ(from->grid->squares[i].points[j*2+1] - points[3])); 1092 SQ(from->grid->squares[i].points[j*2+1] - points[3]));
1088 if (dist < 0.1) 1093 if (dist < 0.1F)
1089 dkey[match++] = j; 1094 dkey[match++] = j;
1090 } 1095 }
1091 1096
@@ -1140,7 +1145,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1140 cy = (int)(state->grid->squares[state->current].y * GRID_SCALE) + ds->oy; 1145 cy = (int)(state->grid->squares[state->current].y * GRID_SCALE) + ds->oy;
1141 1146
1142 if (x == cx && y == cy) 1147 if (x == cx && y == cy)
1143 return NULL; /* clicked in exact centre! */ 1148 return MOVE_NO_EFFECT; /* clicked in exact centre! */
1144 angle = atan2(y - cy, x - cx); 1149 angle = atan2(y - cy, x - cx);
1145 1150
1146 /* 1151 /*
@@ -1191,11 +1196,11 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1191 direction = RIGHT; 1196 direction = RIGHT;
1192 } 1197 }
1193 } else 1198 } else
1194 return NULL; 1199 return MOVE_UNUSED;
1195 1200
1196 mask = state->grid->squares[state->current].directions[direction]; 1201 mask = state->grid->squares[state->current].directions[direction];
1197 if (mask == 0) 1202 if (mask == 0)
1198 return NULL; 1203 return MOVE_NO_EFFECT;
1199 1204
1200 /* 1205 /*
1201 * Translate diagonal directions into orthogonal ones. 1206 * Translate diagonal directions into orthogonal ones.
@@ -1210,14 +1215,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1210 } 1215 }
1211 1216
1212 if (find_move_dest(state, direction, skey, dkey) < 0) 1217 if (find_move_dest(state, direction, skey, dkey) < 0)
1213 return NULL; 1218 return MOVE_NO_EFFECT;
1214 1219
1215 if (direction == LEFT) return dupstr("L"); 1220 if (direction == LEFT) return dupstr("L");
1216 if (direction == RIGHT) return dupstr("R"); 1221 if (direction == RIGHT) return dupstr("R");
1217 if (direction == UP) return dupstr("U"); 1222 if (direction == UP) return dupstr("U");
1218 if (direction == DOWN) return dupstr("D"); 1223 if (direction == DOWN) return dupstr("D");
1219 1224
1220 return NULL; /* should never happen */ 1225 return MOVE_NO_EFFECT; /* should never happen */
1221} 1226}
1222 1227
1223static game_state *execute_move(const game_state *from, const char *move) 1228static game_state *execute_move(const game_state *from, const char *move)
@@ -1484,7 +1489,7 @@ static struct bbox find_bbox(const game_params *params)
1484 ((int)(((bb).d - (bb).u + 2*(solid)->border) * gs)) 1489 ((int)(((bb).d - (bb).u + 2*(solid)->border) * gs))
1485 1490
1486static void game_compute_size(const game_params *params, int tilesize, 1491static void game_compute_size(const game_params *params, int tilesize,
1487 int *x, int *y) 1492 const game_ui *ui, int *x, int *y)
1488{ 1493{
1489 struct bbox bb = find_bbox(params); 1494 struct bbox bb = find_bbox(params);
1490 1495
@@ -1734,19 +1739,6 @@ static int game_status(const game_state *state)
1734 return state->completed ? +1 : 0; 1739 return state->completed ? +1 : 0;
1735} 1740}
1736 1741
1737static bool game_timing_state(const game_state *state, game_ui *ui)
1738{
1739 return true;
1740}
1741
1742static void game_print_size(const game_params *params, float *x, float *y)
1743{
1744}
1745
1746static void game_print(drawing *dr, const game_state *state, int tilesize)
1747{
1748}
1749
1750#ifdef COMBINED 1742#ifdef COMBINED
1751#define thegame cube 1743#define thegame cube
1752#endif 1744#endif
@@ -1766,14 +1758,16 @@ const struct game thegame = {
1766 new_game, 1758 new_game,
1767 dup_game, 1759 dup_game,
1768 free_game, 1760 free_game,
1769 false, solve_game, 1761 false, NULL, /* solve */
1770 false, game_can_format_as_text_now, game_text_format, 1762 false, NULL, NULL, /* can_format_as_text_now, text_format */
1763 NULL, NULL, /* get_prefs, set_prefs */
1771 new_ui, 1764 new_ui,
1772 free_ui, 1765 free_ui,
1773 encode_ui, 1766 NULL, /* encode_ui */
1774 decode_ui, 1767 NULL, /* decode_ui */
1775 NULL, /* game_request_keys */ 1768 NULL, /* game_request_keys */
1776 game_changed_state, 1769 game_changed_state,
1770 NULL, /* current_key_label */
1777 interpret_move, 1771 interpret_move,
1778 execute_move, 1772 execute_move,
1779 PREFERRED_GRID_SCALE, game_compute_size, game_set_size, 1773 PREFERRED_GRID_SCALE, game_compute_size, game_set_size,
@@ -1785,8 +1779,8 @@ const struct game thegame = {
1785 game_flash_length, 1779 game_flash_length,
1786 game_get_cursor_location, 1780 game_get_cursor_location,
1787 game_status, 1781 game_status,
1788 false, false, game_print_size, game_print, 1782 false, false, NULL, NULL, /* print_size, print */
1789 true, /* wants_statusbar */ 1783 true, /* wants_statusbar */
1790 false, game_timing_state, 1784 false, NULL, /* timing_state */
1791 0, /* flags */ 1785 0, /* flags */
1792}; 1786};
diff --git a/apps/plugins/puzzles/src/devel.but b/apps/plugins/puzzles/src/devel.but
index 7521596df9..c201a3e6c9 100644
--- a/apps/plugins/puzzles/src/devel.but
+++ b/apps/plugins/puzzles/src/devel.but
@@ -32,10 +32,11 @@ Puzzle Collection (henceforth referred to simply as \q{Puzzles}),
32for use by anyone attempting to implement a new puzzle or port to a 32for use by anyone attempting to implement a new puzzle or port to a
33new platform. 33new platform.
34 34
35This guide is believed correct as of r6190. Hopefully it will be 35This guide is believed correct as of \cw{git} commit
36updated along with the code in future, but if not, I've at least 36\cw{a2212e82aa2f4b9a4ee22783d6fed2761c213432}. Hopefully it will be
37left this version number in here so you can figure out what's 37updated along with the code in future, but if not, I've at least left
38changed by tracking commit comments from there onwards. 38this version number in here so you can figure out what's changed by
39tracking commit comments from there onwards.
39 40
40\C{intro} Introduction 41\C{intro} Introduction
41 42
@@ -52,25 +53,21 @@ that you replace completely when you port to a different platform.
52So it's responsible for all system calls, all GUI interaction, and 53So it's responsible for all system calls, all GUI interaction, and
53anything else platform-specific. 54anything else platform-specific.
54 55
55The current front ends in the main code base are for Windows, GTK
56and MacOS X; I also know of a third-party front end for PalmOS.
57
58The front end contains \cw{main()} or the local platform's 56The front end contains \cw{main()} or the local platform's
59equivalent. Top-level control over the application's execution flow 57equivalent. Top-level control over the application's execution flow
60belongs to the front end (it isn't, for example, a set of functions 58belongs to the front end (it isn't, for example, a set of functions
61called by a universal \cw{main()} somewhere else). 59called by a universal \cw{main()} somewhere else).
62 60
63The front end has complete freedom to design the GUI for any given 61The front end has complete freedom to design the GUI for any given
64port of Puzzles. There is no centralised mechanism for maintaining 62port of Puzzles. There is no centralised mechanism for maintaining the
65the menu layout, for example. This has a cost in consistency (when I 63menu layout, for example. This has a cost in consistency (when I
66\e{do} want the same menu layout on more than one platform, I have 64\e{do} want the same menu layout on more than one platform, I have to
67to edit two pieces of code in parallel every time I make a change), 65edit N pieces of code in parallel every time I make a change), but the
68but the advantage is that local GUI conventions can be conformed to 66advantage is that local GUI conventions can be conformed to and local
69and local constraints adapted to. For example, MacOS X has strict 67constraints adapted to. For example, MacOS has strict human interface
70human interface guidelines which specify a different menu layout 68guidelines which specify a different menu layout from the one I've
71from the one I've used on Windows and GTK; there's nothing stopping 69used on Windows and GTK; there's nothing stopping the MacOS front end
72the OS X front end from providing a menu layout consistent with 70from providing a menu layout consistent with those guidelines.
73those guidelines.
74 71
75Although the front end is mostly caller rather than the callee in 72Although the front end is mostly caller rather than the callee in
76its interactions with other parts of the code, it is required to 73its interactions with other parts of the code, it is required to
@@ -143,9 +140,10 @@ etc).
143\b Handling the dialog boxes which ask the user for a game ID. 140\b Handling the dialog boxes which ask the user for a game ID.
144 141
145\b Handling serialisation of entire games (for loading and saving a 142\b Handling serialisation of entire games (for loading and saving a
146half-finished game to a disk file, or for handling application 143half-finished game to a disk file; for handling application shutdown
147shutdown and restart on platforms such as PalmOS where state is 144and restart on platforms such as PalmOS where state is expected to be
148expected to be saved). 145saved; for storing the previous game in order to undo and redo across
146a New Game event).
149 147
150Thus, there's a lot of work done once by the mid-end so that 148Thus, there's a lot of work done once by the mid-end so that
151individual back ends don't have to worry about it. All the back end 149individual back ends don't have to worry about it. All the back end
@@ -193,9 +191,8 @@ end module builds a different puzzle.
193\b On platforms such as MacOS X and PalmOS, which build all the 191\b On platforms such as MacOS X and PalmOS, which build all the
194puzzles into a single monolithic binary, the game structure in each 192puzzles into a single monolithic binary, the game structure in each
195back end must have a different name, and there's a helper module 193back end must have a different name, and there's a helper module
196\c{list.c} (constructed automatically by the same Perl script that 194\c{list.c} which constructs a complete list of those game structures
197builds the \cw{Makefile}s) which contains a complete list of those 195from a header file generated by CMake.
198game structures.
199 196
200On the latter type of platform, source files may assume that the 197On the latter type of platform, source files may assume that the
201preprocessor symbol \c{COMBINED} has been defined. Thus, the usual 198preprocessor symbol \c{COMBINED} has been defined. Thus, the usual
@@ -249,14 +246,15 @@ yet been necessary to do this in any puzzle so far, but the
249capability is there just in case.) 246capability is there just in case.)
250 247
251\c{game_params} is also the only structure which the game's 248\c{game_params} is also the only structure which the game's
252\cw{compute_size()} function may refer to; this means that any 249\cw{compute_size()} function may refer to; this means that any aspect
253aspect of the game which affects the size of the window it needs to 250of the game which affects the size of the window it needs to be drawn
254be drawn in must be stored in \c{game_params}. In particular, this 251in (other than the magnification level) must be stored in
255imposes the fundamental limitation that random game generation may 252\c{game_params}. In particular, this imposes the fundamental
256not have a random effect on the window size: game generation 253limitation that random game generation may not have a random effect on
257algorithms are constrained to work by starting from the grid size 254the window size: game generation algorithms are constrained to work by
258rather than generating it as an emergent phenomenon. (Although this 255starting from the grid size rather than generating it as an emergent
259is a restriction in theory, it has not yet seemed to be a problem.) 256phenomenon. (Although this is a restriction in theory, it has not yet
257seemed to be a problem.)
260 258
261\S{backend-game-state} \c{game_state} 259\S{backend-game-state} \c{game_state}
262 260
@@ -268,14 +266,25 @@ The mid-end keeps \c{game_state}s in a list, and adds to the list
268every time the player makes a move; the Undo and Redo functions step 266every time the player makes a move; the Undo and Redo functions step
269back and forth through that list. 267back and forth through that list.
270 268
271Therefore, a good means of deciding whether a data item needs to go 269Therefore, a good means of deciding whether a data item needs to go in
272in \c{game_state} is: would a player expect that data item to be 270\c{game_state} is: would a player expect that data item to be restored
273restored on undo? If so, put it in \c{game_state}, and this will 271on undo? If so, put it in \c{game_state}, and this will automatically
274automatically happen without you having to lift a finger. If not 272happen without you having to lift a finger. If not, then you might
275\dash for example, the deaths counter in Mines is precisely 273have found a data item that needs to go in \c{game_ui} instead.
276something that does \e{not} want to be reset to its previous state 274
277on an undo \dash then you might have found a data item that needs to 275Two quite different examples of this:
278go in \c{game_ui} instead. 276
277\b if the game provides an interface for making moves by moving a
278cursor around the grid with the keyboard and pressing some other key
279when you get to a square you want to change, then the location of that
280cursor belongs in \c{game_ui}, because the player will want to undo
281one \e{square change} at a time, not one \e{cursor movement} at a
282time.
283
284\b Mines tracks the number of times you opened a mine square and died.
285Every time you do that, you can only continue the game by pressing
286Undo. So the deaths counter belongs in \c{game_ui}, because otherwise,
287it would revert to 0 every time you undid your mistaken move.
279 288
280During play, \c{game_state}s are often passed around without an 289During play, \c{game_state}s are often passed around without an
281accompanying \c{game_params} structure. Therefore, any information 290accompanying \c{game_params} structure. Therefore, any information
@@ -293,12 +302,12 @@ is passed to every call to the game redraw function, so that it can
293remember what it has already drawn and what needs redrawing. 302remember what it has already drawn and what needs redrawing.
294 303
295A typical use for a \c{game_drawstate} is to have an array mirroring 304A typical use for a \c{game_drawstate} is to have an array mirroring
296the array of grid squares in the \c{game_state}; then every time the 305the array of grid squares in the \c{game_state}, but describing what
297redraw function was passed a \c{game_state}, it would loop over all 306was drawn in the window on the most recent redraw. This is used to
298the squares, and physically redraw any whose description in the 307identify the squares that need redrawing next time, by deciding what
299\c{game_state} (i.e. what the square needs to look like when the 308the new value in that array should be, and comparing it to what was
300redraw is completed) did not match its description in the 309drawn last time. See \k{writing-howto-redraw} for more on this
301\c{game_drawstate} (i.e. what the square currently looks like). 310subject.
302 311
303\c{game_drawstate} is occasionally completely torn down and 312\c{game_drawstate} is occasionally completely torn down and
304reconstructed by the mid-end, if the user somehow forces a full 313reconstructed by the mid-end, if the user somehow forces a full
@@ -323,23 +332,49 @@ game ID etc). It persists until the user finishes playing that game
323and begins another one (or closes the window); in particular, 332and begins another one (or closes the window); in particular,
324\q{Restart Game} does \e{not} destroy the \c{game_ui}. 333\q{Restart Game} does \e{not} destroy the \c{game_ui}.
325 334
326\c{game_ui} is useful for implementing user-interface state which is 335There are various things that you might store in \c{game_ui}, which
327not part of \c{game_state}. Common examples are keyboard control 336are conceptually different from each other, but I haven't yet found a
328(you wouldn't want to have to separately Undo through every cursor 337need to split them out into smaller sub-structures for different
329motion) and mouse dragging. See \k{writing-keyboard-cursor} and 338purposes:
330\k{writing-howto-dragging}, respectively, for more details. 339
340\dt Transient UI state:
341
342\dd Storing a piece of UI state in \c{game_state} means that you can
343only update it by appending a move to the undo chain. Some UI state
344shouldn't really be treated this way. For example, if your puzzle has
345a keyboard-controlled cursor, you probably don't want every cursor
346movement to be an undoable action, because the history of where the
347cursor went just isn't interesting. More likely the cursor should just
348move freely, and the only undoable actions are the ones where you
349modify the element under the cursor. So you'd store the cursor
350position in \c{game_ui} rather than \c{game_state}. See
351\k{writing-keyboard-cursor} for more details.
352
353\lcont{ Another example of this is the state of an ongoing mouse drag.
354If there's an undoable action involved, it will probably occur when
355the drag is released. In between, you still need to store state that
356the redraw function will use to update the display \dash and that can
357live in \c{game_ui}. See \k{writing-howto-dragging} for more details
358of this. }
359
360\dt Persistent UI state:
361
362\dd An example of this is the counter of deaths in Mines or Inertia.
363This shouldn't be reverted by pressing Undo, for the opposite reason
364to the cursor position: the cursor position is too boring to store the
365history of, but the deaths counter is too \e{important}!
366
367\dt Information about recent changes to the game state:
331 368
332Another use for \c{game_ui} is to store highly persistent data such 369\dd This is used in Mines, for example, to indicate whether a
333as the Mines death counter. This is conceptually rather different: 370requested \q{flash} should be a white flash for victory or a red flash
334where the Net cursor position was \e{not important enough} to 371for defeat; see \k{writing-flash-types}.
335preserve for the player to restore by Undo, the Mines death counter
336is \e{too important} to permit the player to revert by Undo!
337 372
338A final use for \c{game_ui} is to pass information to the redraw 373\dt User preferences:
339function about recent changes to the game state. This is used in 374
340Mines, for example, to indicate whether a requested \q{flash} should 375\dd Any user preference about display or UI handled by
341be a white flash for victory or a red flash for defeat; see 376\cw{get_prefs()} and \cw{set_prefs()} will need to live in
342\k{writing-flash-types}. 377\c{game_ui}, because that's the structure that those functions access.
343 378
344\H{backend-simple} Simple data in the back end 379\H{backend-simple} Simple data in the back end
345 380
@@ -356,24 +391,41 @@ name will be used in window titles, in game selection menus on
356monolithic platforms, and anywhere else that the front end needs to 391monolithic platforms, and anywhere else that the front end needs to
357know the name of a game. 392know the name of a game.
358 393
359\S{backend-winhelp} \c{winhelp_topic} 394\S{backend-winhelp} \c{winhelp_topic} and \c{htmlhelp_topic}
360 395
361\c const char *winhelp_topic; 396\c const char *winhelp_topic, *htmlhelp_topic;
362 397
363This member is used on Windows only, to provide online help. 398These members are used on Windows only, to provide online help.
364Although the Windows front end provides a separate binary for each 399Although the Windows front end provides a separate binary for each
365puzzle, it has a single monolithic help file; so when a user selects 400puzzle, it has a single monolithic help file; so when a user selects
366\q{Help} from the menu, the program needs to open the help file and 401\q{Help} from the menu, the program needs to open the help file and
367jump to the chapter describing that particular puzzle. 402jump to the chapter describing that particular puzzle.
368 403
369Therefore, each chapter in \c{puzzles.but} is labelled with a 404This code base still supports the legacy \cw{.HLP} Windows Help format
370\e{help topic} name, similar to this: 405as well as the less old \cw{.CHM} HTML Help format. The two use
406different methods of identifying topics, so you have to specify both.
407
408Each chapter about a puzzle in \c{puzzles.but} is labelled with a
409\e{help topic} name for Windows Help, which typically appears just
410after the \cw{\\C} chapter title paragraph, similar to this:
371 411
412\c \C{net} \i{Net}
413\c
372\c \cfg{winhelp-topic}{games.net} 414\c \cfg{winhelp-topic}{games.net}
373 415
374And then the corresponding game back end encodes the topic string 416But HTML Help is able to use the Halibut identifier for the chapter
375(here \cq{games.net}) in the \c{winhelp_topic} element of the game 417itself, i.e. the keyword that appears in braces immediatey after the
376structure. 418\cw{\\C}.
419
420So the corresponding game back end encodes the \c{winhelp-topic}
421string (here \cq{games.net}) in the \c{winhelp_topic} element of the
422game structure, and puts the chapter identifier (here \cq{net}) in the
423\c{htmlhelp_topic} element. For example:
424
425\c const struct game thegame = {
426\c "Net", "games.net", "net",
427\c // ...
428\c };
377 429
378\H{backend-params} Handling game parameter sets 430\H{backend-params} Handling game parameter sets
379 431
@@ -439,8 +491,8 @@ from the game, and before passing it on to the front end.
439\c char *(*encode_params)(const game_params *params, bool full); 491\c char *(*encode_params)(const game_params *params, bool full);
440 492
441The job of this function is to take a \c{game_params}, and encode it 493The job of this function is to take a \c{game_params}, and encode it
442in a string form for use in game IDs. The return value must be a 494in a printable ASCII string form for use in game IDs. The return value must
443newly allocated C string, and \e{must} not contain a colon or a hash 495be a newly allocated C string, and \e{must} not contain a colon or a hash
444(since those characters are used to mark the end of the parameter 496(since those characters are used to mark the end of the parameter
445section in a game ID). 497section in a game ID).
446 498
@@ -454,7 +506,7 @@ away with commas, periods or underscores without causing anybody any
454major inconvenience. If you venture far beyond that, you're likely 506major inconvenience. If you venture far beyond that, you're likely
455to irritate \e{somebody}. 507to irritate \e{somebody}.
456 508
457(At the time of writing this, all existing games have purely 509(At the time of writing this, most existing games have purely
458alphanumeric string parameter formats. Usually these involve a 510alphanumeric string parameter formats. Usually these involve a
459letter denoting a parameter, followed optionally by a number giving 511letter denoting a parameter, followed optionally by a number giving
460the value of that parameter, with a few mandatory parts at the 512the value of that parameter, with a few mandatory parts at the
@@ -466,15 +518,17 @@ call to \cw{decode_params()} (\k{backend-decode-params}) will yield
466an identical structure. If \c{full} is \cw{false}, however, you 518an identical structure. If \c{full} is \cw{false}, however, you
467should leave out anything which is not necessary to describe a 519should leave out anything which is not necessary to describe a
468\e{specific puzzle instance}, i.e. anything which only takes effect 520\e{specific puzzle instance}, i.e. anything which only takes effect
469when a new puzzle is \e{generated}. For example, the Solo 521when a new puzzle is \e{generated}.
470\c{game_params} includes a difficulty rating used when constructing 522
471new puzzles; but a Solo game ID need not explicitly include the 523For example, the Solo \c{game_params} includes a difficulty rating
472difficulty, since to describe a puzzle once generated it's 524used when constructing new puzzles; but a Solo game ID need not
473sufficient to give the grid dimensions and the location and contents 525explicitly include the difficulty, since to describe a puzzle once
474of the clue squares. (Indeed, one might very easily type in a puzzle 526generated it's sufficient to give the grid dimensions and the location
475out of a newspaper without \e{knowing} what its difficulty level is 527and contents of the clue squares. (Indeed, one might very easily type
476in Solo's terminology.) Therefore, Solo's \cw{encode_params()} only 528in a puzzle out of a newspaper without \e{knowing} what its difficulty
477encodes the difficulty level if \c{full} is set. 529level is in Solo's terminology.) Therefore, Solo's
530\cw{encode_params()} only encodes the difficulty level if \c{full} is
531set.
478 532
479\S{backend-decode-params} \cw{decode_params()} 533\S{backend-decode-params} \cw{decode_params()}
480 534
@@ -489,7 +543,7 @@ to create a \e{new} \c{game_params}, but to modify an existing one.
489This function can receive a string which only encodes a subset of 543This function can receive a string which only encodes a subset of
490the parameters. The most obvious way in which this can happen is if 544the parameters. The most obvious way in which this can happen is if
491the string was constructed by \cw{encode_params()} with its \c{full} 545the string was constructed by \cw{encode_params()} with its \c{full}
492parameter set to \cw{FALSE}; however, it could also happen if the 546parameter set to \cw{false}; however, it could also happen if the
493user typed in a parameter set manually and missed something out. Be 547user typed in a parameter set manually and missed something out. Be
494prepared to deal with a wide range of possibilities. 548prepared to deal with a wide range of possibilities.
495 549
@@ -551,9 +605,10 @@ its initial value; the front end will modify the value fields and
551return the updated array to \cw{custom_params()} (see 605return the updated array to \cw{custom_params()} (see
552\k{backend-custom-params}). 606\k{backend-custom-params}).
553 607
554The \cw{config_item} structure contains the following elements: 608The \cw{config_item} structure contains the following elements used by
609this function:
555 610
556\c char *name; 611\c const char *name;
557\c int type; 612\c int type;
558\c union { /* type-specific fields */ } u; 613\c union { /* type-specific fields */ } u;
559\e iiiiiiiiiiiiiiiiiiiiiiiiii 614\e iiiiiiiiiiiiiiiiiiiiiiiiii
@@ -592,9 +647,7 @@ of the input box.
592 647
593For controls of this type, \c{u.boolean} contains a single field 648For controls of this type, \c{u.boolean} contains a single field
594 649
595\c int bval; 650\c bool bval;
596
597which is either \cw{TRUE} or \cw{FALSE}.
598 651
599} 652}
600 653
@@ -634,8 +687,8 @@ The array returned from this function is expected to have filled in
634the initial values of all the controls according to the input 687the initial values of all the controls according to the input
635\c{game_params} structure. 688\c{game_params} structure.
636 689
637If the game's \c{can_configure} flag is set to \cw{FALSE}, this 690If the game's \c{can_configure} flag is set to \cw{false}, this
638function is never called and need not do anything at all. 691function is never called and can be \cw{NULL}.
639 692
640\S{backend-custom-params} \cw{custom_params()} 693\S{backend-custom-params} \cw{custom_params()}
641 694
@@ -659,8 +712,63 @@ This function is not expected to (and indeed \e{must not}) free the
659input \c{config_item} array. (If the parameters fail to validate, 712input \c{config_item} array. (If the parameters fail to validate,
660the dialog box will stay open.) 713the dialog box will stay open.)
661 714
662If the game's \c{can_configure} flag is set to \cw{FALSE}, this 715If the game's \c{can_configure} flag is set to \cw{false}, this
663function is never called and need not do anything at all. 716function is never called and can be \cw{NULL}.
717
718\S{backend-get-prefs} \cw{get_prefs()}
719
720\c config_item *(*get_prefs)(game_ui *ui);
721
722This function works very like \cw{configure()}, but instead of
723receiving a \c{game_params} and returning GUI elements describing the
724data in it, this function receives a \c{game_ui} and returns GUI
725elements describing any user preferences stored in that.
726
727This function should only deal with fields of \c{game_ui} that are
728user-settable preferences. In-game state like cursor position and
729mouse drags, or per-game state like death counters, are nothing to do
730with this function.
731
732If there are no user preferences, you can set both this function
733pointer and \c{set_prefs} to \cw{NULL}.
734
735If you implement these functions, you must also ensure that your
736game's \cw{new_ui()} function can be called with a null \c{game_state}
737pointer. (See \k{backend-new-ui}.)
738
739In every \c{config_item} returned from this function, you must set an
740additional field beyond the ones described in \k{backend-configure}:
741
742\c const char *kw;
743
744This should be an identifying keyword for the user preference in
745question, suitable for use in configuration files. That means it
746should remain stable, even if the user-facing wording in the \c{name}
747field is reworded for clarity. If it doesn't stay stable, old
748configuration files will not be read correctly.
749
750For \c{config_item}s of type \cw{C_CHOICES}, you must also set an
751extra field in \c{u.choices}:
752
753\c const char *choicekws;
754
755This has the same structure as the \c{choicenames} field (a list of
756values delimited by the first character in the whole string), and it
757provides an identifying keyword for each individual choice in the
758list, in the same order as the entries of \c{choicenames}.
759
760\S{backend-set-prefs} \cw{set_prefs()}
761
762\c void (*set_prefs)(game_ui *ui, const config_item *cfg);
763
764This function is the counterpart to \cw{set_prefs()}, as
765\cw{custom_params()} is to \cw{configure()}. It receives an array of
766\c{config_item}s which was originally created by \cw{get_prefs()},
767with the controls' values updated from user input, and it should
768transcribe the new settings into the provided \c{game_ui}.
769
770If there are no user preferences, you can set both this function
771pointer and \c{get_prefs} to \cw{NULL}.
664 772
665\S{backend-validate-params} \cw{validate_params()} 773\S{backend-validate-params} \cw{validate_params()}
666 774
@@ -718,8 +826,8 @@ ensuring solubility and uniqueness as appropriate.
718 826
719As input it is given a \c{game_params} structure and a random state 827As input it is given a \c{game_params} structure and a random state
720(see \k{utils-random} for the random number API). It must invent a 828(see \k{utils-random} for the random number API). It must invent a
721puzzle instance, encode it in string form, and return a dynamically 829puzzle instance, encode it in printable ASCII string form, and
722allocated C string containing that encoding. 830return a dynamically allocated C string containing that encoding.
723 831
724Additionally, it may return a second dynamically allocated string in 832Additionally, it may return a second dynamically allocated string in
725\c{*aux}. (If it doesn't want to, then it can leave that parameter 833\c{*aux}. (If it doesn't want to, then it can leave that parameter
@@ -824,9 +932,17 @@ allocations contained within it.
824\c game_ui *(*new_ui)(const game_state *state); 932\c game_ui *(*new_ui)(const game_state *state);
825 933
826This function allocates and returns a new \c{game_ui} structure for 934This function allocates and returns a new \c{game_ui} structure for
827playing a particular puzzle. It is passed a pointer to the initial 935playing a particular puzzle.
828\c{game_state}, in case it needs to refer to that when setting up 936
829the initial values for the new game. 937Usually, this function is passed a pointer to the initial
938\c{game_state}, in case it needs to refer to that when setting up the
939initial values for the new game.
940
941However, if the puzzle defines \c{get_prefs()} and \c{set_prefs()}
942functions, then this function may also be called with
943\cw{state==NULL}. In this situation it must still allocate a
944\c{game_ui} which can be used by \c{get_prefs()} and \c{set_prefs()},
945although it need not be usable for actually playing a game.
830 946
831\S{backend-free-ui} \cw{free_ui()} 947\S{backend-free-ui} \cw{free_ui()}
832 948
@@ -840,8 +956,8 @@ allocations contained within it.
840\c char *(*encode_ui)(const game_ui *ui); 956\c char *(*encode_ui)(const game_ui *ui);
841 957
842This function encodes any \e{important} data in a \c{game_ui} 958This function encodes any \e{important} data in a \c{game_ui}
843structure in string form. It is only called when saving a 959structure in printable ASCII string form. It is only called when
844half-finished game to a file. 960saving a half-finished game to a file.
845 961
846It should be used sparingly. Almost all data in a \c{game_ui} is not 962It should be used sparingly. Almost all data in a \c{game_ui} is not
847important enough to save. The location of the keyboard-controlled 963important enough to save. The location of the keyboard-controlled
@@ -859,13 +975,25 @@ user could edit the save file by hand... But if the user is \e{that}
859determined to cheat, they could just as easily modify the game's 975determined to cheat, they could just as easily modify the game's
860source.) 976source.)
861 977
978The \cw{encode_ui()} function is optional. If a back-end doesn't need
979this function it can just set the pointer to \cw{NULL}.
980
862\S{backend-decode-ui} \cw{decode_ui()} 981\S{backend-decode-ui} \cw{decode_ui()}
863 982
864\c void (*decode_ui)(game_ui *ui, const char *encoding); 983\c void (*decode_ui)(game_ui *ui, const char *encoding,
984\c const game_state *state);
865 985
866This function parses a string previously output by \cw{encode_ui()}, 986This function parses a string previously output by \cw{encode_ui()},
867and writes the decoded data back into the provided \c{game_ui} 987and writes the decoded data back into the freshly-created \c{game_ui}
868structure. 988structure provided. If the string is invalid, the function should do
989the best it can, which might just mean not changing the \c{game_ui}
990structure at all. This might happen if a save file is corrupted, or
991simply from a newer version that encodes more \c{game_ui} data. The
992current \c{game_state} is provided in case the function needs to
993refer to it for validation.
994
995Like \cw{encode_ui()}, \cw{decode_ui()} is optional. If a back-end
996doesn't need this function it can just set the pointer to \cw{NULL}.
869 997
870\S{backend-changed-state} \cw{changed_state()} 998\S{backend-changed-state} \cw{changed_state()}
871 999
@@ -928,13 +1056,18 @@ puzzle's drawing area.
928pointer will be to read the game's tile size parameter in order to 1056pointer will be to read the game's tile size parameter in order to
929divide mouse coordinates by it.) 1057divide mouse coordinates by it.)
930 1058
931\cw{interpret_move()} may return in three different ways: 1059\cw{interpret_move()} may return in four different ways:
932 1060
933\b Returning \cw{NULL} indicates that no action whatsoever occurred 1061\b Returning \cw{MOVE_UNUSED} or \cw{MOVE_NO_EFFECT} indicates that no
934in response to the input event; the puzzle was not interested in it 1062action whatsoever occurred in response to the input event; the puzzle
935at all. 1063was not interested in it at all. The distinction between this is that
1064\cw{MOVE_NO_EFFECT} implies that the state of the game is what makes
1065the event uninteresting, while \cw{MOVE_NO_EFFECT} means that the
1066event is intrinsically uninteresting. For example, a mouse click on
1067an already-revealed square in Mines might return \cw{MOVE_NO_EFFECT}
1068while a click outside the board would return \cw{MOVE_UNUSED}.
936 1069
937\b Returning the special value \cw{UI_UPDATE} indicates that the input 1070\b Returning the special value \cw{MOVE_UI_UPDATE} indicates that the input
938event has resulted in a change being made to the \c{game_ui} which 1071event has resulted in a change being made to the \c{game_ui} which
939will require a redraw of the game window, but that no actual \e{move} 1072will require a redraw of the game window, but that no actual \e{move}
940was made (i.e. no new \c{game_state} needs to be created). 1073was made (i.e. no new \c{game_state} needs to be created).
@@ -942,8 +1075,8 @@ was made (i.e. no new \c{game_state} needs to be created).
942\b Returning anything else indicates that a move was made and that a 1075\b Returning anything else indicates that a move was made and that a
943new \c{game_state} must be created. However, instead of actually 1076new \c{game_state} must be created. However, instead of actually
944constructing a new \c{game_state} itself, this function is required 1077constructing a new \c{game_state} itself, this function is required
945to return a string description of the details of the move. This 1078to return a printable ASCII string description of the details of the
946string will be passed to \cw{execute_move()} 1079move. This string will be passed to \cw{execute_move()}
947(\k{backend-execute-move}) to actually create the new 1080(\k{backend-execute-move}) to actually create the new
948\c{game_state}. (Encoding moves as strings in this way means that 1081\c{game_state}. (Encoding moves as strings in this way means that
949the mid-end can keep the strings as well as the game states, and the 1082the mid-end can keep the strings as well as the game states, and the
@@ -952,7 +1085,8 @@ strings can be written to disk when saving the game and fed to
952 1085
953The return value from \cw{interpret_move()} is expected to be 1086The return value from \cw{interpret_move()} is expected to be
954dynamically allocated if and only if it is not either \cw{NULL} 1087dynamically allocated if and only if it is not either \cw{NULL}
955\e{or} the special string constant \c{UI_UPDATE}. 1088\e{or} one of the special string constants \cw{MOVE_UNUSED},
1089\cw{MOVE_NO_EFFECT}, or \cw{MOVE_UI_UPDATE}.
956 1090
957After this function is called, the back end is permitted to rely on 1091After this function is called, the back end is permitted to rely on
958some subsequent operations happening in sequence: 1092some subsequent operations happening in sequence:
@@ -999,19 +1133,21 @@ mouse button will have appeared in between.
999 1133
1000\dd Indicate that an arrow key was pressed. 1134\dd Indicate that an arrow key was pressed.
1001 1135
1002\dt \cw{CURSOR_SELECT} 1136\dt \cw{CURSOR_SELECT}, \cw{CURSOR_SELECT2}
1003 1137
1004\dd On platforms which have a prominent \q{select} button alongside 1138\dd On platforms which have one or two prominent \q{select} button
1005their cursor keys, indicates that that button was pressed. 1139alongside their cursor keys, indicates that one of those buttons was
1140pressed. On other platforms, these represent the Enter (or Return)
1141and Space keys respectively.
1006 1142
1007In addition, there are some modifiers which can be bitwise-ORed into 1143In addition, there are some modifiers which can be bitwise-ORed into
1008the \c{button} parameter: 1144the \c{button} parameter:
1009 1145
1010\dt \cw{MOD_CTRL}, \cw{MOD_SHFT} 1146\dt \cw{MOD_CTRL}, \cw{MOD_SHFT}
1011 1147
1012\dd These indicate that the Control or Shift key was pressed 1148\dd These indicate that the Control or Shift key was pressed alongside
1013alongside the key. They only apply to the cursor keys, not to mouse 1149the key. They only apply to the cursor keys and the ASCII horizontal
1014buttons or anything else. 1150tab character \cw{\\t}, not to mouse buttons or anything else.
1015 1151
1016\dt \cw{MOD_NUM_KEYPAD} 1152\dt \cw{MOD_NUM_KEYPAD}
1017 1153
@@ -1025,8 +1161,10 @@ input probably just wants to treat the numeric keypad as numbers).
1025\dt \cw{MOD_MASK} 1161\dt \cw{MOD_MASK}
1026 1162
1027\dd This mask is the bitwise OR of all the available modifiers; you 1163\dd This mask is the bitwise OR of all the available modifiers; you
1028can bitwise-AND with \cw{~MOD_MASK} to strip all the modifiers off 1164can bitwise-AND with \cw{~MOD_MASK} to strip all the modifiers off any
1029any input value. 1165input value; as this is a common operation, the
1166\cw{STRIP_BUTTON_MODIFIERS()} macro can do this for you (see
1167\k{utils-strip-button-modifiers}).
1030 1168
1031\S{backend-execute-move} \cw{execute_move()} 1169\S{backend-execute-move} \cw{execute_move()}
1032 1170
@@ -1058,7 +1196,8 @@ offer the \q{Solve} menu option.
1058\c const char *aux, const char **error); 1196\c const char *aux, const char **error);
1059 1197
1060This function is called when the user selects the \q{Solve} option 1198This function is called when the user selects the \q{Solve} option
1061from the menu. 1199from the menu. If \cw{can_solve} is \cw{false} then it will never
1200be called and can be \cw{NULL}.
1062 1201
1063It is passed two input game states: \c{orig} is the game state from 1202It is passed two input game states: \c{orig} is the game state from
1064the very start of the puzzle, and \c{curr} is the current one. 1203the very start of the puzzle, and \c{curr} is the current one.
@@ -1075,8 +1214,8 @@ it may return \cw{NULL}. If it does this, it must also set
1075\q{Solution not known for this puzzle}); that error message is not 1214\q{Solution not known for this puzzle}); that error message is not
1076expected to be dynamically allocated. 1215expected to be dynamically allocated.
1077 1216
1078If this function \e{does} produce a solution, it returns a move string 1217If this function \e{does} produce a solution, it returns a printable
1079suitable for feeding to \cw{execute_move()} 1218ASCII move string suitable for feeding to \cw{execute_move()}
1080(\k{backend-execute-move}). Like a (non-empty) string returned from 1219(\k{backend-execute-move}). Like a (non-empty) string returned from
1081\cw{interpret_move()}, the returned string should be dynamically 1220\cw{interpret_move()}, the returned string should be dynamically
1082allocated. 1221allocated.
@@ -1132,15 +1271,15 @@ requirement that the \q{tile size} be proportional to the game
1132window size. Window size is required to increase monotonically with 1271window size. Window size is required to increase monotonically with
1133\q{tile size}, however. 1272\q{tile size}, however.
1134 1273
1135The data element \c{preferred_tilesize} indicates the tile size 1274The data element \c{preferred_tilesize} indicates the tile size which
1136which should be used in the absence of a good reason to do otherwise 1275should be used in the absence of a good reason to do otherwise (such
1137(such as the screen being too small, or the user explicitly 1276as the screen being too small to fit the whole puzzle, or the user
1138requesting a resize if that ever gets implemented). 1277explicitly requesting a resize).
1139 1278
1140\S{backend-compute-size} \cw{compute_size()} 1279\S{backend-compute-size} \cw{compute_size()}
1141 1280
1142\c void (*compute_size)(const game_params *params, int tilesize, 1281\c void (*compute_size)(const game_params *params, int tilesize,
1143\c int *x, int *y); 1282\c const game_ui *ui, int *x, int *y);
1144 1283
1145This function is passed a \c{game_params} structure and a tile size. 1284This function is passed a \c{game_params} structure and a tile size.
1146It returns, in \c{*x} and \c{*y}, the size in pixels of the drawing 1285It returns, in \c{*x} and \c{*y}, the size in pixels of the drawing
@@ -1193,6 +1332,12 @@ end's default colour as their background, apart from a few which
1193depend on drawing relief highlights so they adjust the background 1332depend on drawing relief highlights so they adjust the background
1194colour if it's too light for highlights to show up against it. 1333colour if it's too light for highlights to show up against it.
1195 1334
1335The first colour in the list is slightly special. The mid-end fills
1336the drawing area with it before the first call to \cw{redraw()} (see
1337\k{backend-redraw}). Some front ends also use it fill the part of the
1338puzzle window outside the puzzle. This means that it is usually
1339sensible to make colour 0 the background colour for the puzzle.
1340
1196Note that the colours returned from this function are for 1341Note that the colours returned from this function are for
1197\e{drawing}, not for printing. Printing has an entirely different 1342\e{drawing}, not for printing. Printing has an entirely different
1198colour allocation policy. 1343colour allocation policy.
@@ -1275,7 +1420,7 @@ activity, so that the victory flash in Net is not cancelled by that
1275final locking move. 1420final locking move.
1276 1421
1277The input parameters to \cw{flash_length()} are exactly the same as 1422The input parameters to \cw{flash_length()} are exactly the same as
1278the ones to \cw{anim_length()}. 1423the ones to \cw{anim_length()}: see \k{backend-anim-length}.
1279 1424
1280Just like \cw{anim_length()}, when this function is called, it may 1425Just like \cw{anim_length()}, when this function is called, it may
1281rely on \cw{changed_state()} having been called previously, so if it 1426rely on \cw{changed_state()} having been called previously, so if it
@@ -1303,7 +1448,7 @@ containing the cursor (in games that have one), or other region of
1303interest. 1448interest.
1304 1449
1305This function is called by only 1450This function is called by only
1306\cw{midend_get_cursor_location()}(\k{midend-get-cursor-location}). Its 1451\cw{midend_get_cursor_location()} (\k{midend-get-cursor-location}). Its
1307purpose is to allow front ends to query the location of the backend's 1452purpose is to allow front ends to query the location of the backend's
1308cursor. With knowledge of this location, a front end can, for example, 1453cursor. With knowledge of this location, a front end can, for example,
1309ensure that the region of interest remains visible if the puzzle is 1454ensure that the region of interest remains visible if the puzzle is
@@ -1392,6 +1537,14 @@ that the animation has already been running. If \c{oldstate} is
1392\cw{NULL}, then \c{anim_time} is unused (and will hopefully be set 1537\cw{NULL}, then \c{anim_time} is unused (and will hopefully be set
1393to zero to avoid confusion). 1538to zero to avoid confusion).
1394 1539
1540\c{dir} specifies the chronological order of those states: if it is
1541positive, then the transition is the result of a move or a redo (and
1542so \c{newstate} is the later of the two moves), whereas if it is
1543negative then the transition is the result of an undo (so that
1544\c{newstate} is the \e{earlier} move). This allows move animations
1545that are not time-symmetric (such as Inertia, where gems are consumed
1546during the animation) to be drawn the right way round.
1547
1395\c{flash_time}, if it is is non-zero, denotes that the game is in 1548\c{flash_time}, if it is is non-zero, denotes that the game is in
1396the middle of a flash, and gives the time since the start of the 1549the middle of a flash, and gives the time since the start of the
1397flash. See \k{backend-flash-length} for general discussion of 1550flash. See \k{backend-flash-length} for general discussion of
@@ -1402,7 +1555,9 @@ The very first time this function is called for a new
1402area. Since this often involves drawing visual furniture which is 1555area. Since this often involves drawing visual furniture which is
1403never subsequently altered, it is often simplest to arrange this by 1556never subsequently altered, it is often simplest to arrange this by
1404having a special \q{first time} flag in the draw state, and 1557having a special \q{first time} flag in the draw state, and
1405resetting it after the first redraw. 1558resetting it after the first redraw. This function can assume that
1559the mid-end has filled the drawing area with colour 0 before the first
1560call.
1406 1561
1407When this function (or any subfunction) calls the drawing API, it is 1562When this function (or any subfunction) calls the drawing API, it is
1408expected to pass colour indices which were previously defined by the 1563expected to pass colour indices which were previously defined by the
@@ -1424,7 +1579,7 @@ Twiddle, inherently involve moving things around and so would not
1424make sense to print.) 1579make sense to print.)
1425 1580
1426If this flag is \cw{false}, then the functions \cw{print_size()} 1581If this flag is \cw{false}, then the functions \cw{print_size()}
1427and \cw{print()} will never be called. 1582and \cw{print()} will never be called and can be \cw{NULL}.
1428 1583
1429\S{backend-can-print-in-colour} \c{can_print_in_colour} 1584\S{backend-can-print-in-colour} \c{can_print_in_colour}
1430 1585
@@ -1440,18 +1595,20 @@ ignored.
1440 1595
1441\S{backend-print-size} \cw{print_size()} 1596\S{backend-print-size} \cw{print_size()}
1442 1597
1443\c void (*print_size)(const game_params *params, float *x, float *y); 1598\c void (*print_size)(const game_params *params, const game_ui *ui,
1599\c float *x, float *y);
1444 1600
1445This function is passed a \c{game_params} structure and a tile size. 1601This function is passed a \c{game_params} structure and a tile size.
1446It returns, in \c{*x} and \c{*y}, the preferred size in 1602It returns, in \c{*x} and \c{*y}, the preferred size in
1447\e{millimetres} of that puzzle if it were to be printed out on paper. 1603\e{millimetres} of that puzzle if it were to be printed out on paper.
1448 1604
1449If the \c{can_print} flag is \cw{FALSE}, this function will never be 1605If the \c{can_print} flag is \cw{false}, this function will never be
1450called. 1606called.
1451 1607
1452\S{backend-print} \cw{print()} 1608\S{backend-print} \cw{print()}
1453 1609
1454\c void (*print)(drawing *dr, const game_state *state, int tilesize); 1610\c void (*print)(drawing *dr, const game_state *state,
1611\c const game_ui *ui, int tilesize);
1455 1612
1456This function is called when a puzzle is to be printed out on paper. 1613This function is called when a puzzle is to be printed out on paper.
1457It should use the drawing API functions (see \k{drawing}) to print 1614It should use the drawing API functions (see \k{drawing}) to print
@@ -1500,7 +1657,7 @@ write
1500\c c = print_mono_colour(dr, 0); assert(c == COL_THIS); 1657\c c = print_mono_colour(dr, 0); assert(c == COL_THIS);
1501\c c = print_mono_colour(dr, 0); assert(c == COL_THAT); 1658\c c = print_mono_colour(dr, 0); assert(c == COL_THAT);
1502 1659
1503If the \c{can_print} flag is \cw{FALSE}, this function will never be 1660If the \c{can_print} flag is \cw{false}, this function will never be
1504called. 1661called.
1505 1662
1506\H{backend-misc} Miscellaneous 1663\H{backend-misc} Miscellaneous
@@ -1522,7 +1679,8 @@ just too difficult.
1522 1679
1523If this field is \cw{false}, the functions 1680If this field is \cw{false}, the functions
1524\cw{can_format_as_text_now()} (\k{backend-can-format-as-text-now}) 1681\cw{can_format_as_text_now()} (\k{backend-can-format-as-text-now})
1525and \cw{text_format()} (\k{backend-text-format}) are never called. 1682and \cw{text_format()} (\k{backend-text-format}) are never called
1683and can be \cw{NULL}.
1526 1684
1527\S{backend-can-format-as-text-now} \c{can_format_as_text_now()} 1685\S{backend-can-format-as-text-now} \c{can_format_as_text_now()}
1528 1686
@@ -1544,7 +1702,7 @@ game of exactly the same type is generated.
1544This function should not take into account aspects of the game 1702This function should not take into account aspects of the game
1545parameters which are not encoded by \cw{encode_params()} 1703parameters which are not encoded by \cw{encode_params()}
1546(\k{backend-encode-params}) when the \c{full} parameter is set to 1704(\k{backend-encode-params}) when the \c{full} parameter is set to
1547\cw{FALSE}. Such parameters will not necessarily match up between a 1705\cw{false}. Such parameters will not necessarily match up between a
1548call to this function and a subsequent call to \cw{text_format()} 1706call to this function and a subsequent call to \cw{text_format()}
1549itself. (For instance, game \e{difficulty} should not affect whether 1707itself. (For instance, game \e{difficulty} should not affect whether
1550the game can be copied to the clipboard. Only the actual visible 1708the game can be copied to the clipboard. Only the actual visible
@@ -1561,8 +1719,8 @@ ends.
1561 1719
1562This function will only ever be called if the back end field 1720This function will only ever be called if the back end field
1563\c{can_format_as_text_ever} (\k{backend-can-format-as-text-ever}) is 1721\c{can_format_as_text_ever} (\k{backend-can-format-as-text-ever}) is
1564\cw{TRUE} \e{and} the function \cw{can_format_as_text_now()} 1722\cw{true} \e{and} the function \cw{can_format_as_text_now()}
1565(\k{backend-can-format-as-text-now}) has returned \cw{TRUE} for the 1723(\k{backend-can-format-as-text-now}) has returned \cw{true} for the
1566currently selected game parameters. 1724currently selected game parameters.
1567 1725
1568The returned string may contain line endings (and will probably want 1726The returned string may contain line endings (and will probably want
@@ -1579,7 +1737,9 @@ whether that should come with a newline or not.)
1579 1737
1580This field is set to \cw{true} if the puzzle has a use for a textual 1738This field is set to \cw{true} if the puzzle has a use for a textual
1581status line (to display score, completion status, currently active 1739status line (to display score, completion status, currently active
1582tiles, etc). 1740tiles, etc). If the \c{redraw()} function ever intends to call
1741\c{status_bar()} in the drawing API (\k{drawing-status-bar}), then it
1742should set this flag to \c{true}.
1583 1743
1584\S{backend-is-timed} \c{is_timed} 1744\S{backend-is-timed} \c{is_timed}
1585 1745
@@ -1589,7 +1749,7 @@ This field is \cw{true} if the puzzle is time-critical. If
1589so, the mid-end will maintain a game timer while the user plays. 1749so, the mid-end will maintain a game timer while the user plays.
1590 1750
1591If this field is \cw{false}, then \cw{timing_state()} will never be 1751If this field is \cw{false}, then \cw{timing_state()} will never be
1592called and need not do anything. 1752called and can be \cw{NULL}.
1593 1753
1594\S{backend-timing-state} \cw{timing_state()} 1754\S{backend-timing-state} \cw{timing_state()}
1595 1755
@@ -1618,7 +1778,7 @@ the game size and the backspace character, \cw{\\b}, even though it
1618play the game. Each \cw{key_label} item contains the following fields: 1778play the game. Each \cw{key_label} item contains the following fields:
1619 1779
1620\c struct key_label { 1780\c struct key_label {
1621\c const char *label; /* label for frontend use */ 1781\c char *label; /* label for frontend use */
1622\c int button; /* button to pass to midend */ 1782\c int button; /* button to pass to midend */
1623\c } key_label; 1783\c } key_label;
1624 1784
@@ -1628,6 +1788,12 @@ the backend to \cw{NULL}, in which case the midend will instead call
1628label. The \cw{button} field is the associated code that can be passed 1788label. The \cw{button} field is the associated code that can be passed
1629to the midend when the frontend deems appropriate. 1789to the midend when the frontend deems appropriate.
1630 1790
1791If \cw{label} is not \cw{NULL}, then it's a dynamically allocated
1792string. Therefore, freeing an array of these structures needs more
1793than just a single free operatio. The function \c{free_keys()}
1794(\k{utils-free-keys}) can be used to free a whole array of these
1795structures conveniently.
1796
1631The backend should set \cw{*nkeys} to the number of elements in the 1797The backend should set \cw{*nkeys} to the number of elements in the
1632returned array. 1798returned array.
1633 1799
@@ -1640,6 +1806,44 @@ This function should not be called directly by frontends. Instead,
1640frontends should use \cw{midend_request_keys()} 1806frontends should use \cw{midend_request_keys()}
1641(\k{midend-request-keys}). 1807(\k{midend-request-keys}).
1642 1808
1809\S{backend-current-key-label} \cw{current_key_label()}
1810
1811\c const char *(*current_key_label)(const game_ui *ui,
1812\c const game_state *state,
1813\c int button);
1814
1815This function is called to ask the back-end how certain keys should be
1816labelled on platforms (such a feature phones) where this is
1817conventional.
1818These labels are expected to reflect what the keys will do right now,
1819so they can change depending on the game and UI state.
1820
1821The \c{ui} and \c{state} arguments describe the state of the game for
1822which key labels are required.
1823The \c{button} argument is the same as the one passed to
1824\cw{interpret_move()}.
1825At present, the only values of \c{button} that can be passed to
1826\cw{current_key_label()} are \cw{CURSOR_SELECT} and \cw{CURSOR_SELECT2}.
1827The return value is a short string describing what the requested key
1828will do if pressed.
1829Usually the string should be a static string constant.
1830If it's really necessary to use a dynamically-allocated string, it
1831should remain valid until the next call to \cw{current_key_label()} or
1832\cw{free_ui()} with the same \cw{game_ui} (so it can be referenced from
1833the \cw{game_ui} and freed at the next one of those calls).
1834
1835There's no fixed upper limit on the length of string that this
1836function can return, but more than about 12 characters is likely to
1837cause problems for front-ends. If two buttons have the same effect,
1838their labels should be identical so that the front end can detect
1839this. Similarly, keys that do different things should have different
1840labels. The label should be an empty string (\cw{""}) if the key does
1841nothing.
1842
1843Like \cw{request_keys()}, the \cw{current_key_label} pointer in the
1844\c{game} structure is allowed to be \cw{NULL}, in which case the
1845mid-end will treat it as though it always returned \cw{""}.
1846
1643\S{backend-flags} \c{flags} 1847\S{backend-flags} \c{flags}
1644 1848
1645\c int flags; 1849\c int flags;
@@ -1754,12 +1958,13 @@ whatever it was you needed to do.
1754\C{drawing} The drawing API 1958\C{drawing} The drawing API
1755 1959
1756The back end function \cw{redraw()} (\k{backend-redraw}) is required 1960The back end function \cw{redraw()} (\k{backend-redraw}) is required
1757to draw the puzzle's graphics on the window's drawing area, or on 1961to draw the puzzle's graphics on the window's drawing area. The back
1758paper if the puzzle is printable. To do this portably, it is 1962end function \cw{print()} similarly draws the puzzle on paper, if the
1759provided with a drawing API allowing it to talk directly to the 1963puzzle is printable. To do this portably, the back end is provided
1760front end. In this chapter I document that API, both for the benefit 1964with a drawing API allowing it to talk directly to the front end. In
1761of back end authors trying to use it and for front end authors 1965this chapter I document that API, both for the benefit of back end
1762trying to implement it. 1966authors trying to use it and for front end authors trying to implement
1967it.
1763 1968
1764The drawing API as seen by the back end is a collection of global 1969The drawing API as seen by the back end is a collection of global
1765functions, each of which takes a pointer to a \c{drawing} structure 1970functions, each of which takes a pointer to a \c{drawing} structure
@@ -1911,6 +2116,22 @@ implement it, since it is actually implemented centrally (in
1911 2116
1912This function may be used for both drawing and printing. 2117This function may be used for both drawing and printing.
1913 2118
2119\S{drawing-draw-rect-corner} \cw{draw_rect_corners()}
2120
2121\c void draw_rect_corners(drawing *dr, int cx, int cy, int r, int col);
2122
2123Draws four L-shapes at the corners of a square, in the manner of a
2124target reticule. This is a convenience function for back ends to use
2125to display a keyboard cursor (if they want one in that style).
2126
2127\c{cx} and \c{cy} give the coordinates of the centre of the square.
2128\c{r} is half the side length of the square, so that the corners are
2129at \cw{(cx-r,cy-r)}, \cw{(cx+r,cy-r)}, \cw{(cx-r,cy+r)} and
2130\cw{(cx+r,cy+r)}.
2131
2132\c{colour} is an integer index into the colours array returned by
2133the back end function \cw{colours()} (\k{backend-colours}).
2134
1914\S{drawing-draw-line} \cw{draw_line()} 2135\S{drawing-draw-line} \cw{draw_line()}
1915 2136
1916\c void draw_line(drawing *dr, int x1, int y1, int x2, int y2, 2137\c void draw_line(drawing *dr, int x1, int y1, int x2, int y2,
@@ -1935,7 +2156,7 @@ This function may be used for both drawing and printing.
1935 2156
1936\S{drawing-draw-polygon} \cw{draw_polygon()} 2157\S{drawing-draw-polygon} \cw{draw_polygon()}
1937 2158
1938\c void draw_polygon(drawing *dr, int *coords, int npoints, 2159\c void draw_polygon(drawing *dr, const int *coords, int npoints,
1939\c int fillcolour, int outlinecolour); 2160\c int fillcolour, int outlinecolour);
1940 2161
1941Draws an outlined or filled polygon in the puzzle window. 2162Draws an outlined or filled polygon in the puzzle window.
@@ -2133,6 +2354,7 @@ multiplication sign (U+00D7 in Unicode, represented by the bytes C3
2133\c static const char *const times_signs[] = { "\xC3\x97", "x" }; 2354\c static const char *const times_signs[] = { "\xC3\x97", "x" };
2134\c char *times_sign = text_fallback(dr, times_signs, 2); 2355\c char *times_sign = text_fallback(dr, times_signs, 2);
2135\c sprintf(buffer, "%d%s%d", width, times_sign, height); 2356\c sprintf(buffer, "%d%s%d", width, times_sign, height);
2357\c sfree(times_sign);
2136\c draw_text(dr, x, y, font, size, align, colour, buffer); 2358\c draw_text(dr, x, y, font, size, align, colour, buffer);
2137\c sfree(buffer); 2359\c sfree(buffer);
2138 2360
@@ -2211,8 +2433,9 @@ modify the buffer after use.
2211 2433
2212(This function is not exactly a \e{drawing} function, but it shares 2434(This function is not exactly a \e{drawing} function, but it shares
2213with the drawing API the property that it may only be called from 2435with the drawing API the property that it may only be called from
2214within the back end redraw function, so this is as good a place as 2436within the back end redraw function. And it's implemented by front
2215any to document it.) 2437ends via the \c{drawing_api} function pointer table. So this is the
2438best place to document it.)
2216 2439
2217The supplied text is filtered through the mid-end for optional 2440The supplied text is filtered through the mid-end for optional
2218rewriting before being passed on to the front end; the mid-end will 2441rewriting before being passed on to the front end; the mid-end will
@@ -2497,7 +2720,7 @@ function; see \k{drawing-draw-line}.
2497 2720
2498\S{drawingapi-draw-polygon} \cw{draw_polygon()} 2721\S{drawingapi-draw-polygon} \cw{draw_polygon()}
2499 2722
2500\c void (*draw_polygon)(void *handle, int *coords, int npoints, 2723\c void (*draw_polygon)(void *handle, const int *coords, int npoints,
2501\c int fillcolour, int outlinecolour); 2724\c int fillcolour, int outlinecolour);
2502 2725
2503This function behaves exactly like the back end \cw{draw_polygon()} 2726This function behaves exactly like the back end \cw{draw_polygon()}
@@ -2750,6 +2973,17 @@ Implementations of this API which do not provide printing services
2750may define this function pointer to be \cw{NULL}; it will never be 2973may define this function pointer to be \cw{NULL}; it will never be
2751called unless printing is attempted. 2974called unless printing is attempted.
2752 2975
2976\S{drawingapi-line-dotted} \cw{line_dotted()}
2977
2978\c void (*line_dotted)(void *handle, bool dotted);
2979
2980This function is called to toggle drawing of dotted lines, during
2981printing only.
2982
2983Implementations of this API which do not provide printing services
2984may define this function pointer to be \cw{NULL}; it will never be
2985called unless printing is attempted.
2986
2753\S{drawingapi-text-fallback} \cw{text_fallback()} 2987\S{drawingapi-text-fallback} \cw{text_fallback()}
2754 2988
2755\c char *(*text_fallback)(void *handle, const char *const *strings, 2989\c char *(*text_fallback)(void *handle, const char *const *strings,
@@ -2796,16 +3030,17 @@ the front end.
2796 3030
2797\S{drawing-print-get-colour} \cw{print_get_colour()} 3031\S{drawing-print-get-colour} \cw{print_get_colour()}
2798 3032
2799\c void print_get_colour(drawing *dr, int colour, int printincolour, 3033\c void print_get_colour(drawing *dr, int colour,
2800\c int *hatch, float *r, float *g, float *b) 3034\c bool printing_in_colour,
3035\c int *hatch, float *r, float *g, float *b);
2801 3036
2802This function is called by the implementations of the drawing API 3037This function is called by the implementations of the drawing API
2803functions when they are called in a printing context. It takes a 3038functions when they are called in a printing context. It takes a
2804colour index as input, and returns the description of the colour as 3039colour index as input, and returns the description of the colour as
2805requested by the back end. 3040requested by the back end.
2806 3041
2807\c{printincolour} is \cw{TRUE} iff the implementation is printing in 3042\c{printing_in_colour} is \cw{true} iff the implementation is printing
2808colour. This will alter the results returned if the colour in 3043in colour. This will alter the results returned if the colour in
2809question was specified with a black-and-white fallback value. 3044question was specified with a black-and-white fallback value.
2810 3045
2811If the colour should be rendered by hatching, \c{*hatch} is filled 3046If the colour should be rendered by hatching, \c{*hatch} is filled
@@ -2835,7 +3070,7 @@ puzzle window.
2835\H{midend-new} \cw{midend_new()} 3070\H{midend-new} \cw{midend_new()}
2836 3071
2837\c midend *midend_new(frontend *fe, const game *ourgame, 3072\c midend *midend_new(frontend *fe, const game *ourgame,
2838\c const drawing_api *drapi, void *drhandle) 3073\c const drawing_api *drapi, void *drhandle);
2839 3074
2840Allocates and returns a new mid-end structure. 3075Allocates and returns a new mid-end structure.
2841 3076
@@ -2898,7 +3133,8 @@ when finished with by passing it to the game's own
2898 3133
2899\H{midend-size} \cw{midend_size()} 3134\H{midend-size} \cw{midend_size()}
2900 3135
2901\c void midend_size(midend *me, int *x, int *y, bool user_size); 3136\c void midend_size(midend *me, int *x, int *y,
3137\c bool user_size, double device_pixel_ratio);
2902 3138
2903Tells the mid-end to figure out its window size. 3139Tells the mid-end to figure out its window size.
2904 3140
@@ -2926,7 +3162,7 @@ by the user. Use this option if you want your front end to support
2926dynamic resizing of the puzzle window with automatic scaling of the 3162dynamic resizing of the puzzle window with automatic scaling of the
2927puzzle to fit. 3163puzzle to fit.
2928 3164
2929If \c{user_size} is set to \cw{FALSE}, then the game's tile size 3165If \c{user_size} is set to \cw{false}, then the game's tile size
2930will never go over its preferred one, although it may go under in 3166will never go over its preferred one, although it may go under in
2931order to fit within the maximum bounds specified by \c{*x} and 3167order to fit within the maximum bounds specified by \c{*x} and
2932\c{*y}. This is the recommended approach when opening a new window 3168\c{*y}. This is the recommended approach when opening a new window
@@ -2955,6 +3191,24 @@ to use scroll bars for large puzzles), you can pass dimensions of
2955\cw{INT_MAX} as input to this function. You should probably not do 3191\cw{INT_MAX} as input to this function. You should probably not do
2956that \e{and} set the \c{user_size} flag, though! 3192that \e{and} set the \c{user_size} flag, though!
2957 3193
3194The \cw{device_pixel_ratio} allows the front end to specify that its
3195pixels are unusually large or small (or should be treated as such).
3196The mid-end uses this to adjust the tile size, both at startup (if the
3197ratio is not 1) and if the ratio changes.
3198
3199A \cw{device_pixel_ratio} of 1 indicates normal-sized pixels.
3200\q{Normal} is not precisely defined, but it's about 4 pixels per
3201millimetre on a screen designed to be viewed from a metre away, or a
3202size such that text 15 pixels high is comfortably readable. Some
3203platforms have a concept of a logical pixel that this can be mapped
3204onto. For instance, Cascading Style Sheets (CSS) has a unit called
3205\cq{px} that only matches physical pixels at a \cw{device_pixel_ratio}
3206of 1.
3207
3208The \cw{device_pixel_ratio} indicates the number of physical pixels in
3209a normal-sized pixel, so values less than 1 indicate unusually large
3210pixels and values greater than 1 indicate unusually small pixels.
3211
2958The midend relies on the frontend calling \cw{midend_new_game()} 3212The midend relies on the frontend calling \cw{midend_new_game()}
2959(\k{midend-new-game}) before calling \cw{midend_size()}. 3213(\k{midend-new-game}) before calling \cw{midend_size()}.
2960 3214
@@ -2972,7 +3226,7 @@ the puzzle configuration changes. If you \e{don't} want that, e.g. if
2972you want to provide a command to explicitly reset the puzzle size back 3226you want to provide a command to explicitly reset the puzzle size back
2973to its default, then you can call this just before calling 3227to its default, then you can call this just before calling
2974\cw{midend_size()} (which, in turn, you would probably call with 3228\cw{midend_size()} (which, in turn, you would probably call with
2975\c{user_size} set to \cw{FALSE}). 3229\c{user_size} set to \cw{false}).
2976 3230
2977\H{midend-new-game} \cw{midend_new_game()} 3231\H{midend-new-game} \cw{midend_new_game()}
2978 3232
@@ -3039,14 +3293,19 @@ call to this function. Some back ends require that \cw{midend_size()}
3039 3293
3040\H{midend-process-key} \cw{midend_process_key()} 3294\H{midend-process-key} \cw{midend_process_key()}
3041 3295
3042\c bool midend_process_key(midend *me, int x, int y, int button); 3296\c int midend_process_key(midend *me, int x, int y, int button)
3297
3298The front end calls this function to report a mouse or keyboard event.
3299The parameters \c{x} and \c{y} are identical to the ones passed to the
3300back end function \cw{interpret_move()} (\k{backend-interpret-move}).
3043 3301
3044The front end calls this function to report a mouse or keyboard 3302\c{button} is similar to the parameter passed to
3045event. The parameters \c{x}, \c{y} and \c{button} are almost 3303\cw{interpret_move()}. However, the midend is more relaxed about
3046identical to the ones passed to the back end function 3304values passed to in, and some additional special button values
3047\cw{interpret_move()} (\k{backend-interpret-move}), except that the 3305are defined for the front end to pass to the midend (see below).
3048front end is \e{not} required to provide the guarantees about mouse 3306
3049event ordering. The mid-end will sort out multiple simultaneous 3307Also, the front end is \e{not} required to provide guarantees about
3308mouse event ordering. The mid-end will sort out multiple simultaneous
3050button presses and changes of button; the front end's responsibility 3309button presses and changes of button; the front end's responsibility
3051is simply to pass on the mouse events it receives as accurately as 3310is simply to pass on the mouse events it receives as accurately as
3052possible. 3311possible.
@@ -3072,10 +3331,71 @@ Calling this function is very likely to result in calls back to the
3072front end's drawing API and/or \cw{activate_timer()} 3331front end's drawing API and/or \cw{activate_timer()}
3073(\k{frontend-activate-timer}). 3332(\k{frontend-activate-timer}).
3074 3333
3075The return value from \cw{midend_process_key()} is \cw{true} unless 3334The return value from \cw{midend_process_key()} is one of the
3076the effect of the keypress was to request termination of the program. 3335following constants:
3077A front end should shut down the puzzle in response to a \cw{false} 3336
3078return. 3337\dt \cw{PKR_QUIT}
3338
3339\dd Means that the effect of the keypress was to request termination
3340of the program. A front end should shut down the puzzle in response
3341to a \cw{PKR_QUIT} return.
3342
3343\dt \cw{PKR_SOME_EFFECT}
3344
3345\dd The keypress had some other effect, either in the mid-end or in
3346the puzzle itself.
3347
3348\dt \cw{PKR_NO_EFFECT}
3349
3350\dd The keypress had no effect, but might have had an effect in
3351slightly different circumstances. For instance it requested a move
3352that wasn't possible.
3353
3354\dt \cw{PKR_UNUSED}
3355
3356\dd The key was one that neither the mid-end nor the back-end has any
3357use for at all.
3358
3359A front end might respond to the last value by passing the key on to
3360something else that might be interested in it.
3361
3362The following additional values of \c{button} are permitted to be
3363passed to this function by the front end, but are never passed on to
3364the back end. They indicate front-end specific UI operations, such as
3365selecting an option from a drop-down menu. (Otherwise the front end
3366would have to translate the \q{New Game} menu item into an \cq{n}
3367keypress, for example.)
3368
3369\dt \cw{UI_NEWGAME}
3370
3371\dd Indicates that the user requested a new game, similar to pressing
3372\cq{n}.
3373
3374\dt \cw{UI_SOLVE}
3375
3376\dd Indicates that the user requested the solution of the current game.
3377
3378\dt \cw{UI_UNDO}
3379
3380\dd Indicates that the user attempted to undo a move.
3381
3382\dt \cw{UI_REDO}
3383
3384\dd Indicates that the user attempted to redo an undone move.
3385
3386\dt \cw{UI_QUIT}
3387
3388\dd Indicates that the user asked to quit the game. (Of course, a
3389front end might perfectly well handle this on its own. But including
3390it in this enumeration allows the front end to treat all these menu
3391items the same, by translating each of them into a button code passed
3392to the midend, and handle quitting by noticing the \c{false} return
3393value from \cw{midend_process_key()}.)
3394
3395The midend tolerates any modifier being set on any key and removes
3396them as necessary before passing the key on to the backend. It will
3397also handle translating printable characters combined with
3398\cw{MOD_CTRL} into control characters.
3079 3399
3080\H{midend-request-keys} \cw{midend_request_keys()} 3400\H{midend-request-keys} \cw{midend_request_keys()}
3081 3401
@@ -3089,6 +3409,20 @@ labels (i.e. the \cw{key_label} items that have their \cw{label}
3089fields set to \cw{NULL}) by using \cw{button2label()} 3409fields set to \cw{NULL}) by using \cw{button2label()}
3090(\k{utils-button2label}). 3410(\k{utils-button2label}).
3091 3411
3412\H{midend-current-key-label} \cw{midend_current_key_label()}
3413
3414\c const char *midend_current_key_label(midend *me, int button);
3415
3416This is a thin wrapper around the backend's \cw{current_key_label()}
3417function (\k{backend-current-key-label}). Front ends that need to
3418label \cw{CURSOR_SELECT} or \cw{CURSOR_SELECT2} should call this
3419function after each move (at least after each call to
3420\cw{midend_process_key()}) to get the current labels. The front end
3421should arrange to copy the returned string somewhere before the next
3422call to the mid-end, just in case it's dynamically allocated. If the
3423button supplied does nothing, the label returned will be an empty
3424string.
3425
3092\H{midend-colours} \cw{midend_colours()} 3426\H{midend-colours} \cw{midend_colours()}
3093 3427
3094\c float *midend_colours(midend *me, int *ncolours); 3428\c float *midend_colours(midend *me, int *ncolours);
@@ -3232,6 +3566,17 @@ viewing the existing one). The mid-end generates this dialog box
3232description itself. This should be used when the user selects 3566description itself. This should be used when the user selects
3233\q{Random Seed} from the game menu (or equivalent). 3567\q{Random Seed} from the game menu (or equivalent).
3234 3568
3569\dt \cw{CFG_PREFS}
3570
3571\dd Requests a box suitable for configuring user preferences.
3572
3573(An additional value \cw{CFG_FRONTEND_SPECIFIC} is provided in this
3574enumeration, so that frontends can extend it for their own internal
3575use. For example, you might wrap this function with a
3576\cw{frontend_get_config} which handles some values of \c{which} itself
3577and hands others on to the midend, depending on whether \cw{which <
3578CFG_FRONTEND_SPECIFIC}.)
3579
3235The returned value is an array of \cw{config_item}s, exactly as 3580The returned value is an array of \cw{config_item}s, exactly as
3236described in \k{backend-configure}. Another returned value is an 3581described in \k{backend-configure}. Another returned value is an
3237ASCII string giving a suitable title for the configuration window, 3582ASCII string giving a suitable title for the configuration window,
@@ -3292,7 +3637,7 @@ using \cw{midend_size()} and eventually case a refresh using
3292 3637
3293\H{midend-get-game-id} \cw{midend_get_game_id()} 3638\H{midend-get-game-id} \cw{midend_get_game_id()}
3294 3639
3295\c char *midend_get_game_id(midend *me) 3640\c char *midend_get_game_id(midend *me);
3296 3641
3297Returns a descriptive game ID (i.e. one in the form 3642Returns a descriptive game ID (i.e. one in the form
3298\cq{params:description}) describing the game currently active in the 3643\cq{params:description}) describing the game currently active in the
@@ -3300,7 +3645,7 @@ mid-end. The returned string is dynamically allocated.
3300 3645
3301\H{midend-get-random-seed} \cw{midend_get_random_seed()} 3646\H{midend-get-random-seed} \cw{midend_get_random_seed()}
3302 3647
3303\c char *midend_get_random_seed(midend *me) 3648\c char *midend_get_random_seed(midend *me);
3304 3649
3305Returns a random game ID (i.e. one in the form \cq{params#seedstring}) 3650Returns a random game ID (i.e. one in the form \cq{params#seedstring})
3306describing the game currently active in the mid-end, if there is one. 3651describing the game currently active in the mid-end, if there is one.
@@ -3309,6 +3654,9 @@ currently exist and this function will return \cw{NULL}.
3309 3654
3310The returned string, if it is non-\cw{NULL}, is dynamically allocated. 3655The returned string, if it is non-\cw{NULL}, is dynamically allocated.
3311 3656
3657Unlike the descriptive game ID, the random seed can contain characters
3658outside the printable ASCII set.
3659
3312\H{midend-can-format-as-text-now} \cw{midend_can_format_as_text_now()} 3660\H{midend-can-format-as-text-now} \cw{midend_can_format_as_text_now()}
3313 3661
3314\c bool midend_can_format_as_text_now(midend *me); 3662\c bool midend_can_format_as_text_now(midend *me);
@@ -3327,8 +3675,8 @@ Formats the current game's current state as ASCII text suitable for
3327copying to the clipboard. The returned string is dynamically 3675copying to the clipboard. The returned string is dynamically
3328allocated. 3676allocated.
3329 3677
3330If the game's \c{can_format_as_text_ever} flag is \cw{FALSE}, or if 3678If the game's \c{can_format_as_text_ever} flag is \cw{false}, or if
3331its \cw{can_format_as_text_now()} function returns \cw{FALSE}, then 3679its \cw{can_format_as_text_now()} function returns \cw{false}, then
3332this function will return \cw{NULL}. 3680this function will return \cw{NULL}.
3333 3681
3334If the returned string contains multiple lines (which is likely), it 3682If the returned string contains multiple lines (which is likely), it
@@ -3420,6 +3768,8 @@ visually activate and deactivate a redo button.
3420Calling this function causes the mid-end to convert its entire 3768Calling this function causes the mid-end to convert its entire
3421internal state into a long ASCII text string, and to pass that 3769internal state into a long ASCII text string, and to pass that
3422string (piece by piece) to the supplied \c{write} function. 3770string (piece by piece) to the supplied \c{write} function.
3771The string will consist of printable ASCII characters and line
3772feeds.
3423 3773
3424Desktop implementations can use this function to save a game in any 3774Desktop implementations can use this function to save a game in any
3425state (including half-finished) to a disk file, by supplying a 3775state (including half-finished) to a disk file, by supplying a
@@ -3474,6 +3824,32 @@ application is a monolithic one containing all the puzzles. See
3474identify a save file before you instantiate your mid-end in the first 3824identify a save file before you instantiate your mid-end in the first
3475place. 3825place.
3476 3826
3827\H{midend-save-prefs} \cw{midend_save_prefs()}
3828
3829\c void midend_save_prefs(
3830\c midend *me, void (*write)(void *ctx, const void *buf, int len),
3831\c void *wctx);
3832
3833Calling this function causes the mid-end to write out the states of
3834all user-settable preference options, including its own cross-platform
3835preferences and ones exported by a particular game via
3836\cw{get_prefs()} and \cw{set_prefs()} (\k{backend-get-prefs},
3837\k{backend-set-prefs}). The output is a textual format suitable for
3838writing into a configuration file on disk.
3839
3840The \c{write} and \c{wctx} parameters have the same semantics as for
3841\cw{midend_serialise()} (\k{midend-serialise}).
3842
3843\H{midend-load-prefs} \cw{midend_load_prefs()}
3844
3845\c const char *midend_load_prefs(
3846\c midend *me, bool (*read)(void *ctx, void *buf, int len),
3847\c void *rctx);
3848
3849This function is used to load a configuration file in the same format
3850emitted by \cw{midend_save_prefs()}, and import all the preferences
3851described in the file into the current mid-end.
3852
3477\H{identify-game} \cw{identify_game()} 3853\H{identify-game} \cw{identify_game()}
3478 3854
3479\c const char *identify_game(char **name, 3855\c const char *identify_game(char **name,
@@ -3524,6 +3900,13 @@ so I make it a callback rather than a static function in order to
3524relieve most front ends of the need to provide an empty 3900relieve most front ends of the need to provide an empty
3525implementation. 3901implementation.
3526 3902
3903\H{midend-which-game} \cw{midend_which_game()}
3904
3905\c const game *midend_which_preset(midend *me);
3906
3907This function returns the \c{game} structure for the puzzle type this
3908midend is committed to.
3909
3527\H{frontend-backend} Direct reference to the back end structure by 3910\H{frontend-backend} Direct reference to the back end structure by
3528the front end 3911the front end
3529 3912
@@ -3685,7 +4068,7 @@ printable ASCII, or NUL-terminated strings, or anything like that.
3685 4068
3686Allocates a new \c{random_state}, copies the contents of another 4069Allocates a new \c{random_state}, copies the contents of another
3687\c{random_state} into it, and returns the new state. If exactly the 4070\c{random_state} into it, and returns the new state. If exactly the
3688same sequence of functions is subseqently called on both the copy and 4071same sequence of functions is subsequently called on both the copy and
3689the original, the results will be identical. This may be useful for 4072the original, the results will be identical. This may be useful for
3690speculatively performing some operation using a given random state, 4073speculatively performing some operation using a given random state,
3691and later replaying that operation precisely. 4074and later replaying that operation precisely.
@@ -3707,7 +4090,8 @@ should be between 1 and 32 inclusive.
3707 4090
3708\c unsigned long random_upto(random_state *state, unsigned long limit); 4091\c unsigned long random_upto(random_state *state, unsigned long limit);
3709 4092
3710Returns a random number from 0 to \cw{limit-1} inclusive. 4093Returns a random number from 0 to \cw{limit-1} inclusive. \c{limit}
4094may not be zero.
3711 4095
3712\S{utils-random-state-encode} \cw{random_state_encode()} 4096\S{utils-random-state-encode} \cw{random_state_encode()}
3713 4097
@@ -3890,6 +4274,16 @@ dynamically allocated.
3890(See \k{backend-configure} for details of the \c{config_item} 4274(See \k{backend-configure} for details of the \c{config_item}
3891structure.) 4275structure.)
3892 4276
4277\S{utils-free-keys} \cw{free_keys()}
4278
4279\c void free_keys(key_label *keys, int nkeys);
4280
4281This function correctly frees an array of \c{key_label}s, including
4282the dynamically allocated label string for each key.
4283
4284(See \k{backend-request-keys} for details of the \c{key_label}
4285structure.)
4286
3893\H{utils-tree234} Sorted and counted tree functions 4287\H{utils-tree234} Sorted and counted tree functions
3894 4288
3895Many games require complex algorithms for generating random puzzles, 4289Many games require complex algorithms for generating random puzzles,
@@ -4206,19 +4600,422 @@ element. That function has the prototype
4206and every time it is called, the \c{state} parameter will be set to 4600and every time it is called, the \c{state} parameter will be set to
4207the value you passed in as \c{copyfnstate}. 4601the value you passed in as \c{copyfnstate}.
4208 4602
4603\H{utils-dsf} Disjoint set forests
4604
4605This section describes a set of functions implementing the data
4606structure variously known as \q{union-find} or \q{Tarjan's disjoint
4607set forest}. In this code base, it's universally abbreviated as a
4608\q{dsf}.
4609
4610A dsf represents a collection of elements partitioned into
4611\q{equivalence classes}, in circumstances where equivalences are added
4612incrementally. That is, all elements start off considered to be
4613different, and you gradually declare more and more of them to be equal
4614via the \cw{dsf_merge()} operation, which says that two particular
4615elements should be regarded as equal from now on.
4616
4617For example, if I start off with A,B,U,V all distinct, and I merge A
4618with B and merge U with V, then the structure will tell me that A and
4619U are not equivalent. But if I then merge B with V, then after that,
4620the structure will tell me that A and U \e{are} equivalent, by
4621following the transitive chain of equivalences it knows about.
4622
4623The dsf data structure is therefore ideal for tracking incremental
4624connectivity in an undirected graph (again, \q{incremental} meaning
4625that you only ever add edges, never delete them), and other
4626applications in which you gradually acquire knowledge you didn't
4627previously have about what things are the same as each other. It's
4628used extensively in puzzle solver and generator algorithms, and
4629sometimes during gameplay as well.
4630
4631The time complexity of dsf operations is not \e{quite} constant time,
4632in theory, but it's so close to it as to make no difference in
4633practice. In particular, any time a dsf has to do non-trivial work, it
4634updates the structure so that that work won't be needed a second time.
4635Use dsf operations without worrying about how long they take!
4636
4637For some puzzle-game applications, it's useful to augment this data
4638structure with extra information about how the elements of an
4639equivalence class relate to each other. There's more than one way you
4640might do this; the one supported here is useful in cases where the
4641objects you're tracking are going to end up in one of two states (say,
4642black/white, or on/off), and for any two objects you either know that
4643they're in the same one of those states, or you know they're in
4644opposite states, or you don't know which yet. Puzzles calls this a
4645\q{flip dsf}: it tracks whether objects in the same equivalence class
4646are flipped relative to each other.
4647
4648As well as querying whether two elements are equivalent, this dsf
4649implementation also allows you to ask for the number of elements in a
4650given equivalence class, and the smallest element in the class. (The
4651latter is used, for example, to decide which square to print the clue
4652in each region of a Keen puzzle.)
4653
4654\S{utils-dsf-new} \cw{dsf_new()}, \cw{dsf_new_flip()}, \cw{dsf_new_min()}
4655
4656\c DSF *dsf_new(int size);
4657\c DSF *dsf_new_flip(int size);
4658\c DSF *dsf_new_min(int size);
4659
4660Each of these functions allocates space for a dsf describing \c{size}
4661elements, and initialises it so that every element is in an
4662equivalence class by itself.
4663
4664The elements described by the dsf are represented by the integers from
4665\cw{0} to \cw{size-1} inclusive.
4666
4667\cw{dsf_new_flip()} will create a dsf which has the extra ability to
4668track whether objects in the same equivalence class are flipped
4669relative to each other.
4670
4671\cw{dsf_new_min()} will create a dsf which has the extra ability to
4672track the smallest element of each equivalence class.
4673
4674The returned object from any of these functions must be freed using
4675\cw{dsf_free()}.
4676
4677\S{utils-dsf-free} \cw{dsf_free()}
4678
4679\c void dsf_free(DSF *dsf);
4680
4681Frees a dsf allocated by any of the \cw{dsf_new()} functions.
4682
4683\S{utils-dsf-reinit} \cw{dsf_reinit()}
4684
4685\c void dsf_reinit(DSF *dsf);
4686
4687Reinitialises an existing dsf to the state in which all elements are
4688distinct, without having to free and reallocate it.
4689
4690\S{utils-dsf-copy} \cw{dsf_copy()}
4691
4692\c void dsf_copy(DSF *to, DSF *from);
4693
4694Copies the contents of one dsf over the top of another. Everything
4695previously stored in \c{to} is overwritten.
4696
4697The two dsfs must have been created with the same size, and the
4698destination dsf may not have any extra information that the source dsf
4699does not have.
4700
4701\S{utils-dsf-merge} \cw{dsf_merge()}
4702
4703\c void dsf_merge(DSF *dsf, int v1, int v2);
4704
4705Updates a dsf so that elements \c{v1} and \c{v2} will now be
4706considered to be in the same equivalence class. If they were already
4707in the same class, this function will safely do nothing.
4708
4709This function may not be called on a flip dsf. Use \cw{dsf_merge_flip}
4710instead.
4711
4712\S{utils-dsf-canonify} \cw{dsf_canonify()}
4713
4714\c int dsf_canonify(DSF *dsf, int val);
4715
4716Returns the \q{canonical} element of the equivalence class in the dsf
4717containing \c{val}. This will be some element of the same equivalence
4718class. So in order to determine whether two elements are in the same
4719equivalence class, you can call \cw{dsf_canonify} on both of them, and
4720compare the results.
4721
4722Canonical elements don't necessarily stay the same if the dsf is
4723mutated via \c{dsf_merge}. But between two calls to \c{dsf_merge},
4724they stay the same.
4725
4726\S{utils-dsf-size} \cw{dsf_size()}
4727
4728\c int dsf_size(DSF *dsf, int val);
4729
4730Returns the number of elements currently in the equivalence class
4731containing \c{val}.
4732
4733\c{val} itself counts, so in a newly created dsf, the return value
4734will be 1.
4735
4736\S{utils-dsf-merge-flip} \cw{dsf_merge_flip()}
4737
4738\c void edsf_merge(DSF *dsf, int v1, int v2, bool flip);
4739
4740Updates a flip dsf so that elements \c{v1} and \c{v2} are in the same
4741equivalence class. If \c{flip} is \cw{false}, they will be regarded as
4742in the same state as each other; if \c{flip} is \cw{true} then they
4743will be regarded as being in opposite states.
4744
4745If \c{v1} and \c{v2} were already in the same equivalence class, then
4746the new value of \c{flip} will be checked against what the edsf
4747previously believed, and an assertion failure will occur if you
4748contradict that.
4749
4750For example, if you start from a blank flip dsf and do this:
4751
4752\c dsf_merge_flip(dsf, 0, 1, false);
4753\c dsf_merge_flip(dsf, 1, 2, true);
4754
4755then it will create a dsf in which elements 0,1,2 are all in the same
4756class, with 0,1 in the same state as each other and 2 in the opposite
4757state from both. And then this call will do nothing, because it agrees
4758with what the dsf already knew:
4759
4760\c dsf_merge_flip(dsf, 0, 2, true);
4761
4762But this call will fail an assertion:
4763
4764\c dsf_merge_flip(dsf, 0, 2, false);
4765
4766\S{utils-dsf-canonify-flip} \cw{dsf_canonify_flip()}
4767
4768\c int dsf_canonify_flip(DSF *dsf, int val, bool *inverse);
4769
4770Like \c{dsf_canonify()}, this returns the canonical element of the
4771equivalence class of a dsf containing \c{val}.
4772
4773However, it may only be called on a flip dsf, and it also fills in
4774\c{*flip} with a flag indicating whether \c{val} and the canonical
4775element are in opposite states: \cw{true} if they are in opposite
4776states, or \cw{false} if they're in the same state.
4777
4778So if you want to know the relationship between \c{v1} and \c{v2}, you
4779can do this:
4780
4781\c bool inv1, inv2;
4782\c int canon1 = dsf_canonify_flip(dsf, v1, &inv1);
4783\c int canon2 = dsf_canonify_flip(dsf, v2, &inv2);
4784\c if (canon1 != canon2) {
4785\c // v1 and v2 have no known relation
4786\c } else if (inv1 == inv2) {
4787\c // v1 and v2 are known to be in the same state as each other
4788\c } else {
4789\c // v1 and v2 are known to be in opposite states
4790\c }
4791
4792\S{utils-dsf-minimal} \cw{dsf_minimal()}
4793
4794\c int dsf_minimal(DSF *dsf, int val);
4795
4796Returns the smallest element of the equivalence class in the dsf
4797containing \c{val}.
4798
4799For this function to work, the dsf must have been created using
4800\cw{dsf_new_min()}.
4801
4802\H{utils-tdq} To-do queues
4803
4804This section describes a set of functions implementing a \q{to-do
4805queue}, a simple de-duplicating to-do list mechanism. The code calls
4806this a \q{tdq}.
4807
4808A tdq can store integers up to a given size (specified at creation
4809time). But it can't store the same integer more than once. So you can
4810quickly \e{make sure} an integer is in the queue (which will do
4811nothing if it's already there), and you can quickly pop an integer
4812from the queue and return it, both in constant time.
4813
4814The idea is that you might use this in a game solver, in the kind of
4815game where updating your knowledge about one square of a grid means
4816there's a specific other set of squares (such as its neighbours) where
4817it's now worth attempting further deductions. So you keep a tdq of all
4818the grid squares you plan to look at next, and every time you make a
4819deduction in one square, you add the neighbouring squares to the tdq
4820to make sure they get looked at again after that.
4821
4822In solvers where deductions are mostly localised, this avoids the
4823slowdown of having to find the next thing to do every time by looping
4824over the whole grid: instead, you can keep checking the tdq for
4825\e{specific} squares to look at, until you run out.
4826
4827However, it's common to have games in which \e{most} deductions are
4828localised, but not all. In that situation, when your tdq is empty, you
4829can re-fill it with every square in the grid using \cw{tdq_fill()},
4830which will force an iteration over everything again. And then if the
4831tdq becomes empty \e{again} without you having made any progress, give
4832up.
4833
4834\S{utils-tdq-new} \cw{tdq_new()}
4835
4836\c tdq *tdq_new(int n);
4837
4838Allocates space for a tdq that tracks items from \cw{0} to \cw{size-1}
4839inclusive.
4840
4841\S{utils-tdq-free} \cw{tdq_free()}
4842
4843\c void tdq_free(tdq *tdq);
4844
4845Frees a tdq.
4846
4847\S{utils-tdq-add} \cw{tdq_add()}
4848
4849\c void tdq_add(tdq *tdq, int k);
4850
4851Adds the value \c{k} to a tdq. If \c{k} was already in the to-do list,
4852does nothing.
4853
4854\S{utils-tdq-remove} \cw{tdq_remove()}
4855
4856\c int tdq_remove(tdq *tdq);
4857
4858Removes one item from the tdq, and returns it. If the tdq is empty,
4859returns \cw{-1}.
4860
4861\S{utils-tdq-fill} \cw{tdq_fill()}
4862
4863\c void tdq_fill(tdq *tdq);
4864
4865Fills a tdq with every element it can possibly keep track of.
4866
4867\H{utils-findloop} Finding loops in graphs and grids
4868
4869Many puzzles played on grids or graphs have a common gameplay element
4870of connecting things together into paths in such a way that you need
4871to avoid making loops (or, perhaps, making the \e{wrong} kind of
4872loop).
4873
4874Just determining \e{whether} a loop exists in a graph is easy, using a
4875dsf tracking connectivity between the vertices. Simply iterate over
4876each edge of the graph, merging the two vertices at each end of the
4877edge \dash but before you do that, check whether those vertices are
4878\e{already} known to be connected to each other, and if they are, then
4879the new edge is about to complete a loop.
4880
4881But if you also want to identify \e{exactly} the set of edges that are
4882part of any loop, e.g. to highlight the whole loop red during
4883gameplay, then that's a harder problem. This API is provided here for
4884all puzzles to use for that purpose.
4885
4886\S{utils-findloop-new-state} \cw{findloop_new_state()}
4887
4888\c struct findloopstate *findloop_new_state(int nvertices);
4889
4890Allocates a new state structure for the findloop algorithm, capable of
4891handling a graph with up to \c{nvertices} vertices. The vertices will
4892be represented by integers between \c{0} and \c{nvertices-1} inclusive.
4893
4894\S{utils-findloop-free-state} \cw{findloop_free_state()}
4895
4896\c void findloop_free_state(struct findloopstate *state);
4897
4898Frees a state structure allocated by \cw{findloop_new_state()}.
4899
4900\S{utils-findloop-run} \cw{findloop_run()}
4901
4902\c bool findloop_run(struct findloopstate *state, int nvertices,
4903\c neighbour_fn_t neighbour, void *ctx);
4904
4905Runs the loop-finding algorithm, which will explore the graph and
4906identify whether each edge is or is not part of any loop.
4907
4908The algorithm will call the provided function \c{neighbour} to list
4909the neighbouring vertices of each vertex. It should have this
4910prototype:
4911
4912\c int neighbour(int vertex, void *ctx);
4913
4914In this callback, \c{vertex} will be the index of a vertex when the
4915algorithm \e{first} calls it for a given vertex. The function should
4916return the index of one of that vertex's neighbours, or a negative
4917number if there are none.
4918
4919If the function returned a vertex, the algorithm will then call
4920\c{neighbour} again with a \e{negative} number as the \c{vertex}
4921parameter, which means \q{please give me another neighbour of the same
4922vertex as last time}. Again, the function should return a vertex
4923index, or a negative number to indicate that there are no more
4924vertices.
4925
4926The \c{ctx} parameter passed to \cw{findloop_run()} is passed on
4927unchanged to \c{neighbour}, so you can point that at your game state
4928or solver state or whatever.
4929
4930The return value is \cw{true} if at least one loop exists in the
4931graph, and \cw{false} if no loop exists. Also, the algorithm state
4932will have been filled in with information that the following query
4933functions can use to ask about individual graph edges.
4934
4935\S{utils-findloop-is-loop-edge} \cw{findloop_is_loop_edge()}
4936
4937\c bool findloop_is_loop_edge(struct findloopstate *state,
4938\c int u, int v);
4939
4940Queries whether the graph edge between vertices \c{u} and \c{v} is
4941part of a loop. If so, the return value is \cw{true}, otherwise
4942\cw{false}.
4943
4944\S{utils-findloop-is-bridge} \cw{findloop_is_bridge()}
4945
4946\c bool findloop_is_bridge(struct findloopstate *pv,
4947\c int u, int v, int *u_vertices, int *v_vertices);
4948
4949Queries whether the graph edge between vertices \c{u} and \c{v} is a
4950\q{bridge}, i.e. an edge which would break the graph into (more)
4951disconnected components if it were removed.
4952
4953This is the exact inverse of the \q{loop edge} criterion: a vertex
4954returns \cw{true} from \cw{findloop_is_loop_edge()} if and only if it
4955returns \cw{false} from \cw{findloop_is_bridge()}, and vice versa.
4956
4957However, \cw{findloop_is_bridge()} returns more information. If it
4958returns \cw{true}, then it also fills in \c{*u_vertices} and
4959\c{*v_vertices} with the number of vertices connected to the \c{u} and
4960\c{v} sides of the bridge respectively.
4961
4962For example, if you have three vertices A,B,C all connected to each
4963other, and four vertices U,V,W,X all connected to each other, and a
4964single edge between A and V, then calling \cw{findloop_is_bridge()} on
4965the pair A,V will return true (removing that edge would separate the
4966two sets from each other), and will report that there are three
4967vertices on the A side and four on the V side.
4968
4969\H{utils-combi} Choosing r things out of n
4970
4971This section describes a small API for iterating over all combinations
4972of r things out of n.
4973
4974For example, if you asked for all combinations of 3 things out of 5,
4975you'd get back the sets \{0,1,2\}, \{0,1,3\}, \{0,1,4\}, \{0,2,3\},
4976\{0,2,4\}, \{0,3,4\}, \{1,2,3\}, \{1,2,4\}, \{1,3,4\}, and \{2,3,4\}.
4977
4978These functions use a structure called a \c{combi_ctx}, which contains
4979an element \c{int *a} holding each returned combination, plus other
4980fields for implementation use only.
4981
4982\S{utils-combi-new} \cw{new_combi()}
4983
4984\c combi_ctx *new_combi(int r, int n);
4985
4986Allocates a new \c{combi_ctx} structure for enumerating r things out
4987of n.
4988
4989\S{utils-combi-free} \cw{free_combi()}
4990
4991\c void free_combi(combi_ctx *combi);
4992
4993Frees a \c{combi_ctx} structure.
4994
4995\S{utils-combi-reset} \cw{reset_combi()}
4996
4997\c void reset_combi(combi_ctx *combi);
4998
4999Resets an existing \c{combi_ctx} structure to the start of its
5000iteration
5001
5002\S{utils-combi-next} \cw{next_combi()}
5003
5004\c combi_ctx *next_combi(combi_ctx *combi);
5005
5006Requests a combination from a \c{combi_ctx}.
5007
5008If there are none left to return, the return value is \cw{NULL}.
5009Otherwise, it returns the input structure \c{combi}, indicating that
5010it has filled in \cw{combi->a[0]}, \cw{combi->a[1]}, ...,
5011\cw{combi->a[r-1]} with an increasing sequence of distinct integers
5012from \cw{0} to \cw{n-1} inclusive.
5013
4209\H{utils-misc} Miscellaneous utility functions and macros 5014\H{utils-misc} Miscellaneous utility functions and macros
4210 5015
4211This section contains all the utility functions which didn't 5016This section contains all the utility functions which didn't
4212sensibly fit anywhere else. 5017sensibly fit anywhere else.
4213 5018
4214\S{utils-truefalse} \cw{TRUE} and \cw{FALSE}
4215
4216The main Puzzles header file defines the macros \cw{TRUE} and
4217\cw{FALSE}, which are used throughout the code in place of 1 and 0
4218(respectively) to indicate that the values are in a boolean context.
4219For code base consistency, I'd prefer it if submissions of new code
4220followed this convention as well.
4221
4222\S{utils-maxmin} \cw{max()} and \cw{min()} 5019\S{utils-maxmin} \cw{max()} and \cw{min()}
4223 5020
4224The main Puzzles header file defines the pretty standard macros 5021The main Puzzles header file defines the pretty standard macros
@@ -4228,6 +5025,17 @@ returns the one which compares greater or less respectively.
4228These macros may evaluate their arguments multiple times. Avoid side 5025These macros may evaluate their arguments multiple times. Avoid side
4229effects. 5026effects.
4230 5027
5028\S{utils-max-digits} \cw{MAX_DIGITS()}
5029
5030The \cw{MAX_DIGITS()} macro, defined in the main Puzzles header file,
5031takes a type (or a variable of that type) and expands to an integer
5032constant representing a reasonable upper bound on the number of
5033characters that a number of that type could expand to when formatted
5034as a decimal number using the \c{%u} or \c{%d} format of
5035\cw{printf()}. This is useful for allocating a fixed-size buffer
5036that's guaranteed to be big enough to \cw{sprintf()} a value into.
5037Don't forget to add one for the trailing \cw{'\\0'}!
5038
4231\S{utils-pi} \cw{PI} 5039\S{utils-pi} \cw{PI}
4232 5040
4233The main Puzzles header file defines a macro \cw{PI} which expands 5041The main Puzzles header file defines a macro \cw{PI} which expands
@@ -4238,7 +5046,7 @@ It'd be so useful!)
4238 5046
4239\S{utils-obfuscate-bitmap} \cw{obfuscate_bitmap()} 5047\S{utils-obfuscate-bitmap} \cw{obfuscate_bitmap()}
4240 5048
4241\c void obfuscate_bitmap(unsigned char *bmp, int bits, int decode); 5049\c void obfuscate_bitmap(unsigned char *bmp, int bits, bool decode);
4242 5050
4243This function obscures the contents of a piece of data, by 5051This function obscures the contents of a piece of data, by
4244cryptographic methods. It is useful for games of hidden information 5052cryptographic methods. It is useful for games of hidden information
@@ -4269,8 +5077,8 @@ considered to be used from the top down: thus, for example, setting
4269two} bits of \cw{bmp[1]}. The remainder of a partially used byte is 5077two} bits of \cw{bmp[1]}. The remainder of a partially used byte is
4270undefined (i.e. it may be corrupted by the function). 5078undefined (i.e. it may be corrupted by the function).
4271 5079
4272The parameter \c{decode} is \cw{FALSE} for an encoding operation, 5080The parameter \c{decode} is \cw{false} for an encoding operation,
4273and \cw{TRUE} for a decoding operation. Each is the inverse of the 5081and \cw{true} for a decoding operation. Each is the inverse of the
4274other. (There's no particular reason you shouldn't obfuscate by 5082other. (There's no particular reason you shouldn't obfuscate by
4275decoding and restore cleartext by encoding, if you really wanted to; 5083decoding and restore cleartext by encoding, if you really wanted to;
4276it should still work.) 5084it should still work.)
@@ -4299,6 +5107,67 @@ resulting array will be undefined.
4299 5107
4300This function is the inverse of \cw{bin2hex()}. 5108This function is the inverse of \cw{bin2hex()}.
4301 5109
5110\S{utils-fgetline} \cw{fgetline()}
5111
5112\c char *fgetline(FILE *fp);
5113
5114This function reads a single line of text from a standard C input
5115stream, and returns it as a dynamically allocated string. The returned
5116string still has a newline on the end.
5117
5118\S{utils-arraysort} \cw{arraysort()}
5119
5120Sorts an array, with slightly more flexibility than the standard C
5121\cw{qsort()}.
5122
5123This function is really implemented as a macro, so it doesn't have a
5124prototype as such. But you could imagine it having a prototype like
5125this:
5126
5127\c void arraysort(element_t *array, size_t nmemb,
5128\c arraysort_cmpfn_t cmp, void *ctx);
5129
5130in which \c{element_t} is an unspecified type.
5131
5132(Really, there's an underlying function that takes an extra parameter
5133giving the size of each array element. But callers are encouraged to
5134use this macro version, which fills that in automatically using
5135\c{sizeof}.)
5136
5137This function behaves essentially like \cw{qsort()}: it expects
5138\c{array} to point to an array of \c{nmemb} elements, and it will sort
5139them in place into the order specified by the comparison function
5140\c{cmp}.
5141
5142The comparison function should have this prototype:
5143
5144\c int cmp(const void *a, const void *b, void *ctx);
5145
5146in which \c{a} and \c{b} point at the two elements to be compared, and
5147the return value is negative if \cw{a<b} (that is, \c{a} should appear
5148before \c{b} in the output array), positive if \cw{a>b}, or zero if
5149\c{a=b}.
5150
5151The \c{ctx} parameter to \cw{arraysort()} is passed directly to the
5152comparison function. This is the feature that makes \cw{arraysort()}
5153more flexible than standard \cw{qsort()}: it lets you vary the sorting
5154criterion in a dynamic manner without having to write global variables
5155in the caller for the compare function to read.
5156
5157\S{utils-colour-mix} \cw{colour_mix()}
5158
5159\c void colour_mix(const float src1[3], const float src2[3], float p,
5160\c float dst[3]);
5161
5162This function mixes the colours \c{src1} and \c{src2} in specified
5163proportions, producing \c{dst}. \c{p} is the proportion of \c{src2}
5164in the result. So if \c{p} is \cw{1.0}, \cw{dst} will be the same as
5165\c{src2}. If \c{p} is \cw{0.0}, \cw{dst} will be the same as
5166\c{src1}. And if \c{p} is somewhere in between, so will \c{dst} be.
5167\c{p} is not restricted to the range \cw{0.0} to \cw{1.0}. Values
5168outside that range will produce extrapolated colours, which may be
5169useful for some purposes, but may also produce impossible colours.
5170
4302\S{utils-game-mkhighlight} \cw{game_mkhighlight()} 5171\S{utils-game-mkhighlight} \cw{game_mkhighlight()}
4303 5172
4304\c void game_mkhighlight(frontend *fe, float *ret, 5173\c void game_mkhighlight(frontend *fe, float *ret,
@@ -4310,7 +5179,7 @@ sections. Fifteen, Sixteen and Twiddle are good examples of this.
4310 5179
4311Puzzles using this graphical style are running a risk if they just 5180Puzzles using this graphical style are running a risk if they just
4312use whatever background colour is supplied to them by the front end, 5181use whatever background colour is supplied to them by the front end,
4313because that background colour might be too light to see any 5182because that background colour might be too light or dark to see any
4314highlights on at all. (In particular, it's not unheard of for the 5183highlights on at all. (In particular, it's not unheard of for the
4315front end to specify a default background colour of white.) 5184front end to specify a default background colour of white.)
4316 5185
@@ -4334,6 +5203,24 @@ Thus, \cw{ret[background*3]} to \cw{ret[background*3+2]} will be set
4334to RGB values defining a sensible background colour, and similary 5203to RGB values defining a sensible background colour, and similary
4335\c{highlight} and \c{lowlight} will be set to sensible colours. 5204\c{highlight} and \c{lowlight} will be set to sensible colours.
4336 5205
5206Either \c{highlight} or \c{lowlight} may be passed in as \cw{-1} to
5207indicate that the back-end does not require a highlight or lowlight
5208colour, respectively.
5209
5210\S{utils-game-mkhighlight-specific} \cw{game_mkhighlight_specific()}
5211
5212\c void game_mkhighlight_specific(frontend *fe, float *ret,
5213\c int background, int highlight, int lowlight);
5214
5215This function behaves exactly like \cw{game_mkhighlight()}, except
5216that it expects the background colour to have been filled in
5217\e{already} in the elements \cw{ret[background*3]} to
5218\cw{ret[background*3+2]}. It will fill in the other two colours as
5219brighter and darker versions of that.
5220
5221This is useful if you want to show relief sections of a puzzle in more
5222than one base colour.
5223
4337\S{utils-button2label} \cw{button2label()} 5224\S{utils-button2label} \cw{button2label()}
4338 5225
4339\c char *button2label(int button); 5226\c char *button2label(int button);
@@ -4352,6 +5239,104 @@ the corresponding \cw{button} field.
4352The returned string is dynamically allocated and should be 5239The returned string is dynamically allocated and should be
4353\cw{sfree}'d by the caller. 5240\cw{sfree}'d by the caller.
4354 5241
5242\S{utils-move-cursor} \cw{move_cursor()}
5243
5244\c char *move_cursor(int button, int *x, int *y, int w, int h,
5245\c bool wrap, bool *visible);
5246
5247This function can be called by \cw{interpret_move()} to implement the
5248default keyboard API for moving a cursor around a grid.
5249
5250\c{button} is the same value passed in to \cw{interpret_move()}. If
5251it's not any of \cw{CURSOR_UP}, \cw{CURSOR_DOWN}, \cw{CURSOR_LEFT} or
5252\cw{CURSOR_RIGHT}, the function will do nothing.
5253
5254\c{x} and \c{y} point to two integers which on input give the current
5255location of a cursor in a square grid. \c{w} and \c{h} give the
5256dimensions of the grid. On return, \c{x} and \c{y} are updated to give
5257the cursor's new position according to which arrow key was pressed.
5258
5259This function assumes that the grid coordinates run from \cw{0} to
5260\cw{w-1} inclusive (left to right), and from \cw{0} to \cw{h-1}
5261inclusive (top to bottom).
5262
5263If \c{wrap} is \cw{true}, then trying to move the cursor off any edge
5264of the grid will result in it wrapping round to the corresponding
5265square on the opposite edge. If \c{wrap} is \cw{false}, such a move
5266will have no effect.
5267
5268If \c{visible} is not \cw{NULL}, it points to a flag indicating
5269whether the cursor is visible. This will be set to \cw{true} if
5270\c{button} represents a cursor-movement key.
5271
5272The function returns one of the special constants that can be returned
5273by \cw{interpret_move()}. The return value is \cw{MOVE_UNUSED} if
5274\c{button} is unrecognised, \cw{MOVE_UI_UPDATE} if \c{x}, \c{y}, or
5275\c{visible} was updated, and \cw{MOVE_NO EFFECT} otherwise.
5276
5277\S{utils-divvy-rectangle} \cw{divvy_rectangle()}
5278
5279\c int *divvy_rectangle(int w, int h, int k, random_state *rs);
5280
5281Invents a random division of a rectangle into same-sized polyominoes,
5282such as is found in the block layout of a Solo puzzle in jigsaw mode,
5283or the solution to a Palisade puzzle.
5284
5285\c{w} and \c{h} are the dimensions of the rectangle. \c{k} is the size
5286of polyomino desired. It must be a factor of \c{w*h}.
5287
5288\c{rs} is a \cw{random_state} used to supply the random numbers to
5289select a random division of the rectangle.
5290
5291The return value is a dsf (see \k{utils-dsf}) whose equivalence
5292classes correspond to the polyominoes that the rectangle is divided
5293into. The indices of the dsf are of the form \c{y*w+x}, for the cell
5294with coordinates \cw{x,y}.
5295
5296\S{utils-domino-layout} \cw{domino_layout()}
5297
5298\c int *domino_layout(int w, int h, random_state *rs);
5299
5300Invents a random tiling of a rectangle with dominoes.
5301
5302\c{w} and \c{h} are the dimensions of the rectangle. If they are both
5303odd, then one square will be left untiled.
5304
5305\c{rs} is a \cw{random_state} used to supply the random numbers to
5306select a random division of the rectangle.
5307
5308The return value is an array in which element \c{y*w+x} represents the
5309cell with coordinates \cw{x,y}. Each element of the array gives the
5310index (in the same representation) of the other end of its domino. If
5311there's a left-over square, then that element contains its own index.
5312
5313\S{utils-domino-layout-prealloc} \cw{domino_layout_prealloc()}
5314
5315\c void domino_layout_prealloc(int w, int h, random_state *rs,
5316\c int *grid, int *grid2, int *list);
5317
5318Just like \cw{domino_layout()}, but does no memory allocation. You can
5319use this to save allocator overhead if you expect to need to generate
5320many domino tilings of the same grid.
5321
5322\c{grid} and \c{grid2} should each have space for \cw{w*h} ints.
5323\c{list} should have space for \c{2*w*h} ints.
5324
5325The returned array is delivered in \c{grid}.
5326
5327\S{utils-strip-button-modifiers} \cw{STRIP_BUTTON_MODIFIERS()}
5328
5329This macro, defined in the main Puzzles header file, strips the
5330modifier flags from the key code passed as an argument. It is
5331equivalent to a bitwise-AND with \cw{~MOD_MASK}.
5332
5333\S{utils-swap-regions} \cw{swap_regions()}
5334
5335\c void swap_regions(void *av, void *bv, size_t size);
5336
5337Swap two regions of memory of \cw{size} bytes. The two regions must
5338not overlap.
5339
4355\C{writing} How to write a new puzzle 5340\C{writing} How to write a new puzzle
4356 5341
4357This chapter gives a guide to how to actually write a new puzzle: 5342This chapter gives a guide to how to actually write a new puzzle:
@@ -4370,42 +5355,48 @@ official Puzzles distribution, then there's a criterion it has to
4370meet. 5355meet.
4371 5356
4372The current Puzzles editorial policy is that all games should be 5357The current Puzzles editorial policy is that all games should be
4373\e{fair}. A fair game is one which a player can only fail to 5358\e{fair}. A fair game is one which a player can only fail to complete
4374complete through demonstrable lack of skill \dash that is, such that 5359through demonstrable lack of skill \dash that is, such that a better
4375a better player in the same situation would have \e{known} to do 5360player presented with the same game state would have \e{known} to do
4376something different. 5361something different.
4377 5362
4378For a start, that means every game presented to the user must have 5363For a start, that means every game presented to the user must have
4379\e{at least one solution}. Giving the unsuspecting user a puzzle 5364\e{at least one solution}. Giving the unsuspecting user a puzzle which
4380which is actually impossible is not acceptable. (There is an 5365is actually impossible is not acceptable.
4381exception: if the user has selected some non-default option which is 5366
4382clearly labelled as potentially unfair, \e{then} you're allowed to 5367(An exception to this: if the user has selected some non-default
4383generate possibly insoluble puzzles, because the user isn't 5368option which is clearly labelled as potentially unfair, \e{then}
4384unsuspecting any more. Same Game and Mines both have options of this 5369you're allowed to generate possibly insoluble puzzles, because the
4385type.) 5370user isn't unsuspecting any more. Same Game and Mines both have
4386 5371options of this type.)
4387Also, this actually \e{rules out} games such as Klondike, or the 5372
4388normal form of Mahjong Solitaire. Those games have the property that 5373Secondly, if the game includes hidden information, then it must be
4389even if there is a solution (i.e. some sequence of moves which will 5374possible to deduce a correct move at every stage from the currently
4390get from the start state to the solved state), the player doesn't 5375available information. It's not enough that there should exist some
4391necessarily have enough information to \e{find} that solution. In 5376sequence of moves which will get from the start state to the solved
4392both games, it is possible to reach a dead end because you had an 5377state, if the player doesn't necessarily have enough information to
4393arbitrary choice to make and made it the wrong way. This violates 5378\e{find} that solution. For example, in the card solitaire game
4394the fairness criterion, because a better player couldn't have known 5379Klondike, it's possible to reach a dead end because you had an
4395they needed to make the other choice. 5380arbitrary choice to make on no information, and made it the wrong way,
4396 5381which violates the fairness criterion, because a better player
4397(GNOME has a variant on Mahjong Solitaire which makes it fair: there 5382couldn't have known they needed to make the other choice.
4398is a Shuffle operation which randomly permutes all the remaining 5383
4399tiles without changing their positions, which allows you to get out 5384(Of course, games in this collection always have an Undo function, so
4400of a sticky situation. Using this operation adds a 60-second penalty 5385if you did take the wrong route through a Klondike game, you could use
4401to your solution time, so it's to the player's advantage to try to 5386Undo to back up and try a different choice. This doesn't count. In a
4402minimise the chance of having to use it. It's still possible to 5387fair game, you should be able to determine a correct move from the
4403render the game uncompletable if you end up with only two tiles 5388information visible \e{now}, without having to make moves to get more
4404vertically stacked, but that's easy to foresee and avoid using a 5389information that you can then back up and use.)
4405shuffle operation. This form of the game \e{is} fair. Implementing 5390
4406it in Puzzles would require an infrastructure change so that the 5391Sometimes you can adjust the rules of an unfair puzzle to make it meet
4407back end could communicate time penalties to the mid-end, but that 5392this definition of fairness. For example, more than one implementation
4408would be easy enough.) 5393of solitaire-style games (including card solitaires and Mahjong
5394Solitaire) include a UI action to shuffle the remaining cards or tiles
5395without changing their position; this action might be available at any
5396time with a time or points penalty, or it might be illegal to use
5397unless you have no other possible move. Adding an option like this
5398would make a game \e{technically} fair, but it's better to avoid even
5399that if you can.
4409 5400
4410Providing a \e{unique} solution is a little more negotiable; it 5401Providing a \e{unique} solution is a little more negotiable; it
4411depends on the puzzle. Solo would have been of unacceptably low 5402depends on the puzzle. Solo would have been of unacceptably low
@@ -4441,15 +5432,11 @@ So start by copying \c{nullgame.c} into your new source file. Then
4441you'll gradually add functionality until the very boring Null Game 5432you'll gradually add functionality until the very boring Null Game
4442turns into your real game. 5433turns into your real game.
4443 5434
4444Next you'll need to add your puzzle to the Makefiles, in order to 5435Next you'll need to add your puzzle to the build scripts, in order to
4445compile it conveniently. \e{Do not edit the Makefiles}: they are 5436compile it conveniently. Puzzles is a CMake project, so you do this by
4446created automatically by the script \c{mkfiles.pl}, from the file 5437adding a \cw{puzzle()} statement to CMakeLists.txt. Look at the
4447called \c{Recipe}. Edit \c{Recipe}, and then re-run \c{mkfiles.pl}. 5438existing ones to see what those look like, and add one that looks
4448 5439similar.
4449Also, don't forget to add your puzzle to \c{list.c}: if you don't,
4450then it will still run fine on platforms which build each puzzle
4451separately, but Mac OS X and other monolithic platforms will not
4452include your new puzzle in their single binary.
4453 5440
4454Once your source file is building, you can move on to the fun bit. 5441Once your source file is building, you can move on to the fun bit.
4455 5442
@@ -4726,7 +5713,102 @@ This section lists some common things people want to do when writing
4726a puzzle, and describes how to achieve them within the Puzzles 5713a puzzle, and describes how to achieve them within the Puzzles
4727framework. 5714framework.
4728 5715
4729\S{writing-howto-cursor} Drawing objects at only one position 5716\S{writing-howto-redraw} Redrawing just the changed parts of the window
5717
5718Redrawing the entire window on every move is wasteful. If the user
5719makes a move changing only one square of a grid, it's better to redraw
5720just that square.
5721
5722(Yes, computers are fast these days, but these puzzles still try to be
5723portable to devices at the less fast end of the spectrum, so it's
5724still worth saving effort where it's easy. On the other hand, some
5725puzzles just \e{can't} do this easily \dash Untangle is an example
5726that really does have no better option than to redraw everything.)
5727
5728For a typical grid-oriented puzzle, a robust way to do this is:
5729
5730\b Invent a data representation that describes everything about the
5731appearance of a grid cell in the puzzle window.
5732
5733\b Have \c{game_drawstate} contain an array of those, describing the
5734current appearance of each cell, as it was last drawn in the window.
5735
5736\b In \cw{redraw()}, loop over each cell deciding what the new
5737appearance should be. If it's not the same as the value stored in
5738\c{game_drawstate}, then redraw that cell, and update the entry in the
5739\c{game_drawstate} array.
5740
5741Where possible, I generally make my data representation an integer
5742full of bit flags, to save space, and to make it easy to compare the
5743old and new versions. If yours needs to be bigger than that, you may
5744have to define a small \cw{struct} and write an equality-checking
5745function.
5746
5747The data representation of the \e{appearance} of a square in
5748\c{game_drawstate} will not generally be identical to the
5749representation of the \e{logical state} of a square in \c{game_state},
5750because many things contribute to a square's appearance other than its
5751logical state. For example:
5752
5753\b Extra information overlaid on the square by the user interface,
5754such as a keyboard-controlled cursor, or highlighting of squares
5755currently involved in a mouse drag action.
5756
5757\b Error highlights marking violations of the puzzle constraints.
5758
5759\b Visual intrusions into one square because of things in nearby
5760squares. For example, if you draw thick lines along the edges between
5761grid squares, then the corners of those lines will be visible in
5762logically unrelated squares. An entry in the \c{game_drawstate} array
5763should describe a specific \e{rectangular area of the screen}, so that
5764those areas can be erased and redrawn independently \dash so it must
5765represent anything that appears in that area, even if it's sticking
5766out from a graphic that logically lives in some other square.
5767
5768\b Temporary changes to the appearance of a square because of an
5769ongoing completion flash.
5770
5771\b The current display mode, if a game provides more than one. (For
5772example, the optional letters distinguishing the different coloured
5773pegs in Guess.)
5774
5775All of this must be included in the \c{game_drawstate} representation,
5776but should not be in the \c{game_state} at all. \cw{redraw()} will
5777pull it all together from the \c{game_state}, the \c{game_ui}, and the
5778animation and flash parameters.
5779
5780To make sure that \e{everything} affecting a square's appearance is
5781included in this representation, it's a good idea to have a separate
5782function for drawing a grid square, and deliberately \e{not} pass it a
5783copy of the \c{game_state} or the \c{game_ui} at all. That way, if you
5784want that function to draw anything differently, you \e{have} to do it
5785by including that information in the representation of a square's
5786appearance.
5787
5788But of course there are a couple of exceptions to this rule. A few
5789things \e{don't} have to go in the \c{game_drawstate} array, and can
5790safely be passed separately to the redraw-square function:
5791
5792\b Anything that remains completely fixed throughout the whole of a
5793game, such as the clues provided by the puzzle. This is safe because a
5794\c{game_drawstate} is never reused between puzzle instances: when you
5795press New Game, a new \c{game_drawstate} will always be created from
5796scratch. So the \c{game_drawstate} only needs to describe everything
5797that might \e{change} during gameplay. If you have a sub-\cw{struct}
5798in your \c{game_state} that describes immutable properties of the
5799current game, as suggested in \k{writing-ref-counting}, then it's safe
5800to pass \e{that substructure} to the redraw-square function, and have
5801it retrieve that information directly.
5802
5803\b How far through a move animation the last redraw was. When
5804\cw{redraw()} is called multiple times during an animated move, it's
5805much easier to just assume that any square involved in the animation
5806will \e{always} need redrawing. So \c{anim_length} can safely be
5807passed separately to the redraw-square function \dash but you also
5808have to remember to redraw a square if \e{either} its appearance is
5809different from the last redraw \e{or} it's involved in an animation.
5810
5811\S{writing-howto-cursor} Drawing an object at only one position
4730 5812
4731A common phenomenon is to have an object described in the 5813A common phenomenon is to have an object described in the
4732\c{game_state} or the \c{game_ui} which can only be at one position. 5814\c{game_state} or the \c{game_ui} which can only be at one position.
@@ -4742,41 +5824,19 @@ which you ended up with two cursors or none. The obviously sensible
4742way to store a cursor in the \c{game_ui} is to have fields directly 5824way to store a cursor in the \c{game_ui} is to have fields directly
4743encoding the cursor's coordinates. 5825encoding the cursor's coordinates.
4744 5826
4745However, it is a mistake to assume that the same logic applies to 5827However, it is a mistake to assume that the same logic applies to the
4746the \c{game_drawstate}. If you replicate the cursor position fields 5828\c{game_drawstate}. If you replicate the cursor position fields in the
4747in the draw state, the redraw code will get very complicated. In the 5829draw state, the redraw code will get very complicated. In the draw
4748draw state, in fact, it \e{is} probably the right thing to have a 5830state, in fact, it \e{is} probably the right thing to have a cursor
4749cursor flag for every position in the grid. You probably have an 5831flag for every position in the grid, and make it part of the
4750array for the whole grid in the drawstate already (stating what is 5832representation of each square's appearance, as described in
4751currently displayed in the window at each position); the sensible 5833\k{writing-howto-redraw}. So when you iterate over each square in
4752approach is to add a \q{cursor} flag to each element of that array. 5834\c{redraw()} working out its position, you set the \q{cursor here}
4753Then the main redraw loop will look something like this 5835flag in the representation of the square's appearance, if its
4754(pseudo-code): 5836coordinates match the cursor coordinates stored in the \c{game_ui}.
4755 5837This will automatically ensure that when the cursor moves, the redraw
4756\c for (y = 0; y < h; y++) { 5838loop will redraw the square that \e{previously} contained the cursor
4757\c for (x = 0; x < w; x++) { 5839and doesn't any more, and the one that now contains the cursor.
4758\c int value = state->symbol_at_position[y][x];
4759\c if (x == ui->cursor_x && y == ui->cursor_y)
4760\c value |= CURSOR;
4761\c if (ds->symbol_at_position[y][x] != value) {
4762\c symbol_drawing_subroutine(dr, ds, x, y, value);
4763\c ds->symbol_at_position[y][x] = value;
4764\c }
4765\c }
4766\c }
4767
4768This loop is very simple, pretty hard to get wrong, and
4769\e{automatically} deals both with erasing the previous cursor and
4770drawing the new one, with no special case code required.
4771
4772This type of loop is generally a sensible way to write a redraw
4773function, in fact. The best thing is to ensure that the information
4774stored in the draw state for each position tells you \e{everything}
4775about what was drawn there. A good way to ensure that is to pass
4776precisely the same information, and \e{only} that information, to a
4777subroutine that does the actual drawing; then you know there's no
4778additional information which affects the drawing but which you don't
4779notice changes in.
4780 5840
4781\S{writing-keyboard-cursor} Implementing a keyboard-controlled cursor 5841\S{writing-keyboard-cursor} Implementing a keyboard-controlled cursor
4782 5842
@@ -4790,10 +5850,11 @@ be:
4790\b Put cursor position fields in the \c{game_ui}. 5850\b Put cursor position fields in the \c{game_ui}.
4791 5851
4792\b \cw{interpret_move()} responds to arrow keys by modifying the 5852\b \cw{interpret_move()} responds to arrow keys by modifying the
4793cursor position fields and returning \cw{""}. 5853cursor position fields and returning \cw{MOVE_UI_UPDATE}.
4794 5854
4795\b \cw{interpret_move()} responds to some sort of fire button by 5855\b \cw{interpret_move()} responds to some other button \dash either
4796actually performing a move based on the current cursor location. 5856\cw{CURSOR_SELECT} or some more specific thing like a number key \dash
5857by actually performing a move based on the current cursor location.
4797 5858
4798\b You might want an additional \c{game_ui} field stating whether 5859\b You might want an additional \c{game_ui} field stating whether
4799the cursor is currently visible, and having it disappear when a 5860the cursor is currently visible, and having it disappear when a
@@ -4983,21 +6044,21 @@ The solution is to have \e{two} flags in a queue.
4983\b Define two flags in \c{game_ui}; let's call them \q{current} and 6044\b Define two flags in \c{game_ui}; let's call them \q{current} and
4984\q{next}. 6045\q{next}.
4985 6046
4986\b Set both to \cw{FALSE} in \c{new_ui()}. 6047\b Set both to \cw{false} in \c{new_ui()}.
4987 6048
4988\b When a drag operation completes in \cw{interpret_move()}, set the 6049\b When a drag operation completes in \cw{interpret_move()}, set the
4989\q{next} flag to \cw{TRUE}. 6050\q{next} flag to \cw{true}.
4990 6051
4991\b Every time \cw{changed_state()} is called, set the value of 6052\b Every time \cw{changed_state()} is called, set the value of
4992\q{current} to the value in \q{next}, and then set the value of 6053\q{current} to the value in \q{next}, and then set the value of
4993\q{next} to \cw{FALSE}. 6054\q{next} to \cw{false}.
4994 6055
4995\b That way, \q{current} will be \cw{TRUE} \e{after} a call to 6056\b That way, \q{current} will be \cw{true} \e{after} a call to
4996\cw{changed_state()} if and only if that call to 6057\cw{changed_state()} if and only if that call to
4997\cw{changed_state()} was the result of a drag operation processed by 6058\cw{changed_state()} was the result of a drag operation processed by
4998\cw{interpret_move()}. Any other call to \cw{changed_state()}, due 6059\cw{interpret_move()}. Any other call to \cw{changed_state()}, due
4999to an Undo or a Redo or a Restart or a Solve, will leave \q{current} 6060to an Undo or a Redo or a Restart or a Solve, will leave \q{current}
5000\cw{FALSE}. 6061\cw{false}.
5001 6062
5002\b So now \cw{anim_length()} can request a move animation if and 6063\b So now \cw{anim_length()} can request a move animation if and
5003only if the \q{current} flag is \e{not} set. 6064only if the \q{current} flag is \e{not} set.
@@ -5013,7 +6074,7 @@ This is easily done:
5013 6074
5014\b Add a \q{cheated} flag to the \c{game_state}. 6075\b Add a \q{cheated} flag to the \c{game_state}.
5015 6076
5016\b Set this flag to \cw{FALSE} in \cw{new_game()}. 6077\b Set this flag to \cw{false} in \cw{new_game()}.
5017 6078
5018\b Have \cw{solve()} return a move description string which clearly 6079\b Have \cw{solve()} return a move description string which clearly
5019identifies the move as a solve operation. 6080identifies the move as a solve operation.
diff --git a/apps/plugins/puzzles/src/divvy.c b/apps/plugins/puzzles/src/divvy.c
index ea018010cf..61b04eb80d 100644
--- a/apps/plugins/puzzles/src/divvy.c
+++ b/apps/plugins/puzzles/src/divvy.c
@@ -260,9 +260,10 @@ static bool addremcommon(int w, int h, int x, int y, int *own, int val)
260 * In both of the above suggested use cases, the user would 260 * In both of the above suggested use cases, the user would
261 * probably want w==h==k, but that isn't a requirement. 261 * probably want w==h==k, but that isn't a requirement.
262 */ 262 */
263static int *divvy_internal(int w, int h, int k, random_state *rs) 263DSF *divvy_rectangle_attempt(int w, int h, int k, random_state *rs)
264{ 264{
265 int *order, *queue, *tmp, *own, *sizes, *addable, *retdsf; 265 int *order, *queue, *tmp, *own, *sizes, *addable;
266 DSF *retdsf, *tmpdsf;
266 bool *removable; 267 bool *removable;
267 int wh = w*h; 268 int wh = w*h;
268 int i, j, n, x, y, qhead, qtail; 269 int i, j, n, x, y, qhead, qtail;
@@ -277,6 +278,7 @@ static int *divvy_internal(int w, int h, int k, random_state *rs)
277 queue = snewn(n, int); 278 queue = snewn(n, int);
278 addable = snewn(wh*4, int); 279 addable = snewn(wh*4, int);
279 removable = snewn(wh, bool); 280 removable = snewn(wh, bool);
281 retdsf = tmpdsf = NULL;
280 282
281 /* 283 /*
282 * Permute the grid squares into a random order, which will be 284 * Permute the grid squares into a random order, which will be
@@ -609,7 +611,7 @@ static int *divvy_internal(int w, int h, int k, random_state *rs)
609 assert(own[i] >= 0 && own[i] < n); 611 assert(own[i] >= 0 && own[i] < n);
610 tmp[own[i]] = i; 612 tmp[own[i]] = i;
611 } 613 }
612 retdsf = snew_dsf(wh); 614 retdsf = dsf_new(wh);
613 for (i = 0; i < wh; i++) { 615 for (i = 0; i < wh; i++) {
614 dsf_merge(retdsf, i, tmp[own[i]]); 616 dsf_merge(retdsf, i, tmp[own[i]]);
615 } 617 }
@@ -619,18 +621,18 @@ static int *divvy_internal(int w, int h, int k, random_state *rs)
619 * the ominoes really are k-ominoes and we haven't 621 * the ominoes really are k-ominoes and we haven't
620 * accidentally split one into two disconnected pieces. 622 * accidentally split one into two disconnected pieces.
621 */ 623 */
622 dsf_init(tmp, wh); 624 tmpdsf = dsf_new(wh);
623 for (y = 0; y < h; y++) 625 for (y = 0; y < h; y++)
624 for (x = 0; x+1 < w; x++) 626 for (x = 0; x+1 < w; x++)
625 if (own[y*w+x] == own[y*w+(x+1)]) 627 if (own[y*w+x] == own[y*w+(x+1)])
626 dsf_merge(tmp, y*w+x, y*w+(x+1)); 628 dsf_merge(tmpdsf, y*w+x, y*w+(x+1));
627 for (x = 0; x < w; x++) 629 for (x = 0; x < w; x++)
628 for (y = 0; y+1 < h; y++) 630 for (y = 0; y+1 < h; y++)
629 if (own[y*w+x] == own[(y+1)*w+x]) 631 if (own[y*w+x] == own[(y+1)*w+x])
630 dsf_merge(tmp, y*w+x, (y+1)*w+x); 632 dsf_merge(tmpdsf, y*w+x, (y+1)*w+x);
631 for (i = 0; i < wh; i++) { 633 for (i = 0; i < wh; i++) {
632 j = dsf_canonify(retdsf, i); 634 j = dsf_canonify(retdsf, i);
633 assert(dsf_canonify(tmp, j) == dsf_canonify(tmp, i)); 635 assert(dsf_equivalent(tmpdsf, j, i));
634 } 636 }
635 637
636 cleanup: 638 cleanup:
@@ -640,6 +642,7 @@ static int *divvy_internal(int w, int h, int k, random_state *rs)
640 */ 642 */
641 sfree(order); 643 sfree(order);
642 sfree(tmp); 644 sfree(tmp);
645 dsf_free(tmpdsf);
643 sfree(own); 646 sfree(own);
644 sfree(sizes); 647 sfree(sizes);
645 sfree(queue); 648 sfree(queue);
@@ -652,131 +655,13 @@ static int *divvy_internal(int w, int h, int k, random_state *rs)
652 return retdsf; 655 return retdsf;
653} 656}
654 657
655#ifdef TESTMODE 658DSF *divvy_rectangle(int w, int h, int k, random_state *rs)
656static int fail_counter = 0;
657#endif
658
659int *divvy_rectangle(int w, int h, int k, random_state *rs)
660{ 659{
661 int *ret; 660 DSF *ret;
662 661
663 do { 662 do {
664 ret = divvy_internal(w, h, k, rs); 663 ret = divvy_rectangle_attempt(w, h, k, rs);
665
666#ifdef TESTMODE
667 if (!ret)
668 fail_counter++;
669#endif
670
671 } while (!ret); 664 } while (!ret);
672 665
673 return ret; 666 return ret;
674} 667}
675
676#ifdef TESTMODE
677
678/*
679 * gcc -g -O0 -DTESTMODE -I.. -o divvy divvy.c ../random.c ../malloc.c ../dsf.c ../misc.c ../nullfe.c
680 *
681 * or to debug
682 *
683 * gcc -g -O0 -DDIVVY_DIAGNOSTICS -DTESTMODE -I.. -o divvy divvy.c ../random.c ../malloc.c ../dsf.c ../misc.c ../nullfe.c
684 */
685
686int main(int argc, char **argv)
687{
688 int *dsf;
689 int i;
690 int w = 9, h = 4, k = 6, tries = 100;
691 random_state *rs;
692
693 rs = random_new("123456", 6);
694
695 if (argc > 1)
696 w = atoi(argv[1]);
697 if (argc > 2)
698 h = atoi(argv[2]);
699 if (argc > 3)
700 k = atoi(argv[3]);
701 if (argc > 4)
702 tries = atoi(argv[4]);
703
704 for (i = 0; i < tries; i++) {
705 int x, y;
706
707 dsf = divvy_rectangle(w, h, k, rs);
708 assert(dsf);
709
710 for (y = 0; y <= 2*h; y++) {
711 for (x = 0; x <= 2*w; x++) {
712 int miny = y/2 - 1, maxy = y/2;
713 int minx = x/2 - 1, maxx = x/2;
714 int classes[4], tx, ty;
715 for (ty = 0; ty < 2; ty++)
716 for (tx = 0; tx < 2; tx++) {
717 int cx = minx+tx, cy = miny+ty;
718 if (cx < 0 || cx >= w || cy < 0 || cy >= h)
719 classes[ty*2+tx] = -1;
720 else
721 classes[ty*2+tx] = dsf_canonify(dsf, cy*w+cx);
722 }
723 switch (y%2 * 2 + x%2) {
724 case 0: /* corner */
725 /*
726 * Cases for the corner:
727 *
728 * - if all four surrounding squares belong
729 * to the same omino, we print a space.
730 *
731 * - if the top two are the same and the
732 * bottom two are the same, we print a
733 * horizontal line.
734 *
735 * - if the left two are the same and the
736 * right two are the same, we print a
737 * vertical line.
738 *
739 * - otherwise, we print a cross.
740 */
741 if (classes[0] == classes[1] &&
742 classes[1] == classes[2] &&
743 classes[2] == classes[3])
744 printf(" ");
745 else if (classes[0] == classes[1] &&
746 classes[2] == classes[3])
747 printf("-");
748 else if (classes[0] == classes[2] &&
749 classes[1] == classes[3])
750 printf("|");
751 else
752 printf("+");
753 break;
754 case 1: /* horiz edge */
755 if (classes[1] == classes[3])
756 printf(" ");
757 else
758 printf("--");
759 break;
760 case 2: /* vert edge */
761 if (classes[2] == classes[3])
762 printf(" ");
763 else
764 printf("|");
765 break;
766 case 3: /* square centre */
767 printf(" ");
768 break;
769 }
770 }
771 printf("\n");
772 }
773 printf("\n");
774 sfree(dsf);
775 }
776
777 printf("%d retries needed for %d successes\n", fail_counter, tries);
778
779 return 0;
780}
781
782#endif
diff --git a/apps/plugins/puzzles/src/dominosa.R b/apps/plugins/puzzles/src/dominosa.R
deleted file mode 100644
index b85e7dc1e0..0000000000
--- a/apps/plugins/puzzles/src/dominosa.R
+++ /dev/null
@@ -1,24 +0,0 @@
1# -*- makefile -*-
2
3DOMINOSA_EXTRA = laydomino dsf sort findloop
4
5dominosa : [X] GTK COMMON dominosa DOMINOSA_EXTRA dominosa-icon|no-icon
6
7dominosa : [G] WINDOWS COMMON dominosa DOMINOSA_EXTRA dominosa.res|noicon.res
8
9ALL += dominosa[COMBINED] DOMINOSA_EXTRA
10
11dominosasolver : [U] dominosa[STANDALONE_SOLVER] DOMINOSA_EXTRA STANDALONE
12dominosasolver : [C] dominosa[STANDALONE_SOLVER] DOMINOSA_EXTRA STANDALONE
13
14!begin am gtk
15GAMES += dominosa
16!end
17
18!begin >list.c
19 A(dominosa) \
20!end
21
22!begin >gamedesc.txt
23dominosa:dominosa.exe:Dominosa:Domino tiling puzzle:Tile the rectangle with a full set of dominoes.
24!end
diff --git a/apps/plugins/puzzles/src/dominosa.c b/apps/plugins/puzzles/src/dominosa.c
index 758db4f506..3ac723e6e1 100644
--- a/apps/plugins/puzzles/src/dominosa.c
+++ b/apps/plugins/puzzles/src/dominosa.c
@@ -47,7 +47,12 @@
47#include <string.h> 47#include <string.h>
48#include <assert.h> 48#include <assert.h>
49#include <ctype.h> 49#include <ctype.h>
50#include <math.h> 50#include <limits.h>
51#ifdef NO_TGMATH_H
52# include <math.h>
53#else
54# include <tgmath.h>
55#endif
51 56
52#include "puzzles.h" 57#include "puzzles.h"
53 58
@@ -243,6 +248,10 @@ static const char *validate_params(const game_params *params, bool full)
243{ 248{
244 if (params->n < 1) 249 if (params->n < 1)
245 return "Maximum face number must be at least one"; 250 return "Maximum face number must be at least one";
251 if (params->n > INT_MAX - 2 ||
252 params->n + 2 > INT_MAX / (params->n + 1))
253 return "Maximum face number must not be unreasonably large";
254
246 if (params->diff >= DIFFCOUNT) 255 if (params->diff >= DIFFCOUNT)
247 return "Unknown difficulty rating"; 256 return "Unknown difficulty rating";
248 return NULL; 257 return NULL;
@@ -254,9 +263,9 @@ static const char *validate_params(const game_params *params, bool full)
254 263
255#ifdef STANDALONE_SOLVER 264#ifdef STANDALONE_SOLVER
256#define SOLVER_DIAGNOSTICS 265#define SOLVER_DIAGNOSTICS
257bool solver_diagnostics = false; 266static bool solver_diagnostics = false;
258#elif defined SOLVER_DIAGNOSTICS 267#elif defined SOLVER_DIAGNOSTICS
259const bool solver_diagnostics = true; 268static const bool solver_diagnostics = true;
260#endif 269#endif
261 270
262struct solver_domino; 271struct solver_domino;
@@ -342,6 +351,7 @@ struct solver_scratch {
342 struct findloopstate *fls; 351 struct findloopstate *fls;
343 bool squares_by_number_initialised; 352 bool squares_by_number_initialised;
344 int *wh_scratch, *pc_scratch, *pc_scratch2, *dc_scratch; 353 int *wh_scratch, *pc_scratch, *pc_scratch2, *dc_scratch;
354 DSF *dsf_scratch;
345}; 355};
346 356
347static struct solver_scratch *solver_make_scratch(int n) 357static struct solver_scratch *solver_make_scratch(int n)
@@ -473,6 +483,7 @@ static struct solver_scratch *solver_make_scratch(int n)
473 sc->wh_scratch = NULL; 483 sc->wh_scratch = NULL;
474 sc->pc_scratch = sc->pc_scratch2 = NULL; 484 sc->pc_scratch = sc->pc_scratch2 = NULL;
475 sc->dc_scratch = NULL; 485 sc->dc_scratch = NULL;
486 sc->dsf_scratch = NULL;
476 487
477 return sc; 488 return sc;
478} 489}
@@ -500,6 +511,7 @@ static void solver_free_scratch(struct solver_scratch *sc)
500 sfree(sc->pc_scratch); 511 sfree(sc->pc_scratch);
501 sfree(sc->pc_scratch2); 512 sfree(sc->pc_scratch2);
502 sfree(sc->dc_scratch); 513 sfree(sc->dc_scratch);
514 dsf_free(sc->dsf_scratch);
503 sfree(sc); 515 sfree(sc);
504} 516}
505 517
@@ -925,7 +937,7 @@ struct parity_findloop_ctx {
925 int i; 937 int i;
926}; 938};
927 939
928int parity_neighbour(int vertex, void *vctx) 940static int parity_neighbour(int vertex, void *vctx)
929{ 941{
930 struct parity_findloop_ctx *ctx = (struct parity_findloop_ctx *)vctx; 942 struct parity_findloop_ctx *ctx = (struct parity_findloop_ctx *)vctx;
931 struct solver_placement *p; 943 struct solver_placement *p;
@@ -1416,21 +1428,23 @@ static bool deduce_forcing_chain(struct solver_scratch *sc)
1416 sc->pc_scratch2 = snewn(sc->pc, int); 1428 sc->pc_scratch2 = snewn(sc->pc, int);
1417 if (!sc->dc_scratch) 1429 if (!sc->dc_scratch)
1418 sc->dc_scratch = snewn(sc->dc, int); 1430 sc->dc_scratch = snewn(sc->dc, int);
1431 if (!sc->dsf_scratch)
1432 sc->dsf_scratch = dsf_new_flip(sc->pc);
1419 1433
1420 /* 1434 /*
1421 * Start by identifying chains of placements which must all occur 1435 * Start by identifying chains of placements which must all occur
1422 * together if any of them occurs. We do this by making 1436 * together if any of them occurs. We do this by making
1423 * pc_scratch2 an edsf binding the placements into an equivalence 1437 * dsf_scratch a flip dsf binding the placements into an equivalence
1424 * class for each entire forcing chain, with the two possible sets 1438 * class for each entire forcing chain, with the two possible sets
1425 * of dominoes for the chain listed as inverses. 1439 * of dominoes for the chain listed as inverses.
1426 */ 1440 */
1427 dsf_init(sc->pc_scratch2, sc->pc); 1441 dsf_reinit(sc->dsf_scratch);
1428 for (si = 0; si < sc->wh; si++) { 1442 for (si = 0; si < sc->wh; si++) {
1429 struct solver_square *sq = &sc->squares[si]; 1443 struct solver_square *sq = &sc->squares[si];
1430 if (sq->nplacements == 2) 1444 if (sq->nplacements == 2)
1431 edsf_merge(sc->pc_scratch2, 1445 dsf_merge_flip(sc->dsf_scratch,
1432 sq->placements[0]->index, 1446 sq->placements[0]->index,
1433 sq->placements[1]->index, true); 1447 sq->placements[1]->index, true);
1434 } 1448 }
1435 /* 1449 /*
1436 * Now read out the whole dsf into pc_scratch, flattening its 1450 * Now read out the whole dsf into pc_scratch, flattening its
@@ -1443,7 +1457,7 @@ static bool deduce_forcing_chain(struct solver_scratch *sc)
1443 */ 1457 */
1444 for (pi = 0; pi < sc->pc; pi++) { 1458 for (pi = 0; pi < sc->pc; pi++) {
1445 bool inv; 1459 bool inv;
1446 int c = edsf_canonify(sc->pc_scratch2, pi, &inv); 1460 int c = dsf_canonify_flip(sc->dsf_scratch, pi, &inv);
1447 sc->pc_scratch[pi] = c * 2 + (inv ? 1 : 0); 1461 sc->pc_scratch[pi] = c * 2 + (inv ? 1 : 0);
1448 } 1462 }
1449 1463
@@ -2708,7 +2722,7 @@ static game_ui *new_ui(const game_state *state)
2708{ 2722{
2709 game_ui *ui = snew(game_ui); 2723 game_ui *ui = snew(game_ui);
2710 ui->cur_x = ui->cur_y = 0; 2724 ui->cur_x = ui->cur_y = 0;
2711 ui->cur_visible = false; 2725 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
2712 ui->highlight_1 = ui->highlight_2 = -1; 2726 ui->highlight_1 = ui->highlight_2 = -1;
2713 return ui; 2727 return ui;
2714} 2728}
@@ -2718,15 +2732,6 @@ static void free_ui(game_ui *ui)
2718 sfree(ui); 2732 sfree(ui);
2719} 2733}
2720 2734
2721static char *encode_ui(const game_ui *ui)
2722{
2723 return NULL;
2724}
2725
2726static void decode_ui(game_ui *ui, const char *encoding)
2727{
2728}
2729
2730static void game_changed_state(game_ui *ui, const game_state *oldstate, 2735static void game_changed_state(game_ui *ui, const game_state *oldstate,
2731 const game_state *newstate) 2736 const game_state *newstate)
2732{ 2737{
@@ -2734,6 +2739,33 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
2734 ui->cur_visible = false; 2739 ui->cur_visible = false;
2735} 2740}
2736 2741
2742static const char *current_key_label(const game_ui *ui,
2743 const game_state *state, int button)
2744{
2745 if (IS_CURSOR_SELECT(button)) {
2746 int d1, d2, w = state->w;
2747
2748 if (!((ui->cur_x ^ ui->cur_y) & 1))
2749 return ""; /* must have exactly one dimension odd */
2750 d1 = (ui->cur_y / 2) * w + (ui->cur_x / 2);
2751 d2 = ((ui->cur_y+1) / 2) * w + ((ui->cur_x+1) / 2);
2752
2753 /* We can't mark an edge next to any domino. */
2754 if (button == CURSOR_SELECT2 &&
2755 (state->grid[d1] != d1 || state->grid[d2] != d2))
2756 return "";
2757 if (button == CURSOR_SELECT) {
2758 if (state->grid[d1] == d2) return "Remove";
2759 return "Place";
2760 } else {
2761 int edge = d2 == d1 + 1 ? EDGE_R : EDGE_B;
2762 if (state->edges[d1] & edge) return "Remove";
2763 return "Line";
2764 }
2765 }
2766 return "";
2767}
2768
2737#define PREFERRED_TILESIZE 32 2769#define PREFERRED_TILESIZE 32
2738#define TILESIZE (ds->tilesize) 2770#define TILESIZE (ds->tilesize)
2739#define BORDER (TILESIZE * 3 / 4) 2771#define BORDER (TILESIZE * 3 / 4)
@@ -2746,7 +2778,6 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
2746#define FROMCOORD(x) ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 ) 2778#define FROMCOORD(x) ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 )
2747 2779
2748struct game_drawstate { 2780struct game_drawstate {
2749 bool started;
2750 int w, h, tilesize; 2781 int w, h, tilesize;
2751 unsigned long *visible; 2782 unsigned long *visible;
2752}; 2783};
@@ -2768,7 +2799,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2768 int d1, d2; 2799 int d1, d2;
2769 2800
2770 if (tx < 0 || tx >= w || ty < 0 || ty >= h) 2801 if (tx < 0 || tx >= w || ty < 0 || ty >= h)
2771 return NULL; 2802 return MOVE_UNUSED;
2772 2803
2773 /* 2804 /*
2774 * Now we know which square the click was in, decide which 2805 * Now we know which square the click was in, decide which
@@ -2786,29 +2817,26 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2786 else if (abs(dy) > abs(dx) && dy > 0 && ty+1 < h) 2817 else if (abs(dy) > abs(dx) && dy > 0 && ty+1 < h)
2787 d1 = t, d2 = t + w; /* clicked in top half of domino */ 2818 d1 = t, d2 = t + w; /* clicked in top half of domino */
2788 else 2819 else
2789 return NULL; 2820 return MOVE_NO_EFFECT; /* clicked precisely on a diagonal */
2790 2821
2791 /* 2822 /*
2792 * We can't mark an edge next to any domino. 2823 * We can't mark an edge next to any domino.
2793 */ 2824 */
2794 if (button == RIGHT_BUTTON && 2825 if (button == RIGHT_BUTTON &&
2795 (state->grid[d1] != d1 || state->grid[d2] != d2)) 2826 (state->grid[d1] != d1 || state->grid[d2] != d2))
2796 return NULL; 2827 return MOVE_NO_EFFECT;
2797 2828
2798 ui->cur_visible = false; 2829 ui->cur_visible = false;
2799 sprintf(buf, "%c%d,%d", (int)(button == RIGHT_BUTTON ? 'E' : 'D'), d1, d2); 2830 sprintf(buf, "%c%d,%d", (int)(button == RIGHT_BUTTON ? 'E' : 'D'), d1, d2);
2800 return dupstr(buf); 2831 return dupstr(buf);
2801 } else if (IS_CURSOR_MOVE(button)) { 2832 } else if (IS_CURSOR_MOVE(button)) {
2802 ui->cur_visible = true; 2833 return move_cursor(button, &ui->cur_x, &ui->cur_y, 2*w-1, 2*h-1, false,
2803 2834 &ui->cur_visible);
2804 move_cursor(button, &ui->cur_x, &ui->cur_y, 2*w-1, 2*h-1, false);
2805
2806 return UI_UPDATE;
2807 } else if (IS_CURSOR_SELECT(button)) { 2835 } else if (IS_CURSOR_SELECT(button)) {
2808 int d1, d2; 2836 int d1, d2;
2809 2837
2810 if (!((ui->cur_x ^ ui->cur_y) & 1)) 2838 if (!((ui->cur_x ^ ui->cur_y) & 1))
2811 return NULL; /* must have exactly one dimension odd */ 2839 return MOVE_NO_EFFECT; /* must have exactly one dimension odd */
2812 d1 = (ui->cur_y / 2) * w + (ui->cur_x / 2); 2840 d1 = (ui->cur_y / 2) * w + (ui->cur_x / 2);
2813 d2 = ((ui->cur_y+1) / 2) * w + ((ui->cur_x+1) / 2); 2841 d2 = ((ui->cur_y+1) / 2) * w + ((ui->cur_x+1) / 2);
2814 2842
@@ -2817,14 +2845,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2817 */ 2845 */
2818 if (button == CURSOR_SELECT2 && 2846 if (button == CURSOR_SELECT2 &&
2819 (state->grid[d1] != d1 || state->grid[d2] != d2)) 2847 (state->grid[d1] != d1 || state->grid[d2] != d2))
2820 return NULL; 2848 return MOVE_NO_EFFECT;
2821 2849
2822 sprintf(buf, "%c%d,%d", (int)(button == CURSOR_SELECT2 ? 'E' : 'D'), d1, d2); 2850 sprintf(buf, "%c%d,%d", (int)(button == CURSOR_SELECT2 ? 'E' : 'D'), d1, d2);
2823 return dupstr(buf); 2851 return dupstr(buf);
2824 } else if (isdigit(button)) { 2852 } else if (isdigit(button)) {
2825 int n = state->params.n, num = button - '0'; 2853 int n = state->params.n, num = button - '0';
2826 if (num > n) { 2854 if (num > n) {
2827 return NULL; 2855 return MOVE_UNUSED;
2828 } else if (ui->highlight_1 == num) { 2856 } else if (ui->highlight_1 == num) {
2829 ui->highlight_1 = -1; 2857 ui->highlight_1 = -1;
2830 } else if (ui->highlight_2 == num) { 2858 } else if (ui->highlight_2 == num) {
@@ -2834,12 +2862,12 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2834 } else if (ui->highlight_2 == -1) { 2862 } else if (ui->highlight_2 == -1) {
2835 ui->highlight_2 = num; 2863 ui->highlight_2 = num;
2836 } else { 2864 } else {
2837 return NULL; 2865 return MOVE_NO_EFFECT;
2838 } 2866 }
2839 return UI_UPDATE; 2867 return MOVE_UI_UPDATE;
2840 } 2868 }
2841 2869
2842 return NULL; 2870 return MOVE_UNUSED;
2843} 2871}
2844 2872
2845static game_state *execute_move(const game_state *state, const char *move) 2873static game_state *execute_move(const game_state *state, const char *move)
@@ -2865,7 +2893,8 @@ static game_state *execute_move(const game_state *state, const char *move)
2865 move++; 2893 move++;
2866 } else if (move[0] == 'D' && 2894 } else if (move[0] == 'D' &&
2867 sscanf(move+1, "%d,%d%n", &d1, &d2, &p) == 2 && 2895 sscanf(move+1, "%d,%d%n", &d1, &d2, &p) == 2 &&
2868 d1 >= 0 && d1 < wh && d2 >= 0 && d2 < wh && d1 < d2) { 2896 d1 >= 0 && d1 < wh && d2 >= 0 && d2 < wh && d1 < d2 &&
2897 (d2 - d1 == 1 || d2 - d1 == w)) {
2869 2898
2870 /* 2899 /*
2871 * Toggle domino presence between d1 and d2. 2900 * Toggle domino presence between d1 and d2.
@@ -2933,7 +2962,8 @@ static game_state *execute_move(const game_state *state, const char *move)
2933 } else if (move[0] == 'E' && 2962 } else if (move[0] == 'E' &&
2934 sscanf(move+1, "%d,%d%n", &d1, &d2, &p) == 2 && 2963 sscanf(move+1, "%d,%d%n", &d1, &d2, &p) == 2 &&
2935 d1 >= 0 && d1 < wh && d2 >= 0 && d2 < wh && d1 < d2 && 2964 d1 >= 0 && d1 < wh && d2 >= 0 && d2 < wh && d1 < d2 &&
2936 ret->grid[d1] == d1 && ret->grid[d2] == d2) { 2965 ret->grid[d1] == d1 && ret->grid[d2] == d2 &&
2966 (d2 - d1 == 1 || d2 - d1 == w)) {
2937 2967
2938 /* 2968 /*
2939 * Toggle edge presence between d1 and d2. 2969 * Toggle edge presence between d1 and d2.
@@ -2998,7 +3028,7 @@ static game_state *execute_move(const game_state *state, const char *move)
2998 */ 3028 */
2999 3029
3000static void game_compute_size(const game_params *params, int tilesize, 3030static void game_compute_size(const game_params *params, int tilesize,
3001 int *x, int *y) 3031 const game_ui *ui, int *x, int *y)
3002{ 3032{
3003 int n = params->n, w = n+2, h = n+1; 3033 int n = params->n, w = n+2, h = n+1;
3004 3034
@@ -3059,7 +3089,6 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
3059 struct game_drawstate *ds = snew(struct game_drawstate); 3089 struct game_drawstate *ds = snew(struct game_drawstate);
3060 int i; 3090 int i;
3061 3091
3062 ds->started = false;
3063 ds->w = state->w; 3092 ds->w = state->w;
3064 ds->h = state->h; 3093 ds->h = state->h;
3065 ds->visible = snewn(ds->w * ds->h, unsigned long); 3094 ds->visible = snewn(ds->w * ds->h, unsigned long);
@@ -3225,14 +3254,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
3225 int x, y, i; 3254 int x, y, i;
3226 unsigned char *used; 3255 unsigned char *used;
3227 3256
3228 if (!ds->started) {
3229 int pw, ph;
3230 game_compute_size(&state->params, TILESIZE, &pw, &ph);
3231 draw_rect(dr, 0, 0, pw, ph, COL_BACKGROUND);
3232 draw_update(dr, 0, 0, pw, ph);
3233 ds->started = true;
3234 }
3235
3236 /* 3257 /*
3237 * See how many dominoes of each type there are, so we can 3258 * See how many dominoes of each type there are, so we can
3238 * highlight clashes in red. 3259 * highlight clashes in red.
@@ -3347,24 +3368,21 @@ static int game_status(const game_state *state)
3347 return state->completed ? +1 : 0; 3368 return state->completed ? +1 : 0;
3348} 3369}
3349 3370
3350static bool game_timing_state(const game_state *state, game_ui *ui) 3371static void game_print_size(const game_params *params, const game_ui *ui,
3351{ 3372 float *x, float *y)
3352 return true;
3353}
3354
3355static void game_print_size(const game_params *params, float *x, float *y)
3356{ 3373{
3357 int pw, ph; 3374 int pw, ph;
3358 3375
3359 /* 3376 /*
3360 * I'll use 6mm squares by default. 3377 * I'll use 6mm squares by default.
3361 */ 3378 */
3362 game_compute_size(params, 600, &pw, &ph); 3379 game_compute_size(params, 600, ui, &pw, &ph);
3363 *x = pw / 100.0F; 3380 *x = pw / 100.0F;
3364 *y = ph / 100.0F; 3381 *y = ph / 100.0F;
3365} 3382}
3366 3383
3367static void game_print(drawing *dr, const game_state *state, int tilesize) 3384static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
3385 int tilesize)
3368{ 3386{
3369 int w = state->w, h = state->h; 3387 int w = state->w, h = state->h;
3370 int c, x, y; 3388 int c, x, y;
@@ -3421,12 +3439,14 @@ const struct game thegame = {
3421 free_game, 3439 free_game,
3422 true, solve_game, 3440 true, solve_game,
3423 true, game_can_format_as_text_now, game_text_format, 3441 true, game_can_format_as_text_now, game_text_format,
3442 NULL, NULL, /* get_prefs, set_prefs */
3424 new_ui, 3443 new_ui,
3425 free_ui, 3444 free_ui,
3426 encode_ui, 3445 NULL, /* encode_ui */
3427 decode_ui, 3446 NULL, /* decode_ui */
3428 NULL, /* game_request_keys */ 3447 NULL, /* game_request_keys */
3429 game_changed_state, 3448 game_changed_state,
3449 current_key_label,
3430 interpret_move, 3450 interpret_move,
3431 execute_move, 3451 execute_move,
3432 PREFERRED_TILESIZE, game_compute_size, game_set_size, 3452 PREFERRED_TILESIZE, game_compute_size, game_set_size,
@@ -3440,7 +3460,7 @@ const struct game thegame = {
3440 game_status, 3460 game_status,
3441 true, false, game_print_size, game_print, 3461 true, false, game_print_size, game_print,
3442 false, /* wants_statusbar */ 3462 false, /* wants_statusbar */
3443 false, game_timing_state, 3463 false, NULL, /* timing_state */
3444 0, /* flags */ 3464 0, /* flags */
3445}; 3465};
3446 3466
diff --git a/apps/plugins/puzzles/src/drawing.c b/apps/plugins/puzzles/src/drawing.c
index a8eb8cfd5f..2c8816c31a 100644
--- a/apps/plugins/puzzles/src/drawing.c
+++ b/apps/plugins/puzzles/src/drawing.c
@@ -27,7 +27,11 @@
27#include <stdlib.h> 27#include <stdlib.h>
28#include <string.h> 28#include <string.h>
29#include <assert.h> 29#include <assert.h>
30#include <math.h> 30#ifdef NO_TGMATH_H
31# include <math.h>
32#else
33# include <tgmath.h>
34#endif
31 35
32#include "puzzles.h" 36#include "puzzles.h"
33 37
@@ -90,8 +94,8 @@ void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour)
90void draw_thick_line(drawing *dr, float thickness, 94void draw_thick_line(drawing *dr, float thickness,
91 float x1, float y1, float x2, float y2, int colour) 95 float x1, float y1, float x2, float y2, int colour)
92{ 96{
93 if (thickness < 1.0) 97 if (thickness < 1.0F)
94 thickness = 1.0; 98 thickness = 1.0F;
95 if (dr->api->draw_thick_line) { 99 if (dr->api->draw_thick_line) {
96 dr->api->draw_thick_line(dr->handle, thickness, 100 dr->api->draw_thick_line(dr->handle, thickness,
97 x1, y1, x2, y2, colour); 101 x1, y1, x2, y2, colour);
@@ -101,8 +105,8 @@ void draw_thick_line(drawing *dr, float thickness,
101 * polygon rendering uses integer coordinates. 105 * polygon rendering uses integer coordinates.
102 */ 106 */
103 float len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)); 107 float len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
104 float tvhatx = (x2 - x1)/len * (thickness/2 - 0.2); 108 float tvhatx = (x2 - x1)/len * (thickness/2 - 0.2F);
105 float tvhaty = (y2 - y1)/len * (thickness/2 - 0.2); 109 float tvhaty = (y2 - y1)/len * (thickness/2 - 0.2F);
106 int p[8]; 110 int p[8];
107 111
108 p[0] = x1 - tvhaty; 112 p[0] = x1 - tvhaty;
@@ -117,7 +121,7 @@ void draw_thick_line(drawing *dr, float thickness,
117 } 121 }
118} 122}
119 123
120void draw_polygon(drawing *dr, int *coords, int npoints, 124void draw_polygon(drawing *dr, const int *coords, int npoints,
121 int fillcolour, int outlinecolour) 125 int fillcolour, int outlinecolour)
122{ 126{
123 dr->api->draw_polygon(dr->handle, coords, npoints, fillcolour, 127 dr->api->draw_polygon(dr->handle, coords, npoints, fillcolour,
diff --git a/apps/plugins/puzzles/src/dsf.c b/apps/plugins/puzzles/src/dsf.c
index 832bb3005a..bed564f8ec 100644
--- a/apps/plugins/puzzles/src/dsf.c
+++ b/apps/plugins/puzzles/src/dsf.c
@@ -5,188 +5,301 @@
5 */ 5 */
6 6
7#include <assert.h> 7#include <assert.h>
8#include <limits.h>
8#include <string.h> 9#include <string.h>
9 10
10#include "puzzles.h" 11#include "puzzles.h"
11 12
12/*void print_dsf(int *dsf, int size) 13#define DSF_INDEX_MASK (UINT_MAX >> 1)
14#define DSF_FLAG_CANONICAL (UINT_MAX & ~(UINT_MAX >> 1))
15#define DSF_MAX (DSF_INDEX_MASK + 1)
16
17struct DSF {
18 /*
19 * Size of the dsf.
20 */
21 size_t size;
22
23 /*
24 * Main array storing the data structure.
25 *
26 * If n is the canonical element of an equivalence class,
27 * parent_or_size[n] holds the number of elements in that class,
28 * bitwise-ORed with DSF_FLAG_CANONICAL.
29 *
30 * If n is not the canonical element, parent_or_size[n] holds the
31 * index of another element nearer to the root of the tree for
32 * that class.
33 */
34 unsigned *parent_or_size;
35
36 /*
37 * Extra storage for flip tracking.
38 *
39 * If n is not a canonical element, flip[n] indicates whether the
40 * sense of this element is flipped relative to parent_or_size[n].
41 *
42 * If n is a canonical element, flip[n] is unused.
43 */
44 unsigned char *flip;
45
46 /*
47 * Extra storage for minimal-element tracking.
48 *
49 * If n is a canonical element, min[n] holds the index of the
50 * smallest value in n's equivalence class.
51 *
52 * If n is not a canonical element, min[n] is unused.
53 */
54 unsigned *min;
55};
56
57static DSF *dsf_new_internal(int size, bool flip, bool min)
13{ 58{
14 int *printed_elements = snewn(size, int); 59 DSF *dsf;
15 int *equal_elements = snewn(size, int);
16 int *inverse_elements = snewn(size, int);
17 int printed_count = 0, equal_count, inverse_count;
18 int i, n;
19 bool inverse;
20 60
21 memset(printed_elements, -1, sizeof(int) * size); 61 assert(0 < size && size <= DSF_MAX && "Bad dsf size");
22 62
23 while (1) { 63 dsf = snew(DSF);
24 equal_count = 0; 64 dsf->size = size;
25 inverse_count = 0; 65 dsf->parent_or_size = snewn(size, unsigned);
26 for (i = 0; i < size; ++i) { 66 dsf->flip = flip ? snewn(size, unsigned char) : NULL;
27 if (!memchr(printed_elements, i, sizeof(int) * size)) 67 dsf->min = min ? snewn(size, unsigned) : NULL;
28 break; 68
29 } 69 dsf_reinit(dsf);
30 if (i == size)
31 goto done;
32
33 i = dsf_canonify(dsf, i);
34
35 for (n = 0; n < size; ++n) {
36 if (edsf_canonify(dsf, n, &inverse) == i) {
37 if (inverse)
38 inverse_elements[inverse_count++] = n;
39 else
40 equal_elements[equal_count++] = n;
41 }
42 }
43
44 for (n = 0; n < equal_count; ++n) {
45 fprintf(stderr, "%d ", equal_elements[n]);
46 printed_elements[printed_count++] = equal_elements[n];
47 }
48 if (inverse_count) {
49 fprintf(stderr, "!= ");
50 for (n = 0; n < inverse_count; ++n) {
51 fprintf(stderr, "%d ", inverse_elements[n]);
52 printed_elements[printed_count++] = inverse_elements[n];
53 }
54 }
55 fprintf(stderr, "\n");
56 }
57done:
58 70
59 sfree(printed_elements); 71 return dsf;
60 sfree(equal_elements); 72}
61 sfree(inverse_elements);
62}*/
63 73
64void dsf_init(int *dsf, int size) 74DSF *dsf_new(int size)
65{ 75{
66 int i; 76 return dsf_new_internal(size, false, false);
77}
67 78
68 for (i = 0; i < size; i++) dsf[i] = 6; 79DSF *dsf_new_flip(int size)
69 /* Bottom bit of each element of this array stores whether that 80{
70 * element is opposite to its parent, which starts off as 81 return dsf_new_internal(size, true, false);
71 * false. Second bit of each element stores whether that element
72 * is the root of its tree or not. If it's not the root, the
73 * remaining 30 bits are the parent, otherwise the remaining 30
74 * bits are the number of elements in the tree. */
75} 82}
76 83
77int *snew_dsf(int size) 84DSF *dsf_new_min(int size)
78{ 85{
79 int *ret; 86 return dsf_new_internal(size, false, true);
80 87}
81 ret = snewn(size, int); 88
82 dsf_init(ret, size); 89void dsf_reinit(DSF *dsf)
90{
91 size_t i;
92
93 /* Every element starts as the root of an equivalence class of size 1 */
94 for (i = 0; i < dsf->size; i++)
95 dsf->parent_or_size[i] = DSF_FLAG_CANONICAL | 1;
83 96
84 /*print_dsf(ret, size); */ 97 /* If we're tracking minima then every element is also its own min */
98 if (dsf->min)
99 for (i = 0; i < dsf->size; i++)
100 dsf->min[i] = i;
85 101
86 return ret; 102 /* No need to initialise dsf->flip, even if it exists, because
103 * only the entries for non-root elements are meaningful, and
104 * currently there are none. */
87} 105}
88 106
89int dsf_canonify(int *dsf, int index) 107void dsf_copy(DSF *to, DSF *from)
90{ 108{
91 return edsf_canonify(dsf, index, NULL); 109 assert(to->size == from->size && "Mismatch in dsf_copy");
110 memcpy(to->parent_or_size, from->parent_or_size,
111 to->size * sizeof(*to->parent_or_size));
112 if (to->flip) {
113 assert(from->flip && "Copying a non-flip dsf to a flip one");
114 memcpy(to->flip, from->flip, to->size * sizeof(*to->flip));
115 }
116 if (to->min) {
117 assert(from->min && "Copying a non-min dsf to a min one");
118 memcpy(to->min, from->min, to->size * sizeof(*to->min));
119 }
92} 120}
93 121
94void dsf_merge(int *dsf, int v1, int v2) 122
123void dsf_free(DSF *dsf)
95{ 124{
96 edsf_merge(dsf, v1, v2, false); 125 if (dsf) {
126 sfree(dsf->parent_or_size);
127 sfree(dsf->flip);
128 sfree(dsf->min);
129 sfree(dsf);
130 }
97} 131}
98 132
99int dsf_size(int *dsf, int index) { 133static inline size_t dsf_find_root(DSF *dsf, size_t n)
100 return dsf[dsf_canonify(dsf, index)] >> 2; 134{
135 while (!(dsf->parent_or_size[n] & DSF_FLAG_CANONICAL))
136 n = dsf->parent_or_size[n];
137 return n;
138}
139
140static inline void dsf_path_compress(DSF *dsf, size_t n, size_t root)
141{
142 while (!(dsf->parent_or_size[n] & DSF_FLAG_CANONICAL)) {
143 size_t prev = n;
144 n = dsf->parent_or_size[n];
145 dsf->parent_or_size[prev] = root;
146 }
147 assert(n == root);
101} 148}
102 149
103int edsf_canonify(int *dsf, int index, bool *inverse_return) 150int dsf_canonify(DSF *dsf, int n)
104{ 151{
105 int start_index = index, canonical_index; 152 size_t root;
106 bool inverse = false;
107 153
108/* fprintf(stderr, "dsf = %p\n", dsf); */ 154 assert(0 <= n && n < dsf->size && "Overrun in dsf_canonify");
109/* fprintf(stderr, "Canonify %2d\n", index); */
110 155
111 assert(index >= 0); 156 root = dsf_find_root(dsf, n);
157 dsf_path_compress(dsf, n, root);
158 return root;
159}
160
161void dsf_merge(DSF *dsf, int n1, int n2)
162{
163 size_t r1, r2, s1, s2, root;
164
165 assert(0 <= n1 && n1 < dsf->size && "Overrun in dsf_merge");
166 assert(0 <= n2 && n2 < dsf->size && "Overrun in dsf_merge");
167 assert(!dsf->flip && "dsf_merge on a flip dsf");
168
169 /* Find the root elements */
170 r1 = dsf_find_root(dsf, n1);
171 r2 = dsf_find_root(dsf, n2);
172
173 if (r1 == r2) {
174 /* Classes are already the same, so we have a common root */
175 root = r1;
176 } else {
177 /* Classes must be merged */
178
179 /* Decide which one to use as the overall root, based on size */
180 s1 = dsf->parent_or_size[r1] & DSF_INDEX_MASK;
181 s2 = dsf->parent_or_size[r2] & DSF_INDEX_MASK;
182 if (s1 > s2) {
183 dsf->parent_or_size[r2] = root = r1;
184 } else {
185 dsf->parent_or_size[r1] = root = r2;
186 }
187 dsf->parent_or_size[root] = (s1 + s2) | DSF_FLAG_CANONICAL;
112 188
113 /* Find the index of the canonical element of the 'equivalence class' of 189 if (dsf->min) {
114 * which start_index is a member, and figure out whether start_index is the 190 /* Update the min of the merged class */
115 * same as or inverse to that. */ 191 unsigned m1 = dsf->min[r1], m2 = dsf->min[r2];
116 while ((dsf[index] & 2) == 0) { 192 dsf->min[root] = m1 < m2 ? m1 : m2;
117 inverse ^= (dsf[index] & 1); 193 }
118 index = dsf[index] >> 2;
119/* fprintf(stderr, "index = %2d, ", index); */
120/* fprintf(stderr, "inverse = %d\n", inverse); */
121 } 194 }
122 canonical_index = index; 195
123 196 /* Path-compress both paths from n1 and n2 so they point at the new root */
124 if (inverse_return) 197 dsf_path_compress(dsf, n1, root);
125 *inverse_return = inverse; 198 dsf_path_compress(dsf, n2, root);
126 199}
127 /* Update every member of this 'equivalence class' to point directly at the 200
128 * canonical member. */ 201bool dsf_equivalent(DSF *dsf, int n1, int n2)
129 index = start_index; 202{
130 while (index != canonical_index) { 203 return dsf_canonify(dsf, n1) == dsf_canonify(dsf, n2);
131 int nextindex = dsf[index] >> 2; 204}
132 bool nextinverse = inverse ^ (dsf[index] & 1); 205
133 dsf[index] = (canonical_index << 2) | inverse; 206int dsf_size(DSF *dsf, int n)
134 inverse = nextinverse; 207{
135 index = nextindex; 208 size_t root = dsf_canonify(dsf, n);
209 return dsf->parent_or_size[root] & DSF_INDEX_MASK;
210}
211
212static inline size_t dsf_find_root_flip(DSF *dsf, size_t n, unsigned *flip)
213{
214 *flip = 0;
215 while (!(dsf->parent_or_size[n] & DSF_FLAG_CANONICAL)) {
216 *flip ^= dsf->flip[n];
217 n = dsf->parent_or_size[n];
218 }
219 return n;
220}
221
222static inline void dsf_path_compress_flip(DSF *dsf, size_t n, size_t root,
223 unsigned flip)
224{
225 while (!(dsf->parent_or_size[n] & DSF_FLAG_CANONICAL)) {
226 size_t prev = n;
227 unsigned flip_prev = flip;
228 n = dsf->parent_or_size[n];
229 flip ^= dsf->flip[prev];
230 dsf->flip[prev] = flip_prev;
231 dsf->parent_or_size[prev] = root;
136 } 232 }
233 assert(n == root);
234}
235
236int dsf_canonify_flip(DSF *dsf, int n, bool *inverse)
237{
238 size_t root;
239 unsigned flip;
240
241 assert(0 <= n && n < dsf->size && "Overrun in dsf_canonify_flip");
242 assert(dsf->flip && "dsf_canonify_flip on a non-flip dsf");
243
244 root = dsf_find_root_flip(dsf, n, &flip);
245 dsf_path_compress_flip(dsf, n, root, flip);
246 *inverse = flip;
247 return root;
248}
249
250void dsf_merge_flip(DSF *dsf, int n1, int n2, bool inverse)
251{
252 size_t r1, r2, s1, s2, root;
253 unsigned f1, f2;
254
255 assert(0 <= n1 && n1 < dsf->size && "Overrun in dsf_merge_flip");
256 assert(0 <= n2 && n2 < dsf->size && "Overrun in dsf_merge_flip");
257 assert(dsf->flip && "dsf_merge_flip on a non-flip dsf");
258
259 /* Find the root elements */
260 r1 = dsf_find_root_flip(dsf, n1, &f1);
261 r2 = dsf_find_root_flip(dsf, n2, &f2);
262
263 if (r1 == r2) {
264 /* Classes are already the same, so we have a common root */
265 assert((f1 ^ f2 ^ inverse) == 0 && "Inconsistency in dsf_merge_flip");
266 root = r1;
267 } else {
268 /* Classes must be merged */
137 269
138 assert(!inverse); 270 /* Decide which one to use as the overall root, based on size */
139 271 s1 = dsf->parent_or_size[r1] & DSF_INDEX_MASK;
140/* fprintf(stderr, "Return %2d\n", index); */ 272 s2 = dsf->parent_or_size[r2] & DSF_INDEX_MASK;
141 273 if (s1 > s2) {
142 return index; 274 dsf->parent_or_size[r2] = root = r1;
143} 275 dsf->flip[r2] = f1 ^ f2 ^ inverse;
144 276 f2 ^= dsf->flip[r2];
145void edsf_merge(int *dsf, int v1, int v2, bool inverse) 277 } else {
146{ 278 root = r2;
147 bool i1, i2; 279 dsf->parent_or_size[r1] = root = r2;
148 280 dsf->flip[r1] = f1 ^ f2 ^ inverse;
149/* fprintf(stderr, "dsf = %p\n", dsf); */ 281 f1 ^= dsf->flip[r1];
150/* fprintf(stderr, "Merge [%2d,%2d], %d\n", v1, v2, inverse); */ 282 }
151 283 dsf->parent_or_size[root] = (s1 + s2) | DSF_FLAG_CANONICAL;
152 v1 = edsf_canonify(dsf, v1, &i1); 284
153 assert(dsf[v1] & 2); 285 if (dsf->min) {
154 inverse ^= i1; 286 /* Update the min of the merged class */
155 v2 = edsf_canonify(dsf, v2, &i2); 287 unsigned m1 = dsf->min[r1], m2 = dsf->min[r2];
156 assert(dsf[v2] & 2); 288 dsf->min[root] = m1 < m2 ? m1 : m2;
157 inverse ^= i2; 289 }
158
159/* fprintf(stderr, "Doing [%2d,%2d], %d\n", v1, v2, inverse); */
160
161 if (v1 == v2)
162 assert(!inverse);
163 else {
164 /*
165 * We always make the smaller of v1 and v2 the new canonical
166 * element. This ensures that the canonical element of any
167 * class in this structure is always the first element in
168 * it. 'Keen' depends critically on this property.
169 *
170 * (Jonas Koelker previously had this code choosing which
171 * way round to connect the trees by examining the sizes of
172 * the classes being merged, so that the root of the
173 * larger-sized class became the new root. This gives better
174 * asymptotic performance, but I've changed it to do it this
175 * way because I like having a deterministic canonical
176 * element.)
177 */
178 if (v1 > v2) {
179 int v3 = v1;
180 v1 = v2;
181 v2 = v3;
182 }
183 dsf[v1] += (dsf[v2] >> 2) << 2;
184 dsf[v2] = (v1 << 2) | inverse;
185 } 290 }
186
187 v2 = edsf_canonify(dsf, v2, &i2);
188 assert(v2 == v1);
189 assert(i2 == inverse);
190 291
191/* fprintf(stderr, "dsf[%2d] = %2d\n", v2, dsf[v2]); */ 292 /* Path-compress both paths from n1 and n2 so they point at the new root */
293 dsf_path_compress_flip(dsf, n1, root, f1);
294 dsf_path_compress_flip(dsf, n2, root, f2);
295}
296
297int dsf_minimal(DSF *dsf, int n)
298{
299 size_t root;
300
301 assert(dsf->min && "dsf_minimal on a non-min dsf");
302
303 root = dsf_canonify(dsf, n);
304 return dsf->min[root];
192} 305}
diff --git a/apps/plugins/puzzles/src/emcc.c b/apps/plugins/puzzles/src/emcc.c
index 9a6c742482..6aa9c6b093 100644
--- a/apps/plugins/puzzles/src/emcc.c
+++ b/apps/plugins/puzzles/src/emcc.c
@@ -12,19 +12,8 @@
12/* 12/*
13 * Further thoughts on possible enhancements: 13 * Further thoughts on possible enhancements:
14 * 14 *
15 * - I think it might be feasible to have these JS puzzles permit
16 * loading and saving games in disk files. Saving would be done by
17 * constructing a data: URI encapsulating the save file, and then
18 * telling the browser to visit that URI with the effect that it
19 * would naturally pop up a 'where would you like to save this'
20 * dialog box. Loading, more or less similarly, might be feasible
21 * by using the DOM File API to ask the user to select a file and
22 * permit us to see its contents.
23 *
24 * - I should think about whether these webified puzzles can support 15 * - I should think about whether these webified puzzles can support
25 * touchscreen-based tablet browsers (assuming there are any that 16 * touchscreen-based tablet browsers.
26 * can cope with the reasonably modern JS and run it fast enough to
27 * be worthwhile).
28 * 17 *
29 * - think about making use of localStorage. It might be useful to 18 * - think about making use of localStorage. It might be useful to
30 * let the user save games into there as an alternative to disk 19 * let the user save games into there as an alternative to disk
@@ -32,11 +21,7 @@
32 * out of your browser to (e.g.) email to me as a bug report, but 21 * out of your browser to (e.g.) email to me as a bug report, but
33 * for just resuming a game you were in the middle of, you'd 22 * for just resuming a game you were in the middle of, you'd
34 * probably rather have a nice simple 'quick save' and 'quick load' 23 * probably rather have a nice simple 'quick save' and 'quick load'
35 * button pair. Also, that might be a useful place to store 24 * button pair.
36 * preferences, if I ever get round to writing a preferences UI.
37 *
38 * - some CSS to make the button bar and configuration dialogs a
39 * little less ugly would probably not go amiss.
40 * 25 *
41 * - this is a downright silly idea, but it does occur to me that if 26 * - this is a downright silly idea, but it does occur to me that if
42 * I were to write a PDF output driver for the Puzzles printing 27 * I were to write a PDF output driver for the Puzzles printing
@@ -57,6 +42,8 @@
57/* 42/*
58 * Extern references to Javascript functions provided in emcclib.js. 43 * Extern references to Javascript functions provided in emcclib.js.
59 */ 44 */
45extern void js_init_puzzle(void);
46extern void js_post_init(void);
60extern void js_debug(const char *); 47extern void js_debug(const char *);
61extern void js_error_box(const char *message); 48extern void js_error_box(const char *message);
62extern void js_remove_type_dropdown(void); 49extern void js_remove_type_dropdown(void);
@@ -65,37 +52,39 @@ extern void js_add_preset(int menuid, const char *name, int value);
65extern int js_add_preset_submenu(int menuid, const char *name); 52extern int js_add_preset_submenu(int menuid, const char *name);
66extern int js_get_selected_preset(void); 53extern int js_get_selected_preset(void);
67extern void js_select_preset(int n); 54extern void js_select_preset(int n);
55extern void js_default_colour(float *output);
56extern void js_set_colour(int colour_number, const char *colour_string);
68extern void js_get_date_64(unsigned *p); 57extern void js_get_date_64(unsigned *p);
69extern void js_update_permalinks(const char *desc, const char *seed); 58extern void js_update_permalinks(const char *desc, const char *seed);
70extern void js_enable_undo_redo(bool undo, bool redo); 59extern void js_enable_undo_redo(bool undo, bool redo);
71extern void js_activate_timer(); 60extern void js_update_key_labels(const char *lsk, const char *csk);
72extern void js_deactivate_timer(); 61extern void js_activate_timer(void);
62extern void js_deactivate_timer(void);
73extern void js_canvas_start_draw(void); 63extern void js_canvas_start_draw(void);
74extern void js_canvas_draw_update(int x, int y, int w, int h); 64extern void js_canvas_draw_update(int x, int y, int w, int h);
75extern void js_canvas_end_draw(void); 65extern void js_canvas_end_draw(void);
76extern void js_canvas_draw_rect(int x, int y, int w, int h, 66extern void js_canvas_draw_rect(int x, int y, int w, int h, int colour);
77 const char *colour);
78extern void js_canvas_clip_rect(int x, int y, int w, int h); 67extern void js_canvas_clip_rect(int x, int y, int w, int h);
79extern void js_canvas_unclip(void); 68extern void js_canvas_unclip(void);
80extern void js_canvas_draw_line(float x1, float y1, float x2, float y2, 69extern void js_canvas_draw_line(float x1, float y1, float x2, float y2,
81 int width, const char *colour); 70 int width, int colour);
82extern void js_canvas_draw_poly(int *points, int npoints, 71extern void js_canvas_draw_poly(const int *points, int npoints,
83 const char *fillcolour, 72 int fillcolour, int outlinecolour);
84 const char *outlinecolour);
85extern void js_canvas_draw_circle(int x, int y, int r, 73extern void js_canvas_draw_circle(int x, int y, int r,
86 const char *fillcolour, 74 int fillcolour, int outlinecolour);
87 const char *outlinecolour); 75extern int js_canvas_find_font_midpoint(int height, bool monospaced);
88extern int js_canvas_find_font_midpoint(int height, const char *fontptr);
89extern void js_canvas_draw_text(int x, int y, int halign, 76extern void js_canvas_draw_text(int x, int y, int halign,
90 const char *colptr, const char *fontptr, 77 int colour, int height,
91 const char *text); 78 bool monospaced, const char *text);
92extern int js_canvas_new_blitter(int w, int h); 79extern int js_canvas_new_blitter(int w, int h);
93extern void js_canvas_free_blitter(int id); 80extern void js_canvas_free_blitter(int id);
94extern void js_canvas_copy_to_blitter(int id, int x, int y, int w, int h); 81extern void js_canvas_copy_to_blitter(int id, int x, int y, int w, int h);
95extern void js_canvas_copy_from_blitter(int id, int x, int y, int w, int h); 82extern void js_canvas_copy_from_blitter(int id, int x, int y, int w, int h);
96extern void js_canvas_make_statusbar(void); 83extern void js_canvas_remove_statusbar(void);
97extern void js_canvas_set_statusbar(const char *text); 84extern void js_canvas_set_statusbar(const char *text);
85extern bool js_canvas_get_preferred_size(int *wp, int *hp);
98extern void js_canvas_set_size(int w, int h); 86extern void js_canvas_set_size(int w, int h);
87extern double js_get_device_pixel_ratio(void);
99 88
100extern void js_dialog_init(const char *title); 89extern void js_dialog_init(const char *title);
101extern void js_dialog_string(int i, const char *title, const char *initvalue); 90extern void js_dialog_string(int i, const char *title, const char *initvalue);
@@ -106,6 +95,38 @@ extern void js_dialog_launch(void);
106extern void js_dialog_cleanup(void); 95extern void js_dialog_cleanup(void);
107extern void js_focus_canvas(void); 96extern void js_focus_canvas(void);
108 97
98extern bool js_savefile_read(void *buf, int len);
99
100extern void js_save_prefs(const char *);
101extern void js_load_prefs(midend *);
102
103/*
104 * These functions are called from JavaScript, so their prototypes
105 * need to be kept in sync with emccpre.js.
106 */
107bool mouseup(int x, int y, int button);
108bool mousedown(int x, int y, int button);
109bool mousemove(int x, int y, int buttons);
110bool key(int keycode, const char *key, const char *chr, int location,
111 bool shift, bool ctrl);
112void timer_callback(double tplus);
113void command(int n);
114char *get_text_format(void);
115void free_save_file(char *buffer);
116char *get_save_file(void);
117void free_save_file(char *buffer);
118void load_game(void);
119void dlg_return_sval(int index, const char *val);
120void dlg_return_ival(int index, int val);
121void resize_puzzle(int w, int h);
122void restore_puzzle_size(int w, int h);
123void rescale_puzzle(void);
124
125/*
126 * Internal forward references.
127 */
128static void save_prefs(midend *me);
129
109/* 130/*
110 * Call JS to get the date, and use that to initialise our random 131 * Call JS to get the date, and use that to initialise our random
111 * number generator to invent the first game seed. 132 * number generator to invent the first game seed.
@@ -136,6 +157,7 @@ void fatal(const char *fmt, ...)
136 js_error_box(buf); 157 js_error_box(buf);
137} 158}
138 159
160#ifdef DEBUGGING
139void debug_printf(const char *fmt, ...) 161void debug_printf(const char *fmt, ...)
140{ 162{
141 char buf[512]; 163 char buf[512];
@@ -145,12 +167,13 @@ void debug_printf(const char *fmt, ...)
145 va_end(ap); 167 va_end(ap);
146 js_debug(buf); 168 js_debug(buf);
147} 169}
170#endif
148 171
149/* 172/*
150 * Helper function that makes it easy to test strings that might be 173 * Helper function that makes it easy to test strings that might be
151 * NULL. 174 * NULL.
152 */ 175 */
153int strnullcmp(const char *a, const char *b) 176static int strnullcmp(const char *a, const char *b)
154{ 177{
155 if (a == NULL || b == NULL) 178 if (a == NULL || b == NULL)
156 return a != NULL ? +1 : b != NULL ? -1 : 0; 179 return a != NULL ? +1 : b != NULL ? -1 : 0;
@@ -158,20 +181,14 @@ int strnullcmp(const char *a, const char *b)
158} 181}
159 182
160/* 183/*
161 * HTMLish names for the colours allocated by the puzzle.
162 */
163char **colour_strings;
164int ncolours;
165
166/*
167 * The global midend object. 184 * The global midend object.
168 */ 185 */
169midend *me; 186static midend *me;
170 187
171/* ---------------------------------------------------------------------- 188/* ----------------------------------------------------------------------
172 * Timing functions. 189 * Timing functions.
173 */ 190 */
174bool timer_active = false; 191static bool timer_active = false;
175void deactivate_timer(frontend *fe) 192void deactivate_timer(frontend *fe)
176{ 193{
177 js_deactivate_timer(); 194 js_deactivate_timer();
@@ -196,21 +213,33 @@ void timer_callback(double tplus)
196 */ 213 */
197static int canvas_w, canvas_h; 214static int canvas_w, canvas_h;
198 215
199/* Called when we resize as a result of changing puzzle settings */ 216/*
217 * Called when we resize as a result of changing puzzle settings
218 * or device pixel ratio.
219 */
200static void resize(void) 220static void resize(void)
201{ 221{
202 int w, h; 222 int w, h;
223 bool user;
203 w = h = INT_MAX; 224 w = h = INT_MAX;
204 midend_size(me, &w, &h, false); 225 user = js_canvas_get_preferred_size(&w, &h);
226 midend_size(me, &w, &h, user, js_get_device_pixel_ratio());
205 js_canvas_set_size(w, h); 227 js_canvas_set_size(w, h);
206 canvas_w = w; 228 canvas_w = w;
207 canvas_h = h; 229 canvas_h = h;
208} 230}
209 231
232/* Called from JS when the device pixel ratio changes */
233void rescale_puzzle(void)
234{
235 resize();
236 midend_force_redraw(me);
237}
238
210/* Called from JS when the user uses the resize handle */ 239/* Called from JS when the user uses the resize handle */
211void resize_puzzle(int w, int h) 240void resize_puzzle(int w, int h)
212{ 241{
213 midend_size(me, &w, &h, true); 242 midend_size(me, &w, &h, true, js_get_device_pixel_ratio());
214 if (canvas_w != w || canvas_h != h) { 243 if (canvas_w != w || canvas_h != h) {
215 js_canvas_set_size(w, h); 244 js_canvas_set_size(w, h);
216 canvas_w = w; 245 canvas_w = w;
@@ -228,12 +257,13 @@ void restore_puzzle_size(int w, int h)
228} 257}
229 258
230/* 259/*
231 * HTML doesn't give us a default frontend colour of its own, so we 260 * Try to extract a background colour from the canvas's CSS. In case
232 * just make up a lightish grey ourselves. 261 * it doesn't have a usable one, make up a lightish grey ourselves.
233 */ 262 */
234void frontend_default_colour(frontend *fe, float *output) 263void frontend_default_colour(frontend *fe, float *output)
235{ 264{
236 output[0] = output[1] = output[2] = 0.9F; 265 output[0] = output[1] = output[2] = 0.9F;
266 js_default_colour(output);
237} 267}
238 268
239/* 269/*
@@ -241,60 +271,85 @@ void frontend_default_colour(frontend *fe, float *output)
241 * and redo buttons get properly enabled and disabled after every move 271 * and redo buttons get properly enabled and disabled after every move
242 * or undo or new-game event. 272 * or undo or new-game event.
243 */ 273 */
244static void update_undo_redo(void) 274static void post_move(void)
245{ 275{
246 js_enable_undo_redo(midend_can_undo(me), midend_can_redo(me)); 276 js_enable_undo_redo(midend_can_undo(me), midend_can_redo(me));
277 js_update_key_labels(midend_current_key_label(me, CURSOR_SELECT2),
278 midend_current_key_label(me, CURSOR_SELECT));
247} 279}
248 280
249/* 281/*
250 * Mouse event handlers called from JS. 282 * Mouse event handlers called from JS.
251 */ 283 */
252void mousedown(int x, int y, int button) 284bool mousedown(int x, int y, int button)
253{ 285{
286 bool handled;
287
254 button = (button == 0 ? LEFT_BUTTON : 288 button = (button == 0 ? LEFT_BUTTON :
255 button == 1 ? MIDDLE_BUTTON : RIGHT_BUTTON); 289 button == 1 ? MIDDLE_BUTTON : RIGHT_BUTTON);
256 midend_process_key(me, x, y, button); 290 handled = midend_process_key(me, x, y, button) != PKR_UNUSED;
257 update_undo_redo(); 291 post_move();
292 return handled;
258} 293}
259 294
260void mouseup(int x, int y, int button) 295bool mouseup(int x, int y, int button)
261{ 296{
297 bool handled;
298
262 button = (button == 0 ? LEFT_RELEASE : 299 button = (button == 0 ? LEFT_RELEASE :
263 button == 1 ? MIDDLE_RELEASE : RIGHT_RELEASE); 300 button == 1 ? MIDDLE_RELEASE : RIGHT_RELEASE);
264 midend_process_key(me, x, y, button); 301 handled = midend_process_key(me, x, y, button) != PKR_UNUSED;
265 update_undo_redo(); 302 post_move();
303 return handled;
266} 304}
267 305
268void mousemove(int x, int y, int buttons) 306bool mousemove(int x, int y, int buttons)
269{ 307{
270 int button = (buttons & 2 ? MIDDLE_DRAG : 308 int button = (buttons & 2 ? MIDDLE_DRAG :
271 buttons & 4 ? RIGHT_DRAG : LEFT_DRAG); 309 buttons & 4 ? RIGHT_DRAG : LEFT_DRAG);
272 midend_process_key(me, x, y, button); 310 bool handled;
273 update_undo_redo(); 311
312 handled = midend_process_key(me, x, y, button) != PKR_UNUSED;
313 post_move();
314 return handled;
274} 315}
275 316
276/* 317/*
277 * Keyboard handler called from JS. 318 * Keyboard handler called from JS. Returns true if the key was
319 * handled and hence the keydown event should be cancelled.
278 */ 320 */
279void key(int keycode, int charcode, const char *key, const char *chr, 321bool key(int keycode, const char *key, const char *chr, int location,
280 bool shift, bool ctrl) 322 bool shift, bool ctrl)
281{ 323{
324 /* Key location constants from JavaScript. */
325 #define DOM_KEY_LOCATION_STANDARD 0
326 #define DOM_KEY_LOCATION_LEFT 1
327 #define DOM_KEY_LOCATION_RIGHT 2
328 #define DOM_KEY_LOCATION_NUMPAD 3
282 int keyevent = -1; 329 int keyevent = -1;
330 int process_key_result;
283 331
284 if (!strnullcmp(key, "Backspace") || !strnullcmp(key, "Del") || 332 if (!strnullcmp(key, "Backspace") || !strnullcmp(key, "Delete") ||
285 keycode == 8 || keycode == 46) { 333 !strnullcmp(key, "Del"))
286 keyevent = 127; /* Backspace / Delete */ 334 keyevent = 127; /* Backspace / Delete */
287 } else if (!strnullcmp(key, "Enter") || keycode == 13) { 335 else if (!strnullcmp(key, "Enter"))
288 keyevent = 13; /* return */ 336 keyevent = 13; /* return */
289 } else if (!strnullcmp(key, "Left") || keycode == 37) { 337 else if (!strnullcmp(key, "Spacebar"))
338 keyevent = ' ';
339 else if (!strnullcmp(key, "Escape"))
340 keyevent = 27;
341 else if (!strnullcmp(key, "ArrowLeft") || !strnullcmp(key, "Left"))
290 keyevent = CURSOR_LEFT; 342 keyevent = CURSOR_LEFT;
291 } else if (!strnullcmp(key, "Up") || keycode == 38) { 343 else if (!strnullcmp(key, "ArrowUp") || !strnullcmp(key, "Up"))
292 keyevent = CURSOR_UP; 344 keyevent = CURSOR_UP;
293 } else if (!strnullcmp(key, "Right") || keycode == 39) { 345 else if (!strnullcmp(key, "ArrowRight") || !strnullcmp(key, "Right"))
294 keyevent = CURSOR_RIGHT; 346 keyevent = CURSOR_RIGHT;
295 } else if (!strnullcmp(key, "Down") || keycode == 40) { 347 else if (!strnullcmp(key, "ArrowDown") || !strnullcmp(key, "Down"))
296 keyevent = CURSOR_DOWN; 348 keyevent = CURSOR_DOWN;
297 } else if (!strnullcmp(key, "End") || keycode == 35) { 349 else if (!strnullcmp(key, "SoftLeft"))
350 /* Left soft key on KaiOS. */
351 keyevent = CURSOR_SELECT2;
352 else if (!strnullcmp(key, "End"))
298 /* 353 /*
299 * We interpret Home, End, PgUp and PgDn as numeric keypad 354 * We interpret Home, End, PgUp and PgDn as numeric keypad
300 * controls regardless of whether they're the ones on the 355 * controls regardless of whether they're the ones on the
@@ -304,40 +359,73 @@ void key(int keycode, int charcode, const char *key, const char *chr,
304 * puzzles like Cube and Inertia. 359 * puzzles like Cube and Inertia.
305 */ 360 */
306 keyevent = MOD_NUM_KEYPAD | '1'; 361 keyevent = MOD_NUM_KEYPAD | '1';
307 } else if (!strnullcmp(key, "PageDown") || keycode==34) { 362 else if (!strnullcmp(key, "PageDown"))
308 keyevent = MOD_NUM_KEYPAD | '3'; 363 keyevent = MOD_NUM_KEYPAD | '3';
309 } else if (!strnullcmp(key, "Home") || keycode==36) { 364 else if (!strnullcmp(key, "Home"))
310 keyevent = MOD_NUM_KEYPAD | '7'; 365 keyevent = MOD_NUM_KEYPAD | '7';
311 } else if (!strnullcmp(key, "PageUp") || keycode==33) { 366 else if (!strnullcmp(key, "PageUp"))
312 keyevent = MOD_NUM_KEYPAD | '9'; 367 keyevent = MOD_NUM_KEYPAD | '9';
313 } else if (shift && ctrl && (keycode & 0x1F) == 26) { 368 else if (shift && ctrl && (!strnullcmp(key, "Z") || !strnullcmp(key, "z")))
314 keyevent = UI_REDO; 369 keyevent = UI_REDO;
315 } else if (chr && chr[0] && !chr[1]) { 370 else if (key && (unsigned char)key[0] < 0x80 && key[1] == '\0')
371 /* Key generating a single ASCII character. */
372 keyevent = key[0];
373 /*
374 * In modern browsers (since about 2017), all keys that Puzzles
375 * cares about should be matched by one of the clauses above. The
376 * code below that checks keycode and chr should be relavent only
377 * in older browsers.
378 */
379 else if (keycode == 8 || keycode == 46)
380 keyevent = 127; /* Backspace / Delete */
381 else if (keycode == 13)
382 keyevent = 13; /* return */
383 else if (keycode == 37)
384 keyevent = CURSOR_LEFT;
385 else if (keycode == 38)
386 keyevent = CURSOR_UP;
387 else if (keycode == 39)
388 keyevent = CURSOR_RIGHT;
389 else if (keycode == 40)
390 keyevent = CURSOR_DOWN;
391 else if (keycode == 35)
392 keyevent = MOD_NUM_KEYPAD | '1';
393 else if (keycode == 34)
394 keyevent = MOD_NUM_KEYPAD | '3';
395 else if (keycode == 36)
396 keyevent = MOD_NUM_KEYPAD | '7';
397 else if (keycode == 33)
398 keyevent = MOD_NUM_KEYPAD | '9';
399 else if (shift && ctrl && (keycode & 0x1F) == 26)
400 keyevent = UI_REDO;
401 else if (chr && chr[0] && !chr[1])
316 keyevent = chr[0] & 0xFF; 402 keyevent = chr[0] & 0xFF;
317 } else if (keycode >= 96 && keycode < 106) { 403 else if (keycode >= 96 && keycode < 106)
318 keyevent = MOD_NUM_KEYPAD | ('0' + keycode - 96); 404 keyevent = MOD_NUM_KEYPAD | ('0' + keycode - 96);
319 } else if (keycode >= 65 && keycode <= 90) { 405 else if (keycode >= 65 && keycode <= 90)
320 keyevent = keycode + (shift ? 0 : 32); 406 keyevent = keycode + (shift ? 0 : 32);
321 } else if (keycode >= 48 && keycode <= 57) { 407 else if (keycode >= 48 && keycode <= 57)
322 keyevent = keycode; 408 keyevent = keycode;
323 } else if (keycode == 32) { /* space / CURSOR_SELECT2 */ 409 else if (keycode == 32) /* space / CURSOR_SELECT2 */
324 keyevent = keycode; 410 keyevent = keycode;
325 }
326 411
327 if (keyevent >= 0) { 412 if (keyevent >= 0) {
328 if (shift && (keyevent >= 0x100 && !IS_UI_FAKE_KEY(keyevent))) 413 if (shift) keyevent |= MOD_SHFT;
329 keyevent |= MOD_SHFT; 414 if (ctrl) keyevent |= MOD_CTRL;
330 415 if (location == DOM_KEY_LOCATION_NUMPAD) keyevent |= MOD_NUM_KEYPAD;
331 if (ctrl && !IS_UI_FAKE_KEY(keyevent)) {
332 if (keyevent >= 0x100)
333 keyevent |= MOD_CTRL;
334 else
335 keyevent &= 0x1F;
336 }
337 416
338 midend_process_key(me, 0, 0, keyevent); 417 process_key_result = midend_process_key(me, 0, 0, keyevent);
339 update_undo_redo(); 418 post_move();
419 /*
420 * Treat Backspace specially because that's expected on KaiOS.
421 * https://developer.kaiostech.com/docs/design-guide/key
422 */
423 if (process_key_result == PKR_NO_EFFECT &&
424 !strnullcmp(key, "Backspace"))
425 return false;
426 return process_key_result != PKR_UNUSED;
340 } 427 }
428 return false; /* Event not handled, because we don't even recognise it. */
341} 429}
342 430
343/* 431/*
@@ -387,14 +475,10 @@ static void js_draw_text(void *handle, int x, int y, int fonttype,
387 int fontsize, int align, int colour, 475 int fontsize, int align, int colour,
388 const char *text) 476 const char *text)
389{ 477{
390 char fontstyle[80];
391 int halign; 478 int halign;
392 479
393 sprintf(fontstyle, "%dpx %s", fontsize,
394 fonttype == FONT_FIXED ? "monospace" : "sans-serif");
395
396 if (align & ALIGN_VCENTRE) 480 if (align & ALIGN_VCENTRE)
397 y += js_canvas_find_font_midpoint(fontsize, fontstyle); 481 y += js_canvas_find_font_midpoint(fontsize, fonttype == FONT_FIXED);
398 482
399 if (align & ALIGN_HCENTRE) 483 if (align & ALIGN_HCENTRE)
400 halign = 1; 484 halign = 1;
@@ -403,41 +487,38 @@ static void js_draw_text(void *handle, int x, int y, int fonttype,
403 else 487 else
404 halign = 0; 488 halign = 0;
405 489
406 js_canvas_draw_text(x, y, halign, colour_strings[colour], fontstyle, text); 490 js_canvas_draw_text(x, y, halign, colour,
491 fontsize, fonttype == FONT_FIXED, text);
407} 492}
408 493
409static void js_draw_rect(void *handle, int x, int y, int w, int h, int colour) 494static void js_draw_rect(void *handle, int x, int y, int w, int h, int colour)
410{ 495{
411 js_canvas_draw_rect(x, y, w, h, colour_strings[colour]); 496 js_canvas_draw_rect(x, y, w, h, colour);
412} 497}
413 498
414static void js_draw_line(void *handle, int x1, int y1, int x2, int y2, 499static void js_draw_line(void *handle, int x1, int y1, int x2, int y2,
415 int colour) 500 int colour)
416{ 501{
417 js_canvas_draw_line(x1, y1, x2, y2, 1, colour_strings[colour]); 502 js_canvas_draw_line(x1, y1, x2, y2, 1, colour);
418} 503}
419 504
420static void js_draw_thick_line(void *handle, float thickness, 505static void js_draw_thick_line(void *handle, float thickness,
421 float x1, float y1, float x2, float y2, 506 float x1, float y1, float x2, float y2,
422 int colour) 507 int colour)
423{ 508{
424 js_canvas_draw_line(x1, y1, x2, y2, thickness, colour_strings[colour]); 509 js_canvas_draw_line(x1, y1, x2, y2, thickness, colour);
425} 510}
426 511
427static void js_draw_poly(void *handle, int *coords, int npoints, 512static void js_draw_poly(void *handle, const int *coords, int npoints,
428 int fillcolour, int outlinecolour) 513 int fillcolour, int outlinecolour)
429{ 514{
430 js_canvas_draw_poly(coords, npoints, 515 js_canvas_draw_poly(coords, npoints, fillcolour, outlinecolour);
431 fillcolour >= 0 ? colour_strings[fillcolour] : NULL,
432 colour_strings[outlinecolour]);
433} 516}
434 517
435static void js_draw_circle(void *handle, int cx, int cy, int radius, 518static void js_draw_circle(void *handle, int cx, int cy, int radius,
436 int fillcolour, int outlinecolour) 519 int fillcolour, int outlinecolour)
437{ 520{
438 js_canvas_draw_circle(cx, cy, radius, 521 js_canvas_draw_circle(cx, cy, radius, fillcolour, outlinecolour);
439 fillcolour >= 0 ? colour_strings[fillcolour] : NULL,
440 colour_strings[outlinecolour]);
441} 522}
442 523
443struct blitter { 524struct blitter {
@@ -527,7 +608,7 @@ static char *js_text_fallback(void *handle, const char *const *strings,
527 return dupstr(strings[0]); /* Emscripten has no trouble with UTF-8 */ 608 return dupstr(strings[0]); /* Emscripten has no trouble with UTF-8 */
528} 609}
529 610
530const struct drawing_api js_drawing = { 611static const struct drawing_api js_drawing = {
531 js_draw_text, 612 js_draw_text,
532 js_draw_rect, 613 js_draw_rect,
533 js_draw_line, 614 js_draw_line,
@@ -554,9 +635,9 @@ const struct drawing_api js_drawing = {
554 */ 635 */
555static game_params **presets; 636static game_params **presets;
556static int npresets; 637static int npresets;
557bool have_presets_dropdown; 638static bool have_presets_dropdown;
558 639
559void populate_js_preset_menu(int menuid, struct preset_menu *menu) 640static void populate_js_preset_menu(int menuid, struct preset_menu *menu)
560{ 641{
561 int i; 642 int i;
562 for (i = 0; i < menu->n_entries; i++) { 643 for (i = 0; i < menu->n_entries; i++) {
@@ -571,7 +652,7 @@ void populate_js_preset_menu(int menuid, struct preset_menu *menu)
571 } 652 }
572} 653}
573 654
574void select_appropriate_preset(void) 655static void select_appropriate_preset(void)
575{ 656{
576 if (have_presets_dropdown) { 657 if (have_presets_dropdown) {
577 int preset = midend_which_preset(me); 658 int preset = midend_which_preset(me);
@@ -665,10 +746,20 @@ static void cfg_end(bool use_results)
665 * open for the user to adjust them and try again. 746 * open for the user to adjust them and try again.
666 */ 747 */
667 js_error_box(err); 748 js_error_box(err);
749 } else if (cfg_which == CFG_PREFS) {
750 /*
751 * Acceptable settings for user preferences: enact them
752 * without blowing away the current game.
753 */
754 resize();
755 midend_redraw(me);
756 free_cfg(cfg);
757 js_dialog_cleanup();
758 save_prefs(me);
668 } else { 759 } else {
669 /* 760 /*
670 * New settings are fine; start a new game and close the 761 * Acceptable settings for the remaining configuration
671 * dialog. 762 * types: start a new game and close the dialog.
672 */ 763 */
673 select_appropriate_preset(); 764 select_appropriate_preset();
674 midend_new_game(me); 765 midend_new_game(me);
@@ -686,10 +777,7 @@ static void cfg_end(bool use_results)
686 * select Custom from the list, but change your mind and hit 777 * select Custom from the list, but change your mind and hit
687 * Esc. The Custom option will now still be selected in the 778 * Esc. The Custom option will now still be selected in the
688 * list, whereas obviously it should show the preset you still 779 * list, whereas obviously it should show the preset you still
689 * _actually_ have selected. Worse still, it'll be the visible 780 * _actually_ have selected.)
690 * rather than invisible Custom option - see the comment in
691 * js_add_preset in emcclib.js - so you won't even be able to
692 * select Custom without a faffy workaround.)
693 */ 781 */
694 select_appropriate_preset(); 782 select_appropriate_preset();
695 783
@@ -731,7 +819,7 @@ void command(int n)
731 midend_new_game(me); 819 midend_new_game(me);
732 resize(); 820 resize();
733 midend_redraw(me); 821 midend_redraw(me);
734 update_undo_redo(); 822 post_move();
735 js_focus_canvas(); 823 js_focus_canvas();
736 select_appropriate_preset(); 824 select_appropriate_preset();
737 } 825 }
@@ -739,30 +827,30 @@ void command(int n)
739 break; 827 break;
740 case 3: /* OK clicked in a config box */ 828 case 3: /* OK clicked in a config box */
741 cfg_end(true); 829 cfg_end(true);
742 update_undo_redo(); 830 post_move();
743 break; 831 break;
744 case 4: /* Cancel clicked in a config box */ 832 case 4: /* Cancel clicked in a config box */
745 cfg_end(false); 833 cfg_end(false);
746 update_undo_redo(); 834 post_move();
747 break; 835 break;
748 case 5: /* New Game */ 836 case 5: /* New Game */
749 midend_process_key(me, 0, 0, UI_NEWGAME); 837 midend_process_key(me, 0, 0, UI_NEWGAME);
750 update_undo_redo(); 838 post_move();
751 js_focus_canvas(); 839 js_focus_canvas();
752 break; 840 break;
753 case 6: /* Restart */ 841 case 6: /* Restart */
754 midend_restart_game(me); 842 midend_restart_game(me);
755 update_undo_redo(); 843 post_move();
756 js_focus_canvas(); 844 js_focus_canvas();
757 break; 845 break;
758 case 7: /* Undo */ 846 case 7: /* Undo */
759 midend_process_key(me, 0, 0, UI_UNDO); 847 midend_process_key(me, 0, 0, UI_UNDO);
760 update_undo_redo(); 848 post_move();
761 js_focus_canvas(); 849 js_focus_canvas();
762 break; 850 break;
763 case 8: /* Redo */ 851 case 8: /* Redo */
764 midend_process_key(me, 0, 0, UI_REDO); 852 midend_process_key(me, 0, 0, UI_REDO);
765 update_undo_redo(); 853 post_move();
766 js_focus_canvas(); 854 js_focus_canvas();
767 break; 855 break;
768 case 9: /* Solve */ 856 case 9: /* Solve */
@@ -771,12 +859,25 @@ void command(int n)
771 if (msg) 859 if (msg)
772 js_error_box(msg); 860 js_error_box(msg);
773 } 861 }
774 update_undo_redo(); 862 post_move();
775 js_focus_canvas(); 863 js_focus_canvas();
776 break; 864 break;
865 case 10: /* user preferences */
866 cfg_start(CFG_PREFS);
867 break;
777 } 868 }
778} 869}
779 870
871char *get_text_format(void)
872{
873 return midend_text_format(me);
874}
875
876void free_text_format(char *buffer)
877{
878 sfree(buffer);
879}
880
780/* ---------------------------------------------------------------------- 881/* ----------------------------------------------------------------------
781 * Called from JS to prepare a save-game file, and free one after it's 882 * Called from JS to prepare a save-game file, and free one after it's
782 * been used. 883 * been used.
@@ -824,30 +925,20 @@ void free_save_file(char *buffer)
824 sfree(buffer); 925 sfree(buffer);
825} 926}
826 927
827struct savefile_read_ctx {
828 const char *buffer;
829 int len_remaining;
830};
831
832static bool savefile_read(void *vctx, void *buf, int len) 928static bool savefile_read(void *vctx, void *buf, int len)
833{ 929{
834 struct savefile_read_ctx *ctx = (struct savefile_read_ctx *)vctx; 930 return js_savefile_read(buf, len);
835 if (ctx->len_remaining < len)
836 return false;
837 memcpy(buf, ctx->buffer, len);
838 ctx->len_remaining -= len;
839 ctx->buffer += len;
840 return true;
841} 931}
842 932
843void load_game(const char *buffer, int len) 933void load_game(void)
844{ 934{
845 struct savefile_read_ctx ctx;
846 const char *err; 935 const char *err;
847 936
848 ctx.buffer = buffer; 937 /*
849 ctx.len_remaining = len; 938 * savefile_read_callback in JavaScript was set up by our caller
850 err = midend_deserialise(me, savefile_read, &ctx); 939 * as a closure that knows what file we're loading.
940 */
941 err = midend_deserialise(me, savefile_read, NULL);
851 942
852 if (err) { 943 if (err) {
853 js_error_box(err); 944 js_error_box(err);
@@ -855,10 +946,70 @@ void load_game(const char *buffer, int len)
855 select_appropriate_preset(); 946 select_appropriate_preset();
856 resize(); 947 resize();
857 midend_redraw(me); 948 midend_redraw(me);
949 update_permalinks();
950 post_move();
858 } 951 }
859} 952}
860 953
861/* ---------------------------------------------------------------------- 954/* ----------------------------------------------------------------------
955 * Functions to load and save preferences, calling out to JS to access
956 * the appropriate localStorage slot.
957 */
958
959static void save_prefs(midend *me)
960{
961 struct savefile_write_ctx ctx;
962 size_t size;
963
964 /* First pass, to count up the size */
965 ctx.buffer = NULL;
966 ctx.pos = 0;
967 midend_save_prefs(me, savefile_write, &ctx);
968 size = ctx.pos;
969
970 /* Second pass, to actually write out the data. As with
971 * get_save_file, we append a terminating \0. */
972 ctx.buffer = snewn(size+1, char);
973 ctx.pos = 0;
974 midend_save_prefs(me, savefile_write, &ctx);
975 assert(ctx.pos == size);
976 ctx.buffer[ctx.pos] = '\0';
977
978 js_save_prefs(ctx.buffer);
979
980 sfree(ctx.buffer);
981}
982
983struct prefs_read_ctx {
984 const char *buffer;
985 size_t pos, len;
986};
987
988static bool prefs_read(void *vctx, void *buf, int len)
989{
990 struct prefs_read_ctx *ctx = (struct prefs_read_ctx *)vctx;
991
992 if (len < 0)
993 return false;
994 if (ctx->len - ctx->pos < len)
995 return false;
996 memcpy(buf, ctx->buffer + ctx->pos, len);
997 ctx->pos += len;
998 return true;
999}
1000
1001void prefs_load_callback(midend *me, const char *prefs)
1002{
1003 struct prefs_read_ctx ctx;
1004
1005 ctx.buffer = prefs;
1006 ctx.len = strlen(prefs);
1007 ctx.pos = 0;
1008
1009 midend_load_prefs(me, prefs_read, &ctx);
1010}
1011
1012/* ----------------------------------------------------------------------
862 * Setup function called at page load time. It's called main() because 1013 * Setup function called at page load time. It's called main() because
863 * that's the most convenient thing in Emscripten, but it's not main() 1014 * that's the most convenient thing in Emscripten, but it's not main()
864 * in the usual sense of bounding the program's entire execution. 1015 * in the usual sense of bounding the program's entire execution.
@@ -870,12 +1021,18 @@ int main(int argc, char **argv)
870{ 1021{
871 const char *param_err; 1022 const char *param_err;
872 float *colours; 1023 float *colours;
873 int i; 1024 int i, ncolours;
1025
1026 /*
1027 * Initialise JavaScript event handlers.
1028 */
1029 js_init_puzzle();
874 1030
875 /* 1031 /*
876 * Instantiate a midend. 1032 * Instantiate a midend.
877 */ 1033 */
878 me = midend_new(NULL, &thegame, &js_drawing, NULL); 1034 me = midend_new(NULL, &thegame, &js_drawing, NULL);
1035 js_load_prefs(me);
879 1036
880 /* 1037 /*
881 * Chuck in the HTML fragment ID if we have one (trimming the 1038 * Chuck in the HTML fragment ID if we have one (trimming the
@@ -896,10 +1053,10 @@ int main(int argc, char **argv)
896 resize(); 1053 resize();
897 1054
898 /* 1055 /*
899 * Create a status bar, if needed. 1056 * Remove the status bar, if not needed.
900 */ 1057 */
901 if (midend_wants_statusbar(me)) 1058 if (!midend_wants_statusbar(me))
902 js_canvas_make_statusbar(); 1059 js_canvas_remove_statusbar();
903 1060
904 /* 1061 /*
905 * Set up the game-type dropdown with presets and/or the Custom 1062 * Set up the game-type dropdown with presets and/or the Custom
@@ -907,23 +1064,33 @@ int main(int argc, char **argv)
907 */ 1064 */
908 { 1065 {
909 struct preset_menu *menu = midend_get_presets(me, &npresets); 1066 struct preset_menu *menu = midend_get_presets(me, &npresets);
1067 bool may_configure = false;
910 presets = snewn(npresets, game_params *); 1068 presets = snewn(npresets, game_params *);
911 for (i = 0; i < npresets; i++) 1069 for (i = 0; i < npresets; i++)
912 presets[i] = NULL; 1070 presets[i] = NULL;
913 1071
914 populate_js_preset_menu(0, menu); 1072 populate_js_preset_menu(0, menu);
915 1073
916 if (thegame.can_configure)
917 js_add_preset(0, "Custom", -1);
918
919 have_presets_dropdown = true;
920
921 /* 1074 /*
922 * Now ensure the appropriate element of the presets menu 1075 * Crude hack to allow the "Custom..." item to be hidden on
923 * starts off selected, in case it isn't the first one in the 1076 * KaiOS, where dialogs don't yet work.
924 * list (e.g. Slant).
925 */ 1077 */
926 select_appropriate_preset(); 1078 if (thegame.can_configure && getenv_bool("PUZZLES_ALLOW_CUSTOM", true))
1079 may_configure = true;
1080 if (may_configure)
1081 js_add_preset(0, "Custom...", -1);
1082
1083 have_presets_dropdown = npresets > 1 || may_configure;
1084
1085 if (have_presets_dropdown)
1086 /*
1087 * Now ensure the appropriate element of the presets menu
1088 * starts off selected, in case it isn't the first one in the
1089 * list (e.g. Slant).
1090 */
1091 select_appropriate_preset();
1092 else
1093 js_remove_type_dropdown();
927 } 1094 }
928 1095
929 /* 1096 /*
@@ -937,14 +1104,13 @@ int main(int argc, char **argv)
937 * hex ID strings. 1104 * hex ID strings.
938 */ 1105 */
939 colours = midend_colours(me, &ncolours); 1106 colours = midend_colours(me, &ncolours);
940 colour_strings = snewn(ncolours, char *);
941 for (i = 0; i < ncolours; i++) { 1107 for (i = 0; i < ncolours; i++) {
942 char col[40]; 1108 char col[40];
943 sprintf(col, "#%02x%02x%02x", 1109 sprintf(col, "#%02x%02x%02x",
944 (unsigned)(0.5 + 255 * colours[i*3+0]), 1110 (unsigned)(0.5F + 255 * colours[i*3+0]),
945 (unsigned)(0.5 + 255 * colours[i*3+1]), 1111 (unsigned)(0.5F + 255 * colours[i*3+1]),
946 (unsigned)(0.5 + 255 * colours[i*3+2])); 1112 (unsigned)(0.5F + 255 * colours[i*3+2]));
947 colour_strings[i] = dupstr(col); 1113 js_set_colour(i, col);
948 } 1114 }
949 1115
950 /* 1116 /*
@@ -960,7 +1126,7 @@ int main(int argc, char **argv)
960 */ 1126 */
961 midend_redraw(me); 1127 midend_redraw(me);
962 update_permalinks(); 1128 update_permalinks();
963 update_undo_redo(); 1129 post_move();
964 1130
965 /* 1131 /*
966 * If we were given an erroneous game ID in argv[1], now's the 1132 * If we were given an erroneous game ID in argv[1], now's the
@@ -972,6 +1138,11 @@ int main(int argc, char **argv)
972 js_error_box(param_err); 1138 js_error_box(param_err);
973 1139
974 /* 1140 /*
1141 * Reveal the puzzle!
1142 */
1143 js_post_init();
1144
1145 /*
975 * Done. Return to JS, and await callbacks! 1146 * Done. Return to JS, and await callbacks!
976 */ 1147 */
977 return 0; 1148 return 0;
diff --git a/apps/plugins/puzzles/src/emcccopy.but b/apps/plugins/puzzles/src/emcccopy.but
new file mode 100644
index 0000000000..5332e0df38
--- /dev/null
+++ b/apps/plugins/puzzles/src/emcccopy.but
@@ -0,0 +1,128 @@
1\A{thirdparty} Third-party software licences
2
3\# This file should contain the copyright notices for third-party code
4included in the Emscripten builds of Puzzles. To get a list of
5relevant source files, you can build Puzzles with "-gsource-map" and
6then do something like:
7
8\# jq -r '.sources[]' *.map | sort -u
9
10\# This file is based on a build of Git commit
112e48ce132e011e83517a9fc4905edcc8f9a5ef58 using Emscripten 3.1.35
12
13\# system/lib/compiler-rt/lib/builtins/*
14\# upstream/lib/clang/17/include/tgmath.h
15
16\# These are under the Apache Licence v2.0 with LLVM Exceptions. The
17LLVM Exceptions allow us not to mention them in binary distributions.
18
19\# system/lib/dlmalloc.c
20
21\# dlmalloc is in the public domain and so needs no acknowledgement.
22
23The JavaScript and KaiOS versions of Puzzles incorporate some third
24party software. Most of it is licensed under the \i{MIT licence} (see
25\k{licence}) and requires the following \i{copyright} notices:
26
27\quote{
28
29\# system/lib/libc/emscripten_get_heap_size.c
30\# system/lib/libc/emscripten_memcpy.c
31\# system/lib/libc/emscripten_syscall_stubs.c
32\# system/lib/libc/wasi-helpers.c
33\# system/lib/pthread/library_pthread_stub.c
34\# system/lib/pthread/pthread_self_stub.c
35\# system/lib/sbrk.c
36
37\# These are parts of Emscripten and either refer explicitly to the
38Emscripten LICENSE file or make no mention of a licence. LICENSE
39allows use under the MIT licence and specifies this copyright notice:
40
41Copyright (c) 2010-2014 Emscripten authors, see AUTHORS file.
42
43\# cache/sysroot/include/math.h
44\# system/lib/libc/musl/src/ctype/*
45\# system/lib/libc/musl/src/env/*
46\# system/lib/libc/musl/src/errno/*
47\# system/lib/libc/musl/src/internal/atomic.h
48\# system/lib/libc/musl/src/internal/floatscan.c
49\# system/lib/libc/musl/src/internal/intscan.c
50\# system/lib/libc/musl/src/internal/shgetc.c
51\# system/lib/libc/musl/src/math/copysignl.c
52\# system/lib/libc/musl/src/math/fabs.c
53\# system/lib/libc/musl/src/math/fabsl.c
54\# system/lib/libc/musl/src/math/floor.c
55\# system/lib/libc/musl/src/math/fmodl.c
56\# system/lib/libc/musl/src/math/__fpclassifyl.c
57\# system/lib/libc/musl/src/math/frexp.c
58\# system/lib/libc/musl/src/math/scalbn.c
59\# system/lib/libc/musl/src/math/scalbnl.c
60\# system/lib/libc/musl/src/math/sqrtf.c
61\# system/lib/libc/musl/src/multibyte/*
62\# system/lib/libc/musl/src/stdio/*
63\# system/lib/libc/musl/src/stdlib/abs.c
64\# system/lib/libc/musl/src/stdlib/atof.c
65\# system/lib/libc/musl/src/stdlib/atoi.c
66\# system/lib/libc/musl/src/stdlib/atol.c
67\# system/lib/libc/musl/src/stdlib/labs.c
68\# system/lib/libc/musl/src/stdlib/qsort_nr.c
69\# system/lib/libc/musl/src/stdlib/strtod.c
70\# system/lib/libc/musl/src/stdlib/strtol.c
71\# system/lib/libc/musl/src/string/*
72\# system/lib/libc/musl/src/unistd/getpid.c
73
74\# These are parts of musl, which is licensed "as a whole" under the
75MIT licence. These parts don't carry any licence notice themselves.
76This is the copyright notice from musl's COPYRIGHT file, modified to
77allow for non-Unicode targets:
78
79Copyright \u00A9{(C)} 2005-2020 Rich Felker, et al.
80
81\# system/lib/libc/musl/src/stdlib/qsort.c
82
83\# This is part of musl, but has its own copyright notice and MIT
84licence in its source file.
85
86Copyright (C) 2011 by Valentin Ochs
87
88}
89
90Other incorporated software requires these notices:
91
92\quote{
93
94\# system/lib/libc/musl/src/math/acosf.c
95\# system/lib/libc/musl/src/math/atan.c
96\# system/lib/libc/musl/src/math/cos.c
97\# system/lib/libc/musl/src/math/__cosdf.c
98\# system/lib/libc/musl/src/math/cosf.c
99\# system/lib/libc/musl/src/math/__rem_pio2f.c
100\# system/lib/libc/musl/src/math/sin.c
101\# system/lib/libc/musl/src/math/__sindf.c
102\# system/lib/libc/musl/src/math/sinf.c
103
104\# These are parts of musl with a SunPro copyright notice and licence.
105
106Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
107
108Developed at SunPro, a Sun Microsystems, Inc. business.
109Permission to use, copy, modify, and distribute this
110software is freely granted, provided that this notice
111is preserved.
112
113\# system/lib/libc/musl/src/math/atan2.c
114\# system/lib/libc/musl/src/math/__cos.c
115\# system/lib/libc/musl/src/math/__rem_pio2.c
116\# system/lib/libc/musl/src/math/__rem_pio2_large.c
117\# system/lib/libc/musl/src/math/__sin.c
118
119\# These are parts of musl with a SunSoft copyright notice and licence.
120
121Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
122
123Developed at SunSoft, a Sun Microsystems, Inc. business.
124Permission to use, copy, modify, and distribute this
125software is freely granted, provided that this notice
126is preserved.
127
128} \ No newline at end of file
diff --git a/apps/plugins/puzzles/src/fifteen.R b/apps/plugins/puzzles/src/fifteen.R
deleted file mode 100644
index b2292acc69..0000000000
--- a/apps/plugins/puzzles/src/fifteen.R
+++ /dev/null
@@ -1,22 +0,0 @@
1# -*- makefile -*-
2
3fifteen : [X] GTK COMMON fifteen fifteen-icon|no-icon
4
5fifteen : [G] WINDOWS COMMON fifteen fifteen.res|noicon.res
6
7fifteensolver : [U] fifteen[STANDALONE_SOLVER] STANDALONE
8fifteensolver : [C] fifteen[STANDALONE_SOLVER] STANDALONE
9
10ALL += fifteen[COMBINED]
11
12!begin am gtk
13GAMES += fifteen
14!end
15
16!begin >list.c
17 A(fifteen) \
18!end
19
20!begin >gamedesc.txt
21fifteen:fifteen.exe:Fifteen:Sliding block puzzle:Slide the tiles around to arrange them into order.
22!end
diff --git a/apps/plugins/puzzles/src/fifteen.c b/apps/plugins/puzzles/src/fifteen.c
index 4b877dc098..a2a9554523 100644
--- a/apps/plugins/puzzles/src/fifteen.c
+++ b/apps/plugins/puzzles/src/fifteen.c
@@ -7,7 +7,12 @@
7#include <string.h> 7#include <string.h>
8#include <assert.h> 8#include <assert.h>
9#include <ctype.h> 9#include <ctype.h>
10#include <math.h> 10#include <limits.h>
11#ifdef NO_TGMATH_H
12# include <math.h>
13#else
14# include <tgmath.h>
15#endif
11 16
12#include "puzzles.h" 17#include "puzzles.h"
13 18
@@ -138,6 +143,8 @@ static const char *validate_params(const game_params *params, bool full)
138{ 143{
139 if (params->w < 2 || params->h < 2) 144 if (params->w < 2 || params->h < 2)
140 return "Width and height must both be at least two"; 145 return "Width and height must both be at least two";
146 if (params->w > INT_MAX / params->h)
147 return "Width times height must not be unreasonably large";
141 148
142 return NULL; 149 return NULL;
143} 150}
@@ -156,6 +163,14 @@ static int perm_parity(int *perm, int n)
156 return ret; 163 return ret;
157} 164}
158 165
166static int is_completed(int *tiles, int n) {
167 int p;
168 for (p = 0; p < n; p++)
169 if (tiles[p] != (p < n-1 ? p+1 : 0))
170 return 0;
171 return 1;
172}
173
159static char *new_game_desc(const game_params *params, random_state *rs, 174static char *new_game_desc(const game_params *params, random_state *rs,
160 char **aux, bool interactive) 175 char **aux, bool interactive)
161{ 176{
@@ -171,81 +186,83 @@ static char *new_game_desc(const game_params *params, random_state *rs,
171 tiles = snewn(n, int); 186 tiles = snewn(n, int);
172 used = snewn(n, bool); 187 used = snewn(n, bool);
173 188
174 for (i = 0; i < n; i++) { 189 do {
175 tiles[i] = -1; 190 for (i = 0; i < n; i++) {
176 used[i] = false; 191 tiles[i] = -1;
177 } 192 used[i] = false;
193 }
178 194
179 gap = random_upto(rs, n); 195 gap = random_upto(rs, n);
180 tiles[gap] = 0; 196 tiles[gap] = 0;
181 used[0] = true; 197 used[0] = true;
182 198
183 /* 199 /*
184 * Place everything else except the last two tiles. 200 * Place everything else except the last two tiles.
185 */ 201 */
186 for (x = 0, i = n-1; i > 2; i--) { 202 for (x = 0, i = n - 1; i > 2; i--) {
187 int k = random_upto(rs, i); 203 int k = random_upto(rs, i);
188 int j; 204 int j;
189 205
190 for (j = 0; j < n; j++) 206 for (j = 0; j < n; j++)
191 if (!used[j] && (k-- == 0)) 207 if (!used[j] && (k-- == 0))
192 break; 208 break;
193 209
194 assert(j < n && !used[j]); 210 assert(j < n && !used[j]);
195 used[j] = true; 211 used[j] = true;
212
213 while (tiles[x] >= 0)
214 x++;
215 assert(x < n);
216 tiles[x] = j;
217 }
196 218
219 /*
220 * Find the last two locations, and the last two pieces.
221 */
197 while (tiles[x] >= 0) 222 while (tiles[x] >= 0)
198 x++; 223 x++;
199 assert(x < n); 224 assert(x < n);
200 tiles[x] = j; 225 x1 = x;
201 }
202
203 /*
204 * Find the last two locations, and the last two pieces.
205 */
206 while (tiles[x] >= 0)
207 x++;
208 assert(x < n);
209 x1 = x;
210 x++;
211 while (tiles[x] >= 0)
212 x++; 226 x++;
213 assert(x < n); 227 while (tiles[x] >= 0)
214 x2 = x; 228 x++;
215 229 assert(x < n);
216 for (i = 0; i < n; i++) 230 x2 = x;
217 if (!used[i])
218 break;
219 p1 = i;
220 for (i = p1+1; i < n; i++)
221 if (!used[i])
222 break;
223 p2 = i;
224 231
225 /* 232 for (i = 0; i < n; i++)
226 * Determine the required parity of the overall permutation. 233 if (!used[i])
227 * This is the XOR of: 234 break;
228 * 235 p1 = i;
229 * - The chessboard parity ((x^y)&1) of the gap square. The 236 for (i = p1 + 1; i < n; i++)
230 * bottom right counts as even. 237 if (!used[i])
231 * 238 break;
232 * - The parity of n. (The target permutation is 1,...,n-1,0 239 p2 = i;
233 * rather than 0,...,n-1; this is a cyclic permutation of
234 * the starting point and hence is odd iff n is even.)
235 */
236 parity = PARITY_P(params, gap);
237 240
238 /* 241 /*
239 * Try the last two tiles one way round. If that fails, swap 242 * Determine the required parity of the overall permutation.
240 * them. 243 * This is the XOR of:
241 */ 244 *
242 tiles[x1] = p1; 245 * - The chessboard parity ((x^y)&1) of the gap square. The
243 tiles[x2] = p2; 246 * bottom right counts as even.
244 if (perm_parity(tiles, n) != parity) { 247 *
245 tiles[x1] = p2; 248 * - The parity of n. (The target permutation is 1,...,n-1,0
246 tiles[x2] = p1; 249 * rather than 0,...,n-1; this is a cyclic permutation of
247 assert(perm_parity(tiles, n) == parity); 250 * the starting point and hence is odd iff n is even.)
248 } 251 */
252 parity = PARITY_P(params, gap);
253
254 /*
255 * Try the last two tiles one way round. If that fails, swap
256 * them.
257 */
258 tiles[x1] = p1;
259 tiles[x2] = p2;
260 if (perm_parity(tiles, n) != parity) {
261 tiles[x1] = p2;
262 tiles[x2] = p1;
263 assert(perm_parity(tiles, n) == parity);
264 }
265 } while (is_completed(tiles, n));
249 266
250 /* 267 /*
251 * Now construct the game description, by describing the tile 268 * Now construct the game description, by describing the tile
@@ -432,22 +449,68 @@ static char *game_text_format(const game_state *state)
432 return ret; 449 return ret;
433} 450}
434 451
452struct game_ui {
453 /*
454 * User-preference option: invert the direction of arrow-key
455 * control, so that the arrow on the key you press indicates in
456 * which direction you want the _space_ to move, rather than in
457 * which direction you want a tile to move to fill the space.
458 */
459 bool invert_cursor;
460};
461
462static void legacy_prefs_override(struct game_ui *ui_out)
463{
464 static bool initialised = false;
465 static int invert_cursor = -1;
466
467 if (!initialised) {
468 initialised = true;
469 invert_cursor = getenv_bool("FIFTEEN_INVERT_CURSOR", -1);
470 }
471
472 if (invert_cursor != -1)
473 ui_out->invert_cursor = invert_cursor;
474}
475
435static game_ui *new_ui(const game_state *state) 476static game_ui *new_ui(const game_state *state)
436{ 477{
437 return NULL; 478 struct game_ui *ui = snew(struct game_ui);
479
480 ui->invert_cursor = false;
481
482 legacy_prefs_override(ui);
483
484 return ui;
438} 485}
439 486
440static void free_ui(game_ui *ui) 487static config_item *get_prefs(game_ui *ui)
441{ 488{
489 config_item *ret;
490
491 ret = snewn(2, config_item);
492
493 ret[0].name = "Sense of arrow keys";
494 ret[0].kw = "arrow-semantics";
495 ret[0].type = C_CHOICES;
496 ret[0].u.choices.choicenames = ":Move the tile:Move the gap";
497 ret[0].u.choices.choicekws = ":tile:gap";
498 ret[0].u.choices.selected = ui->invert_cursor;
499
500 ret[1].name = NULL;
501 ret[1].type = C_END;
502
503 return ret;
442} 504}
443 505
444static char *encode_ui(const game_ui *ui) 506static void set_prefs(game_ui *ui, const config_item *cfg)
445{ 507{
446 return NULL; 508 ui->invert_cursor = cfg[0].u.choices.selected;
447} 509}
448 510
449static void decode_ui(game_ui *ui, const char *encoding) 511static void free_ui(game_ui *ui)
450{ 512{
513 sfree(ui);
451} 514}
452 515
453static void game_changed_state(game_ui *ui, const game_state *oldstate, 516static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -692,28 +755,23 @@ static char *interpret_move(const game_state *state, game_ui *ui,
692 int cy = Y(state, state->gap_pos), ny = cy; 755 int cy = Y(state, state->gap_pos), ny = cy;
693 char buf[80]; 756 char buf[80];
694 757
695 button &= ~MOD_MASK; 758 button = STRIP_BUTTON_MODIFIERS(button);
696 759
697 if (button == LEFT_BUTTON) { 760 if (button == LEFT_BUTTON) {
698 nx = FROMCOORD(x); 761 nx = FROMCOORD(x);
699 ny = FROMCOORD(y); 762 ny = FROMCOORD(y);
700 if (nx < 0 || nx >= state->w || ny < 0 || ny >= state->h) 763 if (nx < 0 || nx >= state->w || ny < 0 || ny >= state->h)
701 return NULL; /* out of bounds */ 764 return MOVE_UNUSED; /* out of bounds */
702 } else if (IS_CURSOR_MOVE(button)) { 765 } else if (IS_CURSOR_MOVE(button)) {
703 static int invert_cursor = -1;
704 if (invert_cursor == -1) {
705 char *env = getenv("FIFTEEN_INVERT_CURSOR");
706 invert_cursor = (env && (env[0] == 'y' || env[0] == 'Y'));
707 }
708 button = flip_cursor(button); /* the default */ 766 button = flip_cursor(button); /* the default */
709 if (invert_cursor) 767 if (ui->invert_cursor)
710 button = flip_cursor(button); /* undoes the first flip */ 768 button = flip_cursor(button); /* undoes the first flip */
711 move_cursor(button, &nx, &ny, state->w, state->h, false); 769 move_cursor(button, &nx, &ny, state->w, state->h, false, NULL);
712 } else if ((button == 'h' || button == 'H') && !state->completed) { 770 } else if ((button == 'h' || button == 'H') && !state->completed) {
713 if (!compute_hint(state, &nx, &ny)) 771 if (!compute_hint(state, &nx, &ny))
714 return NULL; /* shouldn't happen, since ^^we^^checked^^ */ 772 return MOVE_NO_EFFECT;/* shouldn't happen, since ^^we^^checked^^ */
715 } else 773 } else
716 return NULL; /* no move */ 774 return MOVE_UNUSED; /* no move */
717 775
718 /* 776 /*
719 * Any click location should be equal to the gap location 777 * Any click location should be equal to the gap location
@@ -724,7 +782,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
724 return dupstr(buf); 782 return dupstr(buf);
725 } 783 }
726 784
727 return NULL; 785 return MOVE_NO_EFFECT;
728} 786}
729 787
730static game_state *execute_move(const game_state *from, const char *move) 788static game_state *execute_move(const game_state *from, const char *move)
@@ -786,11 +844,8 @@ static game_state *execute_move(const game_state *from, const char *move)
786 /* 844 /*
787 * See if the game has been completed. 845 * See if the game has been completed.
788 */ 846 */
789 if (!ret->completed) { 847 if (!ret->completed && is_completed(ret->tiles, ret->n)) {
790 ret->completed = ret->movecount; 848 ret->completed = ret->movecount;
791 for (p = 0; p < ret->n; p++)
792 if (ret->tiles[p] != (p < ret->n-1 ? p+1 : 0))
793 ret->completed = 0;
794 } 849 }
795 850
796 return ret; 851 return ret;
@@ -801,7 +856,7 @@ static game_state *execute_move(const game_state *from, const char *move)
801 */ 856 */
802 857
803static void game_compute_size(const game_params *params, int tilesize, 858static void game_compute_size(const game_params *params, int tilesize,
804 int *x, int *y) 859 const game_ui *ui, int *x, int *y)
805{ 860{
806 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 861 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
807 struct { int tilesize; } ads, *ds = &ads; 862 struct { int tilesize; } ads, *ds = &ads;
@@ -904,13 +959,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
904 if (!ds->started) { 959 if (!ds->started) {
905 int coords[10]; 960 int coords[10];
906 961
907 draw_rect(dr, 0, 0,
908 TILE_SIZE * state->w + 2 * BORDER,
909 TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND);
910 draw_update(dr, 0, 0,
911 TILE_SIZE * state->w + 2 * BORDER,
912 TILE_SIZE * state->h + 2 * BORDER);
913
914 /* 962 /*
915 * Recessed area containing the whole puzzle. 963 * Recessed area containing the whole puzzle.
916 */ 964 */
@@ -1077,19 +1125,6 @@ static int game_status(const game_state *state)
1077 return state->completed ? +1 : 0; 1125 return state->completed ? +1 : 0;
1078} 1126}
1079 1127
1080static bool game_timing_state(const game_state *state, game_ui *ui)
1081{
1082 return true;
1083}
1084
1085static void game_print_size(const game_params *params, float *x, float *y)
1086{
1087}
1088
1089static void game_print(drawing *dr, const game_state *state, int tilesize)
1090{
1091}
1092
1093#ifdef COMBINED 1128#ifdef COMBINED
1094#define thegame fifteen 1129#define thegame fifteen
1095#endif 1130#endif
@@ -1111,12 +1146,14 @@ const struct game thegame = {
1111 free_game, 1146 free_game,
1112 true, solve_game, 1147 true, solve_game,
1113 true, game_can_format_as_text_now, game_text_format, 1148 true, game_can_format_as_text_now, game_text_format,
1149 get_prefs, set_prefs,
1114 new_ui, 1150 new_ui,
1115 free_ui, 1151 free_ui,
1116 encode_ui, 1152 NULL, /* encode_ui */
1117 decode_ui, 1153 NULL, /* decode_ui */
1118 NULL, /* game_request_keys */ 1154 NULL, /* game_request_keys */
1119 game_changed_state, 1155 game_changed_state,
1156 NULL, /* current_key_label */
1120 interpret_move, 1157 interpret_move,
1121 execute_move, 1158 execute_move,
1122 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 1159 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -1128,9 +1165,9 @@ const struct game thegame = {
1128 game_flash_length, 1165 game_flash_length,
1129 game_get_cursor_location, 1166 game_get_cursor_location,
1130 game_status, 1167 game_status,
1131 false, false, game_print_size, game_print, 1168 false, false, NULL, NULL, /* print_size, print */
1132 true, /* wants_statusbar */ 1169 true, /* wants_statusbar */
1133 false, game_timing_state, 1170 false, NULL, /* timing_state */
1134 0, /* flags */ 1171 0, /* flags */
1135}; 1172};
1136 1173
diff --git a/apps/plugins/puzzles/src/filling.R b/apps/plugins/puzzles/src/filling.R
deleted file mode 100644
index cffbafaa0a..0000000000
--- a/apps/plugins/puzzles/src/filling.R
+++ /dev/null
@@ -1,24 +0,0 @@
1# -*- makefile -*-
2
3FILLING_EXTRA = dsf
4
5fillingsolver : [U] filling[STANDALONE_SOLVER] FILLING_EXTRA STANDALONE
6fillingsolver : [C] filling[STANDALONE_SOLVER] FILLING_EXTRA STANDALONE
7
8filling : [X] GTK COMMON filling FILLING_EXTRA filling-icon|no-icon
9
10filling : [G] WINDOWS COMMON filling FILLING_EXTRA filling.res|noicon.res
11
12ALL += filling[COMBINED] FILLING_EXTRA
13
14!begin am gtk
15GAMES += filling
16!end
17
18!begin >list.c
19 A(filling) \
20!end
21
22!begin >gamedesc.txt
23filling:filling.exe:Filling:Polyomino puzzle:Mark every square with the area of its containing region.
24!end
diff --git a/apps/plugins/puzzles/src/filling.c b/apps/plugins/puzzles/src/filling.c
index 6d9beb5c28..a0c144714b 100644
--- a/apps/plugins/puzzles/src/filling.c
+++ b/apps/plugins/puzzles/src/filling.c
@@ -1,4 +1,4 @@
1/* -*- tab-width: 8; indent-tabs-mode: t -*- 1/*
2 * filling.c: An implementation of the Nikoli game fillomino. 2 * filling.c: An implementation of the Nikoli game fillomino.
3 * Copyright (C) 2007 Jonas Kölker. See LICENSE for the license. 3 * Copyright (C) 2007 Jonas Kölker. See LICENSE for the license.
4 */ 4 */
@@ -58,7 +58,11 @@
58 58
59#include <assert.h> 59#include <assert.h>
60#include <ctype.h> 60#include <ctype.h>
61#include <math.h> 61#ifdef NO_TGMATH_H
62# include <math.h>
63#else
64# include <tgmath.h>
65#endif
62#include <stdarg.h> 66#include <stdarg.h>
63#include <stdio.h> 67#include <stdio.h>
64#include <stdlib.h> 68#include <stdlib.h>
@@ -68,16 +72,11 @@
68 72
69static bool verbose; 73static bool verbose;
70 74
71static void printv(const char *fmt, ...) { 75#ifdef STANDALONE_SOLVER
72#if !defined(PALM) && !defined(ROCKBOX) 76#define printv if (!verbose); else printf
73 if (verbose) { 77#else
74 va_list va; 78#define printv(...)
75 va_start(va, fmt);
76 vprintf(fmt, va);
77 va_end(va);
78 }
79#endif 79#endif
80}
81 80
82/***************************************************************************** 81/*****************************************************************************
83 * GAME CONFIGURATION AND PARAMETERS * 82 * GAME CONFIGURATION AND PARAMETERS *
@@ -188,6 +187,8 @@ static const char *validate_params(const game_params *params, bool full)
188{ 187{
189 if (params->w < 1) return "Width must be at least one"; 188 if (params->w < 1) return "Width must be at least one";
190 if (params->h < 1) return "Height must be at least one"; 189 if (params->h < 1) return "Height must be at least one";
190 if (params->w > INT_MAX / params->h)
191 return "Width times height must not be unreasonably large";
191 192
192 return NULL; 193 return NULL;
193} 194}
@@ -289,14 +290,15 @@ static const int dy[4] = {0, 0, -1, 1};
289 290
290struct solver_state 291struct solver_state
291{ 292{
292 int *dsf; 293 DSF *dsf;
293 int *board; 294 int *board;
294 int *connected; 295 int *connected;
295 int nempty; 296 int nempty;
296 297
297 /* Used internally by learn_bitmap_deductions; kept here to avoid 298 /* Used internally by learn_bitmap_deductions; kept here to avoid
298 * mallocing/freeing them every time that function is called. */ 299 * mallocing/freeing them every time that function is called. */
299 int *bm, *bmdsf, *bmminsize; 300 int *bm, *bmminsize;
301 DSF *bmdsf;
300}; 302};
301 303
302static void print_board(int *board, int w, int h) { 304static void print_board(int *board, int w, int h) {
@@ -310,7 +312,7 @@ static void print_board(int *board, int w, int h) {
310static game_state *new_game(midend *, const game_params *, const char *); 312static game_state *new_game(midend *, const game_params *, const char *);
311static void free_game(game_state *); 313static void free_game(game_state *);
312 314
313#define SENTINEL sz 315#define SENTINEL (sz+1)
314 316
315static bool mark_region(int *board, int w, int h, int i, int n, int m) { 317static bool mark_region(int *board, int w, int h, int i, int n, int m) {
316 int j; 318 int j;
@@ -390,7 +392,8 @@ static void make_board(int *board, int w, int h, random_state *rs) {
390 /* Note that if 1 in {w, h} then it's impossible to have a region 392 /* Note that if 1 in {w, h} then it's impossible to have a region
391 * of size > w*h, so the special case only affects w=h=2. */ 393 * of size > w*h, so the special case only affects w=h=2. */
392 394
393 int i, *dsf; 395 int i;
396 DSF *dsf;
394 bool change; 397 bool change;
395 398
396 assert(w >= 1); 399 assert(w >= 1);
@@ -401,9 +404,9 @@ static void make_board(int *board, int w, int h, random_state *rs) {
401 * contains a shuffled list of numbers {0, ..., sz-1}. */ 404 * contains a shuffled list of numbers {0, ..., sz-1}. */
402 for (i = 0; i < sz; ++i) board[i] = i; 405 for (i = 0; i < sz; ++i) board[i] = i;
403 406
404 dsf = snewn(sz, int); 407 dsf = dsf_new(sz);
405retry: 408retry:
406 dsf_init(dsf, sz); 409 dsf_reinit(dsf);
407 shuffle(board, sz, sizeof (int), rs); 410 shuffle(board, sz, sizeof (int), rs);
408 411
409 do { 412 do {
@@ -414,10 +417,15 @@ retry:
414 int merge = SENTINEL, min = maxsize - size + 1; 417 int merge = SENTINEL, min = maxsize - size + 1;
415 bool error = false; 418 bool error = false;
416 int neighbour, neighbour_size, j; 419 int neighbour, neighbour_size, j;
420 int directions[4];
421
422 for (j = 0; j < 4; ++j)
423 directions[j] = j;
424 shuffle(directions, 4, sizeof(int), rs);
417 425
418 for (j = 0; j < 4; ++j) { 426 for (j = 0; j < 4; ++j) {
419 const int x = (board[i] % w) + dx[j]; 427 const int x = (board[i] % w) + dx[directions[j]];
420 const int y = (board[i] / w) + dy[j]; 428 const int y = (board[i] / w) + dy[directions[j]];
421 if (x < 0 || x >= w || y < 0 || y >= h) continue; 429 if (x < 0 || x >= w || y < 0 || y >= h) continue;
422 430
423 neighbour = dsf_canonify(dsf, w*y + x); 431 neighbour = dsf_canonify(dsf, w*y + x);
@@ -429,7 +437,7 @@ retry:
429 /* find the smallest neighbour to merge with, which 437 /* find the smallest neighbour to merge with, which
430 * wouldn't make the region too large. (This is 438 * wouldn't make the region too large. (This is
431 * guaranteed by the initial value of `min'.) */ 439 * guaranteed by the initial value of `min'.) */
432 if (neighbour_size < min) { 440 if (neighbour_size < min && random_upto(rs, 10)) {
433 min = neighbour_size; 441 min = neighbour_size;
434 merge = neighbour; 442 merge = neighbour;
435 } 443 }
@@ -453,10 +461,10 @@ retry:
453 for (i = 0; i < sz; ++i) board[i] = dsf_size(dsf, i); 461 for (i = 0; i < sz; ++i) board[i] = dsf_size(dsf, i);
454 merge_ones(board, w, h); 462 merge_ones(board, w, h);
455 463
456 sfree(dsf); 464 dsf_free(dsf);
457} 465}
458 466
459static void merge(int *dsf, int *connected, int a, int b) { 467static void merge(DSF *dsf, int *connected, int a, int b) {
460 int c; 468 int c;
461 assert(dsf); 469 assert(dsf);
462 assert(connected); 470 assert(connected);
@@ -532,7 +540,7 @@ static bool check_capacity(int *board, int w, int h, int i) {
532 return n == 0; 540 return n == 0;
533} 541}
534 542
535static int expandsize(const int *board, int *dsf, int w, int h, int i, int n) { 543static int expandsize(const int *board, DSF *dsf, int w, int h, int i, int n) {
536 int j; 544 int j;
537 int nhits = 0; 545 int nhits = 0;
538 int hits[4]; 546 int hits[4];
@@ -548,7 +556,7 @@ static int expandsize(const int *board, int *dsf, int w, int h, int i, int n) {
548 root = dsf_canonify(dsf, idx); 556 root = dsf_canonify(dsf, idx);
549 for (m = 0; m < nhits && root != hits[m]; ++m); 557 for (m = 0; m < nhits && root != hits[m]; ++m);
550 if (m < nhits) continue; 558 if (m < nhits) continue;
551 printv("\t (%d, %d) contrib %d to size\n", x, y, dsf[root] >> 2); 559 printv("\t (%d, %d) contrib %d to size\n", x, y, dsf_size(dsf, root));
552 size += dsf_size(dsf, root); 560 size += dsf_size(dsf, root);
553 assert(dsf_size(dsf, root) >= 1); 561 assert(dsf_size(dsf, root) >= 1);
554 hits[nhits++] = root; 562 hits[nhits++] = root;
@@ -833,7 +841,7 @@ static bool learn_bitmap_deductions(struct solver_state *s, int w, int h)
833{ 841{
834 const int sz = w * h; 842 const int sz = w * h;
835 int *bm = s->bm; 843 int *bm = s->bm;
836 int *dsf = s->bmdsf; 844 DSF *dsf = s->bmdsf;
837 int *minsize = s->bmminsize; 845 int *minsize = s->bmminsize;
838 int x, y, i, j, n; 846 int x, y, i, j, n;
839 bool learn = false; 847 bool learn = false;
@@ -933,7 +941,7 @@ static bool learn_bitmap_deductions(struct solver_state *s, int w, int h)
933 * have a completely new n-region in it. 941 * have a completely new n-region in it.
934 */ 942 */
935 for (n = 1; n <= 9; n++) { 943 for (n = 1; n <= 9; n++) {
936 dsf_init(dsf, sz); 944 dsf_reinit(dsf);
937 945
938 /* Build the dsf */ 946 /* Build the dsf */
939 for (y = 0; y < h; y++) 947 for (y = 0; y < h; y++)
@@ -1076,12 +1084,12 @@ static bool solver(const int *orig, int w, int h, char **solution) {
1076 1084
1077 struct solver_state ss; 1085 struct solver_state ss;
1078 ss.board = memdup(orig, sz, sizeof (int)); 1086 ss.board = memdup(orig, sz, sizeof (int));
1079 ss.dsf = snew_dsf(sz); /* eqv classes: connected components */ 1087 ss.dsf = dsf_new(sz); /* eqv classes: connected components */
1080 ss.connected = snewn(sz, int); /* connected[n] := n.next; */ 1088 ss.connected = snewn(sz, int); /* connected[n] := n.next; */
1081 /* cyclic disjoint singly linked lists, same partitioning as dsf. 1089 /* cyclic disjoint singly linked lists, same partitioning as dsf.
1082 * The lists lets you iterate over a partition given any member */ 1090 * The lists lets you iterate over a partition given any member */
1083 ss.bm = snewn(sz, int); 1091 ss.bm = snewn(sz, int);
1084 ss.bmdsf = snew_dsf(sz); 1092 ss.bmdsf = dsf_new(sz);
1085 ss.bmminsize = snewn(sz, int); 1093 ss.bmminsize = snewn(sz, int);
1086 1094
1087 printv("trying to solve this:\n"); 1095 printv("trying to solve this:\n");
@@ -1105,28 +1113,26 @@ static bool solver(const int *orig, int w, int h, char **solution) {
1105 **solution = 's'; 1113 **solution = 's';
1106 for (i = 0; i < sz; ++i) (*solution)[i + 1] = ss.board[i] + '0'; 1114 for (i = 0; i < sz; ++i) (*solution)[i + 1] = ss.board[i] + '0';
1107 (*solution)[sz + 1] = '\0'; 1115 (*solution)[sz + 1] = '\0';
1108 /* We don't need the \0 for execute_move (the only user)
1109 * I'm just being printf-friendly in case I wanna print */
1110 } 1116 }
1111 1117
1112 sfree(ss.dsf); 1118 dsf_free(ss.dsf);
1113 sfree(ss.board); 1119 sfree(ss.board);
1114 sfree(ss.connected); 1120 sfree(ss.connected);
1115 sfree(ss.bm); 1121 sfree(ss.bm);
1116 sfree(ss.bmdsf); 1122 dsf_free(ss.bmdsf);
1117 sfree(ss.bmminsize); 1123 sfree(ss.bmminsize);
1118 1124
1119 return !ss.nempty; 1125 return !ss.nempty;
1120} 1126}
1121 1127
1122static int *make_dsf(int *dsf, int *board, const int w, const int h) { 1128static DSF *make_dsf(DSF *dsf, int *board, const int w, const int h) {
1123 const int sz = w * h; 1129 const int sz = w * h;
1124 int i; 1130 int i;
1125 1131
1126 if (!dsf) 1132 if (!dsf)
1127 dsf = snew_dsf(w * h); 1133 dsf = dsf_new_min(w * h);
1128 else 1134 else
1129 dsf_init(dsf, w * h); 1135 dsf_reinit(dsf);
1130 1136
1131 for (i = 0; i < sz; ++i) { 1137 for (i = 0; i < sz; ++i) {
1132 int j; 1138 int j;
@@ -1145,7 +1151,8 @@ static void minimize_clue_set(int *board, int w, int h, random_state *rs)
1145{ 1151{
1146 const int sz = w * h; 1152 const int sz = w * h;
1147 int *shuf = snewn(sz, int), i; 1153 int *shuf = snewn(sz, int), i;
1148 int *dsf, *next; 1154 DSF *dsf;
1155 int *next;
1149 1156
1150 for (i = 0; i < sz; ++i) shuf[i] = i; 1157 for (i = 0; i < sz; ++i) shuf[i] = i;
1151 shuffle(shuf, sz, sizeof (int), rs); 1158 shuffle(shuf, sz, sizeof (int), rs);
@@ -1162,14 +1169,14 @@ static void minimize_clue_set(int *board, int w, int h, random_state *rs)
1162 dsf = make_dsf(NULL, board, w, h); 1169 dsf = make_dsf(NULL, board, w, h);
1163 next = snewn(sz, int); 1170 next = snewn(sz, int);
1164 for (i = 0; i < sz; ++i) { 1171 for (i = 0; i < sz; ++i) {
1165 int j = dsf_canonify(dsf, i); 1172 int j = dsf_minimal(dsf, i);
1166 if (i == j) { 1173 if (i == j) {
1167 /* First cell of a region; set next[i] = -1 to indicate 1174 /* First cell of a region; set next[i] = -1 to indicate
1168 * end-of-list. */ 1175 * end-of-list. */
1169 next[i] = -1; 1176 next[i] = -1;
1170 } else { 1177 } else {
1171 /* Add this cell to a region which already has a 1178 /* Add this cell to a region which already has a
1172 * linked-list head, by pointing the canonical element j 1179 * linked-list head, by pointing the minimal element j
1173 * at this one, and pointing this one in turn at wherever 1180 * at this one, and pointing this one in turn at wherever
1174 * j previously pointed. (This should end up with the 1181 * j previously pointed. (This should end up with the
1175 * elements linked in the order 1,n,n-1,n-2,...,2, which 1182 * elements linked in the order 1,n,n-1,n-2,...,2, which
@@ -1197,7 +1204,7 @@ static void minimize_clue_set(int *board, int w, int h, random_state *rs)
1197 * if we can. 1204 * if we can.
1198 */ 1205 */
1199 for (i = 0; i < sz; ++i) { 1206 for (i = 0; i < sz; ++i) {
1200 int j = dsf_canonify(dsf, shuf[i]); 1207 int j = dsf_minimal(dsf, shuf[i]);
1201 if (next[j] != -2) { 1208 if (next[j] != -2) {
1202 int tmp = board[j]; 1209 int tmp = board[j];
1203 int k; 1210 int k;
@@ -1217,7 +1224,7 @@ static void minimize_clue_set(int *board, int w, int h, random_state *rs)
1217 } 1224 }
1218 } 1225 }
1219 sfree(next); 1226 sfree(next);
1220 sfree(dsf); 1227 dsf_free(dsf);
1221 1228
1222 /* 1229 /*
1223 * Now go through individual cells, in the same shuffled order, 1230 * Now go through individual cells, in the same shuffled order,
@@ -1391,7 +1398,7 @@ static game_ui *new_ui(const game_state *state)
1391 1398
1392 ui->sel = NULL; 1399 ui->sel = NULL;
1393 ui->cur_x = ui->cur_y = 0; 1400 ui->cur_x = ui->cur_y = 0;
1394 ui->cur_visible = false; 1401 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1395 ui->keydragging = false; 1402 ui->keydragging = false;
1396 1403
1397 return ui; 1404 return ui;
@@ -1404,15 +1411,6 @@ static void free_ui(game_ui *ui)
1404 sfree(ui); 1411 sfree(ui);
1405} 1412}
1406 1413
1407static char *encode_ui(const game_ui *ui)
1408{
1409 return NULL;
1410}
1411
1412static void decode_ui(game_ui *ui, const char *encoding)
1413{
1414}
1415
1416static void game_changed_state(game_ui *ui, const game_state *oldstate, 1414static void game_changed_state(game_ui *ui, const game_state *oldstate,
1417 const game_state *newstate) 1415 const game_state *newstate)
1418{ 1416{
@@ -1424,6 +1422,23 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1424 ui->keydragging = false; 1422 ui->keydragging = false;
1425} 1423}
1426 1424
1425static const char *current_key_label(const game_ui *ui,
1426 const game_state *state, int button)
1427{
1428 const int w = state->shared->params.w;
1429
1430 if (IS_CURSOR_SELECT(button) && ui->cur_visible) {
1431 if (button == CURSOR_SELECT) {
1432 if (ui->keydragging) return "Stop";
1433 return "Multiselect";
1434 }
1435 if (button == CURSOR_SELECT2 &&
1436 !state->shared->clues[w*ui->cur_y + ui->cur_x])
1437 return (ui->sel[w*ui->cur_y + ui->cur_x]) ? "Deselect" : "Select";
1438 }
1439 return "";
1440}
1441
1427#define PREFERRED_TILE_SIZE 32 1442#define PREFERRED_TILE_SIZE 32
1428#define TILE_SIZE (ds->tilesize) 1443#define TILE_SIZE (ds->tilesize)
1429#define BORDER (TILE_SIZE / 2) 1444#define BORDER (TILE_SIZE / 2)
@@ -1434,7 +1449,8 @@ struct game_drawstate {
1434 int tilesize; 1449 int tilesize;
1435 bool started; 1450 bool started;
1436 int *v, *flags; 1451 int *v, *flags;
1437 int *dsf_scratch, *border_scratch; 1452 DSF *dsf_scratch;
1453 int *border_scratch;
1438}; 1454};
1439 1455
1440static char *interpret_move(const game_state *state, game_ui *ui, 1456static char *interpret_move(const game_state *state, game_ui *ui,
@@ -1453,7 +1469,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1453 assert(ui); 1469 assert(ui);
1454 assert(ds); 1470 assert(ds);
1455 1471
1456 button &= ~MOD_MASK; 1472 button = STRIP_BUTTON_MODIFIERS(button);
1457 1473
1458 if (button == LEFT_BUTTON || button == LEFT_DRAG) { 1474 if (button == LEFT_BUTTON || button == LEFT_DRAG) {
1459 /* A left-click anywhere will clear the current selection. */ 1475 /* A left-click anywhere will clear the current selection. */
@@ -1472,22 +1488,22 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1472 ui->sel[w*ty+tx] = true; 1488 ui->sel[w*ty+tx] = true;
1473 } 1489 }
1474 ui->cur_visible = false; 1490 ui->cur_visible = false;
1475 return UI_UPDATE; 1491 return MOVE_UI_UPDATE;
1476 } 1492 }
1477 1493
1478 if (IS_CURSOR_MOVE(button)) { 1494 if (IS_CURSOR_MOVE(button)) {
1479 ui->cur_visible = true; 1495 ui->cur_visible = true;
1480 move_cursor(button, &ui->cur_x, &ui->cur_y, w, h, false); 1496 move_cursor(button, &ui->cur_x, &ui->cur_y, w, h, false, NULL);
1481 if (ui->keydragging) goto select_square; 1497 if (ui->keydragging) goto select_square;
1482 return UI_UPDATE; 1498 return MOVE_UI_UPDATE;
1483 } 1499 }
1484 if (button == CURSOR_SELECT) { 1500 if (button == CURSOR_SELECT) {
1485 if (!ui->cur_visible) { 1501 if (!ui->cur_visible) {
1486 ui->cur_visible = true; 1502 ui->cur_visible = true;
1487 return UI_UPDATE; 1503 return MOVE_UI_UPDATE;
1488 } 1504 }
1489 ui->keydragging = !ui->keydragging; 1505 ui->keydragging = !ui->keydragging;
1490 if (!ui->keydragging) return UI_UPDATE; 1506 if (!ui->keydragging) return MOVE_UI_UPDATE;
1491 1507
1492 select_square: 1508 select_square:
1493 if (!ui->sel) { 1509 if (!ui->sel) {
@@ -1496,12 +1512,12 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1496 } 1512 }
1497 if (!state->shared->clues[w*ui->cur_y + ui->cur_x]) 1513 if (!state->shared->clues[w*ui->cur_y + ui->cur_x])
1498 ui->sel[w*ui->cur_y + ui->cur_x] = true; 1514 ui->sel[w*ui->cur_y + ui->cur_x] = true;
1499 return UI_UPDATE; 1515 return MOVE_UI_UPDATE;
1500 } 1516 }
1501 if (button == CURSOR_SELECT2) { 1517 if (button == CURSOR_SELECT2) {
1502 if (!ui->cur_visible) { 1518 if (!ui->cur_visible) {
1503 ui->cur_visible = true; 1519 ui->cur_visible = true;
1504 return UI_UPDATE; 1520 return MOVE_UI_UPDATE;
1505 } 1521 }
1506 if (!ui->sel) { 1522 if (!ui->sel) {
1507 ui->sel = snewn(w*h, bool); 1523 ui->sel = snewn(w*h, bool);
@@ -1515,19 +1531,19 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1515 sfree(ui->sel); 1531 sfree(ui->sel);
1516 ui->sel = NULL; 1532 ui->sel = NULL;
1517 } 1533 }
1518 return UI_UPDATE; 1534 return MOVE_UI_UPDATE;
1519 } 1535 }
1520 1536
1521 if (button == '\b' || button == 27) { 1537 if (button == '\b' || button == 27) {
1522 sfree(ui->sel); 1538 sfree(ui->sel);
1523 ui->sel = NULL; 1539 ui->sel = NULL;
1524 ui->keydragging = false; 1540 ui->keydragging = false;
1525 return UI_UPDATE; 1541 return MOVE_UI_UPDATE;
1526 } 1542 }
1527 1543
1528 if (button < '0' || button > '9') return NULL; 1544 if (button < '0' || button > '9') return MOVE_UNUSED;
1529 button -= '0'; 1545 button -= '0';
1530 if (button > (w == 2 && h == 2 ? 3 : max(w, h))) return NULL; 1546 if (button > (w == 2 && h == 2 ? 3 : max(w, h))) return MOVE_UNUSED;
1531 ui->keydragging = false; 1547 ui->keydragging = false;
1532 1548
1533 for (i = 0; i < w*h; i++) { 1549 for (i = 0; i < w*h; i++) {
@@ -1553,11 +1569,11 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1553 move = srealloc(move, strlen(move)+strlen(buf)+1); 1569 move = srealloc(move, strlen(move)+strlen(buf)+1);
1554 strcat(move, buf); 1570 strcat(move, buf);
1555 } 1571 }
1556 if (!ui->sel) return move ? move : NULL; 1572 if (!ui->sel) return move ? move : MOVE_NO_EFFECT;
1557 sfree(ui->sel); 1573 sfree(ui->sel);
1558 ui->sel = NULL; 1574 ui->sel = NULL;
1559 /* Need to update UI at least, as we cleared the selection */ 1575 /* Need to update UI at least, as we cleared the selection */
1560 return move ? move : UI_UPDATE; 1576 return move ? move : MOVE_UI_UPDATE;
1561} 1577}
1562 1578
1563static game_state *execute_move(const game_state *state, const char *move) 1579static game_state *execute_move(const game_state *state, const char *move)
@@ -1567,6 +1583,7 @@ static game_state *execute_move(const game_state *state, const char *move)
1567 1583
1568 if (*move == 's') { 1584 if (*move == 's') {
1569 int i = 0; 1585 int i = 0;
1586 if (strlen(move) != sz + 1) return NULL;
1570 new_state = dup_game(state); 1587 new_state = dup_game(state);
1571 for (++move; i < sz; ++i) new_state->board[i] = move[i] - '0'; 1588 for (++move; i < sz; ++i) new_state->board[i] = move[i] - '0';
1572 new_state->cheated = true; 1589 new_state->cheated = true;
@@ -1596,10 +1613,10 @@ static game_state *execute_move(const game_state *state, const char *move)
1596 const int w = new_state->shared->params.w; 1613 const int w = new_state->shared->params.w;
1597 const int h = new_state->shared->params.h; 1614 const int h = new_state->shared->params.h;
1598 const int sz = w * h; 1615 const int sz = w * h;
1599 int *dsf = make_dsf(NULL, new_state->board, w, h); 1616 DSF *dsf = make_dsf(NULL, new_state->board, w, h);
1600 int i; 1617 int i;
1601 for (i = 0; i < sz && new_state->board[i] == dsf_size(dsf, i); ++i); 1618 for (i = 0; i < sz && new_state->board[i] == dsf_size(dsf, i); ++i);
1602 sfree(dsf); 1619 dsf_free(dsf);
1603 if (i == sz) 1620 if (i == sz)
1604 new_state->completed = true; 1621 new_state->completed = true;
1605 } 1622 }
@@ -1630,7 +1647,7 @@ enum {
1630}; 1647};
1631 1648
1632static void game_compute_size(const game_params *params, int tilesize, 1649static void game_compute_size(const game_params *params, int tilesize,
1633 int *x, int *y) 1650 const game_ui *ui, int *x, int *y)
1634{ 1651{
1635 *x = (params->w + 1) * tilesize; 1652 *x = (params->w + 1) * tilesize;
1636 *y = (params->h + 1) * tilesize; 1653 *y = (params->h + 1) * tilesize;
@@ -1652,9 +1669,9 @@ static float *game_colours(frontend *fe, int *ncolours)
1652 ret[COL_GRID * 3 + 1] = 0.0F; 1669 ret[COL_GRID * 3 + 1] = 0.0F;
1653 ret[COL_GRID * 3 + 2] = 0.0F; 1670 ret[COL_GRID * 3 + 2] = 0.0F;
1654 1671
1655 ret[COL_HIGHLIGHT * 3 + 0] = 0.85F * ret[COL_BACKGROUND * 3 + 0]; 1672 ret[COL_HIGHLIGHT * 3 + 0] = 0.7F * ret[COL_BACKGROUND * 3 + 0];
1656 ret[COL_HIGHLIGHT * 3 + 1] = 0.85F * ret[COL_BACKGROUND * 3 + 1]; 1673 ret[COL_HIGHLIGHT * 3 + 1] = 0.7F * ret[COL_BACKGROUND * 3 + 1];
1657 ret[COL_HIGHLIGHT * 3 + 2] = 0.85F * ret[COL_BACKGROUND * 3 + 2]; 1674 ret[COL_HIGHLIGHT * 3 + 2] = 0.7F * ret[COL_BACKGROUND * 3 + 2];
1658 1675
1659 ret[COL_CORRECT * 3 + 0] = 0.9F * ret[COL_BACKGROUND * 3 + 0]; 1676 ret[COL_CORRECT * 3 + 0] = 0.9F * ret[COL_BACKGROUND * 3 + 0];
1660 ret[COL_CORRECT * 3 + 1] = 0.9F * ret[COL_BACKGROUND * 3 + 1]; 1677 ret[COL_CORRECT * 3 + 1] = 0.9F * ret[COL_BACKGROUND * 3 + 1];
@@ -1699,7 +1716,7 @@ static void game_free_drawstate(drawing *dr, game_drawstate *ds)
1699 sfree(ds->v); 1716 sfree(ds->v);
1700 sfree(ds->flags); 1717 sfree(ds->flags);
1701 sfree(ds->border_scratch); 1718 sfree(ds->border_scratch);
1702 sfree(ds->dsf_scratch); 1719 dsf_free(ds->dsf_scratch);
1703 sfree(ds); 1720 sfree(ds);
1704} 1721}
1705 1722
@@ -2016,17 +2033,8 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2016 (flashtime <= FLASH_TIME/3 || flashtime >= FLASH_TIME*2/3); 2033 (flashtime <= FLASH_TIME/3 || flashtime >= FLASH_TIME*2/3);
2017 2034
2018 if (!ds->started) { 2035 if (!ds->started) {
2019 /*
2020 * The initial contents of the window are not guaranteed and
2021 * can vary with front ends. To be on the safe side, all games
2022 * should start by drawing a big background-colour rectangle
2023 * covering the whole window.
2024 */
2025 draw_rect(dr, 0, 0, w*TILE_SIZE + 2*BORDER, h*TILE_SIZE + 2*BORDER,
2026 COL_BACKGROUND);
2027
2028 /* 2036 /*
2029 * Smaller black rectangle which is the main grid. 2037 * Black rectangle which is the main grid.
2030 */ 2038 */
2031 draw_rect(dr, BORDER - BORDER_WIDTH, BORDER - BORDER_WIDTH, 2039 draw_rect(dr, BORDER - BORDER_WIDTH, BORDER - BORDER_WIDTH,
2032 w*TILE_SIZE + 2*BORDER_WIDTH + 1, 2040 w*TILE_SIZE + 2*BORDER_WIDTH + 1,
@@ -2079,24 +2087,21 @@ static int game_status(const game_state *state)
2079 return state->completed ? +1 : 0; 2087 return state->completed ? +1 : 0;
2080} 2088}
2081 2089
2082static bool game_timing_state(const game_state *state, game_ui *ui) 2090static void game_print_size(const game_params *params, const game_ui *ui,
2083{ 2091 float *x, float *y)
2084 return true;
2085}
2086
2087static void game_print_size(const game_params *params, float *x, float *y)
2088{ 2092{
2089 int pw, ph; 2093 int pw, ph;
2090 2094
2091 /* 2095 /*
2092 * I'll use 6mm squares by default. 2096 * I'll use 6mm squares by default.
2093 */ 2097 */
2094 game_compute_size(params, 600, &pw, &ph); 2098 game_compute_size(params, 600, ui, &pw, &ph);
2095 *x = pw / 100.0F; 2099 *x = pw / 100.0F;
2096 *y = ph / 100.0F; 2100 *y = ph / 100.0F;
2097} 2101}
2098 2102
2099static void game_print(drawing *dr, const game_state *state, int tilesize) 2103static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2104 int tilesize)
2100{ 2105{
2101 const int w = state->shared->params.w; 2106 const int w = state->shared->params.w;
2102 const int h = state->shared->params.h; 2107 const int h = state->shared->params.h;
@@ -2164,12 +2169,14 @@ const struct game thegame = {
2164 free_game, 2169 free_game,
2165 true, solve_game, 2170 true, solve_game,
2166 true, game_can_format_as_text_now, game_text_format, 2171 true, game_can_format_as_text_now, game_text_format,
2172 NULL, NULL, /* get_prefs, set_prefs */
2167 new_ui, 2173 new_ui,
2168 free_ui, 2174 free_ui,
2169 encode_ui, 2175 NULL, /* encode_ui */
2170 decode_ui, 2176 NULL, /* decode_ui */
2171 game_request_keys, 2177 game_request_keys,
2172 game_changed_state, 2178 game_changed_state,
2179 current_key_label,
2173 interpret_move, 2180 interpret_move,
2174 execute_move, 2181 execute_move,
2175 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 2182 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -2183,13 +2190,18 @@ const struct game thegame = {
2183 game_status, 2190 game_status,
2184 true, false, game_print_size, game_print, 2191 true, false, game_print_size, game_print,
2185 false, /* wants_statusbar */ 2192 false, /* wants_statusbar */
2186 false, game_timing_state, 2193 false, NULL, /* timing_state */
2187 REQUIRE_NUMPAD, /* flags */ 2194 REQUIRE_NUMPAD, /* flags */
2188}; 2195};
2189 2196
2190#ifdef STANDALONE_SOLVER /* solver? hah! */ 2197#ifdef STANDALONE_SOLVER /* solver? hah! */
2191 2198
2192int main(int argc, char **argv) { 2199int main(int argc, char **argv) {
2200 if (!strcmp(argv[1], "--verbose")) {
2201 verbose = true;
2202 argv++;
2203 }
2204
2193 while (*++argv) { 2205 while (*++argv) {
2194 game_params *params; 2206 game_params *params;
2195 game_state *state; 2207 game_state *state;
diff --git a/apps/plugins/puzzles/src/flip.R b/apps/plugins/puzzles/src/flip.R
deleted file mode 100644
index 03241f015b..0000000000
--- a/apps/plugins/puzzles/src/flip.R
+++ /dev/null
@@ -1,21 +0,0 @@
1# -*- makefile -*-
2
3FLIP_EXTRA = tree234
4
5flip : [X] GTK COMMON flip FLIP_EXTRA flip-icon|no-icon
6
7flip : [G] WINDOWS COMMON flip FLIP_EXTRA flip.res|noicon.res
8
9ALL += flip[COMBINED] FLIP_EXTRA
10
11!begin am gtk
12GAMES += flip
13!end
14
15!begin >list.c
16 A(flip) \
17!end
18
19!begin >gamedesc.txt
20flip:flip.exe:Flip:Tile inversion puzzle:Flip groups of squares to light them all up at once.
21!end
diff --git a/apps/plugins/puzzles/src/flip.c b/apps/plugins/puzzles/src/flip.c
index 5d4f2250aa..044d6c30c3 100644
--- a/apps/plugins/puzzles/src/flip.c
+++ b/apps/plugins/puzzles/src/flip.c
@@ -8,7 +8,12 @@
8#include <string.h> 8#include <string.h>
9#include <assert.h> 9#include <assert.h>
10#include <ctype.h> 10#include <ctype.h>
11#include <math.h> 11#include <limits.h>
12#ifdef NO_TGMATH_H
13# include <math.h>
14#else
15# include <tgmath.h>
16#endif
12 17
13#include "puzzles.h" 18#include "puzzles.h"
14#include "tree234.h" 19#include "tree234.h"
@@ -181,9 +186,16 @@ static game_params *custom_params(const config_item *cfg)
181 186
182static const char *validate_params(const game_params *params, bool full) 187static const char *validate_params(const game_params *params, bool full)
183{ 188{
189 int wh;
190
184 if (params->w <= 0 || params->h <= 0) 191 if (params->w <= 0 || params->h <= 0)
185 return "Width and height must both be greater than zero"; 192 return "Width and height must both be greater than zero";
186 return NULL; 193 if (params->w > (INT_MAX - 3) / params->h)
194 return "Width times height must not be unreasonably large";
195 wh = params->w * params->h;
196 if (wh > (INT_MAX - 3) / wh)
197 return "Width times height is too large";
198 return NULL;
187} 199}
188 200
189static char *encode_bitmap(unsigned char *bmp, int len) 201static char *encode_bitmap(unsigned char *bmp, int len)
@@ -905,7 +917,7 @@ static game_ui *new_ui(const game_state *state)
905{ 917{
906 game_ui *ui = snew(game_ui); 918 game_ui *ui = snew(game_ui);
907 ui->cx = ui->cy = 0; 919 ui->cx = ui->cy = 0;
908 ui->cdraw = false; 920 ui->cdraw = getenv_bool("PUZZLES_SHOW_CURSOR", false);
909 return ui; 921 return ui;
910} 922}
911 923
@@ -914,18 +926,16 @@ static void free_ui(game_ui *ui)
914 sfree(ui); 926 sfree(ui);
915} 927}
916 928
917static char *encode_ui(const game_ui *ui) 929static void game_changed_state(game_ui *ui, const game_state *oldstate,
918{ 930 const game_state *newstate)
919 return NULL;
920}
921
922static void decode_ui(game_ui *ui, const char *encoding)
923{ 931{
924} 932}
925 933
926static void game_changed_state(game_ui *ui, const game_state *oldstate, 934static const char *current_key_label(const game_ui *ui,
927 const game_state *newstate) 935 const game_state *state, int button)
928{ 936{
937 if (IS_CURSOR_SELECT(button)) return "Flip";
938 return "";
929} 939}
930 940
931struct game_drawstate { 941struct game_drawstate {
@@ -940,7 +950,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
940 int x, int y, int button) 950 int x, int y, int button)
941{ 951{
942 int w = state->w, h = state->h, wh = w * h; 952 int w = state->w, h = state->h, wh = w * h;
943 char buf[80], *nullret = NULL; 953 char buf[80], *nullret = MOVE_UNUSED;
944 954
945 if (button == LEFT_BUTTON || IS_CURSOR_SELECT(button)) { 955 if (button == LEFT_BUTTON || IS_CURSOR_SELECT(button)) {
946 int tx, ty; 956 int tx, ty;
@@ -951,7 +961,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
951 tx = ui->cx; ty = ui->cy; 961 tx = ui->cx; ty = ui->cy;
952 ui->cdraw = true; 962 ui->cdraw = true;
953 } 963 }
954 nullret = UI_UPDATE; 964 nullret = MOVE_UI_UPDATE;
955 965
956 if (tx >= 0 && tx < w && ty >= 0 && ty < h) { 966 if (tx >= 0 && tx < w && ty >= 0 && ty < h) {
957 /* 967 /*
@@ -969,25 +979,12 @@ static char *interpret_move(const game_state *state, game_ui *ui,
969 sprintf(buf, "M%d,%d", tx, ty); 979 sprintf(buf, "M%d,%d", tx, ty);
970 return dupstr(buf); 980 return dupstr(buf);
971 } else { 981 } else {
972 return NULL; 982 return MOVE_NO_EFFECT;
973 } 983 }
974 } 984 }
975 } 985 } else if (IS_CURSOR_MOVE(button))
976 else if (IS_CURSOR_MOVE(button)) { 986 nullret = move_cursor(button, &ui->cx, &ui->cy, state->w, state->h,
977 int dx = 0, dy = 0; 987 false, &ui->cdraw);
978 switch (button) {
979 case CURSOR_UP: dy = -1; break;
980 case CURSOR_DOWN: dy = 1; break;
981 case CURSOR_RIGHT: dx = 1; break;
982 case CURSOR_LEFT: dx = -1; break;
983 default: assert(!"shouldn't get here");
984 }
985 ui->cx += dx; ui->cy += dy;
986 ui->cx = min(max(ui->cx, 0), state->w - 1);
987 ui->cy = min(max(ui->cy, 0), state->h - 1);
988 ui->cdraw = true;
989 nullret = UI_UPDATE;
990 }
991 988
992 return nullret; 989 return nullret;
993} 990}
@@ -1045,7 +1042,7 @@ static game_state *execute_move(const game_state *from, const char *move)
1045 */ 1042 */
1046 1043
1047static void game_compute_size(const game_params *params, int tilesize, 1044static void game_compute_size(const game_params *params, int tilesize,
1048 int *x, int *y) 1045 const game_ui *ui, int *x, int *y)
1049{ 1046{
1050 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 1047 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1051 struct { int tilesize; } ads, *ds = &ads; 1048 struct { int tilesize; } ads, *ds = &ads;
@@ -1145,7 +1142,7 @@ static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state,
1145 coords[7] = by + TILE_SIZE - (int)((float)TILE_SIZE * animtime); 1142 coords[7] = by + TILE_SIZE - (int)((float)TILE_SIZE * animtime);
1146 1143
1147 colour = (tile & 1 ? COL_WRONG : COL_RIGHT); 1144 colour = (tile & 1 ? COL_WRONG : COL_RIGHT);
1148 if (animtime < 0.5) 1145 if (animtime < 0.5F)
1149 colour = COL_WRONG + COL_RIGHT - colour; 1146 colour = COL_WRONG + COL_RIGHT - colour;
1150 1147
1151 draw_polygon(dr, coords, 4, colour, COL_GRID); 1148 draw_polygon(dr, coords, 4, colour, COL_GRID);
@@ -1159,7 +1156,7 @@ static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state,
1159 for (j = 0; j < w; j++) 1156 for (j = 0; j < w; j++)
1160 if (state->matrix->matrix[(y*w+x)*wh + i*w+j]) { 1157 if (state->matrix->matrix[(y*w+x)*wh + i*w+j]) {
1161 int ox = j - x, oy = i - y; 1158 int ox = j - x, oy = i - y;
1162 int td = TILE_SIZE / 16; 1159 int td = TILE_SIZE / 16 ? TILE_SIZE / 16 : 1;
1163 int cx = (bx + TILE_SIZE/2) + (2 * ox - 1) * td; 1160 int cx = (bx + TILE_SIZE/2) + (2 * ox - 1) * td;
1164 int cy = (by + TILE_SIZE/2) + (2 * oy - 1) * td; 1161 int cy = (by + TILE_SIZE/2) + (2 * oy - 1) * td;
1165 if (ox == 0 && oy == 0) 1162 if (ox == 0 && oy == 0)
@@ -1202,9 +1199,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1202 int i, flashframe; 1199 int i, flashframe;
1203 1200
1204 if (!ds->started) { 1201 if (!ds->started) {
1205 draw_rect(dr, 0, 0, TILE_SIZE * w + 2 * BORDER,
1206 TILE_SIZE * h + 2 * BORDER, COL_BACKGROUND);
1207
1208 /* 1202 /*
1209 * Draw the grid lines. 1203 * Draw the grid lines.
1210 */ 1204 */
@@ -1309,19 +1303,6 @@ static int game_status(const game_state *state)
1309 return state->completed ? +1 : 0; 1303 return state->completed ? +1 : 0;
1310} 1304}
1311 1305
1312static bool game_timing_state(const game_state *state, game_ui *ui)
1313{
1314 return true;
1315}
1316
1317static void game_print_size(const game_params *params, float *x, float *y)
1318{
1319}
1320
1321static void game_print(drawing *dr, const game_state *state, int tilesize)
1322{
1323}
1324
1325#ifdef COMBINED 1306#ifdef COMBINED
1326#define thegame flip 1307#define thegame flip
1327#endif 1308#endif
@@ -1343,12 +1324,14 @@ const struct game thegame = {
1343 free_game, 1324 free_game,
1344 true, solve_game, 1325 true, solve_game,
1345 true, game_can_format_as_text_now, game_text_format, 1326 true, game_can_format_as_text_now, game_text_format,
1327 NULL, NULL, /* get_prefs, set_prefs */
1346 new_ui, 1328 new_ui,
1347 free_ui, 1329 free_ui,
1348 encode_ui, 1330 NULL, /* encode_ui */
1349 decode_ui, 1331 NULL, /* decode_ui */
1350 NULL, /* game_request_keys */ 1332 NULL, /* game_request_keys */
1351 game_changed_state, 1333 game_changed_state,
1334 current_key_label,
1352 interpret_move, 1335 interpret_move,
1353 execute_move, 1336 execute_move,
1354 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 1337 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -1360,8 +1343,8 @@ const struct game thegame = {
1360 game_flash_length, 1343 game_flash_length,
1361 game_get_cursor_location, 1344 game_get_cursor_location,
1362 game_status, 1345 game_status,
1363 false, false, game_print_size, game_print, 1346 false, false, NULL, NULL, /* print_size, print */
1364 true, /* wants_statusbar */ 1347 true, /* wants_statusbar */
1365 false, game_timing_state, 1348 false, NULL, /* timing_state */
1366 0, /* flags */ 1349 0, /* flags */
1367}; 1350};
diff --git a/apps/plugins/puzzles/src/flood.R b/apps/plugins/puzzles/src/flood.R
deleted file mode 100644
index 359bbb5dce..0000000000
--- a/apps/plugins/puzzles/src/flood.R
+++ /dev/null
@@ -1,19 +0,0 @@
1# -*- makefile -*-
2
3flood : [X] GTK COMMON flood flood-icon|no-icon
4
5flood : [G] WINDOWS COMMON flood flood.res|noicon.res
6
7ALL += flood[COMBINED]
8
9!begin am gtk
10GAMES += flood
11!end
12
13!begin >list.c
14 A(flood) \
15!end
16
17!begin >gamedesc.txt
18flood:flood.exe:Flood:Flood-filling puzzle:Turn the grid the same colour in as few flood fills as possible.
19!end
diff --git a/apps/plugins/puzzles/src/flood.c b/apps/plugins/puzzles/src/flood.c
index 74214a50b6..fe809745db 100644
--- a/apps/plugins/puzzles/src/flood.c
+++ b/apps/plugins/puzzles/src/flood.c
@@ -31,7 +31,12 @@
31#include <string.h> 31#include <string.h>
32#include <assert.h> 32#include <assert.h>
33#include <ctype.h> 33#include <ctype.h>
34#include <math.h> 34#include <limits.h>
35#ifdef NO_TGMATH_H
36# include <math.h>
37#else
38# include <tgmath.h>
39#endif
35 40
36#include "puzzles.h" 41#include "puzzles.h"
37 42
@@ -140,13 +145,13 @@ static void decode_params(game_params *ret, char const *string)
140 if (*string == 'c') { 145 if (*string == 'c') {
141 string++; 146 string++;
142 ret->colours = atoi(string); 147 ret->colours = atoi(string);
143 while (string[1] && isdigit((unsigned char)string[1])) string++; 148 while (*string && isdigit((unsigned char)*string)) string++;
144 } else if (*string == 'm') { 149 } else if (*string == 'm') {
145 string++; 150 string++;
146 ret->leniency = atoi(string); 151 ret->leniency = atoi(string);
147 while (string[1] && isdigit((unsigned char)string[1])) string++; 152 while (*string && isdigit((unsigned char)*string)) string++;
148 } 153 } else
149 string++; 154 string++;
150 } 155 }
151} 156}
152 157
@@ -210,7 +215,9 @@ static const char *validate_params(const game_params *params, bool full)
210 if (params->w * params->h < 2) 215 if (params->w * params->h < 2)
211 return "Grid must contain at least two squares"; 216 return "Grid must contain at least two squares";
212 if (params->w < 1 || params->h < 1) 217 if (params->w < 1 || params->h < 1)
213 return "Width and height must both be at least one"; 218 return "Width and height must be at least one";
219 if (params->w > INT_MAX / params->h)
220 return "Width times height must not be unreasonably large";
214 if (params->colours < 3 || params->colours > 10) 221 if (params->colours < 3 || params->colours > 10)
215 return "Must have between 3 and 10 colours"; 222 return "Must have between 3 and 10 colours";
216 if (params->leniency < 0) 223 if (params->leniency < 0)
@@ -554,8 +561,10 @@ static char *new_game_desc(const game_params *params, random_state *rs,
554 /* 561 /*
555 * Invent a random grid. 562 * Invent a random grid.
556 */ 563 */
557 for (i = 0; i < wh; i++) 564 do {
558 scratch->grid[i] = random_upto(rs, params->colours); 565 for (i = 0; i < wh; i++)
566 scratch->grid[i] = random_upto(rs, params->colours);
567 } while (completed(w, h, scratch->grid));
559 568
560 /* 569 /*
561 * Run the solver, and count how many moves it uses. 570 * Run the solver, and count how many moves it uses.
@@ -770,7 +779,7 @@ struct game_ui {
770static game_ui *new_ui(const game_state *state) 779static game_ui *new_ui(const game_state *state)
771{ 780{
772 struct game_ui *ui = snew(struct game_ui); 781 struct game_ui *ui = snew(struct game_ui);
773 ui->cursor_visible = false; 782 ui->cursor_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
774 ui->cx = FILLX; 783 ui->cx = FILLX;
775 ui->cy = FILLY; 784 ui->cy = FILLY;
776 return ui; 785 return ui;
@@ -781,18 +790,21 @@ static void free_ui(game_ui *ui)
781 sfree(ui); 790 sfree(ui);
782} 791}
783 792
784static char *encode_ui(const game_ui *ui) 793static void game_changed_state(game_ui *ui, const game_state *oldstate,
785{ 794 const game_state *newstate)
786 return NULL;
787}
788
789static void decode_ui(game_ui *ui, const char *encoding)
790{ 795{
791} 796}
792 797
793static void game_changed_state(game_ui *ui, const game_state *oldstate, 798static const char *current_key_label(const game_ui *ui,
794 const game_state *newstate) 799 const game_state *state, int button)
795{ 800{
801 if (button == CURSOR_SELECT &&
802 state->grid[0] != state->grid[ui->cy*state->w+ui->cx])
803 return "Fill";
804 if (button == CURSOR_SELECT2 &&
805 state->soln && state->solnpos < state->soln->nmoves)
806 return "Advance";
807 return "";
796} 808}
797 809
798struct game_drawstate { 810struct game_drawstate {
@@ -818,35 +830,26 @@ static char *interpret_move(const game_state *state, game_ui *ui,
818{ 830{
819 int w = state->w, h = state->h; 831 int w = state->w, h = state->h;
820 int tx = -1, ty = -1, move = -1; 832 int tx = -1, ty = -1, move = -1;
833 char *nullret = MOVE_NO_EFFECT;
821 834
822 if (button == LEFT_BUTTON) { 835 if (button == LEFT_BUTTON) {
823 tx = FROMCOORD(x); 836 tx = FROMCOORD(x);
824 ty = FROMCOORD(y); 837 ty = FROMCOORD(y);
825 ui->cursor_visible = false; 838 if (ui->cursor_visible) {
826 } else if (button == CURSOR_LEFT && ui->cx > 0) { 839 ui->cursor_visible = false;
827 ui->cx--; 840 nullret = MOVE_UI_UPDATE;
828 ui->cursor_visible = true; 841 }
829 return UI_UPDATE; 842 } else if (IS_CURSOR_MOVE(button)) {
830 } else if (button == CURSOR_RIGHT && ui->cx+1 < w) { 843 return move_cursor(button, &ui->cx, &ui->cy, w, h, false,
831 ui->cx++; 844 &ui->cursor_visible);
832 ui->cursor_visible = true;
833 return UI_UPDATE;
834 } else if (button == CURSOR_UP && ui->cy > 0) {
835 ui->cy--;
836 ui->cursor_visible = true;
837 return UI_UPDATE;
838 } else if (button == CURSOR_DOWN && ui->cy+1 < h) {
839 ui->cy++;
840 ui->cursor_visible = true;
841 return UI_UPDATE;
842 } else if (button == CURSOR_SELECT) { 845 } else if (button == CURSOR_SELECT) {
843 tx = ui->cx; 846 tx = ui->cx;
844 ty = ui->cy; 847 ty = ui->cy;
845 } else if (button == CURSOR_SELECT2 && 848 } else if (button == CURSOR_SELECT2) {
846 state->soln && state->solnpos < state->soln->nmoves) { 849 if (state->soln && state->solnpos < state->soln->nmoves)
847 move = state->soln->moves[state->solnpos]; 850 move = state->soln->moves[state->solnpos];
848 } else { 851 } else {
849 return NULL; 852 return MOVE_UNUSED;
850 } 853 }
851 854
852 if (tx >= 0 && tx < w && ty >= 0 && ty < h && 855 if (tx >= 0 && tx < w && ty >= 0 && ty < h &&
@@ -859,7 +862,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
859 return dupstr(buf); 862 return dupstr(buf);
860 } 863 }
861 864
862 return NULL; 865 return nullret;
863} 866}
864 867
865static game_state *execute_move(const game_state *state, const char *move) 868static game_state *execute_move(const game_state *state, const char *move)
@@ -869,7 +872,8 @@ static game_state *execute_move(const game_state *state, const char *move)
869 872
870 if (move[0] == 'M' && 873 if (move[0] == 'M' &&
871 sscanf(move+1, "%d", &c) == 1 && 874 sscanf(move+1, "%d", &c) == 1 &&
872 c >= 0 && 875 c >= 0 && c < state->colours &&
876 c != state->grid[FILLY * state->w + FILLX] &&
873 !state->complete) { 877 !state->complete) {
874 int *queue = snewn(state->w * state->h, int); 878 int *queue = snewn(state->w * state->h, int);
875 ret = dup_game(state); 879 ret = dup_game(state);
@@ -920,11 +924,23 @@ static game_state *execute_move(const game_state *state, const char *move)
920 924
921 sol->moves = snewn(sol->nmoves, char); 925 sol->moves = snewn(sol->nmoves, char);
922 for (i = 0, p = move; i < sol->nmoves; i++) { 926 for (i = 0, p = move; i < sol->nmoves; i++) {
923 assert(*p); 927 if (!*p) {
928 badsolve:
929 sfree(sol->moves);
930 sfree(sol);
931 return NULL;
932 };
924 sol->moves[i] = atoi(p); 933 sol->moves[i] = atoi(p);
934 if (sol->moves[i] < 0 || sol->moves[i] >= state->colours ||
935 (i == 0 ?
936 sol->moves[i] == state->grid[FILLY * state->w + FILLX] :
937 sol->moves[i] == sol->moves[i-1]))
938 /* Solution contains a fill with an invalid colour or
939 * the current colour. */
940 goto badsolve;
925 p += strspn(p, "0123456789"); 941 p += strspn(p, "0123456789");
926 if (*p) { 942 if (*p) {
927 assert(*p == ','); 943 if (*p != ',') goto badsolve;
928 p++; 944 p++;
929 } 945 }
930 } 946 }
@@ -949,7 +965,7 @@ static game_state *execute_move(const game_state *state, const char *move)
949 */ 965 */
950 966
951static void game_compute_size(const game_params *params, int tilesize, 967static void game_compute_size(const game_params *params, int tilesize,
952 int *x, int *y) 968 const game_ui *ui, int *x, int *y)
953{ 969{
954 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 970 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
955 struct { int tilesize; } ads, *ds = &ads; 971 struct { int tilesize; } ads, *ds = &ads;
@@ -1076,31 +1092,33 @@ static void draw_tile(drawing *dr, game_drawstate *ds,
1076 colour += COL_1; 1092 colour += COL_1;
1077 draw_rect(dr, tx, ty, TILESIZE, TILESIZE, colour); 1093 draw_rect(dr, tx, ty, TILESIZE, TILESIZE, colour);
1078 1094
1079 if (tile & BORDER_L) 1095 if (SEP_WIDTH > 0) {
1080 draw_rect(dr, tx, ty, 1096 if (tile & BORDER_L)
1081 SEP_WIDTH, TILESIZE, COL_SEPARATOR); 1097 draw_rect(dr, tx, ty,
1082 if (tile & BORDER_R) 1098 SEP_WIDTH, TILESIZE, COL_SEPARATOR);
1083 draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty, 1099 if (tile & BORDER_R)
1084 SEP_WIDTH, TILESIZE, COL_SEPARATOR); 1100 draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty,
1085 if (tile & BORDER_U) 1101 SEP_WIDTH, TILESIZE, COL_SEPARATOR);
1086 draw_rect(dr, tx, ty, 1102 if (tile & BORDER_U)
1087 TILESIZE, SEP_WIDTH, COL_SEPARATOR); 1103 draw_rect(dr, tx, ty,
1088 if (tile & BORDER_D) 1104 TILESIZE, SEP_WIDTH, COL_SEPARATOR);
1089 draw_rect(dr, tx, ty + TILESIZE - SEP_WIDTH, 1105 if (tile & BORDER_D)
1090 TILESIZE, SEP_WIDTH, COL_SEPARATOR); 1106 draw_rect(dr, tx, ty + TILESIZE - SEP_WIDTH,
1091 1107 TILESIZE, SEP_WIDTH, COL_SEPARATOR);
1092 if (tile & CORNER_UL) 1108
1093 draw_rect(dr, tx, ty, 1109 if (tile & CORNER_UL)
1094 SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); 1110 draw_rect(dr, tx, ty,
1095 if (tile & CORNER_UR) 1111 SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR);
1096 draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty, 1112 if (tile & CORNER_UR)
1097 SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); 1113 draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty,
1098 if (tile & CORNER_DL) 1114 SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR);
1099 draw_rect(dr, tx, ty + TILESIZE - SEP_WIDTH, 1115 if (tile & CORNER_DL)
1100 SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); 1116 draw_rect(dr, tx, ty + TILESIZE - SEP_WIDTH,
1101 if (tile & CORNER_DR) 1117 SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR);
1102 draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty + TILESIZE - SEP_WIDTH, 1118 if (tile & CORNER_DR)
1103 SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); 1119 draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty + TILESIZE - SEP_WIDTH,
1120 SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR);
1121 }
1104 1122
1105 if (tile & CURSOR) 1123 if (tile & CURSOR)
1106 draw_rect_outline(dr, tx + CURSOR_INSET, ty + CURSOR_INSET, 1124 draw_rect_outline(dr, tx + CURSOR_INSET, ty + CURSOR_INSET,
@@ -1130,13 +1148,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1130 if (!ds->started) { 1148 if (!ds->started) {
1131 int coords[10]; 1149 int coords[10];
1132 1150
1133 draw_rect(dr, 0, 0,
1134 TILESIZE * w + 2 * BORDER,
1135 TILESIZE * h + 2 * BORDER, COL_BACKGROUND);
1136 draw_update(dr, 0, 0,
1137 TILESIZE * w + 2 * BORDER,
1138 TILESIZE * h + 2 * BORDER);
1139
1140 /* 1151 /*
1141 * Recessed area containing the whole puzzle. 1152 * Recessed area containing the whole puzzle.
1142 */ 1153 */
@@ -1326,19 +1337,6 @@ static float game_flash_length(const game_state *oldstate,
1326 return 0.0F; 1337 return 0.0F;
1327} 1338}
1328 1339
1329static bool game_timing_state(const game_state *state, game_ui *ui)
1330{
1331 return true;
1332}
1333
1334static void game_print_size(const game_params *params, float *x, float *y)
1335{
1336}
1337
1338static void game_print(drawing *dr, const game_state *state, int tilesize)
1339{
1340}
1341
1342#ifdef COMBINED 1340#ifdef COMBINED
1343#define thegame flood 1341#define thegame flood
1344#endif 1342#endif
@@ -1360,12 +1358,14 @@ const struct game thegame = {
1360 free_game, 1358 free_game,
1361 true, solve_game, 1359 true, solve_game,
1362 true, game_can_format_as_text_now, game_text_format, 1360 true, game_can_format_as_text_now, game_text_format,
1361 NULL, NULL, /* get_prefs, set_prefs */
1363 new_ui, 1362 new_ui,
1364 free_ui, 1363 free_ui,
1365 encode_ui, 1364 NULL, /* encode_ui */
1366 decode_ui, 1365 NULL, /* decode_ui */
1367 NULL, /* game_request_keys */ 1366 NULL, /* game_request_keys */
1368 game_changed_state, 1367 game_changed_state,
1368 current_key_label,
1369 interpret_move, 1369 interpret_move,
1370 execute_move, 1370 execute_move,
1371 PREFERRED_TILESIZE, game_compute_size, game_set_size, 1371 PREFERRED_TILESIZE, game_compute_size, game_set_size,
@@ -1377,8 +1377,8 @@ const struct game thegame = {
1377 game_flash_length, 1377 game_flash_length,
1378 game_get_cursor_location, 1378 game_get_cursor_location,
1379 game_status, 1379 game_status,
1380 false, false, game_print_size, game_print, 1380 false, false, NULL, NULL, /* print_size, print */
1381 true, /* wants_statusbar */ 1381 true, /* wants_statusbar */
1382 false, game_timing_state, 1382 false, NULL, /* timing_state */
1383 0, /* flags */ 1383 0, /* flags */
1384}; 1384};
diff --git a/apps/plugins/puzzles/src/fuzzpuzz.c b/apps/plugins/puzzles/src/fuzzpuzz.c
new file mode 100644
index 0000000000..3fb632ec57
--- /dev/null
+++ b/apps/plugins/puzzles/src/fuzzpuzz.c
@@ -0,0 +1,250 @@
1/*
2 * fuzzpuzz.c: Fuzzing frontend to all puzzles.
3 */
4
5/*
6 * The idea here is that this front-end supports all back-ends and can
7 * feed them save files. It then asks the back-end to draw the puzzle
8 * (through a null drawing API) and reserialises the state. This
9 * tests the deserialiser, the code for loading game descriptions, the
10 * processing of move strings, the redraw code, and the serialisation
11 * routines, but is still pretty quick.
12 *
13 * To use AFL++ to drive fuzzpuzz, you can do something like:
14 *
15 * CC=afl-cc cmake -B build-afl
16 * cmake --build build-afl --target fuzzpuzz
17 * mkdir fuzz-in && ln icons/''*.sav fuzz-in
18 * afl-fuzz -i fuzz-in -o fuzz-out -x fuzzpuzz.dict -- build-afl/fuzzpuzz
19 *
20 * Similarly with Honggfuzz:
21 *
22 * CC=hfuzz-cc cmake -B build-honggfuzz
23 * cmake --build build-honggfuzz --target fuzzpuzz
24 * mkdir fuzz-corpus && ln icons/''*.sav fuzz-corpus
25 * honggfuzz -s -i fuzz-corpus -w fuzzpuzz.dict -- build-honggfuzz/fuzzpuzz
26 *
27 * You can also use libFuzzer, though it's not really a good fit for
28 * Puzzles. The experimental forking mode seems to work OK:
29 *
30 * CC=clang cmake -B build-clang -DWITH_LIBFUZZER=Y
31 * cmake --build build-clang --target fuzzpuzz
32 * mkdir fuzz-corpus && ln icons/''*.sav fuzz-corpus
33 * build-clang/fuzzpuzz -fork=1 -ignore_crashes=1 -dict=fuzzpuzz.dict \
34 * fuzz-corpus
35 */
36
37#include <stdbool.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#ifdef __AFL_FUZZ_TESTCASE_LEN
42# include <unistd.h> /* read() is used by __AFL_FUZZ_TESTCASE_LEN. */
43#endif
44
45#include "puzzles.h"
46
47#ifdef __AFL_FUZZ_INIT
48__AFL_FUZZ_INIT();
49#endif
50
51#ifdef HAVE_HF_ITER
52extern int HF_ITER(unsigned char **, size_t *);
53#endif
54
55/* This function is expected by libFuzzer. */
56
57int LLVMFuzzerTestOneInput(unsigned char *data, size_t size);
58
59static const char *fuzz_one(bool (*readfn)(void *, void *, int), void *rctx,
60 void (*rewindfn)(void *),
61 void (*writefn)(void *, const void *, int),
62 void *wctx)
63{
64 const char *err;
65 char *gamename;
66 int i, w, h;
67 const game *ourgame = NULL;
68 static const drawing_api drapi = { NULL };
69 midend *me;
70
71 err = identify_game(&gamename, readfn, rctx);
72 if (err != NULL) return err;
73
74 for (i = 0; i < gamecount; i++)
75 if (strcmp(gamename, gamelist[i]->name) == 0)
76 ourgame = gamelist[i];
77 sfree(gamename);
78 if (ourgame == NULL)
79 return "Game not recognised";
80
81 me = midend_new(NULL, ourgame, &drapi, NULL);
82
83 rewindfn(rctx);
84 err = midend_deserialise(me, readfn, rctx);
85 if (err != NULL) {
86 midend_free(me);
87 return err;
88 }
89 w = h = INT_MAX;
90 midend_size(me, &w, &h, false, 1);
91 midend_redraw(me);
92 midend_serialise(me, writefn, wctx);
93 midend_free(me);
94 return NULL;
95}
96
97#if defined(__AFL_FUZZ_TESTCASE_LEN) || defined(HAVE_HF_ITER) || \
98 !defined(OMIT_MAIN)
99static void savefile_write(void *wctx, const void *buf, int len)
100{
101 FILE *fp = (FILE *)wctx;
102
103 fwrite(buf, 1, len, fp);
104}
105#endif
106
107struct memread {
108 const unsigned char *buf;
109 size_t pos;
110 size_t len;
111};
112
113static bool mem_read(void *wctx, void *buf, int len)
114{
115 struct memread *ctx = wctx;
116
117 if (ctx->pos + len > ctx->len) return false;
118 memcpy(buf, ctx->buf + ctx->pos, len);
119 ctx->pos += len;
120 return true;
121}
122
123static void mem_rewind(void *wctx)
124{
125 struct memread *ctx = wctx;
126
127 ctx->pos = 0;
128}
129
130static void null_write(void *wctx, const void *buf, int len)
131{
132}
133
134int LLVMFuzzerTestOneInput(unsigned char *data, size_t size) {
135 struct memread ctx;
136
137 ctx.buf = data;
138 ctx.len = size;
139 ctx.pos = 0;
140 fuzz_one(mem_read, &ctx, mem_rewind, null_write, NULL);
141 return 0;
142}
143
144#if defined(__AFL_FUZZ_TESTCASE_LEN) || defined(HAVE_HF_ITER)
145static const char *fuzz_one_mem(unsigned char *data, size_t size) {
146 struct memread ctx;
147
148 ctx.buf = data;
149 ctx.len = size;
150 ctx.pos = 0;
151 return fuzz_one(mem_read, &ctx, mem_rewind, savefile_write, stdout);
152}
153#endif
154
155/*
156 * Three different versions of main(), for standalone, AFL, and
157 * Honggfuzz modes. LibFuzzer brings its own main().
158 */
159
160#ifdef OMIT_MAIN
161/* Nothing. */
162#elif defined(__AFL_FUZZ_TESTCASE_LEN)
163/*
164 * AFL persistent mode, where we fuzz from a RAM buffer provided
165 * by AFL in a loop. This version can still be run standalone if
166 * necessary, for instance to diagnose a crash.
167 */
168int main(int argc, char **argv)
169{
170 const char *err;
171 int ret;
172
173 if (argc != 1) {
174 fprintf(stderr, "usage: %s\n", argv[0]);
175 return 1;
176 }
177#ifdef __AFL_HAVE_MANUAL_CONTROL
178 __AFL_INIT();
179#endif
180 while (__AFL_LOOP(10000)) {
181 err = fuzz_one_mem(__AFL_FUZZ_TESTCASE_BUF, __AFL_FUZZ_TESTCASE_LEN);
182 if (err != NULL) {
183 fprintf(stderr, "%s\n", err);
184 ret = 1;
185 } else
186 ret = 0;
187 }
188 return ret;
189}
190#elif defined(HAVE_HF_ITER)
191/*
192 * Honggfuzz persistent mode. Unlike AFL persistent mode, the
193 * resulting executable cannot be run outside of Honggfuzz.
194 */
195int main(int argc, char **argv)
196{
197 if (argc != 1) {
198 fprintf(stderr, "usage: %s\n", argv[0]);
199 return 1;
200 }
201 while (true) {
202 unsigned char *testcase_buf;
203 size_t testcase_len;
204 HF_ITER(&testcase_buf, &testcase_len);
205 fuzz_one_mem(testcase_buf, testcase_len);
206 }
207}
208#else
209/*
210 * Stand-alone mode: just handle a single test case on stdin.
211 */
212static bool savefile_read(void *wctx, void *buf, int len)
213{
214 FILE *fp = (FILE *)wctx;
215 int ret;
216
217 ret = fread(buf, 1, len, fp);
218 return (ret == len);
219}
220
221static void savefile_rewind(void *wctx)
222{
223 FILE *fp = (FILE *)wctx;
224
225 rewind(fp);
226}
227
228int main(int argc, char **argv)
229{
230 const char *err;
231
232 if (argc != 1) {
233 fprintf(stderr, "usage: %s\n", argv[0]);
234 return 1;
235 }
236
237 /* Might in theory use this mode under AFL. */
238#ifdef __AFL_HAVE_MANUAL_CONTROL
239 __AFL_INIT();
240#endif
241
242 err = fuzz_one(savefile_read, stdin, savefile_rewind,
243 savefile_write, stdout);
244 if (err != NULL) {
245 fprintf(stderr, "%s\n", err);
246 return 1;
247 }
248 return 0;
249}
250#endif
diff --git a/apps/plugins/puzzles/src/galaxies.R b/apps/plugins/puzzles/src/galaxies.R
deleted file mode 100644
index 957e5dad90..0000000000
--- a/apps/plugins/puzzles/src/galaxies.R
+++ /dev/null
@@ -1,28 +0,0 @@
1# -*- makefile -*-
2
3GALAXIES_EXTRA = dsf
4
5galaxies : [X] GTK COMMON galaxies GALAXIES_EXTRA galaxies-icon|no-icon
6
7galaxies : [G] WINDOWS COMMON galaxies GALAXIES_EXTRA galaxies.res|noicon.res
8
9galaxiessolver : [U] galaxies[STANDALONE_SOLVER] GALAXIES_EXTRA STANDALONE m.lib
10galaxiessolver : [C] galaxies[STANDALONE_SOLVER] GALAXIES_EXTRA STANDALONE
11
12galaxiespicture : [U] galaxies[STANDALONE_PICTURE_GENERATOR] GALAXIES_EXTRA STANDALONE
13 + m.lib
14galaxiespicture : [C] galaxies[STANDALONE_PICTURE_GENERATOR] GALAXIES_EXTRA STANDALONE
15
16ALL += galaxies[COMBINED] GALAXIES_EXTRA
17
18!begin am gtk
19GAMES += galaxies
20!end
21
22!begin >list.c
23 A(galaxies) \
24!end
25
26!begin >gamedesc.txt
27galaxies:galaxies.exe:Galaxies:Symmetric polyomino puzzle:Divide the grid into rotationally symmetric regions each centred on a dot.
28!end
diff --git a/apps/plugins/puzzles/src/galaxies.c b/apps/plugins/puzzles/src/galaxies.c
index 9172b90e12..8859917558 100644
--- a/apps/plugins/puzzles/src/galaxies.c
+++ b/apps/plugins/puzzles/src/galaxies.c
@@ -13,9 +13,46 @@
13 * Edges have on/off state; obviously the actual edges of the 13 * Edges have on/off state; obviously the actual edges of the
14 * board are fixed to on, and everything else starts as off. 14 * board are fixed to on, and everything else starts as off.
15 * 15 *
16 * TTD: 16 * Future solver directions:
17 * Cleverer solver 17 *
18 * Think about how to display remote groups of tiles? 18 * - Non-local version of the exclave extension? Suppose you have an
19 * exclave with multiple potential paths back home, but all of them
20 * go through the same tile somewhere in the middle of the path.
21 * Then _that_ critical square can be assigned to the home dot,
22 * even if we don't yet know the details of the path from it to
23 * either existing region.
24 *
25 * - Permit non-simply-connected puzzle instances in sub-Unreasonable
26 * mode? Even the simplest case 5x3:ubb is graded Unreasonable at
27 * present, because we have no solution technique short of
28 * recursion that can handle it.
29 *
30 * The reasoning a human uses for that puzzle is to observe that
31 * the centre left square has to connect to the centre dot, so it
32 * must have _some_ path back there. It could go round either side
33 * of the dot in the way. But _whichever_ way it goes, that rules
34 * out the left dot extending to the squares above and below it,
35 * because if it did that, that would block _both_ routes back to
36 * the centre.
37 *
38 * But the exclave-extending deduction we have at present is only
39 * capable of extending an exclave with _one_ liberty. This has
40 * two, so the only technique we have available is to try them one
41 * by one via recursion.
42 *
43 * My vague plan to fix this would be to re-run the exclave
44 * extension on a per-dot basis (probably after working out a
45 * non-local version as described above): instead of trying to find
46 * all exclaves at once, try it for one exclave at a time, or
47 * perhaps all exclaves relating to a particular home dot H. The
48 * point of this is that then you could spot pairs of squares with
49 * _two_ possible dots, one of which is H, and which are opposite
50 * to each other with respect to their other dot D (such as the
51 * squares above/below the left dot in this example). And then you
52 * merge those into one vertex of the connectivity graph, on the
53 * grounds that they're either both H or both D - and _then_ you
54 * have an exclave with only one path back home, and can make
55 * progress.
19 * 56 *
20 * Bugs: 57 * Bugs:
21 * 58 *
@@ -42,15 +79,22 @@
42#include <string.h> 79#include <string.h>
43#include <assert.h> 80#include <assert.h>
44#include <ctype.h> 81#include <ctype.h>
45#include <math.h> 82#include <limits.h>
83#ifdef NO_TGMATH_H
84# include <math.h>
85#else
86# include <tgmath.h>
87#endif
46 88
47#include "puzzles.h" 89#include "puzzles.h"
48 90
49#ifdef DEBUGGING 91#ifdef DEBUGGING
50#define solvep debug 92#define solvep debug
51#else 93#elif defined STANDALONE_SOLVER
52static bool solver_show_working; 94static bool solver_show_working;
53#define solvep(x) do { if (solver_show_working) { printf x; } } while(0) 95#define solvep(x) do { if (solver_show_working) { printf x; } } while(0)
96#else
97#define solvep(x) ((void)0)
54#endif 98#endif
55 99
56#ifdef STANDALONE_PICTURE_GENERATOR 100#ifdef STANDALONE_PICTURE_GENERATOR
@@ -148,13 +192,15 @@ struct game_state {
148 or -1 if stale. */ 192 or -1 if stale. */
149}; 193};
150 194
151static bool check_complete(const game_state *state, int *dsf, int *colours); 195static bool check_complete(const game_state *state, DSF *dsf, int *colours);
196static int solver_state_inner(game_state *state, int maxdiff, int depth);
152static int solver_state(game_state *state, int maxdiff); 197static int solver_state(game_state *state, int maxdiff);
153static int solver_obvious(game_state *state); 198static int solver_obvious(game_state *state);
154static int solver_obvious_dot(game_state *state, space *dot); 199static int solver_obvious_dot(game_state *state, space *dot);
155static space *space_opposite_dot(const game_state *state, const space *sp, 200static space *space_opposite_dot(const game_state *state, const space *sp,
156 const space *dot); 201 const space *dot);
157static space *tile_opposite(const game_state *state, const space *sp); 202static space *tile_opposite(const game_state *state, const space *sp);
203static game_state *execute_move(const game_state *state, const char *move);
158 204
159/* ---------------------------------------------------------- 205/* ----------------------------------------------------------
160 * Game parameters and presets 206 * Game parameters and presets
@@ -168,7 +214,9 @@ static const game_params galaxies_presets[] = {
168 { 7, 7, DIFF_NORMAL }, 214 { 7, 7, DIFF_NORMAL },
169 { 7, 7, DIFF_UNREASONABLE }, 215 { 7, 7, DIFF_UNREASONABLE },
170 { 10, 10, DIFF_NORMAL }, 216 { 10, 10, DIFF_NORMAL },
217 { 10, 10, DIFF_UNREASONABLE },
171 { 15, 15, DIFF_NORMAL }, 218 { 15, 15, DIFF_NORMAL },
219 { 15, 15, DIFF_UNREASONABLE },
172}; 220};
173 221
174static bool game_fetch_preset(int i, char **name, game_params **params) 222static bool game_fetch_preset(int i, char **name, game_params **params)
@@ -281,6 +329,10 @@ static const char *validate_params(const game_params *params, bool full)
281{ 329{
282 if (params->w < 3 || params->h < 3) 330 if (params->w < 3 || params->h < 3)
283 return "Width and height must both be at least 3"; 331 return "Width and height must both be at least 3";
332 if (params->w > INT_MAX / 2 || params->h > INT_MAX / 2 ||
333 params->w > (INT_MAX - params->w*2 - params->h*2 - 1) / 4 / params->h)
334 return "Width times height must not be unreasonably large";
335
284 /* 336 /*
285 * This shouldn't be able to happen at all, since decode_params 337 * This shouldn't be able to happen at all, since decode_params
286 * and custom_params will never generate anything that isn't 338 * and custom_params will never generate anything that isn't
@@ -352,6 +404,8 @@ static bool ok_to_add_assoc_with_opposite_internal(
352 int *colors; 404 int *colors;
353 bool toret; 405 bool toret;
354 406
407 if (tile->type != s_tile)
408 return false;
355 if (tile->flags & F_DOT) 409 if (tile->flags & F_DOT)
356 return false; 410 return false;
357 if (opposite == NULL) 411 if (opposite == NULL)
@@ -372,20 +426,21 @@ static bool ok_to_add_assoc_with_opposite_internal(
372 return toret; 426 return toret;
373} 427}
374 428
429#ifndef EDITOR
375static bool ok_to_add_assoc_with_opposite( 430static bool ok_to_add_assoc_with_opposite(
376 const game_state *state, space *tile, space *dot) 431 const game_state *state, space *tile, space *dot)
377{ 432{
378 space *opposite = space_opposite_dot(state, tile, dot); 433 space *opposite = space_opposite_dot(state, tile, dot);
379 return ok_to_add_assoc_with_opposite_internal(state, tile, opposite); 434 return ok_to_add_assoc_with_opposite_internal(state, tile, opposite);
380} 435}
436#endif
381 437
382static void add_assoc_with_opposite(game_state *state, space *tile, space *dot) { 438static void add_assoc_with_opposite(game_state *state, space *tile, space *dot) {
383 space *opposite = space_opposite_dot(state, tile, dot); 439 space *opposite = space_opposite_dot(state, tile, dot);
384 440
385 if(opposite) 441 if(opposite && ok_to_add_assoc_with_opposite_internal(
442 state, tile, opposite))
386 { 443 {
387 assert(ok_to_add_assoc_with_opposite_internal(state, tile, opposite));
388
389 remove_assoc_with_opposite(state, tile); 444 remove_assoc_with_opposite(state, tile);
390 add_assoc(state, tile, dot); 445 add_assoc(state, tile, dot);
391 remove_assoc_with_opposite(state, opposite); 446 remove_assoc_with_opposite(state, opposite);
@@ -393,12 +448,14 @@ static void add_assoc_with_opposite(game_state *state, space *tile, space *dot)
393 } 448 }
394} 449}
395 450
451#ifndef EDITOR
396static space *sp2dot(const game_state *state, int x, int y) 452static space *sp2dot(const game_state *state, int x, int y)
397{ 453{
398 space *sp = &SPACE(state, x, y); 454 space *sp = &SPACE(state, x, y);
399 if (!(sp->flags & F_TILE_ASSOC)) return NULL; 455 if (!(sp->flags & F_TILE_ASSOC)) return NULL;
400 return &SPACE(state, sp->dotx, sp->doty); 456 return &SPACE(state, sp->dotx, sp->doty);
401} 457}
458#endif
402 459
403#define IS_VERTICAL_EDGE(x) ((x % 2) == 0) 460#define IS_VERTICAL_EDGE(x) ((x % 2) == 0)
404 461
@@ -407,8 +464,24 @@ static bool game_can_format_as_text_now(const game_params *params)
407 return true; 464 return true;
408} 465}
409 466
467static char *encode_game(const game_state *state);
468
410static char *game_text_format(const game_state *state) 469static char *game_text_format(const game_state *state)
411{ 470{
471#ifdef EDITOR
472 game_params par;
473 char *params, *desc, *ret;
474 par.w = state->w;
475 par.h = state->h;
476 par.diff = DIFF_MAX; /* shouldn't be used */
477 params = encode_params(&par, false);
478 desc = encode_game(state);
479 ret = snewn(strlen(params) + strlen(desc) + 2, char);
480 sprintf(ret, "%s:%s", params, desc);
481 sfree(params);
482 sfree(desc);
483 return ret;
484#else
412 int maxlen = (state->sx+1)*state->sy, x, y; 485 int maxlen = (state->sx+1)*state->sy, x, y;
413 char *ret, *p; 486 char *ret, *p;
414 space *sp; 487 space *sp;
@@ -462,6 +535,7 @@ static char *game_text_format(const game_state *state)
462 *p = '\0'; 535 *p = '\0';
463 536
464 return ret; 537 return ret;
538#endif
465} 539}
466 540
467static void dbg_state(const game_state *state) 541static void dbg_state(const game_state *state)
@@ -684,7 +758,7 @@ static void tiles_from_edge(game_state *state, space *sp, space **ts)
684/* Returns a move string for use by 'solve', including the initial 758/* Returns a move string for use by 'solve', including the initial
685 * 'S' if issolve is true. */ 759 * 'S' if issolve is true. */
686static char *diff_game(const game_state *src, const game_state *dest, 760static char *diff_game(const game_state *src, const game_state *dest,
687 bool issolve) 761 bool issolve, int set_cdiff)
688{ 762{
689 int movelen = 0, movesize = 256, x, y, len; 763 int movelen = 0, movesize = 256, x, y, len;
690 char *move = snewn(movesize, char), buf[80]; 764 char *move = snewn(movesize, char), buf[80];
@@ -698,6 +772,26 @@ static char *diff_game(const game_state *src, const game_state *dest,
698 move[movelen++] = 'S'; 772 move[movelen++] = 'S';
699 sep = ";"; 773 sep = ";";
700 } 774 }
775#ifdef EDITOR
776 if (set_cdiff >= 0) {
777 switch (set_cdiff) {
778 case DIFF_IMPOSSIBLE:
779 movelen += sprintf(move+movelen, "%sII", sep);
780 break;
781 case DIFF_AMBIGUOUS:
782 movelen += sprintf(move+movelen, "%sIA", sep);
783 break;
784 case DIFF_UNFINISHED:
785 movelen += sprintf(move+movelen, "%sIU", sep);
786 break;
787 default:
788 movelen += sprintf(move+movelen, "%si%c",
789 sep, galaxies_diffchars[set_cdiff]);
790 break;
791 }
792 sep = ";";
793 }
794#endif
701 move[movelen] = '\0'; 795 move[movelen] = '\0';
702 for (x = 0; x < src->sx; x++) { 796 for (x = 0; x < src->sx; x++) {
703 for (y = 0; y < src->sy; y++) { 797 for (y = 0; y < src->sy; y++) {
@@ -747,7 +841,8 @@ static char *diff_game(const game_state *src, const game_state *dest,
747 841
748/* Returns true if a dot here would not be too close to any other dots 842/* Returns true if a dot here would not be too close to any other dots
749 * (and would avoid other game furniture). */ 843 * (and would avoid other game furniture). */
750static bool dot_is_possible(game_state *state, space *sp, bool allow_assoc) 844static bool dot_is_possible(const game_state *state, space *sp,
845 bool allow_assoc)
751{ 846{
752 int bx = 0, by = 0, dx, dy; 847 int bx = 0, by = 0, dx, dy;
753 space *adj; 848 space *adj;
@@ -921,7 +1016,7 @@ static void free_game(game_state *state)
921 * an edit mode. 1016 * an edit mode.
922 */ 1017 */
923 1018
924static char *encode_game(game_state *state) 1019static char *encode_game(const game_state *state)
925{ 1020{
926 char *desc, *p; 1021 char *desc, *p;
927 int run, x, y, area; 1022 int run, x, y, area;
@@ -1229,10 +1324,7 @@ static bool generate_try_block(game_state *state, random_state *rs,
1229} 1324}
1230 1325
1231#ifdef STANDALONE_SOLVER 1326#ifdef STANDALONE_SOLVER
1232int maxtries; 1327static bool one_try; /* override for soak testing */
1233#define MAXTRIES maxtries
1234#else
1235#define MAXTRIES 50
1236#endif 1328#endif
1237 1329
1238#define GP_DOTS 1 1330#define GP_DOTS 1
@@ -1242,6 +1334,8 @@ static void generate_pass(game_state *state, random_state *rs, int *scratch,
1242{ 1334{
1243 int sz = state->sx*state->sy, nspc, i, ret; 1335 int sz = state->sx*state->sy, nspc, i, ret;
1244 1336
1337 /* Random list of squares to try and process, one-by-one. */
1338 for (i = 0; i < sz; i++) scratch[i] = i;
1245 shuffle(scratch, sz, sizeof(int), rs); 1339 shuffle(scratch, sz, sizeof(int), rs);
1246 1340
1247 /* This bug took me a, er, little while to track down. On PalmOS, 1341 /* This bug took me a, er, little while to track down. On PalmOS,
@@ -1297,30 +1391,94 @@ static void generate_pass(game_state *state, random_state *rs, int *scratch,
1297 dbg_state(state); 1391 dbg_state(state);
1298} 1392}
1299 1393
1394/*
1395 * We try several times to generate a grid at all, before even feeding
1396 * it to the solver. Then we pick whichever of the resulting grids was
1397 * the most 'wiggly', as measured by the number of inward corners in
1398 * the shape of any region.
1399 *
1400 * Rationale: wiggly shapes are what make this puzzle fun, and it's
1401 * disappointing to be served a game whose entire solution is a
1402 * collection of rectangles. But we also don't want to introduce a
1403 * _hard requirement_ of wiggliness, because a player who knew that
1404 * was there would be able to use it as an extra clue. This way, we
1405 * just probabilistically skew in favour of wiggliness.
1406 */
1407#define GENERATE_TRIES 10
1408
1409static bool is_wiggle(const game_state *state, int x, int y, int dx, int dy)
1410{
1411 int x1 = x+2*dx, y1 = y+2*dy;
1412 int x2 = x-2*dy, y2 = y+2*dx;
1413 space *t, *t1, *t2;
1414
1415 if (!INGRID(state, x1, y1) || !INGRID(state, x2, y2))
1416 return false;
1417
1418 t = &SPACE(state, x, y);
1419 t1 = &SPACE(state, x1, y1);
1420 t2 = &SPACE(state, x2, y2);
1421 return ((t1->dotx == t2->dotx && t1->doty == t2->doty) &&
1422 !(t1->dotx == t->dotx && t1->doty == t->doty));
1423}
1424
1425static int measure_wiggliness(const game_state *state, int *scratch)
1426{
1427 int sz = state->sx*state->sy;
1428 int x, y, nwiggles = 0;
1429 memset(scratch, 0, sz);
1430
1431 for (y = 1; y < state->sy; y += 2) {
1432 for (x = 1; x < state->sx; x += 2) {
1433 if (y+2 < state->sy) {
1434 nwiggles += is_wiggle(state, x, y, 0, +1);
1435 nwiggles += is_wiggle(state, x, y, 0, -1);
1436 nwiggles += is_wiggle(state, x, y, +1, 0);
1437 nwiggles += is_wiggle(state, x, y, -1, 0);
1438 }
1439 }
1440 }
1441
1442 return nwiggles;
1443}
1444
1300static char *new_game_desc(const game_params *params, random_state *rs, 1445static char *new_game_desc(const game_params *params, random_state *rs,
1301 char **aux, bool interactive) 1446 char **aux, bool interactive)
1302{ 1447{
1303 game_state *state = blank_game(params->w, params->h), *copy; 1448 game_state *state = blank_game(params->w, params->h), *copy;
1304 char *desc; 1449 char *desc;
1305 int *scratch, sz = state->sx*state->sy, i; 1450 int *scratch, sz = state->sx*state->sy, i;
1306 int diff, ntries = 0; 1451 int diff, best_wiggliness;
1307 bool cc; 1452 bool cc;
1308 1453
1309 /* Random list of squares to try and process, one-by-one. */
1310 scratch = snewn(sz, int); 1454 scratch = snewn(sz, int);
1311 for (i = 0; i < sz; i++) scratch[i] = i;
1312 1455
1313generate: 1456generate:
1314 clear_game(state, true); 1457 best_wiggliness = -1;
1315 ntries++; 1458 copy = NULL;
1316 1459 for (i = 0; i < GENERATE_TRIES; i++) {
1317 /* generate_pass(state, rs, scratch, 10, GP_DOTS); */ 1460 int this_wiggliness;
1318 /* generate_pass(state, rs, scratch, 100, 0); */ 1461
1319 generate_pass(state, rs, scratch, 100, GP_DOTS); 1462 do {
1320 1463 clear_game(state, true);
1321 game_update_dots(state); 1464 generate_pass(state, rs, scratch, 100, GP_DOTS);
1322 1465 game_update_dots(state);
1323 if (state->ndots == 1) goto generate; 1466 } while (state->ndots == 1);
1467
1468 this_wiggliness = measure_wiggliness(state, scratch);
1469 debug(("Grid gen #%d: wiggliness=%d", i, this_wiggliness));
1470 if (this_wiggliness > best_wiggliness) {
1471 best_wiggliness = this_wiggliness;
1472 if (copy)
1473 free_game(copy);
1474 copy = dup_game(state);
1475 debug((" new best"));
1476 }
1477 debug(("\n"));
1478 }
1479 assert(copy);
1480 free_game(state);
1481 state = copy;
1324 1482
1325#ifdef DEBUGGING 1483#ifdef DEBUGGING
1326 { 1484 {
@@ -1345,12 +1503,17 @@ generate:
1345 assert(diff != DIFF_IMPOSSIBLE); 1503 assert(diff != DIFF_IMPOSSIBLE);
1346 if (diff != params->diff) { 1504 if (diff != params->diff) {
1347 /* 1505 /*
1348 * We'll grudgingly accept a too-easy puzzle, but we must 1506 * If the puzzle was insoluble at this difficulty level (i.e.
1349 * _not_ permit a too-hard one (one which the solver 1507 * too hard), _or_ soluble at a lower level (too easy), go
1350 * couldn't handle at all). 1508 * round again.
1509 *
1510 * An exception is in soak-testing mode, where we return the
1511 * first puzzle we got regardless.
1351 */ 1512 */
1352 if (diff > params->diff || 1513#ifdef STANDALONE_SOLVER
1353 ntries < MAXTRIES) goto generate; 1514 if (!one_try)
1515#endif
1516 goto generate;
1354 } 1517 }
1355 1518
1356#ifdef STANDALONE_PICTURE_GENERATOR 1519#ifdef STANDALONE_PICTURE_GENERATOR
@@ -1527,6 +1690,10 @@ generate:
1527 dbg_state(state); 1690 dbg_state(state);
1528#endif 1691#endif
1529 1692
1693 game_state *blank = blank_game(params->w, params->h);
1694 *aux = diff_game(blank, state, true, -1);
1695 free_game(blank);
1696
1530 free_game(state); 1697 free_game(state);
1531 sfree(scratch); 1698 sfree(scratch);
1532 1699
@@ -1623,13 +1790,17 @@ static game_state *new_game(midend *me, const game_params *params,
1623 * Solver and all its little wizards. 1790 * Solver and all its little wizards.
1624 */ 1791 */
1625 1792
1793#if defined DEBUGGING || defined STANDALONE_SOLVER
1626static int solver_recurse_depth; 1794static int solver_recurse_depth;
1795#define STATIC_RECURSION_DEPTH
1796#endif
1627 1797
1628typedef struct solver_ctx { 1798typedef struct solver_ctx {
1629 game_state *state; 1799 game_state *state;
1630 int sz; /* state->sx * state->sy */ 1800 int sz; /* state->sx * state->sy */
1631 space **scratch; /* size sz */ 1801 space **scratch; /* size sz */
1632 1802 DSF *dsf; /* size sz */
1803 int *iscratch; /* size sz */
1633} solver_ctx; 1804} solver_ctx;
1634 1805
1635static solver_ctx *new_solver(game_state *state) 1806static solver_ctx *new_solver(game_state *state)
@@ -1638,12 +1809,16 @@ static solver_ctx *new_solver(game_state *state)
1638 sctx->state = state; 1809 sctx->state = state;
1639 sctx->sz = state->sx*state->sy; 1810 sctx->sz = state->sx*state->sy;
1640 sctx->scratch = snewn(sctx->sz, space *); 1811 sctx->scratch = snewn(sctx->sz, space *);
1812 sctx->dsf = dsf_new(sctx->sz);
1813 sctx->iscratch = snewn(sctx->sz, int);
1641 return sctx; 1814 return sctx;
1642} 1815}
1643 1816
1644static void free_solver(solver_ctx *sctx) 1817static void free_solver(solver_ctx *sctx)
1645{ 1818{
1646 sfree(sctx->scratch); 1819 sfree(sctx->scratch);
1820 dsf_free(sctx->dsf);
1821 sfree(sctx->iscratch);
1647 sfree(sctx); 1822 sfree(sctx);
1648} 1823}
1649 1824
@@ -1804,7 +1979,7 @@ static int solver_lines_opposite_cb(game_state *state, space *edge, void *ctx)
1804 if (!(edge_opp->flags & F_EDGE_SET)) { 1979 if (!(edge_opp->flags & F_EDGE_SET)) {
1805 solvep(("%*sSetting edge %d,%d as opposite %d,%d\n", 1980 solvep(("%*sSetting edge %d,%d as opposite %d,%d\n",
1806 solver_recurse_depth*4, "", 1981 solver_recurse_depth*4, "",
1807 tile_opp->x-dx, tile_opp->y-dy, edge->x, edge->y)); 1982 tile_opp->x+dx, tile_opp->y+dy, edge->x, edge->y));
1808 edge_opp->flags |= F_EDGE_SET; 1983 edge_opp->flags |= F_EDGE_SET;
1809 didsth = 1; 1984 didsth = 1;
1810 } 1985 }
@@ -2097,6 +2272,177 @@ static int solver_expand_dots(game_state *state, solver_ctx *sctx)
2097 return foreach_tile(state, solver_expand_postcb, IMPOSSIBLE_QUITS, sctx); 2272 return foreach_tile(state, solver_expand_postcb, IMPOSSIBLE_QUITS, sctx);
2098} 2273}
2099 2274
2275static int solver_extend_exclaves(game_state *state, solver_ctx *sctx)
2276{
2277 int x, y, done_something = 0;
2278
2279 /*
2280 * Make a dsf by unifying any two adjacent tiles associated with
2281 * the same dot. This will identify separate connected components
2282 * of the tiles belonging to a given dot. Any such component that
2283 * doesn't contain its own dot is an 'exclave', and will need some
2284 * kind of path of tiles to connect it back to the dot.
2285 */
2286 dsf_reinit(sctx->dsf);
2287 for (x = 1; x < state->sx; x += 2) {
2288 for (y = 1; y < state->sy; y += 2) {
2289 int dotx, doty;
2290 space *tile, *othertile;
2291
2292 tile = &SPACE(state, x, y);
2293 if (!(tile->flags & F_TILE_ASSOC))
2294 continue; /* not associated with any dot */
2295 dotx = tile->dotx;
2296 doty = tile->doty;
2297
2298 if (INGRID(state, x+2, y)) {
2299 othertile = &SPACE(state, x+2, y);
2300 if ((othertile->flags & F_TILE_ASSOC) &&
2301 othertile->dotx == dotx && othertile->doty == doty)
2302 dsf_merge(sctx->dsf, y*state->sx+x, y*state->sx+(x+2));
2303 }
2304
2305 if (INGRID(state, x, y+2)) {
2306 othertile = &SPACE(state, x, y+2);
2307 if ((othertile->flags & F_TILE_ASSOC) &&
2308 othertile->dotx == dotx && othertile->doty == doty)
2309 dsf_merge(sctx->dsf, y*state->sx+x, (y+2)*state->sx+x);
2310 }
2311 }
2312 }
2313
2314 /*
2315 * Go through the grid again, and count the 'liberties' of each
2316 * connected component, in the Go sense, i.e. the number of
2317 * currently unassociated squares adjacent to the component. The
2318 * idea is that if an exclave has just one liberty, then that
2319 * square _must_ extend the exclave, or else it will be completely
2320 * cut off from connecting back to its home dot.
2321 *
2322 * We need to count each adjacent square just once, even if it
2323 * borders the component on multiple edges. So we'll go through
2324 * each unassociated square, check all four of its neighbours, and
2325 * de-duplicate them.
2326 *
2327 * We'll store the count of liberties in the entry of iscratch
2328 * corresponding to the square centre (i.e. with odd coordinates).
2329 * Every time we find a liberty, we store its index in the square
2330 * to the left of that, so that when a component has exactly one
2331 * liberty we can remember what it was.
2332 *
2333 * Square centres that are not the canonical dsf element of a
2334 * connected component will get their liberty count set to -1,
2335 * which will allow us to identify them in the later loop (after
2336 * we start making changes and need to spot that an associated
2337 * square _now_ was not associated when the dsf was built).
2338 */
2339
2340 /* Initialise iscratch */
2341 for (x = 1; x < state->sx; x += 2) {
2342 for (y = 1; y < state->sy; y += 2) {
2343 int index = y * state->sx + x;
2344 if (!(SPACE(state, x, y).flags & F_TILE_ASSOC) ||
2345 dsf_canonify(sctx->dsf, index) != index) {
2346 sctx->iscratch[index] = -1; /* mark as not a component */
2347 } else {
2348 sctx->iscratch[index] = 0; /* zero liberty count */
2349 sctx->iscratch[index-1] = 0; /* initialise neighbour id */
2350 }
2351 }
2352 }
2353
2354 /* Find each unassociated square and see what it's a liberty of */
2355 for (x = 1; x < state->sx; x += 2) {
2356 for (y = 1; y < state->sy; y += 2) {
2357 int dx, dy, ni[4], nn, i;
2358
2359 if ((SPACE(state, x, y).flags & F_TILE_ASSOC))
2360 continue; /* not an unassociated square */
2361
2362 /* Find distinct indices of adjacent components */
2363 nn = 0;
2364 for (dx = -1; dx <= 1; dx++) {
2365 for (dy = -1; dy <= 1; dy++) {
2366 if (dx != 0 && dy != 0) continue;
2367 if (dx == 0 && dy == 0) continue;
2368
2369 if (INGRID(state, x+2*dx, y+2*dy) &&
2370 (SPACE(state, x+2*dx, y+2*dy).flags & F_TILE_ASSOC)) {
2371 /* Find id of the component adjacent to x,y */
2372 int nindex = (y+2*dy) * state->sx + (x+2*dx);
2373 nindex = dsf_canonify(sctx->dsf, nindex);
2374
2375 /* See if we've seen it before in another direction */
2376 for (i = 0; i < nn; i++)
2377 if (ni[i] == nindex)
2378 break;
2379 if (i == nn) {
2380 /* No, it's new. Mark x,y as a liberty of it */
2381 sctx->iscratch[nindex]++;
2382 assert(nindex > 0);
2383 sctx->iscratch[nindex-1] = y * state->sx + x;
2384
2385 /* And record this component as having been seen */
2386 ni[nn++] = nindex;
2387 }
2388 }
2389 }
2390 }
2391 }
2392 }
2393
2394 /*
2395 * Now we have all the data we need to find exclaves with exactly
2396 * one liberty. In each case, associate the unique liberty square
2397 * with the same dot.
2398 */
2399 for (x = 1; x < state->sx; x += 2) {
2400 for (y = 1; y < state->sy; y += 2) {
2401 int index, dotx, doty, ex, ey, added;
2402 space *tile;
2403
2404 index = y*state->sx+x;
2405 if (sctx->iscratch[index] == -1)
2406 continue; /* wasn't canonical when dsf was built */
2407
2408 tile = &SPACE(state, x, y);
2409 if (!(tile->flags & F_TILE_ASSOC))
2410 continue; /* not associated with any dot */
2411 dotx = tile->dotx;
2412 doty = tile->doty;
2413
2414 if (index == dsf_canonify(
2415 sctx->dsf, (doty | 1) * state->sx + (dotx | 1)))
2416 continue; /* not an exclave - contains its own dot */
2417
2418 if (sctx->iscratch[index] == 0) {
2419 solvep(("%*sExclave at %d,%d has no liberties!\n",
2420 solver_recurse_depth*4, "", x, y));
2421 return -1;
2422 }
2423
2424 if (sctx->iscratch[index] != 1)
2425 continue; /* more than one liberty, can't be sure which */
2426
2427 assert(sctx->iscratch[index-1] != 0);
2428 ex = sctx->iscratch[index-1] % state->sx;
2429 ey = sctx->iscratch[index-1] / state->sx;
2430 tile = &SPACE(state, ex, ey);
2431 if (tile->flags & F_TILE_ASSOC)
2432 continue; /* already done by earlier iteration of this loop */
2433
2434 added = solver_add_assoc(state, tile, dotx, doty,
2435 "to connect exclave");
2436 if (added < 0)
2437 return -1;
2438 if (added > 0)
2439 done_something = 1;
2440 }
2441 }
2442
2443 return done_something;
2444}
2445
2100struct recurse_ctx { 2446struct recurse_ctx {
2101 space *best; 2447 space *best;
2102 int bestn; 2448 int bestn;
@@ -2124,14 +2470,14 @@ static int solver_recurse_cb(game_state *state, space *tile, void *ctx)
2124 2470
2125#define MAXRECURSE 5 2471#define MAXRECURSE 5
2126 2472
2127static int solver_recurse(game_state *state, int maxdiff) 2473static int solver_recurse(game_state *state, int maxdiff, int depth)
2128{ 2474{
2129 int diff = DIFF_IMPOSSIBLE, ret, n, gsz = state->sx * state->sy; 2475 int diff = DIFF_IMPOSSIBLE, ret, n, gsz = state->sx * state->sy;
2130 space *ingrid, *outgrid = NULL, *bestopp; 2476 space *ingrid, *outgrid = NULL, *bestopp;
2131 struct recurse_ctx rctx; 2477 struct recurse_ctx rctx;
2132 2478
2133 if (solver_recurse_depth >= MAXRECURSE) { 2479 if (depth >= MAXRECURSE) {
2134 solvep(("Limiting recursion to %d, returning.", MAXRECURSE)); 2480 solvep(("Limiting recursion to %d, returning.\n", MAXRECURSE));
2135 return DIFF_UNFINISHED; 2481 return DIFF_UNFINISHED;
2136 } 2482 }
2137 2483
@@ -2149,10 +2495,6 @@ static int solver_recurse(game_state *state, int maxdiff)
2149 solver_recurse_depth*4, "", 2495 solver_recurse_depth*4, "",
2150 rctx.best->x, rctx.best->y, rctx.bestn)); 2496 rctx.best->x, rctx.best->y, rctx.bestn));
2151 2497
2152#ifdef STANDALONE_SOLVER
2153 solver_recurse_depth++;
2154#endif
2155
2156 ingrid = snewn(gsz, space); 2498 ingrid = snewn(gsz, space);
2157 memcpy(ingrid, state->grid, gsz * sizeof(space)); 2499 memcpy(ingrid, state->grid, gsz * sizeof(space));
2158 2500
@@ -2166,7 +2508,11 @@ static int solver_recurse(game_state *state, int maxdiff)
2166 state->dots[n]->x, state->dots[n]->y, 2508 state->dots[n]->x, state->dots[n]->y,
2167 "Attempting for recursion"); 2509 "Attempting for recursion");
2168 2510
2169 ret = solver_state(state, maxdiff); 2511 ret = solver_state_inner(state, maxdiff, depth + 1);
2512
2513#ifdef STATIC_RECURSION_DEPTH
2514 solver_recurse_depth = depth; /* restore after recursion returns */
2515#endif
2170 2516
2171 if (diff == DIFF_IMPOSSIBLE && ret != DIFF_IMPOSSIBLE) { 2517 if (diff == DIFF_IMPOSSIBLE && ret != DIFF_IMPOSSIBLE) {
2172 /* we found our first solved grid; copy it away. */ 2518 /* we found our first solved grid; copy it away. */
@@ -2198,10 +2544,6 @@ static int solver_recurse(game_state *state, int maxdiff)
2198 break; 2544 break;
2199 } 2545 }
2200 2546
2201#ifdef STANDALONE_SOLVER
2202 solver_recurse_depth--;
2203#endif
2204
2205 if (outgrid) { 2547 if (outgrid) {
2206 /* we found (at least one) soln; copy it back to state */ 2548 /* we found (at least one) soln; copy it back to state */
2207 memcpy(state->grid, outgrid, gsz * sizeof(space)); 2549 memcpy(state->grid, outgrid, gsz * sizeof(space));
@@ -2211,7 +2553,7 @@ static int solver_recurse(game_state *state, int maxdiff)
2211 return diff; 2553 return diff;
2212} 2554}
2213 2555
2214static int solver_state(game_state *state, int maxdiff) 2556static int solver_state_inner(game_state *state, int maxdiff, int depth)
2215{ 2557{
2216 solver_ctx *sctx = new_solver(state); 2558 solver_ctx *sctx = new_solver(state);
2217 int ret, diff = DIFF_NORMAL; 2559 int ret, diff = DIFF_NORMAL;
@@ -2223,6 +2565,10 @@ static int solver_state(game_state *state, int maxdiff)
2223 picture = NULL; 2565 picture = NULL;
2224#endif 2566#endif
2225 2567
2568#ifdef STATIC_RECURSION_DEPTH
2569 solver_recurse_depth = depth;
2570#endif
2571
2226 ret = solver_obvious(state); 2572 ret = solver_obvious(state);
2227 if (ret < 0) { 2573 if (ret < 0) {
2228 diff = DIFF_IMPOSSIBLE; 2574 diff = DIFF_IMPOSSIBLE;
@@ -2247,6 +2593,9 @@ cont:
2247 ret = solver_expand_dots(state, sctx); 2593 ret = solver_expand_dots(state, sctx);
2248 CHECKRET(DIFF_NORMAL); 2594 CHECKRET(DIFF_NORMAL);
2249 2595
2596 ret = solver_extend_exclaves(state, sctx);
2597 CHECKRET(DIFF_NORMAL);
2598
2250 if (maxdiff <= DIFF_NORMAL) 2599 if (maxdiff <= DIFF_NORMAL)
2251 break; 2600 break;
2252 2601
@@ -2259,7 +2608,7 @@ cont:
2259 if (check_complete(state, NULL, NULL)) goto got_result; 2608 if (check_complete(state, NULL, NULL)) goto got_result;
2260 2609
2261 diff = (maxdiff >= DIFF_UNREASONABLE) ? 2610 diff = (maxdiff >= DIFF_UNREASONABLE) ?
2262 solver_recurse(state, maxdiff) : DIFF_UNFINISHED; 2611 solver_recurse(state, maxdiff, depth) : DIFF_UNFINISHED;
2263 2612
2264got_result: 2613got_result:
2265 free_solver(sctx); 2614 free_solver(sctx);
@@ -2275,6 +2624,11 @@ got_result:
2275 return diff; 2624 return diff;
2276} 2625}
2277 2626
2627static int solver_state(game_state *state, int maxdiff)
2628{
2629 return solver_state_inner(state, maxdiff, 0);
2630}
2631
2278#ifndef EDITOR 2632#ifndef EDITOR
2279static char *solve_game(const game_state *state, const game_state *currstate, 2633static char *solve_game(const game_state *state, const game_state *currstate,
2280 const char *aux, const char **error) 2634 const char *aux, const char **error)
@@ -2284,21 +2638,26 @@ static char *solve_game(const game_state *state, const game_state *currstate,
2284 int i; 2638 int i;
2285 int diff; 2639 int diff;
2286 2640
2287 tosolve = dup_game(currstate); 2641 if (aux) {
2288 diff = solver_state(tosolve, DIFF_UNREASONABLE); 2642 tosolve = execute_move(state, aux);
2289 if (diff != DIFF_UNFINISHED && diff != DIFF_IMPOSSIBLE) {
2290 debug(("solve_game solved with current state.\n"));
2291 goto solved; 2643 goto solved;
2292 } 2644 } else {
2293 free_game(tosolve); 2645 tosolve = dup_game(currstate);
2646 diff = solver_state(tosolve, DIFF_UNREASONABLE);
2647 if (diff != DIFF_UNFINISHED && diff != DIFF_IMPOSSIBLE) {
2648 debug(("solve_game solved with current state.\n"));
2649 goto solved;
2650 }
2651 free_game(tosolve);
2294 2652
2295 tosolve = dup_game(state); 2653 tosolve = dup_game(state);
2296 diff = solver_state(tosolve, DIFF_UNREASONABLE); 2654 diff = solver_state(tosolve, DIFF_UNREASONABLE);
2297 if (diff != DIFF_UNFINISHED && diff != DIFF_IMPOSSIBLE) { 2655 if (diff != DIFF_UNFINISHED && diff != DIFF_IMPOSSIBLE) {
2298 debug(("solve_game solved with original state.\n")); 2656 debug(("solve_game solved with original state.\n"));
2299 goto solved; 2657 goto solved;
2658 }
2659 free_game(tosolve);
2300 } 2660 }
2301 free_game(tosolve);
2302 2661
2303 return NULL; 2662 return NULL;
2304 2663
@@ -2309,7 +2668,7 @@ solved:
2309 */ 2668 */
2310 for (i = 0; i < tosolve->sx*tosolve->sy; i++) 2669 for (i = 0; i < tosolve->sx*tosolve->sy; i++)
2311 tosolve->grid[i].flags &= ~F_TILE_ASSOC; 2670 tosolve->grid[i].flags &= ~F_TILE_ASSOC;
2312 ret = diff_game(currstate, tosolve, true); 2671 ret = diff_game(currstate, tosolve, true, -1);
2313 free_game(tosolve); 2672 free_game(tosolve);
2314 return ret; 2673 return ret;
2315} 2674}
@@ -2333,7 +2692,7 @@ static game_ui *new_ui(const game_state *state)
2333 game_ui *ui = snew(game_ui); 2692 game_ui *ui = snew(game_ui);
2334 ui->dragging = false; 2693 ui->dragging = false;
2335 ui->cur_x = ui->cur_y = 1; 2694 ui->cur_x = ui->cur_y = 1;
2336 ui->cur_visible = false; 2695 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
2337 return ui; 2696 return ui;
2338} 2697}
2339 2698
@@ -2342,15 +2701,6 @@ static void free_ui(game_ui *ui)
2342 sfree(ui); 2701 sfree(ui);
2343} 2702}
2344 2703
2345static char *encode_ui(const game_ui *ui)
2346{
2347 return NULL;
2348}
2349
2350static void decode_ui(game_ui *ui, const char *encoding)
2351{
2352}
2353
2354static void game_changed_state(game_ui *ui, const game_state *oldstate, 2704static void game_changed_state(game_ui *ui, const game_state *oldstate,
2355 const game_state *newstate) 2705 const game_state *newstate)
2356{ 2706{
@@ -2383,7 +2733,7 @@ struct game_drawstate {
2383 blitter *blmirror; 2733 blitter *blmirror;
2384 2734
2385 bool dragging; 2735 bool dragging;
2386 int dragx, dragy; 2736 int dragx, dragy, oppx, oppy;
2387 2737
2388 int *colour_scratch; 2738 int *colour_scratch;
2389 2739
@@ -2445,34 +2795,74 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2445 int px, py; 2795 int px, py;
2446 space *sp; 2796 space *sp;
2447 2797
2448 px = 2*FROMCOORD((float)x) + 0.5; 2798 px = 2*FROMCOORD((float)x) + 0.5F;
2449 py = 2*FROMCOORD((float)y) + 0.5; 2799 py = 2*FROMCOORD((float)y) + 0.5F;
2450
2451 state->cdiff = -1;
2452 2800
2453 if (button == 'C' || button == 'c') return dupstr("C"); 2801 if (button == 'C' || button == 'c') return dupstr("C");
2454 2802
2455 if (button == 'S' || button == 's') { 2803 if (button == 'S' || button == 's') {
2456 char *ret; 2804 char *ret;
2457 game_state *tmp = dup_game(state); 2805 game_state *tmp = dup_game(state);
2458 state->cdiff = solver_state(tmp, DIFF_UNREASONABLE-1); 2806 int cdiff = solver_state(tmp, DIFF_UNREASONABLE-1);
2459 ret = diff_game(state, tmp, 0); 2807 ret = diff_game(state, tmp, 0, cdiff);
2460 free_game(tmp); 2808 free_game(tmp);
2461 return ret; 2809 return ret;
2462 } 2810 }
2463 2811
2464 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { 2812 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
2465 if (!INUI(state, px, py)) return NULL; 2813 if (!INUI(state, px, py)) return MOVE_UNUSED;
2466 sp = &SPACE(state, px, py); 2814 sp = &SPACE(state, px, py);
2467 if (!dot_is_possible(state, sp, 1)) return NULL; 2815 if (!dot_is_possible(state, sp, 1)) return MOVE_NO_EFFECT;
2468 sprintf(buf, "%c%d,%d", 2816 sprintf(buf, "%c%d,%d",
2469 (char)((button == LEFT_BUTTON) ? 'D' : 'd'), px, py); 2817 (char)((button == LEFT_BUTTON) ? 'D' : 'd'), px, py);
2470 return dupstr(buf); 2818 return dupstr(buf);
2471 } 2819 }
2472 2820
2473 return NULL; 2821 return MOVE_UNUSED;
2474} 2822}
2475#else 2823#else
2824static bool edge_placement_legal(const game_state *state, int x, int y)
2825{
2826 space *sp = &SPACE(state, x, y);
2827 if (sp->type != s_edge)
2828 return false; /* this is a face-centre or a grid vertex */
2829
2830 /* Check this line doesn't actually intersect a dot */
2831 unsigned int flags = (GRID(state, grid, x, y).flags |
2832 GRID(state, grid, x & ~1U, y & ~1U).flags |
2833 GRID(state, grid, (x+1) & ~1U, (y+1) & ~1U).flags);
2834 if (flags & F_DOT)
2835 return false;
2836 return true;
2837}
2838
2839static const char *current_key_label(const game_ui *ui,
2840 const game_state *state, int button)
2841{
2842 space *sp;
2843
2844 if (IS_CURSOR_SELECT(button) && ui->cur_visible) {
2845 sp = &SPACE(state, ui->cur_x, ui->cur_y);
2846 if (ui->dragging) {
2847 if (ui->cur_x == ui->srcx && ui->cur_y == ui->srcy)
2848 return "Cancel";
2849 if (ok_to_add_assoc_with_opposite(
2850 state, &SPACE(state, ui->cur_x, ui->cur_y),
2851 &SPACE(state, ui->dotx, ui->doty)))
2852 return "Place";
2853 return (ui->srcx == ui->dotx && ui->srcy == ui->doty) ?
2854 "Cancel" : "Remove";
2855 } else if (sp->flags & F_DOT)
2856 return "New arrow";
2857 else if (sp->flags & F_TILE_ASSOC)
2858 return "Move arrow";
2859 else if (sp->type == s_edge &&
2860 edge_placement_legal(state, ui->cur_x, ui->cur_y))
2861 return (sp->flags & F_EDGE_SET) ? "Clear" : "Edge";
2862 }
2863 return "";
2864}
2865
2476static char *interpret_move(const game_state *state, game_ui *ui, 2866static char *interpret_move(const game_state *state, game_ui *ui,
2477 const game_drawstate *ds, 2867 const game_drawstate *ds,
2478 int x, int y, int button) 2868 int x, int y, int button)
@@ -2499,7 +2889,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2499 char *ret; 2889 char *ret;
2500 game_state *tmp = dup_game(state); 2890 game_state *tmp = dup_game(state);
2501 solver_obvious(tmp); 2891 solver_obvious(tmp);
2502 ret = diff_game(state, tmp, false); 2892 ret = diff_game(state, tmp, false, -1);
2503 free_game(tmp); 2893 free_game(tmp);
2504 return ret; 2894 return ret;
2505 } 2895 }
@@ -2509,21 +2899,19 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2509 coord_round_to_edge(FROMCOORD((float)x), FROMCOORD((float)y), 2899 coord_round_to_edge(FROMCOORD((float)x), FROMCOORD((float)y),
2510 &px, &py); 2900 &px, &py);
2511 2901
2512 if (!INUI(state, px, py)) return NULL; 2902 if (!INUI(state, px, py)) return MOVE_UNUSED;
2903 if (!edge_placement_legal(state, px, py))
2904 return MOVE_NO_EFFECT;
2513 2905
2514 sp = &SPACE(state, px, py); 2906 sprintf(buf, "E%d,%d", px, py);
2515 assert(sp->type == s_edge); 2907 return dupstr(buf);
2516 {
2517 sprintf(buf, "E%d,%d", px, py);
2518 return dupstr(buf);
2519 }
2520 } else if (button == RIGHT_BUTTON) { 2908 } else if (button == RIGHT_BUTTON) {
2521 int px1, py1; 2909 int px1, py1;
2522 2910
2523 ui->cur_visible = false; 2911 ui->cur_visible = false;
2524 2912
2525 px = (int)(2*FROMCOORD((float)x) + 0.5); 2913 px = (int)(2*FROMCOORD((float)x) + 0.5F);
2526 py = (int)(2*FROMCOORD((float)y) + 0.5); 2914 py = (int)(2*FROMCOORD((float)y) + 0.5F);
2527 2915
2528 dot = NULL; 2916 dot = NULL;
2529 2917
@@ -2575,28 +2963,29 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2575 ui->dy = y; 2963 ui->dy = y;
2576 ui->dotx = dot->x; 2964 ui->dotx = dot->x;
2577 ui->doty = dot->y; 2965 ui->doty = dot->y;
2578 return UI_UPDATE; 2966 return MOVE_UI_UPDATE;
2579 } 2967 }
2968 return MOVE_NO_EFFECT;
2580 } else if (button == RIGHT_DRAG && ui->dragging) { 2969 } else if (button == RIGHT_DRAG && ui->dragging) {
2581 /* just move the drag coords. */ 2970 /* just move the drag coords. */
2582 ui->dx = x; 2971 ui->dx = x;
2583 ui->dy = y; 2972 ui->dy = y;
2584 return UI_UPDATE; 2973 return MOVE_UI_UPDATE;
2585 } else if (button == RIGHT_RELEASE && ui->dragging) { 2974 } else if (button == RIGHT_RELEASE && ui->dragging) {
2586 ui->dragging = false;
2587
2588 /* 2975 /*
2589 * Drags are always targeted at a single square. 2976 * Drags are always targeted at a single square.
2590 */ 2977 */
2591 px = 2*FROMCOORD(x+TILE_SIZE) - 1; 2978 px = 2*FROMCOORD(x+TILE_SIZE) - 1;
2592 py = 2*FROMCOORD(y+TILE_SIZE) - 1; 2979 py = 2*FROMCOORD(y+TILE_SIZE) - 1;
2593 2980
2981 dropped: /* We arrive here from the end of a keyboard drag. */
2982 ui->dragging = false;
2594 /* 2983 /*
2595 * Dragging an arrow on to the same square it started from 2984 * Dragging an arrow on to the same square it started from
2596 * is a null move; just update the ui and finish. 2985 * is a null move; just update the ui and finish.
2597 */ 2986 */
2598 if (px == ui->srcx && py == ui->srcy) 2987 if (px == ui->srcx && py == ui->srcy)
2599 return UI_UPDATE; 2988 return MOVE_UI_UPDATE;
2600 2989
2601 /* 2990 /*
2602 * Otherwise, we remove the arrow from its starting 2991 * Otherwise, we remove the arrow from its starting
@@ -2630,43 +3019,33 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2630 if (buf[0]) 3019 if (buf[0])
2631 return dupstr(buf); 3020 return dupstr(buf);
2632 else 3021 else
2633 return UI_UPDATE; 3022 return MOVE_UI_UPDATE;
2634 } else if (IS_CURSOR_MOVE(button)) { 3023 } else if (IS_CURSOR_MOVE(button)) {
2635 move_cursor(button, &ui->cur_x, &ui->cur_y, state->sx-1, state->sy-1, false); 3024 int cx = ui->cur_x - 1, cy = ui->cur_y - 1;
2636 if (ui->cur_x < 1) ui->cur_x = 1; 3025 char *ret = move_cursor(button, &cx, &cy, state->sx-2, state->sy-2,
2637 if (ui->cur_y < 1) ui->cur_y = 1; 3026 false, &ui->cur_visible);
2638 ui->cur_visible = true; 3027 ui->cur_x = cx + 1, ui->cur_y = cy + 1;
2639 if (ui->dragging) { 3028 if (ui->dragging) {
2640 ui->dx = SCOORD(ui->cur_x); 3029 ui->dx = SCOORD(ui->cur_x);
2641 ui->dy = SCOORD(ui->cur_y); 3030 ui->dy = SCOORD(ui->cur_y);
2642 } 3031 }
2643 return UI_UPDATE; 3032 return ret;
2644 } else if (IS_CURSOR_SELECT(button)) { 3033 } else if (IS_CURSOR_SELECT(button)) {
2645 if (!ui->cur_visible) { 3034 if (!ui->cur_visible) {
2646 ui->cur_visible = true; 3035 ui->cur_visible = true;
2647 return UI_UPDATE; 3036 return MOVE_UI_UPDATE;
2648 } 3037 }
2649 sp = &SPACE(state, ui->cur_x, ui->cur_y); 3038 sp = &SPACE(state, ui->cur_x, ui->cur_y);
2650 if (ui->dragging) { 3039 if (ui->dragging) {
2651 ui->dragging = false; 3040 px = ui->cur_x; py = ui->cur_y;
2652 3041 goto dropped;
2653 if ((ui->srcx != ui->dotx || ui->srcy != ui->doty) &&
2654 SPACE(state, ui->srcx, ui->srcy).flags & F_TILE_ASSOC) {
2655 sprintf(buf, "%sU%d,%d", sep, ui->srcx, ui->srcy);
2656 sep = ";";
2657 }
2658 if (sp->type == s_tile && !(sp->flags & F_DOT) && !(sp->flags & F_TILE_ASSOC)) {
2659 sprintf(buf + strlen(buf), "%sA%d,%d,%d,%d",
2660 sep, ui->cur_x, ui->cur_y, ui->dotx, ui->doty);
2661 }
2662 return dupstr(buf);
2663 } else if (sp->flags & F_DOT) { 3042 } else if (sp->flags & F_DOT) {
2664 ui->dragging = true; 3043 ui->dragging = true;
2665 ui->dx = SCOORD(ui->cur_x); 3044 ui->dx = SCOORD(ui->cur_x);
2666 ui->dy = SCOORD(ui->cur_y); 3045 ui->dy = SCOORD(ui->cur_y);
2667 ui->dotx = ui->srcx = ui->cur_x; 3046 ui->dotx = ui->srcx = ui->cur_x;
2668 ui->doty = ui->srcy = ui->cur_y; 3047 ui->doty = ui->srcy = ui->cur_y;
2669 return UI_UPDATE; 3048 return MOVE_UI_UPDATE;
2670 } else if (sp->flags & F_TILE_ASSOC) { 3049 } else if (sp->flags & F_TILE_ASSOC) {
2671 assert(sp->type == s_tile); 3050 assert(sp->type == s_tile);
2672 ui->dragging = true; 3051 ui->dragging = true;
@@ -2676,18 +3055,19 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2676 ui->doty = sp->doty; 3055 ui->doty = sp->doty;
2677 ui->srcx = ui->cur_x; 3056 ui->srcx = ui->cur_x;
2678 ui->srcy = ui->cur_y; 3057 ui->srcy = ui->cur_y;
2679 return UI_UPDATE; 3058 return MOVE_UI_UPDATE;
2680 } else if (sp->type == s_edge) { 3059 } else if (sp->type == s_edge &&
3060 edge_placement_legal(state, ui->cur_x, ui->cur_y)) {
2681 sprintf(buf, "E%d,%d", ui->cur_x, ui->cur_y); 3061 sprintf(buf, "E%d,%d", ui->cur_x, ui->cur_y);
2682 return dupstr(buf); 3062 return dupstr(buf);
2683 } 3063 }
2684 } 3064 }
2685 3065
2686 return NULL; 3066 return MOVE_UNUSED;
2687} 3067}
2688#endif 3068#endif
2689 3069
2690static bool check_complete(const game_state *state, int *dsf, int *colours) 3070static bool check_complete(const game_state *state, DSF *dsf, int *colours)
2691{ 3071{
2692 int w = state->w, h = state->h; 3072 int w = state->w, h = state->h;
2693 int x, y, i; 3073 int x, y, i;
@@ -2702,10 +3082,10 @@ static bool check_complete(const game_state *state, int *dsf, int *colours)
2702 } *sqdata; 3082 } *sqdata;
2703 3083
2704 if (!dsf) { 3084 if (!dsf) {
2705 dsf = snew_dsf(w*h); 3085 dsf = dsf_new(w*h);
2706 free_dsf = true; 3086 free_dsf = true;
2707 } else { 3087 } else {
2708 dsf_init(dsf, w*h); 3088 dsf_reinit(dsf);
2709 free_dsf = false; 3089 free_dsf = false;
2710 } 3090 }
2711 3091
@@ -2861,7 +3241,7 @@ static bool check_complete(const game_state *state, int *dsf, int *colours)
2861 3241
2862 sfree(sqdata); 3242 sfree(sqdata);
2863 if (free_dsf) 3243 if (free_dsf)
2864 sfree(dsf); 3244 dsf_free(dsf);
2865 3245
2866 return ret; 3246 return ret;
2867} 3247}
@@ -2959,6 +3339,35 @@ static game_state *execute_move(const game_state *state, const char *move)
2959 } else if (c == 'C') { 3339 } else if (c == 'C') {
2960 move++; 3340 move++;
2961 clear_game(ret, true); 3341 clear_game(ret, true);
3342 } else if (c == 'i') {
3343 int diff;
3344 move++;
3345 for (diff = 0; diff <= DIFF_UNREASONABLE; diff++)
3346 if (*move == galaxies_diffchars[diff])
3347 break;
3348 if (diff > DIFF_UNREASONABLE)
3349 goto badmove;
3350
3351 ret->cdiff = diff;
3352 move++;
3353 } else if (c == 'I') {
3354 int diff;
3355 move++;
3356 switch (*move) {
3357 case 'A':
3358 diff = DIFF_AMBIGUOUS;
3359 break;
3360 case 'I':
3361 diff = DIFF_IMPOSSIBLE;
3362 break;
3363 case 'U':
3364 diff = DIFF_UNFINISHED;
3365 break;
3366 default:
3367 goto badmove;
3368 }
3369 ret->cdiff = diff;
3370 move++;
2962#endif 3371#endif
2963 } else if (c == 'S') { 3372 } else if (c == 'S') {
2964 move++; 3373 move++;
@@ -2997,7 +3406,7 @@ badmove:
2997 */ 3406 */
2998 3407
2999static void game_compute_size(const game_params *params, int sz, 3408static void game_compute_size(const game_params *params, int sz,
3000 int *x, int *y) 3409 const game_ui *ui, int *x, int *y)
3001{ 3410{
3002 struct { int tilesize, w, h; } ads, *ds = &ads; 3411 struct { int tilesize, w, h; } ads, *ds = &ads;
3003 3412
@@ -3098,7 +3507,7 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
3098 ds->bl = NULL; 3507 ds->bl = NULL;
3099 ds->blmirror = NULL; 3508 ds->blmirror = NULL;
3100 ds->dragging = false; 3509 ds->dragging = false;
3101 ds->dragx = ds->dragy = 0; 3510 ds->dragx = ds->dragy = ds->oppx = ds->oppy = 0;
3102 3511
3103 ds->colour_scratch = snewn(ds->w * ds->h, int); 3512 ds->colour_scratch = snewn(ds->w * ds->h, int);
3104 3513
@@ -3145,7 +3554,10 @@ static void game_free_drawstate(drawing *dr, game_drawstate *ds)
3145static void draw_arrow(drawing *dr, game_drawstate *ds, 3554static void draw_arrow(drawing *dr, game_drawstate *ds,
3146 int cx, int cy, int ddx, int ddy, int col) 3555 int cx, int cy, int ddx, int ddy, int col)
3147{ 3556{
3148 float vlen = (float)sqrt(ddx*ddx+ddy*ddy); 3557 int sqdist = ddx*ddx+ddy*ddy;
3558 if (sqdist == 0)
3559 return; /* avoid division by zero */
3560 float vlen = (float)sqrt(sqdist);
3149 float xdx = ddx/vlen, xdy = ddy/vlen; 3561 float xdx = ddx/vlen, xdy = ddy/vlen;
3150 float ydx = -xdy, ydy = xdx; 3562 float ydx = -xdy, ydy = xdx;
3151 int e1x = cx + (int)(xdx*TILE_SIZE/3), e1y = cy + (int)(xdy*TILE_SIZE/3); 3563 int e1x = cx + (int)(xdx*TILE_SIZE/3), e1y = cy + (int)(xdy*TILE_SIZE/3);
@@ -3257,7 +3669,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
3257 int w = ds->w, h = ds->h; 3669 int w = ds->w, h = ds->h;
3258 int x, y; 3670 int x, y;
3259 bool flashing = false; 3671 bool flashing = false;
3260 int oppx, oppy;
3261 3672
3262 if (flashtime > 0) { 3673 if (flashtime > 0) {
3263 int frame = (int)(flashtime / FLASH_TIME); 3674 int frame = (int)(flashtime / FLASH_TIME);
@@ -3267,14 +3678,10 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
3267 if (ds->dragging) { 3678 if (ds->dragging) {
3268 assert(ds->bl); 3679 assert(ds->bl);
3269 assert(ds->blmirror); 3680 assert(ds->blmirror);
3270 calculate_opposite_point(ui, ds, ds->dragx + TILE_SIZE/2, 3681 blitter_load(dr, ds->blmirror, ds->oppx, ds->oppy);
3271 ds->dragy + TILE_SIZE/2, &oppx, &oppy); 3682 draw_update(dr, ds->oppx, ds->oppy, TILE_SIZE, TILE_SIZE);
3272 oppx -= TILE_SIZE/2;
3273 oppy -= TILE_SIZE/2;
3274 blitter_load(dr, ds->bl, ds->dragx, ds->dragy); 3683 blitter_load(dr, ds->bl, ds->dragx, ds->dragy);
3275 draw_update(dr, ds->dragx, ds->dragy, TILE_SIZE, TILE_SIZE); 3684 draw_update(dr, ds->dragx, ds->dragy, TILE_SIZE, TILE_SIZE);
3276 blitter_load(dr, ds->blmirror, oppx, oppy);
3277 draw_update(dr, oppx, oppy, TILE_SIZE, TILE_SIZE);
3278 ds->dragging = false; 3685 ds->dragging = false;
3279 } 3686 }
3280 if (ds->cur_visible) { 3687 if (ds->cur_visible) {
@@ -3285,7 +3692,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
3285 } 3692 }
3286 3693
3287 if (!ds->started) { 3694 if (!ds->started) {
3288 draw_rect(dr, 0, 0, DRAW_WIDTH, DRAW_HEIGHT, COL_BACKGROUND);
3289 draw_rect(dr, BORDER - EDGE_THICKNESS + 1, BORDER - EDGE_THICKNESS + 1, 3695 draw_rect(dr, BORDER - EDGE_THICKNESS + 1, BORDER - EDGE_THICKNESS + 1,
3290 w*TILE_SIZE + EDGE_THICKNESS*2 - 1, 3696 w*TILE_SIZE + EDGE_THICKNESS*2 - 1,
3291 h*TILE_SIZE + EDGE_THICKNESS*2 - 1, COL_EDGE); 3697 h*TILE_SIZE + EDGE_THICKNESS*2 - 1, COL_EDGE);
@@ -3433,16 +3839,28 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
3433 } 3839 }
3434 3840
3435 if (ui->dragging) { 3841 if (ui->dragging) {
3842 int oppx, oppy;
3843
3436 ds->dragging = true; 3844 ds->dragging = true;
3437 ds->dragx = ui->dx - TILE_SIZE/2; 3845 ds->dragx = ui->dx - TILE_SIZE/2;
3438 ds->dragy = ui->dy - TILE_SIZE/2; 3846 ds->dragy = ui->dy - TILE_SIZE/2;
3439 calculate_opposite_point(ui, ds, ui->dx, ui->dy, &oppx, &oppy); 3847 calculate_opposite_point(ui, ds, ui->dx, ui->dy, &oppx, &oppy);
3848 ds->oppx = oppx - TILE_SIZE/2;
3849 ds->oppy = oppy - TILE_SIZE/2;
3850
3440 blitter_save(dr, ds->bl, ds->dragx, ds->dragy); 3851 blitter_save(dr, ds->bl, ds->dragx, ds->dragy);
3441 blitter_save(dr, ds->blmirror, oppx - TILE_SIZE/2, oppy - TILE_SIZE/2); 3852 clip(dr, ds->dragx, ds->dragy, TILE_SIZE, TILE_SIZE);
3442 draw_arrow(dr, ds, ui->dx, ui->dy, SCOORD(ui->dotx) - ui->dx, 3853 draw_arrow(dr, ds, ui->dx, ui->dy, SCOORD(ui->dotx) - ui->dx,
3443 SCOORD(ui->doty) - ui->dy, COL_ARROW); 3854 SCOORD(ui->doty) - ui->dy, COL_ARROW);
3855 unclip(dr);
3856 draw_update(dr, ds->dragx, ds->dragy, TILE_SIZE, TILE_SIZE);
3857
3858 blitter_save(dr, ds->blmirror, ds->oppx, ds->oppy);
3859 clip(dr, ds->oppx, ds->oppy, TILE_SIZE, TILE_SIZE);
3444 draw_arrow(dr, ds, oppx, oppy, SCOORD(ui->dotx) - oppx, 3860 draw_arrow(dr, ds, oppx, oppy, SCOORD(ui->dotx) - oppx,
3445 SCOORD(ui->doty) - oppy, COL_ARROW); 3861 SCOORD(ui->doty) - oppy, COL_ARROW);
3862 unclip(dr);
3863 draw_update(dr, ds->oppx, ds->oppy, TILE_SIZE, TILE_SIZE);
3446 } 3864 }
3447#ifdef EDITOR 3865#ifdef EDITOR
3448 { 3866 {
@@ -3508,13 +3926,9 @@ static int game_status(const game_state *state)
3508 return state->completed ? +1 : 0; 3926 return state->completed ? +1 : 0;
3509} 3927}
3510 3928
3511static bool game_timing_state(const game_state *state, game_ui *ui)
3512{
3513 return true;
3514}
3515
3516#ifndef EDITOR 3929#ifndef EDITOR
3517static void game_print_size(const game_params *params, float *x, float *y) 3930static void game_print_size(const game_params *params, const game_ui *ui,
3931 float *x, float *y)
3518{ 3932{
3519 int pw, ph; 3933 int pw, ph;
3520 3934
@@ -3522,17 +3936,19 @@ static void game_print_size(const game_params *params, float *x, float *y)
3522 * 8mm squares by default. (There isn't all that much detail 3936 * 8mm squares by default. (There isn't all that much detail
3523 * that needs to go in each square.) 3937 * that needs to go in each square.)
3524 */ 3938 */
3525 game_compute_size(params, 800, &pw, &ph); 3939 game_compute_size(params, 800, ui, &pw, &ph);
3526 *x = pw / 100.0F; 3940 *x = pw / 100.0F;
3527 *y = ph / 100.0F; 3941 *y = ph / 100.0F;
3528} 3942}
3529 3943
3530static void game_print(drawing *dr, const game_state *state, int sz) 3944static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
3945 int sz)
3531{ 3946{
3532 int w = state->w, h = state->h; 3947 int w = state->w, h = state->h;
3533 int white, black, blackish; 3948 int white, black, blackish;
3534 int x, y, i, j; 3949 int x, y, i, j;
3535 int *colours, *dsf; 3950 int *colours;
3951 DSF *dsf;
3536 int *coords = NULL; 3952 int *coords = NULL;
3537 int ncoords = 0, coordsize = 0; 3953 int ncoords = 0, coordsize = 0;
3538 3954
@@ -3547,7 +3963,7 @@ static void game_print(drawing *dr, const game_state *state, int sz)
3547 /* 3963 /*
3548 * Get the completion information. 3964 * Get the completion information.
3549 */ 3965 */
3550 dsf = snewn(w * h, int); 3966 dsf = dsf_new(w * h);
3551 colours = snewn(w * h, int); 3967 colours = snewn(w * h, int);
3552 check_complete(state, dsf, colours); 3968 check_complete(state, dsf, colours);
3553 3969
@@ -3683,7 +4099,7 @@ static void game_print(drawing *dr, const game_state *state, int sz)
3683 black : white), black); 4099 black : white), black);
3684 } 4100 }
3685 4101
3686 sfree(dsf); 4102 dsf_free(dsf);
3687 sfree(colours); 4103 sfree(colours);
3688 sfree(coords); 4104 sfree(coords);
3689} 4105}
@@ -3714,12 +4130,18 @@ const struct game thegame = {
3714 true, solve_game, 4130 true, solve_game,
3715#endif 4131#endif
3716 true, game_can_format_as_text_now, game_text_format, 4132 true, game_can_format_as_text_now, game_text_format,
4133 NULL, NULL, /* get_prefs, set_prefs */
3717 new_ui, 4134 new_ui,
3718 free_ui, 4135 free_ui,
3719 encode_ui, 4136 NULL, /* encode_ui */
3720 decode_ui, 4137 NULL, /* decode_ui */
3721 NULL, /* game_request_keys */ 4138 NULL, /* game_request_keys */
3722 game_changed_state, 4139 game_changed_state,
4140#ifdef EDITOR
4141 NULL,
4142#else
4143 current_key_label,
4144#endif
3723 interpret_move, 4145 interpret_move,
3724 execute_move, 4146 execute_move,
3725 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 4147 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -3738,13 +4160,13 @@ const struct game thegame = {
3738 true, false, game_print_size, game_print, 4160 true, false, game_print_size, game_print,
3739 false, /* wants_statusbar */ 4161 false, /* wants_statusbar */
3740#endif 4162#endif
3741 false, game_timing_state, 4163 false, NULL, /* timing_state */
3742 REQUIRE_RBUTTON, /* flags */ 4164 REQUIRE_RBUTTON, /* flags */
3743}; 4165};
3744 4166
3745#ifdef STANDALONE_SOLVER 4167#ifdef STANDALONE_SOLVER
3746 4168
3747const char *quis; 4169static const char *quis;
3748 4170
3749#include <time.h> 4171#include <time.h>
3750 4172
@@ -3802,7 +4224,7 @@ static void soak(game_params *p, random_state *rs)
3802#endif 4224#endif
3803 tt_start = tt_now = time(NULL); 4225 tt_start = tt_now = time(NULL);
3804 for (i = 0; i < DIFF_MAX; i++) diffs[i] = 0; 4226 for (i = 0; i < DIFF_MAX; i++) diffs[i] = 0;
3805 maxtries = 1; 4227 one_try = true;
3806 4228
3807 printf("Soak-generating a %dx%d grid, max. diff %s.\n", 4229 printf("Soak-generating a %dx%d grid, max. diff %s.\n",
3808 p->w, p->h, galaxies_diffnames[p->diff]); 4230 p->w, p->h, galaxies_diffnames[p->diff]);
@@ -3812,7 +4234,9 @@ static void soak(game_params *p, random_state *rs)
3812 printf("]\n"); 4234 printf("]\n");
3813 4235
3814 while (1) { 4236 while (1) {
3815 desc = new_game_desc(p, rs, NULL, false); 4237 char *aux;
4238 desc = new_game_desc(p, rs, &aux, false);
4239 sfree(aux);
3816 st = new_game(NULL, p, desc); 4240 st = new_game(NULL, p, desc);
3817 diff = solver_state(st, p->diff); 4241 diff = solver_state(st, p->diff);
3818 nspaces += st->w*st->h; 4242 nspaces += st->w*st->h;
@@ -3866,8 +4290,6 @@ int main(int argc, char **argv)
3866 } 4290 }
3867 } 4291 }
3868 4292
3869 maxtries = 50;
3870
3871 p = default_params(); 4293 p = default_params();
3872 rs = random_new((void*)&seed, sizeof(time_t)); 4294 rs = random_new((void*)&seed, sizeof(time_t));
3873 4295
diff --git a/apps/plugins/puzzles/src/grid.c b/apps/plugins/puzzles/src/grid.c
index 5ea37439d4..04bb8a36cd 100644
--- a/apps/plugins/puzzles/src/grid.c
+++ b/apps/plugins/puzzles/src/grid.c
@@ -11,13 +11,21 @@
11#include <string.h> 11#include <string.h>
12#include <assert.h> 12#include <assert.h>
13#include <ctype.h> 13#include <ctype.h>
14#include <math.h>
15#include <float.h> 14#include <float.h>
15#include <limits.h>
16#ifdef NO_TGMATH_H
17# include <math.h>
18#else
19# include <tgmath.h>
20#endif
16 21
17#include "puzzles.h" 22#include "puzzles.h"
18#include "tree234.h" 23#include "tree234.h"
19#include "grid.h" 24#include "grid.h"
25#include "penrose-legacy.h"
20#include "penrose.h" 26#include "penrose.h"
27#include "hat.h"
28#include "spectre.h"
21 29
22/* Debugging options */ 30/* Debugging options */
23 31
@@ -36,12 +44,17 @@ void grid_free(grid *g)
36 if (g->refcount == 0) { 44 if (g->refcount == 0) {
37 int i; 45 int i;
38 for (i = 0; i < g->num_faces; i++) { 46 for (i = 0; i < g->num_faces; i++) {
39 sfree(g->faces[i].dots); 47 sfree(g->faces[i]->dots);
40 sfree(g->faces[i].edges); 48 sfree(g->faces[i]->edges);
49 sfree(g->faces[i]);
41 } 50 }
42 for (i = 0; i < g->num_dots; i++) { 51 for (i = 0; i < g->num_dots; i++) {
43 sfree(g->dots[i].faces); 52 sfree(g->dots[i]->faces);
44 sfree(g->dots[i].edges); 53 sfree(g->dots[i]->edges);
54 sfree(g->dots[i]);
55 }
56 for (i = 0; i < g->num_edges; i++) {
57 sfree(g->edges[i]);
45 } 58 }
46 sfree(g->faces); 59 sfree(g->faces);
47 sfree(g->edges); 60 sfree(g->edges);
@@ -59,6 +72,7 @@ static grid *grid_empty(void)
59 g->edges = NULL; 72 g->edges = NULL;
60 g->dots = NULL; 73 g->dots = NULL;
61 g->num_faces = g->num_edges = g->num_dots = 0; 74 g->num_faces = g->num_edges = g->num_dots = 0;
75 g->size_faces = g->size_edges = g->size_dots = 0;
62 g->refcount = 1; 76 g->refcount = 1;
63 g->lowest_x = g->lowest_y = g->highest_x = g->highest_y = 0; 77 g->lowest_x = g->lowest_y = g->highest_x = g->highest_y = 0;
64 return g; 78 return g;
@@ -116,7 +130,7 @@ grid_edge *grid_nearest_edge(grid *g, int x, int y)
116 best_edge = NULL; 130 best_edge = NULL;
117 131
118 for (i = 0; i < g->num_edges; i++) { 132 for (i = 0; i < g->num_edges; i++) {
119 grid_edge *e = &g->edges[i]; 133 grid_edge *e = g->edges[i];
120 long e2; /* squared length of edge */ 134 long e2; /* squared length of edge */
121 long a2, b2; /* squared lengths of other sides */ 135 long a2, b2; /* squared lengths of other sides */
122 double dist; 136 double dist;
@@ -185,7 +199,7 @@ xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n\n");
185 if (which & SVG_FACES) { 199 if (which & SVG_FACES) {
186 fprintf(fp, "<g>\n"); 200 fprintf(fp, "<g>\n");
187 for (i = 0; i < g->num_faces; i++) { 201 for (i = 0; i < g->num_faces; i++) {
188 grid_face *f = g->faces + i; 202 grid_face *f = g->faces[i];
189 fprintf(fp, "<polygon points=\""); 203 fprintf(fp, "<polygon points=\"");
190 for (j = 0; j < f->order; j++) { 204 for (j = 0; j < f->order; j++) {
191 grid_dot *d = f->dots[j]; 205 grid_dot *d = f->dots[j];
@@ -200,7 +214,7 @@ xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n\n");
200 if (which & SVG_EDGES) { 214 if (which & SVG_EDGES) {
201 fprintf(fp, "<g>\n"); 215 fprintf(fp, "<g>\n");
202 for (i = 0; i < g->num_edges; i++) { 216 for (i = 0; i < g->num_edges; i++) {
203 grid_edge *e = g->edges + i; 217 grid_edge *e = g->edges[i];
204 grid_dot *d1 = e->dot1, *d2 = e->dot2; 218 grid_dot *d1 = e->dot1, *d2 = e->dot2;
205 219
206 fprintf(fp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" " 220 fprintf(fp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" "
@@ -213,7 +227,7 @@ xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n\n");
213 if (which & SVG_DOTS) { 227 if (which & SVG_DOTS) {
214 fprintf(fp, "<g>\n"); 228 fprintf(fp, "<g>\n");
215 for (i = 0; i < g->num_dots; i++) { 229 for (i = 0; i < g->num_dots; i++) {
216 grid_dot *d = g->dots + i; 230 grid_dot *d = g->dots[i];
217 fprintf(fp, "<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" fill=\"%s\" />", 231 fprintf(fp, "<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" fill=\"%s\" />",
218 d->x, d->y, g->tilesize/20, g->tilesize/20, DOT_COLOUR); 232 d->x, d->y, g->tilesize/20, g->tilesize/20, DOT_COLOUR);
219 } 233 }
@@ -251,13 +265,17 @@ static void grid_debug_basic(grid *g)
251#ifdef DEBUG_GRID 265#ifdef DEBUG_GRID
252 int i; 266 int i;
253 printf("--- Basic Grid Data ---\n"); 267 printf("--- Basic Grid Data ---\n");
268 for (i = 0; i < g->num_dots; i++) {
269 grid_dot *d = g->dots[i];
270 printf("Dot %d at (%d,%d)\n", i, d->x, d->y);
271 }
254 for (i = 0; i < g->num_faces; i++) { 272 for (i = 0; i < g->num_faces; i++) {
255 grid_face *f = g->faces + i; 273 grid_face *f = g->faces[i];
256 printf("Face %d: dots[", i); 274 printf("Face %d: dots[", i);
257 int j; 275 int j;
258 for (j = 0; j < f->order; j++) { 276 for (j = 0; j < f->order; j++) {
259 grid_dot *d = f->dots[j]; 277 grid_dot *d = f->dots[j];
260 printf("%s%d", j ? "," : "", (int)(d - g->dots)); 278 printf("%s%d", j ? "," : "", (int)(d->index));
261 } 279 }
262 printf("]\n"); 280 printf("]\n");
263 } 281 }
@@ -275,38 +293,38 @@ static void grid_debug_derived(grid *g)
275 int i; 293 int i;
276 printf("--- Derived Grid Data ---\n"); 294 printf("--- Derived Grid Data ---\n");
277 for (i = 0; i < g->num_edges; i++) { 295 for (i = 0; i < g->num_edges; i++) {
278 grid_edge *e = g->edges + i; 296 grid_edge *e = g->edges[i];
279 printf("Edge %d: dots[%d,%d] faces[%d,%d]\n", 297 printf("Edge %d: dots[%d,%d] faces[%d,%d]\n",
280 i, (int)(e->dot1 - g->dots), (int)(e->dot2 - g->dots), 298 i, (int)(e->dot1->index), (int)(e->dot2->index),
281 e->face1 ? (int)(e->face1 - g->faces) : -1, 299 e->face1 ? (int)(e->face1->index) : -1,
282 e->face2 ? (int)(e->face2 - g->faces) : -1); 300 e->face2 ? (int)(e->face2->index) : -1);
283 } 301 }
284 /* faces */ 302 /* faces */
285 for (i = 0; i < g->num_faces; i++) { 303 for (i = 0; i < g->num_faces; i++) {
286 grid_face *f = g->faces + i; 304 grid_face *f = g->faces[i];
287 int j; 305 int j;
288 printf("Face %d: faces[", i); 306 printf("Face %d: faces[", i);
289 for (j = 0; j < f->order; j++) { 307 for (j = 0; j < f->order; j++) {
290 grid_edge *e = f->edges[j]; 308 grid_edge *e = f->edges[j];
291 grid_face *f2 = (e->face1 == f) ? e->face2 : e->face1; 309 grid_face *f2 = (e->face1 == f) ? e->face2 : e->face1;
292 printf("%s%d", j ? "," : "", f2 ? (int)(f2 - g->faces) : -1); 310 printf("%s%d", j ? "," : "", f2 ? f2->index : -1);
293 } 311 }
294 printf("]\n"); 312 printf("]\n");
295 } 313 }
296 /* dots */ 314 /* dots */
297 for (i = 0; i < g->num_dots; i++) { 315 for (i = 0; i < g->num_dots; i++) {
298 grid_dot *d = g->dots + i; 316 grid_dot *d = g->dots[i];
299 int j; 317 int j;
300 printf("Dot %d: dots[", i); 318 printf("Dot %d: dots[", i);
301 for (j = 0; j < d->order; j++) { 319 for (j = 0; j < d->order; j++) {
302 grid_edge *e = d->edges[j]; 320 grid_edge *e = d->edges[j];
303 grid_dot *d2 = (e->dot1 == d) ? e->dot2 : e->dot1; 321 grid_dot *d2 = (e->dot1 == d) ? e->dot2 : e->dot1;
304 printf("%s%d", j ? "," : "", (int)(d2 - g->dots)); 322 printf("%s%d", j ? "," : "", d2->index);
305 } 323 }
306 printf("] faces["); 324 printf("] faces[");
307 for (j = 0; j < d->order; j++) { 325 for (j = 0; j < d->order; j++) {
308 grid_face *f = d->faces[j]; 326 grid_face *f = d->faces[j];
309 printf("%s%d", j ? "," : "", f ? (int)(f - g->faces) : -1); 327 printf("%s%d", j ? "," : "", f ? f->index : -1);
310 } 328 }
311 printf("]\n"); 329 printf("]\n");
312 } 330 }
@@ -324,21 +342,23 @@ static int grid_edge_bydots_cmpfn(void *v1, void *v2)
324 grid_edge *b = v2; 342 grid_edge *b = v2;
325 grid_dot *da, *db; 343 grid_dot *da, *db;
326 344
327 /* Pointer subtraction is valid here, because all dots point into the 345 /* Edges are not "normalised" - the 2 dots could be stored in any order,
328 * same dot-list (g->dots).
329 * Edges are not "normalised" - the 2 dots could be stored in any order,
330 * so we need to take this into account when comparing edges. */ 346 * so we need to take this into account when comparing edges. */
331 347
332 /* Compare first dots */ 348 /* Compare first dots */
333 da = (a->dot1 < a->dot2) ? a->dot1 : a->dot2; 349 da = (a->dot1 < a->dot2) ? a->dot1 : a->dot2;
334 db = (b->dot1 < b->dot2) ? b->dot1 : b->dot2; 350 db = (b->dot1 < b->dot2) ? b->dot1 : b->dot2;
335 if (da != db) 351 if (da->index < db->index)
336 return db - da; 352 return -1;
353 if (da->index > db->index)
354 return +1;
337 /* Compare last dots */ 355 /* Compare last dots */
338 da = (a->dot1 < a->dot2) ? a->dot2 : a->dot1; 356 da = (a->dot1 < a->dot2) ? a->dot2 : a->dot1;
339 db = (b->dot1 < b->dot2) ? b->dot2 : b->dot1; 357 db = (b->dot1 < b->dot2) ? b->dot2 : b->dot1;
340 if (da != db) 358 if (da->index < db->index)
341 return db - da; 359 return -1;
360 if (da->index > db->index)
361 return +1;
342 362
343 return 0; 363 return 0;
344} 364}
@@ -358,7 +378,7 @@ static int grid_edge_bydots_cmpfn(void *v1, void *v2)
358static void grid_trim_vigorously(grid *g) 378static void grid_trim_vigorously(grid *g)
359{ 379{
360 int *dotpairs, *faces, *dots; 380 int *dotpairs, *faces, *dots;
361 int *dsf; 381 DSF *dsf;
362 int i, j, k, size, newfaces, newdots; 382 int i, j, k, size, newfaces, newdots;
363 383
364 /* 384 /*
@@ -371,10 +391,10 @@ static void grid_trim_vigorously(grid *g)
371 for (j = 0; j < g->num_dots; j++) 391 for (j = 0; j < g->num_dots; j++)
372 dotpairs[i*g->num_dots+j] = -1; 392 dotpairs[i*g->num_dots+j] = -1;
373 for (i = 0; i < g->num_faces; i++) { 393 for (i = 0; i < g->num_faces; i++) {
374 grid_face *f = g->faces + i; 394 grid_face *f = g->faces[i];
375 int dot0 = f->dots[f->order-1] - g->dots; 395 int dot0 = f->dots[f->order-1]->index;
376 for (j = 0; j < f->order; j++) { 396 for (j = 0; j < f->order; j++) {
377 int dot1 = f->dots[j] - g->dots; 397 int dot1 = f->dots[j]->index;
378 dotpairs[dot0 * g->num_dots + dot1] = i; 398 dotpairs[dot0 * g->num_dots + dot1] = i;
379 dot0 = dot1; 399 dot0 = dot1;
380 } 400 }
@@ -398,7 +418,7 @@ static void grid_trim_vigorously(grid *g)
398 * Now identify connected pairs of landlocked dots, and form a dsf 418 * Now identify connected pairs of landlocked dots, and form a dsf
399 * unifying them. 419 * unifying them.
400 */ 420 */
401 dsf = snew_dsf(g->num_dots); 421 dsf = dsf_new(g->num_dots);
402 for (i = 0; i < g->num_dots; i++) 422 for (i = 0; i < g->num_dots; i++)
403 for (j = 0; j < i; j++) 423 for (j = 0; j < i; j++)
404 if (dots[i] && dots[j] && 424 if (dots[i] && dots[j] &&
@@ -434,60 +454,52 @@ static void grid_trim_vigorously(grid *g)
434 for (i = 0; i < g->num_dots; i++) 454 for (i = 0; i < g->num_dots; i++)
435 dots[i] = 0; 455 dots[i] = 0;
436 for (i = 0; i < g->num_faces; i++) { 456 for (i = 0; i < g->num_faces; i++) {
437 grid_face *f = g->faces + i; 457 grid_face *f = g->faces[i];
438 bool keep = false; 458 bool keep = false;
439 for (k = 0; k < f->order; k++) 459 for (k = 0; k < f->order; k++)
440 if (dsf_canonify(dsf, f->dots[k] - g->dots) == j) 460 if (dsf_canonify(dsf, f->dots[k]->index) == j)
441 keep = true; 461 keep = true;
442 if (keep) { 462 if (keep) {
443 faces[i] = 1; 463 faces[i] = 1;
444 for (k = 0; k < f->order; k++) 464 for (k = 0; k < f->order; k++)
445 dots[f->dots[k]-g->dots] = 1; 465 dots[f->dots[k]->index] = 1;
446 } 466 }
447 } 467 }
448 468
449 /* 469 /*
450 * Work out the new indices of those faces and dots, when we 470 * Compact the faces array, rewriting the faces' indices and
451 * compact the arrays containing them. 471 * freeing the unwanted ones.
452 */
453 for (i = newfaces = 0; i < g->num_faces; i++)
454 faces[i] = (faces[i] ? newfaces++ : -1);
455 for (i = newdots = 0; i < g->num_dots; i++)
456 dots[i] = (dots[i] ? newdots++ : -1);
457
458 /*
459 * Free the dynamically allocated 'dots' pointer lists in faces
460 * we're going to discard.
461 */ 472 */
462 for (i = 0; i < g->num_faces; i++) 473 for (i = newfaces = 0; i < g->num_faces; i++) {
463 if (faces[i] < 0) 474 grid_face *f = g->faces[i];
464 sfree(g->faces[i].dots); 475 if (faces[i]) {
476 f->index = newfaces++;
477 g->faces[f->index] = f;
478 } else {
479 sfree(f->dots);
480 sfree(f);
481 }
482 }
483 g->num_faces = newfaces;
465 484
466 /* 485 /*
467 * Go through and compact the arrays. 486 * Compact the dots array, similarly.
468 */ 487 */
469 for (i = 0; i < g->num_dots; i++) 488 for (i = newdots = 0; i < g->num_dots; i++) {
470 if (dots[i] >= 0) { 489 grid_dot *d = g->dots[i];
471 grid_dot *dnew = g->dots + dots[i], *dold = g->dots + i; 490 if (dots[i]) {
472 *dnew = *dold; /* structure copy */ 491 d->index = newdots++;
473 } 492 g->dots[d->index] = d;
474 for (i = 0; i < g->num_faces; i++) 493 } else {
475 if (faces[i] >= 0) { 494 sfree(d->edges);
476 grid_face *fnew = g->faces + faces[i], *fold = g->faces + i; 495 sfree(d->faces);
477 *fnew = *fold; /* structure copy */ 496 sfree(d);
478 for (j = 0; j < fnew->order; j++) {
479 /*
480 * Reindex the dots in this face.
481 */
482 k = fnew->dots[j] - g->dots;
483 fnew->dots[j] = g->dots + dots[k];
484 }
485 } 497 }
486 g->num_faces = newfaces; 498 }
487 g->num_dots = newdots; 499 g->num_dots = newdots;
488 500
489 sfree(dotpairs); 501 sfree(dotpairs);
490 sfree(dsf); 502 dsf_free(dsf);
491 sfree(dots); 503 sfree(dots);
492 sfree(faces); 504 sfree(faces);
493} 505}
@@ -505,7 +517,6 @@ static void grid_make_consistent(grid *g)
505{ 517{
506 int i; 518 int i;
507 tree234 *incomplete_edges; 519 tree234 *incomplete_edges;
508 grid_edge *next_new_edge; /* Where new edge will go into g->edges */
509 520
510 grid_debug_basic(g); 521 grid_debug_basic(g);
511 522
@@ -513,14 +524,6 @@ static void grid_make_consistent(grid *g)
513 * Generate edges 524 * Generate edges
514 */ 525 */
515 526
516 /* We know how many dots and faces there are, so we can find the exact
517 * number of edges from Euler's polyhedral formula: F + V = E + 2 .
518 * We use "-1", not "-2" here, because Euler's formula includes the
519 * infinite face, which we don't count. */
520 g->num_edges = g->num_faces + g->num_dots - 1;
521 g->edges = snewn(g->num_edges, grid_edge);
522 next_new_edge = g->edges;
523
524 /* Iterate over faces, and over each face's dots, generating edges as we 527 /* Iterate over faces, and over each face's dots, generating edges as we
525 * go. As we find each new edge, we can immediately fill in the edge's 528 * go. As we find each new edge, we can immediately fill in the edge's
526 * dots, but only one of the edge's faces. Later on in the iteration, we 529 * dots, but only one of the edge's faces. Later on in the iteration, we
@@ -530,7 +533,7 @@ static void grid_make_consistent(grid *g)
530 * their dots. */ 533 * their dots. */
531 incomplete_edges = newtree234(grid_edge_bydots_cmpfn); 534 incomplete_edges = newtree234(grid_edge_bydots_cmpfn);
532 for (i = 0; i < g->num_faces; i++) { 535 for (i = 0; i < g->num_faces; i++) {
533 grid_face *f = g->faces + i; 536 grid_face *f = g->faces[i];
534 int j; 537 int j;
535 for (j = 0; j < f->order; j++) { 538 for (j = 0; j < f->order; j++) {
536 grid_edge e; /* fake edge for searching */ 539 grid_edge e; /* fake edge for searching */
@@ -548,18 +551,28 @@ static void grid_make_consistent(grid *g)
548 * Edge is already removed from incomplete_edges. */ 551 * Edge is already removed from incomplete_edges. */
549 edge_found->face2 = f; 552 edge_found->face2 = f;
550 } else { 553 } else {
551 assert(next_new_edge - g->edges < g->num_edges); 554 grid_edge *new_edge = snew(grid_edge);
552 next_new_edge->dot1 = e.dot1; 555 new_edge->dot1 = e.dot1;
553 next_new_edge->dot2 = e.dot2; 556 new_edge->dot2 = e.dot2;
554 next_new_edge->face1 = f; 557 new_edge->face1 = f;
555 next_new_edge->face2 = NULL; /* potentially infinite face */ 558 new_edge->face2 = NULL; /* potentially infinite face */
556 add234(incomplete_edges, next_new_edge); 559 add234(incomplete_edges, new_edge);
557 ++next_new_edge; 560
561 /* And add it to g->edges. */
562 if (g->num_edges >= g->size_edges) {
563 int increment = g->num_edges / 4 + 128;
564 g->size_edges = (increment < INT_MAX - g->num_edges ?
565 g->num_edges + increment : INT_MAX);
566 g->edges = sresize(g->edges, g->size_edges, grid_edge *);
567 }
568 assert(g->num_edges < INT_MAX);
569 new_edge->index = g->num_edges++;
570 g->edges[new_edge->index] = new_edge;
558 } 571 }
559 } 572 }
560 } 573 }
561 freetree234(incomplete_edges); 574 freetree234(incomplete_edges);
562 575
563 /* ====== Stage 2 ====== 576 /* ====== Stage 2 ======
564 * For each face, build its edge list. 577 * For each face, build its edge list.
565 */ 578 */
@@ -567,7 +580,7 @@ static void grid_make_consistent(grid *g)
567 /* Allocate space for each edge list. Can do this, because each face's 580 /* Allocate space for each edge list. Can do this, because each face's
568 * edge-list is the same size as its dot-list. */ 581 * edge-list is the same size as its dot-list. */
569 for (i = 0; i < g->num_faces; i++) { 582 for (i = 0; i < g->num_faces; i++) {
570 grid_face *f = g->faces + i; 583 grid_face *f = g->faces[i];
571 int j; 584 int j;
572 f->edges = snewn(f->order, grid_edge*); 585 f->edges = snewn(f->order, grid_edge*);
573 /* Preload with NULLs, to help detect potential bugs. */ 586 /* Preload with NULLs, to help detect potential bugs. */
@@ -579,7 +592,7 @@ static void grid_make_consistent(grid *g)
579 * the face's edge-list, after finding where it should go in the 592 * the face's edge-list, after finding where it should go in the
580 * sequence. */ 593 * sequence. */
581 for (i = 0; i < g->num_edges; i++) { 594 for (i = 0; i < g->num_edges; i++) {
582 grid_edge *e = g->edges + i; 595 grid_edge *e = g->edges[i];
583 int j; 596 int j;
584 for (j = 0; j < 2; j++) { 597 for (j = 0; j < 2; j++) {
585 grid_face *f = j ? e->face2 : e->face1; 598 grid_face *f = j ? e->face2 : e->face1;
@@ -641,16 +654,16 @@ static void grid_make_consistent(grid *g)
641 * allocate the right space for these lists. Pre-compute the sizes by 654 * allocate the right space for these lists. Pre-compute the sizes by
642 * iterating over each edge and recording a tally against each dot. */ 655 * iterating over each edge and recording a tally against each dot. */
643 for (i = 0; i < g->num_dots; i++) { 656 for (i = 0; i < g->num_dots; i++) {
644 g->dots[i].order = 0; 657 g->dots[i]->order = 0;
645 } 658 }
646 for (i = 0; i < g->num_edges; i++) { 659 for (i = 0; i < g->num_edges; i++) {
647 grid_edge *e = g->edges + i; 660 grid_edge *e = g->edges[i];
648 ++(e->dot1->order); 661 ++(e->dot1->order);
649 ++(e->dot2->order); 662 ++(e->dot2->order);
650 } 663 }
651 /* Now we have the sizes, pre-allocate the edge and face lists. */ 664 /* Now we have the sizes, pre-allocate the edge and face lists. */
652 for (i = 0; i < g->num_dots; i++) { 665 for (i = 0; i < g->num_dots; i++) {
653 grid_dot *d = g->dots + i; 666 grid_dot *d = g->dots[i];
654 int j; 667 int j;
655 assert(d->order >= 2); /* sanity check */ 668 assert(d->order >= 2); /* sanity check */
656 d->edges = snewn(d->order, grid_edge*); 669 d->edges = snewn(d->order, grid_edge*);
@@ -663,7 +676,7 @@ static void grid_make_consistent(grid *g)
663 /* For each dot, need to find a face that touches it, so we can seed 676 /* For each dot, need to find a face that touches it, so we can seed
664 * the edge-face-edge-face process around each dot. */ 677 * the edge-face-edge-face process around each dot. */
665 for (i = 0; i < g->num_faces; i++) { 678 for (i = 0; i < g->num_faces; i++) {
666 grid_face *f = g->faces + i; 679 grid_face *f = g->faces[i];
667 int j; 680 int j;
668 for (j = 0; j < f->order; j++) { 681 for (j = 0; j < f->order; j++) {
669 grid_dot *d = f->dots[j]; 682 grid_dot *d = f->dots[j];
@@ -677,7 +690,7 @@ static void grid_make_consistent(grid *g)
677 * blocks progress. But there's only one such face, so we will 690 * blocks progress. But there's only one such face, so we will
678 * succeed in finding every edge and face this way. */ 691 * succeed in finding every edge and face this way. */
679 for (i = 0; i < g->num_dots; i++) { 692 for (i = 0; i < g->num_dots; i++) {
680 grid_dot *d = g->dots + i; 693 grid_dot *d = g->dots[i];
681 int current_face1 = 0; /* ascends clockwise */ 694 int current_face1 = 0; /* ascends clockwise */
682 int current_face2 = 0; /* descends anticlockwise */ 695 int current_face2 = 0; /* descends anticlockwise */
683 696
@@ -774,7 +787,7 @@ static void grid_make_consistent(grid *g)
774 787
775 /* Bounding rectangle */ 788 /* Bounding rectangle */
776 for (i = 0; i < g->num_dots; i++) { 789 for (i = 0; i < g->num_dots; i++) {
777 grid_dot *d = g->dots + i; 790 grid_dot *d = g->dots[i];
778 if (i == 0) { 791 if (i == 0) {
779 g->lowest_x = g->highest_x = d->x; 792 g->lowest_x = g->highest_x = d->x;
780 g->lowest_y = g->highest_y = d->y; 793 g->lowest_y = g->highest_y = d->y;
@@ -802,36 +815,52 @@ static int grid_point_cmp_fn(void *v1, void *v2)
802 else 815 else
803 return p2->x - p1->x; 816 return p2->x - p1->x;
804} 817}
805/* Add a new face to the grid, with its dot list allocated. 818/* Add a new face to the grid, with its dot list allocated. */
806 * Assumes there's enough space allocated for the new face in grid->faces */
807static void grid_face_add_new(grid *g, int face_size) 819static void grid_face_add_new(grid *g, int face_size)
808{ 820{
809 int i; 821 int i;
810 grid_face *new_face = g->faces + g->num_faces; 822 grid_face *new_face = snew(grid_face);
823 assert(g->num_faces < INT_MAX);
824 if (g->num_faces >= g->size_faces) {
825 int increment = g->num_faces / 4 + 128;
826 g->size_faces = (increment < INT_MAX - g->num_faces ?
827 g->num_faces + increment : INT_MAX);
828 g->faces = sresize(g->faces, g->size_faces, grid_face *);
829 }
830 new_face->index = g->num_faces++;
831 g->faces[new_face->index] = new_face;
832
811 new_face->order = face_size; 833 new_face->order = face_size;
812 new_face->dots = snewn(face_size, grid_dot*); 834 new_face->dots = snewn(face_size, grid_dot*);
813 for (i = 0; i < face_size; i++) 835 for (i = 0; i < face_size; i++)
814 new_face->dots[i] = NULL; 836 new_face->dots[i] = NULL;
815 new_face->edges = NULL; 837 new_face->edges = NULL;
816 new_face->has_incentre = false; 838 new_face->has_incentre = false;
817 g->num_faces++;
818} 839}
819/* Assumes dot list has enough space */
820static grid_dot *grid_dot_add_new(grid *g, int x, int y) 840static grid_dot *grid_dot_add_new(grid *g, int x, int y)
821{ 841{
822 grid_dot *new_dot = g->dots + g->num_dots; 842 grid_dot *new_dot = snew(grid_dot);
843 if (g->num_dots >= g->size_dots) {
844 int increment = g->num_dots / 4 + 128;
845 g->size_dots = (increment < INT_MAX - g->num_dots ?
846 g->num_dots + increment : INT_MAX);
847 g->dots = sresize(g->dots, g->size_dots, grid_dot *);
848 }
849 assert(g->num_dots < INT_MAX);
850 new_dot->index = g->num_dots++;
851 g->dots[new_dot->index] = new_dot;
852
823 new_dot->order = 0; 853 new_dot->order = 0;
824 new_dot->edges = NULL; 854 new_dot->edges = NULL;
825 new_dot->faces = NULL; 855 new_dot->faces = NULL;
826 new_dot->x = x; 856 new_dot->x = x;
827 new_dot->y = y; 857 new_dot->y = y;
828 g->num_dots++; 858
829 return new_dot; 859 return new_dot;
830} 860}
831/* Retrieve a dot with these (x,y) coordinates. Either return an existing dot 861/* Retrieve a dot with these (x,y) coordinates. Either return an existing dot
832 * in the dot_list, or add a new dot to the grid (and the dot_list) and 862 * in the dot_list, or add a new dot to the grid (and the dot_list) and
833 * return that. 863 * return that. */
834 * Assumes g->dots has enough capacity allocated */
835static grid_dot *grid_get_dot(grid *g, tree234 *dot_list, int x, int y) 864static grid_dot *grid_get_dot(grid *g, tree234 *dot_list, int x, int y)
836{ 865{
837 grid_dot test, *ret; 866 grid_dot test, *ret;
@@ -855,7 +884,7 @@ static grid_dot *grid_get_dot(grid *g, tree234 *dot_list, int x, int y)
855 * previously been added, with the required number of dots allocated) */ 884 * previously been added, with the required number of dots allocated) */
856static void grid_face_set_dot(grid *g, grid_dot *d, int position) 885static void grid_face_set_dot(grid *g, grid_dot *d, int position)
857{ 886{
858 grid_face *last_face = g->faces + g->num_faces - 1; 887 grid_face *last_face = g->faces[g->num_faces - 1];
859 last_face->dots[position] = d; 888 last_face->dots[position] = d;
860} 889}
861 890
@@ -1388,6 +1417,15 @@ void grid_find_incentre(grid_face *f)
1388 1417
1389#define SQUARE_TILESIZE 20 1418#define SQUARE_TILESIZE 20
1390 1419
1420static const char *grid_validate_params_square(int width, int height)
1421{
1422 if (width > INT_MAX / SQUARE_TILESIZE || /* xextent */
1423 height > INT_MAX / SQUARE_TILESIZE || /* yextent */
1424 width + 1 > INT_MAX / (height + 1)) /* max_dots */
1425 return "Grid size must not be unreasonably large";
1426 return NULL;
1427}
1428
1391static void grid_size_square(int width, int height, 1429static void grid_size_square(int width, int height,
1392 int *tilesize, int *xextent, int *yextent) 1430 int *tilesize, int *xextent, int *yextent)
1393{ 1431{
@@ -1404,16 +1442,10 @@ static grid *grid_new_square(int width, int height, const char *desc)
1404 /* Side length */ 1442 /* Side length */
1405 int a = SQUARE_TILESIZE; 1443 int a = SQUARE_TILESIZE;
1406 1444
1407 /* Upper bounds - don't have to be exact */
1408 int max_faces = width * height;
1409 int max_dots = (width + 1) * (height + 1);
1410
1411 tree234 *points; 1445 tree234 *points;
1412 1446
1413 grid *g = grid_empty(); 1447 grid *g = grid_empty();
1414 g->tilesize = a; 1448 g->tilesize = a;
1415 g->faces = snewn(max_faces, grid_face);
1416 g->dots = snewn(max_dots, grid_dot);
1417 1449
1418 points = newtree234(grid_point_cmp_fn); 1450 points = newtree234(grid_point_cmp_fn);
1419 1451
@@ -1438,8 +1470,6 @@ static grid *grid_new_square(int width, int height, const char *desc)
1438 } 1470 }
1439 1471
1440 freetree234(points); 1472 freetree234(points);
1441 assert(g->num_faces <= max_faces);
1442 assert(g->num_dots <= max_dots);
1443 1473
1444 grid_make_consistent(g); 1474 grid_make_consistent(g);
1445 return g; 1475 return g;
@@ -1450,6 +1480,18 @@ static grid *grid_new_square(int width, int height, const char *desc)
1450#define HONEY_A 15 1480#define HONEY_A 15
1451#define HONEY_B 26 1481#define HONEY_B 26
1452 1482
1483static const char *grid_validate_params_honeycomb(int width, int height)
1484{
1485 int a = HONEY_A;
1486 int b = HONEY_B;
1487
1488 if (width - 1 > (INT_MAX - 4*a) / (3 * a) || /* xextent */
1489 height - 1 > (INT_MAX - 3*b) / (2 * b) || /* yextent */
1490 width + 1 > INT_MAX / 2 / (height + 1)) /* max_dots */
1491 return "Grid size must not be unreasonably large";
1492 return NULL;
1493}
1494
1453static void grid_size_honeycomb(int width, int height, 1495static void grid_size_honeycomb(int width, int height,
1454 int *tilesize, int *xextent, int *yextent) 1496 int *tilesize, int *xextent, int *yextent)
1455{ 1497{
@@ -1467,16 +1509,10 @@ static grid *grid_new_honeycomb(int width, int height, const char *desc)
1467 int a = HONEY_A; 1509 int a = HONEY_A;
1468 int b = HONEY_B; 1510 int b = HONEY_B;
1469 1511
1470 /* Upper bounds - don't have to be exact */
1471 int max_faces = width * height;
1472 int max_dots = 2 * (width + 1) * (height + 1);
1473
1474 tree234 *points; 1512 tree234 *points;
1475 1513
1476 grid *g = grid_empty(); 1514 grid *g = grid_empty();
1477 g->tilesize = HONEY_TILESIZE; 1515 g->tilesize = HONEY_TILESIZE;
1478 g->faces = snewn(max_faces, grid_face);
1479 g->dots = snewn(max_dots, grid_dot);
1480 1516
1481 points = newtree234(grid_point_cmp_fn); 1517 points = newtree234(grid_point_cmp_fn);
1482 1518
@@ -1507,8 +1543,6 @@ static grid *grid_new_honeycomb(int width, int height, const char *desc)
1507 } 1543 }
1508 1544
1509 freetree234(points); 1545 freetree234(points);
1510 assert(g->num_faces <= max_faces);
1511 assert(g->num_dots <= max_dots);
1512 1546
1513 grid_make_consistent(g); 1547 grid_make_consistent(g);
1514 return g; 1548 return g;
@@ -1519,6 +1553,18 @@ static grid *grid_new_honeycomb(int width, int height, const char *desc)
1519#define TRIANGLE_VEC_X 15 1553#define TRIANGLE_VEC_X 15
1520#define TRIANGLE_VEC_Y 26 1554#define TRIANGLE_VEC_Y 26
1521 1555
1556static const char *grid_validate_params_triangular(int width, int height)
1557{
1558 int vec_x = TRIANGLE_VEC_X;
1559 int vec_y = TRIANGLE_VEC_Y;
1560
1561 if (width > INT_MAX / (2 * vec_x) - 1 || /* xextent */
1562 height > INT_MAX / vec_y || /* yextent */
1563 width + 1 > INT_MAX / 4 / (height + 1)) /* max_dots */
1564 return "Grid size must not be unreasonably large";
1565 return NULL;
1566}
1567
1522static void grid_size_triangular(int width, int height, 1568static void grid_size_triangular(int width, int height,
1523 int *tilesize, int *xextent, int *yextent) 1569 int *tilesize, int *xextent, int *yextent)
1524{ 1570{
@@ -1582,16 +1628,18 @@ static grid *grid_new_triangular(int width, int height, const char *desc)
1582 * 5x6t1:a022a212h1a1d1a12c2b11a012b1a20d1a0a12e 1628 * 5x6t1:a022a212h1a1d1a12c2b11a012b1a20d1a0a12e
1583 */ 1629 */
1584 1630
1585 g->num_faces = width * height * 2; 1631 g->num_faces = g->size_faces = width * height * 2;
1586 g->num_dots = (width + 1) * (height + 1); 1632 g->num_dots = g->size_dots = (width + 1) * (height + 1);
1587 g->faces = snewn(g->num_faces, grid_face); 1633 g->faces = snewn(g->size_faces, grid_face *);
1588 g->dots = snewn(g->num_dots, grid_dot); 1634 g->dots = snewn(g->size_dots, grid_dot *);
1589 1635
1590 /* generate dots */ 1636 /* generate dots */
1591 index = 0; 1637 index = 0;
1592 for (y = 0; y <= height; y++) { 1638 for (y = 0; y <= height; y++) {
1593 for (x = 0; x <= width; x++) { 1639 for (x = 0; x <= width; x++) {
1594 grid_dot *d = g->dots + index; 1640 grid_dot *d = snew(grid_dot);
1641 d->index = index;
1642 g->dots[d->index] = d;
1595 /* odd rows are offset to the right */ 1643 /* odd rows are offset to the right */
1596 d->order = 0; 1644 d->order = 0;
1597 d->edges = NULL; 1645 d->edges = NULL;
@@ -1607,8 +1655,11 @@ static grid *grid_new_triangular(int width, int height, const char *desc)
1607 for (y = 0; y < height; y++) { 1655 for (y = 0; y < height; y++) {
1608 for (x = 0; x < width; x++) { 1656 for (x = 0; x < width; x++) {
1609 /* initialise two faces for this (x,y) */ 1657 /* initialise two faces for this (x,y) */
1610 grid_face *f1 = g->faces + index; 1658 grid_face *f1 = snew(grid_face), *f2 = snew(grid_face);
1611 grid_face *f2 = f1 + 1; 1659 f1->index = index;
1660 f2->index = index + 1;
1661 g->faces[f1->index] = f1;
1662 g->faces[f2->index] = f2;
1612 f1->edges = NULL; 1663 f1->edges = NULL;
1613 f1->order = 3; 1664 f1->order = 3;
1614 f1->dots = snewn(f1->order, grid_dot*); 1665 f1->dots = snewn(f1->order, grid_dot*);
@@ -1621,19 +1672,19 @@ static grid *grid_new_triangular(int width, int height, const char *desc)
1621 /* face descriptions depend on whether the row-number is 1672 /* face descriptions depend on whether the row-number is
1622 * odd or even */ 1673 * odd or even */
1623 if (y % 2) { 1674 if (y % 2) {
1624 f1->dots[0] = g->dots + y * w + x; 1675 f1->dots[0] = g->dots[y * w + x];
1625 f1->dots[1] = g->dots + (y + 1) * w + x + 1; 1676 f1->dots[1] = g->dots[(y + 1) * w + x + 1];
1626 f1->dots[2] = g->dots + (y + 1) * w + x; 1677 f1->dots[2] = g->dots[(y + 1) * w + x];
1627 f2->dots[0] = g->dots + y * w + x; 1678 f2->dots[0] = g->dots[y * w + x];
1628 f2->dots[1] = g->dots + y * w + x + 1; 1679 f2->dots[1] = g->dots[y * w + x + 1];
1629 f2->dots[2] = g->dots + (y + 1) * w + x + 1; 1680 f2->dots[2] = g->dots[(y + 1) * w + x + 1];
1630 } else { 1681 } else {
1631 f1->dots[0] = g->dots + y * w + x; 1682 f1->dots[0] = g->dots[y * w + x];
1632 f1->dots[1] = g->dots + y * w + x + 1; 1683 f1->dots[1] = g->dots[y * w + x + 1];
1633 f1->dots[2] = g->dots + (y + 1) * w + x; 1684 f1->dots[2] = g->dots[(y + 1) * w + x];
1634 f2->dots[0] = g->dots + y * w + x + 1; 1685 f2->dots[0] = g->dots[y * w + x + 1];
1635 f2->dots[1] = g->dots + (y + 1) * w + x + 1; 1686 f2->dots[1] = g->dots[(y + 1) * w + x + 1];
1636 f2->dots[2] = g->dots + (y + 1) * w + x; 1687 f2->dots[2] = g->dots[(y + 1) * w + x];
1637 } 1688 }
1638 index += 2; 1689 index += 2;
1639 } 1690 }
@@ -1650,12 +1701,6 @@ static grid *grid_new_triangular(int width, int height, const char *desc)
1650 * 5x6t1:0_a1212c22c2a02a2f22a0c12a110d0e1c0c0a101121a1 1701 * 5x6t1:0_a1212c22c2a02a2f22a0c12a110d0e1c0c0a101121a1
1651 */ 1702 */
1652 tree234 *points = newtree234(grid_point_cmp_fn); 1703 tree234 *points = newtree234(grid_point_cmp_fn);
1653 /* Upper bounds - don't have to be exact */
1654 int max_faces = height * (2*width+1);
1655 int max_dots = (height+1) * (width+1) * 4;
1656
1657 g->faces = snewn(max_faces, grid_face);
1658 g->dots = snewn(max_dots, grid_dot);
1659 1704
1660 for (y = 0; y < height; y++) { 1705 for (y = 0; y < height; y++) {
1661 /* 1706 /*
@@ -1703,8 +1748,6 @@ static grid *grid_new_triangular(int width, int height, const char *desc)
1703 } 1748 }
1704 1749
1705 freetree234(points); 1750 freetree234(points);
1706 assert(g->num_faces <= max_faces);
1707 assert(g->num_dots <= max_dots);
1708 } 1751 }
1709 1752
1710 grid_make_consistent(g); 1753 grid_make_consistent(g);
@@ -1716,6 +1759,19 @@ static grid *grid_new_triangular(int width, int height, const char *desc)
1716#define SNUBSQUARE_A 15 1759#define SNUBSQUARE_A 15
1717#define SNUBSQUARE_B 26 1760#define SNUBSQUARE_B 26
1718 1761
1762static const char *grid_validate_params_snubsquare(int width, int height)
1763{
1764 int a = SNUBSQUARE_A;
1765 int b = SNUBSQUARE_B;
1766
1767 if (width-1 > (INT_MAX - (a + b)) / (a+b) || /* xextent */
1768 height > (INT_MAX - (a + b)) / (a+b) || /* yextent */
1769 width > INT_MAX / 3 / height || /* max_faces */
1770 width + 1 > INT_MAX / 2 / (height + 1)) /* max_dots */
1771 return "Grid size must not be unreasonably large";
1772 return NULL;
1773}
1774
1719static void grid_size_snubsquare(int width, int height, 1775static void grid_size_snubsquare(int width, int height,
1720 int *tilesize, int *xextent, int *yextent) 1776 int *tilesize, int *xextent, int *yextent)
1721{ 1777{
@@ -1733,16 +1789,10 @@ static grid *grid_new_snubsquare(int width, int height, const char *desc)
1733 int a = SNUBSQUARE_A; 1789 int a = SNUBSQUARE_A;
1734 int b = SNUBSQUARE_B; 1790 int b = SNUBSQUARE_B;
1735 1791
1736 /* Upper bounds - don't have to be exact */
1737 int max_faces = 3 * width * height;
1738 int max_dots = 2 * (width + 1) * (height + 1);
1739
1740 tree234 *points; 1792 tree234 *points;
1741 1793
1742 grid *g = grid_empty(); 1794 grid *g = grid_empty();
1743 g->tilesize = SNUBSQUARE_TILESIZE; 1795 g->tilesize = SNUBSQUARE_TILESIZE;
1744 g->faces = snewn(max_faces, grid_face);
1745 g->dots = snewn(max_dots, grid_dot);
1746 1796
1747 points = newtree234(grid_point_cmp_fn); 1797 points = newtree234(grid_point_cmp_fn);
1748 1798
@@ -1818,8 +1868,6 @@ static grid *grid_new_snubsquare(int width, int height, const char *desc)
1818 } 1868 }
1819 1869
1820 freetree234(points); 1870 freetree234(points);
1821 assert(g->num_faces <= max_faces);
1822 assert(g->num_dots <= max_dots);
1823 1871
1824 grid_make_consistent(g); 1872 grid_make_consistent(g);
1825 return g; 1873 return g;
@@ -1830,6 +1878,18 @@ static grid *grid_new_snubsquare(int width, int height, const char *desc)
1830#define CAIRO_A 14 1878#define CAIRO_A 14
1831#define CAIRO_B 31 1879#define CAIRO_B 31
1832 1880
1881static const char *grid_validate_params_cairo(int width, int height)
1882{
1883 int b = CAIRO_B; /* a unused in determining grid size. */
1884
1885 if (width - 1 > (INT_MAX - 2*b) / (2*b) || /* xextent */
1886 height - 1 > (INT_MAX - 2*b) / (2*b) || /* yextent */
1887 width > INT_MAX / 2 / height || /* max_faces */
1888 width + 1 > INT_MAX / 3 / (height + 1)) /* max_dots */
1889 return "Grid size must not be unreasonably large";
1890 return NULL;
1891}
1892
1833static void grid_size_cairo(int width, int height, 1893static void grid_size_cairo(int width, int height,
1834 int *tilesize, int *xextent, int *yextent) 1894 int *tilesize, int *xextent, int *yextent)
1835{ 1895{
@@ -1846,16 +1906,10 @@ static grid *grid_new_cairo(int width, int height, const char *desc)
1846 int a = CAIRO_A; 1906 int a = CAIRO_A;
1847 int b = CAIRO_B; 1907 int b = CAIRO_B;
1848 1908
1849 /* Upper bounds - don't have to be exact */
1850 int max_faces = 2 * width * height;
1851 int max_dots = 3 * (width + 1) * (height + 1);
1852
1853 tree234 *points; 1909 tree234 *points;
1854 1910
1855 grid *g = grid_empty(); 1911 grid *g = grid_empty();
1856 g->tilesize = CAIRO_TILESIZE; 1912 g->tilesize = CAIRO_TILESIZE;
1857 g->faces = snewn(max_faces, grid_face);
1858 g->dots = snewn(max_dots, grid_dot);
1859 1913
1860 points = newtree234(grid_point_cmp_fn); 1914 points = newtree234(grid_point_cmp_fn);
1861 1915
@@ -1924,8 +1978,6 @@ static grid *grid_new_cairo(int width, int height, const char *desc)
1924 } 1978 }
1925 1979
1926 freetree234(points); 1980 freetree234(points);
1927 assert(g->num_faces <= max_faces);
1928 assert(g->num_dots <= max_dots);
1929 1981
1930 grid_make_consistent(g); 1982 grid_make_consistent(g);
1931 return g; 1983 return g;
@@ -1936,6 +1988,18 @@ static grid *grid_new_cairo(int width, int height, const char *desc)
1936#define GREATHEX_A 15 1988#define GREATHEX_A 15
1937#define GREATHEX_B 26 1989#define GREATHEX_B 26
1938 1990
1991static const char *grid_validate_params_greathexagonal(int width, int height)
1992{
1993 int a = GREATHEX_A;
1994 int b = GREATHEX_B;
1995
1996 if (width-1 > (INT_MAX - 4*a) / (3*a + b) || /* xextent */
1997 height-1 > (INT_MAX - (3*b + a)) / (2*a + 2*b) || /* yextent */
1998 width + 1 > INT_MAX / 6 / (height + 1)) /* max_faces */
1999 return "Grid size must not be unreasonably large";
2000 return NULL;
2001}
2002
1939static void grid_size_greathexagonal(int width, int height, 2003static void grid_size_greathexagonal(int width, int height,
1940 int *tilesize, int *xextent, int *yextent) 2004 int *tilesize, int *xextent, int *yextent)
1941{ 2005{
@@ -1953,16 +2017,10 @@ static grid *grid_new_greathexagonal(int width, int height, const char *desc)
1953 int a = GREATHEX_A; 2017 int a = GREATHEX_A;
1954 int b = GREATHEX_B; 2018 int b = GREATHEX_B;
1955 2019
1956 /* Upper bounds - don't have to be exact */
1957 int max_faces = 6 * (width + 1) * (height + 1);
1958 int max_dots = 6 * width * height;
1959
1960 tree234 *points; 2020 tree234 *points;
1961 2021
1962 grid *g = grid_empty(); 2022 grid *g = grid_empty();
1963 g->tilesize = GREATHEX_TILESIZE; 2023 g->tilesize = GREATHEX_TILESIZE;
1964 g->faces = snewn(max_faces, grid_face);
1965 g->dots = snewn(max_dots, grid_dot);
1966 2024
1967 points = newtree234(grid_point_cmp_fn); 2025 points = newtree234(grid_point_cmp_fn);
1968 2026
@@ -2054,8 +2112,6 @@ static grid *grid_new_greathexagonal(int width, int height, const char *desc)
2054 } 2112 }
2055 2113
2056 freetree234(points); 2114 freetree234(points);
2057 assert(g->num_faces <= max_faces);
2058 assert(g->num_dots <= max_dots);
2059 2115
2060 grid_make_consistent(g); 2116 grid_make_consistent(g);
2061 return g; 2117 return g;
@@ -2066,6 +2122,18 @@ static grid *grid_new_greathexagonal(int width, int height, const char *desc)
2066#define KAGOME_A 15 2122#define KAGOME_A 15
2067#define KAGOME_B 26 2123#define KAGOME_B 26
2068 2124
2125static const char *grid_validate_params_kagome(int width, int height)
2126{
2127 int a = KAGOME_A;
2128 int b = KAGOME_B;
2129
2130 if (width-1 > (INT_MAX - 6*a) / (4*a) || /* xextent */
2131 height-1 > (INT_MAX - 2*b) / (2*b) || /* yextent */
2132 width + 1 > INT_MAX / 6 / (height + 1)) /* max_faces */
2133 return "Grid size must not be unreasonably large";
2134 return NULL;
2135}
2136
2069static void grid_size_kagome(int width, int height, 2137static void grid_size_kagome(int width, int height,
2070 int *tilesize, int *xextent, int *yextent) 2138 int *tilesize, int *xextent, int *yextent)
2071{ 2139{
@@ -2083,16 +2151,10 @@ static grid *grid_new_kagome(int width, int height, const char *desc)
2083 int a = KAGOME_A; 2151 int a = KAGOME_A;
2084 int b = KAGOME_B; 2152 int b = KAGOME_B;
2085 2153
2086 /* Upper bounds - don't have to be exact */
2087 int max_faces = 6 * (width + 1) * (height + 1);
2088 int max_dots = 6 * width * height;
2089
2090 tree234 *points; 2154 tree234 *points;
2091 2155
2092 grid *g = grid_empty(); 2156 grid *g = grid_empty();
2093 g->tilesize = KAGOME_TILESIZE; 2157 g->tilesize = KAGOME_TILESIZE;
2094 g->faces = snewn(max_faces, grid_face);
2095 g->dots = snewn(max_dots, grid_dot);
2096 2158
2097 points = newtree234(grid_point_cmp_fn); 2159 points = newtree234(grid_point_cmp_fn);
2098 2160
@@ -2150,8 +2212,6 @@ static grid *grid_new_kagome(int width, int height, const char *desc)
2150 } 2212 }
2151 2213
2152 freetree234(points); 2214 freetree234(points);
2153 assert(g->num_faces <= max_faces);
2154 assert(g->num_dots <= max_dots);
2155 2215
2156 grid_make_consistent(g); 2216 grid_make_consistent(g);
2157 return g; 2217 return g;
@@ -2162,6 +2222,18 @@ static grid *grid_new_kagome(int width, int height, const char *desc)
2162#define OCTAGONAL_A 29 2222#define OCTAGONAL_A 29
2163#define OCTAGONAL_B 41 2223#define OCTAGONAL_B 41
2164 2224
2225static const char *grid_validate_params_octagonal(int width, int height)
2226{
2227 int a = OCTAGONAL_A;
2228 int b = OCTAGONAL_B;
2229
2230 if (width > INT_MAX / (2*a + b) || /* xextent */
2231 height > INT_MAX / (2*a + b) || /* yextent */
2232 height + 1 > INT_MAX / 4 / (width + 1)) /* max_dots */
2233 return "Grid size must not be unreasonably large";
2234 return NULL;
2235}
2236
2165static void grid_size_octagonal(int width, int height, 2237static void grid_size_octagonal(int width, int height,
2166 int *tilesize, int *xextent, int *yextent) 2238 int *tilesize, int *xextent, int *yextent)
2167{ 2239{
@@ -2179,16 +2251,10 @@ static grid *grid_new_octagonal(int width, int height, const char *desc)
2179 int a = OCTAGONAL_A; 2251 int a = OCTAGONAL_A;
2180 int b = OCTAGONAL_B; 2252 int b = OCTAGONAL_B;
2181 2253
2182 /* Upper bounds - don't have to be exact */
2183 int max_faces = 2 * width * height;
2184 int max_dots = 4 * (width + 1) * (height + 1);
2185
2186 tree234 *points; 2254 tree234 *points;
2187 2255
2188 grid *g = grid_empty(); 2256 grid *g = grid_empty();
2189 g->tilesize = OCTAGONAL_TILESIZE; 2257 g->tilesize = OCTAGONAL_TILESIZE;
2190 g->faces = snewn(max_faces, grid_face);
2191 g->dots = snewn(max_dots, grid_dot);
2192 2258
2193 points = newtree234(grid_point_cmp_fn); 2259 points = newtree234(grid_point_cmp_fn);
2194 2260
@@ -2233,8 +2299,6 @@ static grid *grid_new_octagonal(int width, int height, const char *desc)
2233 } 2299 }
2234 2300
2235 freetree234(points); 2301 freetree234(points);
2236 assert(g->num_faces <= max_faces);
2237 assert(g->num_dots <= max_dots);
2238 2302
2239 grid_make_consistent(g); 2303 grid_make_consistent(g);
2240 return g; 2304 return g;
@@ -2245,6 +2309,18 @@ static grid *grid_new_octagonal(int width, int height, const char *desc)
2245#define KITE_A 15 2309#define KITE_A 15
2246#define KITE_B 26 2310#define KITE_B 26
2247 2311
2312static const char *grid_validate_params_kites(int width, int height)
2313{
2314 int a = KITE_A;
2315 int b = KITE_B;
2316
2317 if (width > (INT_MAX - 2*b) / (4*b) || /* xextent */
2318 height - 1 > (INT_MAX - 8*a) / (6*a) || /* yextent */
2319 width + 1 > INT_MAX / 6 / (height + 1)) /* max_dots */
2320 return "Grid size must not be unreasonably large";
2321 return NULL;
2322}
2323
2248static void grid_size_kites(int width, int height, 2324static void grid_size_kites(int width, int height,
2249 int *tilesize, int *xextent, int *yextent) 2325 int *tilesize, int *xextent, int *yextent)
2250{ 2326{
@@ -2262,16 +2338,10 @@ static grid *grid_new_kites(int width, int height, const char *desc)
2262 int a = KITE_A; 2338 int a = KITE_A;
2263 int b = KITE_B; 2339 int b = KITE_B;
2264 2340
2265 /* Upper bounds - don't have to be exact */
2266 int max_faces = 6 * width * height;
2267 int max_dots = 6 * (width + 1) * (height + 1);
2268
2269 tree234 *points; 2341 tree234 *points;
2270 2342
2271 grid *g = grid_empty(); 2343 grid *g = grid_empty();
2272 g->tilesize = KITE_TILESIZE; 2344 g->tilesize = KITE_TILESIZE;
2273 g->faces = snewn(max_faces, grid_face);
2274 g->dots = snewn(max_dots, grid_dot);
2275 2345
2276 points = newtree234(grid_point_cmp_fn); 2346 points = newtree234(grid_point_cmp_fn);
2277 2347
@@ -2353,8 +2423,6 @@ static grid *grid_new_kites(int width, int height, const char *desc)
2353 } 2423 }
2354 2424
2355 freetree234(points); 2425 freetree234(points);
2356 assert(g->num_faces <= max_faces);
2357 assert(g->num_dots <= max_dots);
2358 2426
2359 grid_make_consistent(g); 2427 grid_make_consistent(g);
2360 return g; 2428 return g;
@@ -2367,6 +2435,20 @@ static grid *grid_new_kites(int width, int height, const char *desc)
2367#define FLORET_PX 75 2435#define FLORET_PX 75
2368#define FLORET_PY -26 2436#define FLORET_PY -26
2369 2437
2438static const char *grid_validate_params_floret(int width, int height)
2439{
2440 int px = FLORET_PX, py = FLORET_PY; /* |( 75, -26)| = 79.43 */
2441 int qx = 4*px/5, qy = -py*2; /* |( 60, 52)| = 79.40 */
2442 int ry = qy-py;
2443 /* rx unused in determining grid size. */
2444
2445 if (width - 1 > (INT_MAX - (4*qx + 2*px)) / ((6*px+3*qx)/2) ||/* xextent */
2446 height - 1 > (INT_MAX - (4*qy + 2*ry)) / (5*qy-4*py) || /* yextent */
2447 width + 1 > INT_MAX / 9 / (height + 1)) /* max_dots */
2448 return "Grid size must not be unreasonably large";
2449 return NULL;
2450}
2451
2370static void grid_size_floret(int width, int height, 2452static void grid_size_floret(int width, int height,
2371 int *tilesize, int *xextent, int *yextent) 2453 int *tilesize, int *xextent, int *yextent)
2372{ 2454{
@@ -2393,16 +2475,10 @@ static grid *grid_new_floret(int width, int height, const char *desc)
2393 int qx = 4*px/5, qy = -py*2; /* |( 60, 52)| = 79.40 */ 2475 int qx = 4*px/5, qy = -py*2; /* |( 60, 52)| = 79.40 */
2394 int rx = qx-px, ry = qy-py; /* |(-15, 78)| = 79.38 */ 2476 int rx = qx-px, ry = qy-py; /* |(-15, 78)| = 79.38 */
2395 2477
2396 /* Upper bounds - don't have to be exact */
2397 int max_faces = 6 * width * height;
2398 int max_dots = 9 * (width + 1) * (height + 1);
2399
2400 tree234 *points; 2478 tree234 *points;
2401 2479
2402 grid *g = grid_empty(); 2480 grid *g = grid_empty();
2403 g->tilesize = FLORET_TILESIZE; 2481 g->tilesize = FLORET_TILESIZE;
2404 g->faces = snewn(max_faces, grid_face);
2405 g->dots = snewn(max_dots, grid_dot);
2406 2482
2407 points = newtree234(grid_point_cmp_fn); 2483 points = newtree234(grid_point_cmp_fn);
2408 2484
@@ -2463,8 +2539,6 @@ static grid *grid_new_floret(int width, int height, const char *desc)
2463 } 2539 }
2464 2540
2465 freetree234(points); 2541 freetree234(points);
2466 assert(g->num_faces <= max_faces);
2467 assert(g->num_dots <= max_dots);
2468 2542
2469 grid_make_consistent(g); 2543 grid_make_consistent(g);
2470 return g; 2544 return g;
@@ -2476,6 +2550,18 @@ static grid *grid_new_floret(int width, int height, const char *desc)
2476#define DODEC_A 15 2550#define DODEC_A 15
2477#define DODEC_B 26 2551#define DODEC_B 26
2478 2552
2553static const char *grid_validate_params_dodecagonal(int width, int height)
2554{
2555 int a = DODEC_A;
2556 int b = DODEC_B;
2557
2558 if (width - 1 > (INT_MAX - 3*(2*a + b)) / (4*a + 2*b) || /* xextent */
2559 height - 1 > (INT_MAX - 2*(2*a + b)) / (3*a + 2*b) || /* yextent */
2560 width > INT_MAX / 14 / height) /* max_dots */
2561 return "Grid size must not be unreasonably large";
2562 return NULL;
2563}
2564
2479static void grid_size_dodecagonal(int width, int height, 2565static void grid_size_dodecagonal(int width, int height,
2480 int *tilesize, int *xextent, int *yextent) 2566 int *tilesize, int *xextent, int *yextent)
2481{ 2567{
@@ -2493,16 +2579,10 @@ static grid *grid_new_dodecagonal(int width, int height, const char *desc)
2493 int a = DODEC_A; 2579 int a = DODEC_A;
2494 int b = DODEC_B; 2580 int b = DODEC_B;
2495 2581
2496 /* Upper bounds - don't have to be exact */
2497 int max_faces = 3 * width * height;
2498 int max_dots = 14 * width * height;
2499
2500 tree234 *points; 2582 tree234 *points;
2501 2583
2502 grid *g = grid_empty(); 2584 grid *g = grid_empty();
2503 g->tilesize = DODEC_TILESIZE; 2585 g->tilesize = DODEC_TILESIZE;
2504 g->faces = snewn(max_faces, grid_face);
2505 g->dots = snewn(max_dots, grid_dot);
2506 2586
2507 points = newtree234(grid_point_cmp_fn); 2587 points = newtree234(grid_point_cmp_fn);
2508 2588
@@ -2549,13 +2629,23 @@ static grid *grid_new_dodecagonal(int width, int height, const char *desc)
2549 } 2629 }
2550 2630
2551 freetree234(points); 2631 freetree234(points);
2552 assert(g->num_faces <= max_faces);
2553 assert(g->num_dots <= max_dots);
2554 2632
2555 grid_make_consistent(g); 2633 grid_make_consistent(g);
2556 return g; 2634 return g;
2557} 2635}
2558 2636
2637static const char *grid_validate_params_greatdodecagonal(int width, int height)
2638{
2639 int a = DODEC_A;
2640 int b = DODEC_B;
2641
2642 if (width - 1 > (INT_MAX - (2*(2*a + b) + 3*a + b)) / (6*a + 2*b) ||
2643 height - 1 > (INT_MAX - 2*(2*a + b)) / (3*a + 3*b) || /* yextent */
2644 width > INT_MAX / 200 / height) /* max_dots */
2645 return "Grid size must not be unreasonably large";
2646 return NULL;
2647}
2648
2559static void grid_size_greatdodecagonal(int width, int height, 2649static void grid_size_greatdodecagonal(int width, int height,
2560 int *tilesize, int *xextent, int *yextent) 2650 int *tilesize, int *xextent, int *yextent)
2561{ 2651{
@@ -2574,16 +2664,10 @@ static grid *grid_new_greatdodecagonal(int width, int height, const char *desc)
2574 int a = DODEC_A; 2664 int a = DODEC_A;
2575 int b = DODEC_B; 2665 int b = DODEC_B;
2576 2666
2577 /* Upper bounds - don't have to be exact */
2578 int max_faces = 30 * width * height;
2579 int max_dots = 200 * width * height;
2580
2581 tree234 *points; 2667 tree234 *points;
2582 2668
2583 grid *g = grid_empty(); 2669 grid *g = grid_empty();
2584 g->tilesize = DODEC_TILESIZE; 2670 g->tilesize = DODEC_TILESIZE;
2585 g->faces = snewn(max_faces, grid_face);
2586 g->dots = snewn(max_dots, grid_dot);
2587 2671
2588 points = newtree234(grid_point_cmp_fn); 2672 points = newtree234(grid_point_cmp_fn);
2589 2673
@@ -2663,13 +2747,24 @@ static grid *grid_new_greatdodecagonal(int width, int height, const char *desc)
2663 } 2747 }
2664 2748
2665 freetree234(points); 2749 freetree234(points);
2666 assert(g->num_faces <= max_faces);
2667 assert(g->num_dots <= max_dots);
2668 2750
2669 grid_make_consistent(g); 2751 grid_make_consistent(g);
2670 return g; 2752 return g;
2671} 2753}
2672 2754
2755static const char *grid_validate_params_greatgreatdodecagonal(
2756 int width, int height)
2757{
2758 int a = DODEC_A;
2759 int b = DODEC_B;
2760
2761 if (width-1 > (INT_MAX - (2*(2*a + b) + 2*a + 2*b)) / (4*a + 4*b) ||
2762 height-1 > (INT_MAX - 2*(2*a + b)) / (6*a + 2*b) || /* yextent */
2763 width > INT_MAX / 300 / height) /* max_dots */
2764 return "Grid size must not be unreasonably large";
2765 return NULL;
2766}
2767
2673static void grid_size_greatgreatdodecagonal(int width, int height, 2768static void grid_size_greatgreatdodecagonal(int width, int height,
2674 int *tilesize, int *xextent, int *yextent) 2769 int *tilesize, int *xextent, int *yextent)
2675{ 2770{
@@ -2688,16 +2783,10 @@ static grid *grid_new_greatgreatdodecagonal(int width, int height, const char *d
2688 int a = DODEC_A; 2783 int a = DODEC_A;
2689 int b = DODEC_B; 2784 int b = DODEC_B;
2690 2785
2691 /* Upper bounds - don't have to be exact */
2692 int max_faces = 50 * width * height;
2693 int max_dots = 300 * width * height;
2694
2695 tree234 *points; 2786 tree234 *points;
2696 2787
2697 grid *g = grid_empty(); 2788 grid *g = grid_empty();
2698 g->tilesize = DODEC_TILESIZE; 2789 g->tilesize = DODEC_TILESIZE;
2699 g->faces = snewn(max_faces, grid_face);
2700 g->dots = snewn(max_dots, grid_dot);
2701 2790
2702 points = newtree234(grid_point_cmp_fn); 2791 points = newtree234(grid_point_cmp_fn);
2703 2792
@@ -2747,7 +2836,7 @@ static grid *grid_new_greatgreatdodecagonal(int width, int height, const char *d
2747 d = grid_get_dot(g, points, px + (2*a + 2*b), py - 2*a); grid_face_set_dot(g, d, 5); 2836 d = grid_get_dot(g, points, px + (2*a + 2*b), py - 2*a); grid_face_set_dot(g, d, 5);
2748 } 2837 }
2749 2838
2750 /* hexagon on bottom right of dodecagon */ 2839 /* hexagon on bottom right of dodecagon */
2751 if ((y < height - 1) && (x < width - 1 || !(y % 2))) { 2840 if ((y < height - 1) && (x < width - 1 || !(y % 2))) {
2752 grid_face_add_new(g, 6); 2841 grid_face_add_new(g, 6);
2753 d = grid_get_dot(g, points, px + (a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 0); 2842 d = grid_get_dot(g, points, px + (a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 0);
@@ -2832,29 +2921,165 @@ static grid *grid_new_greatgreatdodecagonal(int width, int height, const char *d
2832 } 2921 }
2833 2922
2834 freetree234(points); 2923 freetree234(points);
2835 assert(g->num_faces <= max_faces);
2836 assert(g->num_dots <= max_dots);
2837 2924
2838 grid_make_consistent(g); 2925 grid_make_consistent(g);
2839 return g; 2926 return g;
2840} 2927}
2841 2928
2842typedef struct setface_ctx 2929static const char *grid_validate_params_compassdodecagonal(
2930 int width, int height)
2931{
2932 int a = DODEC_A;
2933 int b = DODEC_B;
2934
2935 if (width > INT_MAX / (4*a + 2*b) || /* xextent */
2936 height > INT_MAX / (4*a + 2*b) || /* yextent */
2937 width > INT_MAX / 18 / height) /* max_dots */
2938 return "Grid must not be unreasonably large";
2939 return NULL;
2940}
2941
2942static void grid_size_compassdodecagonal(int width, int height,
2943 int *tilesize, int *xextent, int *yextent)
2944{
2945 int a = DODEC_A;
2946 int b = DODEC_B;
2947
2948 *tilesize = DODEC_TILESIZE;
2949 *xextent = (4*a + 2*b) * width;
2950 *yextent = (4*a + 2*b) * height;
2951}
2952
2953static grid *grid_new_compassdodecagonal(int width, int height, const char *desc)
2843{ 2954{
2955 int x, y;
2956 /* Vector for side of triangle - ratio is close to sqrt(3) */
2957 int a = DODEC_A;
2958 int b = DODEC_B;
2959
2960 tree234 *points;
2961
2962 grid *g = grid_empty();
2963 g->tilesize = DODEC_TILESIZE;
2964
2965 points = newtree234(grid_point_cmp_fn);
2966
2967 for (y = 0; y < height; y++) {
2968 for (x = 0; x < width; x++) {
2969 grid_dot *d;
2970 /* centre of dodecagon */
2971 int px = (4*a + 2*b) * x;
2972 int py = (4*a + 2*b) * y;
2973
2974 /* dodecagon */
2975 grid_face_add_new(g, 12);
2976 d = grid_get_dot(g, points, px + ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 0);
2977 d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 1);
2978 d = grid_get_dot(g, points, px + (2*a + b), py - ( a )); grid_face_set_dot(g, d, 2);
2979 d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 3);
2980 d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 4);
2981 d = grid_get_dot(g, points, px + ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 5);
2982 d = grid_get_dot(g, points, px - ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 6);
2983 d = grid_get_dot(g, points, px - ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 7);
2984 d = grid_get_dot(g, points, px - (2*a + b), py + ( a )); grid_face_set_dot(g, d, 8);
2985 d = grid_get_dot(g, points, px - (2*a + b), py - ( a )); grid_face_set_dot(g, d, 9);
2986 d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 10);
2987 d = grid_get_dot(g, points, px - ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 11);
2988
2989 if (x < width - 1 && y < height - 1) {
2990 /* north triangle */
2991 grid_face_add_new(g, 3);
2992 d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 0);
2993 d = grid_get_dot(g, points, px + (3*a + b), py + ( a + b)); grid_face_set_dot(g, d, 1);
2994 d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 2);
2995
2996 /* east triangle */
2997 grid_face_add_new(g, 3);
2998 d = grid_get_dot(g, points, px + (3*a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 0);
2999 d = grid_get_dot(g, points, px + (3*a + b), py + (3*a + b)); grid_face_set_dot(g, d, 1);
3000 d = grid_get_dot(g, points, px + (3*a + b), py + ( a + b)); grid_face_set_dot(g, d, 2);
3001
3002 /* south triangle */
3003 grid_face_add_new(g, 3);
3004 d = grid_get_dot(g, points, px + (3*a + b), py + (3*a + b)); grid_face_set_dot(g, d, 0);
3005 d = grid_get_dot(g, points, px + (2*a + b), py + (3*a + 2*b)); grid_face_set_dot(g, d, 1);
3006 d = grid_get_dot(g, points, px + ( a + b), py + (3*a + b)); grid_face_set_dot(g, d, 2);
3007
3008 /* west triangle */
3009 grid_face_add_new(g, 3);
3010 d = grid_get_dot(g, points, px + (a + b), py + ( a + b)); grid_face_set_dot(g, d, 0);
3011 d = grid_get_dot(g, points, px + (a + b), py + (3*a + b)); grid_face_set_dot(g, d, 1);
3012 d = grid_get_dot(g, points, px + (a ), py + (2*a + b)); grid_face_set_dot(g, d, 2);
3013
3014 /* square in center */
3015 grid_face_add_new(g, 4);
3016 d = grid_get_dot(g, points, px + (3*a + b), py + ( a + b)); grid_face_set_dot(g, d, 0);
3017 d = grid_get_dot(g, points, px + (3*a + b), py + (3*a + b)); grid_face_set_dot(g, d, 1);
3018 d = grid_get_dot(g, points, px + ( a + b), py + (3*a + b)); grid_face_set_dot(g, d, 2);
3019 d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 3);
3020 }
3021 }
3022 }
3023
3024 freetree234(points);
3025
3026 grid_make_consistent(g);
3027 return g;
3028}
3029
3030/*
3031 * Penrose tilings. For historical reasons, we support two totally
3032 * different generation algorithms: the legacy one is only supported
3033 * by grid_new_penrose, for backwards compatibility with game
3034 * descriptions generated before we switched. New grid generation uses
3035 * only the new system.
3036 */
3037
3038#define PENROSE_TILESIZE 100
3039
3040static const char *grid_validate_params_penrose(int width, int height)
3041{
3042 int l = PENROSE_TILESIZE;
3043
3044 if (width > INT_MAX / l || /* xextent */
3045 height > INT_MAX / l || /* yextent */
3046 width > INT_MAX / (3 * 3 * 4 * height)) /* max_dots */
3047 return "Grid must not be unreasonably large";
3048 return NULL;
3049}
3050
3051static void grid_size_penrose(int width, int height,
3052 int *tilesize, int *xextent, int *yextent)
3053{
3054 int l = PENROSE_TILESIZE;
3055
3056 *tilesize = l;
3057 *xextent = l * width;
3058 *yextent = l * height;
3059}
3060
3061/*
3062 * Legacy generation by selecting a patch of tiling from the expansion
3063 * of a big triangle.
3064 */
3065
3066typedef struct penrose_legacy_set_faces_ctx {
2844 int xmin, xmax, ymin, ymax; 3067 int xmin, xmax, ymin, ymax;
2845 3068
2846 grid *g; 3069 grid *g;
2847 tree234 *points; 3070 tree234 *points;
2848} setface_ctx; 3071} penrose_legacy_set_faces_ctx;
2849 3072
2850static double round_int_nearest_away(double r) 3073static double round_int_nearest_away(double r)
2851{ 3074{
2852 return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); 3075 return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5);
2853} 3076}
2854 3077
2855static int set_faces(penrose_state *state, vector *vs, int n, int depth) 3078static int penrose_legacy_set_faces(penrose_legacy_state *state, vector *vs,
3079 int n, int depth)
2856{ 3080{
2857 setface_ctx *sf_ctx = (setface_ctx *)state->ctx; 3081 penrose_legacy_set_faces_ctx *sf_ctx =
3082 (penrose_legacy_set_faces_ctx *)state->ctx;
2858 int i; 3083 int i;
2859 int xs[4], ys[4]; 3084 int xs[4], ys[4];
2860 3085
@@ -2864,7 +3089,7 @@ static int set_faces(penrose_state *state, vector *vs, int n, int depth)
2864#endif 3089#endif
2865 3090
2866 for (i = 0; i < n; i++) { 3091 for (i = 0; i < n; i++) {
2867 double tx = v_x(vs, i), ty = v_y(vs, i); 3092 double tx = penrose_legacy_vx(vs, i), ty = penrose_legacy_vy(vs, i);
2868 3093
2869 xs[i] = (int)round_int_nearest_away(tx); 3094 xs[i] = (int)round_int_nearest_away(tx);
2870 ys[i] = (int)round_int_nearest_away(ty); 3095 ys[i] = (int)round_int_nearest_away(ty);
@@ -2875,88 +3100,24 @@ static int set_faces(penrose_state *state, vector *vs, int n, int depth)
2875 3100
2876 grid_face_add_new(sf_ctx->g, n); 3101 grid_face_add_new(sf_ctx->g, n);
2877 debug(("penrose: new face l=%f gen=%d...", 3102 debug(("penrose: new face l=%f gen=%d...",
2878 penrose_side_length(state->start_size, depth), depth)); 3103 penrose_legacy_side_length(state->start_size, depth), depth));
2879 for (i = 0; i < n; i++) { 3104 for (i = 0; i < n; i++) {
2880 grid_dot *d = grid_get_dot(sf_ctx->g, sf_ctx->points, 3105 grid_dot *d = grid_get_dot(sf_ctx->g, sf_ctx->points,
2881 xs[i], ys[i]); 3106 xs[i], ys[i]);
2882 grid_face_set_dot(sf_ctx->g, d, i); 3107 grid_face_set_dot(sf_ctx->g, d, i);
2883 debug((" ... dot 0x%x (%d,%d) (was %2.2f,%2.2f)", 3108 debug((" ... dot 0x%x (%d,%d) (was %2.2f,%2.2f)",
2884 d, d->x, d->y, v_x(vs, i), v_y(vs, i))); 3109 d, d->x, d->y, penrose_legacy_vx(vs, i),
3110 penrose_legacy_vy(vs, i)));
2885 } 3111 }
2886 3112
2887 return 0; 3113 return 0;
2888} 3114}
2889 3115
2890#define PENROSE_TILESIZE 100 3116static grid *grid_new_penrose_legacy(int width, int height, int which,
2891 3117 const char *desc);
2892static void grid_size_penrose(int width, int height,
2893 int *tilesize, int *xextent, int *yextent)
2894{
2895 int l = PENROSE_TILESIZE;
2896
2897 *tilesize = l;
2898 *xextent = l * width;
2899 *yextent = l * height;
2900}
2901
2902static grid *grid_new_penrose(int width, int height, int which, const char *desc); /* forward reference */
2903
2904static char *grid_new_desc_penrose(grid_type type, int width, int height, random_state *rs)
2905{
2906 int tilesize = PENROSE_TILESIZE, startsz, depth, xoff, yoff, aoff;
2907 double outer_radius;
2908 int inner_radius;
2909 char gd[255];
2910 int which = (type == GRID_PENROSE_P2 ? PENROSE_P2 : PENROSE_P3);
2911 grid *g;
2912
2913 while (1) {
2914 /* We want to produce a random bit of penrose tiling, so we
2915 * calculate a random offset (within the patch that penrose.c
2916 * calculates for us) and an angle (multiple of 36) to rotate
2917 * the patch. */
2918
2919 penrose_calculate_size(which, tilesize, width, height,
2920 &outer_radius, &startsz, &depth);
2921
2922 /* Calculate radius of (circumcircle of) patch, subtract from
2923 * radius calculated. */
2924 inner_radius = (int)(outer_radius - sqrt(width*width + height*height));
2925
2926 /* Pick a random offset (the easy way: choose within outer
2927 * square, discarding while it's outside the circle) */
2928 do {
2929 xoff = random_upto(rs, 2*inner_radius) - inner_radius;
2930 yoff = random_upto(rs, 2*inner_radius) - inner_radius;
2931 } while (sqrt(xoff*xoff+yoff*yoff) > inner_radius);
2932
2933 aoff = random_upto(rs, 360/36) * 36;
2934
2935 debug(("grid_desc: ts %d, %dx%d patch, orad %2.2f irad %d",
2936 tilesize, width, height, outer_radius, inner_radius));
2937 debug((" -> xoff %d yoff %d aoff %d", xoff, yoff, aoff));
2938
2939 sprintf(gd, "G%d,%d,%d", xoff, yoff, aoff);
2940
2941 /*
2942 * Now test-generate our grid, to make sure it actually
2943 * produces something.
2944 */
2945 g = grid_new_penrose(width, height, which, gd);
2946 if (g) {
2947 grid_free(g);
2948 break;
2949 }
2950 /* If not, go back to the top of this while loop and try again
2951 * with a different random offset. */
2952 }
2953
2954 return dupstr(gd);
2955}
2956 3118
2957static const char *grid_validate_desc_penrose(grid_type type, 3119static const char *grid_validate_desc_penrose_legacy(
2958 int width, int height, 3120 grid_type type, int width, int height, const char *desc)
2959 const char *desc)
2960{ 3121{
2961 int tilesize = PENROSE_TILESIZE, startsz, depth, xoff, yoff, aoff, inner_radius; 3122 int tilesize = PENROSE_TILESIZE, startsz, depth, xoff, yoff, aoff, inner_radius;
2962 double outer_radius; 3123 double outer_radius;
@@ -2966,8 +3127,8 @@ static const char *grid_validate_desc_penrose(grid_type type,
2966 if (!desc) 3127 if (!desc)
2967 return "Missing grid description string."; 3128 return "Missing grid description string.";
2968 3129
2969 penrose_calculate_size(which, tilesize, width, height, 3130 penrose_legacy_calculate_size(which, tilesize, width, height,
2970 &outer_radius, &startsz, &depth); 3131 &outer_radius, &startsz, &depth);
2971 inner_radius = (int)(outer_radius - sqrt(width*width + height*height)); 3132 inner_radius = (int)(outer_radius - sqrt(width*width + height*height));
2972 3133
2973 if (sscanf(desc, "G%d,%d,%d", &xoff, &yoff, &aoff) != 3) 3134 if (sscanf(desc, "G%d,%d,%d", &xoff, &yoff, &aoff) != 3)
@@ -2982,7 +3143,7 @@ static const char *grid_validate_desc_penrose(grid_type type,
2982 * Test-generate to ensure these parameters don't end us up with 3143 * Test-generate to ensure these parameters don't end us up with
2983 * no grid at all. 3144 * no grid at all.
2984 */ 3145 */
2985 g = grid_new_penrose(width, height, which, desc); 3146 g = grid_new_penrose_legacy(width, height, which, desc);
2986 if (!g) 3147 if (!g)
2987 return "Patch coordinates do not identify a usable grid fragment"; 3148 return "Patch coordinates do not identify a usable grid fragment";
2988 grid_free(g); 3149 grid_free(g);
@@ -2990,40 +3151,30 @@ static const char *grid_validate_desc_penrose(grid_type type,
2990 return NULL; 3151 return NULL;
2991} 3152}
2992 3153
2993/* 3154static grid *grid_new_penrose_legacy(int width, int height, int which,
2994 * We're asked for a grid of a particular size, and we generate enough 3155 const char *desc)
2995 * of the tiling so we can be sure to have enough random grid from which
2996 * to pick.
2997 */
2998
2999static grid *grid_new_penrose(int width, int height, int which, const char *desc)
3000{ 3156{
3001 int max_faces, max_dots, tilesize = PENROSE_TILESIZE; 3157 int tilesize = PENROSE_TILESIZE;
3002 int xsz, ysz, xoff, yoff, aoff; 3158 int xsz, ysz, xoff, yoff, aoff;
3003 double rradius; 3159 double rradius;
3004 3160
3005 tree234 *points; 3161 tree234 *points;
3006 grid *g; 3162 grid *g;
3007 3163
3008 penrose_state ps; 3164 penrose_legacy_state ps;
3009 setface_ctx sf_ctx; 3165 penrose_legacy_set_faces_ctx sf_ctx;
3010 3166
3011 penrose_calculate_size(which, tilesize, width, height, 3167 penrose_legacy_calculate_size(which, tilesize, width, height,
3012 &rradius, &ps.start_size, &ps.max_depth); 3168 &rradius, &ps.start_size, &ps.max_depth);
3013 3169
3014 debug(("penrose: w%d h%d, tile size %d, start size %d, depth %d", 3170 debug(("penrose: w%d h%d, tile size %d, start size %d, depth %d",
3015 width, height, tilesize, ps.start_size, ps.max_depth)); 3171 width, height, tilesize, ps.start_size, ps.max_depth));
3016 3172
3017 ps.new_tile = set_faces; 3173 ps.new_tile = penrose_legacy_set_faces;
3018 ps.ctx = &sf_ctx; 3174 ps.ctx = &sf_ctx;
3019 3175
3020 max_faces = (width*3) * (height*3); /* somewhat paranoid... */
3021 max_dots = max_faces * 4; /* ditto... */
3022
3023 g = grid_empty(); 3176 g = grid_empty();
3024 g->tilesize = tilesize; 3177 g->tilesize = tilesize;
3025 g->faces = snewn(max_faces, grid_face);
3026 g->dots = snewn(max_dots, grid_dot);
3027 3178
3028 points = newtree234(grid_point_cmp_fn); 3179 points = newtree234(grid_point_cmp_fn);
3029 3180
@@ -3051,11 +3202,9 @@ static grid *grid_new_penrose(int width, int height, int which, const char *desc
3051 debug(("penrose: x range (%f --> %f), y range (%f --> %f)", 3202 debug(("penrose: x range (%f --> %f), y range (%f --> %f)",
3052 sf_ctx.xmin, sf_ctx.xmax, sf_ctx.ymin, sf_ctx.ymax)); 3203 sf_ctx.xmin, sf_ctx.xmax, sf_ctx.ymin, sf_ctx.ymax));
3053 3204
3054 penrose(&ps, which, aoff); 3205 penrose_legacy(&ps, which, aoff);
3055 3206
3056 freetree234(points); 3207 freetree234(points);
3057 assert(g->num_faces <= max_faces);
3058 assert(g->num_dots <= max_dots);
3059 3208
3060 debug(("penrose: %d faces total (equivalent to %d wide by %d high)", 3209 debug(("penrose: %d faces total (equivalent to %d wide by %d high)",
3061 g->num_faces, g->num_faces/height, g->num_faces/width)); 3210 g->num_faces, g->num_faces/height, g->num_faces/width));
@@ -3091,6 +3240,223 @@ static grid *grid_new_penrose(int width, int height, int which, const char *desc
3091 return g; 3240 return g;
3092} 3241}
3093 3242
3243/*
3244 * Combinatorial-coordinate generation.
3245 *
3246 * We receive coordinates from the generator in the form of x,y pairs
3247 * each of which is an integer combination of 1 and sqrt(5), but those
3248 * pairs have different scale units in the x and y directions. The
3249 * scale units are 1/4 for x and sin(pi/5)/2 for y, which makes their
3250 * ratio equal to 2 sin(pi/5) ~= 1.1756. We fudge that irrational
3251 * aspect ratio into a rational approximation, by simply taking a pair
3252 * of integer scale factors for the x and y dimensions; this distorts
3253 * the output tiling slightly, but the distortion is consistent, and
3254 * doesn't accumulate over a large patch of tiling, so it won't make
3255 * anything end up totally out of place.
3256 *
3257 * (However, we compute the subsequent combination of 1 and sqrt(5)
3258 * exactly, because using an approximation to sqrt(5) _could_ mean
3259 * that in a sufficiently large patch of tiling two such combinations
3260 * ended up misordered.)
3261 *
3262 * Adding to the confusion, we also flip round the x and y
3263 * coordinates, because it's slightly nicer to have vertical edges in
3264 * the tiling rather than horizontal ones. (Both for aesthetics, and
3265 * also because if two P3 thin rhombs are separated by a horizontal
3266 * line and both contain numeric clues then the clue numbers look a
3267 * bit crowded, due to digits being taller than they are wide.)
3268 *
3269 * Finally, we have different base unit sizes for the two tiling
3270 * types, because sensible sizes for the two are actually different.
3271 * Each of P2 and P3 can be subdivided into the other, via dividing
3272 * the larger triangle type in two, so that L large and S small become
3273 * L+S large and L small. In the limit, this means that you expect the
3274 * number of triangles (hence tiles) to grow by a factor of phi in
3275 * each of those subdivisions (and hence by a factor of phi^2 in a
3276 * full subdivision of P2 to a finer P2). So a sensible size ratio
3277 * between the two tilings is one that makes them fit about the same
3278 * number of tiles into the same area - and since tile area is
3279 * proportional to _square_ of length, it follows that the P2 and P3
3280 * length unit should differ by a factor of sqrt(phi).
3281 */
3282#define PENROSE_XUNIT_P2 37
3283#define PENROSE_YUNIT_P2 44
3284#define PENROSE_XUNIT_P3 30
3285#define PENROSE_YUNIT_P3 35
3286
3287struct size { int w, h; };
3288static struct size api_size_penrose(int width, int height, int which)
3289{
3290 int xunit = (which == PENROSE_P2 ? PENROSE_XUNIT_P2 : PENROSE_XUNIT_P3);
3291 int yunit = (which == PENROSE_P2 ? PENROSE_YUNIT_P2 : PENROSE_YUNIT_P3);
3292 struct size size = {
3293 width * PENROSE_TILESIZE / yunit,
3294 height * PENROSE_TILESIZE / xunit,
3295 };
3296 return size;
3297}
3298
3299static grid *grid_new_penrose(int width, int height, int which,
3300 const char *desc); /* forward reference */
3301
3302static char *grid_new_desc_penrose(grid_type type, int width, int height,
3303 random_state *rs)
3304{
3305 char *buf;
3306 struct PenrosePatchParams params;
3307 int which = (type == GRID_PENROSE_P2 ? PENROSE_P2 : PENROSE_P3);
3308 struct size size = api_size_penrose(width, height, which);
3309
3310 penrose_tiling_randomise(&params, which, size.h, size.w, rs);
3311
3312 buf = snewn(params.ncoords + 3, char);
3313 buf[0] = '0' + params.orientation;
3314 buf[1] = '0' + params.start_vertex;
3315 memcpy(buf + 2, params.coords, params.ncoords);
3316 buf[2 + params.ncoords] = '\0';
3317
3318 sfree(params.coords);
3319 return buf;
3320}
3321
3322/* Shared code between validating and reading grid descs.
3323 * Always allocates params->coords, whether or not it returns an error. */
3324static const char *grid_desc_to_penrose_params(
3325 const char *desc, int which, struct PenrosePatchParams *params)
3326{
3327 int i;
3328
3329 if (!*desc)
3330 return "empty grid description";
3331
3332 params->ncoords = strlen(desc) - 2;
3333 params->coords = snewn(params->ncoords, char);
3334
3335 {
3336 char c = desc[0];
3337 if (isdigit((unsigned char)c))
3338 params->orientation = c - '0';
3339 else
3340 return "expected digit at start of grid description";
3341
3342 c = desc[1];
3343 if (c >= '0' && c < '3')
3344 params->start_vertex = c - '0';
3345 else
3346 return "expected digit as second char of grid description";
3347 }
3348
3349 for (i = 0; i < params->ncoords; i++) {
3350 char c = desc[i+2];
3351 if (!penrose_valid_letter(c, which))
3352 return "expected tile letter in grid description";
3353 params->coords[i] = c;
3354 }
3355
3356 return NULL;
3357}
3358
3359static const char *grid_validate_desc_penrose(grid_type type,
3360 int width, int height,
3361 const char *desc)
3362{
3363 struct PenrosePatchParams params;
3364 const char *error = NULL;
3365 int which = (type == GRID_PENROSE_P2 ? PENROSE_P2 : PENROSE_P3);
3366
3367 if (!desc)
3368 return "Missing grid description string.";
3369
3370 if (*desc == 'G')
3371 return grid_validate_desc_penrose_legacy(type, width, height, desc);
3372
3373 error = grid_desc_to_penrose_params(desc, which, &params);
3374 if (!error)
3375 error = penrose_tiling_params_invalid(&params, which);
3376
3377 sfree(params.coords);
3378 return error;
3379}
3380
3381struct penrosecontext {
3382 grid *g;
3383 tree234 *points;
3384 int xunit, yunit;
3385};
3386
3387static void grid_penrose_callback(void *vctx, const int *coords)
3388{
3389 struct penrosecontext *ctx = (struct penrosecontext *)vctx;
3390 size_t i;
3391
3392 grid_face_add_new(ctx->g, 4);
3393 for (i = 0; i < 4; i++) {
3394 grid_dot *d = grid_get_dot(
3395 ctx->g, ctx->points,
3396 coords[4*i+2] * ctx->yunit + n_times_root_k(
3397 coords[4*i+3] * ctx->yunit, 5),
3398 coords[4*i+0] * ctx->xunit + n_times_root_k(
3399 coords[4*i+1] * ctx->xunit, 5));
3400 grid_face_set_dot(ctx->g, d, i);
3401 }
3402}
3403
3404static grid *grid_new_penrose(int width, int height, int which,
3405 const char *desc)
3406{
3407 struct PenrosePatchParams params;
3408 const char *error = NULL;
3409 struct penrosecontext ctx[1];
3410 struct size size;
3411
3412 if (*desc == 'G')
3413 return grid_new_penrose_legacy(width, height, which, desc);
3414
3415 error = grid_desc_to_penrose_params(desc, which, &params);
3416 assert(error == NULL && "grid_validate_desc_penrose should have failed");
3417
3418 ctx->g = grid_empty();
3419 ctx->g->tilesize = PENROSE_TILESIZE;
3420
3421 ctx->points = newtree234(grid_point_cmp_fn);
3422
3423 ctx->xunit = (which == PENROSE_P2 ? PENROSE_XUNIT_P2 : PENROSE_XUNIT_P3);
3424 ctx->yunit = (which == PENROSE_P2 ? PENROSE_YUNIT_P2 : PENROSE_YUNIT_P3);
3425
3426 size = api_size_penrose(width, height, which);
3427 penrose_tiling_generate(&params, size.h, size.w,
3428 grid_penrose_callback, ctx);
3429
3430 freetree234(ctx->points);
3431 sfree(params.coords);
3432
3433 grid_trim_vigorously(ctx->g);
3434 grid_make_consistent(ctx->g);
3435
3436 /*
3437 * Centre the grid in its originally promised rectangle.
3438 */
3439 {
3440 int w = width * PENROSE_TILESIZE, h = height * PENROSE_TILESIZE;
3441 ctx->g->lowest_x -= (w - (ctx->g->highest_x - ctx->g->lowest_x))/2;
3442 ctx->g->lowest_y -= (h - (ctx->g->highest_y - ctx->g->lowest_y))/2;
3443 ctx->g->highest_x = ctx->g->lowest_x + w;
3444 ctx->g->highest_y = ctx->g->lowest_y + h;
3445 }
3446
3447 return ctx->g;
3448}
3449
3450static const char *grid_validate_params_penrose_p2_kite(int width, int height)
3451{
3452 return grid_validate_params_penrose(width, height);
3453}
3454
3455static const char *grid_validate_params_penrose_p3_thick(int width, int height)
3456{
3457 return grid_validate_params_penrose(width, height);
3458}
3459
3094static void grid_size_penrose_p2_kite(int width, int height, 3460static void grid_size_penrose_p2_kite(int width, int height,
3095 int *tilesize, int *xextent, int *yextent) 3461 int *tilesize, int *xextent, int *yextent)
3096{ 3462{
@@ -3113,18 +3479,349 @@ static grid *grid_new_penrose_p3_thick(int width, int height, const char *desc)
3113 return grid_new_penrose(width, height, PENROSE_P3, desc); 3479 return grid_new_penrose(width, height, PENROSE_P3, desc);
3114} 3480}
3115 3481
3482#define HATS_TILESIZE 32
3483#define HATS_XSQUARELEN 4
3484#define HATS_YSQUARELEN 6
3485#define HATS_XUNIT 14
3486#define HATS_YUNIT 8
3487
3488static const char *grid_validate_params_hats(
3489 int width, int height)
3490{
3491 int l = HATS_TILESIZE;
3492
3493 if (width > INT_MAX / l || /* xextent */
3494 height > INT_MAX / l || /* yextent */
3495 width > INT_MAX / (6 * height)) /* max_dots */
3496 return "Grid must not be unreasonably large";
3497 return NULL;
3498}
3499
3500static void grid_size_hats(int width, int height,
3501 int *tilesize, int *xextent, int *yextent)
3502{
3503 *tilesize = HATS_TILESIZE;
3504 *xextent = width * HATS_XUNIT * HATS_XSQUARELEN;
3505 *yextent = height * HATS_YUNIT * HATS_YSQUARELEN;
3506}
3507
3508static char *grid_new_desc_hats(
3509 grid_type type, int width, int height, random_state *rs)
3510{
3511 char *buf, *p;
3512 size_t bufmax, i;
3513 struct HatPatchParams hp;
3514
3515 hat_tiling_randomise(&hp, width, height, rs);
3516
3517 bufmax = 3 * hp.ncoords + 2;
3518 buf = snewn(bufmax, char);
3519 p = buf;
3520 for (i = 0; i < hp.ncoords; i++) {
3521 assert(hp.coords[i] < 100); /* at most 2 digits */
3522 assert(p - buf <= bufmax-4); /* room for 2 digits, comma and NUL */
3523 p += sprintf(p, "%d,", (int)hp.coords[i]);
3524 }
3525 assert(p - buf <= bufmax-2); /* room for final letter and NUL */
3526 p[0] = hp.final_metatile;
3527 p[1] = '\0';
3528
3529 sfree(hp.coords);
3530 return buf;
3531}
3532
3533/* Shared code between validating and reading grid descs.
3534 * Always allocates hp->coords, whether or not it returns an error. */
3535static const char *grid_desc_to_hat_params(
3536 const char *desc, struct HatPatchParams *hp)
3537{
3538 size_t maxcoords;
3539 const char *p = desc;
3540
3541 maxcoords = (strlen(desc) + 1) / 2;
3542 hp->coords = snewn(maxcoords, unsigned char);
3543 hp->ncoords = 0;
3544
3545 while (isdigit((unsigned char)*p)) {
3546 const char *p_orig = p;
3547 int n = atoi(p);
3548 while (*p && isdigit((unsigned char)*p)) p++;
3549 if (*p != ',')
3550 return "expected ',' in grid description";
3551 if (p - p_orig > 2 || n > 0xFF)
3552 return "too-large coordinate in grid description";
3553 p++; /* eat the comma */
3554
3555 /* This assert should be guaranteed by the way we calculated
3556 * maxcoords, so a failure of this check is a bug in this
3557 * function, not an indication of an invalid input string */
3558 assert(hp->ncoords < maxcoords);
3559 hp->coords[hp->ncoords++] = n;
3560 }
3561
3562 if (*p == 'H' || *p == 'T' || *p == 'P' || *p == 'F')
3563 hp->final_metatile = *p;
3564 else
3565 return "invalid character in grid description";
3566
3567 return NULL;
3568}
3569
3570static const char *grid_validate_desc_hats(
3571 grid_type type, int width, int height, const char *desc)
3572{
3573 struct HatPatchParams hp;
3574 const char *error = NULL;
3575
3576 if (!desc)
3577 return "Missing grid description string.";
3578
3579 error = grid_desc_to_hat_params(desc, &hp);
3580 if (!error)
3581 error = hat_tiling_params_invalid(&hp);
3582
3583 sfree(hp.coords);
3584 return error;
3585}
3586
3587struct hatcontext {
3588 grid *g;
3589 tree234 *points;
3590};
3591
3592static void grid_hats_callback(void *vctx, size_t nvertices, int *coords)
3593{
3594 struct hatcontext *ctx = (struct hatcontext *)vctx;
3595 size_t i;
3596
3597 grid_face_add_new(ctx->g, nvertices);
3598 for (i = 0; i < nvertices; i++) {
3599 grid_dot *d = grid_get_dot(
3600 ctx->g, ctx->points,
3601 coords[2*i] * HATS_XUNIT,
3602 coords[2*i+1] * HATS_YUNIT);
3603 grid_face_set_dot(ctx->g, d, i);
3604 }
3605}
3606
3607static grid *grid_new_hats(int width, int height, const char *desc)
3608{
3609 struct HatPatchParams hp;
3610 const char *error = NULL;
3611
3612 error = grid_desc_to_hat_params(desc, &hp);
3613 assert(error == NULL && "grid_validate_desc_hats should have failed");
3614
3615 struct hatcontext ctx[1];
3616
3617 ctx->g = grid_empty();
3618 ctx->g->tilesize = HATS_TILESIZE;
3619
3620 ctx->points = newtree234(grid_point_cmp_fn);
3621
3622 hat_tiling_generate(&hp, width, height, grid_hats_callback, ctx);
3623
3624 freetree234(ctx->points);
3625 sfree(hp.coords);
3626
3627 grid_trim_vigorously(ctx->g);
3628 grid_make_consistent(ctx->g);
3629 return ctx->g;
3630}
3631
3632#define SPECTRE_TILESIZE 32
3633#define SPECTRE_SQUARELEN 7
3634#define SPECTRE_UNIT 8
3635
3636static const char *grid_validate_params_spectres(
3637 int width, int height)
3638{
3639 int l = SPECTRE_UNIT * SPECTRE_SQUARELEN;
3640
3641 if (width > INT_MAX / l || /* xextent */
3642 height > INT_MAX / l || /* yextent */
3643 width > (INT_MAX / SPECTRE_SQUARELEN /
3644 SPECTRE_SQUARELEN / height)) /* max_faces */
3645 return "Grid must not be unreasonably large";
3646 return NULL;
3647}
3648
3649static void grid_size_spectres(int width, int height,
3650 int *tilesize, int *xextent, int *yextent)
3651{
3652 *tilesize = SPECTRE_TILESIZE;
3653 *xextent = width * SPECTRE_UNIT * SPECTRE_SQUARELEN;
3654 *yextent = height * SPECTRE_UNIT * SPECTRE_SQUARELEN;
3655}
3656
3657static char *grid_new_desc_spectres(
3658 grid_type type, int width, int height, random_state *rs)
3659{
3660 char *buf;
3661 size_t i;
3662 struct SpectrePatchParams sp;
3663
3664 spectre_tiling_randomise(&sp, width * SPECTRE_SQUARELEN,
3665 height * SPECTRE_SQUARELEN, rs);
3666
3667 buf = snewn(sp.ncoords + 3, char);
3668 buf[0] = (sp.orientation < 10 ? '0' + sp.orientation :
3669 'A' + sp.orientation - 10);
3670 for (i = 0; i < sp.ncoords; i++) {
3671 assert(sp.coords[i] < 10); /* all indices are 1 digit */
3672 buf[i+1] = '0' + sp.coords[i];
3673 }
3674 buf[sp.ncoords+1] = sp.final_hex;
3675 buf[sp.ncoords+2] = '\0';
3676
3677 sfree(sp.coords);
3678 return buf;
3679}
3680
3681/* Shared code between validating and reading grid descs.
3682 * Always allocates sp->coords, whether or not it returns an error. */
3683static const char *grid_desc_to_spectre_params(
3684 const char *desc, struct SpectrePatchParams *sp)
3685{
3686 size_t i;
3687
3688 if (!*desc)
3689 return "empty grid description";
3690
3691 sp->ncoords = strlen(desc) - 2;
3692 sp->coords = snewn(sp->ncoords, unsigned char);
3693
3694 {
3695 char c = desc[0];
3696 if (isdigit((unsigned char)c))
3697 sp->orientation = c - '0';
3698 else if (c == 'A' || c == 'B')
3699 sp->orientation = 10 + c - 'A';
3700 else
3701 return "expected digit or A,B at start of grid description";
3702 }
3703
3704 for (i = 0; i < sp->ncoords; i++) {
3705 char c = desc[i+1];
3706 if (!isdigit((unsigned char)c))
3707 return "expected digit in grid description";
3708 sp->coords[i] = c - '0';
3709 }
3710
3711 sp->final_hex = desc[sp->ncoords+1];
3712
3713 return NULL;
3714}
3715
3716static const char *grid_validate_desc_spectres(
3717 grid_type type, int width, int height, const char *desc)
3718{
3719 struct SpectrePatchParams sp;
3720 const char *error = NULL;
3721
3722 if (!desc)
3723 return "Missing grid description string.";
3724
3725 error = grid_desc_to_spectre_params(desc, &sp);
3726 if (!error)
3727 error = spectre_tiling_params_invalid(&sp);
3728
3729 sfree(sp.coords);
3730 return error;
3731}
3732
3733struct spectrecontext {
3734 grid *g;
3735 tree234 *points;
3736};
3737
3738static void grid_spectres_callback(void *vctx, const int *coords)
3739{
3740 struct spectrecontext *ctx = (struct spectrecontext *)vctx;
3741 size_t i;
3742
3743 grid_face_add_new(ctx->g, SPECTRE_NVERTICES);
3744 for (i = 0; i < SPECTRE_NVERTICES; i++) {
3745 grid_dot *d = grid_get_dot(
3746 ctx->g, ctx->points,
3747 (coords[4*i+0] * SPECTRE_UNIT +
3748 n_times_root_k(coords[4*i+1] * SPECTRE_UNIT, 3)),
3749 (coords[4*i+2] * SPECTRE_UNIT +
3750 n_times_root_k(coords[4*i+3] * SPECTRE_UNIT, 3)));
3751 grid_face_set_dot(ctx->g, d, i);
3752 }
3753}
3754
3755static grid *grid_new_spectres(int width, int height, const char *desc)
3756{
3757 struct SpectrePatchParams sp;
3758 const char *error = NULL;
3759 int width2 = width * SPECTRE_SQUARELEN;
3760 int height2 = height * SPECTRE_SQUARELEN;
3761
3762 error = grid_desc_to_spectre_params(desc, &sp);
3763 assert(error == NULL && "grid_validate_desc_spectres should have failed");
3764
3765 struct spectrecontext ctx[1];
3766
3767 ctx->g = grid_empty();
3768 ctx->g->tilesize = SPECTRE_TILESIZE;
3769
3770 ctx->points = newtree234(grid_point_cmp_fn);
3771
3772 spectre_tiling_generate(&sp, width2, height2, grid_spectres_callback, ctx);
3773
3774 freetree234(ctx->points);
3775 sfree(sp.coords);
3776
3777 grid_trim_vigorously(ctx->g);
3778 grid_make_consistent(ctx->g);
3779
3780 /*
3781 * As with the Penrose tiling, we're likely to have different
3782 * sized margins due to the lack of a neat grid that this tiling
3783 * fits on. So now we know what tiles we're left with, recentre
3784 * them.
3785 */
3786 {
3787 int w = width2 * SPECTRE_UNIT, h = height2 * SPECTRE_UNIT;
3788 ctx->g->lowest_x -= (w - (ctx->g->highest_x - ctx->g->lowest_x))/2;
3789 ctx->g->lowest_y -= (h - (ctx->g->highest_y - ctx->g->lowest_y))/2;
3790 ctx->g->highest_x = ctx->g->lowest_x + w;
3791 ctx->g->highest_y = ctx->g->lowest_y + h;
3792 }
3793
3794 return ctx->g;
3795}
3796
3116/* ----------- End of grid generators ------------- */ 3797/* ----------- End of grid generators ------------- */
3117 3798
3799#define FNVAL(upper,lower) &grid_validate_params_ ## lower,
3118#define FNNEW(upper,lower) &grid_new_ ## lower, 3800#define FNNEW(upper,lower) &grid_new_ ## lower,
3119#define FNSZ(upper,lower) &grid_size_ ## lower, 3801#define FNSZ(upper,lower) &grid_size_ ## lower,
3120 3802
3803static const char *(*(grid_validate_paramses[]))(int, int) =
3804 { GRIDGEN_LIST(FNVAL) };
3121static grid *(*(grid_news[]))(int, int, const char*) = { GRIDGEN_LIST(FNNEW) }; 3805static grid *(*(grid_news[]))(int, int, const char*) = { GRIDGEN_LIST(FNNEW) };
3122static void(*(grid_sizes[]))(int, int, int*, int*, int*) = { GRIDGEN_LIST(FNSZ) }; 3806static void(*(grid_sizes[]))(int, int, int*, int*, int*) = { GRIDGEN_LIST(FNSZ) };
3123 3807
3808/* Work out if a grid can be made, and complain if not. */
3809
3810const char *grid_validate_params(grid_type type, int width, int height)
3811{
3812 if (width <= 0 || height <= 0)
3813 return "Width and height must both be positive";
3814 return grid_validate_paramses[type](width, height);
3815}
3816
3124char *grid_new_desc(grid_type type, int width, int height, random_state *rs) 3817char *grid_new_desc(grid_type type, int width, int height, random_state *rs)
3125{ 3818{
3126 if (type == GRID_PENROSE_P2 || type == GRID_PENROSE_P3) { 3819 if (type == GRID_PENROSE_P2 || type == GRID_PENROSE_P3) {
3127 return grid_new_desc_penrose(type, width, height, rs); 3820 return grid_new_desc_penrose(type, width, height, rs);
3821 } else if (type == GRID_HATS) {
3822 return grid_new_desc_hats(type, width, height, rs);
3823 } else if (type == GRID_SPECTRES) {
3824 return grid_new_desc_spectres(type, width, height, rs);
3128 } else if (type == GRID_TRIANGULAR) { 3825 } else if (type == GRID_TRIANGULAR) {
3129 return dupstr("0"); /* up-to-date version of triangular grid */ 3826 return dupstr("0"); /* up-to-date version of triangular grid */
3130 } else { 3827 } else {
@@ -3137,6 +3834,10 @@ const char *grid_validate_desc(grid_type type, int width, int height,
3137{ 3834{
3138 if (type == GRID_PENROSE_P2 || type == GRID_PENROSE_P3) { 3835 if (type == GRID_PENROSE_P2 || type == GRID_PENROSE_P3) {
3139 return grid_validate_desc_penrose(type, width, height, desc); 3836 return grid_validate_desc_penrose(type, width, height, desc);
3837 } else if (type == GRID_HATS) {
3838 return grid_validate_desc_hats(type, width, height, desc);
3839 } else if (type == GRID_SPECTRES) {
3840 return grid_validate_desc_spectres(type, width, height, desc);
3140 } else if (type == GRID_TRIANGULAR) { 3841 } else if (type == GRID_TRIANGULAR) {
3141 return grid_validate_desc_triangular(type, width, height, desc); 3842 return grid_validate_desc_triangular(type, width, height, desc);
3142 } else { 3843 } else {
diff --git a/apps/plugins/puzzles/src/grid.h b/apps/plugins/puzzles/src/grid.h
index 7ca3ff1d5f..77c8dd800f 100644
--- a/apps/plugins/puzzles/src/grid.h
+++ b/apps/plugins/puzzles/src/grid.h
@@ -33,6 +33,7 @@ typedef struct grid_edge grid_edge;
33typedef struct grid_dot grid_dot; 33typedef struct grid_dot grid_dot;
34 34
35struct grid_face { 35struct grid_face {
36 int index; /* index in grid->faces[] where this face appears */
36 int order; /* Number of edges, also the number of dots */ 37 int order; /* Number of edges, also the number of dots */
37 grid_edge **edges; /* edges around this face */ 38 grid_edge **edges; /* edges around this face */
38 grid_dot **dots; /* corners of this face */ 39 grid_dot **dots; /* corners of this face */
@@ -56,8 +57,10 @@ struct grid_face {
56struct grid_edge { 57struct grid_edge {
57 grid_dot *dot1, *dot2; 58 grid_dot *dot1, *dot2;
58 grid_face *face1, *face2; /* Use NULL for the infinite outside face */ 59 grid_face *face1, *face2; /* Use NULL for the infinite outside face */
60 int index; /* index in grid->edges[] where this edge appears */
59}; 61};
60struct grid_dot { 62struct grid_dot {
63 int index; /* index in grid->dots[] where this dot appears */
61 int order; 64 int order;
62 grid_edge **edges; 65 grid_edge **edges;
63 grid_face **faces; /* A NULL grid_face* means infinite outside face */ 66 grid_face **faces; /* A NULL grid_face* means infinite outside face */
@@ -69,11 +72,13 @@ struct grid_dot {
69 int x, y; 72 int x, y;
70}; 73};
71typedef struct grid { 74typedef struct grid {
72 /* These are (dynamically allocated) arrays of all the 75 /* Arrays of all the faces, edges, dots that are in the grid.
73 * faces, edges, dots that are in the grid. */ 76 * The arrays themselves are dynamically allocated, and so is each object
74 int num_faces; grid_face *faces; 77 * inside them. num_foo indicates the number of things actually stored,
75 int num_edges; grid_edge *edges; 78 * and size_foo indicates the allocated size of the array. */
76 int num_dots; grid_dot *dots; 79 int num_faces, size_faces; grid_face **faces;
80 int num_edges, size_edges; grid_edge **edges;
81 int num_dots, size_dots; grid_dot **dots;
77 82
78 /* Cache the bounding-box of the grid, so the drawing-code can quickly 83 /* Cache the bounding-box of the grid, so the drawing-code can quickly
79 * figure out the proper scaling to draw onto a given area. */ 84 * figure out the proper scaling to draw onto a given area. */
@@ -107,13 +112,19 @@ typedef struct grid {
107 A(DODECAGONAL,dodecagonal) \ 112 A(DODECAGONAL,dodecagonal) \
108 A(GREATDODECAGONAL,greatdodecagonal) \ 113 A(GREATDODECAGONAL,greatdodecagonal) \
109 A(GREATGREATDODECAGONAL,greatgreatdodecagonal) \ 114 A(GREATGREATDODECAGONAL,greatgreatdodecagonal) \
115 A(COMPASSDODECAGONAL,compassdodecagonal) \
110 A(PENROSE_P2,penrose_p2_kite) \ 116 A(PENROSE_P2,penrose_p2_kite) \
111 A(PENROSE_P3,penrose_p3_thick) 117 A(PENROSE_P3,penrose_p3_thick) \
118 A(HATS,hats) \
119 A(SPECTRES,spectres) \
120 /* end of list */
112 121
113#define ENUM(upper,lower) GRID_ ## upper, 122#define ENUM(upper,lower) GRID_ ## upper,
114typedef enum grid_type { GRIDGEN_LIST(ENUM) GRID_TYPE_MAX } grid_type; 123typedef enum grid_type { GRIDGEN_LIST(ENUM) GRID_TYPE_MAX } grid_type;
115#undef ENUM 124#undef ENUM
116 125
126const char *grid_validate_params(grid_type type, int width, int height);
127
117/* Free directly after use if non-NULL. Will never contain an underscore 128/* Free directly after use if non-NULL. Will never contain an underscore
118 * (so clients can safely use that as a separator). */ 129 * (so clients can safely use that as a separator). */
119char *grid_new_desc(grid_type type, int width, int height, random_state *rs); 130char *grid_new_desc(grid_type type, int width, int height, random_state *rs);
diff --git a/apps/plugins/puzzles/src/gtk.c b/apps/plugins/puzzles/src/gtk.c
index 7588ee0dc6..a40a70187f 100644
--- a/apps/plugins/puzzles/src/gtk.c
+++ b/apps/plugins/puzzles/src/gtk.c
@@ -2,6 +2,10 @@
2 * gtk.c: GTK front end for my puzzle collection. 2 * gtk.c: GTK front end for my puzzle collection.
3 */ 3 */
4 4
5#ifndef _GNU_SOURCE
6#define _GNU_SOURCE 1 /* for strcasestr */
7#endif
8
5#include <stdio.h> 9#include <stdio.h>
6#include <assert.h> 10#include <assert.h>
7#include <stdlib.h> 11#include <stdlib.h>
@@ -9,8 +13,16 @@
9#include <stdarg.h> 13#include <stdarg.h>
10#include <string.h> 14#include <string.h>
11#include <errno.h> 15#include <errno.h>
12#include <math.h> 16#ifdef NO_TGMATH_H
17# include <math.h>
18#else
19# include <tgmath.h>
20#endif
21#include <unistd.h>
13 22
23#include <fcntl.h>
24#include <sys/stat.h>
25#include <sys/types.h>
14#include <sys/time.h> 26#include <sys/time.h>
15#include <sys/resource.h> 27#include <sys/resource.h>
16 28
@@ -25,6 +37,7 @@
25#include <X11/Xatom.h> 37#include <X11/Xatom.h>
26 38
27#include "puzzles.h" 39#include "puzzles.h"
40#include "gtk.h"
28 41
29#if GTK_CHECK_VERSION(2,0,0) 42#if GTK_CHECK_VERSION(2,0,0)
30# define USE_PANGO 43# define USE_PANGO
@@ -82,7 +95,7 @@
82#ifdef DEBUGGING 95#ifdef DEBUGGING
83static FILE *debug_fp = NULL; 96static FILE *debug_fp = NULL;
84 97
85void dputs(const char *buf) 98static void dputs(const char *buf)
86{ 99{
87 if (!debug_fp) { 100 if (!debug_fp) {
88 debug_fp = fopen("debug.log", "w"); 101 debug_fp = fopen("debug.log", "w");
@@ -131,6 +144,8 @@ void fatal(const char *fmt, ...)
131 */ 144 */
132 145
133static void changed_preset(frontend *fe); 146static void changed_preset(frontend *fe);
147static void load_prefs(frontend *fe);
148static char *save_prefs(frontend *fe);
134 149
135struct font { 150struct font {
136#ifdef USE_PANGO 151#ifdef USE_PANGO
@@ -314,7 +329,7 @@ void frontend_default_colour(frontend *fe, float *output)
314 output[0] = output[1] = output[2] = 0.9F; 329 output[0] = output[1] = output[2] = 0.9F;
315} 330}
316 331
317void gtk_status_bar(void *handle, const char *text) 332static void gtk_status_bar(void *handle, const char *text)
318{ 333{
319 frontend *fe = (frontend *)handle; 334 frontend *fe = (frontend *)handle;
320 335
@@ -389,6 +404,21 @@ static void print_set_colour(frontend *fe, int colour)
389 404
390static void set_window_background(frontend *fe, int colour) 405static void set_window_background(frontend *fe, int colour)
391{ 406{
407#if GTK_CHECK_VERSION(3,0,0)
408 /* In case the user's chosen theme is dark, we should not override
409 * the background colour for the whole window as this makes the
410 * menu and status bars unreadable. This might be visible through
411 * the gtk-application-prefer-dark-theme flag or else we have to
412 * work it out from the name. */
413 gboolean dark_theme = false;
414 char *theme_name = NULL;
415 g_object_get(gtk_settings_get_default(),
416 "gtk-application-prefer-dark-theme", &dark_theme,
417 "gtk-theme-name", &theme_name,
418 NULL);
419 if (theme_name && strcasestr(theme_name, "-dark"))
420 dark_theme = true;
421 g_free(theme_name);
392#if GTK_CHECK_VERSION(3,20,0) 422#if GTK_CHECK_VERSION(3,20,0)
393 char css_buf[512]; 423 char css_buf[512];
394 sprintf(css_buf, ".background { " 424 sprintf(css_buf, ".background { "
@@ -401,23 +431,28 @@ static void set_window_background(frontend *fe, int colour)
401 if (!gtk_css_provider_load_from_data( 431 if (!gtk_css_provider_load_from_data(
402 GTK_CSS_PROVIDER(fe->css_provider), css_buf, -1, NULL)) 432 GTK_CSS_PROVIDER(fe->css_provider), css_buf, -1, NULL))
403 assert(0 && "Couldn't load CSS"); 433 assert(0 && "Couldn't load CSS");
404 gtk_style_context_add_provider( 434 if (!dark_theme) {
405 gtk_widget_get_style_context(fe->window), 435 gtk_style_context_add_provider(
406 GTK_STYLE_PROVIDER(fe->css_provider), 436 gtk_widget_get_style_context(fe->window),
407 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); 437 GTK_STYLE_PROVIDER(fe->css_provider),
438 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
439 }
408 gtk_style_context_add_provider( 440 gtk_style_context_add_provider(
409 gtk_widget_get_style_context(fe->area), 441 gtk_widget_get_style_context(fe->area),
410 GTK_STYLE_PROVIDER(fe->css_provider), 442 GTK_STYLE_PROVIDER(fe->css_provider),
411 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); 443 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
412#elif GTK_CHECK_VERSION(3,0,0) 444#else // still at least GTK 3.0 but less than 3.20
413 GdkRGBA rgba; 445 GdkRGBA rgba;
414 rgba.red = fe->colours[3*colour + 0]; 446 rgba.red = fe->colours[3*colour + 0];
415 rgba.green = fe->colours[3*colour + 1]; 447 rgba.green = fe->colours[3*colour + 1];
416 rgba.blue = fe->colours[3*colour + 2]; 448 rgba.blue = fe->colours[3*colour + 2];
417 rgba.alpha = 1.0; 449 rgba.alpha = 1.0;
418 gdk_window_set_background_rgba(gtk_widget_get_window(fe->area), &rgba); 450 gdk_window_set_background_rgba(gtk_widget_get_window(fe->area), &rgba);
419 gdk_window_set_background_rgba(gtk_widget_get_window(fe->window), &rgba); 451 if (!dark_theme)
420#else 452 gdk_window_set_background_rgba(gtk_widget_get_window(fe->window),
453 &rgba);
454#endif // GTK_CHECK_VERSION(3,20,0)
455#else // GTK 2 version comes next
421 GdkColormap *colmap; 456 GdkColormap *colmap;
422 457
423 colmap = gdk_colormap_get_system(); 458 colmap = gdk_colormap_get_system();
@@ -571,7 +606,7 @@ static void do_draw_thick_line(frontend *fe, float thickness,
571 cairo_restore(fe->cr); 606 cairo_restore(fe->cr);
572} 607}
573 608
574static void do_draw_poly(frontend *fe, int *coords, int npoints, 609static void do_draw_poly(frontend *fe, const int *coords, int npoints,
575 int fillcolour, int outlinecolour) 610 int fillcolour, int outlinecolour)
576{ 611{
577 int i; 612 int i;
@@ -832,7 +867,7 @@ static void do_draw_thick_line(frontend *fe, float thickness,
832 save.join_style); 867 save.join_style);
833} 868}
834 869
835static void do_draw_poly(frontend *fe, int *coords, int npoints, 870static void do_draw_poly(frontend *fe, const int *coords, int npoints,
836 int fillcolour, int outlinecolour) 871 int fillcolour, int outlinecolour)
837{ 872{
838 GdkPoint *points = snewn(npoints, GdkPoint); 873 GdkPoint *points = snewn(npoints, GdkPoint);
@@ -1129,7 +1164,7 @@ static void align_and_draw_text(int index, int align, int x, int y,
1129 * The exported drawing functions. 1164 * The exported drawing functions.
1130 */ 1165 */
1131 1166
1132void gtk_start_draw(void *handle) 1167static void gtk_start_draw(void *handle)
1133{ 1168{
1134 frontend *fe = (frontend *)handle; 1169 frontend *fe = (frontend *)handle;
1135 fe->bbox_l = fe->w; 1170 fe->bbox_l = fe->w;
@@ -1139,20 +1174,21 @@ void gtk_start_draw(void *handle)
1139 setup_drawing(fe); 1174 setup_drawing(fe);
1140} 1175}
1141 1176
1142void gtk_clip(void *handle, int x, int y, int w, int h) 1177static void gtk_clip(void *handle, int x, int y, int w, int h)
1143{ 1178{
1144 frontend *fe = (frontend *)handle; 1179 frontend *fe = (frontend *)handle;
1145 do_clip(fe, x, y, w, h); 1180 do_clip(fe, x, y, w, h);
1146} 1181}
1147 1182
1148void gtk_unclip(void *handle) 1183static void gtk_unclip(void *handle)
1149{ 1184{
1150 frontend *fe = (frontend *)handle; 1185 frontend *fe = (frontend *)handle;
1151 do_unclip(fe); 1186 do_unclip(fe);
1152} 1187}
1153 1188
1154void gtk_draw_text(void *handle, int x, int y, int fonttype, int fontsize, 1189static void gtk_draw_text(void *handle, int x, int y, int fonttype,
1155 int align, int colour, const char *text) 1190 int fontsize, int align, int colour,
1191 const char *text)
1156{ 1192{
1157 frontend *fe = (frontend *)handle; 1193 frontend *fe = (frontend *)handle;
1158 int i; 1194 int i;
@@ -1184,43 +1220,45 @@ void gtk_draw_text(void *handle, int x, int y, int fonttype, int fontsize,
1184 align_and_draw_text(fe, i, align, x, y, text); 1220 align_and_draw_text(fe, i, align, x, y, text);
1185} 1221}
1186 1222
1187void gtk_draw_rect(void *handle, int x, int y, int w, int h, int colour) 1223static void gtk_draw_rect(void *handle, int x, int y, int w, int h, int colour)
1188{ 1224{
1189 frontend *fe = (frontend *)handle; 1225 frontend *fe = (frontend *)handle;
1190 fe->dr_api->set_colour(fe, colour); 1226 fe->dr_api->set_colour(fe, colour);
1191 do_draw_rect(fe, x, y, w, h); 1227 do_draw_rect(fe, x, y, w, h);
1192} 1228}
1193 1229
1194void gtk_draw_line(void *handle, int x1, int y1, int x2, int y2, int colour) 1230static void gtk_draw_line(void *handle, int x1, int y1, int x2, int y2,
1231 int colour)
1195{ 1232{
1196 frontend *fe = (frontend *)handle; 1233 frontend *fe = (frontend *)handle;
1197 fe->dr_api->set_colour(fe, colour); 1234 fe->dr_api->set_colour(fe, colour);
1198 do_draw_line(fe, x1, y1, x2, y2); 1235 do_draw_line(fe, x1, y1, x2, y2);
1199} 1236}
1200 1237
1201void gtk_draw_thick_line(void *handle, float thickness, 1238static void gtk_draw_thick_line(void *handle, float thickness,
1202 float x1, float y1, float x2, float y2, int colour) 1239 float x1, float y1, float x2, float y2,
1240 int colour)
1203{ 1241{
1204 frontend *fe = (frontend *)handle; 1242 frontend *fe = (frontend *)handle;
1205 fe->dr_api->set_colour(fe, colour); 1243 fe->dr_api->set_colour(fe, colour);
1206 do_draw_thick_line(fe, thickness, x1, y1, x2, y2); 1244 do_draw_thick_line(fe, thickness, x1, y1, x2, y2);
1207} 1245}
1208 1246
1209void gtk_draw_poly(void *handle, int *coords, int npoints, 1247static void gtk_draw_poly(void *handle, const int *coords, int npoints,
1210 int fillcolour, int outlinecolour) 1248 int fillcolour, int outlinecolour)
1211{ 1249{
1212 frontend *fe = (frontend *)handle; 1250 frontend *fe = (frontend *)handle;
1213 do_draw_poly(fe, coords, npoints, fillcolour, outlinecolour); 1251 do_draw_poly(fe, coords, npoints, fillcolour, outlinecolour);
1214} 1252}
1215 1253
1216void gtk_draw_circle(void *handle, int cx, int cy, int radius, 1254static void gtk_draw_circle(void *handle, int cx, int cy, int radius,
1217 int fillcolour, int outlinecolour) 1255 int fillcolour, int outlinecolour)
1218{ 1256{
1219 frontend *fe = (frontend *)handle; 1257 frontend *fe = (frontend *)handle;
1220 do_draw_circle(fe, cx, cy, radius, fillcolour, outlinecolour); 1258 do_draw_circle(fe, cx, cy, radius, fillcolour, outlinecolour);
1221} 1259}
1222 1260
1223blitter *gtk_blitter_new(void *handle, int w, int h) 1261static blitter *gtk_blitter_new(void *handle, int w, int h)
1224{ 1262{
1225 blitter *bl = snew(blitter); 1263 blitter *bl = snew(blitter);
1226 setup_blitter(bl, w, h); 1264 setup_blitter(bl, w, h);
@@ -1229,13 +1267,13 @@ blitter *gtk_blitter_new(void *handle, int w, int h)
1229 return bl; 1267 return bl;
1230} 1268}
1231 1269
1232void gtk_blitter_free(void *handle, blitter *bl) 1270static void gtk_blitter_free(void *handle, blitter *bl)
1233{ 1271{
1234 teardown_blitter(bl); 1272 teardown_blitter(bl);
1235 sfree(bl); 1273 sfree(bl);
1236} 1274}
1237 1275
1238void gtk_blitter_save(void *handle, blitter *bl, int x, int y) 1276static void gtk_blitter_save(void *handle, blitter *bl, int x, int y)
1239{ 1277{
1240 frontend *fe = (frontend *)handle; 1278 frontend *fe = (frontend *)handle;
1241 do_blitter_save(fe, bl, x, y); 1279 do_blitter_save(fe, bl, x, y);
@@ -1243,7 +1281,7 @@ void gtk_blitter_save(void *handle, blitter *bl, int x, int y)
1243 bl->y = y; 1281 bl->y = y;
1244} 1282}
1245 1283
1246void gtk_blitter_load(void *handle, blitter *bl, int x, int y) 1284static void gtk_blitter_load(void *handle, blitter *bl, int x, int y)
1247{ 1285{
1248 frontend *fe = (frontend *)handle; 1286 frontend *fe = (frontend *)handle;
1249 if (x == BLITTER_FROMSAVED && y == BLITTER_FROMSAVED) { 1287 if (x == BLITTER_FROMSAVED && y == BLITTER_FROMSAVED) {
@@ -1253,7 +1291,7 @@ void gtk_blitter_load(void *handle, blitter *bl, int x, int y)
1253 do_blitter_load(fe, bl, x, y); 1291 do_blitter_load(fe, bl, x, y);
1254} 1292}
1255 1293
1256void gtk_draw_update(void *handle, int x, int y, int w, int h) 1294static void gtk_draw_update(void *handle, int x, int y, int w, int h)
1257{ 1295{
1258 frontend *fe = (frontend *)handle; 1296 frontend *fe = (frontend *)handle;
1259 if (fe->bbox_l > x ) fe->bbox_l = x ; 1297 if (fe->bbox_l > x ) fe->bbox_l = x ;
@@ -1262,7 +1300,7 @@ void gtk_draw_update(void *handle, int x, int y, int w, int h)
1262 if (fe->bbox_d < y+h) fe->bbox_d = y+h; 1300 if (fe->bbox_d < y+h) fe->bbox_d = y+h;
1263} 1301}
1264 1302
1265void gtk_end_draw(void *handle) 1303static void gtk_end_draw(void *handle)
1266{ 1304{
1267 frontend *fe = (frontend *)handle; 1305 frontend *fe = (frontend *)handle;
1268 1306
@@ -1286,7 +1324,8 @@ void gtk_end_draw(void *handle)
1286} 1324}
1287 1325
1288#ifdef USE_PANGO 1326#ifdef USE_PANGO
1289char *gtk_text_fallback(void *handle, const char *const *strings, int nstrings) 1327static char *gtk_text_fallback(void *handle, const char *const *strings,
1328 int nstrings)
1290{ 1329{
1291 /* 1330 /*
1292 * We assume Pango can cope with any UTF-8 likely to be emitted 1331 * We assume Pango can cope with any UTF-8 likely to be emitted
@@ -1297,18 +1336,18 @@ char *gtk_text_fallback(void *handle, const char *const *strings, int nstrings)
1297#endif 1336#endif
1298 1337
1299#ifdef USE_PRINTING 1338#ifdef USE_PRINTING
1300void gtk_begin_doc(void *handle, int pages) 1339static void gtk_begin_doc(void *handle, int pages)
1301{ 1340{
1302 frontend *fe = (frontend *)handle; 1341 frontend *fe = (frontend *)handle;
1303 gtk_print_operation_set_n_pages(fe->printop, pages); 1342 gtk_print_operation_set_n_pages(fe->printop, pages);
1304} 1343}
1305 1344
1306void gtk_begin_page(void *handle, int number) 1345static void gtk_begin_page(void *handle, int number)
1307{ 1346{
1308} 1347}
1309 1348
1310void gtk_begin_puzzle(void *handle, float xm, float xc, 1349static void gtk_begin_puzzle(void *handle, float xm, float xc,
1311 float ym, float yc, int pw, int ph, float wmm) 1350 float ym, float yc, int pw, int ph, float wmm)
1312{ 1351{
1313 frontend *fe = (frontend *)handle; 1352 frontend *fe = (frontend *)handle;
1314 double ppw, pph, pox, poy, dpmmx, dpmmy; 1353 double ppw, pph, pox, poy, dpmmx, dpmmy;
@@ -1346,27 +1385,27 @@ void gtk_begin_puzzle(void *handle, float xm, float xc,
1346 fe->hatchspace = 1.0 * pw / wmm; 1385 fe->hatchspace = 1.0 * pw / wmm;
1347} 1386}
1348 1387
1349void gtk_end_puzzle(void *handle) 1388static void gtk_end_puzzle(void *handle)
1350{ 1389{
1351 frontend *fe = (frontend *)handle; 1390 frontend *fe = (frontend *)handle;
1352 cairo_restore(fe->cr); 1391 cairo_restore(fe->cr);
1353} 1392}
1354 1393
1355void gtk_end_page(void *handle, int number) 1394static void gtk_end_page(void *handle, int number)
1356{ 1395{
1357} 1396}
1358 1397
1359void gtk_end_doc(void *handle) 1398static void gtk_end_doc(void *handle)
1360{ 1399{
1361} 1400}
1362 1401
1363void gtk_line_width(void *handle, float width) 1402static void gtk_line_width(void *handle, float width)
1364{ 1403{
1365 frontend *fe = (frontend *)handle; 1404 frontend *fe = (frontend *)handle;
1366 cairo_set_line_width(fe->cr, width); 1405 cairo_set_line_width(fe->cr, width);
1367} 1406}
1368 1407
1369void gtk_line_dotted(void *handle, bool dotted) 1408static void gtk_line_dotted(void *handle, bool dotted)
1370{ 1409{
1371 frontend *fe = (frontend *)handle; 1410 frontend *fe = (frontend *)handle;
1372 1411
@@ -1379,7 +1418,7 @@ void gtk_line_dotted(void *handle, bool dotted)
1379} 1418}
1380#endif /* USE_PRINTING */ 1419#endif /* USE_PRINTING */
1381 1420
1382const struct internal_drawing_api internal_drawing = { 1421static const struct internal_drawing_api internal_drawing = {
1383 draw_set_colour, 1422 draw_set_colour,
1384#ifdef USE_CAIRO 1423#ifdef USE_CAIRO
1385 do_draw_fill, 1424 do_draw_fill,
@@ -1388,14 +1427,14 @@ const struct internal_drawing_api internal_drawing = {
1388}; 1427};
1389 1428
1390#ifdef USE_CAIRO 1429#ifdef USE_CAIRO
1391const struct internal_drawing_api internal_printing = { 1430static const struct internal_drawing_api internal_printing = {
1392 print_set_colour, 1431 print_set_colour,
1393 do_print_fill, 1432 do_print_fill,
1394 do_print_fill_preserve, 1433 do_print_fill_preserve,
1395}; 1434};
1396#endif 1435#endif
1397 1436
1398const struct drawing_api gtk_drawing = { 1437static const struct drawing_api gtk_drawing = {
1399 gtk_draw_text, 1438 gtk_draw_text,
1400 gtk_draw_rect, 1439 gtk_draw_rect,
1401 gtk_draw_line, 1440 gtk_draw_line,
@@ -1502,13 +1541,18 @@ static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
1502 keyval = '\177'; 1541 keyval = '\177';
1503 else if ((event->keyval == 'z' || event->keyval == 'Z') && shift && ctrl) 1542 else if ((event->keyval == 'z' || event->keyval == 'Z') && shift && ctrl)
1504 keyval = UI_REDO; 1543 keyval = UI_REDO;
1544 else if (event->keyval == GDK_KEY_ISO_Left_Tab) {
1545 /* SHIFT+TAB gets special handling. Ref:
1546 * https://mail.gnome.org/archives/gtk-list/1999-August/msg00145.html */
1547 keyval = '\t' | MOD_SHFT;
1548 }
1505 else if (event->string[0] && !event->string[1]) 1549 else if (event->string[0] && !event->string[1])
1506 keyval = (unsigned char)event->string[0]; 1550 keyval = (unsigned char)event->string[0];
1507 else 1551 else
1508 keyval = -1; 1552 keyval = -1;
1509 1553
1510 if (keyval >= 0 && 1554 if (keyval >= 0 &&
1511 !midend_process_key(fe->me, 0, 0, keyval)) 1555 midend_process_key(fe->me, 0, 0, keyval) == PKR_QUIT)
1512 gtk_widget_destroy(fe->window); 1556 gtk_widget_destroy(fe->window);
1513 1557
1514 return true; 1558 return true;
@@ -1542,8 +1586,8 @@ static gint button_event(GtkWidget *widget, GdkEventButton *event,
1542 if (event->type == GDK_BUTTON_RELEASE && button >= LEFT_BUTTON) 1586 if (event->type == GDK_BUTTON_RELEASE && button >= LEFT_BUTTON)
1543 button += LEFT_RELEASE - LEFT_BUTTON; 1587 button += LEFT_RELEASE - LEFT_BUTTON;
1544 1588
1545 if (!midend_process_key(fe->me, event->x - fe->ox, 1589 if (midend_process_key(fe->me, event->x - fe->ox,
1546 event->y - fe->oy, button)) 1590 event->y - fe->oy, button) == PKR_QUIT)
1547 gtk_widget_destroy(fe->window); 1591 gtk_widget_destroy(fe->window);
1548 1592
1549 return true; 1593 return true;
@@ -1567,8 +1611,8 @@ static gint motion_event(GtkWidget *widget, GdkEventMotion *event,
1567 else 1611 else
1568 return false; /* don't even know what button! */ 1612 return false; /* don't even know what button! */
1569 1613
1570 if (!midend_process_key(fe->me, event->x - fe->ox, 1614 if (midend_process_key(fe->me, event->x - fe->ox,
1571 event->y - fe->oy, button)) 1615 event->y - fe->oy, button) == PKR_QUIT)
1572 gtk_widget_destroy(fe->window); 1616 gtk_widget_destroy(fe->window);
1573#if GTK_CHECK_VERSION(2,12,0) 1617#if GTK_CHECK_VERSION(2,12,0)
1574 gdk_event_request_motions(event); 1618 gdk_event_request_motions(event);
@@ -1649,7 +1693,7 @@ static void resize_puzzle_to_area(frontend *fe, int x, int y)
1649 1693
1650 fe->w = x; 1694 fe->w = x;
1651 fe->h = y; 1695 fe->h = y;
1652 midend_size(fe->me, &x, &y, true); 1696 midend_size(fe->me, &x, &y, true, 1.0);
1653 fe->pw = x; 1697 fe->pw = x;
1654 fe->ph = y; 1698 fe->ph = y;
1655#if GTK_CHECK_VERSION(3,10,0) 1699#if GTK_CHECK_VERSION(3,10,0)
@@ -1773,8 +1817,8 @@ static void align_label(GtkLabel *label, double x, double y)
1773} 1817}
1774 1818
1775#if GTK_CHECK_VERSION(3,0,0) 1819#if GTK_CHECK_VERSION(3,0,0)
1776bool message_box(GtkWidget *parent, const char *title, const char *msg, 1820static bool message_box(GtkWidget *parent, const char *title, const char *msg,
1777 bool centre, int type) 1821 bool centre, int type)
1778{ 1822{
1779 GtkWidget *window; 1823 GtkWidget *window;
1780 gint ret; 1824 gint ret;
@@ -1807,7 +1851,7 @@ bool message_box(GtkWidget *parent, const char *title, const char *msg,
1807 bool centre, int type) 1851 bool centre, int type)
1808{ 1852{
1809 GtkWidget *window, *hbox, *text, *button; 1853 GtkWidget *window, *hbox, *text, *button;
1810 char *titles; 1854 const char *titles;
1811 int i, def, cancel; 1855 int i, def, cancel;
1812 1856
1813 window = gtk_dialog_new(); 1857 window = gtk_dialog_new();
@@ -1868,7 +1912,7 @@ bool message_box(GtkWidget *parent, const char *title, const char *msg,
1868} 1912}
1869#endif /* GTK_CHECK_VERSION(3,0,0) */ 1913#endif /* GTK_CHECK_VERSION(3,0,0) */
1870 1914
1871void error_box(GtkWidget *parent, const char *msg) 1915static void error_box(GtkWidget *parent, const char *msg)
1872{ 1916{
1873 message_box(parent, "Error", msg, false, MB_OK); 1917 message_box(parent, "Error", msg, false, MB_OK);
1874} 1918}
@@ -1883,9 +1927,17 @@ static void config_ok_button_clicked(GtkButton *button, gpointer data)
1883 if (err) 1927 if (err)
1884 error_box(fe->cfgbox, err); 1928 error_box(fe->cfgbox, err);
1885 else { 1929 else {
1930 if (fe->cfg_which == CFG_PREFS) {
1931 char *prefs_err = save_prefs(fe);
1932 if (prefs_err) {
1933 error_box(fe->cfgbox, prefs_err);
1934 sfree(prefs_err);
1935 }
1936 }
1886 fe->cfgret = true; 1937 fe->cfgret = true;
1887 gtk_widget_destroy(fe->cfgbox); 1938 gtk_widget_destroy(fe->cfgbox);
1888 changed_preset(fe); 1939 if (fe->cfg_which != CFG_PREFS)
1940 changed_preset(fe);
1889 } 1941 }
1890} 1942}
1891 1943
@@ -2163,7 +2215,7 @@ static void menu_key_event(GtkMenuItem *menuitem, gpointer data)
2163 frontend *fe = (frontend *)data; 2215 frontend *fe = (frontend *)data;
2164 int key = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem), 2216 int key = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem),
2165 "user-data")); 2217 "user-data"));
2166 if (!midend_process_key(fe->me, 0, 0, key)) 2218 if (midend_process_key(fe->me, 0, 0, key) == PKR_QUIT)
2167 gtk_widget_destroy(fe->window); 2219 gtk_widget_destroy(fe->window);
2168} 2220}
2169 2221
@@ -2185,7 +2237,7 @@ static void get_size(frontend *fe, int *px, int *py)
2185 */ 2237 */
2186 x = INT_MAX; 2238 x = INT_MAX;
2187 y = INT_MAX; 2239 y = INT_MAX;
2188 midend_size(fe->me, &x, &y, false); 2240 midend_size(fe->me, &x, &y, false, 1.0);
2189 *px = x; 2241 *px = x;
2190 *py = y; 2242 *py = y;
2191} 2243}
@@ -2362,8 +2414,8 @@ static void menu_preset_event(GtkMenuItem *menuitem, gpointer data)
2362 midend_redraw(fe->me); 2414 midend_redraw(fe->me);
2363} 2415}
2364 2416
2365GdkAtom compound_text_atom, utf8_string_atom; 2417static GdkAtom compound_text_atom, utf8_string_atom;
2366bool paste_initialised = false; 2418static bool paste_initialised = false;
2367 2419
2368static void set_selection(frontend *fe, GdkAtom selection) 2420static void set_selection(frontend *fe, GdkAtom selection)
2369{ 2421{
@@ -2380,16 +2432,16 @@ static void set_selection(frontend *fe, GdkAtom selection)
2380 * COMPOUND_TEXT or UTF8_STRING. 2432 * COMPOUND_TEXT or UTF8_STRING.
2381 */ 2433 */
2382 2434
2383 if (gtk_selection_owner_set(fe->area, selection, CurrentTime)) { 2435 if (gtk_selection_owner_set(fe->window, selection, CurrentTime)) {
2384 gtk_selection_clear_targets(fe->area, selection); 2436 gtk_selection_clear_targets(fe->window, selection);
2385 gtk_selection_add_target(fe->area, selection, 2437 gtk_selection_add_target(fe->window, selection,
2386 GDK_SELECTION_TYPE_STRING, 1); 2438 GDK_SELECTION_TYPE_STRING, 1);
2387 gtk_selection_add_target(fe->area, selection, compound_text_atom, 1); 2439 gtk_selection_add_target(fe->window, selection, compound_text_atom, 1);
2388 gtk_selection_add_target(fe->area, selection, utf8_string_atom, 1); 2440 gtk_selection_add_target(fe->window, selection, utf8_string_atom, 1);
2389 } 2441 }
2390} 2442}
2391 2443
2392void write_clip(frontend *fe, char *data) 2444static void write_clip(frontend *fe, char *data)
2393{ 2445{
2394 if (fe->paste_data) 2446 if (fe->paste_data)
2395 sfree(fe->paste_data); 2447 sfree(fe->paste_data);
@@ -2401,16 +2453,16 @@ void write_clip(frontend *fe, char *data)
2401 set_selection(fe, GDK_SELECTION_CLIPBOARD); 2453 set_selection(fe, GDK_SELECTION_CLIPBOARD);
2402} 2454}
2403 2455
2404void selection_get(GtkWidget *widget, GtkSelectionData *seldata, 2456static void selection_get(GtkWidget *widget, GtkSelectionData *seldata,
2405 guint info, guint time_stamp, gpointer data) 2457 guint info, guint time_stamp, gpointer data)
2406{ 2458{
2407 frontend *fe = (frontend *)data; 2459 frontend *fe = (frontend *)data;
2408 gtk_selection_data_set(seldata, gtk_selection_data_get_target(seldata), 8, 2460 gtk_selection_data_set(seldata, gtk_selection_data_get_target(seldata), 8,
2409 fe->paste_data, fe->paste_data_len); 2461 fe->paste_data, fe->paste_data_len);
2410} 2462}
2411 2463
2412gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata, 2464static gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata,
2413 gpointer data) 2465 gpointer data)
2414{ 2466{
2415 frontend *fe = (frontend *)data; 2467 frontend *fe = (frontend *)data;
2416 2468
@@ -2508,7 +2560,7 @@ static char *file_selector(frontend *fe, const char *title, bool save)
2508#endif 2560#endif
2509 2561
2510#ifdef USE_PRINTING 2562#ifdef USE_PRINTING
2511GObject *create_print_widget(GtkPrintOperation *print, gpointer data) 2563static GObject *create_print_widget(GtkPrintOperation *print, gpointer data)
2512{ 2564{
2513 GtkLabel *count_label, *width_label, *height_label, 2565 GtkLabel *count_label, *width_label, *height_label,
2514 *scale_llabel, *scale_rlabel; 2566 *scale_llabel, *scale_rlabel;
@@ -2649,8 +2701,8 @@ GObject *create_print_widget(GtkPrintOperation *print, gpointer data)
2649 return G_OBJECT(grid); 2701 return G_OBJECT(grid);
2650} 2702}
2651 2703
2652void apply_print_widget(GtkPrintOperation *print, 2704static void apply_print_widget(GtkPrintOperation *print,
2653 GtkWidget *widget, gpointer data) 2705 GtkWidget *widget, gpointer data)
2654{ 2706{
2655 frontend *fe = (frontend *)data; 2707 frontend *fe = (frontend *)data;
2656 2708
@@ -2673,8 +2725,8 @@ void apply_print_widget(GtkPrintOperation *print,
2673 } 2725 }
2674} 2726}
2675 2727
2676void print_begin(GtkPrintOperation *printop, 2728static void print_begin(GtkPrintOperation *printop,
2677 GtkPrintContext *context, gpointer data) 2729 GtkPrintContext *context, gpointer data)
2678{ 2730{
2679 frontend *fe = (frontend *)data; 2731 frontend *fe = (frontend *)data;
2680 midend *nme = NULL; /* non-interactive midend for bulk puzzle generation */ 2732 midend *nme = NULL; /* non-interactive midend for bulk puzzle generation */
@@ -2708,6 +2760,8 @@ void print_begin(GtkPrintOperation *printop,
2708 thegame.free_params(params); 2760 thegame.free_params(params);
2709 } 2761 }
2710 2762
2763 load_prefs(fe);
2764
2711 midend_new_game(nme); 2765 midend_new_game(nme);
2712 err = midend_print_puzzle(nme, fe->doc, fe->printsolns); 2766 err = midend_print_puzzle(nme, fe->doc, fe->printsolns);
2713 } 2767 }
@@ -2725,16 +2779,16 @@ void print_begin(GtkPrintOperation *printop,
2725 document_begin(fe->doc, fe->print_dr); 2779 document_begin(fe->doc, fe->print_dr);
2726} 2780}
2727 2781
2728void draw_page(GtkPrintOperation *printop, 2782static void draw_page(GtkPrintOperation *printop,
2729 GtkPrintContext *context, 2783 GtkPrintContext *context,
2730 gint page_nr, gpointer data) 2784 gint page_nr, gpointer data)
2731{ 2785{
2732 frontend *fe = (frontend *)data; 2786 frontend *fe = (frontend *)data;
2733 document_print_page(fe->doc, fe->print_dr, page_nr); 2787 document_print_page(fe->doc, fe->print_dr, page_nr);
2734} 2788}
2735 2789
2736void print_end(GtkPrintOperation *printop, 2790static void print_end(GtkPrintOperation *printop,
2737 GtkPrintContext *context, gpointer data) 2791 GtkPrintContext *context, gpointer data)
2738{ 2792{
2739 frontend *fe = (frontend *)data; 2793 frontend *fe = (frontend *)data;
2740 2794
@@ -2919,6 +2973,206 @@ static void menu_load_event(GtkMenuItem *menuitem, gpointer data)
2919 } 2973 }
2920} 2974}
2921 2975
2976static char *prefs_dir(void)
2977{
2978 const char *var;
2979 if ((var = getenv("SGT_PUZZLES_DIR")) != NULL)
2980 return dupstr(var);
2981 if ((var = getenv("XDG_CONFIG_HOME")) != NULL) {
2982 size_t size = strlen(var) + 20;
2983 char *dir = snewn(size, char);
2984 sprintf(dir, "%s/sgt-puzzles", var);
2985 return dir;
2986 }
2987 if ((var = getenv("HOME")) != NULL) {
2988 size_t size = strlen(var) + 32;
2989 char *dir = snewn(size, char);
2990 sprintf(dir, "%s/.config/sgt-puzzles", var);
2991 return dir;
2992 }
2993 return NULL;
2994}
2995
2996static char *prefs_path_general(const game *game, const char *suffix)
2997{
2998 char *dir, *path;
2999
3000 dir = prefs_dir();
3001 if (!dir)
3002 return NULL;
3003
3004 path = make_prefs_path(dir, "/", game, suffix);
3005
3006 sfree(dir);
3007 return path;
3008}
3009
3010static char *prefs_path(const game *game)
3011{
3012 return prefs_path_general(game, ".conf");
3013}
3014
3015static char *prefs_tmp_path(const game *game)
3016{
3017 return prefs_path_general(game, ".conf.tmp");
3018}
3019
3020static void load_prefs(frontend *fe)
3021{
3022 const game *game = midend_which_game(fe->me);
3023 char *path = prefs_path(game);
3024 if (!path)
3025 return;
3026 FILE *fp = fopen(path, "r");
3027 if (!fp)
3028 return;
3029 const char *err = midend_load_prefs(fe->me, savefile_read, fp);
3030 fclose(fp);
3031 if (err)
3032 fprintf(stderr, "Unable to load preferences file %s:\n%s\n",
3033 path, err);
3034 sfree(path);
3035}
3036
3037static char *save_prefs(frontend *fe)
3038{
3039 const game *game = midend_which_game(fe->me);
3040 char *dir_path = prefs_dir();
3041 char *file_path = prefs_path(game);
3042 char *tmp_path = prefs_tmp_path(game);
3043 struct savefile_write_ctx wctx[1];
3044 int fd;
3045 bool cleanup_dir = false, cleanup_tmpfile = false;
3046 char *err = NULL;
3047
3048 if (!dir_path || !file_path || !tmp_path) {
3049 sprintf(err = snewn(256, char),
3050 "Unable to save preferences:\n"
3051 "Could not determine pathname for configuration files");
3052 goto out;
3053 }
3054
3055 if (mkdir(dir_path, 0777) < 0) {
3056 /* Ignore errors while trying to make the directory. It may
3057 * well already exist, and even if we got some error code
3058 * other than EEXIST, it's still worth at least _trying_ to
3059 * make the file inside it, and see if that goes wrong. */
3060 } else {
3061 cleanup_dir = true;
3062 }
3063
3064 fd = open(tmp_path, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666);
3065 if (fd < 0) {
3066 const char *os_err = strerror(errno);
3067 sprintf(err = snewn(256 + strlen(tmp_path) + strlen(os_err), char),
3068 "Unable to save preferences:\n"
3069 "Unable to create file '%s': %s", tmp_path, os_err);
3070 goto out;
3071 } else {
3072 cleanup_tmpfile = true;
3073 }
3074
3075 wctx->error = 0;
3076 wctx->fp = fdopen(fd, "w");
3077 midend_save_prefs(fe->me, savefile_write, wctx);
3078 fclose(wctx->fp);
3079 if (wctx->error) {
3080 const char *os_err = strerror(wctx->error);
3081 sprintf(err = snewn(80 + strlen(tmp_path) + strlen(os_err), char),
3082 "Unable to write file '%s': %s", tmp_path, os_err);
3083 goto out;
3084 }
3085
3086 if (rename(tmp_path, file_path) < 0) {
3087 const char *os_err = strerror(errno);
3088 sprintf(err = snewn(256 + strlen(tmp_path) + strlen(file_path) +
3089 strlen(os_err), char),
3090 "Unable to save preferences:\n"
3091 "Unable to rename '%s' to '%s': %s", tmp_path, file_path,
3092 os_err);
3093 goto out;
3094 } else {
3095 cleanup_dir = false;
3096 cleanup_tmpfile = false;
3097 }
3098
3099 out:
3100 if (cleanup_tmpfile) {
3101 if (unlink(tmp_path) < 0) { /* can't do anything about this */ }
3102 }
3103 if (cleanup_dir) {
3104 if (rmdir(dir_path) < 0) { /* can't do anything about this */ }
3105 }
3106 sfree(dir_path);
3107 sfree(file_path);
3108 sfree(tmp_path);
3109 return err;
3110}
3111
3112static bool delete_prefs(const game *game, char **msg)
3113{
3114 char *dir_path = prefs_dir();
3115 char *file_path = prefs_path(game);
3116 char *tmp_path = prefs_tmp_path(game);
3117 char *msgs[3];
3118 int i, len, nmsgs = 0;
3119 char *p;
3120 bool ok = true;
3121
3122 if (unlink(file_path) == 0) {
3123 sprintf(msgs[nmsgs++] = snewn(256 + strlen(file_path), char),
3124 "Removed preferences file %s\n", file_path);
3125 } else if (errno != ENOENT) {
3126 const char *os_err = strerror(errno);
3127 sprintf(msgs[nmsgs++] = snewn(256 + strlen(file_path) + strlen(os_err),
3128 char),
3129 "Failed to remove preferences file %s: %s\n",
3130 file_path, os_err);
3131 ok = false;
3132 }
3133
3134 if (unlink(tmp_path) == 0) {
3135 sprintf(msgs[nmsgs++] = snewn(256 + strlen(tmp_path), char),
3136 "Removed temporary file %s\n", tmp_path);
3137 } else if (errno != ENOENT) {
3138 const char *os_err = strerror(errno);
3139 sprintf(msgs[nmsgs++] = snewn(256 + strlen(tmp_path) + strlen(os_err),
3140 char),
3141 "Failed to remove temporary file %s: %s\n", tmp_path, os_err);
3142 ok = false;
3143 }
3144
3145 if (rmdir(dir_path) == 0) {
3146 sprintf(msgs[nmsgs++] = snewn(256 + strlen(dir_path), char),
3147 "Removed empty preferences directory %s\n", dir_path);
3148 } else if (errno != ENOENT && errno != ENOTEMPTY) {
3149 const char *os_err = strerror(errno);
3150 sprintf(msgs[nmsgs++] = snewn(256 + strlen(dir_path) + strlen(os_err),
3151 char),
3152 "Failed to remove preferences directory %s: %s\n",
3153 dir_path, os_err);
3154 ok = false;
3155 }
3156
3157 for (i = len = 0; i < nmsgs; i++)
3158 len += strlen(msgs[i]);
3159 *msg = snewn(len + 1, char);
3160 p = *msg;
3161 for (i = len = 0; i < nmsgs; i++) {
3162 size_t len = strlen(msgs[i]);
3163 memcpy(p, msgs[i], len);
3164 p += len;
3165 sfree(msgs[i]);
3166 }
3167 *p = '\0';
3168
3169 sfree(dir_path);
3170 sfree(file_path);
3171 sfree(tmp_path);
3172
3173 return ok;
3174}
3175
2922#ifdef USE_PRINTING 3176#ifdef USE_PRINTING
2923static void menu_print_event(GtkMenuItem *menuitem, gpointer data) 3177static void menu_print_event(GtkMenuItem *menuitem, gpointer data)
2924{ 3178{
@@ -2960,11 +3214,85 @@ static void menu_config_event(GtkMenuItem *menuitem, gpointer data)
2960 if (!get_config(fe, which)) 3214 if (!get_config(fe, which))
2961 return; 3215 return;
2962 3216
2963 midend_new_game(fe->me); 3217 if (which != CFG_PREFS)
3218 midend_new_game(fe->me);
3219
2964 resize_fe(fe); 3220 resize_fe(fe);
2965 midend_redraw(fe->me); 3221 midend_redraw(fe->me);
2966} 3222}
2967 3223
3224#ifndef HELP_BROWSER_PATH
3225#define HELP_BROWSER_PATH "xdg-open:sensible-browser:$BROWSER"
3226#endif
3227
3228static bool try_show_help(const char *browser, const char *help_name)
3229{
3230 const char *argv[3] = { browser, help_name, NULL };
3231
3232 return g_spawn_async(NULL, (char **)argv, NULL,
3233 G_SPAWN_SEARCH_PATH,
3234 NULL, NULL, NULL, NULL);
3235}
3236
3237static void show_help(frontend *fe, const char *topic)
3238{
3239 char *path = dupstr(HELP_BROWSER_PATH);
3240 char *path_entry;
3241 char *help_name;
3242 size_t help_name_size;
3243 bool succeeded = true;
3244
3245 help_name_size = strlen(HELP_DIR) + 4 + strlen(topic) + 6;
3246 help_name = snewn(help_name_size, char);
3247 sprintf(help_name, "%s/en/%s.html",
3248 HELP_DIR, topic);
3249
3250 if (access(help_name, R_OK)) {
3251 error_box(fe->window, "Help file is not installed");
3252 sfree(path);
3253 sfree(help_name);
3254 return;
3255 }
3256
3257 path_entry = path;
3258 for (;;) {
3259 size_t len;
3260 bool last;
3261
3262 len = strcspn(path_entry, ":");
3263 last = path_entry[len] == 0;
3264 path_entry[len] = 0;
3265
3266 if (path_entry[0] == '$') {
3267 const char *command = getenv(path_entry + 1);
3268
3269 if (command)
3270 succeeded = try_show_help(command, help_name);
3271 } else {
3272 succeeded = try_show_help(path_entry, help_name);
3273 }
3274
3275 if (last || succeeded)
3276 break;
3277 path_entry += len + 1;
3278 }
3279
3280 if (!succeeded)
3281 error_box(fe->window, "Failed to start a help browser");
3282 sfree(path);
3283 sfree(help_name);
3284}
3285
3286static void menu_help_contents_event(GtkMenuItem *menuitem, gpointer data)
3287{
3288 show_help((frontend *)data, "index");
3289}
3290
3291static void menu_help_specific_event(GtkMenuItem *menuitem, gpointer data)
3292{
3293 show_help((frontend *)data, thegame.htmlhelp_topic);
3294}
3295
2968static void menu_about_event(GtkMenuItem *menuitem, gpointer data) 3296static void menu_about_event(GtkMenuItem *menuitem, gpointer data)
2969{ 3297{
2970 frontend *fe = (frontend *)data; 3298 frontend *fe = (frontend *)data;
@@ -2975,12 +3303,9 @@ static void menu_about_event(GtkMenuItem *menuitem, gpointer data)
2975 "version", ver, \ 3303 "version", ver, \
2976 "comments", "Part of Simon Tatham's Portable Puzzle Collection" 3304 "comments", "Part of Simon Tatham's Portable Puzzle Collection"
2977 3305
2978 extern char *const *const xpm_icons[];
2979 extern const int n_xpm_icons;
2980
2981 if (n_xpm_icons) { 3306 if (n_xpm_icons) {
2982 GdkPixbuf *icon = gdk_pixbuf_new_from_xpm_data 3307 GdkPixbuf *icon = gdk_pixbuf_new_from_xpm_data
2983 ((const gchar **)xpm_icons[n_xpm_icons-1]); 3308 ((const gchar **)xpm_icons[0]);
2984 3309
2985 gtk_show_about_dialog 3310 gtk_show_about_dialog
2986 (GTK_WINDOW(fe->window), 3311 (GTK_WINDOW(fe->window),
@@ -3092,8 +3417,6 @@ static frontend *new_window(
3092 GList *iconlist; 3417 GList *iconlist;
3093 int x, y, n; 3418 int x, y, n;
3094 char errbuf[1024]; 3419 char errbuf[1024];
3095 extern char *const *const xpm_icons[];
3096 extern const int n_xpm_icons;
3097 struct preset_menu *preset_menu; 3420 struct preset_menu *preset_menu;
3098 3421
3099 fe = snew(frontend); 3422 fe = snew(frontend);
@@ -3113,6 +3436,7 @@ static frontend *new_window(
3113 fe->timer_id = -1; 3436 fe->timer_id = -1;
3114 3437
3115 fe->me = midend_new(fe, &thegame, &gtk_drawing, fe); 3438 fe->me = midend_new(fe, &thegame, &gtk_drawing, fe);
3439 load_prefs(fe);
3116 3440
3117 fe->dr_api = &internal_drawing; 3441 fe->dr_api = &internal_drawing;
3118 3442
@@ -3376,6 +3700,16 @@ static frontend *new_window(
3376 G_CALLBACK(menu_solve_event), fe); 3700 G_CALLBACK(menu_solve_event), fe);
3377 gtk_widget_show(menuitem); 3701 gtk_widget_show(menuitem);
3378 } 3702 }
3703
3704 add_menu_separator(GTK_CONTAINER(menu));
3705 menuitem = gtk_menu_item_new_with_label("Preferences...");
3706 gtk_container_add(GTK_CONTAINER(menu), menuitem);
3707 g_object_set_data(G_OBJECT(menuitem), "user-data",
3708 GINT_TO_POINTER(CFG_PREFS));
3709 g_signal_connect(G_OBJECT(menuitem), "activate",
3710 G_CALLBACK(menu_config_event), fe);
3711 gtk_widget_show(menuitem);
3712
3379 add_menu_separator(GTK_CONTAINER(menu)); 3713 add_menu_separator(GTK_CONTAINER(menu));
3380 add_menu_ui_item(fe, GTK_CONTAINER(menu), "Exit", UI_QUIT, 'q', 0); 3714 add_menu_ui_item(fe, GTK_CONTAINER(menu), "Exit", UI_QUIT, 'q', 0);
3381 3715
@@ -3386,6 +3720,25 @@ static frontend *new_window(
3386 menu = gtk_menu_new(); 3720 menu = gtk_menu_new();
3387 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu); 3721 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
3388 3722
3723 menuitem = gtk_menu_item_new_with_label("Contents");
3724 gtk_container_add(GTK_CONTAINER(menu), menuitem);
3725 g_signal_connect(G_OBJECT(menuitem), "activate",
3726 G_CALLBACK(menu_help_contents_event), fe);
3727 gtk_widget_show(menuitem);
3728
3729 if (thegame.htmlhelp_topic) {
3730 char *item;
3731 assert(thegame.name);
3732 item = snewn(9 + strlen(thegame.name), char);
3733 sprintf(item, "Help on %s", thegame.name);
3734 menuitem = gtk_menu_item_new_with_label(item);
3735 sfree(item);
3736 gtk_container_add(GTK_CONTAINER(menu), menuitem);
3737 g_signal_connect(G_OBJECT(menuitem), "activate",
3738 G_CALLBACK(menu_help_specific_event), fe);
3739 gtk_widget_show(menuitem);
3740 }
3741
3389 menuitem = gtk_menu_item_new_with_label("About"); 3742 menuitem = gtk_menu_item_new_with_label("About");
3390 gtk_container_add(GTK_CONTAINER(menu), menuitem); 3743 gtk_container_add(GTK_CONTAINER(menu), menuitem);
3391 g_signal_connect(G_OBJECT(menuitem), "activate", 3744 g_signal_connect(G_OBJECT(menuitem), "activate",
@@ -3503,9 +3856,9 @@ static frontend *new_window(
3503 G_CALLBACK(button_event), fe); 3856 G_CALLBACK(button_event), fe);
3504 g_signal_connect(G_OBJECT(fe->area), "motion_notify_event", 3857 g_signal_connect(G_OBJECT(fe->area), "motion_notify_event",
3505 G_CALLBACK(motion_event), fe); 3858 G_CALLBACK(motion_event), fe);
3506 g_signal_connect(G_OBJECT(fe->area), "selection_get", 3859 g_signal_connect(G_OBJECT(fe->window), "selection_get",
3507 G_CALLBACK(selection_get), fe); 3860 G_CALLBACK(selection_get), fe);
3508 g_signal_connect(G_OBJECT(fe->area), "selection_clear_event", 3861 g_signal_connect(G_OBJECT(fe->window), "selection_clear_event",
3509 G_CALLBACK(selection_clear), fe); 3862 G_CALLBACK(selection_clear), fe);
3510#if GTK_CHECK_VERSION(3,0,0) 3863#if GTK_CHECK_VERSION(3,0,0)
3511 g_signal_connect(G_OBJECT(fe->area), "draw", 3864 g_signal_connect(G_OBJECT(fe->area), "draw",
@@ -3534,7 +3887,7 @@ static frontend *new_window(
3534 if (n_xpm_icons) { 3887 if (n_xpm_icons) {
3535 gtk_window_set_icon(GTK_WINDOW(fe->window), 3888 gtk_window_set_icon(GTK_WINDOW(fe->window),
3536 gdk_pixbuf_new_from_xpm_data 3889 gdk_pixbuf_new_from_xpm_data
3537 ((const gchar **)xpm_icons[0])); 3890 ((const gchar **)xpm_icons[n_xpm_icons-1]));
3538 3891
3539 iconlist = NULL; 3892 iconlist = NULL;
3540 for (n = 0; n < n_xpm_icons; n++) { 3893 for (n = 0; n < n_xpm_icons; n++) {
@@ -3578,10 +3931,10 @@ static void list_presets_from_menu(struct preset_menu *menu)
3578int main(int argc, char **argv) 3931int main(int argc, char **argv)
3579{ 3932{
3580 char *pname = argv[0]; 3933 char *pname = argv[0];
3581 char *error;
3582 int ngenerate = 0, px = 1, py = 1; 3934 int ngenerate = 0, px = 1, py = 1;
3583 bool print = false; 3935 bool print = false;
3584 bool time_generation = false, test_solve = false, list_presets = false; 3936 bool time_generation = false, test_solve = false, list_presets = false;
3937 bool delete_prefs_action = false;
3585 bool soln = false, colour = false; 3938 bool soln = false, colour = false;
3586 float scale = 1.0F; 3939 float scale = 1.0F;
3587 float redo_proportion = 0.0F; 3940 float redo_proportion = 0.0F;
@@ -3640,6 +3993,9 @@ int main(int argc, char **argv)
3640 test_solve = true; 3993 test_solve = true;
3641 } else if (doing_opts && !strcmp(p, "--list-presets")) { 3994 } else if (doing_opts && !strcmp(p, "--list-presets")) {
3642 list_presets = true; 3995 list_presets = true;
3996 } else if (doing_opts && (!strcmp(p, "--delete-prefs") ||
3997 !strcmp(p, "--delete-preferences"))) {
3998 delete_prefs_action = true;
3643 } else if (doing_opts && !strcmp(p, "--save")) { 3999 } else if (doing_opts && !strcmp(p, "--save")) {
3644 if (--ac > 0) { 4000 if (--ac > 0) {
3645 savefile = *++av; 4001 savefile = *++av;
@@ -3988,9 +4344,20 @@ int main(int argc, char **argv)
3988 list_presets_from_menu(menu); 4344 list_presets_from_menu(menu);
3989 midend_free(me); 4345 midend_free(me);
3990 return 0; 4346 return 0;
4347 } else if (delete_prefs_action) {
4348 char *msg = NULL;
4349 bool ok = delete_prefs(&thegame, &msg);
4350 if (!ok) {
4351 fputs(msg, stderr);
4352 return 1;
4353 } else {
4354 fputs(msg, stdout);
4355 return 0;
4356 }
3991 } else { 4357 } else {
3992 frontend *fe; 4358 frontend *fe;
3993 bool headless = screenshot_file != NULL; 4359 bool headless = screenshot_file != NULL;
4360 char *error = NULL;
3994 4361
3995 if (!headless) 4362 if (!headless)
3996 gtk_init(&argc, &argv); 4363 gtk_init(&argc, &argv);
@@ -3999,6 +4366,7 @@ int main(int argc, char **argv)
3999 4366
4000 if (!fe) { 4367 if (!fe) {
4001 fprintf(stderr, "%s: %s\n", pname, error); 4368 fprintf(stderr, "%s: %s\n", pname, error);
4369 sfree(error);
4002 return 1; 4370 return 1;
4003 } 4371 }
4004 4372
@@ -4014,7 +4382,7 @@ int main(int argc, char **argv)
4014 4382
4015 if (redo_proportion) { 4383 if (redo_proportion) {
4016 /* Start a redo. */ 4384 /* Start a redo. */
4017 midend_process_key(fe->me, 0, 0, 'r'); 4385 midend_process_key(fe->me, 0, 0, 'r');
4018 /* And freeze the timer at the specified position. */ 4386 /* And freeze the timer at the specified position. */
4019 midend_freeze_timer(fe->me, redo_proportion); 4387 midend_freeze_timer(fe->me, redo_proportion);
4020 } 4388 }
diff --git a/apps/plugins/puzzles/src/gtk.h b/apps/plugins/puzzles/src/gtk.h
new file mode 100644
index 0000000000..a039f0dc36
--- /dev/null
+++ b/apps/plugins/puzzles/src/gtk.h
@@ -0,0 +1,7 @@
1#ifndef PUZZLES_GTK_H
2#define PUZZLES_GTK_H
3
4extern const char *const *const xpm_icons[];
5extern const int n_xpm_icons;
6
7#endif /* PUZZLES_GTK_H */
diff --git a/apps/plugins/puzzles/src/guess.R b/apps/plugins/puzzles/src/guess.R
deleted file mode 100644
index 0e1a00c073..0000000000
--- a/apps/plugins/puzzles/src/guess.R
+++ /dev/null
@@ -1,19 +0,0 @@
1# -*- makefile -*-
2
3guess : [X] GTK COMMON guess guess-icon|no-icon
4
5guess : [G] WINDOWS COMMON guess guess.res|noicon.res
6
7ALL += guess[COMBINED]
8
9!begin am gtk
10GAMES += guess
11!end
12
13!begin >list.c
14 A(guess) \
15!end
16
17!begin >gamedesc.txt
18guess:guess.exe:Guess:Combination-guessing puzzle:Guess the hidden combination of colours.
19!end
diff --git a/apps/plugins/puzzles/src/guess.c b/apps/plugins/puzzles/src/guess.c
index a501579442..5c5f941230 100644
--- a/apps/plugins/puzzles/src/guess.c
+++ b/apps/plugins/puzzles/src/guess.c
@@ -7,7 +7,11 @@
7#include <string.h> 7#include <string.h>
8#include <assert.h> 8#include <assert.h>
9#include <ctype.h> 9#include <ctype.h>
10#include <math.h> 10#ifdef NO_TGMATH_H
11# include <math.h>
12#else
13# include <tgmath.h>
14#endif
11 15
12#include "puzzles.h" 16#include "puzzles.h"
13 17
@@ -35,6 +39,11 @@ typedef struct pegrow {
35 int *pegs; /* 0 is 'empty' */ 39 int *pegs; /* 0 is 'empty' */
36 int *feedback; /* may well be unused */ 40 int *feedback; /* may well be unused */
37} *pegrow; 41} *pegrow;
42/* Pegs can have these flags OR'ed into them. */
43#define PEG_CURSOR 0x1000
44#define PEG_HOLD 0x2000
45#define PEG_LABELLED 0x4000
46#define PEG_FLAGS (PEG_CURSOR | PEG_HOLD | PEG_LABELLED)
38 47
39struct game_state { 48struct game_state {
40 game_params params; 49 game_params params;
@@ -88,13 +97,7 @@ static bool game_fetch_preset(int i, char **name, game_params **params)
88 return false; 97 return false;
89 98
90 *name = dupstr(guess_presets[i].name); 99 *name = dupstr(guess_presets[i].name);
91 /* 100 *params = dup_params(&guess_presets[i].params);
92 * get round annoying const issues
93 */
94 {
95 game_params tmp = guess_presets[i].params;
96 *params = dup_params(&tmp);
97 }
98 101
99 return true; 102 return true;
100} 103}
@@ -365,16 +368,6 @@ static char *solve_game(const game_state *state, const game_state *currstate,
365 return dupstr("S"); 368 return dupstr("S");
366} 369}
367 370
368static bool game_can_format_as_text_now(const game_params *params)
369{
370 return true;
371}
372
373static char *game_text_format(const game_state *state)
374{
375 return NULL;
376}
377
378static bool is_markable(const game_params *params, pegrow pegs) 371static bool is_markable(const game_params *params, pegrow pegs)
379{ 372{
380 int i, nset = 0, nrequired; 373 int i, nset = 0, nrequired;
@@ -386,6 +379,7 @@ static bool is_markable(const game_params *params, pegrow pegs)
386 for (i = 0; i < params->npegs; i++) { 379 for (i = 0; i < params->npegs; i++) {
387 int c = pegs->pegs[i]; 380 int c = pegs->pegs[i];
388 if (c > 0) { 381 if (c > 0) {
382 assert(c <= params->ncolours);
389 colcount->pegs[c-1]++; 383 colcount->pegs[c-1]++;
390 nset++; 384 nset++;
391 } 385 }
@@ -414,7 +408,7 @@ struct game_ui {
414 int drag_col, drag_x, drag_y; /* x and y are *center* of peg! */ 408 int drag_col, drag_x, drag_y; /* x and y are *center* of peg! */
415 int drag_opeg; /* peg index, if dragged from a peg (from current guess), otherwise -1 */ 409 int drag_opeg; /* peg index, if dragged from a peg (from current guess), otherwise -1 */
416 410
417 bool show_labels; /* label the colours with letters */ 411 bool show_labels; /* label the colours with numbers */
418 pegrow hint; 412 pegrow hint;
419}; 413};
420 414
@@ -422,19 +416,45 @@ static game_ui *new_ui(const game_state *state)
422{ 416{
423 game_ui *ui = snew(game_ui); 417 game_ui *ui = snew(game_ui);
424 memset(ui, 0, sizeof(game_ui)); 418 memset(ui, 0, sizeof(game_ui));
425 ui->params = state->params; /* structure copy */ 419 if (state != NULL) {
426 ui->curr_pegs = new_pegrow(state->params.npegs); 420 ui->params = state->params; /* structure copy */
427 ui->holds = snewn(state->params.npegs, bool); 421 ui->curr_pegs = new_pegrow(state->params.npegs);
428 memset(ui->holds, 0, sizeof(bool)*state->params.npegs); 422 ui->holds = snewn(state->params.npegs, bool);
423 memset(ui->holds, 0, sizeof(bool)*state->params.npegs);
424 }
425 ui->display_cur = getenv_bool("PUZZLES_SHOW_CURSOR", false);
429 ui->drag_opeg = -1; 426 ui->drag_opeg = -1;
430 return ui; 427 return ui;
431} 428}
432 429
430static config_item *get_prefs(game_ui *ui)
431{
432 config_item *ret;
433
434 ret = snewn(2, config_item);
435
436 ret[0].name = "Label colours with numbers";
437 ret[0].kw = "show-labels";
438 ret[0].type = C_BOOLEAN;
439 ret[0].u.boolean.bval = ui->show_labels;
440
441 ret[1].name = NULL;
442 ret[1].type = C_END;
443
444 return ret;
445}
446
447static void set_prefs(game_ui *ui, const config_item *cfg)
448{
449 ui->show_labels = cfg[0].u.boolean.bval;
450}
451
433static void free_ui(game_ui *ui) 452static void free_ui(game_ui *ui)
434{ 453{
435 if (ui->hint) 454 if (ui->hint)
436 free_pegrow(ui->hint); 455 free_pegrow(ui->hint);
437 free_pegrow(ui->curr_pegs); 456 if (ui->curr_pegs)
457 free_pegrow(ui->curr_pegs);
438 sfree(ui->holds); 458 sfree(ui->holds);
439 sfree(ui); 459 sfree(ui);
440} 460}
@@ -462,12 +482,16 @@ static char *encode_ui(const game_ui *ui)
462 return sresize(ret, p - ret, char); 482 return sresize(ret, p - ret, char);
463} 483}
464 484
465static void decode_ui(game_ui *ui, const char *encoding) 485static void decode_ui(game_ui *ui, const char *encoding,
486 const game_state *state)
466{ 487{
467 int i; 488 int i;
468 const char *p = encoding; 489 const char *p = encoding;
469 for (i = 0; i < ui->curr_pegs->npegs; i++) { 490 for (i = 0; i < ui->curr_pegs->npegs; i++) {
470 ui->curr_pegs->pegs[i] = atoi(p); 491 ui->curr_pegs->pegs[i] = atoi(p);
492 if (ui->curr_pegs->pegs[i] < 0 ||
493 ui->curr_pegs->pegs[i] > ui->params.ncolours)
494 ui->curr_pegs->pegs[i] = 0; /* Remove invalid pegs. */
471 while (*p && isdigit((unsigned char)*p)) p++; 495 while (*p && isdigit((unsigned char)*p)) p++;
472 if (*p == '_') { 496 if (*p == '_') {
473 /* NB: old versions didn't store holds */ 497 /* NB: old versions didn't store holds */
@@ -507,7 +531,20 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
507 ui->markable = is_markable(&newstate->params, ui->curr_pegs); 531 ui->markable = is_markable(&newstate->params, ui->curr_pegs);
508 /* Clean up cursor position */ 532 /* Clean up cursor position */
509 if (!ui->markable && ui->peg_cur == newstate->solution->npegs) 533 if (!ui->markable && ui->peg_cur == newstate->solution->npegs)
510 ui->peg_cur--; 534 ui->peg_cur = 0;
535}
536
537static const char *current_key_label(const game_ui *ui,
538 const game_state *state, int button)
539{
540 if (state->solved) return "";
541 if (button == CURSOR_SELECT) {
542 if (ui->peg_cur == state->params.npegs) return "Submit";
543 return "Place";
544 }
545 if (button == CURSOR_SELECT2 && ui->peg_cur != state->params.npegs)
546 return "Hold";
547 return "";
511} 548}
512 549
513#define PEGSZ (ds->pegsz) 550#define PEGSZ (ds->pegsz)
@@ -700,7 +737,11 @@ static void compute_hint(const game_state *state, game_ui *ui)
700 for (j = 0; j < state->params.npegs; ++j) 737 for (j = 0; j < state->params.npegs; ++j)
701 if (state->guesses[i]->pegs[j] > maxcolour) 738 if (state->guesses[i]->pegs[j] > maxcolour)
702 maxcolour = state->guesses[i]->pegs[j]; 739 maxcolour = state->guesses[i]->pegs[j];
703 maxcolour = min(maxcolour + 1, state->params.ncolours); 740 if (state->params.allow_multiple)
741 maxcolour = min(maxcolour + 1, state->params.ncolours);
742 else
743 maxcolour = min(maxcolour + state->params.npegs,
744 state->params.ncolours);
704 745
705increase_mincolour: 746increase_mincolour:
706 for (i = 0; i < state->next_go; ++i) { 747 for (i = 0; i < state->next_go; ++i) {
@@ -722,6 +763,7 @@ increase_mincolour:
722 } 763 }
723 764
724 while (ui->hint->pegs[0] <= state->params.ncolours) { 765 while (ui->hint->pegs[0] <= state->params.ncolours) {
766 if (!is_markable(&state->params, ui->hint)) goto increment_pegrow;
725 for (i = 0; i < state->next_go; ++i) { 767 for (i = 0; i < state->next_go; ++i) {
726 mark_pegs(ui->hint, state->guesses[i], maxcolour); 768 mark_pegs(ui->hint, state->guesses[i], maxcolour);
727 for (j = 0; j < state->params.npegs; ++j) 769 for (j = 0; j < state->params.npegs; ++j)
@@ -777,7 +819,7 @@ static char *interpret_move(const game_state *from, game_ui *ui,
777 */ 819 */
778 if (button == 'l' || button == 'L') { 820 if (button == 'l' || button == 'L') {
779 ui->show_labels = !ui->show_labels; 821 ui->show_labels = !ui->show_labels;
780 return UI_UPDATE; 822 return MOVE_UI_UPDATE;
781 } 823 }
782 824
783 if (from->solved) return NULL; 825 if (from->solved) return NULL;
@@ -834,13 +876,13 @@ static char *interpret_move(const game_state *from, game_ui *ui,
834 ui->drag_y = y; 876 ui->drag_y = y;
835 debug(("Start dragging, col = %d, (%d,%d)", 877 debug(("Start dragging, col = %d, (%d,%d)",
836 ui->drag_col, ui->drag_x, ui->drag_y)); 878 ui->drag_col, ui->drag_x, ui->drag_y));
837 ret = UI_UPDATE; 879 ret = MOVE_UI_UPDATE;
838 } 880 }
839 } else if (button == LEFT_DRAG && ui->drag_col) { 881 } else if (button == LEFT_DRAG && ui->drag_col) {
840 ui->drag_x = x; 882 ui->drag_x = x;
841 ui->drag_y = y; 883 ui->drag_y = y;
842 debug(("Keep dragging, (%d,%d)", ui->drag_x, ui->drag_y)); 884 debug(("Keep dragging, (%d,%d)", ui->drag_x, ui->drag_y));
843 ret = UI_UPDATE; 885 ret = MOVE_UI_UPDATE;
844 } else if (button == LEFT_RELEASE && ui->drag_col) { 886 } else if (button == LEFT_RELEASE && ui->drag_col) {
845 if (over_guess > -1) { 887 if (over_guess > -1) {
846 debug(("Dropping colour %d onto guess peg %d", 888 debug(("Dropping colour %d onto guess peg %d",
@@ -857,13 +899,13 @@ static char *interpret_move(const game_state *from, game_ui *ui,
857 ui->drag_opeg = -1; 899 ui->drag_opeg = -1;
858 ui->display_cur = false; 900 ui->display_cur = false;
859 debug(("Stop dragging.")); 901 debug(("Stop dragging."));
860 ret = UI_UPDATE; 902 ret = MOVE_UI_UPDATE;
861 } else if (button == RIGHT_BUTTON) { 903 } else if (button == RIGHT_BUTTON) {
862 if (over_guess > -1) { 904 if (over_guess > -1) {
863 /* we use ths feedback in the game_ui to signify 905 /* we use ths feedback in the game_ui to signify
864 * 'carry this peg to the next guess as well'. */ 906 * 'carry this peg to the next guess as well'. */
865 ui->holds[over_guess] ^= 1; 907 ui->holds[over_guess] ^= 1;
866 ret = UI_UPDATE; 908 ret = MOVE_UI_UPDATE;
867 } 909 }
868 } else if (button == LEFT_RELEASE && over_hint && ui->markable) { 910 } else if (button == LEFT_RELEASE && over_hint && ui->markable) {
869 /* NB this won't trigger if on the end of a drag; that's on 911 /* NB this won't trigger if on the end of a drag; that's on
@@ -872,44 +914,47 @@ static char *interpret_move(const game_state *from, game_ui *ui,
872 } 914 }
873 915
874 /* keyboard input */ 916 /* keyboard input */
875 if (button == CURSOR_UP || button == CURSOR_DOWN) { 917 if (IS_CURSOR_MOVE(button)) {
876 ui->display_cur = true;
877 if (button == CURSOR_DOWN && (ui->colour_cur+1) < from->params.ncolours)
878 ui->colour_cur++;
879 if (button == CURSOR_UP && ui->colour_cur > 0)
880 ui->colour_cur--;
881 ret = UI_UPDATE;
882 } else if (button == 'h' || button == 'H' || button == '?') {
883 compute_hint(from, ui);
884 ret = UI_UPDATE;
885 } else if (button == CURSOR_LEFT || button == CURSOR_RIGHT) {
886 int maxcur = from->params.npegs; 918 int maxcur = from->params.npegs;
887 if (ui->markable) maxcur++; 919 if (ui->markable) maxcur++;
888 920
889 ui->display_cur = true; 921 ret = move_cursor(button, &ui->peg_cur, &ui->colour_cur,
890 if (button == CURSOR_RIGHT && (ui->peg_cur+1) < maxcur) 922 maxcur, from->params.ncolours,
891 ui->peg_cur++; 923 false, &ui->display_cur);
892 if (button == CURSOR_LEFT && ui->peg_cur > 0) 924 } else if (button == 'h' || button == 'H' || button == '?') {
893 ui->peg_cur--; 925 compute_hint(from, ui);
894 ret = UI_UPDATE; 926 ret = MOVE_UI_UPDATE;
895 } else if (IS_CURSOR_SELECT(button)) { 927 } else if (button == CURSOR_SELECT) {
896 ui->display_cur = true; 928 ui->display_cur = true;
897 if (ui->peg_cur == from->params.npegs) { 929 if (ui->peg_cur == from->params.npegs) {
898 ret = encode_move(from, ui); 930 ret = encode_move(from, ui);
899 } else { 931 } else {
900 set_peg(&from->params, ui, ui->peg_cur, ui->colour_cur+1); 932 set_peg(&from->params, ui, ui->peg_cur, ui->colour_cur+1);
901 ret = UI_UPDATE; 933 ret = MOVE_UI_UPDATE;
902 } 934 }
903 } else if (button == 'D' || button == 'd' || button == '\b') { 935 } else if (((button >= '1' && button <= '0' + from->params.ncolours) ||
936 (button == '0' && from->params.ncolours == 10)) &&
937 ui->peg_cur < from->params.npegs) {
904 ui->display_cur = true; 938 ui->display_cur = true;
905 set_peg(&from->params, ui, ui->peg_cur, 0); 939 /* Number keys insert a peg and advance the cursor. */
906 ret = UI_UPDATE; 940 set_peg(&from->params, ui, ui->peg_cur,
941 button == '0' ? 10 : button - '0');
942 if (ui->peg_cur + 1 < from->params.npegs + ui->markable)
943 ui->peg_cur++;
944 ret = MOVE_UI_UPDATE;
945 } else if (button == 'D' || button == 'd' || button == '\b') {
946 if (!ui->display_cur || ui->curr_pegs->pegs[ui->peg_cur] != 0) {
947 ui->display_cur = true;
948 set_peg(&from->params, ui, ui->peg_cur, 0);
949 ret = MOVE_UI_UPDATE;
950 } else
951 ret = MOVE_NO_EFFECT;
907 } else if (button == CURSOR_SELECT2) { 952 } else if (button == CURSOR_SELECT2) {
908 if (ui->peg_cur == from->params.npegs) 953 if (ui->peg_cur == from->params.npegs)
909 return NULL; 954 return NULL;
910 ui->display_cur = true; 955 ui->display_cur = true;
911 ui->holds[ui->peg_cur] ^= 1; 956 ui->holds[ui->peg_cur] ^= 1;
912 ret = UI_UPDATE; 957 ret = MOVE_UI_UPDATE;
913 } 958 }
914 return ret; 959 return ret;
915} 960}
@@ -925,6 +970,8 @@ static game_state *execute_move(const game_state *from, const char *move)
925 ret->solved = -1; 970 ret->solved = -1;
926 return ret; 971 return ret;
927 } else if (move[0] == 'G') { 972 } else if (move[0] == 'G') {
973 /* No guesses are allowed once the game is solved. */
974 if (from->solved) return NULL;
928 p = move+1; 975 p = move+1;
929 976
930 ret = dup_game(from); 977 ret = dup_game(from);
@@ -975,7 +1022,7 @@ static game_state *execute_move(const game_state *from, const char *move)
975#define BORDER 0.5 1022#define BORDER 0.5
976 1023
977static void game_compute_size(const game_params *params, int tilesize, 1024static void game_compute_size(const game_params *params, int tilesize,
978 int *x, int *y) 1025 const game_ui *ui, int *x, int *y)
979{ 1026{
980 double hmul, vmul_c, vmul_g, vmul; 1027 double hmul, vmul_c, vmul_g, vmul;
981 int hintw = (params->npegs+1)/2; 1028 int hintw = (params->npegs+1)/2;
@@ -1019,7 +1066,8 @@ static void game_set_size(drawing *dr, game_drawstate *ds,
1019 guessh = ((ds->pegsz + ds->gapsz) * params->nguesses); /* guesses */ 1066 guessh = ((ds->pegsz + ds->gapsz) * params->nguesses); /* guesses */
1020 guessh += ds->gapsz + ds->pegsz; /* solution */ 1067 guessh += ds->gapsz + ds->pegsz; /* solution */
1021 1068
1022 game_compute_size(params, tilesize, &ds->w, &ds->h); 1069 /* We know we don't need anything from the game_ui we haven't got */
1070 game_compute_size(params, tilesize, NULL, &ds->w, &ds->h);
1023 ds->colx = ds->border; 1071 ds->colx = ds->border;
1024 ds->coly = (ds->h - colh) / 2; 1072 ds->coly = (ds->h - colh) / 2;
1025 1073
@@ -1196,7 +1244,7 @@ static void draw_peg(drawing *dr, game_drawstate *ds, int cx, int cy,
1196 1244
1197 if (labelled && col) { 1245 if (labelled && col) {
1198 char buf[2]; 1246 char buf[2];
1199 buf[0] = 'a'-1 + col; 1247 buf[0] = '0' + (col % 10);
1200 buf[1] = '\0'; 1248 buf[1] = '\0';
1201 draw_text(dr, cx+PEGRAD, cy+PEGRAD, FONT_VARIABLE, PEGRAD, 1249 draw_text(dr, cx+PEGRAD, cy+PEGRAD, FONT_VARIABLE, PEGRAD,
1202 ALIGN_HCENTRE|ALIGN_VCENTRE, COL_FRAME, buf); 1250 ALIGN_HCENTRE|ALIGN_VCENTRE, COL_FRAME, buf);
@@ -1233,23 +1281,25 @@ static void guess_redraw(drawing *dr, game_drawstate *ds, int guess,
1233 for (i = 0; i < dest->npegs; i++) { 1281 for (i = 0; i < dest->npegs; i++) {
1234 scol = src ? src->pegs[i] : 0; 1282 scol = src ? src->pegs[i] : 0;
1235 if (i == cur_col) 1283 if (i == cur_col)
1236 scol |= 0x1000; 1284 scol |= PEG_CURSOR;
1237 if (holds && holds[i]) 1285 if (holds && holds[i])
1238 scol |= 0x2000; 1286 scol |= PEG_HOLD;
1239 if (labelled) 1287 if (labelled)
1240 scol |= 0x4000; 1288 scol |= PEG_LABELLED;
1241 if ((dest->pegs[i] != scol) || force) { 1289 if ((dest->pegs[i] != scol) || force) {
1242 draw_peg(dr, ds, rowx + PEGOFF * i, rowy, false, labelled, 1290 draw_peg(dr, ds, rowx + PEGOFF * i, rowy, false, labelled,
1243 scol &~ 0x7000); 1291 scol &~ PEG_FLAGS);
1292 if (scol & PEG_CURSOR)
1293 draw_cursor(dr, ds, rowx + PEGOFF * i, rowy);
1244 /* 1294 /*
1245 * Hold marker. 1295 * Hold marker.
1246 */ 1296 */
1247 draw_rect(dr, rowx + PEGOFF * i, rowy + PEGSZ + ds->gapsz/2, 1297 if (scol & PEG_HOLD) {
1248 PEGSZ, 2, (scol & 0x2000 ? COL_HOLD : COL_BACKGROUND)); 1298 draw_rect(dr, rowx + PEGOFF * i,
1249 draw_update(dr, rowx + PEGOFF * i, rowy + PEGSZ + ds->gapsz/2, 1299 rowy + PEGSZ + ds->gapsz/2 - 2, PEGSZ, 2, COL_HOLD);
1250 PEGSZ, 2); 1300 }
1251 if (scol & 0x1000) 1301 draw_update(dr, rowx + PEGOFF * i,
1252 draw_cursor(dr, ds, rowx + PEGOFF * i, rowy); 1302 rowy + PEGSZ + ds->gapsz/2 - 2, PEGSZ, 2);
1253 } 1303 }
1254 dest->pegs[i] = scol; 1304 dest->pegs[i] = scol;
1255 } 1305 }
@@ -1276,9 +1326,9 @@ static void hint_redraw(drawing *dr, game_drawstate *ds, int guess,
1276 for (i = 0; i < dest->npegs; i++) { 1326 for (i = 0; i < dest->npegs; i++) {
1277 scol = src ? src->feedback[i] : 0; 1327 scol = src ? src->feedback[i] : 0;
1278 if (i == 0 && cursor) 1328 if (i == 0 && cursor)
1279 scol |= 0x1000; 1329 scol |= PEG_CURSOR;
1280 if (i == 0 && markable) 1330 if (i == 0 && markable)
1281 scol |= 0x2000; 1331 scol |= PEG_HOLD;
1282 if ((scol != dest->feedback[i]) || force) { 1332 if ((scol != dest->feedback[i]) || force) {
1283 need_redraw = true; 1333 need_redraw = true;
1284 } 1334 }
@@ -1349,7 +1399,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1349 new_move = (state->next_go != ds->next_go) || !ds->started; 1399 new_move = (state->next_go != ds->next_go) || !ds->started;
1350 1400
1351 if (!ds->started) { 1401 if (!ds->started) {
1352 draw_rect(dr, 0, 0, ds->w, ds->h, COL_BACKGROUND);
1353 draw_rect(dr, SOLN_OX, SOLN_OY - ds->gapsz - 1, SOLN_W, 2, COL_FRAME); 1402 draw_rect(dr, SOLN_OX, SOLN_OY - ds->gapsz - 1, SOLN_W, 2, COL_FRAME);
1354 draw_update(dr, 0, 0, ds->w, ds->h); 1403 draw_update(dr, 0, 0, ds->w, ds->h);
1355 } 1404 }
@@ -1364,19 +1413,18 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1364 for (i = 0; i < state->params.ncolours; i++) { 1413 for (i = 0; i < state->params.ncolours; i++) {
1365 int val = i+1; 1414 int val = i+1;
1366 if (ui->display_cur && ui->colour_cur == i) 1415 if (ui->display_cur && ui->colour_cur == i)
1367 val |= 0x1000; 1416 val |= PEG_CURSOR;
1368 if (ui->show_labels) 1417 if (ui->show_labels)
1369 val |= 0x2000; 1418 val |= PEG_HOLD;
1370 if (ds->colours->pegs[i] != val) { 1419 if (ds->colours->pegs[i] != val) {
1371 draw_peg(dr, ds, COL_X(i), COL_Y(i), false, ui->show_labels, i+1); 1420 draw_peg(dr, ds, COL_X(i), COL_Y(i), false, ui->show_labels, i+1);
1372 if (val & 0x1000) 1421 if (val & PEG_CURSOR)
1373 draw_cursor(dr, ds, COL_X(i), COL_Y(i)); 1422 draw_cursor(dr, ds, COL_X(i), COL_Y(i));
1374 ds->colours->pegs[i] = val; 1423 ds->colours->pegs[i] = val;
1375 } 1424 }
1376 } 1425 }
1377 1426
1378 /* draw the guesses (so far) and the hints 1427 /* draw the guesses (so far) and the hints (postponing the
1379 * (in reverse order to avoid trampling holds, and postponing the
1380 * next_go'th to not overrender the top of the circular cursor) */ 1428 * next_go'th to not overrender the top of the circular cursor) */
1381 for (i = state->params.nguesses - 1; i >= 0; i--) { 1429 for (i = state->params.nguesses - 1; i >= 0; i--) {
1382 if (i < state->next_go || state->solved) { 1430 if (i < state->next_go || state->solved) {
@@ -1473,19 +1521,6 @@ static int game_status(const game_state *state)
1473 return state->solved; 1521 return state->solved;
1474} 1522}
1475 1523
1476static bool game_timing_state(const game_state *state, game_ui *ui)
1477{
1478 return true;
1479}
1480
1481static void game_print_size(const game_params *params, float *x, float *y)
1482{
1483}
1484
1485static void game_print(drawing *dr, const game_state *state, int tilesize)
1486{
1487}
1488
1489#ifdef COMBINED 1524#ifdef COMBINED
1490#define thegame guess 1525#define thegame guess
1491#endif 1526#endif
@@ -1506,13 +1541,15 @@ const struct game thegame = {
1506 dup_game, 1541 dup_game,
1507 free_game, 1542 free_game,
1508 true, solve_game, 1543 true, solve_game,
1509 false, game_can_format_as_text_now, game_text_format, 1544 false, NULL, NULL, /* can_format_as_text_now, text_format */
1545 get_prefs, set_prefs,
1510 new_ui, 1546 new_ui,
1511 free_ui, 1547 free_ui,
1512 encode_ui, 1548 encode_ui,
1513 decode_ui, 1549 decode_ui,
1514 NULL, /* game_request_keys */ 1550 NULL, /* game_request_keys */
1515 game_changed_state, 1551 game_changed_state,
1552 current_key_label,
1516 interpret_move, 1553 interpret_move,
1517 execute_move, 1554 execute_move,
1518 PEG_PREFER_SZ, game_compute_size, game_set_size, 1555 PEG_PREFER_SZ, game_compute_size, game_set_size,
@@ -1524,9 +1561,9 @@ const struct game thegame = {
1524 game_flash_length, 1561 game_flash_length,
1525 game_get_cursor_location, 1562 game_get_cursor_location,
1526 game_status, 1563 game_status,
1527 false, false, game_print_size, game_print, 1564 false, false, NULL, NULL, /* print_size, print */
1528 false, /* wants_statusbar */ 1565 false, /* wants_statusbar */
1529 false, game_timing_state, 1566 false, NULL, /* timing_state */
1530 0, /* flags */ 1567 0, /* flags */
1531}; 1568};
1532 1569
diff --git a/apps/plugins/puzzles/src/hat-internal.h b/apps/plugins/puzzles/src/hat-internal.h
new file mode 100644
index 0000000000..2be96327a8
--- /dev/null
+++ b/apps/plugins/puzzles/src/hat-internal.h
@@ -0,0 +1,271 @@
1/*
2 * Internal definitions for the hat.c tiling generator, shared between
3 * hat.c itself and hat-test.c.
4 */
5
6#include "puzzles.h"
7
8/*
9 * Coordinate system:
10 *
11 * The output of this code lives on the tiling known to grid.c as
12 * 'Kites', which can be viewed as a tiling of hexagons each of which
13 * is subdivided into six kites sharing their pointy vertex, or
14 * (equivalently) a tiling of equilateral triangles each subdivided
15 * into three kits sharing their blunt vertex.
16 *
17 * We express coordinates in this system relative to the basis (1, r)
18 * where r = (1 + sqrt(3)i) / 2 is a primitive 6th root of unity. This
19 * gives us a system in which two integer coordinates can address any
20 * grid point, provided we scale up so that the side length of the
21 * equilateral triangles in the tiling is 6.
22 */
23
24typedef struct Point {
25 int x, y; /* represents x + yr */
26} Point;
27
28static inline Point pointscale(int scale, Point a)
29{
30 Point r = { scale * a.x, scale * a.y };
31 return r;
32}
33
34static inline Point pointadd(Point a, Point b)
35{
36 Point r = { a.x + b.x, a.y + b.y };
37 return r;
38}
39
40/*
41 * We identify a single kite by the coordinates of its four vertices.
42 * This allows us to construct the coordinates of an adjacent kite by
43 * taking affine transformations of the original kite's vertices.
44 *
45 * This is a useful way to do it because it means that if you reflect
46 * the kite (by swapping its left and right vertices) then these
47 * transformations also perform in a reflected way. This will be
48 * useful in the code below that outputs the coordinates of each hat,
49 * because this way it can work by walking around its 8 kites using a
50 * fixed set of steps, and if the hat is reflected, then we just
51 * reflect the starting kite before doing that, and everything still
52 * works.
53 */
54
55typedef struct Kite {
56 Point centre, left, right, outer;
57} Kite;
58
59static inline Kite kite_left(Kite k)
60{
61 Kite r;
62 r.centre = k.centre;
63 r.right = k.left;
64 r.outer = pointadd(pointscale(2, k.left), pointscale(-1, k.outer));
65 r.left = pointadd(pointadd(k.centre, k.left), pointscale(-1, k.right));
66 return r;
67}
68
69static inline Kite kite_right(Kite k)
70{
71 Kite r;
72 r.centre = k.centre;
73 r.left = k.right;
74 r.outer = pointadd(pointscale(2, k.right), pointscale(-1, k.outer));
75 r.right = pointadd(pointadd(k.centre, k.right), pointscale(-1, k.left));
76 return r;
77}
78
79static inline Kite kite_forward_left(Kite k)
80{
81 Kite r;
82 r.outer = k.outer;
83 r.right = k.left;
84 r.centre = pointadd(pointscale(2, k.left), pointscale(-1, k.centre));
85 r.left = pointadd(pointadd(k.right, k.left), pointscale(-1, k.centre));
86 return r;
87}
88
89static inline Kite kite_forward_right(Kite k)
90{
91 Kite r;
92 r.outer = k.outer;
93 r.left = k.right;
94 r.centre = pointadd(pointscale(2, k.right), pointscale(-1, k.centre));
95 r.right = pointadd(pointadd(k.left, k.right), pointscale(-1, k.centre));
96 return r;
97}
98
99typedef enum KiteStep { KS_LEFT, KS_RIGHT, KS_F_LEFT, KS_F_RIGHT } KiteStep;
100
101static inline Kite kite_step(Kite k, KiteStep step)
102{
103 switch (step) {
104 case KS_LEFT: return kite_left(k);
105 case KS_RIGHT: return kite_right(k);
106 case KS_F_LEFT: return kite_forward_left(k);
107 default /* case KS_F_RIGHT */: return kite_forward_right(k);
108 }
109}
110
111/*
112 * Functiond to enumerate the kites in a rectangular region, in a
113 * serpentine-raster fashion so that every kite delivered shares an
114 * edge with a recent previous one.
115 */
116#define KE_NKEEP 3
117typedef struct KiteEnum {
118 /* Fields private to the enumerator */
119 int state;
120 int x, y, w, h;
121 unsigned curr_index;
122
123 /* Fields the client can legitimately read out */
124 Kite *curr;
125 Kite recent[KE_NKEEP];
126 unsigned last_index;
127 KiteStep last_step; /* step that got curr from recent[last_index] */
128} KiteEnum;
129void hat_kiteenum_first(KiteEnum *s, int w, int h);
130bool hat_kiteenum_next(KiteEnum *s);
131
132/*
133 * Assorted useful definitions.
134 */
135typedef enum TileType { TT_H, TT_T, TT_P, TT_F, TT_KITE, TT_HAT } TileType;
136static const char tilechars[] = "HTPF";
137
138#define HAT_KITES 8 /* number of kites in a hat */
139#define MT_MAXEXPAND 13 /* largest number of metatiles in any expansion */
140
141/*
142 * Definitions for the autogenerated hat-tables.h header file that
143 * defines all the lookup tables.
144 */
145typedef struct KitemapEntry {
146 int kite, hat, meta; /* all -1 if impossible */
147} KitemapEntry;
148
149typedef struct MetamapEntry {
150 int meta, meta2;
151} MetamapEntry;
152
153static inline size_t kitemap_index(KiteStep step, unsigned kite,
154 unsigned hat, unsigned meta)
155{
156 return step + 4 * (kite + 8 * (hat + 4 * meta));
157}
158
159static inline size_t metamap_index(unsigned meta, unsigned meta2)
160{
161 return meta2 * MT_MAXEXPAND + meta;
162}
163
164/*
165 * Coordinate system for tracking kites within a randomly selected
166 * part of the recursively expanded hat tiling.
167 *
168 * HatCoords will store an array of HatCoord, in little-endian
169 * arrangement. So hc->c[0] will always have type TT_KITE and index a
170 * single kite within a hat; hc->c[1] will have type TT_HAT and index
171 * a hat within a first-order metatile; hc->c[2] will be the smallest
172 * metatile containing this hat, and hc->c[3, 4, 5, ...] will be
173 * higher-order metatiles as needed.
174 *
175 * The last coordinate stored, hc->c[hc->nc-1], will have a tile type
176 * but no index (represented by index==-1). This means "we haven't
177 * decided yet what this level of metatile needs to be". If we need to
178 * refer to this level during the hatctx_step algorithm, we make it up
179 * at random, based on a table of what metatiles each type can
180 * possibly be part of, at what index.
181 */
182typedef struct HatCoord {
183 int index; /* index within that tile, or -1 if not yet known */
184 TileType type; /* type of this tile */
185} HatCoord;
186
187typedef struct HatCoords {
188 HatCoord *c;
189 size_t nc, csize;
190} HatCoords;
191
192HatCoords *hat_coords_new(void);
193void hat_coords_free(HatCoords *hc);
194void hat_coords_make_space(HatCoords *hc, size_t size);
195HatCoords *hat_coords_copy(HatCoords *hc_in);
196
197#ifdef HAT_COORDS_DEBUG
198static inline void hat_coords_debug(const char *prefix, HatCoords *hc,
199 const char *suffix)
200{
201 const char *sep = "";
202 static const char *const types[] = {"H","T","P","F","kite","hat"};
203
204 fputs(prefix, stderr);
205 for (size_t i = 0; i < hc->nc; i++) {
206 fprintf(stderr, "%s %s ", sep, types[hc->c[i].type]);
207 sep = " .";
208 if (hc->c[i].index == -1)
209 fputs("?", stderr);
210 else
211 fprintf(stderr, "%d", hc->c[i].index);
212 }
213 fputs(suffix, stderr);
214}
215#else
216#define hat_coords_debug(p,c,s) ((void)0)
217#endif
218
219/*
220 * HatContext is the shared context of a whole run of the algorithm.
221 * Its 'prototype' HatCoords object represents the coordinates of the
222 * starting kite, and is extended as necessary; any other HatCoord
223 * that needs extending will copy the higher-order values from
224 * ctx->prototype as needed, so that once each choice has been made,
225 * it remains consistent.
226 *
227 * When we're inventing a random piece of tiling in the first place,
228 * we append to ctx->prototype by choosing a random (but legal)
229 * higher-level metatile for the current topmost one to turn out to be
230 * part of. When we're replaying a generation whose parameters are
231 * already stored, we don't have a random_state, and we make fixed
232 * decisions if not enough coordinates were provided.
233 *
234 * (Of course another approach would be to reject grid descriptions
235 * that didn't define enough coordinates! But that would involve a
236 * whole extra iteration over the whole grid region just for
237 * validation, and that seems like more timewasting than really
238 * needed. So we tolerate short descriptions, and do something
239 * deterministic with them.)
240 */
241
242typedef struct HatContext {
243 random_state *rs;
244 HatCoords *prototype;
245} HatContext;
246
247void hatctx_init_random(HatContext *ctx, random_state *rs);
248void hatctx_cleanup(HatContext *ctx);
249HatCoords *hatctx_initial_coords(HatContext *ctx);
250void hatctx_extend_coords(HatContext *ctx, HatCoords *hc, size_t n);
251HatCoords *hatctx_step(HatContext *ctx, HatCoords *hc_in, KiteStep step);
252
253/*
254 * Subroutine of hat_tiling_generate, called for each kite in the grid
255 * as we iterate over it, to decide whether to generate an output hat
256 * and pass it to the client. Exposed in this header file so that
257 * hat-test can reuse it.
258 *
259 * We do this by starting from kite #0 of each hat, and tracing round
260 * the boundary. If the whole boundary is within the caller's bounding
261 * region, we return it; if it goes off the edge, we don't.
262 *
263 * (Of course, every hat we _do_ want to return will have all its
264 * kites inside the rectangle, so its kite #0 will certainly be caught
265 * by this iteration.)
266 */
267
268typedef void (*internal_hat_callback_fn)(void *ctx, Kite kite0, HatCoords *hc,
269 int *coords);
270void maybe_report_hat(int w, int h, Kite kite, HatCoords *hc,
271 internal_hat_callback_fn cb, void *cbctx);
diff --git a/apps/plugins/puzzles/src/hat-tables.h b/apps/plugins/puzzles/src/hat-tables.h
new file mode 100644
index 0000000000..b55fbb405b
--- /dev/null
+++ b/apps/plugins/puzzles/src/hat-tables.h
@@ -0,0 +1,2120 @@
1/*
2 * Header file autogenerated by auxiliary/hatgen.c
3 *
4 * To regenerate, run 'hatgen --tables > hat-tables.h'
5 */
6
7static const unsigned hats_in_metatile[] = { 4, 1, 2, 2, };
8
9static const TileType children_H[] = {
10 TT_H, TT_H, TT_H, TT_T, TT_P, TT_P, TT_P, TT_F, TT_F, TT_F, TT_F, TT_F, TT_F,
11};
12static const TileType children_T[] = {
13 TT_H, TT_P, TT_P, TT_P, TT_F, TT_F, TT_F,
14};
15static const TileType children_P[] = {
16 TT_H, TT_H, TT_P, TT_P, TT_P, TT_F, TT_F, TT_F, TT_F, TT_F, TT_F,
17};
18static const TileType children_F[] = {
19 TT_H, TT_H, TT_P, TT_P, TT_F, TT_F, TT_F, TT_F, TT_F, TT_F, TT_F,
20};
21static const TileType *const children[] = {
22 children_H,
23 children_T,
24 children_P,
25 children_F,
26};
27static const size_t nchildren[] = {
28 13,
29 7,
30 11,
31 11,
32};
33
34static const KitemapEntry kitemap_H[] = {
35 /* hat #0 in metatile #0 (type H) */
36 {1,0,0}, {7,3,0}, {3,0,4}, {4,0,4},
37 {4,3,0}, {0,0,0}, {5,0,0}, {2,0,0},
38 {3,0,4}, {3,0,0}, {1,0,0}, {5,0,0},
39 {2,0,0}, {1,2,1}, {4,0,0}, {6,2,1},
40 {3,0,3}, {5,0,0}, {6,2,1}, {3,0,0},
41 {4,0,0}, {6,0,0}, {2,0,0}, {1,0,0},
42 {5,0,0}, {7,0,0}, {4,3,0}, {3,3,0},
43 {6,0,0}, {2,0,3}, {7,1,0}, {0,0,3},
44 /* hat #1 in metatile #0 (type H) */
45 {1,1,0}, {2,0,5}, {7,1,8}, {0,0,5},
46 {3,0,2}, {0,1,0}, {5,1,0}, {2,1,0},
47 {7,1,8}, {3,1,0}, {1,1,0}, {5,1,0},
48 {2,1,0}, {4,1,8}, {4,1,0}, {0,3,0},
49 {2,3,0}, {5,1,0}, {0,3,0}, {3,1,0},
50 {4,1,0}, {6,1,0}, {2,1,0}, {1,1,0},
51 {5,1,0}, {7,1,0}, {3,0,2}, {4,0,2},
52 {6,1,0}, {3,3,0}, {0,0,3}, {7,0,0},
53 /* hat #2 in metatile #0 (type H) */
54 {1,2,0}, {1,0,7}, {7,1,4}, {6,0,7},
55 {3,0,8}, {0,2,0}, {5,2,0}, {2,2,0},
56 {7,1,4}, {3,2,0}, {1,2,0}, {5,2,0},
57 {2,2,0}, {4,1,4}, {4,2,0}, {6,3,0},
58 {1,3,0}, {5,2,0}, {6,3,0}, {3,2,0},
59 {4,2,0}, {6,2,0}, {2,2,0}, {1,2,0},
60 {5,2,0}, {7,2,0}, {3,0,8}, {4,0,8},
61 {6,2,0}, {0,3,0}, {3,1,8}, {4,1,8},
62 /* hat #3 in metatile #0 (type H) */
63 {7,2,0}, {1,3,0}, {3,1,0}, {4,1,0},
64 {0,3,0}, {4,2,0}, {2,3,0}, {5,3,0},
65 {3,3,0}, {4,1,0}, {5,3,0}, {1,3,0},
66 {7,1,0}, {2,3,0}, {6,0,0}, {4,3,0},
67 {5,3,0}, {1,0,0}, {3,3,0}, {6,0,0},
68 {6,3,0}, {4,3,0}, {1,3,0}, {2,3,0},
69 {7,3,0}, {5,3,0}, {3,2,0}, {4,2,0},
70 {0,0,0}, {6,3,0}, {3,1,4}, {4,1,4},
71 /* hat #0 in metatile #1 (type H) */
72 {1,0,1}, {7,3,1}, {3,0,9}, {4,0,9},
73 {4,3,1}, {0,0,1}, {5,0,1}, {2,0,1},
74 {3,0,9}, {3,0,1}, {1,0,1}, {5,0,1},
75 {2,0,1}, {1,0,10}, {4,0,1}, {6,0,10},
76 {0,0,6}, {5,0,1}, {6,0,10}, {3,0,1},
77 {4,0,1}, {6,0,1}, {2,0,1}, {1,0,1},
78 {5,0,1}, {7,0,1}, {4,3,1}, {3,3,1},
79 {6,0,1}, {1,0,6}, {7,1,1}, {6,0,6},
80 /* hat #1 in metatile #1 (type H) */
81 {1,1,1}, {1,1,2}, {7,0,3}, {6,1,2},
82 {0,1,6}, {0,1,1}, {5,1,1}, {2,1,1},
83 {7,0,3}, {3,1,1}, {1,1,1}, {5,1,1},
84 {2,1,1}, {4,0,3}, {4,1,1}, {0,3,1},
85 {2,3,1}, {5,1,1}, {0,3,1}, {3,1,1},
86 {4,1,1}, {6,1,1}, {2,1,1}, {1,1,1},
87 {5,1,1}, {7,1,1}, {0,1,6}, {7,0,6},
88 {6,1,1}, {3,3,1}, {6,0,6}, {7,0,1},
89 /* hat #2 in metatile #1 (type H) */
90 {1,2,1}, {2,0,4}, {7,1,9}, {0,0,4},
91 {3,0,0}, {0,2,1}, {5,2,1}, {2,2,1},
92 {7,1,9}, {3,2,1}, {1,2,1}, {5,2,1},
93 {2,2,1}, {4,1,9}, {4,2,1}, {6,3,1},
94 {1,3,1}, {5,2,1}, {6,3,1}, {3,2,1},
95 {4,2,1}, {6,2,1}, {2,2,1}, {1,2,1},
96 {5,2,1}, {7,2,1}, {3,0,0}, {4,0,0},
97 {6,2,1}, {0,3,1}, {3,0,3}, {4,0,3},
98 /* hat #3 in metatile #1 (type H) */
99 {7,2,1}, {1,3,1}, {3,1,1}, {4,1,1},
100 {0,3,1}, {4,2,1}, {2,3,1}, {5,3,1},
101 {3,3,1}, {4,1,1}, {5,3,1}, {1,3,1},
102 {7,1,1}, {2,3,1}, {6,0,1}, {4,3,1},
103 {5,3,1}, {1,0,1}, {3,3,1}, {6,0,1},
104 {6,3,1}, {4,3,1}, {1,3,1}, {2,3,1},
105 {7,3,1}, {5,3,1}, {3,2,1}, {4,2,1},
106 {0,0,1}, {6,3,1}, {3,1,9}, {4,1,9},
107 /* hat #0 in metatile #2 (type H) */
108 {1,0,2}, {7,3,2}, {3,0,5}, {4,0,5},
109 {4,3,2}, {0,0,2}, {5,0,2}, {2,0,2},
110 {3,0,5}, {3,0,2}, {1,0,2}, {5,0,2},
111 {2,0,2}, {1,1,0}, {4,0,2}, {6,1,0},
112 {0,0,3}, {5,0,2}, {6,1,0}, {3,0,2},
113 {4,0,2}, {6,0,2}, {2,0,2}, {1,0,2},
114 {5,0,2}, {7,0,2}, {4,3,2}, {3,3,2},
115 {6,0,2}, {1,0,3}, {7,1,2}, {6,0,3},
116 /* hat #1 in metatile #2 (type H) */
117 {1,1,2}, {1,1,6}, {7,1,12}, {6,1,6},
118 {0,1,1}, {0,1,2}, {5,1,2}, {2,1,2},
119 {7,1,12}, {3,1,2}, {1,1,2}, {5,1,2},
120 {2,1,2}, {4,1,12}, {4,1,2}, {0,3,2},
121 {2,3,2}, {5,1,2}, {0,3,2}, {3,1,2},
122 {4,1,2}, {6,1,2}, {2,1,2}, {1,1,2},
123 {5,1,2}, {7,1,2}, {0,1,1}, {7,0,3},
124 {6,1,2}, {3,3,2}, {6,0,3}, {7,0,2},
125 /* hat #2 in metatile #2 (type H) */
126 {1,2,2}, {1,0,11}, {7,1,5}, {6,0,11},
127 {3,0,12}, {0,2,2}, {5,2,2}, {2,2,2},
128 {7,1,5}, {3,2,2}, {1,2,2}, {5,2,2},
129 {2,2,2}, {4,1,5}, {4,2,2}, {6,3,2},
130 {1,3,2}, {5,2,2}, {6,3,2}, {3,2,2},
131 {4,2,2}, {6,2,2}, {2,2,2}, {1,2,2},
132 {5,2,2}, {7,2,2}, {3,0,12}, {4,0,12},
133 {6,2,2}, {0,3,2}, {3,1,12}, {4,1,12},
134 /* hat #3 in metatile #2 (type H) */
135 {7,2,2}, {1,3,2}, {3,1,2}, {4,1,2},
136 {0,3,2}, {4,2,2}, {2,3,2}, {5,3,2},
137 {3,3,2}, {4,1,2}, {5,3,2}, {1,3,2},
138 {7,1,2}, {2,3,2}, {6,0,2}, {4,3,2},
139 {5,3,2}, {1,0,2}, {3,3,2}, {6,0,2},
140 {6,3,2}, {4,3,2}, {1,3,2}, {2,3,2},
141 {7,3,2}, {5,3,2}, {3,2,2}, {4,2,2},
142 {0,0,2}, {6,3,2}, {3,1,5}, {4,1,5},
143 /* hat #0 in metatile #3 (type T) */
144 {1,0,3}, {4,0,2}, {7,0,0}, {7,1,0},
145 {7,0,2}, {0,0,3}, {5,0,3}, {2,0,3},
146 {7,0,0}, {3,0,3}, {1,0,3}, {5,0,3},
147 {2,0,3}, {4,0,0}, {4,0,3}, {7,2,1},
148 {3,1,1}, {5,0,3}, {7,2,1}, {3,0,3},
149 {4,0,3}, {6,0,3}, {2,0,3}, {1,0,3},
150 {5,0,3}, {7,0,3}, {7,0,2}, {7,1,2},
151 {6,0,3}, {2,1,1}, {6,1,2}, {0,1,1},
152 /* hat #1 in metatile #3 (type T) does not exist */
153 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
154 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
155 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
156 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
157 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
158 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
159 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
160 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
161 /* hat #2 in metatile #3 (type T) does not exist */
162 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
163 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
164 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
165 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
166 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
167 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
168 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
169 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
170 /* hat #3 in metatile #3 (type T) does not exist */
171 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
172 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
173 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
174 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
175 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
176 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
177 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
178 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
179 /* hat #0 in metatile #4 (type P) */
180 {1,0,4}, {-1,-1,-1}, {0,2,1}, {7,1,9},
181 {-1,-1,-1}, {0,0,4}, {5,0,4}, {2,0,4},
182 {0,2,1}, {3,0,4}, {1,0,4}, {5,0,4},
183 {2,0,4}, {2,0,0}, {4,0,4}, {0,0,0},
184 {3,1,4}, {5,0,4}, {0,0,0}, {3,0,4},
185 {4,0,4}, {6,0,4}, {2,0,4}, {1,0,4},
186 {5,0,4}, {7,0,4}, {-1,-1,-1}, {-1,-1,-1},
187 {6,0,4}, {2,1,4}, {-1,-1,-1}, {0,1,4},
188 /* hat #1 in metatile #4 (type P) */
189 {1,1,4}, {-1,-1,-1}, {7,0,4}, {-1,-1,-1},
190 {0,1,7}, {0,1,4}, {5,1,4}, {2,1,4},
191 {7,0,4}, {3,1,4}, {1,1,4}, {5,1,4},
192 {2,1,4}, {4,0,4}, {4,1,4}, {7,3,0},
193 {3,2,0}, {5,1,4}, {7,3,0}, {3,1,4},
194 {4,1,4}, {6,1,4}, {2,1,4}, {1,1,4},
195 {5,1,4}, {7,1,4}, {0,1,7}, {7,0,7},
196 {6,1,4}, {2,2,0}, {6,0,7}, {0,2,0},
197 /* hat #2 in metatile #4 (type P) does not exist */
198 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
199 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
200 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
201 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
202 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
203 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
204 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
205 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
206 /* hat #3 in metatile #4 (type P) does not exist */
207 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
208 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
209 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
210 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
211 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
212 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
213 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
214 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
215 /* hat #0 in metatile #5 (type P) */
216 {1,0,5}, {-1,-1,-1}, {0,1,0}, {7,1,8},
217 {-1,-1,-1}, {0,0,5}, {5,0,5}, {2,0,5},
218 {0,1,0}, {3,0,5}, {1,0,5}, {5,0,5},
219 {2,0,5}, {2,0,2}, {4,0,5}, {0,0,2},
220 {3,1,5}, {5,0,5}, {0,0,2}, {3,0,5},
221 {4,0,5}, {6,0,5}, {2,0,5}, {1,0,5},
222 {5,0,5}, {7,0,5}, {-1,-1,-1}, {-1,-1,-1},
223 {6,0,5}, {2,1,5}, {-1,-1,-1}, {0,1,5},
224 /* hat #1 in metatile #5 (type P) */
225 {1,1,5}, {-1,-1,-1}, {7,0,5}, {-1,-1,-1},
226 {0,1,11}, {0,1,5}, {5,1,5}, {2,1,5},
227 {7,0,5}, {3,1,5}, {1,1,5}, {5,1,5},
228 {2,1,5}, {4,0,5}, {4,1,5}, {7,3,2},
229 {3,2,2}, {5,1,5}, {7,3,2}, {3,1,5},
230 {4,1,5}, {6,1,5}, {2,1,5}, {1,1,5},
231 {5,1,5}, {7,1,5}, {0,1,11}, {7,0,11},
232 {6,1,5}, {2,2,2}, {6,0,11}, {0,2,2},
233 /* hat #2 in metatile #5 (type P) does not exist */
234 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
235 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
236 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
237 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
238 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
239 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
240 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
241 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
242 /* hat #3 in metatile #5 (type P) does not exist */
243 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
244 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
245 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
246 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
247 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
248 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
249 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
250 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
251 /* hat #0 in metatile #6 (type P) */
252 {1,0,6}, {4,0,1}, {0,1,10}, {7,0,10},
253 {7,0,1}, {0,0,6}, {5,0,6}, {2,0,6},
254 {0,1,10}, {3,0,6}, {1,0,6}, {5,0,6},
255 {2,0,6}, {-1,-1,-1}, {4,0,6}, {-1,-1,-1},
256 {3,1,6}, {5,0,6}, {-1,-1,-1}, {3,0,6},
257 {4,0,6}, {6,0,6}, {2,0,6}, {1,0,6},
258 {5,0,6}, {7,0,6}, {7,0,1}, {7,1,1},
259 {6,0,6}, {2,1,6}, {6,1,1}, {0,1,6},
260 /* hat #1 in metatile #6 (type P) */
261 {1,1,6}, {1,1,1}, {7,0,6}, {6,1,1},
262 {0,1,2}, {0,1,6}, {5,1,6}, {2,1,6},
263 {7,0,6}, {3,1,6}, {1,1,6}, {5,1,6},
264 {2,1,6}, {4,0,6}, {4,1,6}, {-1,-1,-1},
265 {-1,-1,-1}, {5,1,6}, {-1,-1,-1}, {3,1,6},
266 {4,1,6}, {6,1,6}, {2,1,6}, {1,1,6},
267 {5,1,6}, {7,1,6}, {0,1,2}, {7,1,12},
268 {6,1,6}, {-1,-1,-1}, {6,1,12}, {-1,-1,-1},
269 /* hat #2 in metatile #6 (type P) does not exist */
270 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
271 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
272 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
273 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
274 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
275 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
276 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
277 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
278 /* hat #3 in metatile #6 (type P) does not exist */
279 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
280 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
281 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
282 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
283 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
284 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
285 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
286 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
287 /* hat #0 in metatile #7 (type F) */
288 {1,0,7}, {2,0,8}, {-1,-1,-1}, {0,0,8},
289 {0,2,0}, {0,0,7}, {5,0,7}, {2,0,7},
290 {-1,-1,-1}, {3,0,7}, {1,0,7}, {5,0,7},
291 {2,0,7}, {-1,-1,-1}, {4,0,7}, {-1,-1,-1},
292 {3,1,7}, {5,0,7}, {-1,-1,-1}, {3,0,7},
293 {4,0,7}, {6,0,7}, {2,0,7}, {1,0,7},
294 {5,0,7}, {7,0,7}, {0,2,0}, {7,1,4},
295 {6,0,7}, {2,1,7}, {6,1,4}, {0,1,7},
296 /* hat #1 in metatile #7 (type F) */
297 {1,1,7}, {1,1,4}, {7,0,7}, {6,1,4},
298 {-1,-1,-1}, {0,1,7}, {5,1,7}, {2,1,7},
299 {7,0,7}, {3,1,7}, {1,1,7}, {5,1,7},
300 {2,1,7}, {4,0,7}, {4,1,7}, {-1,-1,-1},
301 {-1,-1,-1}, {5,1,7}, {-1,-1,-1}, {3,1,7},
302 {4,1,7}, {6,1,7}, {2,1,7}, {1,1,7},
303 {5,1,7}, {7,1,7}, {-1,-1,-1}, {-1,-1,-1},
304 {6,1,7}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
305 /* hat #2 in metatile #7 (type F) does not exist */
306 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
307 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
308 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
309 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
310 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
311 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
312 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
313 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
314 /* hat #3 in metatile #7 (type F) does not exist */
315 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
316 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
317 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
318 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
319 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
320 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
321 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
322 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
323 /* hat #0 in metatile #8 (type F) */
324 {1,0,8}, {-1,-1,-1}, {0,0,7}, {-1,-1,-1},
325 {-1,-1,-1}, {0,0,8}, {5,0,8}, {2,0,8},
326 {0,0,7}, {3,0,8}, {1,0,8}, {5,0,8},
327 {2,0,8}, {1,2,0}, {4,0,8}, {6,2,0},
328 {3,1,8}, {5,0,8}, {6,2,0}, {3,0,8},
329 {4,0,8}, {6,0,8}, {2,0,8}, {1,0,8},
330 {5,0,8}, {7,0,8}, {-1,-1,-1}, {-1,-1,-1},
331 {6,0,8}, {2,1,8}, {-1,-1,-1}, {0,1,8},
332 /* hat #1 in metatile #8 (type F) */
333 {1,1,8}, {-1,-1,-1}, {7,0,8}, {-1,-1,-1},
334 {-1,-1,-1}, {0,1,8}, {5,1,8}, {2,1,8},
335 {7,0,8}, {3,1,8}, {1,1,8}, {5,1,8},
336 {2,1,8}, {4,0,8}, {4,1,8}, {7,2,0},
337 {3,1,0}, {5,1,8}, {7,2,0}, {3,1,8},
338 {4,1,8}, {6,1,8}, {2,1,8}, {1,1,8},
339 {5,1,8}, {7,1,8}, {-1,-1,-1}, {-1,-1,-1},
340 {6,1,8}, {2,1,0}, {0,0,5}, {0,1,0},
341 /* hat #2 in metatile #8 (type F) does not exist */
342 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
343 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
344 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
345 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
346 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
347 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
348 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
349 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
350 /* hat #3 in metatile #8 (type F) does not exist */
351 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
352 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
353 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
354 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
355 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
356 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
357 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
358 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
359 /* hat #0 in metatile #9 (type F) */
360 {1,0,9}, {-1,-1,-1}, {0,0,10}, {-1,-1,-1},
361 {-1,-1,-1}, {0,0,9}, {5,0,9}, {2,0,9},
362 {0,0,10}, {3,0,9}, {1,0,9}, {5,0,9},
363 {2,0,9}, {2,0,1}, {4,0,9}, {0,0,1},
364 {3,1,9}, {5,0,9}, {0,0,1}, {3,0,9},
365 {4,0,9}, {6,0,9}, {2,0,9}, {1,0,9},
366 {5,0,9}, {7,0,9}, {-1,-1,-1}, {-1,-1,-1},
367 {6,0,9}, {2,1,9}, {-1,-1,-1}, {0,1,9},
368 /* hat #1 in metatile #9 (type F) */
369 {1,1,9}, {-1,-1,-1}, {7,0,9}, {-1,-1,-1},
370 {-1,-1,-1}, {0,1,9}, {5,1,9}, {2,1,9},
371 {7,0,9}, {3,1,9}, {1,1,9}, {5,1,9},
372 {2,1,9}, {4,0,9}, {4,1,9}, {7,3,1},
373 {3,2,1}, {5,1,9}, {7,3,1}, {3,1,9},
374 {4,1,9}, {6,1,9}, {2,1,9}, {1,1,9},
375 {5,1,9}, {7,1,9}, {-1,-1,-1}, {-1,-1,-1},
376 {6,1,9}, {2,2,1}, {0,0,4}, {0,2,1},
377 /* hat #2 in metatile #9 (type F) does not exist */
378 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
379 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
380 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
381 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
382 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
383 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
384 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
385 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
386 /* hat #3 in metatile #9 (type F) does not exist */
387 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
388 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
389 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
390 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
391 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
392 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
393 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
394 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
395 /* hat #0 in metatile #10 (type F) */
396 {1,0,10}, {2,0,9}, {-1,-1,-1}, {0,0,9},
397 {3,0,1}, {0,0,10}, {5,0,10}, {2,0,10},
398 {-1,-1,-1}, {3,0,10}, {1,0,10}, {5,0,10},
399 {2,0,10}, {-1,-1,-1}, {4,0,10}, {-1,-1,-1},
400 {3,1,10}, {5,0,10}, {-1,-1,-1}, {3,0,10},
401 {4,0,10}, {6,0,10}, {2,0,10}, {1,0,10},
402 {5,0,10}, {7,0,10}, {3,0,1}, {4,0,1},
403 {6,0,10}, {2,1,10}, {0,0,6}, {0,1,10},
404 /* hat #1 in metatile #10 (type F) */
405 {1,1,10}, {2,0,6}, {7,0,10}, {0,0,6},
406 {-1,-1,-1}, {0,1,10}, {5,1,10}, {2,1,10},
407 {7,0,10}, {3,1,10}, {1,1,10}, {5,1,10},
408 {2,1,10}, {4,0,10}, {4,1,10}, {-1,-1,-1},
409 {-1,-1,-1}, {5,1,10}, {-1,-1,-1}, {3,1,10},
410 {4,1,10}, {6,1,10}, {2,1,10}, {1,1,10},
411 {5,1,10}, {7,1,10}, {-1,-1,-1}, {-1,-1,-1},
412 {6,1,10}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
413 /* hat #2 in metatile #10 (type F) does not exist */
414 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
415 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
416 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
417 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
418 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
419 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
420 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
421 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
422 /* hat #3 in metatile #10 (type F) does not exist */
423 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
424 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
425 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
426 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
427 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
428 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
429 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
430 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
431 /* hat #0 in metatile #11 (type F) */
432 {1,0,11}, {2,0,12}, {-1,-1,-1}, {0,0,12},
433 {0,2,2}, {0,0,11}, {5,0,11}, {2,0,11},
434 {-1,-1,-1}, {3,0,11}, {1,0,11}, {5,0,11},
435 {2,0,11}, {-1,-1,-1}, {4,0,11}, {-1,-1,-1},
436 {3,1,11}, {5,0,11}, {-1,-1,-1}, {3,0,11},
437 {4,0,11}, {6,0,11}, {2,0,11}, {1,0,11},
438 {5,0,11}, {7,0,11}, {0,2,2}, {7,1,5},
439 {6,0,11}, {2,1,11}, {6,1,5}, {0,1,11},
440 /* hat #1 in metatile #11 (type F) */
441 {1,1,11}, {1,1,5}, {7,0,11}, {6,1,5},
442 {-1,-1,-1}, {0,1,11}, {5,1,11}, {2,1,11},
443 {7,0,11}, {3,1,11}, {1,1,11}, {5,1,11},
444 {2,1,11}, {4,0,11}, {4,1,11}, {-1,-1,-1},
445 {-1,-1,-1}, {5,1,11}, {-1,-1,-1}, {3,1,11},
446 {4,1,11}, {6,1,11}, {2,1,11}, {1,1,11},
447 {5,1,11}, {7,1,11}, {-1,-1,-1}, {-1,-1,-1},
448 {6,1,11}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
449 /* hat #2 in metatile #11 (type F) does not exist */
450 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
451 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
452 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
453 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
454 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
455 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
456 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
457 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
458 /* hat #3 in metatile #11 (type F) does not exist */
459 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
460 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
461 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
462 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
463 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
464 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
465 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
466 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
467 /* hat #0 in metatile #12 (type F) */
468 {1,0,12}, {-1,-1,-1}, {0,0,11}, {-1,-1,-1},
469 {-1,-1,-1}, {0,0,12}, {5,0,12}, {2,0,12},
470 {0,0,11}, {3,0,12}, {1,0,12}, {5,0,12},
471 {2,0,12}, {1,2,2}, {4,0,12}, {6,2,2},
472 {3,1,12}, {5,0,12}, {6,2,2}, {3,0,12},
473 {4,0,12}, {6,0,12}, {2,0,12}, {1,0,12},
474 {5,0,12}, {7,0,12}, {-1,-1,-1}, {-1,-1,-1},
475 {6,0,12}, {2,1,12}, {-1,-1,-1}, {0,1,12},
476 /* hat #1 in metatile #12 (type F) */
477 {1,1,12}, {-1,-1,-1}, {7,0,12}, {-1,-1,-1},
478 {-1,-1,-1}, {0,1,12}, {5,1,12}, {2,1,12},
479 {7,0,12}, {3,1,12}, {1,1,12}, {5,1,12},
480 {2,1,12}, {4,0,12}, {4,1,12}, {7,2,2},
481 {3,1,2}, {5,1,12}, {7,2,2}, {3,1,12},
482 {4,1,12}, {6,1,12}, {2,1,12}, {1,1,12},
483 {5,1,12}, {7,1,12}, {-1,-1,-1}, {7,1,6},
484 {6,1,12}, {2,1,2}, {6,1,6}, {0,1,2},
485 /* hat #2 in metatile #12 (type F) does not exist */
486 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
487 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
488 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
489 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
490 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
491 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
492 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
493 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
494 /* hat #3 in metatile #12 (type F) does not exist */
495 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
496 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
497 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
498 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
499 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
500 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
501 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
502 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
503};
504static const KitemapEntry kitemap_T[] = {
505 /* hat #0 in metatile #0 (type H) */
506 {1,0,0}, {7,3,0}, {3,0,3}, {4,0,3},
507 {4,3,0}, {0,0,0}, {5,0,0}, {2,0,0},
508 {3,0,3}, {3,0,0}, {1,0,0}, {5,0,0},
509 {2,0,0}, {1,1,6}, {4,0,0}, {6,1,6},
510 {0,0,2}, {5,0,0}, {6,1,6}, {3,0,0},
511 {4,0,0}, {6,0,0}, {2,0,0}, {1,0,0},
512 {5,0,0}, {7,0,0}, {4,3,0}, {3,3,0},
513 {6,0,0}, {1,0,2}, {7,1,0}, {6,0,2},
514 /* hat #1 in metatile #0 (type H) */
515 {1,1,0}, {1,1,4}, {7,1,1}, {6,1,4},
516 {0,1,2}, {0,1,0}, {5,1,0}, {2,1,0},
517 {7,1,1}, {3,1,0}, {1,1,0}, {5,1,0},
518 {2,1,0}, {4,1,1}, {4,1,0}, {0,3,0},
519 {2,3,0}, {5,1,0}, {0,3,0}, {3,1,0},
520 {4,1,0}, {6,1,0}, {2,1,0}, {1,1,0},
521 {5,1,0}, {7,1,0}, {0,1,2}, {7,0,2},
522 {6,1,0}, {3,3,0}, {6,0,2}, {7,0,0},
523 /* hat #2 in metatile #0 (type H) */
524 {1,2,0}, {1,1,5}, {7,1,3}, {6,1,5},
525 {3,0,1}, {0,2,0}, {5,2,0}, {2,2,0},
526 {7,1,3}, {3,2,0}, {1,2,0}, {5,2,0},
527 {2,2,0}, {4,1,3}, {4,2,0}, {6,3,0},
528 {1,3,0}, {5,2,0}, {6,3,0}, {3,2,0},
529 {4,2,0}, {6,2,0}, {2,2,0}, {1,2,0},
530 {5,2,0}, {7,2,0}, {3,0,1}, {4,0,1},
531 {6,2,0}, {0,3,0}, {3,1,1}, {4,1,1},
532 /* hat #3 in metatile #0 (type H) */
533 {7,2,0}, {1,3,0}, {3,1,0}, {4,1,0},
534 {0,3,0}, {4,2,0}, {2,3,0}, {5,3,0},
535 {3,3,0}, {4,1,0}, {5,3,0}, {1,3,0},
536 {7,1,0}, {2,3,0}, {6,0,0}, {4,3,0},
537 {5,3,0}, {1,0,0}, {3,3,0}, {6,0,0},
538 {6,3,0}, {4,3,0}, {1,3,0}, {2,3,0},
539 {7,3,0}, {5,3,0}, {3,2,0}, {4,2,0},
540 {0,0,0}, {6,3,0}, {3,1,3}, {4,1,3},
541 /* hat #0 in metatile #1 (type P) */
542 {1,0,1}, {-1,-1,-1}, {0,1,5}, {7,0,5},
543 {-1,-1,-1}, {0,0,1}, {5,0,1}, {2,0,1},
544 {0,1,5}, {3,0,1}, {1,0,1}, {5,0,1},
545 {2,0,1}, {1,2,0}, {4,0,1}, {6,2,0},
546 {3,1,1}, {5,0,1}, {6,2,0}, {3,0,1},
547 {4,0,1}, {6,0,1}, {2,0,1}, {1,0,1},
548 {5,0,1}, {7,0,1}, {-1,-1,-1}, {-1,-1,-1},
549 {6,0,1}, {2,1,1}, {-1,-1,-1}, {0,1,1},
550 /* hat #1 in metatile #1 (type P) */
551 {1,1,1}, {-1,-1,-1}, {7,0,1}, {-1,-1,-1},
552 {-1,-1,-1}, {0,1,1}, {5,1,1}, {2,1,1},
553 {7,0,1}, {3,1,1}, {1,1,1}, {5,1,1},
554 {2,1,1}, {4,0,1}, {4,1,1}, {7,2,0},
555 {3,1,0}, {5,1,1}, {7,2,0}, {3,1,1},
556 {4,1,1}, {6,1,1}, {2,1,1}, {1,1,1},
557 {5,1,1}, {7,1,1}, {-1,-1,-1}, {7,1,4},
558 {6,1,1}, {2,1,0}, {6,1,4}, {0,1,0},
559 /* hat #2 in metatile #1 (type P) does not exist */
560 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
561 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
562 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
563 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
564 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
565 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
566 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
567 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
568 /* hat #3 in metatile #1 (type P) does not exist */
569 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
570 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
571 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
572 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
573 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
574 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
575 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
576 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
577 /* hat #0 in metatile #2 (type P) */
578 {1,0,2}, {4,0,0}, {-1,-1,-1}, {7,1,6},
579 {7,0,0}, {0,0,2}, {5,0,2}, {2,0,2},
580 {-1,-1,-1}, {3,0,2}, {1,0,2}, {5,0,2},
581 {2,0,2}, {-1,-1,-1}, {4,0,2}, {-1,-1,-1},
582 {3,1,2}, {5,0,2}, {-1,-1,-1}, {3,0,2},
583 {4,0,2}, {6,0,2}, {2,0,2}, {1,0,2},
584 {5,0,2}, {7,0,2}, {7,0,0}, {7,1,0},
585 {6,0,2}, {2,1,2}, {6,1,0}, {0,1,2},
586 /* hat #1 in metatile #2 (type P) */
587 {1,1,2}, {1,1,0}, {7,0,2}, {6,1,0},
588 {0,1,4}, {0,1,2}, {5,1,2}, {2,1,2},
589 {7,0,2}, {3,1,2}, {1,1,2}, {5,1,2},
590 {2,1,2}, {4,0,2}, {4,1,2}, {-1,-1,-1},
591 {-1,-1,-1}, {5,1,2}, {-1,-1,-1}, {3,1,2},
592 {4,1,2}, {6,1,2}, {2,1,2}, {1,1,2},
593 {5,1,2}, {7,1,2}, {0,1,4}, {7,0,4},
594 {6,1,2}, {-1,-1,-1}, {6,0,4}, {-1,-1,-1},
595 /* hat #2 in metatile #2 (type P) does not exist */
596 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
597 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
598 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
599 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
600 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
601 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
602 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
603 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
604 /* hat #3 in metatile #2 (type P) does not exist */
605 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
606 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
607 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
608 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
609 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
610 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
611 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
612 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
613 /* hat #0 in metatile #3 (type P) */
614 {1,0,3}, {-1,-1,-1}, {0,1,6}, {7,0,6},
615 {-1,-1,-1}, {0,0,3}, {5,0,3}, {2,0,3},
616 {0,1,6}, {3,0,3}, {1,0,3}, {5,0,3},
617 {2,0,3}, {2,0,0}, {4,0,3}, {0,0,0},
618 {3,1,3}, {5,0,3}, {0,0,0}, {3,0,3},
619 {4,0,3}, {6,0,3}, {2,0,3}, {1,0,3},
620 {5,0,3}, {7,0,3}, {-1,-1,-1}, {-1,-1,-1},
621 {6,0,3}, {2,1,3}, {-1,-1,-1}, {0,1,3},
622 /* hat #1 in metatile #3 (type P) */
623 {1,1,3}, {-1,-1,-1}, {7,0,3}, {-1,-1,-1},
624 {-1,-1,-1}, {0,1,3}, {5,1,3}, {2,1,3},
625 {7,0,3}, {3,1,3}, {1,1,3}, {5,1,3},
626 {2,1,3}, {4,0,3}, {4,1,3}, {7,3,0},
627 {3,2,0}, {5,1,3}, {7,3,0}, {3,1,3},
628 {4,1,3}, {6,1,3}, {2,1,3}, {1,1,3},
629 {5,1,3}, {7,1,3}, {-1,-1,-1}, {7,1,5},
630 {6,1,3}, {2,2,0}, {6,1,5}, {0,2,0},
631 /* hat #2 in metatile #3 (type P) does not exist */
632 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
633 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
634 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
635 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
636 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
637 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
638 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
639 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
640 /* hat #3 in metatile #3 (type P) does not exist */
641 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
642 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
643 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
644 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
645 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
646 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
647 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
648 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
649 /* hat #0 in metatile #4 (type F) */
650 {1,0,4}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
651 {-1,-1,-1}, {0,0,4}, {5,0,4}, {2,0,4},
652 {-1,-1,-1}, {3,0,4}, {1,0,4}, {5,0,4},
653 {2,0,4}, {-1,-1,-1}, {4,0,4}, {-1,-1,-1},
654 {3,1,4}, {5,0,4}, {-1,-1,-1}, {3,0,4},
655 {4,0,4}, {6,0,4}, {2,0,4}, {1,0,4},
656 {5,0,4}, {7,0,4}, {-1,-1,-1}, {7,1,2},
657 {6,0,4}, {2,1,4}, {6,1,2}, {0,1,4},
658 /* hat #1 in metatile #4 (type F) */
659 {1,1,4}, {1,1,2}, {7,0,4}, {6,1,2},
660 {0,1,0}, {0,1,4}, {5,1,4}, {2,1,4},
661 {7,0,4}, {3,1,4}, {1,1,4}, {5,1,4},
662 {2,1,4}, {4,0,4}, {4,1,4}, {-1,-1,-1},
663 {-1,-1,-1}, {5,1,4}, {-1,-1,-1}, {3,1,4},
664 {4,1,4}, {6,1,4}, {2,1,4}, {1,1,4},
665 {5,1,4}, {7,1,4}, {0,1,0}, {7,1,1},
666 {6,1,4}, {-1,-1,-1}, {6,1,1}, {-1,-1,-1},
667 /* hat #2 in metatile #4 (type F) does not exist */
668 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
669 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
670 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
671 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
672 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
673 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
674 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
675 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
676 /* hat #3 in metatile #4 (type F) does not exist */
677 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
678 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
679 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
680 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
681 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
682 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
683 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
684 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
685 /* hat #0 in metatile #5 (type F) */
686 {1,0,5}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
687 {-1,-1,-1}, {0,0,5}, {5,0,5}, {2,0,5},
688 {-1,-1,-1}, {3,0,5}, {1,0,5}, {5,0,5},
689 {2,0,5}, {-1,-1,-1}, {4,0,5}, {-1,-1,-1},
690 {3,1,5}, {5,0,5}, {-1,-1,-1}, {3,0,5},
691 {4,0,5}, {6,0,5}, {2,0,5}, {1,0,5},
692 {5,0,5}, {7,0,5}, {-1,-1,-1}, {-1,-1,-1},
693 {6,0,5}, {2,1,5}, {0,0,1}, {0,1,5},
694 /* hat #1 in metatile #5 (type F) */
695 {1,1,5}, {2,0,1}, {7,0,5}, {0,0,1},
696 {0,2,0}, {0,1,5}, {5,1,5}, {2,1,5},
697 {7,0,5}, {3,1,5}, {1,1,5}, {5,1,5},
698 {2,1,5}, {4,0,5}, {4,1,5}, {-1,-1,-1},
699 {-1,-1,-1}, {5,1,5}, {-1,-1,-1}, {3,1,5},
700 {4,1,5}, {6,1,5}, {2,1,5}, {1,1,5},
701 {5,1,5}, {7,1,5}, {0,2,0}, {7,1,3},
702 {6,1,5}, {-1,-1,-1}, {6,1,3}, {-1,-1,-1},
703 /* hat #2 in metatile #5 (type F) does not exist */
704 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
705 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
706 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
707 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
708 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
709 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
710 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
711 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
712 /* hat #3 in metatile #5 (type F) does not exist */
713 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
714 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
715 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
716 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
717 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
718 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
719 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
720 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
721 /* hat #0 in metatile #6 (type F) */
722 {1,0,6}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
723 {-1,-1,-1}, {0,0,6}, {5,0,6}, {2,0,6},
724 {-1,-1,-1}, {3,0,6}, {1,0,6}, {5,0,6},
725 {2,0,6}, {-1,-1,-1}, {4,0,6}, {-1,-1,-1},
726 {3,1,6}, {5,0,6}, {-1,-1,-1}, {3,0,6},
727 {4,0,6}, {6,0,6}, {2,0,6}, {1,0,6},
728 {5,0,6}, {7,0,6}, {-1,-1,-1}, {-1,-1,-1},
729 {6,0,6}, {2,1,6}, {0,0,3}, {0,1,6},
730 /* hat #1 in metatile #6 (type F) */
731 {1,1,6}, {2,0,3}, {7,0,6}, {0,0,3},
732 {3,0,0}, {0,1,6}, {5,1,6}, {2,1,6},
733 {7,0,6}, {3,1,6}, {1,1,6}, {5,1,6},
734 {2,1,6}, {4,0,6}, {4,1,6}, {-1,-1,-1},
735 {-1,-1,-1}, {5,1,6}, {-1,-1,-1}, {3,1,6},
736 {4,1,6}, {6,1,6}, {2,1,6}, {1,1,6},
737 {5,1,6}, {7,1,6}, {3,0,0}, {4,0,0},
738 {6,1,6}, {-1,-1,-1}, {0,0,2}, {-1,-1,-1},
739 /* hat #2 in metatile #6 (type F) does not exist */
740 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
741 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
742 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
743 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
744 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
745 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
746 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
747 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
748 /* hat #3 in metatile #6 (type F) does not exist */
749 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
750 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
751 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
752 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
753 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
754 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
755 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
756 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
757};
758static const KitemapEntry kitemap_P[] = {
759 /* hat #0 in metatile #0 (type H) */
760 {1,0,0}, {7,3,0}, {3,0,4}, {4,0,4},
761 {4,3,0}, {0,0,0}, {5,0,0}, {2,0,0},
762 {3,0,4}, {3,0,0}, {1,0,0}, {5,0,0},
763 {2,0,0}, {1,1,9}, {4,0,0}, {6,1,9},
764 {0,0,3}, {5,0,0}, {6,1,9}, {3,0,0},
765 {4,0,0}, {6,0,0}, {2,0,0}, {1,0,0},
766 {5,0,0}, {7,0,0}, {4,3,0}, {3,3,0},
767 {6,0,0}, {1,0,3}, {7,1,0}, {6,0,3},
768 /* hat #1 in metatile #0 (type H) */
769 {1,1,0}, {1,1,8}, {7,1,5}, {6,1,8},
770 {0,1,3}, {0,1,0}, {5,1,0}, {2,1,0},
771 {7,1,5}, {3,1,0}, {1,1,0}, {5,1,0},
772 {2,1,0}, {4,1,5}, {4,1,0}, {0,3,0},
773 {2,3,0}, {5,1,0}, {0,3,0}, {3,1,0},
774 {4,1,0}, {6,1,0}, {2,1,0}, {1,1,0},
775 {5,1,0}, {7,1,0}, {0,1,3}, {7,0,3},
776 {6,1,0}, {3,3,0}, {6,0,3}, {7,0,0},
777 /* hat #2 in metatile #0 (type H) */
778 {1,2,0}, {1,0,6}, {7,1,4}, {6,0,6},
779 {3,0,5}, {0,2,0}, {5,2,0}, {2,2,0},
780 {7,1,4}, {3,2,0}, {1,2,0}, {5,2,0},
781 {2,2,0}, {4,1,4}, {4,2,0}, {6,3,0},
782 {1,3,0}, {5,2,0}, {6,3,0}, {3,2,0},
783 {4,2,0}, {6,2,0}, {2,2,0}, {1,2,0},
784 {5,2,0}, {7,2,0}, {3,0,5}, {4,0,5},
785 {6,2,0}, {0,3,0}, {3,1,5}, {4,1,5},
786 /* hat #3 in metatile #0 (type H) */
787 {7,2,0}, {1,3,0}, {3,1,0}, {4,1,0},
788 {0,3,0}, {4,2,0}, {2,3,0}, {5,3,0},
789 {3,3,0}, {4,1,0}, {5,3,0}, {1,3,0},
790 {7,1,0}, {2,3,0}, {6,0,0}, {4,3,0},
791 {5,3,0}, {1,0,0}, {3,3,0}, {6,0,0},
792 {6,3,0}, {4,3,0}, {1,3,0}, {2,3,0},
793 {7,3,0}, {5,3,0}, {3,2,0}, {4,2,0},
794 {0,0,0}, {6,3,0}, {3,1,4}, {4,1,4},
795 /* hat #0 in metatile #1 (type H) */
796 {1,0,1}, {7,3,1}, {3,0,10}, {4,0,10},
797 {4,3,1}, {0,0,1}, {5,0,1}, {2,0,1},
798 {3,0,10}, {3,0,1}, {1,0,1}, {5,0,1},
799 {2,0,1}, {1,0,9}, {4,0,1}, {6,0,9},
800 {0,0,4}, {5,0,1}, {6,0,9}, {3,0,1},
801 {4,0,1}, {6,0,1}, {2,0,1}, {1,0,1},
802 {5,0,1}, {7,0,1}, {4,3,1}, {3,3,1},
803 {6,0,1}, {1,0,4}, {7,1,1}, {6,0,4},
804 /* hat #1 in metatile #1 (type H) */
805 {1,1,1}, {1,1,6}, {7,1,2}, {6,1,6},
806 {0,1,4}, {0,1,1}, {5,1,1}, {2,1,1},
807 {7,1,2}, {3,1,1}, {1,1,1}, {5,1,1},
808 {2,1,1}, {4,1,2}, {4,1,1}, {0,3,1},
809 {2,3,1}, {5,1,1}, {0,3,1}, {3,1,1},
810 {4,1,1}, {6,1,1}, {2,1,1}, {1,1,1},
811 {5,1,1}, {7,1,1}, {0,1,4}, {7,0,4},
812 {6,1,1}, {3,3,1}, {6,0,4}, {7,0,1},
813 /* hat #2 in metatile #1 (type H) */
814 {1,2,1}, {1,1,7}, {7,1,10}, {6,1,7},
815 {3,0,2}, {0,2,1}, {5,2,1}, {2,2,1},
816 {7,1,10}, {3,2,1}, {1,2,1}, {5,2,1},
817 {2,2,1}, {4,1,10}, {4,2,1}, {6,3,1},
818 {1,3,1}, {5,2,1}, {6,3,1}, {3,2,1},
819 {4,2,1}, {6,2,1}, {2,2,1}, {1,2,1},
820 {5,2,1}, {7,2,1}, {3,0,2}, {4,0,2},
821 {6,2,1}, {0,3,1}, {3,1,2}, {4,1,2},
822 /* hat #3 in metatile #1 (type H) */
823 {7,2,1}, {1,3,1}, {3,1,1}, {4,1,1},
824 {0,3,1}, {4,2,1}, {2,3,1}, {5,3,1},
825 {3,3,1}, {4,1,1}, {5,3,1}, {1,3,1},
826 {7,1,1}, {2,3,1}, {6,0,1}, {4,3,1},
827 {5,3,1}, {1,0,1}, {3,3,1}, {6,0,1},
828 {6,3,1}, {4,3,1}, {1,3,1}, {2,3,1},
829 {7,3,1}, {5,3,1}, {3,2,1}, {4,2,1},
830 {0,0,1}, {6,3,1}, {3,1,10}, {4,1,10},
831 /* hat #0 in metatile #2 (type P) */
832 {1,0,2}, {-1,-1,-1}, {0,1,7}, {7,0,7},
833 {-1,-1,-1}, {0,0,2}, {5,0,2}, {2,0,2},
834 {0,1,7}, {3,0,2}, {1,0,2}, {5,0,2},
835 {2,0,2}, {1,2,1}, {4,0,2}, {6,2,1},
836 {3,1,2}, {5,0,2}, {6,2,1}, {3,0,2},
837 {4,0,2}, {6,0,2}, {2,0,2}, {1,0,2},
838 {5,0,2}, {7,0,2}, {-1,-1,-1}, {-1,-1,-1},
839 {6,0,2}, {2,1,2}, {-1,-1,-1}, {0,1,2},
840 /* hat #1 in metatile #2 (type P) */
841 {1,1,2}, {-1,-1,-1}, {7,0,2}, {-1,-1,-1},
842 {-1,-1,-1}, {0,1,2}, {5,1,2}, {2,1,2},
843 {7,0,2}, {3,1,2}, {1,1,2}, {5,1,2},
844 {2,1,2}, {4,0,2}, {4,1,2}, {7,2,1},
845 {3,1,1}, {5,1,2}, {7,2,1}, {3,1,2},
846 {4,1,2}, {6,1,2}, {2,1,2}, {1,1,2},
847 {5,1,2}, {7,1,2}, {-1,-1,-1}, {7,1,6},
848 {6,1,2}, {2,1,1}, {6,1,6}, {0,1,1},
849 /* hat #2 in metatile #2 (type P) does not exist */
850 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
851 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
852 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
853 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
854 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
855 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
856 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
857 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
858 /* hat #3 in metatile #2 (type P) does not exist */
859 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
860 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
861 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
862 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
863 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
864 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
865 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
866 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
867 /* hat #0 in metatile #3 (type P) */
868 {1,0,3}, {4,0,0}, {-1,-1,-1}, {7,1,9},
869 {7,0,0}, {0,0,3}, {5,0,3}, {2,0,3},
870 {-1,-1,-1}, {3,0,3}, {1,0,3}, {5,0,3},
871 {2,0,3}, {-1,-1,-1}, {4,0,3}, {-1,-1,-1},
872 {3,1,3}, {5,0,3}, {-1,-1,-1}, {3,0,3},
873 {4,0,3}, {6,0,3}, {2,0,3}, {1,0,3},
874 {5,0,3}, {7,0,3}, {7,0,0}, {7,1,0},
875 {6,0,3}, {2,1,3}, {6,1,0}, {0,1,3},
876 /* hat #1 in metatile #3 (type P) */
877 {1,1,3}, {1,1,0}, {7,0,3}, {6,1,0},
878 {0,1,8}, {0,1,3}, {5,1,3}, {2,1,3},
879 {7,0,3}, {3,1,3}, {1,1,3}, {5,1,3},
880 {2,1,3}, {4,0,3}, {4,1,3}, {-1,-1,-1},
881 {-1,-1,-1}, {5,1,3}, {-1,-1,-1}, {3,1,3},
882 {4,1,3}, {6,1,3}, {2,1,3}, {1,1,3},
883 {5,1,3}, {7,1,3}, {0,1,8}, {7,0,8},
884 {6,1,3}, {-1,-1,-1}, {6,0,8}, {-1,-1,-1},
885 /* hat #2 in metatile #3 (type P) does not exist */
886 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
887 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
888 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
889 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
890 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
891 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
892 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
893 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
894 /* hat #3 in metatile #3 (type P) does not exist */
895 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
896 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
897 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
898 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
899 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
900 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
901 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
902 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
903 /* hat #0 in metatile #4 (type P) */
904 {1,0,4}, {4,0,1}, {0,1,9}, {7,0,9},
905 {7,0,1}, {0,0,4}, {5,0,4}, {2,0,4},
906 {0,1,9}, {3,0,4}, {1,0,4}, {5,0,4},
907 {2,0,4}, {2,0,0}, {4,0,4}, {0,0,0},
908 {3,1,4}, {5,0,4}, {0,0,0}, {3,0,4},
909 {4,0,4}, {6,0,4}, {2,0,4}, {1,0,4},
910 {5,0,4}, {7,0,4}, {7,0,1}, {7,1,1},
911 {6,0,4}, {2,1,4}, {6,1,1}, {0,1,4},
912 /* hat #1 in metatile #4 (type P) */
913 {1,1,4}, {1,1,1}, {7,0,4}, {6,1,1},
914 {0,1,6}, {0,1,4}, {5,1,4}, {2,1,4},
915 {7,0,4}, {3,1,4}, {1,1,4}, {5,1,4},
916 {2,1,4}, {4,0,4}, {4,1,4}, {7,3,0},
917 {3,2,0}, {5,1,4}, {7,3,0}, {3,1,4},
918 {4,1,4}, {6,1,4}, {2,1,4}, {1,1,4},
919 {5,1,4}, {7,1,4}, {0,1,6}, {7,0,6},
920 {6,1,4}, {2,2,0}, {6,0,6}, {0,2,0},
921 /* hat #2 in metatile #4 (type P) does not exist */
922 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
923 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
924 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
925 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
926 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
927 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
928 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
929 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
930 /* hat #3 in metatile #4 (type P) does not exist */
931 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
932 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
933 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
934 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
935 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
936 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
937 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
938 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
939 /* hat #0 in metatile #5 (type F) */
940 {1,0,5}, {-1,-1,-1}, {0,0,6}, {-1,-1,-1},
941 {-1,-1,-1}, {0,0,5}, {5,0,5}, {2,0,5},
942 {0,0,6}, {3,0,5}, {1,0,5}, {5,0,5},
943 {2,0,5}, {1,2,0}, {4,0,5}, {6,2,0},
944 {3,1,5}, {5,0,5}, {6,2,0}, {3,0,5},
945 {4,0,5}, {6,0,5}, {2,0,5}, {1,0,5},
946 {5,0,5}, {7,0,5}, {-1,-1,-1}, {-1,-1,-1},
947 {6,0,5}, {2,1,5}, {-1,-1,-1}, {0,1,5},
948 /* hat #1 in metatile #5 (type F) */
949 {1,1,5}, {-1,-1,-1}, {7,0,5}, {-1,-1,-1},
950 {-1,-1,-1}, {0,1,5}, {5,1,5}, {2,1,5},
951 {7,0,5}, {3,1,5}, {1,1,5}, {5,1,5},
952 {2,1,5}, {4,0,5}, {4,1,5}, {7,2,0},
953 {3,1,0}, {5,1,5}, {7,2,0}, {3,1,5},
954 {4,1,5}, {6,1,5}, {2,1,5}, {1,1,5},
955 {5,1,5}, {7,1,5}, {-1,-1,-1}, {7,1,8},
956 {6,1,5}, {2,1,0}, {6,1,8}, {0,1,0},
957 /* hat #2 in metatile #5 (type F) does not exist */
958 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
959 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
960 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
961 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
962 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
963 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
964 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
965 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
966 /* hat #3 in metatile #5 (type F) does not exist */
967 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
968 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
969 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
970 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
971 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
972 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
973 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
974 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
975 /* hat #0 in metatile #6 (type F) */
976 {1,0,6}, {2,0,5}, {-1,-1,-1}, {0,0,5},
977 {0,2,0}, {0,0,6}, {5,0,6}, {2,0,6},
978 {-1,-1,-1}, {3,0,6}, {1,0,6}, {5,0,6},
979 {2,0,6}, {-1,-1,-1}, {4,0,6}, {-1,-1,-1},
980 {3,1,6}, {5,0,6}, {-1,-1,-1}, {3,0,6},
981 {4,0,6}, {6,0,6}, {2,0,6}, {1,0,6},
982 {5,0,6}, {7,0,6}, {0,2,0}, {7,1,4},
983 {6,0,6}, {2,1,6}, {6,1,4}, {0,1,6},
984 /* hat #1 in metatile #6 (type F) */
985 {1,1,6}, {1,1,4}, {7,0,6}, {6,1,4},
986 {0,1,1}, {0,1,6}, {5,1,6}, {2,1,6},
987 {7,0,6}, {3,1,6}, {1,1,6}, {5,1,6},
988 {2,1,6}, {4,0,6}, {4,1,6}, {-1,-1,-1},
989 {-1,-1,-1}, {5,1,6}, {-1,-1,-1}, {3,1,6},
990 {4,1,6}, {6,1,6}, {2,1,6}, {1,1,6},
991 {5,1,6}, {7,1,6}, {0,1,1}, {7,1,2},
992 {6,1,6}, {-1,-1,-1}, {6,1,2}, {-1,-1,-1},
993 /* hat #2 in metatile #6 (type F) does not exist */
994 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
995 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
996 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
997 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
998 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
999 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1000 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1001 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1002 /* hat #3 in metatile #6 (type F) does not exist */
1003 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1004 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1005 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1006 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1007 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1008 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1009 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1010 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1011 /* hat #0 in metatile #7 (type F) */
1012 {1,0,7}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1013 {-1,-1,-1}, {0,0,7}, {5,0,7}, {2,0,7},
1014 {-1,-1,-1}, {3,0,7}, {1,0,7}, {5,0,7},
1015 {2,0,7}, {-1,-1,-1}, {4,0,7}, {-1,-1,-1},
1016 {3,1,7}, {5,0,7}, {-1,-1,-1}, {3,0,7},
1017 {4,0,7}, {6,0,7}, {2,0,7}, {1,0,7},
1018 {5,0,7}, {7,0,7}, {-1,-1,-1}, {-1,-1,-1},
1019 {6,0,7}, {2,1,7}, {0,0,2}, {0,1,7},
1020 /* hat #1 in metatile #7 (type F) */
1021 {1,1,7}, {2,0,2}, {7,0,7}, {0,0,2},
1022 {0,2,1}, {0,1,7}, {5,1,7}, {2,1,7},
1023 {7,0,7}, {3,1,7}, {1,1,7}, {5,1,7},
1024 {2,1,7}, {4,0,7}, {4,1,7}, {-1,-1,-1},
1025 {-1,-1,-1}, {5,1,7}, {-1,-1,-1}, {3,1,7},
1026 {4,1,7}, {6,1,7}, {2,1,7}, {1,1,7},
1027 {5,1,7}, {7,1,7}, {0,2,1}, {7,1,10},
1028 {6,1,7}, {-1,-1,-1}, {6,1,10}, {-1,-1,-1},
1029 /* hat #2 in metatile #7 (type F) does not exist */
1030 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1031 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1032 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1033 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1034 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1035 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1036 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1037 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1038 /* hat #3 in metatile #7 (type F) does not exist */
1039 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1040 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1041 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1042 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1043 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1044 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1045 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1046 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1047 /* hat #0 in metatile #8 (type F) */
1048 {1,0,8}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1049 {-1,-1,-1}, {0,0,8}, {5,0,8}, {2,0,8},
1050 {-1,-1,-1}, {3,0,8}, {1,0,8}, {5,0,8},
1051 {2,0,8}, {-1,-1,-1}, {4,0,8}, {-1,-1,-1},
1052 {3,1,8}, {5,0,8}, {-1,-1,-1}, {3,0,8},
1053 {4,0,8}, {6,0,8}, {2,0,8}, {1,0,8},
1054 {5,0,8}, {7,0,8}, {-1,-1,-1}, {7,1,3},
1055 {6,0,8}, {2,1,8}, {6,1,3}, {0,1,8},
1056 /* hat #1 in metatile #8 (type F) */
1057 {1,1,8}, {1,1,3}, {7,0,8}, {6,1,3},
1058 {0,1,0}, {0,1,8}, {5,1,8}, {2,1,8},
1059 {7,0,8}, {3,1,8}, {1,1,8}, {5,1,8},
1060 {2,1,8}, {4,0,8}, {4,1,8}, {-1,-1,-1},
1061 {-1,-1,-1}, {5,1,8}, {-1,-1,-1}, {3,1,8},
1062 {4,1,8}, {6,1,8}, {2,1,8}, {1,1,8},
1063 {5,1,8}, {7,1,8}, {0,1,0}, {7,1,5},
1064 {6,1,8}, {-1,-1,-1}, {6,1,5}, {-1,-1,-1},
1065 /* hat #2 in metatile #8 (type F) does not exist */
1066 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1067 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1068 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1069 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1070 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1071 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1072 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1073 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1074 /* hat #3 in metatile #8 (type F) does not exist */
1075 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1076 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1077 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1078 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1079 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1080 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1081 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1082 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1083 /* hat #0 in metatile #9 (type F) */
1084 {1,0,9}, {2,0,10}, {-1,-1,-1}, {0,0,10},
1085 {3,0,1}, {0,0,9}, {5,0,9}, {2,0,9},
1086 {-1,-1,-1}, {3,0,9}, {1,0,9}, {5,0,9},
1087 {2,0,9}, {-1,-1,-1}, {4,0,9}, {-1,-1,-1},
1088 {3,1,9}, {5,0,9}, {-1,-1,-1}, {3,0,9},
1089 {4,0,9}, {6,0,9}, {2,0,9}, {1,0,9},
1090 {5,0,9}, {7,0,9}, {3,0,1}, {4,0,1},
1091 {6,0,9}, {2,1,9}, {0,0,4}, {0,1,9},
1092 /* hat #1 in metatile #9 (type F) */
1093 {1,1,9}, {2,0,4}, {7,0,9}, {0,0,4},
1094 {3,0,0}, {0,1,9}, {5,1,9}, {2,1,9},
1095 {7,0,9}, {3,1,9}, {1,1,9}, {5,1,9},
1096 {2,1,9}, {4,0,9}, {4,1,9}, {-1,-1,-1},
1097 {-1,-1,-1}, {5,1,9}, {-1,-1,-1}, {3,1,9},
1098 {4,1,9}, {6,1,9}, {2,1,9}, {1,1,9},
1099 {5,1,9}, {7,1,9}, {3,0,0}, {4,0,0},
1100 {6,1,9}, {-1,-1,-1}, {0,0,3}, {-1,-1,-1},
1101 /* hat #2 in metatile #9 (type F) does not exist */
1102 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1103 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1104 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1105 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1106 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1107 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1108 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1109 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1110 /* hat #3 in metatile #9 (type F) does not exist */
1111 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1112 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1113 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1114 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1115 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1116 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1117 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1118 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1119 /* hat #0 in metatile #10 (type F) */
1120 {1,0,10}, {-1,-1,-1}, {0,0,9}, {-1,-1,-1},
1121 {-1,-1,-1}, {0,0,10}, {5,0,10}, {2,0,10},
1122 {0,0,9}, {3,0,10}, {1,0,10}, {5,0,10},
1123 {2,0,10}, {2,0,1}, {4,0,10}, {0,0,1},
1124 {3,1,10}, {5,0,10}, {0,0,1}, {3,0,10},
1125 {4,0,10}, {6,0,10}, {2,0,10}, {1,0,10},
1126 {5,0,10}, {7,0,10}, {-1,-1,-1}, {-1,-1,-1},
1127 {6,0,10}, {2,1,10}, {-1,-1,-1}, {0,1,10},
1128 /* hat #1 in metatile #10 (type F) */
1129 {1,1,10}, {-1,-1,-1}, {7,0,10}, {-1,-1,-1},
1130 {-1,-1,-1}, {0,1,10}, {5,1,10}, {2,1,10},
1131 {7,0,10}, {3,1,10}, {1,1,10}, {5,1,10},
1132 {2,1,10}, {4,0,10}, {4,1,10}, {7,3,1},
1133 {3,2,1}, {5,1,10}, {7,3,1}, {3,1,10},
1134 {4,1,10}, {6,1,10}, {2,1,10}, {1,1,10},
1135 {5,1,10}, {7,1,10}, {-1,-1,-1}, {7,1,7},
1136 {6,1,10}, {2,2,1}, {6,1,7}, {0,2,1},
1137 /* hat #2 in metatile #10 (type F) does not exist */
1138 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1139 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1140 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1141 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1142 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1143 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1144 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1145 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1146 /* hat #3 in metatile #10 (type F) does not exist */
1147 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1148 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1149 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1150 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1151 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1152 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1153 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1154 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1155};
1156static const KitemapEntry kitemap_F[] = {
1157 /* hat #0 in metatile #0 (type H) */
1158 {1,0,0}, {7,3,0}, {3,0,3}, {4,0,3},
1159 {4,3,0}, {0,0,0}, {5,0,0}, {2,0,0},
1160 {3,0,3}, {3,0,0}, {1,0,0}, {5,0,0},
1161 {2,0,0}, {1,1,9}, {4,0,0}, {6,1,9},
1162 {0,0,2}, {5,0,0}, {6,1,9}, {3,0,0},
1163 {4,0,0}, {6,0,0}, {2,0,0}, {1,0,0},
1164 {5,0,0}, {7,0,0}, {4,3,0}, {3,3,0},
1165 {6,0,0}, {1,0,2}, {7,1,0}, {6,0,2},
1166 /* hat #1 in metatile #0 (type H) */
1167 {1,1,0}, {1,1,8}, {7,1,4}, {6,1,8},
1168 {0,1,2}, {0,1,0}, {5,1,0}, {2,1,0},
1169 {7,1,4}, {3,1,0}, {1,1,0}, {5,1,0},
1170 {2,1,0}, {4,1,4}, {4,1,0}, {0,3,0},
1171 {2,3,0}, {5,1,0}, {0,3,0}, {3,1,0},
1172 {4,1,0}, {6,1,0}, {2,1,0}, {1,1,0},
1173 {5,1,0}, {7,1,0}, {0,1,2}, {7,0,2},
1174 {6,1,0}, {3,3,0}, {6,0,2}, {7,0,0},
1175 /* hat #2 in metatile #0 (type H) */
1176 {1,2,0}, {1,0,5}, {7,1,3}, {6,0,5},
1177 {3,0,4}, {0,2,0}, {5,2,0}, {2,2,0},
1178 {7,1,3}, {3,2,0}, {1,2,0}, {5,2,0},
1179 {2,2,0}, {4,1,3}, {4,2,0}, {6,3,0},
1180 {1,3,0}, {5,2,0}, {6,3,0}, {3,2,0},
1181 {4,2,0}, {6,2,0}, {2,2,0}, {1,2,0},
1182 {5,2,0}, {7,2,0}, {3,0,4}, {4,0,4},
1183 {6,2,0}, {0,3,0}, {3,1,4}, {4,1,4},
1184 /* hat #3 in metatile #0 (type H) */
1185 {7,2,0}, {1,3,0}, {3,1,0}, {4,1,0},
1186 {0,3,0}, {4,2,0}, {2,3,0}, {5,3,0},
1187 {3,3,0}, {4,1,0}, {5,3,0}, {1,3,0},
1188 {7,1,0}, {2,3,0}, {6,0,0}, {4,3,0},
1189 {5,3,0}, {1,0,0}, {3,3,0}, {6,0,0},
1190 {6,3,0}, {4,3,0}, {1,3,0}, {2,3,0},
1191 {7,3,0}, {5,3,0}, {3,2,0}, {4,2,0},
1192 {0,0,0}, {6,3,0}, {3,1,3}, {4,1,3},
1193 /* hat #0 in metatile #1 (type H) */
1194 {1,0,1}, {7,3,1}, {3,0,10}, {4,0,10},
1195 {4,3,1}, {0,0,1}, {5,0,1}, {2,0,1},
1196 {3,0,10}, {3,0,1}, {1,0,1}, {5,0,1},
1197 {2,0,1}, {1,0,9}, {4,0,1}, {6,0,9},
1198 {0,0,3}, {5,0,1}, {6,0,9}, {3,0,1},
1199 {4,0,1}, {6,0,1}, {2,0,1}, {1,0,1},
1200 {5,0,1}, {7,0,1}, {4,3,1}, {3,3,1},
1201 {6,0,1}, {1,0,3}, {7,1,1}, {6,0,3},
1202 /* hat #1 in metatile #1 (type H) */
1203 {1,1,1}, {1,1,5}, {7,1,6}, {6,1,5},
1204 {0,1,3}, {0,1,1}, {5,1,1}, {2,1,1},
1205 {7,1,6}, {3,1,1}, {1,1,1}, {5,1,1},
1206 {2,1,1}, {4,1,6}, {4,1,1}, {0,3,1},
1207 {2,3,1}, {5,1,1}, {0,3,1}, {3,1,1},
1208 {4,1,1}, {6,1,1}, {2,1,1}, {1,1,1},
1209 {5,1,1}, {7,1,1}, {0,1,3}, {7,0,3},
1210 {6,1,1}, {3,3,1}, {6,0,3}, {7,0,1},
1211 /* hat #2 in metatile #1 (type H) */
1212 {1,2,1}, {1,0,7}, {7,1,10}, {6,0,7},
1213 {3,0,6}, {0,2,1}, {5,2,1}, {2,2,1},
1214 {7,1,10}, {3,2,1}, {1,2,1}, {5,2,1},
1215 {2,2,1}, {4,1,10}, {4,2,1}, {6,3,1},
1216 {1,3,1}, {5,2,1}, {6,3,1}, {3,2,1},
1217 {4,2,1}, {6,2,1}, {2,2,1}, {1,2,1},
1218 {5,2,1}, {7,2,1}, {3,0,6}, {4,0,6},
1219 {6,2,1}, {0,3,1}, {3,1,6}, {4,1,6},
1220 /* hat #3 in metatile #1 (type H) */
1221 {7,2,1}, {1,3,1}, {3,1,1}, {4,1,1},
1222 {0,3,1}, {4,2,1}, {2,3,1}, {5,3,1},
1223 {3,3,1}, {4,1,1}, {5,3,1}, {1,3,1},
1224 {7,1,1}, {2,3,1}, {6,0,1}, {4,3,1},
1225 {5,3,1}, {1,0,1}, {3,3,1}, {6,0,1},
1226 {6,3,1}, {4,3,1}, {1,3,1}, {2,3,1},
1227 {7,3,1}, {5,3,1}, {3,2,1}, {4,2,1},
1228 {0,0,1}, {6,3,1}, {3,1,10}, {4,1,10},
1229 /* hat #0 in metatile #2 (type P) */
1230 {1,0,2}, {4,0,0}, {-1,-1,-1}, {7,1,9},
1231 {7,0,0}, {0,0,2}, {5,0,2}, {2,0,2},
1232 {-1,-1,-1}, {3,0,2}, {1,0,2}, {5,0,2},
1233 {2,0,2}, {-1,-1,-1}, {4,0,2}, {-1,-1,-1},
1234 {3,1,2}, {5,0,2}, {-1,-1,-1}, {3,0,2},
1235 {4,0,2}, {6,0,2}, {2,0,2}, {1,0,2},
1236 {5,0,2}, {7,0,2}, {7,0,0}, {7,1,0},
1237 {6,0,2}, {2,1,2}, {6,1,0}, {0,1,2},
1238 /* hat #1 in metatile #2 (type P) */
1239 {1,1,2}, {1,1,0}, {7,0,2}, {6,1,0},
1240 {0,1,8}, {0,1,2}, {5,1,2}, {2,1,2},
1241 {7,0,2}, {3,1,2}, {1,1,2}, {5,1,2},
1242 {2,1,2}, {4,0,2}, {4,1,2}, {-1,-1,-1},
1243 {-1,-1,-1}, {5,1,2}, {-1,-1,-1}, {3,1,2},
1244 {4,1,2}, {6,1,2}, {2,1,2}, {1,1,2},
1245 {5,1,2}, {7,1,2}, {0,1,8}, {7,0,8},
1246 {6,1,2}, {-1,-1,-1}, {6,0,8}, {-1,-1,-1},
1247 /* hat #2 in metatile #2 (type P) does not exist */
1248 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1249 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1250 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1251 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1252 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1253 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1254 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1255 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1256 /* hat #3 in metatile #2 (type P) does not exist */
1257 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1258 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1259 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1260 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1261 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1262 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1263 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1264 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1265 /* hat #0 in metatile #3 (type P) */
1266 {1,0,3}, {4,0,1}, {0,1,9}, {7,0,9},
1267 {7,0,1}, {0,0,3}, {5,0,3}, {2,0,3},
1268 {0,1,9}, {3,0,3}, {1,0,3}, {5,0,3},
1269 {2,0,3}, {2,0,0}, {4,0,3}, {0,0,0},
1270 {3,1,3}, {5,0,3}, {0,0,0}, {3,0,3},
1271 {4,0,3}, {6,0,3}, {2,0,3}, {1,0,3},
1272 {5,0,3}, {7,0,3}, {7,0,1}, {7,1,1},
1273 {6,0,3}, {2,1,3}, {6,1,1}, {0,1,3},
1274 /* hat #1 in metatile #3 (type P) */
1275 {1,1,3}, {1,1,1}, {7,0,3}, {6,1,1},
1276 {0,1,5}, {0,1,3}, {5,1,3}, {2,1,3},
1277 {7,0,3}, {3,1,3}, {1,1,3}, {5,1,3},
1278 {2,1,3}, {4,0,3}, {4,1,3}, {7,3,0},
1279 {3,2,0}, {5,1,3}, {7,3,0}, {3,1,3},
1280 {4,1,3}, {6,1,3}, {2,1,3}, {1,1,3},
1281 {5,1,3}, {7,1,3}, {0,1,5}, {7,0,5},
1282 {6,1,3}, {2,2,0}, {6,0,5}, {0,2,0},
1283 /* hat #2 in metatile #3 (type P) does not exist */
1284 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1285 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1286 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1287 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1288 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1289 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1290 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1291 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1292 /* hat #3 in metatile #3 (type P) does not exist */
1293 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1294 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1295 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1296 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1297 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1298 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1299 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1300 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1301 /* hat #0 in metatile #4 (type F) */
1302 {1,0,4}, {-1,-1,-1}, {0,0,5}, {-1,-1,-1},
1303 {-1,-1,-1}, {0,0,4}, {5,0,4}, {2,0,4},
1304 {0,0,5}, {3,0,4}, {1,0,4}, {5,0,4},
1305 {2,0,4}, {1,2,0}, {4,0,4}, {6,2,0},
1306 {3,1,4}, {5,0,4}, {6,2,0}, {3,0,4},
1307 {4,0,4}, {6,0,4}, {2,0,4}, {1,0,4},
1308 {5,0,4}, {7,0,4}, {-1,-1,-1}, {-1,-1,-1},
1309 {6,0,4}, {2,1,4}, {-1,-1,-1}, {0,1,4},
1310 /* hat #1 in metatile #4 (type F) */
1311 {1,1,4}, {-1,-1,-1}, {7,0,4}, {-1,-1,-1},
1312 {-1,-1,-1}, {0,1,4}, {5,1,4}, {2,1,4},
1313 {7,0,4}, {3,1,4}, {1,1,4}, {5,1,4},
1314 {2,1,4}, {4,0,4}, {4,1,4}, {7,2,0},
1315 {3,1,0}, {5,1,4}, {7,2,0}, {3,1,4},
1316 {4,1,4}, {6,1,4}, {2,1,4}, {1,1,4},
1317 {5,1,4}, {7,1,4}, {-1,-1,-1}, {7,1,8},
1318 {6,1,4}, {2,1,0}, {6,1,8}, {0,1,0},
1319 /* hat #2 in metatile #4 (type F) does not exist */
1320 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1321 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1322 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1323 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1324 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1325 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1326 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1327 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1328 /* hat #3 in metatile #4 (type F) does not exist */
1329 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1330 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1331 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1332 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1333 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1334 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1335 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1336 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1337 /* hat #0 in metatile #5 (type F) */
1338 {1,0,5}, {2,0,4}, {-1,-1,-1}, {0,0,4},
1339 {0,2,0}, {0,0,5}, {5,0,5}, {2,0,5},
1340 {-1,-1,-1}, {3,0,5}, {1,0,5}, {5,0,5},
1341 {2,0,5}, {-1,-1,-1}, {4,0,5}, {-1,-1,-1},
1342 {3,1,5}, {5,0,5}, {-1,-1,-1}, {3,0,5},
1343 {4,0,5}, {6,0,5}, {2,0,5}, {1,0,5},
1344 {5,0,5}, {7,0,5}, {0,2,0}, {7,1,3},
1345 {6,0,5}, {2,1,5}, {6,1,3}, {0,1,5},
1346 /* hat #1 in metatile #5 (type F) */
1347 {1,1,5}, {1,1,3}, {7,0,5}, {6,1,3},
1348 {0,1,1}, {0,1,5}, {5,1,5}, {2,1,5},
1349 {7,0,5}, {3,1,5}, {1,1,5}, {5,1,5},
1350 {2,1,5}, {4,0,5}, {4,1,5}, {-1,-1,-1},
1351 {-1,-1,-1}, {5,1,5}, {-1,-1,-1}, {3,1,5},
1352 {4,1,5}, {6,1,5}, {2,1,5}, {1,1,5},
1353 {5,1,5}, {7,1,5}, {0,1,1}, {7,1,6},
1354 {6,1,5}, {-1,-1,-1}, {6,1,6}, {-1,-1,-1},
1355 /* hat #2 in metatile #5 (type F) does not exist */
1356 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1357 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1358 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1359 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1360 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1361 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1362 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1363 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1364 /* hat #3 in metatile #5 (type F) does not exist */
1365 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1366 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1367 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1368 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1369 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1370 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1371 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1372 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1373 /* hat #0 in metatile #6 (type F) */
1374 {1,0,6}, {-1,-1,-1}, {0,0,7}, {-1,-1,-1},
1375 {-1,-1,-1}, {0,0,6}, {5,0,6}, {2,0,6},
1376 {0,0,7}, {3,0,6}, {1,0,6}, {5,0,6},
1377 {2,0,6}, {1,2,1}, {4,0,6}, {6,2,1},
1378 {3,1,6}, {5,0,6}, {6,2,1}, {3,0,6},
1379 {4,0,6}, {6,0,6}, {2,0,6}, {1,0,6},
1380 {5,0,6}, {7,0,6}, {-1,-1,-1}, {-1,-1,-1},
1381 {6,0,6}, {2,1,6}, {-1,-1,-1}, {0,1,6},
1382 /* hat #1 in metatile #6 (type F) */
1383 {1,1,6}, {-1,-1,-1}, {7,0,6}, {-1,-1,-1},
1384 {-1,-1,-1}, {0,1,6}, {5,1,6}, {2,1,6},
1385 {7,0,6}, {3,1,6}, {1,1,6}, {5,1,6},
1386 {2,1,6}, {4,0,6}, {4,1,6}, {7,2,1},
1387 {3,1,1}, {5,1,6}, {7,2,1}, {3,1,6},
1388 {4,1,6}, {6,1,6}, {2,1,6}, {1,1,6},
1389 {5,1,6}, {7,1,6}, {-1,-1,-1}, {7,1,5},
1390 {6,1,6}, {2,1,1}, {6,1,5}, {0,1,1},
1391 /* hat #2 in metatile #6 (type F) does not exist */
1392 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1393 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1394 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1395 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1396 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1397 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1398 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1399 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1400 /* hat #3 in metatile #6 (type F) does not exist */
1401 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1402 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1403 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1404 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1405 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1406 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1407 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1408 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1409 /* hat #0 in metatile #7 (type F) */
1410 {1,0,7}, {2,0,6}, {-1,-1,-1}, {0,0,6},
1411 {0,2,1}, {0,0,7}, {5,0,7}, {2,0,7},
1412 {-1,-1,-1}, {3,0,7}, {1,0,7}, {5,0,7},
1413 {2,0,7}, {-1,-1,-1}, {4,0,7}, {-1,-1,-1},
1414 {3,1,7}, {5,0,7}, {-1,-1,-1}, {3,0,7},
1415 {4,0,7}, {6,0,7}, {2,0,7}, {1,0,7},
1416 {5,0,7}, {7,0,7}, {0,2,1}, {7,1,10},
1417 {6,0,7}, {2,1,7}, {6,1,10}, {0,1,7},
1418 /* hat #1 in metatile #7 (type F) */
1419 {1,1,7}, {1,1,10}, {7,0,7}, {6,1,10},
1420 {-1,-1,-1}, {0,1,7}, {5,1,7}, {2,1,7},
1421 {7,0,7}, {3,1,7}, {1,1,7}, {5,1,7},
1422 {2,1,7}, {4,0,7}, {4,1,7}, {-1,-1,-1},
1423 {-1,-1,-1}, {5,1,7}, {-1,-1,-1}, {3,1,7},
1424 {4,1,7}, {6,1,7}, {2,1,7}, {1,1,7},
1425 {5,1,7}, {7,1,7}, {-1,-1,-1}, {-1,-1,-1},
1426 {6,1,7}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1427 /* hat #2 in metatile #7 (type F) does not exist */
1428 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1429 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1430 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1431 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1432 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1433 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1434 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1435 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1436 /* hat #3 in metatile #7 (type F) does not exist */
1437 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1438 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1439 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1440 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1441 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1442 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1443 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1444 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1445 /* hat #0 in metatile #8 (type F) */
1446 {1,0,8}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1447 {-1,-1,-1}, {0,0,8}, {5,0,8}, {2,0,8},
1448 {-1,-1,-1}, {3,0,8}, {1,0,8}, {5,0,8},
1449 {2,0,8}, {-1,-1,-1}, {4,0,8}, {-1,-1,-1},
1450 {3,1,8}, {5,0,8}, {-1,-1,-1}, {3,0,8},
1451 {4,0,8}, {6,0,8}, {2,0,8}, {1,0,8},
1452 {5,0,8}, {7,0,8}, {-1,-1,-1}, {7,1,2},
1453 {6,0,8}, {2,1,8}, {6,1,2}, {0,1,8},
1454 /* hat #1 in metatile #8 (type F) */
1455 {1,1,8}, {1,1,2}, {7,0,8}, {6,1,2},
1456 {0,1,0}, {0,1,8}, {5,1,8}, {2,1,8},
1457 {7,0,8}, {3,1,8}, {1,1,8}, {5,1,8},
1458 {2,1,8}, {4,0,8}, {4,1,8}, {-1,-1,-1},
1459 {-1,-1,-1}, {5,1,8}, {-1,-1,-1}, {3,1,8},
1460 {4,1,8}, {6,1,8}, {2,1,8}, {1,1,8},
1461 {5,1,8}, {7,1,8}, {0,1,0}, {7,1,4},
1462 {6,1,8}, {-1,-1,-1}, {6,1,4}, {-1,-1,-1},
1463 /* hat #2 in metatile #8 (type F) does not exist */
1464 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1465 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1466 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1467 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1468 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1469 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1470 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1471 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1472 /* hat #3 in metatile #8 (type F) does not exist */
1473 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1474 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1475 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1476 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1477 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1478 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1479 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1480 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1481 /* hat #0 in metatile #9 (type F) */
1482 {1,0,9}, {2,0,10}, {-1,-1,-1}, {0,0,10},
1483 {3,0,1}, {0,0,9}, {5,0,9}, {2,0,9},
1484 {-1,-1,-1}, {3,0,9}, {1,0,9}, {5,0,9},
1485 {2,0,9}, {-1,-1,-1}, {4,0,9}, {-1,-1,-1},
1486 {3,1,9}, {5,0,9}, {-1,-1,-1}, {3,0,9},
1487 {4,0,9}, {6,0,9}, {2,0,9}, {1,0,9},
1488 {5,0,9}, {7,0,9}, {3,0,1}, {4,0,1},
1489 {6,0,9}, {2,1,9}, {0,0,3}, {0,1,9},
1490 /* hat #1 in metatile #9 (type F) */
1491 {1,1,9}, {2,0,3}, {7,0,9}, {0,0,3},
1492 {3,0,0}, {0,1,9}, {5,1,9}, {2,1,9},
1493 {7,0,9}, {3,1,9}, {1,1,9}, {5,1,9},
1494 {2,1,9}, {4,0,9}, {4,1,9}, {-1,-1,-1},
1495 {-1,-1,-1}, {5,1,9}, {-1,-1,-1}, {3,1,9},
1496 {4,1,9}, {6,1,9}, {2,1,9}, {1,1,9},
1497 {5,1,9}, {7,1,9}, {3,0,0}, {4,0,0},
1498 {6,1,9}, {-1,-1,-1}, {0,0,2}, {-1,-1,-1},
1499 /* hat #2 in metatile #9 (type F) does not exist */
1500 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1501 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1502 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1503 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1504 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1505 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1506 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1507 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1508 /* hat #3 in metatile #9 (type F) does not exist */
1509 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1510 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1511 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1512 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1513 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1514 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1515 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1516 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1517 /* hat #0 in metatile #10 (type F) */
1518 {1,0,10}, {-1,-1,-1}, {0,0,9}, {-1,-1,-1},
1519 {-1,-1,-1}, {0,0,10}, {5,0,10}, {2,0,10},
1520 {0,0,9}, {3,0,10}, {1,0,10}, {5,0,10},
1521 {2,0,10}, {2,0,1}, {4,0,10}, {0,0,1},
1522 {3,1,10}, {5,0,10}, {0,0,1}, {3,0,10},
1523 {4,0,10}, {6,0,10}, {2,0,10}, {1,0,10},
1524 {5,0,10}, {7,0,10}, {-1,-1,-1}, {-1,-1,-1},
1525 {6,0,10}, {2,1,10}, {-1,-1,-1}, {0,1,10},
1526 /* hat #1 in metatile #10 (type F) */
1527 {1,1,10}, {-1,-1,-1}, {7,0,10}, {-1,-1,-1},
1528 {0,1,7}, {0,1,10}, {5,1,10}, {2,1,10},
1529 {7,0,10}, {3,1,10}, {1,1,10}, {5,1,10},
1530 {2,1,10}, {4,0,10}, {4,1,10}, {7,3,1},
1531 {3,2,1}, {5,1,10}, {7,3,1}, {3,1,10},
1532 {4,1,10}, {6,1,10}, {2,1,10}, {1,1,10},
1533 {5,1,10}, {7,1,10}, {0,1,7}, {7,0,7},
1534 {6,1,10}, {2,2,1}, {6,0,7}, {0,2,1},
1535 /* hat #2 in metatile #10 (type F) does not exist */
1536 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1537 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1538 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1539 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1540 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1541 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1542 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1543 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1544 /* hat #3 in metatile #10 (type F) does not exist */
1545 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1546 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1547 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1548 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1549 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1550 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1551 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1552 {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1},
1553};
1554static const KitemapEntry *const kitemap[] = {
1555 kitemap_H,
1556 kitemap_T,
1557 kitemap_P,
1558 kitemap_F,
1559};
1560
1561static const MetamapEntry metamap_H[] = {
1562 /* 0, 0 -> */ {0, 0}, /* no alternatives */
1563 /* 1, 0 -> */ {1, 0}, /* no alternatives */
1564 /* 2, 0 -> */ {2, 0}, /* no alternatives */
1565 /* 3, 0 -> */ {3, 0}, /* no alternatives */
1566 /* 4, 0 -> */ {3, 4},
1567 /* 5, 0 -> */ {2, 8},
1568 /* 6, 0 -> */ {3, 3},
1569 /* 7, 0 -> */ {8, 4},
1570 /* 8, 0 -> */ {9, 8},
1571 /* 9, 0 -> */ {9, 4},
1572 /* 10, 0 -> */ {8, 1},
1573 /* 11, 0 -> */ {10, 5},
1574 /* 12, 0 -> */ {5, 3},
1575 /* 0, 1 -> */ {0, 1}, /* no alternatives */
1576 /* 1, 1 -> */ {1, 1}, /* no alternatives */
1577 /* 2, 1 -> */ {2, 1}, /* no alternatives */
1578 /* 3, 1 -> */ {3, 1}, /* no alternatives */
1579 /* 4, 1 -> */ {2, 9},
1580 /* 5, 1 -> */ {2, 3},
1581 /* 6, 1 -> */ {2, 6},
1582 /* 7, 1 -> */ {10, 4},
1583 /* 8, 1 -> */ {6, 3},
1584 /* 9, 1 -> */ {9, 9},
1585 /* 10, 1 -> */ {6, 10},
1586 /* 11, 1 -> */ {4, 3},
1587 /* 12, 1 -> */ {6, 6},
1588 /* 0, 2 -> */ {0, 2}, /* no alternatives */
1589 /* 1, 2 -> */ {1, 2}, /* no alternatives */
1590 /* 2, 2 -> */ {2, 2}, /* no alternatives */
1591 /* 3, 2 -> */ {3, 2}, /* no alternatives */
1592 /* 4, 2 -> */ {3, 5},
1593 /* 5, 2 -> */ {2, 12},
1594 /* 6, 2 -> */ {1, 3},
1595 /* 7, 2 -> */ {8, 5},
1596 /* 8, 2 -> */ {9, 12},
1597 /* 9, 2 -> */ {9, 5},
1598 /* 10, 2 -> */ {12, 0},
1599 /* 11, 2 -> */ {5, 6},
1600 /* 12, 2 -> */ {11, 1},
1601 /* 0, 3 -> */ {0, 3}, /* no alternatives */
1602 /* 1, 3 -> */ {6, 2},
1603 /* 2, 3 -> */ {5, 1},
1604 /* 3, 3 -> */ {6, 0},
1605 /* 4, 3 -> */ {12, 2},
1606 /* 5, 3 -> */ {10, 2},
1607 /* 6, 3 -> */ {10, 0},
1608 /* 7, 3 -> */ {-1,-1}, /* does not exist */
1609 /* 8, 3 -> */ {-1,-1}, /* does not exist */
1610 /* 9, 3 -> */ {-1,-1}, /* does not exist */
1611 /* 10, 3 -> */ {-1,-1}, /* does not exist */
1612 /* 11, 3 -> */ {-1,-1}, /* does not exist */
1613 /* 12, 3 -> */ {-1,-1}, /* does not exist */
1614 /* 0, 4 -> */ {0, 4}, /* no alternatives */
1615 /* 1, 4 -> */ {1, 4}, /* no alternatives */
1616 /* 2, 4 -> */ {2, 4}, /* no alternatives */
1617 /* 3, 4 -> */ {4, 0},
1618 /* 4, 4 -> */ {4, 4}, /* no alternatives */
1619 /* 5, 4 -> */ {5, 7},
1620 /* 6, 4 -> */ {6, 4}, /* no alternatives */
1621 /* 7, 4 -> */ {4, 9},
1622 /* 8, 4 -> */ {6, 7},
1623 /* 9, 4 -> */ {9, 0},
1624 /* 10, 4 -> */ {8, 9},
1625 /* 11, 4 -> */ {-1,-1}, /* does not exist */
1626 /* 12, 4 -> */ {-1,-1}, /* does not exist */
1627 /* 0, 5 -> */ {0, 5}, /* no alternatives */
1628 /* 1, 5 -> */ {1, 5}, /* no alternatives */
1629 /* 2, 5 -> */ {2, 5}, /* no alternatives */
1630 /* 3, 5 -> */ {4, 2},
1631 /* 4, 5 -> */ {4, 5}, /* no alternatives */
1632 /* 5, 5 -> */ {5, 11},
1633 /* 6, 5 -> */ {6, 5}, /* no alternatives */
1634 /* 7, 5 -> */ {4, 8},
1635 /* 8, 5 -> */ {6, 11},
1636 /* 9, 5 -> */ {9, 2},
1637 /* 10, 5 -> */ {8, 8},
1638 /* 11, 5 -> */ {-1,-1}, /* does not exist */
1639 /* 12, 5 -> */ {-1,-1}, /* does not exist */
1640 /* 0, 6 -> */ {0, 6}, /* no alternatives */
1641 /* 1, 6 -> */ {1, 6}, /* no alternatives */
1642 /* 2, 6 -> */ {6, 1},
1643 /* 3, 6 -> */ {3, 6}, /* no alternatives */
1644 /* 4, 6 -> */ {4, 6}, /* no alternatives */
1645 /* 5, 6 -> */ {8, 12},
1646 /* 6, 6 -> */ {12, 1},
1647 /* 7, 6 -> */ {10, 1},
1648 /* 8, 6 -> */ {4, 12},
1649 /* 9, 6 -> */ {9, 6}, /* no alternatives */
1650 /* 10, 6 -> */ {5, 10},
1651 /* 11, 6 -> */ {-1,-1}, /* does not exist */
1652 /* 12, 6 -> */ {-1,-1}, /* does not exist */
1653 /* 0, 7 -> */ {0, 7}, /* no alternatives */
1654 /* 1, 7 -> */ {1, 7}, /* no alternatives */
1655 /* 2, 7 -> */ {2, 7}, /* no alternatives */
1656 /* 3, 7 -> */ {3, 7}, /* no alternatives */
1657 /* 4, 7 -> */ {4, 7}, /* no alternatives */
1658 /* 5, 7 -> */ {5, 4},
1659 /* 6, 7 -> */ {7, 0},
1660 /* 7, 7 -> */ {10, 8},
1661 /* 8, 7 -> */ {8, 7}, /* no alternatives */
1662 /* 9, 7 -> */ {9, 7}, /* no alternatives */
1663 /* 10, 7 -> */ {10, 7}, /* no alternatives */
1664 /* 11, 7 -> */ {-1,-1}, /* does not exist */
1665 /* 12, 7 -> */ {-1,-1}, /* does not exist */
1666 /* 0, 8 -> */ {0, 8}, /* no alternatives */
1667 /* 1, 8 -> */ {1, 8}, /* no alternatives */
1668 /* 2, 8 -> */ {5, 0},
1669 /* 3, 8 -> */ {3, 8}, /* no alternatives */
1670 /* 4, 8 -> */ {7, 5},
1671 /* 5, 8 -> */ {5, 8}, /* no alternatives */
1672 /* 6, 8 -> */ {6, 8}, /* no alternatives */
1673 /* 7, 8 -> */ {7, 8}, /* no alternatives */
1674 /* 8, 8 -> */ {11, 0},
1675 /* 9, 8 -> */ {8, 0},
1676 /* 10, 8 -> */ {7, 7},
1677 /* 11, 8 -> */ {-1,-1}, /* does not exist */
1678 /* 12, 8 -> */ {-1,-1}, /* does not exist */
1679 /* 0, 9 -> */ {0, 9}, /* no alternatives */
1680 /* 1, 9 -> */ {1, 9}, /* no alternatives */
1681 /* 2, 9 -> */ {4, 1},
1682 /* 3, 9 -> */ {3, 9}, /* no alternatives */
1683 /* 4, 9 -> */ {7, 4},
1684 /* 5, 9 -> */ {5, 9}, /* no alternatives */
1685 /* 6, 9 -> */ {6, 9}, /* no alternatives */
1686 /* 7, 9 -> */ {7, 9}, /* no alternatives */
1687 /* 8, 9 -> */ {7, 1},
1688 /* 9, 9 -> */ {9, 1},
1689 /* 10, 9 -> */ {7, 10},
1690 /* 11, 9 -> */ {-1,-1}, /* does not exist */
1691 /* 12, 9 -> */ {-1,-1}, /* does not exist */
1692 /* 0, 10 -> */ {0, 10}, /* no alternatives */
1693 /* 1, 10 -> */ {1, 10}, /* no alternatives */
1694 /* 2, 10 -> */ {2, 10}, /* no alternatives */
1695 /* 3, 10 -> */ {3, 10}, /* no alternatives */
1696 /* 4, 10 -> */ {4, 10}, /* no alternatives */
1697 /* 5, 10 -> */ {10, 6},
1698 /* 6, 10 -> */ {7, 6},
1699 /* 7, 10 -> */ {10, 9},
1700 /* 8, 10 -> */ {8, 10}, /* no alternatives */
1701 /* 9, 10 -> */ {9, 10}, /* no alternatives */
1702 /* 10, 10 -> */ {10, 10}, /* no alternatives */
1703 /* 11, 10 -> */ {-1,-1}, /* does not exist */
1704 /* 12, 10 -> */ {-1,-1}, /* does not exist */
1705 /* 0, 11 -> */ {0, 11}, /* no alternatives */
1706 /* 1, 11 -> */ {1, 11}, /* no alternatives */
1707 /* 2, 11 -> */ {2, 11}, /* no alternatives */
1708 /* 3, 11 -> */ {3, 11}, /* no alternatives */
1709 /* 4, 11 -> */ {4, 11}, /* no alternatives */
1710 /* 5, 11 -> */ {5, 5},
1711 /* 6, 11 -> */ {7, 2},
1712 /* 7, 11 -> */ {10, 12},
1713 /* 8, 11 -> */ {8, 11}, /* no alternatives */
1714 /* 9, 11 -> */ {9, 11}, /* no alternatives */
1715 /* 10, 11 -> */ {10, 11}, /* no alternatives */
1716 /* 11, 11 -> */ {-1,-1}, /* does not exist */
1717 /* 12, 11 -> */ {-1,-1}, /* does not exist */
1718 /* 0, 12 -> */ {0, 12}, /* no alternatives */
1719 /* 1, 12 -> */ {1, 12}, /* no alternatives */
1720 /* 2, 12 -> */ {5, 2},
1721 /* 3, 12 -> */ {3, 12}, /* no alternatives */
1722 /* 4, 12 -> */ {8, 6},
1723 /* 5, 12 -> */ {5, 12}, /* no alternatives */
1724 /* 6, 12 -> */ {6, 12}, /* no alternatives */
1725 /* 7, 12 -> */ {7, 12}, /* no alternatives */
1726 /* 8, 12 -> */ {11, 2},
1727 /* 9, 12 -> */ {8, 2},
1728 /* 10, 12 -> */ {7, 11},
1729 /* 11, 12 -> */ {-1,-1}, /* does not exist */
1730 /* 12, 12 -> */ {-1,-1}, /* does not exist */
1731};
1732static const MetamapEntry metamap_T[] = {
1733 /* 0, 0 -> */ {0, 0}, /* no alternatives */
1734 /* 1, 0 -> */ {1, 0}, /* no alternatives */
1735 /* 2, 0 -> */ {2, 0}, /* no alternatives */
1736 /* 3, 0 -> */ {3, 0}, /* no alternatives */
1737 /* 4, 0 -> */ {3, 3},
1738 /* 5, 0 -> */ {3, 1},
1739 /* 6, 0 -> */ {2, 2},
1740 /* 7, 0 -> */ {8, 3},
1741 /* 8, 0 -> */ {9, 1},
1742 /* 9, 0 -> */ {9, 3},
1743 /* 10, 0 -> */ {4, 6},
1744 /* 11, 0 -> */ {4, 4},
1745 /* 12, 0 -> */ {6, 2},
1746 /* 0, 1 -> */ {0, 1}, /* no alternatives */
1747 /* 1, 1 -> */ {1, 1}, /* no alternatives */
1748 /* 2, 1 -> */ {2, 1}, /* no alternatives */
1749 /* 3, 1 -> */ {5, 0},
1750 /* 4, 1 -> */ {4, 1}, /* no alternatives */
1751 /* 5, 1 -> */ {8, 4},
1752 /* 6, 1 -> */ {6, 1}, /* no alternatives */
1753 /* 7, 1 -> */ {6, 5},
1754 /* 8, 1 -> */ {11, 0},
1755 /* 9, 1 -> */ {8, 0},
1756 /* 10, 1 -> */ {5, 5},
1757 /* 11, 1 -> */ {-1,-1}, /* does not exist */
1758 /* 12, 1 -> */ {-1,-1}, /* does not exist */
1759 /* 0, 2 -> */ {0, 2}, /* no alternatives */
1760 /* 1, 2 -> */ {1, 2}, /* no alternatives */
1761 /* 2, 2 -> */ {6, 0},
1762 /* 3, 2 -> */ {3, 2}, /* no alternatives */
1763 /* 4, 2 -> */ {4, 2}, /* no alternatives */
1764 /* 5, 2 -> */ {5, 4},
1765 /* 6, 2 -> */ {12, 0},
1766 /* 7, 2 -> */ {10, 0},
1767 /* 8, 2 -> */ {6, 4},
1768 /* 9, 2 -> */ {9, 2}, /* no alternatives */
1769 /* 10, 2 -> */ {8, 6},
1770 /* 11, 2 -> */ {-1,-1}, /* does not exist */
1771 /* 12, 2 -> */ {-1,-1}, /* does not exist */
1772 /* 0, 3 -> */ {0, 3}, /* no alternatives */
1773 /* 1, 3 -> */ {1, 3}, /* no alternatives */
1774 /* 2, 3 -> */ {2, 3}, /* no alternatives */
1775 /* 3, 3 -> */ {4, 0},
1776 /* 4, 3 -> */ {4, 3}, /* no alternatives */
1777 /* 5, 3 -> */ {8, 5},
1778 /* 6, 3 -> */ {6, 3}, /* no alternatives */
1779 /* 7, 3 -> */ {6, 6},
1780 /* 8, 3 -> */ {4, 5},
1781 /* 9, 3 -> */ {9, 0},
1782 /* 10, 3 -> */ {5, 6},
1783 /* 11, 3 -> */ {-1,-1}, /* does not exist */
1784 /* 12, 3 -> */ {-1,-1}, /* does not exist */
1785 /* 0, 4 -> */ {0, 4}, /* no alternatives */
1786 /* 1, 4 -> */ {1, 4}, /* no alternatives */
1787 /* 2, 4 -> */ {2, 4}, /* no alternatives */
1788 /* 3, 4 -> */ {3, 4}, /* no alternatives */
1789 /* 4, 4 -> */ {8, 1},
1790 /* 5, 4 -> */ {5, 2},
1791 /* 6, 4 -> */ {8, 2},
1792 /* 7, 4 -> */ {7, 4}, /* no alternatives */
1793 /* 8, 4 -> */ {5, 1},
1794 /* 9, 4 -> */ {9, 4}, /* no alternatives */
1795 /* 10, 4 -> */ {10, 4}, /* no alternatives */
1796 /* 11, 4 -> */ {-1,-1}, /* does not exist */
1797 /* 12, 4 -> */ {-1,-1}, /* does not exist */
1798 /* 0, 5 -> */ {0, 5}, /* no alternatives */
1799 /* 1, 5 -> */ {1, 5}, /* no alternatives */
1800 /* 2, 5 -> */ {2, 5}, /* no alternatives */
1801 /* 3, 5 -> */ {3, 5}, /* no alternatives */
1802 /* 4, 5 -> */ {7, 0},
1803 /* 5, 5 -> */ {10, 1},
1804 /* 6, 5 -> */ {7, 1},
1805 /* 7, 5 -> */ {7, 5}, /* no alternatives */
1806 /* 8, 5 -> */ {5, 3},
1807 /* 9, 5 -> */ {9, 5}, /* no alternatives */
1808 /* 10, 5 -> */ {10, 5}, /* no alternatives */
1809 /* 11, 5 -> */ {-1,-1}, /* does not exist */
1810 /* 12, 5 -> */ {-1,-1}, /* does not exist */
1811 /* 0, 6 -> */ {0, 6}, /* no alternatives */
1812 /* 1, 6 -> */ {1, 6}, /* no alternatives */
1813 /* 2, 6 -> */ {2, 6}, /* no alternatives */
1814 /* 3, 6 -> */ {3, 6}, /* no alternatives */
1815 /* 4, 6 -> */ {7, 2},
1816 /* 5, 6 -> */ {10, 3},
1817 /* 6, 6 -> */ {7, 3},
1818 /* 7, 6 -> */ {7, 6}, /* no alternatives */
1819 /* 8, 6 -> */ {10, 2},
1820 /* 9, 6 -> */ {9, 6}, /* no alternatives */
1821 /* 10, 6 -> */ {10, 6}, /* no alternatives */
1822 /* 11, 6 -> */ {-1,-1}, /* does not exist */
1823 /* 12, 6 -> */ {-1,-1}, /* does not exist */
1824};
1825static const MetamapEntry metamap_P[] = {
1826 /* 0, 0 -> */ {0, 0}, /* no alternatives */
1827 /* 1, 0 -> */ {1, 0}, /* no alternatives */
1828 /* 2, 0 -> */ {2, 0}, /* no alternatives */
1829 /* 3, 0 -> */ {3, 0}, /* no alternatives */
1830 /* 4, 0 -> */ {3, 4},
1831 /* 5, 0 -> */ {2, 5},
1832 /* 6, 0 -> */ {2, 3},
1833 /* 7, 0 -> */ {8, 4},
1834 /* 8, 0 -> */ {9, 5},
1835 /* 9, 0 -> */ {9, 4},
1836 /* 10, 0 -> */ {4, 9},
1837 /* 11, 0 -> */ {4, 8},
1838 /* 12, 0 -> */ {6, 3},
1839 /* 0, 1 -> */ {0, 1}, /* no alternatives */
1840 /* 1, 1 -> */ {1, 1}, /* no alternatives */
1841 /* 2, 1 -> */ {2, 1}, /* no alternatives */
1842 /* 3, 1 -> */ {3, 1}, /* no alternatives */
1843 /* 4, 1 -> */ {2, 10},
1844 /* 5, 1 -> */ {3, 2},
1845 /* 6, 1 -> */ {2, 4},
1846 /* 7, 1 -> */ {8, 10},
1847 /* 8, 1 -> */ {9, 2},
1848 /* 9, 1 -> */ {9, 10},
1849 /* 10, 1 -> */ {7, 4},
1850 /* 11, 1 -> */ {8, 2},
1851 /* 12, 1 -> */ {6, 4},
1852 /* 0, 2 -> */ {0, 2}, /* no alternatives */
1853 /* 1, 2 -> */ {1, 2}, /* no alternatives */
1854 /* 2, 2 -> */ {2, 2}, /* no alternatives */
1855 /* 3, 2 -> */ {5, 1},
1856 /* 4, 2 -> */ {4, 2}, /* no alternatives */
1857 /* 5, 2 -> */ {8, 6},
1858 /* 6, 2 -> */ {6, 2}, /* no alternatives */
1859 /* 7, 2 -> */ {6, 7},
1860 /* 8, 2 -> */ {4, 6},
1861 /* 9, 2 -> */ {8, 1},
1862 /* 10, 2 -> */ {5, 7},
1863 /* 11, 2 -> */ {-1,-1}, /* does not exist */
1864 /* 12, 2 -> */ {-1,-1}, /* does not exist */
1865 /* 0, 3 -> */ {0, 3}, /* no alternatives */
1866 /* 1, 3 -> */ {1, 3}, /* no alternatives */
1867 /* 2, 3 -> */ {6, 0},
1868 /* 3, 3 -> */ {3, 3}, /* no alternatives */
1869 /* 4, 3 -> */ {4, 3}, /* no alternatives */
1870 /* 5, 3 -> */ {5, 8},
1871 /* 6, 3 -> */ {12, 0},
1872 /* 7, 3 -> */ {10, 0},
1873 /* 8, 3 -> */ {6, 8},
1874 /* 9, 3 -> */ {9, 3}, /* no alternatives */
1875 /* 10, 3 -> */ {8, 9},
1876 /* 11, 3 -> */ {-1,-1}, /* does not exist */
1877 /* 12, 3 -> */ {-1,-1}, /* does not exist */
1878 /* 0, 4 -> */ {0, 4}, /* no alternatives */
1879 /* 1, 4 -> */ {1, 4}, /* no alternatives */
1880 /* 2, 4 -> */ {6, 1},
1881 /* 3, 4 -> */ {4, 0},
1882 /* 4, 4 -> */ {4, 4}, /* no alternatives */
1883 /* 5, 4 -> */ {5, 6},
1884 /* 6, 4 -> */ {12, 1},
1885 /* 7, 4 -> */ {6, 9},
1886 /* 8, 4 -> */ {6, 6},
1887 /* 9, 4 -> */ {9, 0},
1888 /* 10, 4 -> */ {5, 9},
1889 /* 11, 4 -> */ {-1,-1}, /* does not exist */
1890 /* 12, 4 -> */ {-1,-1}, /* does not exist */
1891 /* 0, 5 -> */ {0, 5}, /* no alternatives */
1892 /* 1, 5 -> */ {1, 5}, /* no alternatives */
1893 /* 2, 5 -> */ {5, 0},
1894 /* 3, 5 -> */ {3, 5}, /* no alternatives */
1895 /* 4, 5 -> */ {8, 8},
1896 /* 5, 5 -> */ {5, 5}, /* no alternatives */
1897 /* 6, 5 -> */ {6, 5}, /* no alternatives */
1898 /* 7, 5 -> */ {7, 5}, /* no alternatives */
1899 /* 8, 5 -> */ {11, 0},
1900 /* 9, 5 -> */ {8, 0},
1901 /* 10, 5 -> */ {7, 6},
1902 /* 11, 5 -> */ {-1,-1}, /* does not exist */
1903 /* 12, 5 -> */ {-1,-1}, /* does not exist */
1904 /* 0, 6 -> */ {0, 6}, /* no alternatives */
1905 /* 1, 6 -> */ {1, 6}, /* no alternatives */
1906 /* 2, 6 -> */ {2, 6}, /* no alternatives */
1907 /* 3, 6 -> */ {3, 6}, /* no alternatives */
1908 /* 4, 6 -> */ {11, 1},
1909 /* 5, 6 -> */ {5, 4},
1910 /* 6, 6 -> */ {7, 0},
1911 /* 7, 6 -> */ {10, 5},
1912 /* 8, 6 -> */ {5, 2},
1913 /* 9, 6 -> */ {9, 6}, /* no alternatives */
1914 /* 10, 6 -> */ {10, 6}, /* no alternatives */
1915 /* 11, 6 -> */ {-1,-1}, /* does not exist */
1916 /* 12, 6 -> */ {-1,-1}, /* does not exist */
1917 /* 0, 7 -> */ {0, 7}, /* no alternatives */
1918 /* 1, 7 -> */ {1, 7}, /* no alternatives */
1919 /* 2, 7 -> */ {2, 7}, /* no alternatives */
1920 /* 3, 7 -> */ {3, 7}, /* no alternatives */
1921 /* 4, 7 -> */ {7, 1},
1922 /* 5, 7 -> */ {10, 2},
1923 /* 6, 7 -> */ {7, 2},
1924 /* 7, 7 -> */ {7, 7}, /* no alternatives */
1925 /* 8, 7 -> */ {4, 10},
1926 /* 9, 7 -> */ {9, 7}, /* no alternatives */
1927 /* 10, 7 -> */ {10, 7}, /* no alternatives */
1928 /* 11, 7 -> */ {-1,-1}, /* does not exist */
1929 /* 12, 7 -> */ {-1,-1}, /* does not exist */
1930 /* 0, 8 -> */ {0, 8}, /* no alternatives */
1931 /* 1, 8 -> */ {1, 8}, /* no alternatives */
1932 /* 2, 8 -> */ {2, 8}, /* no alternatives */
1933 /* 3, 8 -> */ {3, 8}, /* no alternatives */
1934 /* 4, 8 -> */ {8, 5},
1935 /* 5, 8 -> */ {5, 3},
1936 /* 6, 8 -> */ {8, 3},
1937 /* 7, 8 -> */ {7, 8}, /* no alternatives */
1938 /* 8, 8 -> */ {4, 5},
1939 /* 9, 8 -> */ {9, 8}, /* no alternatives */
1940 /* 10, 8 -> */ {10, 8}, /* no alternatives */
1941 /* 11, 8 -> */ {-1,-1}, /* does not exist */
1942 /* 12, 8 -> */ {-1,-1}, /* does not exist */
1943 /* 0, 9 -> */ {0, 9}, /* no alternatives */
1944 /* 1, 9 -> */ {1, 9}, /* no alternatives */
1945 /* 2, 9 -> */ {2, 9}, /* no alternatives */
1946 /* 3, 9 -> */ {3, 9}, /* no alternatives */
1947 /* 4, 9 -> */ {7, 3},
1948 /* 5, 9 -> */ {10, 4},
1949 /* 6, 9 -> */ {10, 1},
1950 /* 7, 9 -> */ {10, 10},
1951 /* 8, 9 -> */ {10, 3},
1952 /* 9, 9 -> */ {9, 9}, /* no alternatives */
1953 /* 10, 9 -> */ {10, 9}, /* no alternatives */
1954 /* 11, 9 -> */ {-1,-1}, /* does not exist */
1955 /* 12, 9 -> */ {-1,-1}, /* does not exist */
1956 /* 0, 10 -> */ {0, 10}, /* no alternatives */
1957 /* 1, 10 -> */ {1, 10}, /* no alternatives */
1958 /* 2, 10 -> */ {4, 1},
1959 /* 3, 10 -> */ {3, 10}, /* no alternatives */
1960 /* 4, 10 -> */ {8, 7},
1961 /* 5, 10 -> */ {5, 10}, /* no alternatives */
1962 /* 6, 10 -> */ {6, 10}, /* no alternatives */
1963 /* 7, 10 -> */ {7, 10}, /* no alternatives */
1964 /* 8, 10 -> */ {4, 7},
1965 /* 9, 10 -> */ {9, 1},
1966 /* 10, 10 -> */ {7, 9},
1967 /* 11, 10 -> */ {-1,-1}, /* does not exist */
1968 /* 12, 10 -> */ {-1,-1}, /* does not exist */
1969};
1970static const MetamapEntry metamap_F[] = {
1971 /* 0, 0 -> */ {0, 0}, /* no alternatives */
1972 /* 1, 0 -> */ {1, 0}, /* no alternatives */
1973 /* 2, 0 -> */ {2, 0}, /* no alternatives */
1974 /* 3, 0 -> */ {3, 0}, /* no alternatives */
1975 /* 4, 0 -> */ {3, 3},
1976 /* 5, 0 -> */ {2, 4},
1977 /* 6, 0 -> */ {2, 2},
1978 /* 7, 0 -> */ {8, 3},
1979 /* 8, 0 -> */ {9, 4},
1980 /* 9, 0 -> */ {9, 3},
1981 /* 10, 0 -> */ {4, 9},
1982 /* 11, 0 -> */ {4, 8},
1983 /* 12, 0 -> */ {6, 2},
1984 /* 0, 1 -> */ {0, 1}, /* no alternatives */
1985 /* 1, 1 -> */ {1, 1}, /* no alternatives */
1986 /* 2, 1 -> */ {2, 1}, /* no alternatives */
1987 /* 3, 1 -> */ {3, 1}, /* no alternatives */
1988 /* 4, 1 -> */ {2, 10},
1989 /* 5, 1 -> */ {2, 6},
1990 /* 6, 1 -> */ {2, 3},
1991 /* 7, 1 -> */ {8, 10},
1992 /* 8, 1 -> */ {9, 6},
1993 /* 9, 1 -> */ {9, 10},
1994 /* 10, 1 -> */ {7, 3},
1995 /* 11, 1 -> */ {8, 6},
1996 /* 12, 1 -> */ {6, 3},
1997 /* 0, 2 -> */ {0, 2}, /* no alternatives */
1998 /* 1, 2 -> */ {1, 2}, /* no alternatives */
1999 /* 2, 2 -> */ {6, 0},
2000 /* 3, 2 -> */ {3, 2}, /* no alternatives */
2001 /* 4, 2 -> */ {4, 2}, /* no alternatives */
2002 /* 5, 2 -> */ {5, 8},
2003 /* 6, 2 -> */ {12, 0},
2004 /* 7, 2 -> */ {10, 0},
2005 /* 8, 2 -> */ {6, 8},
2006 /* 9, 2 -> */ {9, 2}, /* no alternatives */
2007 /* 10, 2 -> */ {8, 9},
2008 /* 11, 2 -> */ {-1,-1}, /* does not exist */
2009 /* 12, 2 -> */ {-1,-1}, /* does not exist */
2010 /* 0, 3 -> */ {0, 3}, /* no alternatives */
2011 /* 1, 3 -> */ {1, 3}, /* no alternatives */
2012 /* 2, 3 -> */ {6, 1},
2013 /* 3, 3 -> */ {4, 0},
2014 /* 4, 3 -> */ {4, 3}, /* no alternatives */
2015 /* 5, 3 -> */ {5, 5},
2016 /* 6, 3 -> */ {12, 1},
2017 /* 7, 3 -> */ {6, 9},
2018 /* 8, 3 -> */ {6, 5},
2019 /* 9, 3 -> */ {9, 0},
2020 /* 10, 3 -> */ {5, 9},
2021 /* 11, 3 -> */ {-1,-1}, /* does not exist */
2022 /* 12, 3 -> */ {-1,-1}, /* does not exist */
2023 /* 0, 4 -> */ {0, 4}, /* no alternatives */
2024 /* 1, 4 -> */ {1, 4}, /* no alternatives */
2025 /* 2, 4 -> */ {5, 0},
2026 /* 3, 4 -> */ {3, 4}, /* no alternatives */
2027 /* 4, 4 -> */ {8, 8},
2028 /* 5, 4 -> */ {5, 4}, /* no alternatives */
2029 /* 6, 4 -> */ {6, 4}, /* no alternatives */
2030 /* 7, 4 -> */ {7, 4}, /* no alternatives */
2031 /* 8, 4 -> */ {11, 0},
2032 /* 9, 4 -> */ {8, 0},
2033 /* 10, 4 -> */ {7, 5},
2034 /* 11, 4 -> */ {-1,-1}, /* does not exist */
2035 /* 12, 4 -> */ {-1,-1}, /* does not exist */
2036 /* 0, 5 -> */ {0, 5}, /* no alternatives */
2037 /* 1, 5 -> */ {1, 5}, /* no alternatives */
2038 /* 2, 5 -> */ {2, 5}, /* no alternatives */
2039 /* 3, 5 -> */ {3, 5}, /* no alternatives */
2040 /* 4, 5 -> */ {11, 1},
2041 /* 5, 5 -> */ {5, 3},
2042 /* 6, 5 -> */ {7, 0},
2043 /* 7, 5 -> */ {10, 4},
2044 /* 8, 5 -> */ {4, 6},
2045 /* 9, 5 -> */ {9, 5}, /* no alternatives */
2046 /* 10, 5 -> */ {10, 5}, /* no alternatives */
2047 /* 11, 5 -> */ {-1,-1}, /* does not exist */
2048 /* 12, 5 -> */ {-1,-1}, /* does not exist */
2049 /* 0, 6 -> */ {0, 6}, /* no alternatives */
2050 /* 1, 6 -> */ {1, 6}, /* no alternatives */
2051 /* 2, 6 -> */ {5, 1},
2052 /* 3, 6 -> */ {3, 6}, /* no alternatives */
2053 /* 4, 6 -> */ {8, 5},
2054 /* 5, 6 -> */ {5, 6}, /* no alternatives */
2055 /* 6, 6 -> */ {6, 6}, /* no alternatives */
2056 /* 7, 6 -> */ {7, 6}, /* no alternatives */
2057 /* 8, 6 -> */ {4, 5},
2058 /* 9, 6 -> */ {8, 1},
2059 /* 10, 6 -> */ {7, 7},
2060 /* 11, 6 -> */ {-1,-1}, /* does not exist */
2061 /* 12, 6 -> */ {-1,-1}, /* does not exist */
2062 /* 0, 7 -> */ {0, 7}, /* no alternatives */
2063 /* 1, 7 -> */ {1, 7}, /* no alternatives */
2064 /* 2, 7 -> */ {2, 7}, /* no alternatives */
2065 /* 3, 7 -> */ {3, 7}, /* no alternatives */
2066 /* 4, 7 -> */ {4, 7}, /* no alternatives */
2067 /* 5, 7 -> */ {4, 10},
2068 /* 6, 7 -> */ {7, 1},
2069 /* 7, 7 -> */ {10, 6},
2070 /* 8, 7 -> */ {8, 7}, /* no alternatives */
2071 /* 9, 7 -> */ {9, 7}, /* no alternatives */
2072 /* 10, 7 -> */ {10, 7}, /* no alternatives */
2073 /* 11, 7 -> */ {-1,-1}, /* does not exist */
2074 /* 12, 7 -> */ {-1,-1}, /* does not exist */
2075 /* 0, 8 -> */ {0, 8}, /* no alternatives */
2076 /* 1, 8 -> */ {1, 8}, /* no alternatives */
2077 /* 2, 8 -> */ {2, 8}, /* no alternatives */
2078 /* 3, 8 -> */ {3, 8}, /* no alternatives */
2079 /* 4, 8 -> */ {8, 4},
2080 /* 5, 8 -> */ {5, 2},
2081 /* 6, 8 -> */ {8, 2},
2082 /* 7, 8 -> */ {7, 8}, /* no alternatives */
2083 /* 8, 8 -> */ {4, 4},
2084 /* 9, 8 -> */ {9, 8}, /* no alternatives */
2085 /* 10, 8 -> */ {10, 8}, /* no alternatives */
2086 /* 11, 8 -> */ {-1,-1}, /* does not exist */
2087 /* 12, 8 -> */ {-1,-1}, /* does not exist */
2088 /* 0, 9 -> */ {0, 9}, /* no alternatives */
2089 /* 1, 9 -> */ {1, 9}, /* no alternatives */
2090 /* 2, 9 -> */ {2, 9}, /* no alternatives */
2091 /* 3, 9 -> */ {3, 9}, /* no alternatives */
2092 /* 4, 9 -> */ {7, 2},
2093 /* 5, 9 -> */ {10, 3},
2094 /* 6, 9 -> */ {10, 1},
2095 /* 7, 9 -> */ {10, 10},
2096 /* 8, 9 -> */ {10, 2},
2097 /* 9, 9 -> */ {9, 9}, /* no alternatives */
2098 /* 10, 9 -> */ {10, 9}, /* no alternatives */
2099 /* 11, 9 -> */ {-1,-1}, /* does not exist */
2100 /* 12, 9 -> */ {-1,-1}, /* does not exist */
2101 /* 0, 10 -> */ {0, 10}, /* no alternatives */
2102 /* 1, 10 -> */ {1, 10}, /* no alternatives */
2103 /* 2, 10 -> */ {4, 1},
2104 /* 3, 10 -> */ {3, 10}, /* no alternatives */
2105 /* 4, 10 -> */ {5, 7},
2106 /* 5, 10 -> */ {5, 10}, /* no alternatives */
2107 /* 6, 10 -> */ {6, 10}, /* no alternatives */
2108 /* 7, 10 -> */ {7, 10}, /* no alternatives */
2109 /* 8, 10 -> */ {6, 7},
2110 /* 9, 10 -> */ {9, 1},
2111 /* 10, 10 -> */ {7, 9},
2112 /* 11, 10 -> */ {-1,-1}, /* does not exist */
2113 /* 12, 10 -> */ {-1,-1}, /* does not exist */
2114};
2115static const MetamapEntry *const metamap[] = {
2116 metamap_H,
2117 metamap_T,
2118 metamap_P,
2119 metamap_F,
2120};
diff --git a/apps/plugins/puzzles/src/hat.c b/apps/plugins/puzzles/src/hat.c
new file mode 100644
index 0000000000..176d1f049e
--- /dev/null
+++ b/apps/plugins/puzzles/src/hat.c
@@ -0,0 +1,891 @@
1/*
2 * Code to generate patches of the aperiodic 'hat' tiling discovered
3 * in 2023.
4 *
5 * This uses the 'combinatorial coordinates' system documented in my
6 * public article
7 * https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/aperiodic-tilings/
8 *
9 * The internal document auxiliary/doc/hats.html also contains an
10 * explanation of the basic ideas of this algorithm (less polished but
11 * containing more detail).
12 *
13 * Neither of those documents can really be put in a source file,
14 * because they just have too many complicated diagrams. So read at
15 * least one of those first; the comments in here will refer to it.
16 *
17 * Discoverers' website: https://cs.uwaterloo.ca/~csk/hat/
18 * Preprint of paper: https://arxiv.org/abs/2303.10798
19 */
20
21#include <assert.h>
22#ifdef NO_TGMATH_H
23# include <math.h>
24#else
25# include <tgmath.h>
26#endif
27#include <stdbool.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include "puzzles.h"
33#include "hat.h"
34#include "hat-internal.h"
35
36void hat_kiteenum_first(KiteEnum *s, int w, int h)
37{
38 Kite start = { {0,0}, {0, 3}, {3, 0}, {2, 2} };
39 size_t i;
40
41 for (i = 0; i < KE_NKEEP; i++)
42 s->recent[i] = start; /* initialise to *something* */
43 s->curr_index = 0;
44 s->curr = &s->recent[s->curr_index];
45 s->state = 1;
46 s->w = w;
47 s->h = h;
48 s->x = 0;
49 s->y = 0;
50}
51
52bool hat_kiteenum_next(KiteEnum *s)
53{
54 unsigned lastbut1 = s->last_index;
55 s->last_index = s->curr_index;
56 s->curr_index = (s->curr_index + 1) % KE_NKEEP;
57 s->curr = &s->recent[s->curr_index];
58
59 switch (s->state) {
60 /* States 1,2,3 walk rightwards along the upper side of a
61 * horizontal grid line with a pointy kite end at the start
62 * point */
63 case 1:
64 s->last_step = KS_F_RIGHT;
65 s->state = 2;
66 break;
67
68 case 2:
69 if (s->x+1 >= s->w) {
70 s->last_step = KS_F_RIGHT;
71 s->state = 4;
72 break;
73 }
74 s->last_step = KS_RIGHT;
75 s->state = 3;
76 s->x++;
77 break;
78
79 case 3:
80 s->last_step = KS_RIGHT;
81 s->state = 1;
82 break;
83
84 /* State 4 is special: we've just moved up into a row below a
85 * grid line, but we can't produce the rightmost tile of that
86 * row because it's not adjacent any tile so far emitted. So
87 * instead, emit the second-rightmost tile, and next time,
88 * we'll emit the rightmost. */
89 case 4:
90 s->last_step = KS_LEFT;
91 s->state = 5;
92 break;
93
94 /* And now we have to emit the third-rightmost tile relative
95 * to the last but one tile we emitted (the one from state 2,
96 * not state 4). */
97 case 5:
98 s->last_step = KS_RIGHT;
99 s->last_index = lastbut1;
100 s->state = 6;
101 break;
102
103 /* Now states 6-8 handle the general case of walking leftwards
104 * along the lower side of a line, starting from a
105 * right-angled kite end. */
106 case 6:
107 if (s->x <= 0) {
108 if (s->y+1 >= s->h) {
109 s->state = 0;
110 return false;
111 }
112 s->last_step = KS_RIGHT;
113 s->state = 9;
114 s->y++;
115 break;
116 }
117 s->last_step = KS_F_RIGHT;
118 s->state = 7;
119 s->x--;
120 break;
121
122 case 7:
123 s->last_step = KS_RIGHT;
124 s->state = 8;
125 break;
126
127 case 8:
128 s->last_step = KS_RIGHT;
129 s->state = 6;
130 break;
131
132 /* States 9,10,11 walk rightwards along the upper side of a
133 * horizontal grid line with a right-angled kite end at the
134 * start point. This time there's no awkward transition from
135 * the previous row. */
136 case 9:
137 s->last_step = KS_RIGHT;
138 s->state = 10;
139 break;
140
141 case 10:
142 s->last_step = KS_RIGHT;
143 s->state = 11;
144 break;
145
146 case 11:
147 if (s->x+1 >= s->w) {
148 /* Another awkward transition to the next row, where we
149 * have to generate it based on the previous state-9 tile.
150 * But this time at least we generate the rightmost tile
151 * of the new row, so the next states will be simple. */
152 s->last_step = KS_F_RIGHT;
153 s->last_index = lastbut1;
154 s->state = 12;
155 break;
156 }
157 s->last_step = KS_F_RIGHT;
158 s->state = 9;
159 s->x++;
160 break;
161
162 /* States 12,13,14 walk leftwards along the upper edge of a
163 * horizontal grid line with a pointy kite end at the start
164 * point */
165 case 12:
166 s->last_step = KS_F_RIGHT;
167 s->state = 13;
168 break;
169
170 case 13:
171 if (s->x <= 0) {
172 if (s->y+1 >= s->h) {
173 s->state = 0;
174 return false;
175 }
176 s->last_step = KS_LEFT;
177 s->state = 1;
178 s->y++;
179 break;
180 }
181 s->last_step = KS_RIGHT;
182 s->state = 14;
183 s->x--;
184 break;
185
186 case 14:
187 s->last_step = KS_RIGHT;
188 s->state = 12;
189 break;
190
191 default:
192 return false;
193 }
194
195 *s->curr = kite_step(s->recent[s->last_index], s->last_step);
196 return true;
197}
198
199/*
200 * The actual tables.
201 */
202#include "hat-tables.h"
203
204/*
205 * One set of tables that we write by hand: the permitted ways to
206 * extend the coordinate system outwards from a given metatile.
207 *
208 * One obvious approach would be to make a table of all the places
209 * each metatile can appear in the expansion of another (e.g. H can be
210 * subtile 0, 1 or 2 of another H, subtile 0 of a T, or 0 or 1 of a P
211 * or an F), and when we need to decide what our current topmost tile
212 * turns out to be a subtile of, choose equiprobably at random from
213 * those options.
214 *
215 * That's what I did originally, but a better approach is to skew the
216 * probabilities. We'd like to generate our patch of actual tiling
217 * uniformly at random, in the sense that if you selected uniformly
218 * from a very large region of the plane, the distribution of possible
219 * finite patches of tiling would converge to some limit as that
220 * region tended to infinity, and we'd be picking from that limiting
221 * distribution on finite patches.
222 *
223 * For this we have to refer back to the original paper, which
224 * indicates the subset of each metatile's expansion that can be
225 * considered to 'belong' to that metatile, such that every subtile
226 * belongs to exactly one parent metatile, and the overlaps are
227 * eliminated. Reading out the diagrams from their Figure 2.8:
228 *
229 * - H: we discard three of the outer F subtiles, in the symmetric
230 * positions index by our coordinates as 7, 10, 11. So we keep the
231 * remaining subtiles {0,1,2,3,4,5,6,8,9,12}, which consist of
232 * three H, one T, three P and three F.
233 *
234 * - T: only the central H expanded from a T is considered to belong
235 * to it, so we just keep {0}, a single H.
236 *
237 * - P: we discard everything intersected by a long edge of the
238 * parallelogram, leaving the central three tiles and the endmost
239 * pair of F. That is, we keep {0,1,4,5,10}, consisting of two H,
240 * one P and two F.
241 *
242 * - F: looks like P at one end, and we retain the corresponding set
243 * of tiles there, but at the other end we keep the two F on either
244 * side of the endmost one. So we keep {0,1,3,6,8,10}, consisting of
245 * two H, one P and _three_ F.
246 *
247 * Adding up the tile numbers gives us this matrix system:
248 *
249 * (H_1) (3 1 2 2)(H_0)
250 * (T_1) = (1 0 0 0)(T_0)
251 * (P_1) (3 0 1 1)(P_0)
252 * (F_1) (3 0 2 3)(F_0)
253 *
254 * which says that if you have a patch of metatiling consisting of H_0
255 * H tiles, T_0 T tiles etc, then this matrix shows the number H_1 of
256 * smaller H tiles, etc, expanded from it.
257 *
258 * If you expand _many_ times, that's equivalent to raising the matrix
259 * to a power:
260 *
261 * n
262 * (H_n) (3 1 2 2) (H_0)
263 * (T_n) = (1 0 0 0) (T_0)
264 * (P_n) (3 0 1 1) (P_0)
265 * (F_n) (3 0 2 3) (F_0)
266 *
267 * The limiting distribution of metatiles is obtained by looking at
268 * the four-way ratio between H_n, T_n, P_n and F_n as n tends to
269 * infinity. To calculate this, we find the eigenvalues and
270 * eigenvectors of the matrix, and extract the eigenvector
271 * corresponding to the eigenvalue of largest magnitude. (Things get
272 * more complicated in cases where there isn't a _unique_ eigenvalue
273 * of largest magnitude, but here, there is.)
274 *
275 * That eigenvector is
276 *
277 * [ 1 ] [ 1 ]
278 * [ (7 - 3 sqrt(5)) / 2 ] ~= [ 0.14589803375031545538 ]
279 * [ 3 sqrt(5) - 6 ] [ 0.70820393249936908922 ]
280 * [ (9 - 3 sqrt(5)) / 2 ] [ 1.14589803375031545538 ]
281 *
282 * So those are the limiting relative proportions of metatiles.
283 *
284 * So if we have a particular metatile, how likely is it for its
285 * parent to be one of those? We have to adjust by the number of
286 * metatiles of each type that each tile has as its children. For
287 * example, the P and F tiles have one P child each, but the H has
288 * three P children. So if we have a P, the proportion of H in its
289 * potential ancestry is three times what's shown here. (And T can't
290 * occur at all as a parent.)
291 *
292 * In other words, we should choose _each coordinate_ with probability
293 * corresponding to one of those numbers (scaled down so they all sum
294 * to 1). Continuing to use P as an example, it will be:
295 *
296 * - child 4 of H with relative probability 1
297 * - child 5 of H with relative probability 1
298 * - child 6 of H with relative probability 1
299 * - child 4 of P with relative probability 0.70820393249936908922
300 * - child 3 of F with relative probability 1.14589803375031545538
301 *
302 * and then we obtain the true probabilities by scaling those values
303 * down so that they sum to 1.
304 *
305 * The tables below give a reasonable approximation in 32-bit
306 * integers to these proportions.
307 */
308
309typedef struct MetatilePossibleParent {
310 TileType type;
311 unsigned index;
312 unsigned long probability;
313} MetatilePossibleParent;
314
315/* The above probabilities scaled up by 10000000 */
316#define PROB_H 10000000
317#define PROB_T 1458980
318#define PROB_P 7082039
319#define PROB_F 11458980
320
321static const MetatilePossibleParent parents_H[] = {
322 { TT_H, 0, PROB_H },
323 { TT_H, 1, PROB_H },
324 { TT_H, 2, PROB_H },
325 { TT_T, 0, PROB_T },
326 { TT_P, 0, PROB_P },
327 { TT_P, 1, PROB_P },
328 { TT_F, 0, PROB_F },
329 { TT_F, 1, PROB_F },
330};
331static const MetatilePossibleParent parents_T[] = {
332 { TT_H, 3, PROB_H },
333};
334static const MetatilePossibleParent parents_P[] = {
335 { TT_H, 4, PROB_H },
336 { TT_H, 5, PROB_H },
337 { TT_H, 6, PROB_H },
338 { TT_P, 4, PROB_P },
339 { TT_F, 3, PROB_F },
340};
341static const MetatilePossibleParent parents_F[] = {
342 { TT_H, 8, PROB_H },
343 { TT_H, 9, PROB_H },
344 { TT_H, 12, PROB_H },
345 { TT_P, 5, PROB_P },
346 { TT_P, 10, PROB_P },
347 { TT_F, 6, PROB_F },
348 { TT_F, 8, PROB_F },
349 { TT_F, 10, PROB_F },
350};
351
352static const MetatilePossibleParent *const possible_parents[] = {
353 parents_H, parents_T, parents_P, parents_F,
354};
355static const size_t n_possible_parents[] = {
356 lenof(parents_H), lenof(parents_T), lenof(parents_P), lenof(parents_F),
357};
358
359/*
360 * Similarly, we also want to choose our absolute starting hat with
361 * close to uniform probability, which again we do by looking at the
362 * limiting ratio of the metatile types, and this time, scaling by the
363 * number of hats in each metatile.
364 *
365 * We cheatingly use the same MetatilePossibleParent struct, because
366 * it's got all the right fields, even if it has an inappropriate
367 * name.
368 */
369static const MetatilePossibleParent starting_hats[] = {
370 { TT_H, 0, PROB_H },
371 { TT_H, 1, PROB_H },
372 { TT_H, 2, PROB_H },
373 { TT_H, 3, PROB_H },
374 { TT_T, 0, PROB_P },
375 { TT_P, 0, PROB_P },
376 { TT_P, 1, PROB_P },
377 { TT_F, 0, PROB_F },
378 { TT_F, 1, PROB_F },
379};
380
381#undef PROB_H
382#undef PROB_T
383#undef PROB_P
384#undef PROB_F
385
386HatCoords *hat_coords_new(void)
387{
388 HatCoords *hc = snew(HatCoords);
389 hc->nc = hc->csize = 0;
390 hc->c = NULL;
391 return hc;
392}
393
394void hat_coords_free(HatCoords *hc)
395{
396 if (hc) {
397 sfree(hc->c);
398 sfree(hc);
399 }
400}
401
402void hat_coords_make_space(HatCoords *hc, size_t size)
403{
404 if (hc->csize < size) {
405 hc->csize = hc->csize * 5 / 4 + 16;
406 if (hc->csize < size)
407 hc->csize = size;
408 hc->c = sresize(hc->c, hc->csize, HatCoord);
409 }
410}
411
412HatCoords *hat_coords_copy(HatCoords *hc_in)
413{
414 HatCoords *hc_out = hat_coords_new();
415 hat_coords_make_space(hc_out, hc_in->nc);
416 memcpy(hc_out->c, hc_in->c, hc_in->nc * sizeof(*hc_out->c));
417 hc_out->nc = hc_in->nc;
418 return hc_out;
419}
420
421static const MetatilePossibleParent *choose_mpp(
422 random_state *rs, const MetatilePossibleParent *parents, size_t nparents)
423{
424 /*
425 * If we needed to do this _efficiently_, we'd rewrite all those
426 * tables above as cumulative frequency tables and use binary
427 * search. But this happens about log n times in a grid of area n,
428 * so it hardly matters, and it's easier to keep the tables
429 * legible.
430 */
431 unsigned long limit = 0, value;
432 size_t i;
433
434 for (i = 0; i < nparents; i++)
435 limit += parents[i].probability;
436
437 value = random_upto(rs, limit);
438
439 for (i = 0; i+1 < nparents; i++) {
440 if (value < parents[i].probability)
441 return &parents[i];
442 value -= parents[i].probability;
443 }
444
445 assert(i == nparents - 1);
446 assert(value < parents[i].probability);
447 return &parents[i];
448}
449void hatctx_init_random(HatContext *ctx, random_state *rs)
450{
451 const MetatilePossibleParent *starting_hat = choose_mpp(
452 rs, starting_hats, lenof(starting_hats));
453
454 ctx->rs = rs;
455 ctx->prototype = hat_coords_new();
456 hat_coords_make_space(ctx->prototype, 3);
457 ctx->prototype->c[2].type = starting_hat->type;
458 ctx->prototype->c[2].index = -1;
459 ctx->prototype->c[1].type = TT_HAT;
460 ctx->prototype->c[1].index = starting_hat->index;
461 ctx->prototype->c[0].type = TT_KITE;
462 ctx->prototype->c[0].index = random_upto(rs, HAT_KITES);
463 ctx->prototype->nc = 3;
464}
465
466static inline int metatile_char_to_enum(char metatile)
467{
468 return (metatile == 'H' ? TT_H :
469 metatile == 'T' ? TT_T :
470 metatile == 'P' ? TT_P :
471 metatile == 'F' ? TT_F : -1);
472}
473
474static void init_coords_params(HatContext *ctx,
475 const struct HatPatchParams *hp)
476{
477 size_t i;
478
479 ctx->rs = NULL;
480 ctx->prototype = hat_coords_new();
481
482 assert(hp->ncoords >= 3);
483
484 hat_coords_make_space(ctx->prototype, hp->ncoords + 1);
485 ctx->prototype->nc = hp->ncoords + 1;
486
487 for (i = 0; i < hp->ncoords; i++)
488 ctx->prototype->c[i].index = hp->coords[i];
489
490 ctx->prototype->c[hp->ncoords].type =
491 metatile_char_to_enum(hp->final_metatile);
492 ctx->prototype->c[hp->ncoords].index = -1;
493
494 ctx->prototype->c[0].type = TT_KITE;
495 ctx->prototype->c[1].type = TT_HAT;
496
497 for (i = hp->ncoords - 1; i > 1; i--) {
498 TileType metatile = ctx->prototype->c[i+1].type;
499 assert(hp->coords[i] < nchildren[metatile]);
500 ctx->prototype->c[i].type = children[metatile][hp->coords[i]];
501 }
502
503 assert(hp->coords[0] < 8);
504}
505
506HatCoords *hatctx_initial_coords(HatContext *ctx)
507{
508 return hat_coords_copy(ctx->prototype);
509}
510
511/*
512 * Extend hc until it has at least n coordinates in, by copying from
513 * ctx->prototype if needed, and extending ctx->prototype if needed in
514 * order to do that.
515 */
516void hatctx_extend_coords(HatContext *ctx, HatCoords *hc, size_t n)
517{
518 if (ctx->prototype->nc < n) {
519 hat_coords_make_space(ctx->prototype, n);
520 while (ctx->prototype->nc < n) {
521 TileType type = ctx->prototype->c[ctx->prototype->nc - 1].type;
522 assert(ctx->prototype->c[ctx->prototype->nc - 1].index == -1);
523 const MetatilePossibleParent *parent;
524
525 if (ctx->rs)
526 parent = choose_mpp(ctx->rs, possible_parents[type],
527 n_possible_parents[type]);
528 else
529 parent = possible_parents[type];
530
531 ctx->prototype->c[ctx->prototype->nc - 1].index = parent->index;
532 ctx->prototype->c[ctx->prototype->nc].index = -1;
533 ctx->prototype->c[ctx->prototype->nc].type = parent->type;
534 ctx->prototype->nc++;
535 }
536 }
537
538 hat_coords_make_space(hc, n);
539 while (hc->nc < n) {
540 assert(hc->c[hc->nc - 1].index == -1);
541 assert(hc->c[hc->nc - 1].type == ctx->prototype->c[hc->nc - 1].type);
542 hc->c[hc->nc - 1].index = ctx->prototype->c[hc->nc - 1].index;
543 hc->c[hc->nc].index = -1;
544 hc->c[hc->nc].type = ctx->prototype->c[hc->nc].type;
545 hc->nc++;
546 }
547}
548
549void hatctx_cleanup(HatContext *ctx)
550{
551 hat_coords_free(ctx->prototype);
552}
553
554/*
555 * The actual system for finding the coordinates of an adjacent kite.
556 */
557
558/*
559 * Kitemap step: ensure we have enough coordinates to know two levels
560 * of meta-tiling, and use the kite map for the outer layer to move
561 * around the individual kites. If this fails, return NULL.
562 */
563static HatCoords *try_step_coords_kitemap(
564 HatContext *ctx, HatCoords *hc_in, KiteStep step)
565{
566 hatctx_extend_coords(ctx, hc_in, 4);
567 hat_coords_debug(" try kitemap ", hc_in, "\n");
568 unsigned kite = hc_in->c[0].index;
569 unsigned hat = hc_in->c[1].index;
570 unsigned meta = hc_in->c[2].index;
571 TileType meta2type = hc_in->c[3].type;
572 const KitemapEntry *ke = &kitemap[meta2type][
573 kitemap_index(step, kite, hat, meta)];
574 if (ke->kite >= 0) {
575 /*
576 * Success! We've got coordinates for the next kite in this
577 * direction.
578 */
579 HatCoords *hc_out = hat_coords_copy(hc_in);
580
581 hc_out->c[2].index = ke->meta;
582 hc_out->c[2].type = children[meta2type][ke->meta];
583 hc_out->c[1].index = ke->hat;
584 hc_out->c[1].type = TT_HAT;
585 hc_out->c[0].index = ke->kite;
586 hc_out->c[0].type = TT_KITE;
587
588 hat_coords_debug(" success! ", hc_out, "\n");
589 return hc_out;
590 }
591
592 return NULL;
593}
594
595/*
596 * Recursive metamap step. Try using the metamap to rewrite the
597 * coordinates at hc->c[depth] and hc->c[depth+1] (using the metamap
598 * for the tile type described in hc->c[depth+2]). If successful,
599 * recurse back down to see if this led to a successful step via the
600 * kitemap. If even that fails (so that we need to try a higher-order
601 * metamap rewrite), return NULL.
602 */
603static HatCoords *try_step_coords_metamap(
604 HatContext *ctx, HatCoords *hc_in, KiteStep step, size_t depth)
605{
606 HatCoords *hc_tmp = NULL, *hc_out;
607
608 hatctx_extend_coords(ctx, hc_in, depth+3);
609#ifdef HAT_COORDS_DEBUG
610 fprintf(stderr, " try meta %-4d", (int)depth);
611 hat_coords_debug("", hc_in, "\n");
612#endif
613 unsigned meta_orig = hc_in->c[depth].index;
614 unsigned meta2_orig = hc_in->c[depth+1].index;
615 TileType meta3type = hc_in->c[depth+2].type;
616
617 unsigned meta = meta_orig, meta2 = meta2_orig;
618
619 while (true) {
620 const MetamapEntry *me;
621 HatCoords *hc_curr = hc_tmp ? hc_tmp : hc_in;
622
623 if (depth > 2)
624 hc_out = try_step_coords_metamap(ctx, hc_curr, step, depth - 1);
625 else
626 hc_out = try_step_coords_kitemap(ctx, hc_curr, step);
627 if (hc_out) {
628 hat_coords_free(hc_tmp);
629 return hc_out;
630 }
631
632 me = &metamap[meta3type][metamap_index(meta, meta2)];
633 assert(me->meta != -1);
634 if (me->meta == meta_orig && me->meta2 == meta2_orig) {
635 hat_coords_free(hc_tmp);
636 return NULL;
637 }
638
639 meta = me->meta;
640 meta2 = me->meta2;
641
642 /*
643 * We must do the rewrite in a copy of hc_in. It's not
644 * _necessarily_ obvious that that's the case (any successful
645 * rewrite leaves the coordinates still valid and still
646 * referring to the same kite, right?). But the problem is
647 * that we might do a rewrite at this level more than once,
648 * and in between, a metamap rewrite at the next level down
649 * might have modified _one_ of the two coordinates we're
650 * messing about with. So it's easiest to let the recursion
651 * just use a separate copy.
652 */
653 if (!hc_tmp)
654 hc_tmp = hat_coords_copy(hc_in);
655
656 hc_tmp->c[depth+1].index = meta2;
657 hc_tmp->c[depth+1].type = children[meta3type][meta2];
658 hc_tmp->c[depth].index = meta;
659 hc_tmp->c[depth].type = children[hc_tmp->c[depth+1].type][meta];
660
661 hat_coords_debug(" rewritten -> ", hc_tmp, "\n");
662 }
663}
664
665/*
666 * The top-level algorithm for finding the next tile.
667 */
668HatCoords *hatctx_step(HatContext *ctx, HatCoords *hc_in, KiteStep step)
669{
670 HatCoords *hc_out;
671 size_t depth;
672
673#ifdef HAT_COORDS_DEBUG
674 static const char *const directions[] = {
675 " left\n", " right\n", " forward left\n", " forward right\n" };
676 hat_coords_debug("step start ", hc_in, directions[step]);
677#endif
678
679 /*
680 * First, just try a kitemap step immediately. If that succeeds,
681 * we're done.
682 */
683 if ((hc_out = try_step_coords_kitemap(ctx, hc_in, step)) != NULL)
684 return hc_out;
685
686 /*
687 * Otherwise, try metamap rewrites at successively higher layers
688 * until one works. Each one will recurse back down to the
689 * kitemap, as described above.
690 */
691 for (depth = 2;; depth++) {
692 if ((hc_out = try_step_coords_metamap(
693 ctx, hc_in, step, depth)) != NULL)
694 return hc_out;
695 }
696}
697
698/*
699 * Generate a random set of parameters for a tiling of a given size.
700 * To do this, we iterate over the whole tiling via hat_kiteenum_first
701 * and hat_kiteenum_next, and for each kite, calculate its
702 * coordinates. But then we throw the coordinates away and don't do
703 * anything with them!
704 *
705 * But the side effect of _calculating_ all those coordinates is that
706 * we found out how far ctx->prototype needed to be extended, and did
707 * so, pulling random choices out of our random_state. So after this
708 * iteration, ctx->prototype contains everything we need to replicate
709 * the same piece of tiling next time.
710 */
711void hat_tiling_randomise(struct HatPatchParams *hp, int w, int h,
712 random_state *rs)
713{
714 HatContext ctx[1];
715 HatCoords *coords[KE_NKEEP];
716 KiteEnum s[1];
717 size_t i;
718
719 hatctx_init_random(ctx, rs);
720 for (i = 0; i < lenof(coords); i++)
721 coords[i] = NULL;
722
723 hat_kiteenum_first(s, w, h);
724 coords[s->curr_index] = hatctx_initial_coords(ctx);
725
726 while (hat_kiteenum_next(s)) {
727 hat_coords_free(coords[s->curr_index]);
728 coords[s->curr_index] = hatctx_step(
729 ctx, coords[s->last_index], s->last_step);
730 }
731
732 hp->ncoords = ctx->prototype->nc - 1;
733 hp->coords = snewn(hp->ncoords, unsigned char);
734 for (i = 0; i < hp->ncoords; i++)
735 hp->coords[i] = ctx->prototype->c[i].index;
736 hp->final_metatile = tilechars[ctx->prototype->c[hp->ncoords].type];
737
738 hatctx_cleanup(ctx);
739 for (i = 0; i < lenof(coords); i++)
740 hat_coords_free(coords[i]);
741}
742
743const char *hat_tiling_params_invalid(const struct HatPatchParams *hp)
744{
745 TileType metatile;
746 size_t i;
747
748 if (hp->ncoords < 3)
749 return "Grid parameters require at least three coordinates";
750 if (metatile_char_to_enum(hp->final_metatile) < 0)
751 return "Grid parameters contain an invalid final metatile";
752 if (hp->coords[0] >= 8)
753 return "Grid parameters contain an invalid kite index";
754
755 metatile = metatile_char_to_enum(hp->final_metatile);
756 for (i = hp->ncoords - 1; i > 1; i--) {
757 if (hp->coords[i] >= nchildren[metatile])
758 return "Grid parameters contain an invalid metatile index";
759 metatile = children[metatile][hp->coords[i]];
760 }
761
762 if (hp->coords[1] >= hats_in_metatile[metatile])
763 return "Grid parameters contain an invalid hat index";
764
765 return NULL;
766}
767
768void maybe_report_hat(int w, int h, Kite kite, HatCoords *hc,
769 internal_hat_callback_fn cb, void *cbctx)
770{
771 Kite kite0;
772 Point vertices[14];
773 size_t i, j;
774 bool reversed = false;
775 int coords[28];
776
777 /* Only iterate from kite #0 of a hat */
778 if (hc->c[0].index != 0)
779 return;
780 kite0 = kite;
781
782 /*
783 * Identify reflected hats: they are always hat #3 of an H
784 * metatile. If we find one, reflect the starting kite so that the
785 * kite_step operations below will go in the other direction.
786 */
787 if (hc->c[2].type == TT_H && hc->c[1].index == 3) {
788 reversed = true;
789 Point tmp = kite.left;
790 kite.left = kite.right;
791 kite.right = tmp;
792 }
793
794 vertices[0] = kite.centre;
795 vertices[1] = kite.right;
796 vertices[2] = kite.outer;
797 vertices[3] = kite.left;
798 kite = kite_left(kite); /* now on kite #1 */
799 kite = kite_forward_right(kite); /* now on kite #2 */
800 vertices[4] = kite.centre;
801 kite = kite_right(kite); /* now on kite #3 */
802 vertices[5] = kite.right;
803 vertices[6] = kite.outer;
804 kite = kite_forward_left(kite); /* now on kite #4 */
805 vertices[7] = kite.left;
806 vertices[8] = kite.centre;
807 kite = kite_right(kite); /* now on kite #5 */
808 kite = kite_right(kite); /* now on kite #6 */
809 kite = kite_right(kite); /* now on kite #7 */
810 vertices[9] = kite.right;
811 vertices[10] = kite.outer;
812 vertices[11] = kite.left;
813 kite = kite_left(kite); /* now on kite #6 again */
814 vertices[12] = kite.outer;
815 vertices[13] = kite.left;
816
817 if (reversed) {
818 /* For a reversed kite, also reverse the vertex order, so that
819 * we report every polygon in a consistent orientation */
820 for (i = 0, j = 13; i < j; i++, j--) {
821 Point tmp = vertices[i];
822 vertices[i] = vertices[j];
823 vertices[j] = tmp;
824 }
825 }
826
827 /*
828 * Convert from our internal coordinate system into the orthogonal
829 * one used in this module's external API. In the same loop, we
830 * might as well do the bounds check.
831 */
832 for (i = 0; i < 14; i++) {
833 Point v = vertices[i];
834 int x = (v.x * 2 + v.y) / 3, y = v.y;
835
836 if (x < 0 || x > 4*w || y < 0 || y > 6*h)
837 return; /* a vertex of this kite is out of bounds */
838
839 coords[2*i] = x;
840 coords[2*i+1] = y;
841 }
842
843 cb(cbctx, kite0, hc, coords);
844}
845
846struct internal_ctx {
847 hat_tile_callback_fn external_cb;
848 void *external_cbctx;
849};
850static void report_hat(void *vctx, Kite kite0, HatCoords *hc, int *coords)
851{
852 struct internal_ctx *ctx = (struct internal_ctx *)vctx;
853 ctx->external_cb(ctx->external_cbctx, 14, coords);
854}
855
856/*
857 * Generate a hat tiling from a previously generated set of parameters.
858 */
859void hat_tiling_generate(const struct HatPatchParams *hp, int w, int h,
860 hat_tile_callback_fn cb, void *cbctx)
861{
862 HatContext ctx[1];
863 HatCoords *coords[KE_NKEEP];
864 KiteEnum s[1];
865 size_t i;
866 struct internal_ctx report_hat_ctx[1];
867
868 report_hat_ctx->external_cb = cb;
869 report_hat_ctx->external_cbctx = cbctx;
870
871 init_coords_params(ctx, hp);
872 for (i = 0; i < lenof(coords); i++)
873 coords[i] = NULL;
874
875 hat_kiteenum_first(s, w, h);
876 coords[s->curr_index] = hatctx_initial_coords(ctx);
877 maybe_report_hat(w, h, *s->curr, coords[s->curr_index],
878 report_hat, report_hat_ctx);
879
880 while (hat_kiteenum_next(s)) {
881 hat_coords_free(coords[s->curr_index]);
882 coords[s->curr_index] = hatctx_step(
883 ctx, coords[s->last_index], s->last_step);
884 maybe_report_hat(w, h, *s->curr, coords[s->curr_index],
885 report_hat, report_hat_ctx);
886 }
887
888 hatctx_cleanup(ctx);
889 for (i = 0; i < lenof(coords); i++)
890 hat_coords_free(coords[i]);
891}
diff --git a/apps/plugins/puzzles/src/hat.h b/apps/plugins/puzzles/src/hat.h
new file mode 100644
index 0000000000..39e2d31a66
--- /dev/null
+++ b/apps/plugins/puzzles/src/hat.h
@@ -0,0 +1,67 @@
1#ifndef PUZZLES_HAT_H
2#define PUZZLES_HAT_H
3
4struct HatPatchParams {
5 /*
6 * A patch of hat tiling is identified by giving the coordinates
7 * of the kite in one corner, using a multi-level coordinate
8 * system based on metatile expansions. Coordinates are a sequence
9 * of small non-negative integers. The valid range for each
10 * coordinate depends on the next coordinate, or on final_metatile
11 * if it's the last one in the list. The largest valid range is
12 * {0,...,12}.
13 *
14 * 'final_metatile' is one of the characters 'H', 'T', 'P' or 'F'.
15 */
16 size_t ncoords;
17 unsigned char *coords;
18 char final_metatile;
19};
20
21/*
22 * Fill in HatPatchParams with a randomly selected set of coordinates,
23 * in enough detail to generate a patch of tiling covering an area of
24 * w x h 'squares' of a kite tiling.
25 *
26 * The kites grid is considered to be oriented so that it includes
27 * horizontal lines and not vertical ones. So each of the smallest
28 * equilateral triangles in the grid has a bounding rectangle whose
29 * height is sqrt(3)/2 times its width, and either the top or the
30 * bottom of that bounding rectangle is the horizontal edge of the
31 * triangle. A 'square' of a kite tiling (for convenience of choosing
32 * grid dimensions) counts as one of those bounding rectangles.
33 *
34 * The 'coords' field of the structure will be filled in with a new
35 * dynamically allocated array. Any previous pointer in that field
36 * will be overwritten.
37 */
38void hat_tiling_randomise(struct HatPatchParams *params, int w, int h,
39 random_state *rs);
40
41/*
42 * Validate a HatPatchParams to ensure it contains no illegal
43 * coordinates. Returns NULL if it's acceptable, or an error string if
44 * not.
45 */
46const char *hat_tiling_params_invalid(const struct HatPatchParams *params);
47
48/*
49 * Generate the actual set of hat tiles from a HatPatchParams, passing
50 * each one to a callback. The callback receives the vertices of each
51 * point, as a sequence of 2*nvertices integers, with x,y coordinates
52 * interleaved.
53 *
54 * The x coordinates are measured in units of 1/4 of the side length
55 * of the smallest equilateral triangle, or equivalently, 1/2 the
56 * length of one of the long edges of a single kite. The y coordinates
57 * are measured in units of 1/6 the height of the triangle, which is
58 * also 1/2 the length of the short edge of a kite. Therefore, you can
59 * expect x to go up to 4*w and y up to 6*h.
60 */
61typedef void (*hat_tile_callback_fn)(void *ctx, size_t nvertices,
62 int *coords);
63
64void hat_tiling_generate(const struct HatPatchParams *params, int w, int h,
65 hat_tile_callback_fn cb, void *cbctx);
66
67#endif
diff --git a/apps/plugins/puzzles/src/inertia.R b/apps/plugins/puzzles/src/inertia.R
deleted file mode 100644
index e6e86beaec..0000000000
--- a/apps/plugins/puzzles/src/inertia.R
+++ /dev/null
@@ -1,19 +0,0 @@
1# -*- makefile -*-
2
3inertia : [X] GTK COMMON inertia inertia-icon|no-icon
4
5inertia : [G] WINDOWS COMMON inertia inertia.res|noicon.res
6
7ALL += inertia[COMBINED]
8
9!begin am gtk
10GAMES += inertia
11!end
12
13!begin >list.c
14 A(inertia) \
15!end
16
17!begin >gamedesc.txt
18inertia:inertia.exe:Inertia:Gem-collecting puzzle:Collect all the gems without running into any of the mines.
19!end
diff --git a/apps/plugins/puzzles/src/inertia.c b/apps/plugins/puzzles/src/inertia.c
index 726c89c7dd..d120411f55 100644
--- a/apps/plugins/puzzles/src/inertia.c
+++ b/apps/plugins/puzzles/src/inertia.c
@@ -11,7 +11,12 @@
11#include <string.h> 11#include <string.h>
12#include <assert.h> 12#include <assert.h>
13#include <ctype.h> 13#include <ctype.h>
14#include <math.h> 14#include <limits.h>
15#ifdef NO_TGMATH_H
16# include <math.h>
17#else
18# include <tgmath.h>
19#endif
15 20
16#include "puzzles.h" 21#include "puzzles.h"
17 22
@@ -202,6 +207,8 @@ static const char *validate_params(const game_params *params, bool full)
202 */ 207 */
203 if (params->w < 2 || params->h < 2) 208 if (params->w < 2 || params->h < 2)
204 return "Width and height must both be at least two"; 209 return "Width and height must both be at least two";
210 if (params->w > INT_MAX / params->h)
211 return "Width times height must not be unreasonably large";
205 212
206 /* 213 /*
207 * The grid construction algorithm creates 1/5 as many gems as 214 * The grid construction algorithm creates 1/5 as many gems as
@@ -1520,7 +1527,8 @@ static char *encode_ui(const game_ui *ui)
1520 return dupstr(buf); 1527 return dupstr(buf);
1521} 1528}
1522 1529
1523static void decode_ui(game_ui *ui, const char *encoding) 1530static void decode_ui(game_ui *ui, const char *encoding,
1531 const game_state *state)
1524{ 1532{
1525 int p = 0; 1533 int p = 0;
1526 sscanf(encoding, "D%d%n", &ui->deaths, &p); 1534 sscanf(encoding, "D%d%n", &ui->deaths, &p);
@@ -1545,6 +1553,15 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1545 ui->just_made_move = false; 1553 ui->just_made_move = false;
1546} 1554}
1547 1555
1556static const char *current_key_label(const game_ui *ui,
1557 const game_state *state, int button)
1558{
1559 if (IS_CURSOR_SELECT(button) &&
1560 state->soln && state->solnpos < state->soln->len)
1561 return "Advance";
1562 return "";
1563}
1564
1548struct game_drawstate { 1565struct game_drawstate {
1549 game_params p; 1566 game_params p;
1550 int tilesize; 1567 int tilesize;
@@ -1593,7 +1610,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1593 * end up the right way round. */ 1610 * end up the right way round. */
1594 angle = atan2(dx, -dy); 1611 angle = atan2(dx, -dy);
1595 1612
1596 angle = (angle + (PI/8)) / (PI/4); 1613 angle = (angle + (float)(PI/8)) / (float)(PI/4);
1597 assert(angle > -16.0F); 1614 assert(angle > -16.0F);
1598 dir = (int)(angle + 16.0F) & 7; 1615 dir = (int)(angle + 16.0F) & 7;
1599 } 1616 }
@@ -1618,20 +1635,20 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1618 dir = state->soln->list[state->solnpos]; 1635 dir = state->soln->list[state->solnpos];
1619 1636
1620 if (dir < 0) 1637 if (dir < 0)
1621 return NULL; 1638 return MOVE_UNUSED;
1622 1639
1623 /* 1640 /*
1624 * Reject the move if we can't make it at all due to a wall 1641 * Reject the move if we can't make it at all due to a wall
1625 * being in the way. 1642 * being in the way.
1626 */ 1643 */
1627 if (AT(w, h, state->grid, state->px+DX(dir), state->py+DY(dir)) == WALL) 1644 if (AT(w, h, state->grid, state->px+DX(dir), state->py+DY(dir)) == WALL)
1628 return NULL; 1645 return MOVE_NO_EFFECT;
1629 1646
1630 /* 1647 /*
1631 * Reject the move if we're dead! 1648 * Reject the move if we're dead!
1632 */ 1649 */
1633 if (state->dead) 1650 if (state->dead)
1634 return NULL; 1651 return MOVE_NO_EFFECT;
1635 1652
1636 /* 1653 /*
1637 * Otherwise, we can make the move. All we need to specify is 1654 * Otherwise, we can make the move. All we need to specify is
@@ -1685,6 +1702,7 @@ static game_state *execute_move(const game_state *state, const char *move)
1685 * This is a solve move, so we don't actually _change_ the 1702 * This is a solve move, so we don't actually _change_ the
1686 * grid but merely set up a stored solution path. 1703 * grid but merely set up a stored solution path.
1687 */ 1704 */
1705 if (move[1] == '\0') return NULL; /* Solution must be non-empty. */
1688 ret = dup_game(state); 1706 ret = dup_game(state);
1689 install_new_solution(ret, move); 1707 install_new_solution(ret, move);
1690 return ret; 1708 return ret;
@@ -1729,11 +1747,10 @@ static game_state *execute_move(const game_state *state, const char *move)
1729 if (ret->soln) { 1747 if (ret->soln) {
1730 if (ret->dead || ret->gems == 0) 1748 if (ret->dead || ret->gems == 0)
1731 discard_solution(ret); 1749 discard_solution(ret);
1732 else if (ret->soln->list[ret->solnpos] == dir) { 1750 else if (ret->soln->list[ret->solnpos] == dir &&
1751 ret->solnpos+1 < ret->soln->len)
1733 ++ret->solnpos; 1752 ++ret->solnpos;
1734 assert(ret->solnpos < ret->soln->len); /* or gems == 0 */ 1753 else {
1735 assert(!ret->dead); /* or not a solution */
1736 } else {
1737 const char *error = NULL; 1754 const char *error = NULL;
1738 char *soln = solve_game(NULL, ret, NULL, &error); 1755 char *soln = solve_game(NULL, ret, NULL, &error);
1739 if (!error) { 1756 if (!error) {
@@ -1751,7 +1768,7 @@ static game_state *execute_move(const game_state *state, const char *move)
1751 */ 1768 */
1752 1769
1753static void game_compute_size(const game_params *params, int tilesize, 1770static void game_compute_size(const game_params *params, int tilesize,
1754 int *x, int *y) 1771 const game_ui *ui, int *x, int *y)
1755{ 1772{
1756 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 1773 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1757 struct { int tilesize; } ads, *ds = &ads; 1774 struct { int tilesize; } ads, *ds = &ads;
@@ -1869,11 +1886,6 @@ static void draw_player(drawing *dr, game_drawstate *ds, int x, int y,
1869 coords[d*4+2] = x + TILESIZE/2 + (int)((TILESIZE*3/7) * x2); 1886 coords[d*4+2] = x + TILESIZE/2 + (int)((TILESIZE*3/7) * x2);
1870 coords[d*4+3] = y + TILESIZE/2 + (int)((TILESIZE*3/7) * y2); 1887 coords[d*4+3] = y + TILESIZE/2 + (int)((TILESIZE*3/7) * y2);
1871 } 1888 }
1872 /* rockbox hack */
1873 int tmp[2] = { coords[0], coords[1] };
1874 memmove(coords, coords + 2, sizeof(int) * DIRECTIONS * 4 - 2);
1875 memcpy(coords + DIRECTIONS * 4 - 2, tmp, 2 * sizeof(int));
1876
1877 draw_polygon(dr, coords, DIRECTIONS*2, COL_DEAD_PLAYER, COL_OUTLINE); 1889 draw_polygon(dr, coords, DIRECTIONS*2, COL_DEAD_PLAYER, COL_OUTLINE);
1878 } else { 1890 } else {
1879 draw_circle(dr, x + TILESIZE/2, y + TILESIZE/2, 1891 draw_circle(dr, x + TILESIZE/2, y + TILESIZE/2,
@@ -1889,6 +1901,8 @@ static void draw_player(drawing *dr, game_drawstate *ds, int x, int y,
1889 int coords[14], *c; 1901 int coords[14], *c;
1890 1902
1891 c = coords; 1903 c = coords;
1904 *c++ = ox + px/9;
1905 *c++ = oy + py/9;
1892 *c++ = ox + px/9 + ax*2/3; 1906 *c++ = ox + px/9 + ax*2/3;
1893 *c++ = oy + py/9 + ay*2/3; 1907 *c++ = oy + py/9 + ay*2/3;
1894 *c++ = ox + px/3 + ax*2/3; 1908 *c++ = ox + px/3 + ax*2/3;
@@ -1901,8 +1915,6 @@ static void draw_player(drawing *dr, game_drawstate *ds, int x, int y,
1901 *c++ = oy - py/9 + ay*2/3; 1915 *c++ = oy - py/9 + ay*2/3;
1902 *c++ = ox - px/9; 1916 *c++ = ox - px/9;
1903 *c++ = oy - py/9; 1917 *c++ = oy - py/9;
1904 *c++ = ox + px/9;
1905 *c++ = oy + py/9;
1906 draw_polygon(dr, coords, 7, COL_HINT, COL_OUTLINE); 1918 draw_polygon(dr, coords, 7, COL_HINT, COL_OUTLINE);
1907 } 1919 }
1908 1920
@@ -2013,15 +2025,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2013 * Initialise a fresh drawstate. 2025 * Initialise a fresh drawstate.
2014 */ 2026 */
2015 if (!ds->started) { 2027 if (!ds->started) {
2016 int wid, ht;
2017
2018 /*
2019 * Blank out the window initially.
2020 */
2021 game_compute_size(&ds->p, TILESIZE, &wid, &ht);
2022 draw_rect(dr, 0, 0, wid, ht, COL_BACKGROUND);
2023 draw_update(dr, 0, 0, wid, ht);
2024
2025 /* 2028 /*
2026 * Draw the grid lines. 2029 * Draw the grid lines.
2027 */ 2030 */
@@ -2207,19 +2210,6 @@ static int game_status(const game_state *state)
2207 return state->gems == 0 ? +1 : 0; 2210 return state->gems == 0 ? +1 : 0;
2208} 2211}
2209 2212
2210static bool game_timing_state(const game_state *state, game_ui *ui)
2211{
2212 return true;
2213}
2214
2215static void game_print_size(const game_params *params, float *x, float *y)
2216{
2217}
2218
2219static void game_print(drawing *dr, const game_state *state, int tilesize)
2220{
2221}
2222
2223#ifdef COMBINED 2213#ifdef COMBINED
2224#define thegame inertia 2214#define thegame inertia
2225#endif 2215#endif
@@ -2241,12 +2231,14 @@ const struct game thegame = {
2241 free_game, 2231 free_game,
2242 true, solve_game, 2232 true, solve_game,
2243 true, game_can_format_as_text_now, game_text_format, 2233 true, game_can_format_as_text_now, game_text_format,
2234 NULL, NULL, /* get_prefs, set_prefs */
2244 new_ui, 2235 new_ui,
2245 free_ui, 2236 free_ui,
2246 encode_ui, 2237 encode_ui,
2247 decode_ui, 2238 decode_ui,
2248 NULL, /* game_request_keys */ 2239 NULL, /* game_request_keys */
2249 game_changed_state, 2240 game_changed_state,
2241 current_key_label,
2250 interpret_move, 2242 interpret_move,
2251 execute_move, 2243 execute_move,
2252 PREFERRED_TILESIZE, game_compute_size, game_set_size, 2244 PREFERRED_TILESIZE, game_compute_size, game_set_size,
@@ -2258,8 +2250,8 @@ const struct game thegame = {
2258 game_flash_length, 2250 game_flash_length,
2259 game_get_cursor_location, 2251 game_get_cursor_location,
2260 game_status, 2252 game_status,
2261 false, false, game_print_size, game_print, 2253 false, false, NULL, NULL, /* print_size, print */
2262 true, /* wants_statusbar */ 2254 true, /* wants_statusbar */
2263 false, game_timing_state, 2255 false, NULL, /* timing_state */
2264 0, /* flags */ 2256 0, /* flags */
2265}; 2257};
diff --git a/apps/plugins/puzzles/src/keen.R b/apps/plugins/puzzles/src/keen.R
deleted file mode 100644
index 46bd09a33d..0000000000
--- a/apps/plugins/puzzles/src/keen.R
+++ /dev/null
@@ -1,25 +0,0 @@
1# -*- makefile -*-
2
3KEEN_EXTRA = dsf LATIN
4KEEN_EXTRA_SOLVER = dsf LATIN_SOLVER
5
6keen : [X] GTK COMMON keen KEEN_EXTRA keen-icon|no-icon
7
8keen : [G] WINDOWS COMMON keen KEEN_EXTRA keen.res|noicon.res
9
10keensolver : [U] keen[STANDALONE_SOLVER] KEEN_EXTRA_SOLVER STANDALONE
11keensolver : [C] keen[STANDALONE_SOLVER] KEEN_EXTRA_SOLVER STANDALONE
12
13ALL += keen[COMBINED] KEEN_EXTRA
14
15!begin am gtk
16GAMES += keen
17!end
18
19!begin >list.c
20 A(keen) \
21!end
22
23!begin >gamedesc.txt
24keen:keen.exe:Keen:Arithmetic Latin square puzzle:Complete the latin square in accordance with the arithmetic clues.
25!end
diff --git a/apps/plugins/puzzles/src/keen.c b/apps/plugins/puzzles/src/keen.c
index 6b9610dbcd..7e2f71c8f9 100644
--- a/apps/plugins/puzzles/src/keen.c
+++ b/apps/plugins/puzzles/src/keen.c
@@ -8,7 +8,11 @@
8#include <string.h> 8#include <string.h>
9#include <assert.h> 9#include <assert.h>
10#include <ctype.h> 10#include <ctype.h>
11#include <math.h> 11#ifdef NO_TGMATH_H
12# include <math.h>
13#else
14# include <tgmath.h>
15#endif
12 16
13#include "puzzles.h" 17#include "puzzles.h"
14#include "latin.h" 18#include "latin.h"
@@ -69,7 +73,7 @@ struct game_params {
69struct clues { 73struct clues {
70 int refcount; 74 int refcount;
71 int w; 75 int w;
72 int *dsf; 76 DSF *dsf;
73 long *clues; 77 long *clues;
74}; 78};
75 79
@@ -677,7 +681,7 @@ static bool keen_valid(struct latin_solver *solver, void *vctx)
677 return true; 681 return true;
678} 682}
679 683
680static int solver(int w, int *dsf, long *clues, digit *soln, int maxdiff) 684static int solver(int w, DSF *dsf, long *clues, digit *soln, int maxdiff)
681{ 685{
682 int a = w*w; 686 int a = w*w;
683 struct solver_ctx ctx; 687 struct solver_ctx ctx;
@@ -704,11 +708,11 @@ static int solver(int w, int *dsf, long *clues, digit *soln, int maxdiff)
704 ctx.clues = snewn(ctx.nboxes, long); 708 ctx.clues = snewn(ctx.nboxes, long);
705 ctx.whichbox = snewn(a, int); 709 ctx.whichbox = snewn(a, int);
706 for (n = m = i = 0; i < a; i++) 710 for (n = m = i = 0; i < a; i++)
707 if (dsf_canonify(dsf, i) == i) { 711 if (dsf_minimal(dsf, i) == i) {
708 ctx.clues[n] = clues[i]; 712 ctx.clues[n] = clues[i];
709 ctx.boxes[n] = m; 713 ctx.boxes[n] = m;
710 for (j = 0; j < a; j++) 714 for (j = 0; j < a; j++)
711 if (dsf_canonify(dsf, j) == i) { 715 if (dsf_minimal(dsf, j) == i) {
712 ctx.boxlist[m++] = (j % w) * w + (j / w); /* transpose */ 716 ctx.boxlist[m++] = (j % w) * w + (j / w); /* transpose */
713 ctx.whichbox[ctx.boxlist[m-1]] = n; 717 ctx.whichbox[ctx.boxlist[m-1]] = n;
714 } 718 }
@@ -740,7 +744,7 @@ static int solver(int w, int *dsf, long *clues, digit *soln, int maxdiff)
740 * Grid generation. 744 * Grid generation.
741 */ 745 */
742 746
743static char *encode_block_structure(char *p, int w, int *dsf) 747static char *encode_block_structure(char *p, int w, DSF *dsf)
744{ 748{
745 int i, currrun = 0; 749 int i, currrun = 0;
746 char *orig, *q, *r, c; 750 char *orig, *q, *r, c;
@@ -777,7 +781,7 @@ static char *encode_block_structure(char *p, int w, int *dsf)
777 p0 = y*w+x; 781 p0 = y*w+x;
778 p1 = (y+1)*w+x; 782 p1 = (y+1)*w+x;
779 } 783 }
780 edge = (dsf_canonify(dsf, p0) != dsf_canonify(dsf, p1)); 784 edge = !dsf_equivalent(dsf, p0, p1);
781 } 785 }
782 786
783 if (edge) { 787 if (edge) {
@@ -815,13 +819,12 @@ static char *encode_block_structure(char *p, int w, int *dsf)
815 return q; 819 return q;
816} 820}
817 821
818static const char *parse_block_structure(const char **p, int w, int *dsf) 822static const char *parse_block_structure(const char **p, int w, DSF *dsf)
819{ 823{
820 int a = w*w;
821 int pos = 0; 824 int pos = 0;
822 int repc = 0, repn = 0; 825 int repc = 0, repn = 0;
823 826
824 dsf_init(dsf, a); 827 dsf_reinit(dsf);
825 828
826 while (**p && (repn > 0 || **p != ',')) { 829 while (**p && (repn > 0 || **p != ',')) {
827 int c; 830 int c;
@@ -890,7 +893,8 @@ static char *new_game_desc(const game_params *params, random_state *rs,
890{ 893{
891 int w = params->w, a = w*w; 894 int w = params->w, a = w*w;
892 digit *grid, *soln; 895 digit *grid, *soln;
893 int *order, *revorder, *singletons, *dsf; 896 int *order, *revorder, *singletons;
897 DSF *dsf;
894 long *clues, *cluevals; 898 long *clues, *cluevals;
895 int i, j, k, n, x, y, ret; 899 int i, j, k, n, x, y, ret;
896 int diff = params->diff; 900 int diff = params->diff;
@@ -927,7 +931,7 @@ done
927 order = snewn(a, int); 931 order = snewn(a, int);
928 revorder = snewn(a, int); 932 revorder = snewn(a, int);
929 singletons = snewn(a, int); 933 singletons = snewn(a, int);
930 dsf = snew_dsf(a); 934 dsf = dsf_new_min(a);
931 clues = snewn(a, long); 935 clues = snewn(a, long);
932 cluevals = snewn(a, long); 936 cluevals = snewn(a, long);
933 soln = snewn(a, digit); 937 soln = snewn(a, digit);
@@ -955,7 +959,7 @@ done
955 for (i = 0; i < a; i++) 959 for (i = 0; i < a; i++)
956 singletons[i] = true; 960 singletons[i] = true;
957 961
958 dsf_init(dsf, a); 962 dsf_reinit(dsf);
959 963
960 /* Place dominoes. */ 964 /* Place dominoes. */
961 for (i = 0; i < a; i++) { 965 for (i = 0; i < a; i++) {
@@ -1037,11 +1041,10 @@ done
1037 * integer quotient, of course), but we rule out (or try to 1041 * integer quotient, of course), but we rule out (or try to
1038 * avoid) some clues because they're of low quality. 1042 * avoid) some clues because they're of low quality.
1039 * 1043 *
1040 * Hence, we iterate once over the grid, stopping at the 1044 * Hence, we iterate once over the grid, stopping at the first
1041 * canonical element of every >2 block and the _non_- 1045 * element in every >2 block and the _last_ element of every
1042 * canonical element of every 2-block; the latter means that 1046 * 2-block; the latter means that we can make our decision
1043 * we can make our decision about a 2-block in the knowledge 1047 * about a 2-block in the knowledge of both numbers in it.
1044 * of both numbers in it.
1045 * 1048 *
1046 * We reuse the 'singletons' array (finished with in the 1049 * We reuse the 'singletons' array (finished with in the
1047 * above loop) to hold information about which blocks are 1050 * above loop) to hold information about which blocks are
@@ -1055,7 +1058,7 @@ done
1055 1058
1056 for (i = 0; i < a; i++) { 1059 for (i = 0; i < a; i++) {
1057 singletons[i] = 0; 1060 singletons[i] = 0;
1058 j = dsf_canonify(dsf, i); 1061 j = dsf_minimal(dsf, i);
1059 k = dsf_size(dsf, j); 1062 k = dsf_size(dsf, j);
1060 if (params->multiplication_only) 1063 if (params->multiplication_only)
1061 singletons[j] = F_MUL; 1064 singletons[j] = F_MUL;
@@ -1178,7 +1181,7 @@ done
1178 * Having chosen the clue types, calculate the clue values. 1181 * Having chosen the clue types, calculate the clue values.
1179 */ 1182 */
1180 for (i = 0; i < a; i++) { 1183 for (i = 0; i < a; i++) {
1181 j = dsf_canonify(dsf, i); 1184 j = dsf_minimal(dsf, i);
1182 if (j == i) { 1185 if (j == i) {
1183 cluevals[j] = grid[i]; 1186 cluevals[j] = grid[i];
1184 } else { 1187 } else {
@@ -1206,7 +1209,7 @@ done
1206 } 1209 }
1207 1210
1208 for (i = 0; i < a; i++) { 1211 for (i = 0; i < a; i++) {
1209 j = dsf_canonify(dsf, i); 1212 j = dsf_minimal(dsf, i);
1210 if (j == i) { 1213 if (j == i) {
1211 clues[j] |= cluevals[j]; 1214 clues[j] |= cluevals[j];
1212 } 1215 }
@@ -1252,7 +1255,7 @@ done
1252 p = encode_block_structure(p, w, dsf); 1255 p = encode_block_structure(p, w, dsf);
1253 *p++ = ','; 1256 *p++ = ',';
1254 for (i = 0; i < a; i++) { 1257 for (i = 0; i < a; i++) {
1255 j = dsf_canonify(dsf, i); 1258 j = dsf_minimal(dsf, i);
1256 if (j == i) { 1259 if (j == i) {
1257 switch (clues[j] & CMASK) { 1260 switch (clues[j] & CMASK) {
1258 case C_ADD: *p++ = 'a'; break; 1261 case C_ADD: *p++ = 'a'; break;
@@ -1280,7 +1283,7 @@ done
1280 sfree(order); 1283 sfree(order);
1281 sfree(revorder); 1284 sfree(revorder);
1282 sfree(singletons); 1285 sfree(singletons);
1283 sfree(dsf); 1286 dsf_free(dsf);
1284 sfree(clues); 1287 sfree(clues);
1285 sfree(cluevals); 1288 sfree(cluevals);
1286 sfree(soln); 1289 sfree(soln);
@@ -1295,7 +1298,7 @@ done
1295static const char *validate_desc(const game_params *params, const char *desc) 1298static const char *validate_desc(const game_params *params, const char *desc)
1296{ 1299{
1297 int w = params->w, a = w*w; 1300 int w = params->w, a = w*w;
1298 int *dsf; 1301 DSF *dsf;
1299 const char *ret; 1302 const char *ret;
1300 const char *p = desc; 1303 const char *p = desc;
1301 int i; 1304 int i;
@@ -1303,15 +1306,17 @@ static const char *validate_desc(const game_params *params, const char *desc)
1303 /* 1306 /*
1304 * Verify that the block structure makes sense. 1307 * Verify that the block structure makes sense.
1305 */ 1308 */
1306 dsf = snew_dsf(a); 1309 dsf = dsf_new_min(a);
1307 ret = parse_block_structure(&p, w, dsf); 1310 ret = parse_block_structure(&p, w, dsf);
1308 if (ret) { 1311 if (ret) {
1309 sfree(dsf); 1312 dsf_free(dsf);
1310 return ret; 1313 return ret;
1311 } 1314 }
1312 1315
1313 if (*p != ',') 1316 if (*p != ',') {
1317 dsf_free(dsf);
1314 return "Expected ',' after block structure description"; 1318 return "Expected ',' after block structure description";
1319 }
1315 p++; 1320 p++;
1316 1321
1317 /* 1322 /*
@@ -1319,21 +1324,26 @@ static const char *validate_desc(const game_params *params, const char *desc)
1319 * and DIV clues don't apply to blocks of the wrong size. 1324 * and DIV clues don't apply to blocks of the wrong size.
1320 */ 1325 */
1321 for (i = 0; i < a; i++) { 1326 for (i = 0; i < a; i++) {
1322 if (dsf_canonify(dsf, i) == i) { 1327 if (dsf_minimal(dsf, i) == i) {
1323 if (*p == 'a' || *p == 'm') { 1328 if (*p == 'a' || *p == 'm') {
1324 /* these clues need no validation */ 1329 /* these clues need no validation */
1325 } else if (*p == 'd' || *p == 's') { 1330 } else if (*p == 'd' || *p == 's') {
1326 if (dsf_size(dsf, i) != 2) 1331 if (dsf_size(dsf, i) != 2) {
1332 dsf_free(dsf);
1327 return "Subtraction and division blocks must have area 2"; 1333 return "Subtraction and division blocks must have area 2";
1334 }
1328 } else if (!*p) { 1335 } else if (!*p) {
1336 dsf_free(dsf);
1329 return "Too few clues for block structure"; 1337 return "Too few clues for block structure";
1330 } else { 1338 } else {
1339 dsf_free(dsf);
1331 return "Unrecognised clue type"; 1340 return "Unrecognised clue type";
1332 } 1341 }
1333 p++; 1342 p++;
1334 while (*p && isdigit((unsigned char)*p)) p++; 1343 while (*p && isdigit((unsigned char)*p)) p++;
1335 } 1344 }
1336 } 1345 }
1346 dsf_free(dsf);
1337 if (*p) 1347 if (*p)
1338 return "Too many clues for block structure"; 1348 return "Too many clues for block structure";
1339 1349
@@ -1373,7 +1383,7 @@ static game_state *new_game(midend *me, const game_params *params,
1373 state->clues = snew(struct clues); 1383 state->clues = snew(struct clues);
1374 state->clues->refcount = 1; 1384 state->clues->refcount = 1;
1375 state->clues->w = w; 1385 state->clues->w = w;
1376 state->clues->dsf = snew_dsf(a); 1386 state->clues->dsf = dsf_new_min(a);
1377 parse_block_structure(&p, w, state->clues->dsf); 1387 parse_block_structure(&p, w, state->clues->dsf);
1378 1388
1379 assert(*p == ','); 1389 assert(*p == ',');
@@ -1381,7 +1391,7 @@ static game_state *new_game(midend *me, const game_params *params,
1381 1391
1382 state->clues->clues = snewn(a, long); 1392 state->clues->clues = snewn(a, long);
1383 for (i = 0; i < a; i++) { 1393 for (i = 0; i < a; i++) {
1384 if (dsf_canonify(state->clues->dsf, i) == i) { 1394 if (dsf_minimal(state->clues->dsf, i) == i) {
1385 long clue = 0; 1395 long clue = 0;
1386 switch (*p) { 1396 switch (*p) {
1387 case 'a': 1397 case 'a':
@@ -1448,7 +1458,7 @@ static void free_game(game_state *state)
1448 sfree(state->grid); 1458 sfree(state->grid);
1449 sfree(state->pencil); 1459 sfree(state->pencil);
1450 if (--state->clues->refcount <= 0) { 1460 if (--state->clues->refcount <= 0) {
1451 sfree(state->clues->dsf); 1461 dsf_free(state->clues->dsf);
1452 sfree(state->clues->clues); 1462 sfree(state->clues->clues);
1453 sfree(state->clues); 1463 sfree(state->clues);
1454 } 1464 }
@@ -1490,16 +1500,6 @@ static char *solve_game(const game_state *state, const game_state *currstate,
1490 return out; 1500 return out;
1491} 1501}
1492 1502
1493static bool game_can_format_as_text_now(const game_params *params)
1494{
1495 return true;
1496}
1497
1498static char *game_text_format(const game_state *state)
1499{
1500 return NULL;
1501}
1502
1503struct game_ui { 1503struct game_ui {
1504 /* 1504 /*
1505 * These are the coordinates of the currently highlighted 1505 * These are the coordinates of the currently highlighted
@@ -1525,6 +1525,17 @@ struct game_ui {
1525 * allowed on immutable squares. 1525 * allowed on immutable squares.
1526 */ 1526 */
1527 bool hcursor; 1527 bool hcursor;
1528
1529 /*
1530 * User preference option: if the user right-clicks in a square
1531 * and presses a number key to add/remove a pencil mark, do we
1532 * hide the mouse highlight again afterwards?
1533 *
1534 * Historically our answer was yes. The Android port prefers no.
1535 * There are advantages both ways, depending how much you dislike
1536 * the highlight cluttering your view. So it's a preference.
1537 */
1538 bool pencil_keep_highlight;
1528}; 1539};
1529 1540
1530static game_ui *new_ui(const game_state *state) 1541static game_ui *new_ui(const game_state *state)
@@ -1533,8 +1544,9 @@ static game_ui *new_ui(const game_state *state)
1533 1544
1534 ui->hx = ui->hy = 0; 1545 ui->hx = ui->hy = 0;
1535 ui->hpencil = false; 1546 ui->hpencil = false;
1536 ui->hshow = false; 1547 ui->hshow = ui->hcursor = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1537 ui->hcursor = false; 1548
1549 ui->pencil_keep_highlight = false;
1538 1550
1539 return ui; 1551 return ui;
1540} 1552}
@@ -1544,13 +1556,26 @@ static void free_ui(game_ui *ui)
1544 sfree(ui); 1556 sfree(ui);
1545} 1557}
1546 1558
1547static char *encode_ui(const game_ui *ui) 1559static config_item *get_prefs(game_ui *ui)
1548{ 1560{
1549 return NULL; 1561 config_item *ret;
1562
1563 ret = snewn(2, config_item);
1564
1565 ret[0].name = "Keep mouse highlight after changing a pencil mark";
1566 ret[0].kw = "pencil-keep-highlight";
1567 ret[0].type = C_BOOLEAN;
1568 ret[0].u.boolean.bval = ui->pencil_keep_highlight;
1569
1570 ret[1].name = NULL;
1571 ret[1].type = C_END;
1572
1573 return ret;
1550} 1574}
1551 1575
1552static void decode_ui(game_ui *ui, const char *encoding) 1576static void set_prefs(game_ui *ui, const config_item *cfg)
1553{ 1577{
1578 ui->pencil_keep_highlight = cfg[0].u.boolean.bval;
1554} 1579}
1555 1580
1556static void game_changed_state(game_ui *ui, const game_state *oldstate, 1581static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -1569,6 +1594,14 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1569 } 1594 }
1570} 1595}
1571 1596
1597static const char *current_key_label(const game_ui *ui,
1598 const game_state *state, int button)
1599{
1600 if (ui->hshow && (button == CURSOR_SELECT))
1601 return ui->hpencil ? "Ink" : "Pencil";
1602 return "";
1603}
1604
1572#define PREFERRED_TILESIZE 48 1605#define PREFERRED_TILESIZE 48
1573#define TILESIZE (ds->tilesize) 1606#define TILESIZE (ds->tilesize)
1574#define BORDER (TILESIZE / 2) 1607#define BORDER (TILESIZE / 2)
@@ -1613,7 +1646,7 @@ static bool check_errors(const game_state *state, long *errors)
1613 for (i = 0; i < a; i++) { 1646 for (i = 0; i < a; i++) {
1614 long clue; 1647 long clue;
1615 1648
1616 j = dsf_canonify(state->clues->dsf, i); 1649 j = dsf_minimal(state->clues->dsf, i);
1617 if (j == i) { 1650 if (j == i) {
1618 cluevals[i] = state->grid[i]; 1651 cluevals[i] = state->grid[i];
1619 } else { 1652 } else {
@@ -1647,7 +1680,7 @@ static bool check_errors(const game_state *state, long *errors)
1647 } 1680 }
1648 1681
1649 for (i = 0; i < a; i++) { 1682 for (i = 0; i < a; i++) {
1650 j = dsf_canonify(state->clues->dsf, i); 1683 j = dsf_minimal(state->clues->dsf, i);
1651 if (j == i) { 1684 if (j == i) {
1652 if ((state->clues->clues[j] & ~CMASK) != cluevals[i]) { 1685 if ((state->clues->clues[j] & ~CMASK) != cluevals[i]) {
1653 errs = true; 1686 errs = true;
@@ -1709,7 +1742,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1709 int tx, ty; 1742 int tx, ty;
1710 char buf[80]; 1743 char buf[80];
1711 1744
1712 button &= ~MOD_MASK; 1745 button = STRIP_BUTTON_MODIFIERS(button);
1713 1746
1714 tx = FROMCOORD(x); 1747 tx = FROMCOORD(x);
1715 ty = FROMCOORD(y); 1748 ty = FROMCOORD(y);
@@ -1726,7 +1759,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1726 ui->hpencil = false; 1759 ui->hpencil = false;
1727 } 1760 }
1728 ui->hcursor = false; 1761 ui->hcursor = false;
1729 return UI_UPDATE; 1762 return MOVE_UI_UPDATE;
1730 } 1763 }
1731 if (button == RIGHT_BUTTON) { 1764 if (button == RIGHT_BUTTON) {
1732 /* 1765 /*
@@ -1746,20 +1779,18 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1746 ui->hshow = false; 1779 ui->hshow = false;
1747 } 1780 }
1748 ui->hcursor = false; 1781 ui->hcursor = false;
1749 return UI_UPDATE; 1782 return MOVE_UI_UPDATE;
1750 } 1783 }
1751 } 1784 }
1752 if (IS_CURSOR_MOVE(button)) { 1785 if (IS_CURSOR_MOVE(button)) {
1753 move_cursor(button, &ui->hx, &ui->hy, w, w, false);
1754 ui->hshow = true;
1755 ui->hcursor = true; 1786 ui->hcursor = true;
1756 return UI_UPDATE; 1787 return move_cursor(button, &ui->hx, &ui->hy, w, w, false, &ui->hshow);
1757 } 1788 }
1758 if (ui->hshow && 1789 if (ui->hshow &&
1759 (button == CURSOR_SELECT)) { 1790 (button == CURSOR_SELECT)) {
1760 ui->hpencil ^= 1; 1791 ui->hpencil ^= 1;
1761 ui->hcursor = true; 1792 ui->hcursor = true;
1762 return UI_UPDATE; 1793 return MOVE_UI_UPDATE;
1763 } 1794 }
1764 1795
1765 if (ui->hshow && 1796 if (ui->hshow &&
@@ -1776,10 +1807,31 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1776 if (ui->hpencil && state->grid[ui->hy*w+ui->hx]) 1807 if (ui->hpencil && state->grid[ui->hy*w+ui->hx])
1777 return NULL; 1808 return NULL;
1778 1809
1810 /*
1811 * If you ask to fill a square with what it already contains,
1812 * or blank it when it's already empty, that has no effect...
1813 */
1814 if ((!ui->hpencil || n == 0) && state->grid[ui->hy*w+ui->hx] == n &&
1815 state->pencil[ui->hy*w+ui->hx] == 0) {
1816 /* ... expect to remove the cursor in mouse mode. */
1817 if (!ui->hcursor) {
1818 ui->hshow = false;
1819 return MOVE_UI_UPDATE;
1820 }
1821 return NULL;
1822 }
1823
1779 sprintf(buf, "%c%d,%d,%d", 1824 sprintf(buf, "%c%d,%d,%d",
1780 (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); 1825 (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n);
1781 1826
1782 if (!ui->hcursor) ui->hshow = false; 1827 /*
1828 * Hide the highlight after a keypress, if it was mouse-
1829 * generated. Also, don't hide it if this move has changed
1830 * pencil marks and the user preference says not to hide the
1831 * highlight in that situation.
1832 */
1833 if (!ui->hcursor && !(ui->hpencil && ui->pencil_keep_highlight))
1834 ui->hshow = false;
1783 1835
1784 return dupstr(buf); 1836 return dupstr(buf);
1785 } 1837 }
@@ -1854,7 +1906,7 @@ static game_state *execute_move(const game_state *from, const char *move)
1854#define SIZE(w) ((w) * TILESIZE + 2*BORDER) 1906#define SIZE(w) ((w) * TILESIZE + 2*BORDER)
1855 1907
1856static void game_compute_size(const game_params *params, int tilesize, 1908static void game_compute_size(const game_params *params, int tilesize,
1857 int *x, int *y) 1909 const game_ui *ui, int *x, int *y)
1858{ 1910{
1859 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 1911 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1860 struct { int tilesize; } ads, *ds = &ads; 1912 struct { int tilesize; } ads, *ds = &ads;
@@ -1939,6 +1991,7 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues,
1939 int tx, ty, tw, th; 1991 int tx, ty, tw, th;
1940 int cx, cy, cw, ch; 1992 int cx, cy, cw, ch;
1941 char str[64]; 1993 char str[64];
1994 bool draw_clue = dsf_minimal(clues->dsf, y*w+x) == y*w+x;
1942 1995
1943 tx = BORDER + x * TILESIZE + 1 + GRIDEXTRA; 1996 tx = BORDER + x * TILESIZE + 1 + GRIDEXTRA;
1944 ty = BORDER + y * TILESIZE + 1 + GRIDEXTRA; 1997 ty = BORDER + y * TILESIZE + 1 + GRIDEXTRA;
@@ -1948,13 +2001,13 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues,
1948 cw = tw = TILESIZE-1-2*GRIDEXTRA; 2001 cw = tw = TILESIZE-1-2*GRIDEXTRA;
1949 ch = th = TILESIZE-1-2*GRIDEXTRA; 2002 ch = th = TILESIZE-1-2*GRIDEXTRA;
1950 2003
1951 if (x > 0 && dsf_canonify(clues->dsf, y*w+x) == dsf_canonify(clues->dsf, y*w+x-1)) 2004 if (x > 0 && dsf_equivalent(clues->dsf, y*w+x, y*w+x-1))
1952 cx -= GRIDEXTRA, cw += GRIDEXTRA; 2005 cx -= GRIDEXTRA, cw += GRIDEXTRA;
1953 if (x+1 < w && dsf_canonify(clues->dsf, y*w+x) == dsf_canonify(clues->dsf, y*w+x+1)) 2006 if (x+1 < w && dsf_equivalent(clues->dsf, y*w+x, y*w+x+1))
1954 cw += GRIDEXTRA; 2007 cw += GRIDEXTRA;
1955 if (y > 0 && dsf_canonify(clues->dsf, y*w+x) == dsf_canonify(clues->dsf, (y-1)*w+x)) 2008 if (y > 0 && dsf_equivalent(clues->dsf, y*w+x, (y-1)*w+x))
1956 cy -= GRIDEXTRA, ch += GRIDEXTRA; 2009 cy -= GRIDEXTRA, ch += GRIDEXTRA;
1957 if (y+1 < w && dsf_canonify(clues->dsf, y*w+x) == dsf_canonify(clues->dsf, (y+1)*w+x)) 2010 if (y+1 < w && dsf_equivalent(clues->dsf, y*w+x, (y+1)*w+x))
1958 ch += GRIDEXTRA; 2011 ch += GRIDEXTRA;
1959 2012
1960 clip(dr, cx, cy, cw, ch); 2013 clip(dr, cx, cy, cw, ch);
@@ -1979,17 +2032,21 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues,
1979 * Draw the corners of thick lines in corner-adjacent squares, 2032 * Draw the corners of thick lines in corner-adjacent squares,
1980 * which jut into this square by one pixel. 2033 * which jut into this square by one pixel.
1981 */ 2034 */
1982 if (x > 0 && y > 0 && dsf_canonify(clues->dsf, y*w+x) != dsf_canonify(clues->dsf, (y-1)*w+x-1)) 2035 if (x > 0 && y > 0 && !dsf_equivalent(clues->dsf, y*w+x, (y-1)*w+x-1))
1983 draw_rect(dr, tx-GRIDEXTRA, ty-GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); 2036 draw_rect(dr, tx-GRIDEXTRA, ty-GRIDEXTRA,
1984 if (x+1 < w && y > 0 && dsf_canonify(clues->dsf, y*w+x) != dsf_canonify(clues->dsf, (y-1)*w+x+1)) 2037 GRIDEXTRA, GRIDEXTRA, COL_GRID);
1985 draw_rect(dr, tx+TILESIZE-1-2*GRIDEXTRA, ty-GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); 2038 if (x+1 < w && y > 0 && !dsf_equivalent(clues->dsf, y*w+x, (y-1)*w+x+1))
1986 if (x > 0 && y+1 < w && dsf_canonify(clues->dsf, y*w+x) != dsf_canonify(clues->dsf, (y+1)*w+x-1)) 2039 draw_rect(dr, tx+TILESIZE-1-2*GRIDEXTRA, ty-GRIDEXTRA,
1987 draw_rect(dr, tx-GRIDEXTRA, ty+TILESIZE-1-2*GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); 2040 GRIDEXTRA, GRIDEXTRA, COL_GRID);
1988 if (x+1 < w && y+1 < w && dsf_canonify(clues->dsf, y*w+x) != dsf_canonify(clues->dsf, (y+1)*w+x+1)) 2041 if (x > 0 && y+1 < w && !dsf_equivalent(clues->dsf, y*w+x, (y+1)*w+x-1))
1989 draw_rect(dr, tx+TILESIZE-1-2*GRIDEXTRA, ty+TILESIZE-1-2*GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); 2042 draw_rect(dr, tx-GRIDEXTRA, ty+TILESIZE-1-2*GRIDEXTRA,
2043 GRIDEXTRA, GRIDEXTRA, COL_GRID);
2044 if (x+1 < w && y+1 < w && !dsf_equivalent(clues->dsf, y*w+x, (y+1)*w+x+1))
2045 draw_rect(dr, tx+TILESIZE-1-2*GRIDEXTRA, ty+TILESIZE-1-2*GRIDEXTRA,
2046 GRIDEXTRA, GRIDEXTRA, COL_GRID);
1990 2047
1991 /* Draw the box clue. */ 2048 /* Draw the box clue. */
1992 if (dsf_canonify(clues->dsf, y*w+x) == y*w+x) { 2049 if (draw_clue) {
1993 long clue = clues->clues[y*w+x]; 2050 long clue = clues->clues[y*w+x];
1994 long cluetype = clue & CMASK, clueval = clue & ~CMASK; 2051 long cluetype = clue & CMASK, clueval = clue & ~CMASK;
1995 int size = dsf_size(clues->dsf, y*w+x); 2052 int size = dsf_size(clues->dsf, y*w+x);
@@ -2043,7 +2100,7 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues,
2043 pr = pl + TILESIZE - GRIDEXTRA; 2100 pr = pl + TILESIZE - GRIDEXTRA;
2044 pt = ty + GRIDEXTRA; 2101 pt = ty + GRIDEXTRA;
2045 pb = pt + TILESIZE - GRIDEXTRA; 2102 pb = pt + TILESIZE - GRIDEXTRA;
2046 if (dsf_canonify(clues->dsf, y*w+x) == y*w+x) { 2103 if (draw_clue) {
2047 /* 2104 /*
2048 * Make space for the clue text. 2105 * Make space for the clue text.
2049 */ 2106 */
@@ -2097,7 +2154,7 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues,
2097 * And move it down a bit if it's collided with some 2154 * And move it down a bit if it's collided with some
2098 * clue text. 2155 * clue text.
2099 */ 2156 */
2100 if (dsf_canonify(clues->dsf, y*w+x) == y*w+x) { 2157 if (draw_clue) {
2101 pt = max(pt, ty + GRIDEXTRA * 3 + TILESIZE/4); 2158 pt = max(pt, ty + GRIDEXTRA * 3 + TILESIZE/4);
2102 } 2159 }
2103 2160
@@ -2134,14 +2191,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2134 2191
2135 if (!ds->started) { 2192 if (!ds->started) {
2136 /* 2193 /*
2137 * The initial contents of the window are not guaranteed and
2138 * can vary with front ends. To be on the safe side, all
2139 * games should start by drawing a big background-colour
2140 * rectangle covering the whole window.
2141 */
2142 draw_rect(dr, 0, 0, SIZE(w), SIZE(w), COL_BACKGROUND);
2143
2144 /*
2145 * Big containing rectangle. 2194 * Big containing rectangle.
2146 */ 2195 */
2147 draw_rect(dr, COORD(0) - GRIDEXTRA, COORD(0) - GRIDEXTRA, 2196 draw_rect(dr, COORD(0) - GRIDEXTRA, COORD(0) - GRIDEXTRA,
@@ -2217,21 +2266,15 @@ static int game_status(const game_state *state)
2217 return state->completed ? +1 : 0; 2266 return state->completed ? +1 : 0;
2218} 2267}
2219 2268
2220static bool game_timing_state(const game_state *state, game_ui *ui) 2269static void game_print_size(const game_params *params, const game_ui *ui,
2221{ 2270 float *x, float *y)
2222 if (state->completed)
2223 return false;
2224 return true;
2225}
2226
2227static void game_print_size(const game_params *params, float *x, float *y)
2228{ 2271{
2229 int pw, ph; 2272 int pw, ph;
2230 2273
2231 /* 2274 /*
2232 * We use 9mm squares by default, like Solo. 2275 * We use 9mm squares by default, like Solo.
2233 */ 2276 */
2234 game_compute_size(params, 900, &pw, &ph); 2277 game_compute_size(params, 900, ui, &pw, &ph);
2235 *x = pw / 100.0F; 2278 *x = pw / 100.0F;
2236 *y = ph / 100.0F; 2279 *y = ph / 100.0F;
2237} 2280}
@@ -2245,7 +2288,7 @@ static void game_print_size(const game_params *params, float *x, float *y)
2245 * single polygon. 2288 * single polygon.
2246 */ 2289 */
2247static void outline_block_structure(drawing *dr, game_drawstate *ds, 2290static void outline_block_structure(drawing *dr, game_drawstate *ds,
2248 int w, int *dsf, int ink) 2291 int w, DSF *dsf, int ink)
2249{ 2292{
2250 int a = w*w; 2293 int a = w*w;
2251 int *coords; 2294 int *coords;
@@ -2258,7 +2301,7 @@ static void outline_block_structure(drawing *dr, game_drawstate *ds,
2258 * Iterate over all the blocks. 2301 * Iterate over all the blocks.
2259 */ 2302 */
2260 for (i = 0; i < a; i++) { 2303 for (i = 0; i < a; i++) {
2261 if (dsf_canonify(dsf, i) != i) 2304 if (dsf_minimal(dsf, i) != i)
2262 continue; 2305 continue;
2263 2306
2264 /* 2307 /*
@@ -2297,11 +2340,11 @@ static void outline_block_structure(drawing *dr, game_drawstate *ds,
2297 tx = x - dy + dx; 2340 tx = x - dy + dx;
2298 ty = y + dx + dy; 2341 ty = y + dx + dy;
2299 nin += (tx >= 0 && tx < w && ty >= 0 && ty < w && 2342 nin += (tx >= 0 && tx < w && ty >= 0 && ty < w &&
2300 dsf_canonify(dsf, ty*w+tx) == i); 2343 dsf_minimal(dsf, ty*w+tx) == i);
2301 tx = x - dy; 2344 tx = x - dy;
2302 ty = y + dx; 2345 ty = y + dx;
2303 nin += (tx >= 0 && tx < w && ty >= 0 && ty < w && 2346 nin += (tx >= 0 && tx < w && ty >= 0 && ty < w &&
2304 dsf_canonify(dsf, ty*w+tx) == i); 2347 dsf_minimal(dsf, ty*w+tx) == i);
2305 if (nin == 0) { 2348 if (nin == 0) {
2306 /* 2349 /*
2307 * Turn right. 2350 * Turn right.
@@ -2338,9 +2381,9 @@ static void outline_block_structure(drawing *dr, game_drawstate *ds,
2338 * somewhere sensible. 2381 * somewhere sensible.
2339 */ 2382 */
2340 assert(x >= 0 && x < w && y >= 0 && y < w && 2383 assert(x >= 0 && x < w && y >= 0 && y < w &&
2341 dsf_canonify(dsf, y*w+x) == i); 2384 dsf_minimal(dsf, y*w+x) == i);
2342 assert(x+dx < 0 || x+dx >= w || y+dy < 0 || y+dy >= w || 2385 assert(x+dx < 0 || x+dx >= w || y+dy < 0 || y+dy >= w ||
2343 dsf_canonify(dsf, (y+dy)*w+(x+dx)) != i); 2386 dsf_minimal(dsf, (y+dy)*w+(x+dx)) != i);
2344 2387
2345 /* 2388 /*
2346 * Record the point we just went past at one end of the 2389 * Record the point we just went past at one end of the
@@ -2367,7 +2410,8 @@ static void outline_block_structure(drawing *dr, game_drawstate *ds,
2367 sfree(coords); 2410 sfree(coords);
2368} 2411}
2369 2412
2370static void game_print(drawing *dr, const game_state *state, int tilesize) 2413static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2414 int tilesize)
2371{ 2415{
2372 int w = state->par.w; 2416 int w = state->par.w;
2373 int ink = print_mono_colour(dr, 0); 2417 int ink = print_mono_colour(dr, 0);
@@ -2413,7 +2457,7 @@ static void game_print(drawing *dr, const game_state *state, int tilesize)
2413 */ 2457 */
2414 for (y = 0; y < w; y++) 2458 for (y = 0; y < w; y++)
2415 for (x = 0; x < w; x++) 2459 for (x = 0; x < w; x++)
2416 if (dsf_canonify(state->clues->dsf, y*w+x) == y*w+x) { 2460 if (dsf_minimal(state->clues->dsf, y*w+x) == y*w+x) {
2417 long clue = state->clues->clues[y*w+x]; 2461 long clue = state->clues->clues[y*w+x];
2418 long cluetype = clue & CMASK, clueval = clue & ~CMASK; 2462 long cluetype = clue & CMASK, clueval = clue & ~CMASK;
2419 int size = dsf_size(state->clues->dsf, y*w+x); 2463 int size = dsf_size(state->clues->dsf, y*w+x);
@@ -2478,13 +2522,15 @@ const struct game thegame = {
2478 dup_game, 2522 dup_game,
2479 free_game, 2523 free_game,
2480 true, solve_game, 2524 true, solve_game,
2481 false, game_can_format_as_text_now, game_text_format, 2525 false, NULL, NULL, /* can_format_as_text_now, text_format */
2526 get_prefs, set_prefs,
2482 new_ui, 2527 new_ui,
2483 free_ui, 2528 free_ui,
2484 encode_ui, 2529 NULL, /* encode_ui */
2485 decode_ui, 2530 NULL, /* decode_ui */
2486 game_request_keys, 2531 game_request_keys,
2487 game_changed_state, 2532 game_changed_state,
2533 current_key_label,
2488 interpret_move, 2534 interpret_move,
2489 execute_move, 2535 execute_move,
2490 PREFERRED_TILESIZE, game_compute_size, game_set_size, 2536 PREFERRED_TILESIZE, game_compute_size, game_set_size,
@@ -2498,7 +2544,7 @@ const struct game thegame = {
2498 game_status, 2544 game_status,
2499 true, false, game_print_size, game_print, 2545 true, false, game_print_size, game_print,
2500 false, /* wants_statusbar */ 2546 false, /* wants_statusbar */
2501 false, game_timing_state, 2547 false, NULL, /* timing_state */
2502 REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */ 2548 REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */
2503}; 2549};
2504 2550
diff --git a/apps/plugins/puzzles/src/latin.c b/apps/plugins/puzzles/src/latin.c
index 39930166e7..a2d5713b30 100644
--- a/apps/plugins/puzzles/src/latin.c
+++ b/apps/plugins/puzzles/src/latin.c
@@ -563,7 +563,7 @@ void latin_solver_free_scratch(struct latin_solver_scratch *scratch)
563 sfree(scratch); 563 sfree(scratch);
564} 564}
565 565
566void latin_solver_alloc(struct latin_solver *solver, digit *grid, int o) 566bool latin_solver_alloc(struct latin_solver *solver, digit *grid, int o)
567{ 567{
568 int x, y; 568 int x, y;
569 569
@@ -577,14 +577,23 @@ void latin_solver_alloc(struct latin_solver *solver, digit *grid, int o)
577 memset(solver->row, 0, o*o); 577 memset(solver->row, 0, o*o);
578 memset(solver->col, 0, o*o); 578 memset(solver->col, 0, o*o);
579 579
580 for (x = 0; x < o; x++)
581 for (y = 0; y < o; y++)
582 if (grid[y*o+x])
583 latin_solver_place(solver, x, y, grid[y*o+x]);
584
585#ifdef STANDALONE_SOLVER 580#ifdef STANDALONE_SOLVER
586 solver->names = NULL; 581 solver->names = NULL;
587#endif 582#endif
583
584 for (x = 0; x < o; x++) {
585 for (y = 0; y < o; y++) {
586 int n = grid[y*o+x];
587 if (n) {
588 if (cube(x, y, n))
589 latin_solver_place(solver, x, y, n);
590 else
591 return false; /* puzzle is already inconsistent */
592 }
593 }
594 }
595
596 return true;
588} 597}
589 598
590void latin_solver_free(struct latin_solver *solver) 599void latin_solver_free(struct latin_solver *solver)
@@ -810,15 +819,17 @@ static int latin_solver_recurse
810 } else { 819 } else {
811 newctx = ctx; 820 newctx = ctx;
812 } 821 }
813 latin_solver_alloc(&subsolver, outgrid, o);
814#ifdef STANDALONE_SOLVER 822#ifdef STANDALONE_SOLVER
815 subsolver.names = solver->names; 823 subsolver.names = solver->names;
816#endif 824#endif
817 ret = latin_solver_top(&subsolver, diff_recursive, 825 if (latin_solver_alloc(&subsolver, outgrid, o))
818 diff_simple, diff_set_0, diff_set_1, 826 ret = latin_solver_top(&subsolver, diff_recursive,
819 diff_forcing, diff_recursive, 827 diff_simple, diff_set_0, diff_set_1,
820 usersolvers, valid, newctx, 828 diff_forcing, diff_recursive,
821 ctxnew, ctxfree); 829 usersolvers, valid, newctx,
830 ctxnew, ctxfree);
831 else
832 ret = diff_impossible;
822 latin_solver_free(&subsolver); 833 latin_solver_free(&subsolver);
823 if (ctxnew) 834 if (ctxnew)
824 ctxfree(newctx); 835 ctxfree(newctx);
@@ -1059,11 +1070,13 @@ int latin_solver(digit *grid, int o, int maxdiff,
1059 struct latin_solver solver; 1070 struct latin_solver solver;
1060 int diff; 1071 int diff;
1061 1072
1062 latin_solver_alloc(&solver, grid, o); 1073 if (latin_solver_alloc(&solver, grid, o))
1063 diff = latin_solver_main(&solver, maxdiff, 1074 diff = latin_solver_main(&solver, maxdiff,
1064 diff_simple, diff_set_0, diff_set_1, 1075 diff_simple, diff_set_0, diff_set_1,
1065 diff_forcing, diff_recursive, 1076 diff_forcing, diff_recursive,
1066 usersolvers, valid, ctx, ctxnew, ctxfree); 1077 usersolvers, valid, ctx, ctxnew, ctxfree);
1078 else
1079 diff = diff_impossible;
1067 latin_solver_free(&solver); 1080 latin_solver_free(&solver);
1068 return diff; 1081 return diff;
1069} 1082}
@@ -1298,121 +1311,4 @@ bool latin_check(digit *sq, int order)
1298 return ret; 1311 return ret;
1299} 1312}
1300 1313
1301
1302/* --------------------------------------------------------
1303 * Testing (and printing).
1304 */
1305
1306#ifdef STANDALONE_LATIN_TEST
1307
1308#include <stdio.h>
1309#include <time.h>
1310
1311const char *quis;
1312
1313static void latin_print(digit *sq, int order)
1314{
1315 int x, y;
1316
1317 for (y = 0; y < order; y++) {
1318 for (x = 0; x < order; x++) {
1319 printf("%2u ", ELT(sq, x, y));
1320 }
1321 printf("\n");
1322 }
1323 printf("\n");
1324}
1325
1326static void gen(int order, random_state *rs, int debug)
1327{
1328 digit *sq;
1329
1330 solver_show_working = debug;
1331
1332 sq = latin_generate(order, rs);
1333 latin_print(sq, order);
1334 if (latin_check(sq, order)) {
1335 fprintf(stderr, "Square is not a latin square!");
1336 exit(1);
1337 }
1338
1339 sfree(sq);
1340}
1341
1342void test_soak(int order, random_state *rs)
1343{
1344 digit *sq;
1345 int n = 0;
1346 time_t tt_start, tt_now, tt_last;
1347
1348 solver_show_working = 0;
1349 tt_now = tt_start = time(NULL);
1350
1351 while(1) {
1352 sq = latin_generate(order, rs);
1353 sfree(sq);
1354 n++;
1355
1356 tt_last = time(NULL);
1357 if (tt_last > tt_now) {
1358 tt_now = tt_last;
1359 printf("%d total, %3.1f/s\n", n,
1360 (double)n / (double)(tt_now - tt_start));
1361 }
1362 }
1363}
1364
1365void usage_exit(const char *msg)
1366{
1367 if (msg)
1368 fprintf(stderr, "%s: %s\n", quis, msg);
1369 fprintf(stderr, "Usage: %s [--seed SEED] --soak <params> | [game_id [game_id ...]]\n", quis);
1370 exit(1);
1371}
1372
1373int main(int argc, char *argv[])
1374{
1375 int i, soak = 0;
1376 random_state *rs;
1377 time_t seed = time(NULL);
1378
1379 quis = argv[0];
1380 while (--argc > 0) {
1381 const char *p = *++argv;
1382 if (!strcmp(p, "--soak"))
1383 soak = 1;
1384 else if (!strcmp(p, "--seed")) {
1385 if (argc == 0)
1386 usage_exit("--seed needs an argument");
1387 seed = (time_t)atoi(*++argv);
1388 argc--;
1389 } else if (*p == '-')
1390 usage_exit("unrecognised option");
1391 else
1392 break; /* finished options */
1393 }
1394
1395 rs = random_new((void*)&seed, sizeof(time_t));
1396
1397 if (soak == 1) {
1398 if (argc != 1) usage_exit("only one argument for --soak");
1399 test_soak(atoi(*argv), rs);
1400 } else {
1401 if (argc > 0) {
1402 for (i = 0; i < argc; i++) {
1403 gen(atoi(*argv++), rs, 1);
1404 }
1405 } else {
1406 while (1) {
1407 i = random_upto(rs, 20) + 1;
1408 gen(i, rs, 0);
1409 }
1410 }
1411 }
1412 random_free(rs);
1413 return 0;
1414}
1415
1416#endif
1417
1418/* vim: set shiftwidth=4 tabstop=8: */ 1314/* vim: set shiftwidth=4 tabstop=8: */
diff --git a/apps/plugins/puzzles/src/latin.h b/apps/plugins/puzzles/src/latin.h
index bb172ec3c7..96a0480491 100644
--- a/apps/plugins/puzzles/src/latin.h
+++ b/apps/plugins/puzzles/src/latin.h
@@ -61,10 +61,13 @@ int latin_solver_forcing(struct latin_solver *solver,
61/* --- Solver allocation --- */ 61/* --- Solver allocation --- */
62 62
63/* Fills in (and allocates members for) a latin_solver struct. 63/* Fills in (and allocates members for) a latin_solver struct.
64 * Will allocate members of snew, but not snew itself 64 * Will allocate members of solver, but not solver itself
65 * (allowing 'struct latin_solver' to be the first element in a larger 65 * (allowing 'struct latin_solver' to be the first element in a larger
66 * struct, for example). */ 66 * struct, for example).
67void latin_solver_alloc(struct latin_solver *solver, digit *grid, int o); 67 *
68 * latin_solver_alloc returns false if the digits already in the grid
69 * could not be legally placed. */
70bool latin_solver_alloc(struct latin_solver *solver, digit *grid, int o);
68void latin_solver_free(struct latin_solver *solver); 71void latin_solver_free(struct latin_solver *solver);
69 72
70/* Allocates scratch space (for _set and _forcing) */ 73/* Allocates scratch space (for _set and _forcing) */
diff --git a/apps/plugins/puzzles/src/lightup.R b/apps/plugins/puzzles/src/lightup.R
deleted file mode 100644
index a474de815d..0000000000
--- a/apps/plugins/puzzles/src/lightup.R
+++ /dev/null
@@ -1,24 +0,0 @@
1# -*- makefile -*-
2
3LIGHTUP_EXTRA = combi
4
5lightup : [X] GTK COMMON lightup LIGHTUP_EXTRA lightup-icon|no-icon
6
7lightup : [G] WINDOWS COMMON lightup LIGHTUP_EXTRA lightup.res|noicon.res
8
9lightupsolver : [U] lightup[STANDALONE_SOLVER] LIGHTUP_EXTRA STANDALONE
10lightupsolver : [C] lightup[STANDALONE_SOLVER] LIGHTUP_EXTRA STANDALONE
11
12ALL += lightup[COMBINED] LIGHTUP_EXTRA
13
14!begin am gtk
15GAMES += lightup
16!end
17
18!begin >list.c
19 A(lightup) \
20!end
21
22!begin >gamedesc.txt
23lightup:lightup.exe:Light Up:Light-bulb placing puzzle:Place bulbs to light up all the squares.
24!end
diff --git a/apps/plugins/puzzles/src/lightup.c b/apps/plugins/puzzles/src/lightup.c
index ab4be9ec87..e779663e01 100644
--- a/apps/plugins/puzzles/src/lightup.c
+++ b/apps/plugins/puzzles/src/lightup.c
@@ -47,7 +47,12 @@
47#include <string.h> 47#include <string.h>
48#include <assert.h> 48#include <assert.h>
49#include <ctype.h> 49#include <ctype.h>
50#include <math.h> 50#include <limits.h>
51#ifdef NO_TGMATH_H
52# include <math.h>
53#else
54# include <tgmath.h>
55#endif
51 56
52#include "puzzles.h" 57#include "puzzles.h"
53 58
@@ -58,7 +63,7 @@
58 */ 63 */
59#if defined STANDALONE_SOLVER 64#if defined STANDALONE_SOLVER
60#define SOLVER_DIAGNOSTICS 65#define SOLVER_DIAGNOSTICS
61int verbose = 0; 66static int verbose = 0;
62#undef debug 67#undef debug
63#define debug(x) printf x 68#define debug(x) printf x
64#elif defined SOLVER_DIAGNOSTICS 69#elif defined SOLVER_DIAGNOSTICS
@@ -346,6 +351,8 @@ static const char *validate_params(const game_params *params, bool full)
346{ 351{
347 if (params->w < 2 || params->h < 2) 352 if (params->w < 2 || params->h < 2)
348 return "Width and height must be at least 2"; 353 return "Width and height must be at least 2";
354 if (params->w > INT_MAX / params->h)
355 return "Width times height must not be unreasonably large";
349 if (full) { 356 if (full) {
350 if (params->blackpc < 5 || params->blackpc > 100) 357 if (params->blackpc < 5 || params->blackpc > 100)
351 return "Percentage of black squares must be between 5% and 100%"; 358 return "Percentage of black squares must be between 5% and 100%";
@@ -353,6 +360,8 @@ static const char *validate_params(const game_params *params, bool full)
353 if (params->symm == SYMM_ROT4) 360 if (params->symm == SYMM_ROT4)
354 return "4-fold symmetry is only available with square grids"; 361 return "4-fold symmetry is only available with square grids";
355 } 362 }
363 if ((params->symm == SYMM_ROT4 || params->symm == SYMM_REF4) && params->w < 3 && params->h < 3)
364 return "Width or height must be at least 3 for 4-way symmetry";
356 if (params->symm < 0 || params->symm >= SYMM_MAX) 365 if (params->symm < 0 || params->symm >= SYMM_MAX)
357 return "Unknown symmetry type"; 366 return "Unknown symmetry type";
358 if (params->difficulty < 0 || params->difficulty > DIFFCOUNT) 367 if (params->difficulty < 0 || params->difficulty > DIFFCOUNT)
@@ -411,6 +420,8 @@ static void debug_state(game_state *state)
411 int x, y; 420 int x, y;
412 char c = '?'; 421 char c = '?';
413 422
423 (void)c; /* placate -Wunused-but-set-variable if debug() does nothing */
424
414 for (y = 0; y < state->h; y++) { 425 for (y = 0; y < state->h; y++) {
415 for (x = 0; x < state->w; x++) { 426 for (x = 0; x < state->w; x++) {
416 c = '.'; 427 c = '.';
@@ -1822,30 +1833,65 @@ static char *game_text_format(const game_state *state)
1822struct game_ui { 1833struct game_ui {
1823 int cur_x, cur_y; 1834 int cur_x, cur_y;
1824 bool cur_visible; 1835 bool cur_visible;
1836
1837 /*
1838 * User preference: when a square contains both a black blob for
1839 * 'user is convinced this isn't a light' and a yellow highlight
1840 * for 'this square is lit by a light', both of which rule out it
1841 * being a light, should we still bother to show the blob?
1842 */
1843 bool draw_blobs_when_lit;
1825}; 1844};
1826 1845
1846static void legacy_prefs_override(struct game_ui *ui_out)
1847{
1848 static bool initialised = false;
1849 static int draw_blobs_when_lit = -1;
1850
1851 if (!initialised) {
1852 initialised = true;
1853 draw_blobs_when_lit = getenv_bool("LIGHTUP_LIT_BLOBS", -1);
1854 }
1855
1856 if (draw_blobs_when_lit != -1)
1857 ui_out->draw_blobs_when_lit = draw_blobs_when_lit;
1858}
1859
1827static game_ui *new_ui(const game_state *state) 1860static game_ui *new_ui(const game_state *state)
1828{ 1861{
1829 game_ui *ui = snew(game_ui); 1862 game_ui *ui = snew(game_ui);
1830 ui->cur_x = ui->cur_y = 0; 1863 ui->cur_x = ui->cur_y = 0;
1831 ui->cur_visible = false; 1864 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1865 ui->draw_blobs_when_lit = true;
1866 legacy_prefs_override(ui);
1832 return ui; 1867 return ui;
1833} 1868}
1834 1869
1835static void free_ui(game_ui *ui) 1870static config_item *get_prefs(game_ui *ui)
1836{ 1871{
1837 sfree(ui); 1872 config_item *ret;
1873
1874 ret = snewn(2, config_item);
1875
1876 ret[0].name = "Draw non-light marks even when lit";
1877 ret[0].kw = "show-lit-blobs";
1878 ret[0].type = C_BOOLEAN;
1879 ret[0].u.boolean.bval = ui->draw_blobs_when_lit;
1880
1881 ret[1].name = NULL;
1882 ret[1].type = C_END;
1883
1884 return ret;
1838} 1885}
1839 1886
1840static char *encode_ui(const game_ui *ui) 1887static void set_prefs(game_ui *ui, const config_item *cfg)
1841{ 1888{
1842 /* nothing to encode. */ 1889 ui->draw_blobs_when_lit = cfg[0].u.boolean.bval;
1843 return NULL;
1844} 1890}
1845 1891
1846static void decode_ui(game_ui *ui, const char *encoding) 1892static void free_ui(game_ui *ui)
1847{ 1893{
1848 /* nothing to decode. */ 1894 sfree(ui);
1849} 1895}
1850 1896
1851static void game_changed_state(game_ui *ui, const game_state *oldstate, 1897static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -1855,6 +1901,26 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1855 ui->cur_visible = false; 1901 ui->cur_visible = false;
1856} 1902}
1857 1903
1904static const char *current_key_label(const game_ui *ui,
1905 const game_state *state, int button)
1906{
1907 int cx = ui->cur_x, cy = ui->cur_y;
1908 unsigned int flags = GRID(state, flags, cx, cy);
1909
1910 if (!ui->cur_visible) return "";
1911 if (button == CURSOR_SELECT) {
1912 if (flags & (F_BLACK | F_IMPOSSIBLE)) return "";
1913 if (flags & F_LIGHT) return "Clear";
1914 return "Light";
1915 }
1916 if (button == CURSOR_SELECT2) {
1917 if (flags & (F_BLACK | F_LIGHT)) return "";
1918 if (flags & F_IMPOSSIBLE) return "Clear";
1919 return "Mark";
1920 }
1921 return "";
1922}
1923
1858#define DF_BLACK 1 /* black square */ 1924#define DF_BLACK 1 /* black square */
1859#define DF_NUMBERED 2 /* black square with number */ 1925#define DF_NUMBERED 2 /* black square with number */
1860#define DF_LIT 4 /* display (white) square lit up */ 1926#define DF_LIT 4 /* display (white) square lit up */
@@ -1888,7 +1954,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1888 enum { NONE, FLIP_LIGHT, FLIP_IMPOSSIBLE } action = NONE; 1954 enum { NONE, FLIP_LIGHT, FLIP_IMPOSSIBLE } action = NONE;
1889 int cx = -1, cy = -1; 1955 int cx = -1, cy = -1;
1890 unsigned int flags; 1956 unsigned int flags;
1891 char buf[80], *nullret = UI_UPDATE, *empty = UI_UPDATE, c; 1957 char buf[80], *nullret = MOVE_NO_EFFECT, *empty = MOVE_UI_UPDATE, c;
1892 1958
1893 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { 1959 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
1894 if (ui->cur_visible) 1960 if (ui->cur_visible)
@@ -1898,8 +1964,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1898 cy = FROMCOORD(y); 1964 cy = FROMCOORD(y);
1899 action = (button == LEFT_BUTTON) ? FLIP_LIGHT : FLIP_IMPOSSIBLE; 1965 action = (button == LEFT_BUTTON) ? FLIP_LIGHT : FLIP_IMPOSSIBLE;
1900 } else if (IS_CURSOR_SELECT(button) || 1966 } else if (IS_CURSOR_SELECT(button) ||
1901 button == 'i' || button == 'I' || 1967 button == 'i' || button == 'I') {
1902 button == ' ' || button == '\r' || button == '\n') {
1903 if (ui->cur_visible) { 1968 if (ui->cur_visible) {
1904 /* Only allow cursor-effect operations if the cursor is visible 1969 /* Only allow cursor-effect operations if the cursor is visible
1905 * (otherwise you have no idea which square it might be affecting) */ 1970 * (otherwise you have no idea which square it might be affecting) */
@@ -1910,11 +1975,10 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1910 } 1975 }
1911 ui->cur_visible = true; 1976 ui->cur_visible = true;
1912 } else if (IS_CURSOR_MOVE(button)) { 1977 } else if (IS_CURSOR_MOVE(button)) {
1913 move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h, false); 1978 nullret = move_cursor(button, &ui->cur_x, &ui->cur_y,
1914 ui->cur_visible = true; 1979 state->w, state->h, false, &ui->cur_visible);
1915 nullret = empty;
1916 } else 1980 } else
1917 return NULL; 1981 return MOVE_UNUSED;
1918 1982
1919 switch (action) { 1983 switch (action) {
1920 case FLIP_LIGHT: 1984 case FLIP_LIGHT:
@@ -2002,7 +2066,7 @@ badmove:
2002 2066
2003/* XXX entirely cloned from fifteen.c; separate out? */ 2067/* XXX entirely cloned from fifteen.c; separate out? */
2004static void game_compute_size(const game_params *params, int tilesize, 2068static void game_compute_size(const game_params *params, int tilesize,
2005 int *x, int *y) 2069 const game_ui *ui, int *x, int *y)
2006{ 2070{
2007 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2071 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2008 struct { int tilesize; } ads, *ds = &ads; 2072 struct { int tilesize; } ads, *ds = &ads;
@@ -2111,7 +2175,7 @@ static unsigned int tile_flags(game_drawstate *ds, const game_state *state,
2111 return ret; 2175 return ret;
2112} 2176}
2113 2177
2114static void tile_redraw(drawing *dr, game_drawstate *ds, 2178static void tile_redraw(drawing *dr, game_drawstate *ds, const game_ui *ui,
2115 const game_state *state, int x, int y) 2179 const game_state *state, int x, int y)
2116{ 2180{
2117 unsigned int ds_flags = GRID(ds, flags, x, y); 2181 unsigned int ds_flags = GRID(ds, flags, x, y);
@@ -2141,13 +2205,7 @@ static void tile_redraw(drawing *dr, game_drawstate *ds,
2141 draw_circle(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2, TILE_RADIUS, 2205 draw_circle(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2, TILE_RADIUS,
2142 lcol, COL_BLACK); 2206 lcol, COL_BLACK);
2143 } else if ((ds_flags & DF_IMPOSSIBLE)) { 2207 } else if ((ds_flags & DF_IMPOSSIBLE)) {
2144 static int draw_blobs_when_lit = -1; 2208 if (!(ds_flags & DF_LIT) || ui->draw_blobs_when_lit) {
2145 if (draw_blobs_when_lit < 0) {
2146 char *env = getenv("LIGHTUP_LIT_BLOBS");
2147 draw_blobs_when_lit = (!env || (env[0] == 'y' ||
2148 env[0] == 'Y'));
2149 }
2150 if (!(ds_flags & DF_LIT) || draw_blobs_when_lit) {
2151 int rlen = TILE_SIZE / 4; 2209 int rlen = TILE_SIZE / 4;
2152 draw_rect(dr, dx + TILE_SIZE/2 - rlen/2, 2210 draw_rect(dr, dx + TILE_SIZE/2 - rlen/2,
2153 dy + TILE_SIZE/2 - rlen/2, 2211 dy + TILE_SIZE/2 - rlen/2,
@@ -2176,10 +2234,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2176 if (flashtime) flashing = (int)(flashtime * 3 / FLASH_TIME) != 1; 2234 if (flashtime) flashing = (int)(flashtime * 3 / FLASH_TIME) != 1;
2177 2235
2178 if (!ds->started) { 2236 if (!ds->started) {
2179 draw_rect(dr, 0, 0,
2180 TILE_SIZE * ds->w + 2 * BORDER,
2181 TILE_SIZE * ds->h + 2 * BORDER, COL_BACKGROUND);
2182
2183 draw_rect_outline(dr, COORD(0)-1, COORD(0)-1, 2237 draw_rect_outline(dr, COORD(0)-1, COORD(0)-1,
2184 TILE_SIZE * ds->w + 2, 2238 TILE_SIZE * ds->w + 2,
2185 TILE_SIZE * ds->h + 2, 2239 TILE_SIZE * ds->h + 2,
@@ -2196,7 +2250,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2196 unsigned int ds_flags = tile_flags(ds, state, ui, x, y, flashing); 2250 unsigned int ds_flags = tile_flags(ds, state, ui, x, y, flashing);
2197 if (ds_flags != GRID(ds, flags, x, y)) { 2251 if (ds_flags != GRID(ds, flags, x, y)) {
2198 GRID(ds, flags, x, y) = ds_flags; 2252 GRID(ds, flags, x, y) = ds_flags;
2199 tile_redraw(dr, ds, state, x, y); 2253 tile_redraw(dr, ds, ui, state, x, y);
2200 } 2254 }
2201 } 2255 }
2202 } 2256 }
@@ -2235,24 +2289,21 @@ static int game_status(const game_state *state)
2235 return state->completed ? +1 : 0; 2289 return state->completed ? +1 : 0;
2236} 2290}
2237 2291
2238static bool game_timing_state(const game_state *state, game_ui *ui) 2292static void game_print_size(const game_params *params, const game_ui *ui,
2239{ 2293 float *x, float *y)
2240 return true;
2241}
2242
2243static void game_print_size(const game_params *params, float *x, float *y)
2244{ 2294{
2245 int pw, ph; 2295 int pw, ph;
2246 2296
2247 /* 2297 /*
2248 * I'll use 6mm squares by default. 2298 * I'll use 6mm squares by default.
2249 */ 2299 */
2250 game_compute_size(params, 600, &pw, &ph); 2300 game_compute_size(params, 600, ui, &pw, &ph);
2251 *x = pw / 100.0F; 2301 *x = pw / 100.0F;
2252 *y = ph / 100.0F; 2302 *y = ph / 100.0F;
2253} 2303}
2254 2304
2255static void game_print(drawing *dr, const game_state *state, int tilesize) 2305static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2306 int tilesize)
2256{ 2307{
2257 int w = state->w, h = state->h; 2308 int w = state->w, h = state->h;
2258 int ink = print_mono_colour(dr, 0); 2309 int ink = print_mono_colour(dr, 0);
@@ -2323,12 +2374,14 @@ const struct game thegame = {
2323 free_game, 2374 free_game,
2324 true, solve_game, 2375 true, solve_game,
2325 true, game_can_format_as_text_now, game_text_format, 2376 true, game_can_format_as_text_now, game_text_format,
2377 get_prefs, set_prefs,
2326 new_ui, 2378 new_ui,
2327 free_ui, 2379 free_ui,
2328 encode_ui, 2380 NULL, /* encode_ui */
2329 decode_ui, 2381 NULL, /* decode_ui */
2330 NULL, /* game_request_keys */ 2382 NULL, /* game_request_keys */
2331 game_changed_state, 2383 game_changed_state,
2384 current_key_label,
2332 interpret_move, 2385 interpret_move,
2333 execute_move, 2386 execute_move,
2334 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 2387 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -2342,7 +2395,7 @@ const struct game thegame = {
2342 game_status, 2395 game_status,
2343 true, false, game_print_size, game_print, 2396 true, false, game_print_size, game_print,
2344 false, /* wants_statusbar */ 2397 false, /* wants_statusbar */
2345 false, game_timing_state, 2398 false, NULL, /* timing_state */
2346 0, /* flags */ 2399 0, /* flags */
2347}; 2400};
2348 2401
diff --git a/apps/plugins/puzzles/src/list.c b/apps/plugins/puzzles/src/list.c
new file mode 100644
index 0000000000..28cefca017
--- /dev/null
+++ b/apps/plugins/puzzles/src/list.c
@@ -0,0 +1,17 @@
1/*
2 * list.c: List of pointers to puzzle structures, for monolithic
3 * platforms.
4 *
5 * This file depends on the header "generated-games.h", which is
6 * constructed by CMakeLists.txt.
7 */
8
9#include "puzzles.h"
10
11#define GAME(x) &x,
12const game *gamelist[] = {
13#include "generated-games.h"
14};
15#undef GAME
16
17const int gamecount = lenof(gamelist);
diff --git a/apps/plugins/puzzles/src/loopgen.c b/apps/plugins/puzzles/src/loopgen.c
index e738d4a26d..05097fe304 100644
--- a/apps/plugins/puzzles/src/loopgen.c
+++ b/apps/plugins/puzzles/src/loopgen.c
@@ -8,7 +8,11 @@
8#include <string.h> 8#include <string.h>
9#include <assert.h> 9#include <assert.h>
10#include <ctype.h> 10#include <ctype.h>
11#include <math.h> 11#ifdef NO_TGMATH_H
12# include <math.h>
13#else
14# include <tgmath.h>
15#endif
12 16
13#include "puzzles.h" 17#include "puzzles.h"
14#include "tree234.h" 18#include "tree234.h"
@@ -79,7 +83,7 @@ static bool can_colour_face(grid *g, char* board, int face_index,
79 enum face_colour colour) 83 enum face_colour colour)
80{ 84{
81 int i, j; 85 int i, j;
82 grid_face *test_face = g->faces + face_index; 86 grid_face *test_face = g->faces[face_index];
83 grid_face *starting_face, *current_face; 87 grid_face *starting_face, *current_face;
84 grid_dot *starting_dot; 88 grid_dot *starting_dot;
85 int transitions; 89 int transitions;
@@ -344,7 +348,7 @@ void generate_loop(grid *g, char *board, random_state *rs,
344 * to check every face of the board (the grid structure does not keep a 348 * to check every face of the board (the grid structure does not keep a
345 * list of the infinite face's neighbours). */ 349 * list of the infinite face's neighbours). */
346 for (i = 0; i < num_faces; i++) { 350 for (i = 0; i < num_faces; i++) {
347 grid_face *f = g->faces + i; 351 grid_face *f = g->faces[i];
348 struct face_score *fs = face_scores + i; 352 struct face_score *fs = face_scores + i;
349 if (board[i] != FACE_GREY) continue; 353 if (board[i] != FACE_GREY) continue;
350 /* We need the full colourability check here, it's not enough simply 354 /* We need the full colourability check here, it's not enough simply
@@ -426,7 +430,7 @@ void generate_loop(grid *g, char *board, random_state *rs,
426 del234(darkable_faces_sorted, fs); 430 del234(darkable_faces_sorted, fs);
427 431
428 /* Remember which face we've just coloured */ 432 /* Remember which face we've just coloured */
429 cur_face = g->faces + i; 433 cur_face = g->faces[i];
430 434
431 /* The face we've just coloured potentially affects the colourability 435 /* The face we've just coloured potentially affects the colourability
432 * and the scores of any neighbouring faces (touching at a corner or 436 * and the scores of any neighbouring faces (touching at a corner or
@@ -452,7 +456,7 @@ void generate_loop(grid *g, char *board, random_state *rs,
452 if (FACE_COLOUR(f) != FACE_GREY) continue; 456 if (FACE_COLOUR(f) != FACE_GREY) continue;
453 457
454 /* Find the face index and face_score* corresponding to f */ 458 /* Find the face index and face_score* corresponding to f */
455 fi = f - g->faces; 459 fi = f->index;
456 fs = face_scores + fi; 460 fs = face_scores + fi;
457 461
458 /* Remove from lightable list if it's in there. We do this, 462 /* Remove from lightable list if it's in there. We do this,
@@ -513,7 +517,7 @@ void generate_loop(grid *g, char *board, random_state *rs,
513 enum face_colour opp = 517 enum face_colour opp =
514 (board[j] == FACE_WHITE) ? FACE_BLACK : FACE_WHITE; 518 (board[j] == FACE_WHITE) ? FACE_BLACK : FACE_WHITE;
515 if (can_colour_face(g, board, j, opp)) { 519 if (can_colour_face(g, board, j, opp)) {
516 grid_face *face = g->faces +j; 520 grid_face *face = g->faces[j];
517 if (do_random_pass) { 521 if (do_random_pass) {
518 /* final random pass */ 522 /* final random pass */
519 if (!random_upto(rs, 10)) 523 if (!random_upto(rs, 10))
diff --git a/apps/plugins/puzzles/src/loopgen.h b/apps/plugins/puzzles/src/loopgen.h
index 079c87c576..bab95814d2 100644
--- a/apps/plugins/puzzles/src/loopgen.h
+++ b/apps/plugins/puzzles/src/loopgen.h
@@ -2,8 +2,8 @@
2 * loopgen.h: interface file for loop generation functions for grid.[ch]. 2 * loopgen.h: interface file for loop generation functions for grid.[ch].
3 */ 3 */
4 4
5#ifndef _LOOPGEN_H 5#ifndef PUZZLES_LOOPGEN_H
6#define _LOOPGEN_H 6#define PUZZLES_LOOPGEN_H
7 7
8#include "puzzles.h" 8#include "puzzles.h"
9#include "grid.h" 9#include "grid.h"
@@ -13,7 +13,7 @@ enum face_colour { FACE_WHITE, FACE_GREY, FACE_BLACK };
13/* face should be of type grid_face* here. */ 13/* face should be of type grid_face* here. */
14#define FACE_COLOUR(face) \ 14#define FACE_COLOUR(face) \
15 ( (face) == NULL ? FACE_BLACK : \ 15 ( (face) == NULL ? FACE_BLACK : \
16 board[(face) - g->faces] ) 16 board[(face)->index] )
17 17
18typedef int (*loopgen_bias_fn_t)(void *ctx, char *board, int face); 18typedef int (*loopgen_bias_fn_t)(void *ctx, char *board, int face);
19 19
diff --git a/apps/plugins/puzzles/src/loopy.R b/apps/plugins/puzzles/src/loopy.R
deleted file mode 100644
index f44560095d..0000000000
--- a/apps/plugins/puzzles/src/loopy.R
+++ /dev/null
@@ -1,31 +0,0 @@
1# -*- makefile -*-
2
3LOOPY_EXTRA = tree234 dsf grid penrose loopgen
4
5loopy : [X] GTK COMMON loopy LOOPY_EXTRA loopy-icon|no-icon
6
7loopy : [G] WINDOWS COMMON loopy LOOPY_EXTRA loopy.res|noicon.res
8
9loopysolver : [U] loopy[STANDALONE_SOLVER] LOOPY_EXTRA STANDALONE m.lib
10loopysolver : [C] loopy[STANDALONE_SOLVER] LOOPY_EXTRA STANDALONE
11
12#penrose : [U] penrose[TEST_PENROSE] STANDALONE m.lib
13#penrose : [C] penrose[TEST_PENROSE] STANDALONE
14
15#test-basis : [U] penrose[TEST_VECTORS] tree234 STANDALONE m.lib
16#test-basis : [C] penrose[TEST_VECTORS] tree234 STANDALONE
17
18
19ALL += loopy[COMBINED] LOOPY_EXTRA
20
21!begin am gtk
22GAMES += loopy
23!end
24
25!begin >list.c
26 A(loopy) \
27!end
28
29!begin >gamedesc.txt
30loopy:loopy.exe:Loopy:Loop-drawing puzzle:Draw a single closed loop, given clues about number of adjacent edges.
31!end
diff --git a/apps/plugins/puzzles/src/loopy.c b/apps/plugins/puzzles/src/loopy.c
index 176b56285c..b30dd68f4d 100644
--- a/apps/plugins/puzzles/src/loopy.c
+++ b/apps/plugins/puzzles/src/loopy.c
@@ -25,28 +25,28 @@
25 * outside respectively. So if you can track this for all 25 * outside respectively. So if you can track this for all
26 * faces, you figure out the state of the line between a pair 26 * faces, you figure out the state of the line between a pair
27 * once their relative insideness is known. 27 * once their relative insideness is known.
28 * + The way I envisage this working is simply to keep an edsf 28 * + The way I envisage this working is simply to keep a flip dsf
29 * of all _faces_, which indicates whether they're on 29 * of all _faces_, which indicates whether they're on
30 * opposite sides of the loop from one another. We also 30 * opposite sides of the loop from one another. We also
31 * include a special entry in the edsf for the infinite 31 * include a special entry in the dsf for the infinite
32 * exterior "face". 32 * exterior "face".
33 * + So, the simple way to do this is to just go through the 33 * + So, the simple way to do this is to just go through the
34 * edges: every time we see an edge in a state other than 34 * edges: every time we see an edge in a state other than
35 * LINE_UNKNOWN which separates two faces that aren't in the 35 * LINE_UNKNOWN which separates two faces that aren't in the
36 * same edsf class, we can rectify that by merging the 36 * same dsf class, we can rectify that by merging the
37 * classes. Then, conversely, an edge in LINE_UNKNOWN state 37 * classes. Then, conversely, an edge in LINE_UNKNOWN state
38 * which separates two faces that _are_ in the same edsf 38 * which separates two faces that _are_ in the same dsf
39 * class can immediately have its state determined. 39 * class can immediately have its state determined.
40 * + But you can go one better, if you're prepared to loop 40 * + But you can go one better, if you're prepared to loop
41 * over all _pairs_ of edges. Suppose we have edges A and B, 41 * over all _pairs_ of edges. Suppose we have edges A and B,
42 * which respectively separate faces A1,A2 and B1,B2. 42 * which respectively separate faces A1,A2 and B1,B2.
43 * Suppose that A,B are in the same edge-edsf class and that 43 * Suppose that A,B are in the same edge-dsf class and that
44 * A1,B1 (wlog) are in the same face-edsf class; then we can 44 * A1,B1 (wlog) are in the same face-dsf class; then we can
45 * immediately place A2,B2 into the same face-edsf class (as 45 * immediately place A2,B2 into the same face-dsf class (as
46 * each other, not as A1 and A2) one way round or the other. 46 * each other, not as A1 and A2) one way round or the other.
47 * And conversely again, if A1,B1 are in the same face-edsf 47 * And conversely again, if A1,B1 are in the same face-dsf
48 * class and so are A2,B2, then we can put A,B into the same 48 * class and so are A2,B2, then we can put A,B into the same
49 * face-edsf class. 49 * face-dsf class.
50 * * Of course, this deduction requires a quadratic-time 50 * * Of course, this deduction requires a quadratic-time
51 * loop over all pairs of edges in the grid, so it should 51 * loop over all pairs of edges in the grid, so it should
52 * be reserved until there's nothing easier left to be 52 * be reserved until there's nothing easier left to be
@@ -77,7 +77,11 @@
77#include <string.h> 77#include <string.h>
78#include <assert.h> 78#include <assert.h>
79#include <ctype.h> 79#include <ctype.h>
80#include <math.h> 80#ifdef NO_TGMATH_H
81# include <math.h>
82#else
83# include <tgmath.h>
84#endif
81 85
82#include "puzzles.h" 86#include "puzzles.h"
83#include "tree234.h" 87#include "tree234.h"
@@ -153,7 +157,7 @@ typedef struct solver_state {
153 char *face_yes_count; 157 char *face_yes_count;
154 char *face_no_count; 158 char *face_no_count;
155 bool *dot_solved, *face_solved; 159 bool *dot_solved, *face_solved;
156 int *dotdsf; 160 DSF *dotdsf;
157 161
158 /* Information for Normal level deductions: 162 /* Information for Normal level deductions:
159 * For each dline, store a bitmask for whether we know: 163 * For each dline, store a bitmask for whether we know:
@@ -162,7 +166,7 @@ typedef struct solver_state {
162 char *dlines; 166 char *dlines;
163 167
164 /* Hard level information */ 168 /* Hard level information */
165 int *linedsf; 169 DSF *linedsf;
166} solver_state; 170} solver_state;
167 171
168/* 172/*
@@ -279,6 +283,9 @@ static void check_caches(const solver_state* sstate);
279 A("Penrose (rhombs)",PENROSE_P3,3,3) \ 283 A("Penrose (rhombs)",PENROSE_P3,3,3) \
280 A("Great-Great-Dodecagonal",GREATGREATDODECAGONAL,2,2) \ 284 A("Great-Great-Dodecagonal",GREATGREATDODECAGONAL,2,2) \
281 A("Kagome",KAGOME,3,3) \ 285 A("Kagome",KAGOME,3,3) \
286 A("Compass-Dodecagonal",COMPASSDODECAGONAL,2,2) \
287 A("Hats",HATS,6,6) \
288 A("Spectres",SPECTRES,6,6) \
282 /* end of list */ 289 /* end of list */
283 290
284#define GRID_NAME(title,type,amin,omin) title, 291#define GRID_NAME(title,type,amin,omin) title,
@@ -380,7 +387,7 @@ static solver_state *new_solver_state(const game_state *state, int diff) {
380 ret->solver_status = SOLVER_INCOMPLETE; 387 ret->solver_status = SOLVER_INCOMPLETE;
381 ret->diff = diff; 388 ret->diff = diff;
382 389
383 ret->dotdsf = snew_dsf(num_dots); 390 ret->dotdsf = dsf_new(num_dots);
384 ret->looplen = snewn(num_dots, int); 391 ret->looplen = snewn(num_dots, int);
385 392
386 for (i = 0; i < num_dots; i++) { 393 for (i = 0; i < num_dots; i++) {
@@ -411,7 +418,7 @@ static solver_state *new_solver_state(const game_state *state, int diff) {
411 if (diff < DIFF_HARD) { 418 if (diff < DIFF_HARD) {
412 ret->linedsf = NULL; 419 ret->linedsf = NULL;
413 } else { 420 } else {
414 ret->linedsf = snew_dsf(state->game_grid->num_edges); 421 ret->linedsf = dsf_new_flip(state->game_grid->num_edges);
415 } 422 }
416 423
417 return ret; 424 return ret;
@@ -420,7 +427,7 @@ static solver_state *new_solver_state(const game_state *state, int diff) {
420static void free_solver_state(solver_state *sstate) { 427static void free_solver_state(solver_state *sstate) {
421 if (sstate) { 428 if (sstate) {
422 free_game(sstate->state); 429 free_game(sstate->state);
423 sfree(sstate->dotdsf); 430 dsf_free(sstate->dotdsf);
424 sfree(sstate->looplen); 431 sfree(sstate->looplen);
425 sfree(sstate->dot_solved); 432 sfree(sstate->dot_solved);
426 sfree(sstate->face_solved); 433 sfree(sstate->face_solved);
@@ -431,7 +438,7 @@ static void free_solver_state(solver_state *sstate) {
431 438
432 /* OK, because sfree(NULL) is a no-op */ 439 /* OK, because sfree(NULL) is a no-op */
433 sfree(sstate->dlines); 440 sfree(sstate->dlines);
434 sfree(sstate->linedsf); 441 dsf_free(sstate->linedsf);
435 442
436 sfree(sstate); 443 sfree(sstate);
437 } 444 }
@@ -449,10 +456,9 @@ static solver_state *dup_solver_state(const solver_state *sstate) {
449 ret->solver_status = sstate->solver_status; 456 ret->solver_status = sstate->solver_status;
450 ret->diff = sstate->diff; 457 ret->diff = sstate->diff;
451 458
452 ret->dotdsf = snewn(num_dots, int); 459 ret->dotdsf = dsf_new(num_dots);
453 ret->looplen = snewn(num_dots, int); 460 ret->looplen = snewn(num_dots, int);
454 memcpy(ret->dotdsf, sstate->dotdsf, 461 dsf_copy(ret->dotdsf, sstate->dotdsf);
455 num_dots * sizeof(int));
456 memcpy(ret->looplen, sstate->looplen, 462 memcpy(ret->looplen, sstate->looplen,
457 num_dots * sizeof(int)); 463 num_dots * sizeof(int));
458 464
@@ -480,9 +486,8 @@ static solver_state *dup_solver_state(const solver_state *sstate) {
480 } 486 }
481 487
482 if (sstate->linedsf) { 488 if (sstate->linedsf) {
483 ret->linedsf = snewn(num_edges, int); 489 ret->linedsf = dsf_new_flip(num_edges);
484 memcpy(ret->linedsf, sstate->linedsf, 490 dsf_copy(ret->linedsf, sstate->linedsf);
485 num_edges * sizeof(int));
486 } else { 491 } else {
487 ret->linedsf = NULL; 492 ret->linedsf = NULL;
488 } 493 }
@@ -552,6 +557,9 @@ static const game_params loopy_presets_more[] = {
552 { 3, 3, DIFF_HARD, LOOPY_GRID_DODECAGONAL }, 557 { 3, 3, DIFF_HARD, LOOPY_GRID_DODECAGONAL },
553 { 3, 3, DIFF_HARD, LOOPY_GRID_GREATDODECAGONAL }, 558 { 3, 3, DIFF_HARD, LOOPY_GRID_GREATDODECAGONAL },
554 { 3, 2, DIFF_HARD, LOOPY_GRID_GREATGREATDODECAGONAL }, 559 { 3, 2, DIFF_HARD, LOOPY_GRID_GREATGREATDODECAGONAL },
560 { 3, 3, DIFF_HARD, LOOPY_GRID_COMPASSDODECAGONAL },
561 { 6, 6, DIFF_HARD, LOOPY_GRID_HATS },
562 { 6, 6, DIFF_HARD, LOOPY_GRID_SPECTRES },
555#else 563#else
556 { 10, 10, DIFF_HARD, LOOPY_GRID_HONEYCOMB }, 564 { 10, 10, DIFF_HARD, LOOPY_GRID_HONEYCOMB },
557 { 5, 4, DIFF_HARD, LOOPY_GRID_GREATHEXAGONAL }, 565 { 5, 4, DIFF_HARD, LOOPY_GRID_GREATHEXAGONAL },
@@ -561,6 +569,9 @@ static const game_params loopy_presets_more[] = {
561 { 5, 4, DIFF_HARD, LOOPY_GRID_DODECAGONAL }, 569 { 5, 4, DIFF_HARD, LOOPY_GRID_DODECAGONAL },
562 { 5, 4, DIFF_HARD, LOOPY_GRID_GREATDODECAGONAL }, 570 { 5, 4, DIFF_HARD, LOOPY_GRID_GREATDODECAGONAL },
563 { 5, 3, DIFF_HARD, LOOPY_GRID_GREATGREATDODECAGONAL }, 571 { 5, 3, DIFF_HARD, LOOPY_GRID_GREATGREATDODECAGONAL },
572 { 5, 4, DIFF_HARD, LOOPY_GRID_COMPASSDODECAGONAL },
573 { 10, 10, DIFF_HARD, LOOPY_GRID_HATS },
574 { 10, 10, DIFF_HARD, LOOPY_GRID_SPECTRES },
564#endif 575#endif
565}; 576};
566 577
@@ -681,6 +692,7 @@ static game_params *custom_params(const config_item *cfg)
681 692
682static const char *validate_params(const game_params *params, bool full) 693static const char *validate_params(const game_params *params, bool full)
683{ 694{
695 const char *err;
684 if (params->type < 0 || params->type >= NUM_GRID_TYPES) 696 if (params->type < 0 || params->type >= NUM_GRID_TYPES)
685 return "Illegal grid type"; 697 return "Illegal grid type";
686 if (params->w < grid_size_limits[params->type].amin || 698 if (params->w < grid_size_limits[params->type].amin ||
@@ -689,6 +701,8 @@ static const char *validate_params(const game_params *params, bool full)
689 if (params->w < grid_size_limits[params->type].omin && 701 if (params->w < grid_size_limits[params->type].omin &&
690 params->h < grid_size_limits[params->type].omin) 702 params->h < grid_size_limits[params->type].omin)
691 return grid_size_limits[params->type].oerr; 703 return grid_size_limits[params->type].oerr;
704 err = grid_validate_params(grid_types[params->type], params->w, params->h);
705 if (err != NULL) return err;
692 706
693 /* 707 /*
694 * This shouldn't be able to happen at all, since decode_params 708 * This shouldn't be able to happen at all, since decode_params
@@ -771,10 +785,13 @@ static const char *validate_desc(const game_params *params, const char *desc)
771 * know is the precise number of faces. */ 785 * know is the precise number of faces. */
772 grid_desc = extract_grid_desc(&desc); 786 grid_desc = extract_grid_desc(&desc);
773 ret = grid_validate_desc(grid_types[params->type], params->w, params->h, grid_desc); 787 ret = grid_validate_desc(grid_types[params->type], params->w, params->h, grid_desc);
774 if (ret) return ret; 788 if (ret) {
789 sfree(grid_desc);
790 return ret;
791 }
775 792
776 g = loopy_generate_grid(params, grid_desc); 793 g = loopy_generate_grid(params, grid_desc);
777 if (grid_desc) sfree(grid_desc); 794 sfree(grid_desc);
778 795
779 for (; *desc; ++desc) { 796 for (; *desc; ++desc) {
780 if ((*desc >= '0' && *desc <= '9') || (*desc >= 'A' && *desc <= 'Z')) { 797 if ((*desc >= '0' && *desc <= '9') || (*desc >= 'A' && *desc <= 'Z')) {
@@ -785,13 +802,18 @@ static const char *validate_desc(const game_params *params, const char *desc)
785 count += *desc - 'a' + 1; 802 count += *desc - 'a' + 1;
786 continue; 803 continue;
787 } 804 }
805 grid_free(g);
788 return "Unknown character in description"; 806 return "Unknown character in description";
789 } 807 }
790 808
791 if (count < g->num_faces) 809 if (count < g->num_faces) {
810 grid_free(g);
792 return "Description too short for board size"; 811 return "Description too short for board size";
793 if (count > g->num_faces) 812 }
813 if (count > g->num_faces) {
814 grid_free(g);
794 return "Description too long for board size"; 815 return "Description too long for board size";
816 }
795 817
796 grid_free(g); 818 grid_free(g);
797 819
@@ -850,22 +872,98 @@ static char *encode_solve_move(const game_state *state)
850 return ret; 872 return ret;
851} 873}
852 874
875struct game_ui {
876 /*
877 * User preference: should grid lines in LINE_NO state be drawn
878 * very faintly so users can still see where they are, or should
879 * they be completely invisible?
880 */
881 bool draw_faint_lines;
882
883 /*
884 * User preference: when clicking an edge that has only one
885 * possible edge connecting to one (or both) of its ends, should
886 * that edge also change to the same state as the edge we just
887 * clicked?
888 */
889 enum {
890 AF_OFF, /* no, all grid edges are independent in the UI */
891 AF_FIXED, /* yes, but only based on the grid itself */
892 AF_ADAPTIVE /* yes, and consider edges user has already set to NO */
893 } autofollow;
894};
895
896static void legacy_prefs_override(struct game_ui *ui_out)
897{
898 static bool initialised = false;
899 static int draw_faint_lines = -1;
900 static int autofollow = -1;
901
902 if (!initialised) {
903 char *env;
904
905 initialised = true;
906 draw_faint_lines = getenv_bool("LOOPY_FAINT_LINES", -1);
907
908 if ((env = getenv("LOOPY_AUTOFOLLOW")) != NULL) {
909 if (!strcmp(env, "off"))
910 autofollow = AF_OFF;
911 else if (!strcmp(env, "fixed"))
912 autofollow = AF_FIXED;
913 else if (!strcmp(env, "adaptive"))
914 autofollow = AF_ADAPTIVE;
915 }
916 }
917
918 if (draw_faint_lines != -1)
919 ui_out->draw_faint_lines = draw_faint_lines;
920 if (autofollow != -1)
921 ui_out->autofollow = autofollow;
922}
923
853static game_ui *new_ui(const game_state *state) 924static game_ui *new_ui(const game_state *state)
854{ 925{
855 return NULL; 926 game_ui *ui = snew(game_ui);
927 ui->draw_faint_lines = true;
928 ui->autofollow = AF_OFF;
929 legacy_prefs_override(ui);
930 return ui;
856} 931}
857 932
858static void free_ui(game_ui *ui) 933static void free_ui(game_ui *ui)
859{ 934{
935 sfree(ui);
860} 936}
861 937
862static char *encode_ui(const game_ui *ui) 938static config_item *get_prefs(game_ui *ui)
863{ 939{
864 return NULL; 940 config_item *ret;
941
942 ret = snewn(3, config_item);
943
944 ret[0].name = "Draw excluded grid lines faintly";
945 ret[0].kw = "draw-faint-lines";
946 ret[0].type = C_BOOLEAN;
947 ret[0].u.boolean.bval = ui->draw_faint_lines;
948
949 ret[1].name = "Auto-follow unique paths of edges";
950 ret[1].kw = "auto-follow";
951 ret[1].type = C_CHOICES;
952 ret[1].u.choices.choicenames =
953 ":No:Based on grid only:Based on grid and game state";
954 ret[1].u.choices.choicekws = ":off:fixed:adaptive";
955 ret[1].u.choices.selected = ui->autofollow;
956
957 ret[2].name = NULL;
958 ret[2].type = C_END;
959
960 return ret;
865} 961}
866 962
867static void decode_ui(game_ui *ui, const char *encoding) 963static void set_prefs(game_ui *ui, const config_item *cfg)
868{ 964{
965 ui->draw_faint_lines = cfg[0].u.boolean.bval;
966 ui->autofollow = cfg[1].u.choices.selected;
869} 967}
870 968
871static void game_changed_state(game_ui *ui, const game_state *oldstate, 969static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -874,7 +972,7 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
874} 972}
875 973
876static void game_compute_size(const game_params *params, int tilesize, 974static void game_compute_size(const game_params *params, int tilesize,
877 int *x, int *y) 975 const game_ui *ui, int *x, int *y)
878{ 976{
879 int grid_width, grid_height, rendered_width, rendered_height; 977 int grid_width, grid_height, rendered_width, rendered_height;
880 int g_tilesize; 978 int g_tilesize;
@@ -974,11 +1072,6 @@ static void game_free_drawstate(drawing *dr, game_drawstate *ds)
974 sfree(ds); 1072 sfree(ds);
975} 1073}
976 1074
977static bool game_timing_state(const game_state *state, game_ui *ui)
978{
979 return true;
980}
981
982static float game_anim_length(const game_state *oldstate, 1075static float game_anim_length(const game_state *oldstate,
983 const game_state *newstate, int dir, game_ui *ui) 1076 const game_state *newstate, int dir, game_ui *ui)
984{ 1077{
@@ -1004,7 +1097,7 @@ static char *game_text_format(const game_state *state)
1004 assert(state->grid_type == 0); 1097 assert(state->grid_type == 0);
1005 1098
1006 /* Work out the basic size unit */ 1099 /* Work out the basic size unit */
1007 f = g->faces; /* first face */ 1100 f = g->faces[0]; /* first face */
1008 assert(f->order == 4); 1101 assert(f->order == 4);
1009 /* The dots are ordered clockwise, so the two opposite 1102 /* The dots are ordered clockwise, so the two opposite
1010 * corners are guaranteed to span the square */ 1103 * corners are guaranteed to span the square */
@@ -1027,7 +1120,7 @@ static char *game_text_format(const game_state *state)
1027 1120
1028 /* Fill in edge info */ 1121 /* Fill in edge info */
1029 for (i = 0; i < g->num_edges; i++) { 1122 for (i = 0; i < g->num_edges; i++) {
1030 grid_edge *e = g->edges + i; 1123 grid_edge *e = g->edges[i];
1031 /* Cell coordinates, from (0,0) to (w-1,h-1) */ 1124 /* Cell coordinates, from (0,0) to (w-1,h-1) */
1032 int x1 = (e->dot1->x - g->lowest_x) / cell_size; 1125 int x1 = (e->dot1->x - g->lowest_x) / cell_size;
1033 int x2 = (e->dot2->x - g->lowest_x) / cell_size; 1126 int x2 = (e->dot2->x - g->lowest_x) / cell_size;
@@ -1055,7 +1148,7 @@ static char *game_text_format(const game_state *state)
1055 for (i = 0; i < g->num_faces; i++) { 1148 for (i = 0; i < g->num_faces; i++) {
1056 int x1, x2, y1, y2; 1149 int x1, x2, y1, y2;
1057 1150
1058 f = g->faces + i; 1151 f = g->faces[i];
1059 assert(f->order == 4); 1152 assert(f->order == 4);
1060 /* Cell coordinates, from (0,0) to (w-1,h-1) */ 1153 /* Cell coordinates, from (0,0) to (w-1,h-1) */
1061 x1 = (f->dots[0]->x - g->lowest_x) / cell_size; 1154 x1 = (f->dots[0]->x - g->lowest_x) / cell_size;
@@ -1135,26 +1228,26 @@ static bool solver_set_line(solver_state *sstate, int i,
1135#endif 1228#endif
1136 1229
1137 g = state->game_grid; 1230 g = state->game_grid;
1138 e = g->edges + i; 1231 e = g->edges[i];
1139 1232
1140 /* Update the cache for both dots and both faces affected by this. */ 1233 /* Update the cache for both dots and both faces affected by this. */
1141 if (line_new == LINE_YES) { 1234 if (line_new == LINE_YES) {
1142 sstate->dot_yes_count[e->dot1 - g->dots]++; 1235 sstate->dot_yes_count[e->dot1->index]++;
1143 sstate->dot_yes_count[e->dot2 - g->dots]++; 1236 sstate->dot_yes_count[e->dot2->index]++;
1144 if (e->face1) { 1237 if (e->face1) {
1145 sstate->face_yes_count[e->face1 - g->faces]++; 1238 sstate->face_yes_count[e->face1->index]++;
1146 } 1239 }
1147 if (e->face2) { 1240 if (e->face2) {
1148 sstate->face_yes_count[e->face2 - g->faces]++; 1241 sstate->face_yes_count[e->face2->index]++;
1149 } 1242 }
1150 } else { 1243 } else {
1151 sstate->dot_no_count[e->dot1 - g->dots]++; 1244 sstate->dot_no_count[e->dot1->index]++;
1152 sstate->dot_no_count[e->dot2 - g->dots]++; 1245 sstate->dot_no_count[e->dot2->index]++;
1153 if (e->face1) { 1246 if (e->face1) {
1154 sstate->face_no_count[e->face1 - g->faces]++; 1247 sstate->face_no_count[e->face1->index]++;
1155 } 1248 }
1156 if (e->face2) { 1249 if (e->face2) {
1157 sstate->face_no_count[e->face2 - g->faces]++; 1250 sstate->face_no_count[e->face2->index]++;
1158 } 1251 }
1159 } 1252 }
1160 1253
@@ -1178,10 +1271,10 @@ static bool merge_dots(solver_state *sstate, int edge_index)
1178{ 1271{
1179 int i, j, len; 1272 int i, j, len;
1180 grid *g = sstate->state->game_grid; 1273 grid *g = sstate->state->game_grid;
1181 grid_edge *e = g->edges + edge_index; 1274 grid_edge *e = g->edges[edge_index];
1182 1275
1183 i = e->dot1 - g->dots; 1276 i = e->dot1->index;
1184 j = e->dot2 - g->dots; 1277 j = e->dot2->index;
1185 1278
1186 i = dsf_canonify(sstate->dotdsf, i); 1279 i = dsf_canonify(sstate->dotdsf, i);
1187 j = dsf_canonify(sstate->dotdsf, j); 1280 j = dsf_canonify(sstate->dotdsf, j);
@@ -1211,12 +1304,12 @@ static bool merge_lines(solver_state *sstate, int i, int j, bool inverse
1211 assert(i < sstate->state->game_grid->num_edges); 1304 assert(i < sstate->state->game_grid->num_edges);
1212 assert(j < sstate->state->game_grid->num_edges); 1305 assert(j < sstate->state->game_grid->num_edges);
1213 1306
1214 i = edsf_canonify(sstate->linedsf, i, &inv_tmp); 1307 i = dsf_canonify_flip(sstate->linedsf, i, &inv_tmp);
1215 inverse ^= inv_tmp; 1308 inverse ^= inv_tmp;
1216 j = edsf_canonify(sstate->linedsf, j, &inv_tmp); 1309 j = dsf_canonify_flip(sstate->linedsf, j, &inv_tmp);
1217 inverse ^= inv_tmp; 1310 inverse ^= inv_tmp;
1218 1311
1219 edsf_merge(sstate->linedsf, i, j, inverse); 1312 dsf_merge_flip(sstate->linedsf, i, j, inverse);
1220 1313
1221#ifdef SHOW_WORKING 1314#ifdef SHOW_WORKING
1222 if (i != j) { 1315 if (i != j) {
@@ -1239,12 +1332,12 @@ static int dot_order(const game_state* state, int dot, char line_type)
1239{ 1332{
1240 int n = 0; 1333 int n = 0;
1241 grid *g = state->game_grid; 1334 grid *g = state->game_grid;
1242 grid_dot *d = g->dots + dot; 1335 grid_dot *d = g->dots[dot];
1243 int i; 1336 int i;
1244 1337
1245 for (i = 0; i < d->order; i++) { 1338 for (i = 0; i < d->order; i++) {
1246 grid_edge *e = d->edges[i]; 1339 grid_edge *e = d->edges[i];
1247 if (state->lines[e - g->edges] == line_type) 1340 if (state->lines[e->index] == line_type)
1248 ++n; 1341 ++n;
1249 } 1342 }
1250 return n; 1343 return n;
@@ -1256,12 +1349,12 @@ static int face_order(const game_state* state, int face, char line_type)
1256{ 1349{
1257 int n = 0; 1350 int n = 0;
1258 grid *g = state->game_grid; 1351 grid *g = state->game_grid;
1259 grid_face *f = g->faces + face; 1352 grid_face *f = g->faces[face];
1260 int i; 1353 int i;
1261 1354
1262 for (i = 0; i < f->order; i++) { 1355 for (i = 0; i < f->order; i++) {
1263 grid_edge *e = f->edges[i]; 1356 grid_edge *e = f->edges[i];
1264 if (state->lines[e - g->edges] == line_type) 1357 if (state->lines[e->index] == line_type)
1265 ++n; 1358 ++n;
1266 } 1359 }
1267 return n; 1360 return n;
@@ -1282,10 +1375,10 @@ static bool dot_setall(solver_state *sstate, int dot,
1282 return false; 1375 return false;
1283 1376
1284 g = state->game_grid; 1377 g = state->game_grid;
1285 d = g->dots + dot; 1378 d = g->dots[dot];
1286 1379
1287 for (i = 0; i < d->order; i++) { 1380 for (i = 0; i < d->order; i++) {
1288 int line_index = d->edges[i] - g->edges; 1381 int line_index = d->edges[i]->index;
1289 if (state->lines[line_index] == old_type) { 1382 if (state->lines[line_index] == old_type) {
1290 r = solver_set_line(sstate, line_index, new_type); 1383 r = solver_set_line(sstate, line_index, new_type);
1291 assert(r); 1384 assert(r);
@@ -1309,10 +1402,10 @@ static bool face_setall(solver_state *sstate, int face,
1309 return false; 1402 return false;
1310 1403
1311 g = state->game_grid; 1404 g = state->game_grid;
1312 f = g->faces + face; 1405 f = g->faces[face];
1313 1406
1314 for (i = 0; i < f->order; i++) { 1407 for (i = 0; i < f->order; i++) {
1315 int line_index = f->edges[i] - g->edges; 1408 int line_index = f->edges[i]->index;
1316 if (state->lines[line_index] == old_type) { 1409 if (state->lines[line_index] == old_type) {
1317 r = solver_set_line(sstate, line_index, new_type); 1410 r = solver_set_line(sstate, line_index, new_type);
1318 assert(r); 1411 assert(r);
@@ -1341,7 +1434,7 @@ static void add_full_clues(game_state *state, random_state *rs)
1341 * algorithm does work, and there aren't any GREY faces still there. */ 1434 * algorithm does work, and there aren't any GREY faces still there. */
1342 memset(clues, 0, g->num_faces); 1435 memset(clues, 0, g->num_faces);
1343 for (i = 0; i < g->num_edges; i++) { 1436 for (i = 0; i < g->num_edges; i++) {
1344 grid_edge *e = g->edges + i; 1437 grid_edge *e = g->edges[i];
1345 grid_face *f1 = e->face1; 1438 grid_face *f1 = e->face1;
1346 grid_face *f2 = e->face2; 1439 grid_face *f2 = e->face2;
1347 enum face_colour c1 = FACE_COLOUR(f1); 1440 enum face_colour c1 = FACE_COLOUR(f1);
@@ -1349,8 +1442,8 @@ static void add_full_clues(game_state *state, random_state *rs)
1349 assert(c1 != FACE_GREY); 1442 assert(c1 != FACE_GREY);
1350 assert(c2 != FACE_GREY); 1443 assert(c2 != FACE_GREY);
1351 if (c1 != c2) { 1444 if (c1 != c2) {
1352 if (f1) clues[f1 - g->faces]++; 1445 if (f1) clues[f1->index]++;
1353 if (f2) clues[f2 - g->faces]++; 1446 if (f2) clues[f2->index]++;
1354 } 1447 }
1355 } 1448 }
1356 sfree(board); 1449 sfree(board);
@@ -1361,7 +1454,7 @@ static bool game_has_unique_soln(const game_state *state, int diff)
1361{ 1454{
1362 bool ret; 1455 bool ret;
1363 solver_state *sstate_new; 1456 solver_state *sstate_new;
1364 solver_state *sstate = new_solver_state((game_state *)state, diff); 1457 solver_state *sstate = new_solver_state(state, diff);
1365 1458
1366 sstate_new = solve_game_rec(sstate); 1459 sstate_new = solve_game_rec(sstate);
1367 1460
@@ -1541,7 +1634,8 @@ static bool check_completion(game_state *state)
1541 grid *g = state->game_grid; 1634 grid *g = state->game_grid;
1542 int i; 1635 int i;
1543 bool ret; 1636 bool ret;
1544 int *dsf, *component_state; 1637 DSF *dsf;
1638 int *component_state;
1545 int nsilly, nloop, npath, largest_comp, largest_size, total_pathsize; 1639 int nsilly, nloop, npath, largest_comp, largest_size, total_pathsize;
1546 enum { COMP_NONE, COMP_LOOP, COMP_PATH, COMP_SILLY, COMP_EMPTY }; 1640 enum { COMP_NONE, COMP_LOOP, COMP_PATH, COMP_SILLY, COMP_EMPTY };
1547 1641
@@ -1626,13 +1720,13 @@ static bool check_completion(game_state *state)
1626 * leave that one unhighlighted, and light the rest up in red. 1720 * leave that one unhighlighted, and light the rest up in red.
1627 */ 1721 */
1628 1722
1629 dsf = snew_dsf(g->num_dots); 1723 dsf = dsf_new(g->num_dots);
1630 1724
1631 /* Build the dsf. */ 1725 /* Build the dsf. */
1632 for (i = 0; i < g->num_edges; i++) { 1726 for (i = 0; i < g->num_edges; i++) {
1633 if (state->lines[i] == LINE_YES) { 1727 if (state->lines[i] == LINE_YES) {
1634 grid_edge *e = g->edges + i; 1728 grid_edge *e = g->edges[i];
1635 int d1 = e->dot1 - g->dots, d2 = e->dot2 - g->dots; 1729 int d1 = e->dot1->index, d2 = e->dot2->index;
1636 dsf_merge(dsf, d1, d2); 1730 dsf_merge(dsf, d1, d2);
1637 } 1731 }
1638 } 1732 }
@@ -1657,10 +1751,10 @@ static bool check_completion(game_state *state)
1657 int unknown = dot_order(state, i, LINE_UNKNOWN); 1751 int unknown = dot_order(state, i, LINE_UNKNOWN);
1658 if ((yes == 1 && unknown == 0) || (yes >= 3)) { 1752 if ((yes == 1 && unknown == 0) || (yes >= 3)) {
1659 /* violation, so mark all YES edges as errors */ 1753 /* violation, so mark all YES edges as errors */
1660 grid_dot *d = g->dots + i; 1754 grid_dot *d = g->dots[i];
1661 int j; 1755 int j;
1662 for (j = 0; j < d->order; j++) { 1756 for (j = 0; j < d->order; j++) {
1663 int e = d->edges[j] - g->edges; 1757 int e = d->edges[j]->index;
1664 if (state->lines[e] == LINE_YES) 1758 if (state->lines[e] == LINE_YES)
1665 state->line_errors[e] = true; 1759 state->line_errors[e] = true;
1666 } 1760 }
@@ -1723,8 +1817,8 @@ static bool check_completion(game_state *state)
1723 */ 1817 */
1724 for (i = 0; i < g->num_edges; i++) { 1818 for (i = 0; i < g->num_edges; i++) {
1725 if (state->lines[i] == LINE_YES) { 1819 if (state->lines[i] == LINE_YES) {
1726 grid_edge *e = g->edges + i; 1820 grid_edge *e = g->edges[i];
1727 int d1 = e->dot1 - g->dots; /* either endpoint is good enough */ 1821 int d1 = e->dot1->index; /* either endpoint is good enough */
1728 int comp = dsf_canonify(dsf, d1); 1822 int comp = dsf_canonify(dsf, d1);
1729 if ((component_state[comp] == COMP_PATH && 1823 if ((component_state[comp] == COMP_PATH &&
1730 -1 != largest_comp) || 1824 -1 != largest_comp) ||
@@ -1763,7 +1857,7 @@ static bool check_completion(game_state *state)
1763 } 1857 }
1764 1858
1765 sfree(component_state); 1859 sfree(component_state);
1766 sfree(dsf); 1860 dsf_free(dsf);
1767 1861
1768 return ret; 1862 return ret;
1769} 1863}
@@ -1782,7 +1876,7 @@ static bool check_completion(game_state *state)
1782 * know both or neither is on that's already stored more directly.) 1876 * know both or neither is on that's already stored more directly.)
1783 * 1877 *
1784 * Advanced Mode 1878 * Advanced Mode
1785 * Use edsf data structure to make equivalence classes of lines that are 1879 * Use flip dsf data structure to make equivalence classes of lines that are
1786 * known identical to or opposite to one another. 1880 * known identical to or opposite to one another.
1787 */ 1881 */
1788 1882
@@ -1822,11 +1916,10 @@ static int dline_index_from_dot(grid *g, grid_dot *d, int i)
1822 if (i2 == d->order) i2 = 0; 1916 if (i2 == d->order) i2 = 0;
1823 e2 = d->edges[i2]; 1917 e2 = d->edges[i2];
1824#endif 1918#endif
1825 ret = 2 * (e - g->edges) + ((e->dot1 == d) ? 1 : 0); 1919 ret = 2 * (e->index) + ((e->dot1 == d) ? 1 : 0);
1826#ifdef DEBUG_DLINES 1920#ifdef DEBUG_DLINES
1827 printf("dline_index_from_dot: d=%d,i=%d, edges [%d,%d] - %d\n", 1921 printf("dline_index_from_dot: d=%d,i=%d, edges [%d,%d] - %d\n",
1828 (int)(d - g->dots), i, (int)(e - g->edges), 1922 (int)(d->index), i, (int)(e->index), (int)(e2 ->index), ret);
1829 (int)(e2 - g->edges), ret);
1830#endif 1923#endif
1831 return ret; 1924 return ret;
1832} 1925}
@@ -1845,11 +1938,10 @@ static int dline_index_from_face(grid *g, grid_face *f, int i)
1845 if (i2 < 0) i2 += f->order; 1938 if (i2 < 0) i2 += f->order;
1846 e2 = f->edges[i2]; 1939 e2 = f->edges[i2];
1847#endif 1940#endif
1848 ret = 2 * (e - g->edges) + ((e->dot1 == d) ? 1 : 0); 1941 ret = 2 * (e->index) + ((e->dot1 == d) ? 1 : 0);
1849#ifdef DEBUG_DLINES 1942#ifdef DEBUG_DLINES
1850 printf("dline_index_from_face: f=%d,i=%d, edges [%d,%d] - %d\n", 1943 printf("dline_index_from_face: f=%d,i=%d, edges [%d,%d] - %d\n",
1851 (int)(f - g->faces), i, (int)(e - g->edges), 1944 (int)(f->index), i, (int)(e->index), (int)(e2->index), ret);
1852 (int)(e2 - g->edges), ret);
1853#endif 1945#endif
1854 return ret; 1946 return ret;
1855} 1947}
@@ -1907,9 +1999,9 @@ static bool dline_set_opp_atleastone(solver_state *sstate,
1907 opp2 = opp + 1; 1999 opp2 = opp + 1;
1908 if (opp2 == N) opp2 = 0; 2000 if (opp2 == N) opp2 = 0;
1909 /* Check if opp, opp2 point to LINE_UNKNOWNs */ 2001 /* Check if opp, opp2 point to LINE_UNKNOWNs */
1910 if (state->lines[d->edges[opp] - g->edges] != LINE_UNKNOWN) 2002 if (state->lines[d->edges[opp]->index] != LINE_UNKNOWN)
1911 continue; 2003 continue;
1912 if (state->lines[d->edges[opp2] - g->edges] != LINE_UNKNOWN) 2004 if (state->lines[d->edges[opp2]->index] != LINE_UNKNOWN)
1913 continue; 2005 continue;
1914 /* Found opposite UNKNOWNS and they're next to each other */ 2006 /* Found opposite UNKNOWNS and they're next to each other */
1915 opp_dline_index = dline_index_from_dot(g, d, opp); 2007 opp_dline_index = dline_index_from_dot(g, d, opp);
@@ -1931,24 +2023,24 @@ static bool face_setall_identical(solver_state *sstate, int face_index,
1931 bool retval = false; 2023 bool retval = false;
1932 game_state *state = sstate->state; 2024 game_state *state = sstate->state;
1933 grid *g = state->game_grid; 2025 grid *g = state->game_grid;
1934 grid_face *f = g->faces + face_index; 2026 grid_face *f = g->faces[face_index];
1935 int N = f->order; 2027 int N = f->order;
1936 int i, j; 2028 int i, j;
1937 int can1, can2; 2029 int can1, can2;
1938 bool inv1, inv2; 2030 bool inv1, inv2;
1939 2031
1940 for (i = 0; i < N; i++) { 2032 for (i = 0; i < N; i++) {
1941 int line1_index = f->edges[i] - g->edges; 2033 int line1_index = f->edges[i]->index;
1942 if (state->lines[line1_index] != LINE_UNKNOWN) 2034 if (state->lines[line1_index] != LINE_UNKNOWN)
1943 continue; 2035 continue;
1944 for (j = i + 1; j < N; j++) { 2036 for (j = i + 1; j < N; j++) {
1945 int line2_index = f->edges[j] - g->edges; 2037 int line2_index = f->edges[j]->index;
1946 if (state->lines[line2_index] != LINE_UNKNOWN) 2038 if (state->lines[line2_index] != LINE_UNKNOWN)
1947 continue; 2039 continue;
1948 2040
1949 /* Found two UNKNOWNS */ 2041 /* Found two UNKNOWNS */
1950 can1 = edsf_canonify(sstate->linedsf, line1_index, &inv1); 2042 can1 = dsf_canonify_flip(sstate->linedsf, line1_index, &inv1);
1951 can2 = edsf_canonify(sstate->linedsf, line2_index, &inv2); 2043 can2 = dsf_canonify_flip(sstate->linedsf, line2_index, &inv2);
1952 if (can1 == can2 && inv1 == inv2) { 2044 if (can1 == can2 && inv1 == inv2) {
1953 solver_set_line(sstate, line1_index, line_new); 2045 solver_set_line(sstate, line1_index, line_new);
1954 solver_set_line(sstate, line2_index, line_new); 2046 solver_set_line(sstate, line2_index, line_new);
@@ -1966,9 +2058,8 @@ static void find_unknowns(game_state *state,
1966 int *e /* Returned edge indices */) 2058 int *e /* Returned edge indices */)
1967{ 2059{
1968 int c = 0; 2060 int c = 0;
1969 grid *g = state->game_grid;
1970 while (c < expected_count) { 2061 while (c < expected_count) {
1971 int line_index = *edge_list - g->edges; 2062 int line_index = (*edge_list)->index;
1972 if (state->lines[line_index] == LINE_UNKNOWN) { 2063 if (state->lines[line_index] == LINE_UNKNOWN) {
1973 e[c] = line_index; 2064 e[c] = line_index;
1974 c++; 2065 c++;
@@ -1989,7 +2080,7 @@ static int parity_deductions(solver_state *sstate,
1989{ 2080{
1990 game_state *state = sstate->state; 2081 game_state *state = sstate->state;
1991 int diff = DIFF_MAX; 2082 int diff = DIFF_MAX;
1992 int *linedsf = sstate->linedsf; 2083 DSF *linedsf = sstate->linedsf;
1993 2084
1994 if (unknown_count == 2) { 2085 if (unknown_count == 2) {
1995 /* Lines are known alike/opposite, depending on inv. */ 2086 /* Lines are known alike/opposite, depending on inv. */
@@ -2002,9 +2093,9 @@ static int parity_deductions(solver_state *sstate,
2002 int can[3]; /* canonical edges */ 2093 int can[3]; /* canonical edges */
2003 bool inv[3]; /* whether can[x] is inverse to e[x] */ 2094 bool inv[3]; /* whether can[x] is inverse to e[x] */
2004 find_unknowns(state, edge_list, 3, e); 2095 find_unknowns(state, edge_list, 3, e);
2005 can[0] = edsf_canonify(linedsf, e[0], inv); 2096 can[0] = dsf_canonify_flip(linedsf, e[0], inv);
2006 can[1] = edsf_canonify(linedsf, e[1], inv+1); 2097 can[1] = dsf_canonify_flip(linedsf, e[1], inv+1);
2007 can[2] = edsf_canonify(linedsf, e[2], inv+2); 2098 can[2] = dsf_canonify_flip(linedsf, e[2], inv+2);
2008 if (can[0] == can[1]) { 2099 if (can[0] == can[1]) {
2009 if (solver_set_line(sstate, e[2], (total_parity^inv[0]^inv[1]) ? 2100 if (solver_set_line(sstate, e[2], (total_parity^inv[0]^inv[1]) ?
2010 LINE_YES : LINE_NO)) 2101 LINE_YES : LINE_NO))
@@ -2025,10 +2116,10 @@ static int parity_deductions(solver_state *sstate,
2025 int can[4]; /* canonical edges */ 2116 int can[4]; /* canonical edges */
2026 bool inv[4]; /* whether can[x] is inverse to e[x] */ 2117 bool inv[4]; /* whether can[x] is inverse to e[x] */
2027 find_unknowns(state, edge_list, 4, e); 2118 find_unknowns(state, edge_list, 4, e);
2028 can[0] = edsf_canonify(linedsf, e[0], inv); 2119 can[0] = dsf_canonify_flip(linedsf, e[0], inv);
2029 can[1] = edsf_canonify(linedsf, e[1], inv+1); 2120 can[1] = dsf_canonify_flip(linedsf, e[1], inv+1);
2030 can[2] = edsf_canonify(linedsf, e[2], inv+2); 2121 can[2] = dsf_canonify_flip(linedsf, e[2], inv+2);
2031 can[3] = edsf_canonify(linedsf, e[3], inv+3); 2122 can[3] = dsf_canonify_flip(linedsf, e[3], inv+3);
2032 if (can[0] == can[1]) { 2123 if (can[0] == can[1]) {
2033 if (merge_lines(sstate, e[2], e[3], total_parity^inv[0]^inv[1])) 2124 if (merge_lines(sstate, e[2], e[3], total_parity^inv[0]^inv[1]))
2034 diff = min(diff, DIFF_HARD); 2125 diff = min(diff, DIFF_HARD);
@@ -2097,7 +2188,7 @@ static int trivial_deductions(solver_state *sstate)
2097 2188
2098 /* Per-face deductions */ 2189 /* Per-face deductions */
2099 for (i = 0; i < g->num_faces; i++) { 2190 for (i = 0; i < g->num_faces; i++) {
2100 grid_face *f = g->faces + i; 2191 grid_face *f = g->faces[i];
2101 2192
2102 if (sstate->face_solved[i]) 2193 if (sstate->face_solved[i])
2103 continue; 2194 continue;
@@ -2155,22 +2246,22 @@ static int trivial_deductions(solver_state *sstate)
2155 int j, k, e1, e2, e, d; 2246 int j, k, e1, e2, e, d;
2156 2247
2157 for (j = 0; j < f->order; j++) { 2248 for (j = 0; j < f->order; j++) {
2158 e1 = f->edges[j] - g->edges; 2249 e1 = f->edges[j]->index;
2159 e2 = f->edges[j+1 < f->order ? j+1 : 0] - g->edges; 2250 e2 = f->edges[j+1 < f->order ? j+1 : 0]->index;
2160 2251
2161 if (g->edges[e1].dot1 == g->edges[e2].dot1 || 2252 if (g->edges[e1]->dot1 == g->edges[e2]->dot1 ||
2162 g->edges[e1].dot1 == g->edges[e2].dot2) { 2253 g->edges[e1]->dot1 == g->edges[e2]->dot2) {
2163 d = g->edges[e1].dot1 - g->dots; 2254 d = g->edges[e1]->dot1->index;
2164 } else { 2255 } else {
2165 assert(g->edges[e1].dot2 == g->edges[e2].dot1 || 2256 assert(g->edges[e1]->dot2 == g->edges[e2]->dot1 ||
2166 g->edges[e1].dot2 == g->edges[e2].dot2); 2257 g->edges[e1]->dot2 == g->edges[e2]->dot2);
2167 d = g->edges[e1].dot2 - g->dots; 2258 d = g->edges[e1]->dot2->index;
2168 } 2259 }
2169 2260
2170 if (state->lines[e1] == LINE_UNKNOWN && 2261 if (state->lines[e1] == LINE_UNKNOWN &&
2171 state->lines[e2] == LINE_UNKNOWN) { 2262 state->lines[e2] == LINE_UNKNOWN) {
2172 for (k = 0; k < g->dots[d].order; k++) { 2263 for (k = 0; k < g->dots[d]->order; k++) {
2173 int e = g->dots[d].edges[k] - g->edges; 2264 int e = g->dots[d]->edges[k]->index;
2174 if (state->lines[e] == LINE_YES) 2265 if (state->lines[e] == LINE_YES)
2175 goto found; /* multi-level break */ 2266 goto found; /* multi-level break */
2176 } 2267 }
@@ -2184,7 +2275,7 @@ static int trivial_deductions(solver_state *sstate)
2184 * they're e1 and e2. 2275 * they're e1 and e2.
2185 */ 2276 */
2186 for (j = 0; j < f->order; j++) { 2277 for (j = 0; j < f->order; j++) {
2187 e = f->edges[j] - g->edges; 2278 e = f->edges[j]->index;
2188 if (state->lines[e] == LINE_UNKNOWN && e != e1 && e != e2) { 2279 if (state->lines[e] == LINE_UNKNOWN && e != e1 && e != e2) {
2189 bool r = solver_set_line(sstate, e, LINE_YES); 2280 bool r = solver_set_line(sstate, e, LINE_YES);
2190 assert(r); 2281 assert(r);
@@ -2198,7 +2289,7 @@ static int trivial_deductions(solver_state *sstate)
2198 2289
2199 /* Per-dot deductions */ 2290 /* Per-dot deductions */
2200 for (i = 0; i < g->num_dots; i++) { 2291 for (i = 0; i < g->num_dots; i++) {
2201 grid_dot *d = g->dots + i; 2292 grid_dot *d = g->dots[i];
2202 int yes, no, unknown; 2293 int yes, no, unknown;
2203 2294
2204 if (sstate->dot_solved[i]) 2295 if (sstate->dot_solved[i])
@@ -2290,12 +2381,12 @@ static int dline_deductions(solver_state *sstate)
2290 * on that. We check this with an assertion, in case someone decides to 2381 * on that. We check this with an assertion, in case someone decides to
2291 * make a grid which has larger faces than this. Note, this algorithm 2382 * make a grid which has larger faces than this. Note, this algorithm
2292 * could get quite expensive if there are many large faces. */ 2383 * could get quite expensive if there are many large faces. */
2293#define MAX_FACE_SIZE 12 2384#define MAX_FACE_SIZE 14
2294 2385
2295 for (i = 0; i < g->num_faces; i++) { 2386 for (i = 0; i < g->num_faces; i++) {
2296 int maxs[MAX_FACE_SIZE][MAX_FACE_SIZE]; 2387 int maxs[MAX_FACE_SIZE][MAX_FACE_SIZE];
2297 int mins[MAX_FACE_SIZE][MAX_FACE_SIZE]; 2388 int mins[MAX_FACE_SIZE][MAX_FACE_SIZE];
2298 grid_face *f = g->faces + i; 2389 grid_face *f = g->faces[i];
2299 int N = f->order; 2390 int N = f->order;
2300 int j,m; 2391 int j,m;
2301 int clue = state->clues[i]; 2392 int clue = state->clues[i];
@@ -2306,7 +2397,7 @@ static int dline_deductions(solver_state *sstate)
2306 2397
2307 /* Calculate the (j,j+1) entries */ 2398 /* Calculate the (j,j+1) entries */
2308 for (j = 0; j < N; j++) { 2399 for (j = 0; j < N; j++) {
2309 int edge_index = f->edges[j] - g->edges; 2400 int edge_index = f->edges[j]->index;
2310 int dline_index; 2401 int dline_index;
2311 enum line_state line1 = state->lines[edge_index]; 2402 enum line_state line1 = state->lines[edge_index];
2312 enum line_state line2; 2403 enum line_state line2;
@@ -2317,7 +2408,7 @@ static int dline_deductions(solver_state *sstate)
2317 mins[j][k] = (line1 == LINE_YES) ? 1 : 0; 2408 mins[j][k] = (line1 == LINE_YES) ? 1 : 0;
2318 /* Calculate the (j,j+2) entries */ 2409 /* Calculate the (j,j+2) entries */
2319 dline_index = dline_index_from_face(g, f, k); 2410 dline_index = dline_index_from_face(g, f, k);
2320 edge_index = f->edges[k] - g->edges; 2411 edge_index = f->edges[k]->index;
2321 line2 = state->lines[edge_index]; 2412 line2 = state->lines[edge_index];
2322 k++; 2413 k++;
2323 if (k >= N) k = 0; 2414 if (k >= N) k = 0;
@@ -2362,7 +2453,7 @@ static int dline_deductions(solver_state *sstate)
2362 for (j = 0; j < N; j++) { 2453 for (j = 0; j < N; j++) {
2363 int k; 2454 int k;
2364 grid_edge *e = f->edges[j]; 2455 grid_edge *e = f->edges[j];
2365 int line_index = e - g->edges; 2456 int line_index = e->index;
2366 int dline_index; 2457 int dline_index;
2367 2458
2368 if (state->lines[line_index] != LINE_UNKNOWN) 2459 if (state->lines[line_index] != LINE_UNKNOWN)
@@ -2397,7 +2488,7 @@ static int dline_deductions(solver_state *sstate)
2397 if (sstate->diff >= DIFF_TRICKY) { 2488 if (sstate->diff >= DIFF_TRICKY) {
2398 /* Now see if we can make dline deduction for edges{j,j+1} */ 2489 /* Now see if we can make dline deduction for edges{j,j+1} */
2399 e = f->edges[k]; 2490 e = f->edges[k];
2400 if (state->lines[e - g->edges] != LINE_UNKNOWN) 2491 if (state->lines[e->index] != LINE_UNKNOWN)
2401 /* Only worth doing this for an UNKNOWN,UNKNOWN pair. 2492 /* Only worth doing this for an UNKNOWN,UNKNOWN pair.
2402 * Dlines where one of the edges is known, are handled in the 2493 * Dlines where one of the edges is known, are handled in the
2403 * dot-deductions */ 2494 * dot-deductions */
@@ -2429,7 +2520,7 @@ static int dline_deductions(solver_state *sstate)
2429 /* ------ Dot deductions ------ */ 2520 /* ------ Dot deductions ------ */
2430 2521
2431 for (i = 0; i < g->num_dots; i++) { 2522 for (i = 0; i < g->num_dots; i++) {
2432 grid_dot *d = g->dots + i; 2523 grid_dot *d = g->dots[i];
2433 int N = d->order; 2524 int N = d->order;
2434 int yes, no, unknown; 2525 int yes, no, unknown;
2435 int j; 2526 int j;
@@ -2447,8 +2538,8 @@ static int dline_deductions(solver_state *sstate)
2447 k = j + 1; 2538 k = j + 1;
2448 if (k >= N) k = 0; 2539 if (k >= N) k = 0;
2449 dline_index = dline_index_from_dot(g, d, j); 2540 dline_index = dline_index_from_dot(g, d, j);
2450 line1_index = d->edges[j] - g->edges; 2541 line1_index = d->edges[j]->index;
2451 line2_index = d->edges[k] - g->edges; 2542 line2_index = d->edges[k] ->index;
2452 line1 = state->lines[line1_index]; 2543 line1 = state->lines[line1_index];
2453 line2 = state->lines[line2_index]; 2544 line2 = state->lines[line2_index];
2454 2545
@@ -2545,7 +2636,7 @@ static int dline_deductions(solver_state *sstate)
2545 int opp_index; 2636 int opp_index;
2546 if (opp == j || opp == k) 2637 if (opp == j || opp == k)
2547 continue; 2638 continue;
2548 opp_index = d->edges[opp] - g->edges; 2639 opp_index = d->edges[opp]->index;
2549 if (state->lines[opp_index] == LINE_UNKNOWN) { 2640 if (state->lines[opp_index] == LINE_UNKNOWN) {
2550 solver_set_line(sstate, opp_index, 2641 solver_set_line(sstate, opp_index,
2551 LINE_YES); 2642 LINE_YES);
@@ -2596,7 +2687,7 @@ static int linedsf_deductions(solver_state *sstate)
2596 if (clue < 0) 2687 if (clue < 0)
2597 continue; 2688 continue;
2598 2689
2599 N = g->faces[i].order; 2690 N = g->faces[i]->order;
2600 yes = sstate->face_yes_count[i]; 2691 yes = sstate->face_yes_count[i];
2601 if (yes + 1 == clue) { 2692 if (yes + 1 == clue) {
2602 if (face_setall_identical(sstate, i, LINE_NO)) 2693 if (face_setall_identical(sstate, i, LINE_NO))
@@ -2614,14 +2705,14 @@ static int linedsf_deductions(solver_state *sstate)
2614 2705
2615 /* Deductions with small number of LINE_UNKNOWNs, based on overall 2706 /* Deductions with small number of LINE_UNKNOWNs, based on overall
2616 * parity of lines. */ 2707 * parity of lines. */
2617 diff_tmp = parity_deductions(sstate, g->faces[i].edges, 2708 diff_tmp = parity_deductions(sstate, g->faces[i]->edges,
2618 (clue - yes) % 2, unknown); 2709 (clue - yes) % 2, unknown);
2619 diff = min(diff, diff_tmp); 2710 diff = min(diff, diff_tmp);
2620 } 2711 }
2621 2712
2622 /* ------ Dot deductions ------ */ 2713 /* ------ Dot deductions ------ */
2623 for (i = 0; i < g->num_dots; i++) { 2714 for (i = 0; i < g->num_dots; i++) {
2624 grid_dot *d = g->dots + i; 2715 grid_dot *d = g->dots[i];
2625 int N = d->order; 2716 int N = d->order;
2626 int j; 2717 int j;
2627 int yes, no, unknown; 2718 int yes, no, unknown;
@@ -2634,17 +2725,17 @@ static int linedsf_deductions(solver_state *sstate)
2634 int can1, can2; 2725 int can1, can2;
2635 bool inv1, inv2; 2726 bool inv1, inv2;
2636 int j2; 2727 int j2;
2637 line1_index = d->edges[j] - g->edges; 2728 line1_index = d->edges[j]->index;
2638 if (state->lines[line1_index] != LINE_UNKNOWN) 2729 if (state->lines[line1_index] != LINE_UNKNOWN)
2639 continue; 2730 continue;
2640 j2 = j + 1; 2731 j2 = j + 1;
2641 if (j2 == N) j2 = 0; 2732 if (j2 == N) j2 = 0;
2642 line2_index = d->edges[j2] - g->edges; 2733 line2_index = d->edges[j2]->index;
2643 if (state->lines[line2_index] != LINE_UNKNOWN) 2734 if (state->lines[line2_index] != LINE_UNKNOWN)
2644 continue; 2735 continue;
2645 /* Infer dline flags from linedsf */ 2736 /* Infer dline flags from linedsf */
2646 can1 = edsf_canonify(sstate->linedsf, line1_index, &inv1); 2737 can1 = dsf_canonify_flip(sstate->linedsf, line1_index, &inv1);
2647 can2 = edsf_canonify(sstate->linedsf, line2_index, &inv2); 2738 can2 = dsf_canonify_flip(sstate->linedsf, line2_index, &inv2);
2648 if (can1 == can2 && inv1 != inv2) { 2739 if (can1 == can2 && inv1 != inv2) {
2649 /* These are opposites, so set dline atmostone/atleastone */ 2740 /* These are opposites, so set dline atmostone/atleastone */
2650 if (set_atmostone(dlines, dline_index)) 2741 if (set_atmostone(dlines, dline_index))
@@ -2679,7 +2770,7 @@ static int linedsf_deductions(solver_state *sstate)
2679 int can; 2770 int can;
2680 bool inv; 2771 bool inv;
2681 enum line_state s; 2772 enum line_state s;
2682 can = edsf_canonify(sstate->linedsf, i, &inv); 2773 can = dsf_canonify_flip(sstate->linedsf, i, &inv);
2683 if (can == i) 2774 if (can == i)
2684 continue; 2775 continue;
2685 s = sstate->state->lines[can]; 2776 s = sstate->state->lines[can];
@@ -2704,7 +2795,6 @@ static int loop_deductions(solver_state *sstate)
2704 game_state *state = sstate->state; 2795 game_state *state = sstate->state;
2705 grid *g = state->game_grid; 2796 grid *g = state->game_grid;
2706 int shortest_chainlen = g->num_dots; 2797 int shortest_chainlen = g->num_dots;
2707 bool loop_found = false;
2708 int dots_connected; 2798 int dots_connected;
2709 bool progress = false; 2799 bool progress = false;
2710 int i; 2800 int i;
@@ -2717,7 +2807,7 @@ static int loop_deductions(solver_state *sstate)
2717 */ 2807 */
2718 for (i = 0; i < g->num_edges; i++) { 2808 for (i = 0; i < g->num_edges; i++) {
2719 if (state->lines[i] == LINE_YES) { 2809 if (state->lines[i] == LINE_YES) {
2720 loop_found |= merge_dots(sstate, i); 2810 merge_dots(sstate, i);
2721 edgecount++; 2811 edgecount++;
2722 } 2812 }
2723 } 2813 }
@@ -2762,9 +2852,9 @@ static int loop_deductions(solver_state *sstate)
2762 * loop it would create is a solution. 2852 * loop it would create is a solution.
2763 */ 2853 */
2764 for (i = 0; i < g->num_edges; i++) { 2854 for (i = 0; i < g->num_edges; i++) {
2765 grid_edge *e = g->edges + i; 2855 grid_edge *e = g->edges[i];
2766 int d1 = e->dot1 - g->dots; 2856 int d1 = e->dot1->index;
2767 int d2 = e->dot2 - g->dots; 2857 int d2 = e->dot2->index;
2768 int eqclass, val; 2858 int eqclass, val;
2769 if (state->lines[i] != LINE_UNKNOWN) 2859 if (state->lines[i] != LINE_UNKNOWN)
2770 continue; 2860 continue;
@@ -2801,13 +2891,13 @@ static int loop_deductions(solver_state *sstate)
2801 */ 2891 */
2802 sm1_nearby = 0; 2892 sm1_nearby = 0;
2803 if (e->face1) { 2893 if (e->face1) {
2804 int f = e->face1 - g->faces; 2894 int f = e->face1->index;
2805 int c = state->clues[f]; 2895 int c = state->clues[f];
2806 if (c >= 0 && sstate->face_yes_count[f] == c - 1) 2896 if (c >= 0 && sstate->face_yes_count[f] == c - 1)
2807 sm1_nearby++; 2897 sm1_nearby++;
2808 } 2898 }
2809 if (e->face2) { 2899 if (e->face2) {
2810 int f = e->face2 - g->faces; 2900 int f = e->face2->index;
2811 int c = state->clues[f]; 2901 int c = state->clues[f];
2812 if (c >= 0 && sstate->face_yes_count[f] == c - 1) 2902 if (c >= 0 && sstate->face_yes_count[f] == c - 1)
2813 sm1_nearby++; 2903 sm1_nearby++;
@@ -2958,7 +3048,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2958 char button_char = ' '; 3048 char button_char = ' ';
2959 enum line_state old_state; 3049 enum line_state old_state;
2960 3050
2961 button &= ~MOD_MASK; 3051 button = STRIP_BUTTON_MODIFIERS(button);
2962 3052
2963 /* Convert mouse-click (x,y) to grid coordinates */ 3053 /* Convert mouse-click (x,y) to grid coordinates */
2964 x -= BORDER(ds->tilesize); 3054 x -= BORDER(ds->tilesize);
@@ -2972,7 +3062,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2972 if (e == NULL) 3062 if (e == NULL)
2973 return NULL; 3063 return NULL;
2974 3064
2975 i = e - g->edges; 3065 i = e->index;
2976 3066
2977 /* I think it's only possible to play this game with mouse clicks, sorry */ 3067 /* I think it's only possible to play this game with mouse clicks, sorry */
2978 /* Maybe will add mouse drag support some time */ 3068 /* Maybe will add mouse drag support some time */
@@ -3020,73 +3110,58 @@ static char *interpret_move(const game_state *state, game_ui *ui,
3020 movesize = 80; 3110 movesize = 80;
3021 movebuf = snewn(movesize, char); 3111 movebuf = snewn(movesize, char);
3022 movelen = sprintf(movebuf, "%d%c", i, (int)button_char); 3112 movelen = sprintf(movebuf, "%d%c", i, (int)button_char);
3023 {
3024 static enum { OFF, FIXED, ADAPTIVE, DUNNO } autofollow = DUNNO;
3025 if (autofollow == DUNNO) {
3026 const char *env = getenv("LOOPY_AUTOFOLLOW");
3027 if (env && !strcmp(env, "off"))
3028 autofollow = OFF;
3029 else if (env && !strcmp(env, "fixed"))
3030 autofollow = FIXED;
3031 else if (env && !strcmp(env, "adaptive"))
3032 autofollow = ADAPTIVE;
3033 else
3034 autofollow = OFF;
3035 }
3036 3113
3037 if (autofollow != OFF) { 3114 if (ui->autofollow != AF_OFF) {
3038 int dotid; 3115 int dotid;
3039 for (dotid = 0; dotid < 2; dotid++) { 3116 for (dotid = 0; dotid < 2; dotid++) {
3040 grid_dot *dot = (dotid == 0 ? e->dot1 : e->dot2); 3117 grid_dot *dot = (dotid == 0 ? e->dot1 : e->dot2);
3041 grid_edge *e_this = e; 3118 grid_edge *e_this = e;
3042 3119
3043 while (1) { 3120 while (1) {
3044 int j, n_found; 3121 int j, n_found;
3045 grid_edge *e_next = NULL; 3122 grid_edge *e_next = NULL;
3046 3123
3047 for (j = n_found = 0; j < dot->order; j++) { 3124 for (j = n_found = 0; j < dot->order; j++) {
3048 grid_edge *e_candidate = dot->edges[j]; 3125 grid_edge *e_candidate = dot->edges[j];
3049 int i_candidate = e_candidate - g->edges; 3126 int i_candidate = e_candidate->index;
3050 if (e_candidate != e_this && 3127 if (e_candidate != e_this &&
3051 (autofollow == FIXED || 3128 (ui->autofollow == AF_FIXED ||
3052 state->lines[i] == LINE_NO || 3129 state->lines[i] == LINE_NO ||
3053 state->lines[i_candidate] != LINE_NO)) { 3130 state->lines[i_candidate] != LINE_NO)) {
3054 e_next = e_candidate; 3131 e_next = e_candidate;
3055 n_found++; 3132 n_found++;
3056 }
3057 } 3133 }
3134 }
3058 3135
3059 if (n_found != 1 || 3136 if (n_found != 1 ||
3060 state->lines[e_next - g->edges] != state->lines[i]) 3137 state->lines[e_next->index] != state->lines[i])
3061 break; 3138 break;
3062 3139
3063 if (e_next == e) { 3140 if (e_next == e) {
3064 /* 3141 /*
3065 * Special case: we might have come all the 3142 * Special case: we might have come all the way
3066 * way round a loop and found our way back to 3143 * round a loop and found our way back to the same
3067 * the same edge we started from. In that 3144 * edge we started from. In that situation, we
3068 * situation, we must terminate not only this 3145 * must terminate not only this while loop, but
3069 * while loop, but the 'for' outside it that 3146 * the 'for' outside it that was tracing in both
3070 * was tracing in both directions from the 3147 * directions from the starting edge, because if
3071 * starting edge, because if we let it trace 3148 * we let it trace in the second direction then
3072 * in the second direction then we'll only 3149 * we'll only find ourself traversing the same
3073 * find ourself traversing the same loop in 3150 * loop in the other order and generate an encoded
3074 * the other order and generate an encoded 3151 * move string that mentions the same set of edges
3075 * move string that mentions the same set of 3152 * twice.
3076 * edges twice. 3153 */
3077 */ 3154 goto autofollow_done;
3078 goto autofollow_done; 3155 }
3079 }
3080 3156
3081 dot = (e_next->dot1 != dot ? e_next->dot1 : e_next->dot2); 3157 dot = (e_next->dot1 != dot ? e_next->dot1 : e_next->dot2);
3082 if (movelen > movesize - 40) { 3158 if (movelen > movesize - 40) {
3083 movesize = movesize * 5 / 4 + 128; 3159 movesize = movesize * 5 / 4 + 128;
3084 movebuf = sresize(movebuf, movesize, char); 3160 movebuf = sresize(movebuf, movesize, char);
3085 }
3086 e_this = e_next;
3087 movelen += sprintf(movebuf+movelen, "%d%c",
3088 (int)(e_this - g->edges), button_char);
3089 } 3161 }
3162 e_this = e_next;
3163 movelen += sprintf(movebuf+movelen, "%d%c",
3164 (int)(e_this->index), button_char);
3090 } 3165 }
3091 autofollow_done:; 3166 autofollow_done:;
3092 } 3167 }
@@ -3159,7 +3234,7 @@ static void grid_to_screen(const game_drawstate *ds, const grid *g,
3159static void face_text_pos(const game_drawstate *ds, const grid *g, 3234static void face_text_pos(const game_drawstate *ds, const grid *g,
3160 grid_face *f, int *xret, int *yret) 3235 grid_face *f, int *xret, int *yret)
3161{ 3236{
3162 int faceindex = f - g->faces; 3237 int faceindex = f->index;
3163 3238
3164 /* 3239 /*
3165 * Return the cached position for this face, if we've already 3240 * Return the cached position for this face, if we've already
@@ -3192,9 +3267,9 @@ static void face_text_bbox(game_drawstate *ds, grid *g, grid_face *f,
3192 /* There seems to be a certain amount of trial-and-error involved 3267 /* There seems to be a certain amount of trial-and-error involved
3193 * in working out the correct bounding-box for the text. */ 3268 * in working out the correct bounding-box for the text. */
3194 3269
3195 *x = xx - ds->tilesize/4 - 1; 3270 *x = xx - ds->tilesize * 5 / 4 - 1;
3196 *y = yy - ds->tilesize/4 - 3; 3271 *y = yy - ds->tilesize/4 - 3;
3197 *w = ds->tilesize/2 + 2; 3272 *w = ds->tilesize * 5 / 2 + 2;
3198 *h = ds->tilesize/2 + 5; 3273 *h = ds->tilesize/2 + 5;
3199} 3274}
3200 3275
@@ -3202,7 +3277,7 @@ static void game_redraw_clue(drawing *dr, game_drawstate *ds,
3202 const game_state *state, int i) 3277 const game_state *state, int i)
3203{ 3278{
3204 grid *g = state->game_grid; 3279 grid *g = state->game_grid;
3205 grid_face *f = g->faces + i; 3280 grid_face *f = g->faces[i];
3206 int x, y; 3281 int x, y;
3207 char c[20]; 3282 char c[20];
3208 3283
@@ -3228,10 +3303,10 @@ static void edge_bbox(game_drawstate *ds, grid *g, grid_edge *e,
3228 grid_to_screen(ds, g, x1, y1, &x1, &y1); 3303 grid_to_screen(ds, g, x1, y1, &x1, &y1);
3229 grid_to_screen(ds, g, x2, y2, &x2, &y2); 3304 grid_to_screen(ds, g, x2, y2, &x2, &y2);
3230 /* Allow extra margin for dots, and thickness of lines */ 3305 /* Allow extra margin for dots, and thickness of lines */
3231 xmin = min(x1, x2) - 2; 3306 xmin = min(x1, x2) - (ds->tilesize + 15) / 16;
3232 xmax = max(x1, x2) + 2; 3307 xmax = max(x1, x2) + (ds->tilesize + 15) / 16;
3233 ymin = min(y1, y2) - 2; 3308 ymin = min(y1, y2) - (ds->tilesize + 15) / 16;
3234 ymax = max(y1, y2) + 2; 3309 ymax = max(y1, y2) + (ds->tilesize + 15) / 16;
3235 3310
3236 *x = xmin; 3311 *x = xmin;
3237 *y = ymin; 3312 *y = ymin;
@@ -3243,13 +3318,19 @@ static void dot_bbox(game_drawstate *ds, grid *g, grid_dot *d,
3243 int *x, int *y, int *w, int *h) 3318 int *x, int *y, int *w, int *h)
3244{ 3319{
3245 int x1, y1; 3320 int x1, y1;
3321 int xmin, xmax, ymin, ymax;
3246 3322
3247 grid_to_screen(ds, g, d->x, d->y, &x1, &y1); 3323 grid_to_screen(ds, g, d->x, d->y, &x1, &y1);
3248 3324
3249 *x = x1 - 2; 3325 xmin = x1 - (ds->tilesize * 5 + 63) / 64;
3250 *y = y1 - 2; 3326 xmax = x1 + (ds->tilesize * 5 + 63) / 64;
3251 *w = 5; 3327 ymin = y1 - (ds->tilesize * 5 + 63) / 64;
3252 *h = 5; 3328 ymax = y1 + (ds->tilesize * 5 + 63) / 64;
3329
3330 *x = xmin;
3331 *y = ymin;
3332 *w = xmax - xmin + 1;
3333 *h = ymax - ymin + 1;
3253} 3334}
3254 3335
3255static const int loopy_line_redraw_phases[] = { 3336static const int loopy_line_redraw_phases[] = {
@@ -3257,11 +3338,11 @@ static const int loopy_line_redraw_phases[] = {
3257}; 3338};
3258#define NPHASES lenof(loopy_line_redraw_phases) 3339#define NPHASES lenof(loopy_line_redraw_phases)
3259 3340
3260static void game_redraw_line(drawing *dr, game_drawstate *ds, 3341static void game_redraw_line(drawing *dr, game_drawstate *ds,const game_ui *ui,
3261 const game_state *state, int i, int phase) 3342 const game_state *state, int i, int phase)
3262{ 3343{
3263 grid *g = state->game_grid; 3344 grid *g = state->game_grid;
3264 grid_edge *e = g->edges + i; 3345 grid_edge *e = g->edges[i];
3265 int x1, x2, y1, y2; 3346 int x1, x2, y1, y2;
3266 int line_colour; 3347 int line_colour;
3267 3348
@@ -3283,16 +3364,13 @@ static void game_redraw_line(drawing *dr, game_drawstate *ds,
3283 grid_to_screen(ds, g, e->dot2->x, e->dot2->y, &x2, &y2); 3364 grid_to_screen(ds, g, e->dot2->x, e->dot2->y, &x2, &y2);
3284 3365
3285 if (line_colour == COL_FAINT) { 3366 if (line_colour == COL_FAINT) {
3286 static int draw_faint_lines = -1; 3367 if (ui->draw_faint_lines)
3287 if (draw_faint_lines < 0) { 3368 draw_thick_line(dr, ds->tilesize/24.0,
3288 char *env = getenv("LOOPY_FAINT_LINES"); 3369 x1 + 0.5, y1 + 0.5,
3289 draw_faint_lines = (!env || (env[0] == 'y' || 3370 x2 + 0.5, y2 + 0.5,
3290 env[0] == 'Y')); 3371 line_colour);
3291 }
3292 if (draw_faint_lines)
3293 draw_line(dr, x1, y1, x2, y2, line_colour);
3294 } else { 3372 } else {
3295 draw_thick_line(dr, 3.0, 3373 draw_thick_line(dr, ds->tilesize*3/32.0,
3296 x1 + 0.5, y1 + 0.5, 3374 x1 + 0.5, y1 + 0.5,
3297 x2 + 0.5, y2 + 0.5, 3375 x2 + 0.5, y2 + 0.5,
3298 line_colour); 3376 line_colour);
@@ -3303,11 +3381,11 @@ static void game_redraw_dot(drawing *dr, game_drawstate *ds,
3303 const game_state *state, int i) 3381 const game_state *state, int i)
3304{ 3382{
3305 grid *g = state->game_grid; 3383 grid *g = state->game_grid;
3306 grid_dot *d = g->dots + i; 3384 grid_dot *d = g->dots[i];
3307 int x, y; 3385 int x, y;
3308 3386
3309 grid_to_screen(ds, g, d->x, d->y, &x, &y); 3387 grid_to_screen(ds, g, d->x, d->y, &x, &y);
3310 draw_circle(dr, x, y, 2, COL_FOREGROUND, COL_FOREGROUND); 3388 draw_circle(dr, x, y, ds->tilesize*2.5/32.0, COL_FOREGROUND, COL_FOREGROUND);
3311} 3389}
3312 3390
3313static bool boxes_intersect(int x0, int y0, int w0, int h0, 3391static bool boxes_intersect(int x0, int y0, int w0, int h0,
@@ -3322,7 +3400,7 @@ static bool boxes_intersect(int x0, int y0, int w0, int h0,
3322} 3400}
3323 3401
3324static void game_redraw_in_rect(drawing *dr, game_drawstate *ds, 3402static void game_redraw_in_rect(drawing *dr, game_drawstate *ds,
3325 const game_state *state, 3403 const game_ui *ui, const game_state *state,
3326 int x, int y, int w, int h) 3404 int x, int y, int w, int h)
3327{ 3405{
3328 grid *g = state->game_grid; 3406 grid *g = state->game_grid;
@@ -3334,20 +3412,20 @@ static void game_redraw_in_rect(drawing *dr, game_drawstate *ds,
3334 3412
3335 for (i = 0; i < g->num_faces; i++) { 3413 for (i = 0; i < g->num_faces; i++) {
3336 if (state->clues[i] >= 0) { 3414 if (state->clues[i] >= 0) {
3337 face_text_bbox(ds, g, &g->faces[i], &bx, &by, &bw, &bh); 3415 face_text_bbox(ds, g, g->faces[i], &bx, &by, &bw, &bh);
3338 if (boxes_intersect(x, y, w, h, bx, by, bw, bh)) 3416 if (boxes_intersect(x, y, w, h, bx, by, bw, bh))
3339 game_redraw_clue(dr, ds, state, i); 3417 game_redraw_clue(dr, ds, state, i);
3340 } 3418 }
3341 } 3419 }
3342 for (phase = 0; phase < NPHASES; phase++) { 3420 for (phase = 0; phase < NPHASES; phase++) {
3343 for (i = 0; i < g->num_edges; i++) { 3421 for (i = 0; i < g->num_edges; i++) {
3344 edge_bbox(ds, g, &g->edges[i], &bx, &by, &bw, &bh); 3422 edge_bbox(ds, g, g->edges[i], &bx, &by, &bw, &bh);
3345 if (boxes_intersect(x, y, w, h, bx, by, bw, bh)) 3423 if (boxes_intersect(x, y, w, h, bx, by, bw, bh))
3346 game_redraw_line(dr, ds, state, i, phase); 3424 game_redraw_line(dr, ds, ui, state, i, phase);
3347 } 3425 }
3348 } 3426 }
3349 for (i = 0; i < g->num_dots; i++) { 3427 for (i = 0; i < g->num_dots; i++) {
3350 dot_bbox(ds, g, &g->dots[i], &bx, &by, &bw, &bh); 3428 dot_bbox(ds, g, g->dots[i], &bx, &by, &bw, &bh);
3351 if (boxes_intersect(x, y, w, h, bx, by, bw, bh)) 3429 if (boxes_intersect(x, y, w, h, bx, by, bw, bh))
3352 game_redraw_dot(dr, ds, state, i); 3430 game_redraw_dot(dr, ds, state, i);
3353 } 3431 }
@@ -3407,7 +3485,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
3407 3485
3408 /* First, trundle through the faces. */ 3486 /* First, trundle through the faces. */
3409 for (i = 0; i < g->num_faces; i++) { 3487 for (i = 0; i < g->num_faces; i++) {
3410 grid_face *f = g->faces + i; 3488 grid_face *f = g->faces[i];
3411 int sides = f->order; 3489 int sides = f->order;
3412 int yes_order, no_order; 3490 int yes_order, no_order;
3413 bool clue_mistake; 3491 bool clue_mistake;
@@ -3500,26 +3578,26 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
3500 int w = grid_width * ds->tilesize / g->tilesize; 3578 int w = grid_width * ds->tilesize / g->tilesize;
3501 int h = grid_height * ds->tilesize / g->tilesize; 3579 int h = grid_height * ds->tilesize / g->tilesize;
3502 3580
3503 game_redraw_in_rect(dr, ds, state, 3581 game_redraw_in_rect(dr, ds, ui, state,
3504 0, 0, w + 2*border + 1, h + 2*border + 1); 3582 0, 0, w + 2*border + 1, h + 2*border + 1);
3505 } else { 3583 } else {
3506 3584
3507 /* Right. Now we roll up our sleeves. */ 3585 /* Right. Now we roll up our sleeves. */
3508 3586
3509 for (i = 0; i < nfaces; i++) { 3587 for (i = 0; i < nfaces; i++) {
3510 grid_face *f = g->faces + faces[i]; 3588 grid_face *f = g->faces[faces[i]];
3511 int x, y, w, h; 3589 int x, y, w, h;
3512 3590
3513 face_text_bbox(ds, g, f, &x, &y, &w, &h); 3591 face_text_bbox(ds, g, f, &x, &y, &w, &h);
3514 game_redraw_in_rect(dr, ds, state, x, y, w, h); 3592 game_redraw_in_rect(dr, ds, ui, state, x, y, w, h);
3515 } 3593 }
3516 3594
3517 for (i = 0; i < nedges; i++) { 3595 for (i = 0; i < nedges; i++) {
3518 grid_edge *e = g->edges + edges[i]; 3596 grid_edge *e = g->edges[edges[i]];
3519 int x, y, w, h; 3597 int x, y, w, h;
3520 3598
3521 edge_bbox(ds, g, e, &x, &y, &w, &h); 3599 edge_bbox(ds, g, e, &x, &y, &w, &h);
3522 game_redraw_in_rect(dr, ds, state, x, y, w, h); 3600 game_redraw_in_rect(dr, ds, ui, state, x, y, w, h);
3523 } 3601 }
3524 } 3602 }
3525 3603
@@ -3550,19 +3628,21 @@ static int game_status(const game_state *state)
3550 return state->solved ? +1 : 0; 3628 return state->solved ? +1 : 0;
3551} 3629}
3552 3630
3553static void game_print_size(const game_params *params, float *x, float *y) 3631static void game_print_size(const game_params *params, const game_ui *ui,
3632 float *x, float *y)
3554{ 3633{
3555 int pw, ph; 3634 int pw, ph;
3556 3635
3557 /* 3636 /*
3558 * I'll use 7mm "squares" by default. 3637 * I'll use 7mm "squares" by default.
3559 */ 3638 */
3560 game_compute_size(params, 700, &pw, &ph); 3639 game_compute_size(params, 700, ui, &pw, &ph);
3561 *x = pw / 100.0F; 3640 *x = pw / 100.0F;
3562 *y = ph / 100.0F; 3641 *y = ph / 100.0F;
3563} 3642}
3564 3643
3565static void game_print(drawing *dr, const game_state *state, int tilesize) 3644static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
3645 int tilesize)
3566{ 3646{
3567 int ink = print_mono_colour(dr, 0); 3647 int ink = print_mono_colour(dr, 0);
3568 int i; 3648 int i;
@@ -3577,7 +3657,7 @@ static void game_print(drawing *dr, const game_state *state, int tilesize)
3577 3657
3578 for (i = 0; i < g->num_dots; i++) { 3658 for (i = 0; i < g->num_dots; i++) {
3579 int x, y; 3659 int x, y;
3580 grid_to_screen(ds, g, g->dots[i].x, g->dots[i].y, &x, &y); 3660 grid_to_screen(ds, g, g->dots[i]->x, g->dots[i]->y, &x, &y);
3581 draw_circle(dr, x, y, ds->tilesize / 15, ink, ink); 3661 draw_circle(dr, x, y, ds->tilesize / 15, ink, ink);
3582 } 3662 }
3583 3663
@@ -3585,7 +3665,7 @@ static void game_print(drawing *dr, const game_state *state, int tilesize)
3585 * Clues. 3665 * Clues.
3586 */ 3666 */
3587 for (i = 0; i < g->num_faces; i++) { 3667 for (i = 0; i < g->num_faces; i++) {
3588 grid_face *f = g->faces + i; 3668 grid_face *f = g->faces[i];
3589 int clue = state->clues[i]; 3669 int clue = state->clues[i];
3590 if (clue >= 0) { 3670 if (clue >= 0) {
3591 char c[20]; 3671 char c[20];
@@ -3603,7 +3683,7 @@ static void game_print(drawing *dr, const game_state *state, int tilesize)
3603 */ 3683 */
3604 for (i = 0; i < g->num_edges; i++) { 3684 for (i = 0; i < g->num_edges; i++) {
3605 int thickness = (state->lines[i] == LINE_YES) ? 30 : 150; 3685 int thickness = (state->lines[i] == LINE_YES) ? 30 : 150;
3606 grid_edge *e = g->edges + i; 3686 grid_edge *e = g->edges[i];
3607 int x1, y1, x2, y2; 3687 int x1, y1, x2, y2;
3608 grid_to_screen(ds, g, e->dot1->x, e->dot1->y, &x1, &y1); 3688 grid_to_screen(ds, g, e->dot1->x, e->dot1->y, &x1, &y1);
3609 grid_to_screen(ds, g, e->dot2->x, e->dot2->y, &x2, &y2); 3689 grid_to_screen(ds, g, e->dot2->x, e->dot2->y, &x2, &y2);
@@ -3666,14 +3746,16 @@ const struct game thegame = {
3666 new_game, 3746 new_game,
3667 dup_game, 3747 dup_game,
3668 free_game, 3748 free_game,
3669 1, solve_game, 3749 true, solve_game,
3670 true, game_can_format_as_text_now, game_text_format, 3750 true, game_can_format_as_text_now, game_text_format,
3751 get_prefs, set_prefs,
3671 new_ui, 3752 new_ui,
3672 free_ui, 3753 free_ui,
3673 encode_ui, 3754 NULL, /* encode_ui */
3674 decode_ui, 3755 NULL, /* decode_ui */
3675 NULL, /* game_request_keys */ 3756 NULL, /* game_request_keys */
3676 game_changed_state, 3757 game_changed_state,
3758 NULL, /* current_key_label */
3677 interpret_move, 3759 interpret_move,
3678 execute_move, 3760 execute_move,
3679 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 3761 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -3687,7 +3769,7 @@ const struct game thegame = {
3687 game_status, 3769 game_status,
3688 true, false, game_print_size, game_print, 3770 true, false, game_print_size, game_print,
3689 false /* wants_statusbar */, 3771 false /* wants_statusbar */,
3690 false, game_timing_state, 3772 false, NULL, /* timing_state */
3691 0, /* mouse_priorities */ 3773 0, /* mouse_priorities */
3692}; 3774};
3693 3775
diff --git a/apps/plugins/puzzles/src/magnets.R b/apps/plugins/puzzles/src/magnets.R
deleted file mode 100644
index e55e4746ee..0000000000
--- a/apps/plugins/puzzles/src/magnets.R
+++ /dev/null
@@ -1,24 +0,0 @@
1# -*- makefile -*-
2
3MAGNETS_EXTRA = laydomino
4
5magnets : [X] GTK COMMON magnets MAGNETS_EXTRA magnets-icon|no-icon
6
7magnets : [G] WINDOWS COMMON magnets MAGNETS_EXTRA magnets.res|noicon.res
8
9magnetssolver : [U] magnets[STANDALONE_SOLVER] MAGNETS_EXTRA STANDALONE m.lib
10magnetssolver : [C] magnets[STANDALONE_SOLVER] MAGNETS_EXTRA STANDALONE
11
12ALL += magnets[COMBINED] MAGNETS_EXTRA
13
14!begin am gtk
15GAMES += magnets
16!end
17
18!begin >list.c
19 A(magnets) \
20!end
21
22!begin >gamedesc.txt
23magnets:magnets.exe:Magnets:Magnet-placing puzzle:Place magnets to satisfy the clues and avoid like poles touching.
24!end
diff --git a/apps/plugins/puzzles/src/magnets.c b/apps/plugins/puzzles/src/magnets.c
index edbb8490ad..7cb5fbc919 100644
--- a/apps/plugins/puzzles/src/magnets.c
+++ b/apps/plugins/puzzles/src/magnets.c
@@ -36,12 +36,17 @@
36#include <string.h> 36#include <string.h>
37#include <assert.h> 37#include <assert.h>
38#include <ctype.h> 38#include <ctype.h>
39#include <math.h> 39#include <limits.h>
40#ifdef NO_TGMATH_H
41# include <math.h>
42#else
43# include <tgmath.h>
44#endif
40 45
41#include "puzzles.h" 46#include "puzzles.h"
42 47
43#ifdef STANDALONE_SOLVER 48#ifdef STANDALONE_SOLVER
44bool verbose = 0; 49static bool verbose = false;
45#endif 50#endif
46 51
47enum { 52enum {
@@ -230,8 +235,17 @@ static game_params *custom_params(const config_item *cfg)
230 235
231static const char *validate_params(const game_params *params, bool full) 236static const char *validate_params(const game_params *params, bool full)
232{ 237{
233 if (params->w < 2) return "Width must be at least one"; 238 if (params->w < 2) return "Width must be at least two";
234 if (params->h < 2) return "Height must be at least one"; 239 if (params->h < 2) return "Height must be at least two";
240 if (params->w > INT_MAX / params->h)
241 return "Width times height must not be unreasonably large";
242 if (params->diff >= DIFF_TRICKY) {
243 if (params->w < 5 && params->h < 5)
244 return "Either width or height must be at least five for Tricky";
245 } else {
246 if (params->w < 3 && params->h < 3)
247 return "Either width or height must be at least three";
248 }
235 if (params->diff < 0 || params->diff >= DIFFCOUNT) 249 if (params->diff < 0 || params->diff >= DIFFCOUNT)
236 return "Unknown difficulty level"; 250 return "Unknown difficulty level";
237 251
@@ -510,7 +524,9 @@ nextchar:
510 * (i.e. each end points to the other) */ 524 * (i.e. each end points to the other) */
511 for (idx = 0; idx < state->wh; idx++) { 525 for (idx = 0; idx < state->wh; idx++) {
512 if (state->common->dominoes[idx] < 0 || 526 if (state->common->dominoes[idx] < 0 ||
513 state->common->dominoes[idx] > state->wh || 527 state->common->dominoes[idx] >= state->wh ||
528 (state->common->dominoes[idx] % state->w != idx % state->w &&
529 state->common->dominoes[idx] / state->w != idx / state->w) ||
514 state->common->dominoes[state->common->dominoes[idx]] != idx) { 530 state->common->dominoes[state->common->dominoes[idx]] != idx) {
515 *prob = "Domino descriptions inconsistent"; 531 *prob = "Domino descriptions inconsistent";
516 goto done; 532 goto done;
@@ -541,7 +557,7 @@ static const char *validate_desc(const game_params *params, const char *desc)
541{ 557{
542 const char *prob; 558 const char *prob;
543 game_state *st = new_game_int(params, desc, &prob); 559 game_state *st = new_game_int(params, desc, &prob);
544 if (!st) return (char*)prob; 560 if (!st) return prob;
545 free_game(st); 561 free_game(st);
546 return NULL; 562 return NULL;
547} 563}
@@ -1574,6 +1590,7 @@ static int lay_dominoes(game_state *state, random_state *rs, int *scratch)
1574 } 1590 }
1575 1591
1576 debug(("Laid %d dominoes, total %d dominoes.\n", nlaid, state->wh/2)); 1592 debug(("Laid %d dominoes, total %d dominoes.\n", nlaid, state->wh/2));
1593 (void)nlaid;
1577 game_debug(state, "Final layout"); 1594 game_debug(state, "Final layout");
1578 return ret; 1595 return ret;
1579} 1596}
@@ -1720,7 +1737,7 @@ static game_ui *new_ui(const game_state *state)
1720{ 1737{
1721 game_ui *ui = snew(game_ui); 1738 game_ui *ui = snew(game_ui);
1722 ui->cur_x = ui->cur_y = 0; 1739 ui->cur_x = ui->cur_y = 0;
1723 ui->cur_visible = false; 1740 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1724 return ui; 1741 return ui;
1725} 1742}
1726 1743
@@ -1729,15 +1746,6 @@ static void free_ui(game_ui *ui)
1729 sfree(ui); 1746 sfree(ui);
1730} 1747}
1731 1748
1732static char *encode_ui(const game_ui *ui)
1733{
1734 return NULL;
1735}
1736
1737static void decode_ui(game_ui *ui, const char *encoding)
1738{
1739}
1740
1741static void game_changed_state(game_ui *ui, const game_state *oldstate, 1749static void game_changed_state(game_ui *ui, const game_state *oldstate,
1742 const game_state *newstate) 1750 const game_state *newstate)
1743{ 1751{
@@ -1745,6 +1753,36 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1745 ui->cur_visible = false; 1753 ui->cur_visible = false;
1746} 1754}
1747 1755
1756static const char *current_key_label(const game_ui *ui,
1757 const game_state *state, int button)
1758{
1759 int idx;
1760
1761 if (IS_CURSOR_SELECT(button)) {
1762 if (!ui->cur_visible) return "";
1763 idx = ui->cur_y * state->w + ui->cur_x;
1764 if (button == CURSOR_SELECT) {
1765 if (state->grid[idx] == NEUTRAL && state->flags[idx] & GS_SET)
1766 return "";
1767 switch (state->grid[idx]) {
1768 case EMPTY: return "+";
1769 case POSITIVE: return "-";
1770 case NEGATIVE: return "Clear";
1771 }
1772 }
1773 if (button == CURSOR_SELECT2) {
1774 if (state->grid[idx] != NEUTRAL) return "";
1775 if (state->flags[idx] & GS_SET) /* neutral */
1776 return "?";
1777 if (state->flags[idx] & GS_NOTNEUTRAL) /* !neutral */
1778 return "Clear";
1779 else
1780 return "X";
1781 }
1782 }
1783 return "";
1784}
1785
1748struct game_drawstate { 1786struct game_drawstate {
1749 int tilesize; 1787 int tilesize;
1750 bool started, solved; 1788 bool started, solved;
@@ -1805,14 +1843,13 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1805 char *nullret = NULL, buf[80], movech; 1843 char *nullret = NULL, buf[80], movech;
1806 enum { CYCLE_MAGNET, CYCLE_NEUTRAL } action; 1844 enum { CYCLE_MAGNET, CYCLE_NEUTRAL } action;
1807 1845
1808 if (IS_CURSOR_MOVE(button)) { 1846 if (IS_CURSOR_MOVE(button))
1809 move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h, false); 1847 return move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h,
1810 ui->cur_visible = true; 1848 false, &ui->cur_visible);
1811 return UI_UPDATE; 1849 else if (IS_CURSOR_SELECT(button)) {
1812 } else if (IS_CURSOR_SELECT(button)) {
1813 if (!ui->cur_visible) { 1850 if (!ui->cur_visible) {
1814 ui->cur_visible = true; 1851 ui->cur_visible = true;
1815 return UI_UPDATE; 1852 return MOVE_UI_UPDATE;
1816 } 1853 }
1817 action = (button == CURSOR_SELECT) ? CYCLE_MAGNET : CYCLE_NEUTRAL; 1854 action = (button == CURSOR_SELECT) ? CYCLE_MAGNET : CYCLE_NEUTRAL;
1818 gx = ui->cur_x; 1855 gx = ui->cur_x;
@@ -1821,7 +1858,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1821 (button == LEFT_BUTTON || button == RIGHT_BUTTON)) { 1858 (button == LEFT_BUTTON || button == RIGHT_BUTTON)) {
1822 if (ui->cur_visible) { 1859 if (ui->cur_visible) {
1823 ui->cur_visible = false; 1860 ui->cur_visible = false;
1824 nullret = UI_UPDATE; 1861 nullret = MOVE_UI_UPDATE;
1825 } 1862 }
1826 action = (button == LEFT_BUTTON) ? CYCLE_MAGNET : CYCLE_NEUTRAL; 1863 action = (button == LEFT_BUTTON) ? CYCLE_MAGNET : CYCLE_NEUTRAL;
1827 } else if (button == LEFT_BUTTON && is_clue(state, gx, gy)) { 1864 } else if (button == LEFT_BUTTON && is_clue(state, gx, gy)) {
@@ -1928,7 +1965,7 @@ badmove:
1928 */ 1965 */
1929 1966
1930static void game_compute_size(const game_params *params, int tilesize, 1967static void game_compute_size(const game_params *params, int tilesize,
1931 int *x, int *y) 1968 const game_ui *ui, int *x, int *y)
1932{ 1969{
1933 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 1970 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1934 struct { int tilesize; } ads, *ds = &ads; 1971 struct { int tilesize; } ads, *ds = &ads;
@@ -2205,12 +2242,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2205 flash = (int)(flashtime * 5 / FLASH_TIME) % 2; 2242 flash = (int)(flashtime * 5 / FLASH_TIME) % 2;
2206 2243
2207 if (!ds->started) { 2244 if (!ds->started) {
2208 /* draw background, corner +-. */ 2245 /* draw corner +-. */
2209 draw_rect(dr, 0, 0,
2210 TILE_SIZE * (w+2) + 2 * BORDER,
2211 TILE_SIZE * (h+2) + 2 * BORDER,
2212 COL_BACKGROUND);
2213
2214 draw_sym(dr, ds, -1, -1, POSITIVE, COL_TEXT); 2246 draw_sym(dr, ds, -1, -1, POSITIVE, COL_TEXT);
2215 draw_sym(dr, ds, state->w, state->h, NEGATIVE, COL_TEXT); 2247 draw_sym(dr, ds, state->w, state->h, NEGATIVE, COL_TEXT);
2216 2248
@@ -2309,24 +2341,21 @@ static int game_status(const game_state *state)
2309 return state->completed ? +1 : 0; 2341 return state->completed ? +1 : 0;
2310} 2342}
2311 2343
2312static bool game_timing_state(const game_state *state, game_ui *ui) 2344static void game_print_size(const game_params *params, const game_ui *ui,
2313{ 2345 float *x, float *y)
2314 return true;
2315}
2316
2317static void game_print_size(const game_params *params, float *x, float *y)
2318{ 2346{
2319 int pw, ph; 2347 int pw, ph;
2320 2348
2321 /* 2349 /*
2322 * I'll use 6mm squares by default. 2350 * I'll use 6mm squares by default.
2323 */ 2351 */
2324 game_compute_size(params, 600, &pw, &ph); 2352 game_compute_size(params, 600, ui, &pw, &ph);
2325 *x = pw / 100.0F; 2353 *x = pw / 100.0F;
2326 *y = ph / 100.0F; 2354 *y = ph / 100.0F;
2327} 2355}
2328 2356
2329static void game_print(drawing *dr, const game_state *state, int tilesize) 2357static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2358 int tilesize)
2330{ 2359{
2331 int w = state->w, h = state->h; 2360 int w = state->w, h = state->h;
2332 int ink = print_mono_colour(dr, 0); 2361 int ink = print_mono_colour(dr, 0);
@@ -2430,12 +2459,14 @@ const struct game thegame = {
2430 free_game, 2459 free_game,
2431 true, solve_game, 2460 true, solve_game,
2432 true, game_can_format_as_text_now, game_text_format, 2461 true, game_can_format_as_text_now, game_text_format,
2462 NULL, NULL, /* get_prefs, set_prefs */
2433 new_ui, 2463 new_ui,
2434 free_ui, 2464 free_ui,
2435 encode_ui, 2465 NULL, /* encode_ui */
2436 decode_ui, 2466 NULL, /* decode_ui */
2437 NULL, /* game_request_keys */ 2467 NULL, /* game_request_keys */
2438 game_changed_state, 2468 game_changed_state,
2469 current_key_label,
2439 interpret_move, 2470 interpret_move,
2440 execute_move, 2471 execute_move,
2441 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 2472 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -2449,7 +2480,7 @@ const struct game thegame = {
2449 game_status, 2480 game_status,
2450 true, false, game_print_size, game_print, 2481 true, false, game_print_size, game_print,
2451 false, /* wants_statusbar */ 2482 false, /* wants_statusbar */
2452 false, game_timing_state, 2483 false, NULL, /* timing_state */
2453 REQUIRE_RBUTTON, /* flags */ 2484 REQUIRE_RBUTTON, /* flags */
2454}; 2485};
2455 2486
@@ -2458,14 +2489,14 @@ const struct game thegame = {
2458#include <time.h> 2489#include <time.h>
2459#include <stdarg.h> 2490#include <stdarg.h>
2460 2491
2461const char *quis = NULL; 2492static const char *quis = NULL;
2462bool csv = false; 2493static bool csv = false;
2463 2494
2464void usage(FILE *out) { 2495static void usage(FILE *out) {
2465 fprintf(out, "usage: %s [-v] [--print] <params>|<game id>\n", quis); 2496 fprintf(out, "usage: %s [-v] [--print] <params>|<game id>\n", quis);
2466} 2497}
2467 2498
2468void doprint(game_state *state) 2499static void doprint(game_state *state)
2469{ 2500{
2470 char *fmt = game_text_format(state); 2501 char *fmt = game_text_format(state);
2471 printf("%s", fmt); 2502 printf("%s", fmt);
@@ -2559,7 +2590,7 @@ static void start_soak(game_params *p, random_state *rs)
2559 sfree(aux); 2590 sfree(aux);
2560} 2591}
2561 2592
2562int main(int argc, const char *argv[]) 2593int main(int argc, char *argv[])
2563{ 2594{
2564 bool print = false, soak = false, solved = false; 2595 bool print = false, soak = false, solved = false;
2565 int ret; 2596 int ret;
@@ -2608,7 +2639,7 @@ int main(int argc, const char *argv[])
2608 decode_params(p, id); 2639 decode_params(p, id);
2609 err = validate_params(p, true); 2640 err = validate_params(p, true);
2610 if (err) { 2641 if (err) {
2611 fprintf(stderr, "%s: %s", argv[0], err); 2642 fprintf(stderr, "%s: %s\n", argv[0], err);
2612 goto done; 2643 goto done;
2613 } 2644 }
2614 2645
diff --git a/apps/plugins/puzzles/src/malloc.c b/apps/plugins/puzzles/src/malloc.c
index a7fa7c5adc..39bcfac25b 100644
--- a/apps/plugins/puzzles/src/malloc.c
+++ b/apps/plugins/puzzles/src/malloc.c
@@ -2,16 +2,23 @@
2 * malloc.c: safe wrappers around malloc, realloc, free, strdup 2 * malloc.c: safe wrappers around malloc, realloc, free, strdup
3 */ 3 */
4 4
5#ifndef NO_STDINT_H
6#include <stdint.h>
7#endif
5#include <stdlib.h> 8#include <stdlib.h>
6#include <string.h> 9#include <string.h>
7#include "puzzles.h" 10#include "puzzles.h"
8 11
9/* 12/*
10 * smalloc should guarantee to return a useful pointer - Halibut 13 * smalloc should guarantee to return a useful pointer - we
11 * can do nothing except die when it's out of memory anyway. 14 * can do nothing except die when it's out of memory anyway.
12 */ 15 */
13void *smalloc(size_t size) { 16void *smalloc(size_t size) {
14 void *p; 17 void *p;
18#ifdef PTRDIFF_MAX
19 if (size > PTRDIFF_MAX)
20 fatal("allocation too large");
21#endif
15 p = malloc(size); 22 p = malloc(size);
16 if (!p) 23 if (!p)
17 fatal("out of memory"); 24 fatal("out of memory");
@@ -32,6 +39,10 @@ void sfree(void *p) {
32 */ 39 */
33void *srealloc(void *p, size_t size) { 40void *srealloc(void *p, size_t size) {
34 void *q; 41 void *q;
42#ifdef PTRDIFF_MAX
43 if (size > PTRDIFF_MAX)
44 fatal("allocation too large");
45#endif
35 if (p) { 46 if (p) {
36 q = realloc(p, size); 47 q = realloc(p, size);
37 } else { 48 } else {
diff --git a/apps/plugins/puzzles/src/map.R b/apps/plugins/puzzles/src/map.R
deleted file mode 100644
index 1e702aa19d..0000000000
--- a/apps/plugins/puzzles/src/map.R
+++ /dev/null
@@ -1,24 +0,0 @@
1# -*- makefile -*-
2
3MAP_EXTRA = dsf
4
5map : [X] GTK COMMON map MAP_EXTRA map-icon|no-icon
6
7map : [G] WINDOWS COMMON map MAP_EXTRA map.res|noicon.res
8
9mapsolver : [U] map[STANDALONE_SOLVER] MAP_EXTRA STANDALONE m.lib
10mapsolver : [C] map[STANDALONE_SOLVER] MAP_EXTRA STANDALONE
11
12ALL += map[COMBINED] MAP_EXTRA
13
14!begin am gtk
15GAMES += map
16!end
17
18!begin >list.c
19 A(map) \
20!end
21
22!begin >gamedesc.txt
23map:map.exe:Map:Map-colouring puzzle:Colour the map so that adjacent regions are never the same colour.
24!end
diff --git a/apps/plugins/puzzles/src/map.c b/apps/plugins/puzzles/src/map.c
index 9df2d22b52..9cea0d4647 100644
--- a/apps/plugins/puzzles/src/map.c
+++ b/apps/plugins/puzzles/src/map.c
@@ -14,7 +14,12 @@
14#include <string.h> 14#include <string.h>
15#include <assert.h> 15#include <assert.h>
16#include <ctype.h> 16#include <ctype.h>
17#include <math.h> 17#include <limits.h>
18#ifdef NO_TGMATH_H
19# include <math.h>
20#else
21# include <tgmath.h>
22#endif
18 23
19#include "puzzles.h" 24#include "puzzles.h"
20 25
@@ -25,7 +30,7 @@
25 */ 30 */
26#if defined STANDALONE_SOLVER 31#if defined STANDALONE_SOLVER
27#define SOLVER_DIAGNOSTICS 32#define SOLVER_DIAGNOSTICS
28bool verbose = false; 33static bool verbose = false;
29#elif defined SOLVER_DIAGNOSTICS 34#elif defined SOLVER_DIAGNOSTICS
30#define verbose true 35#define verbose true
31#endif 36#endif
@@ -41,12 +46,6 @@ bool verbose = false;
41#define SIX (FOUR+2) 46#define SIX (FOUR+2)
42 47
43/* 48/*
44 * Ghastly run-time configuration option, just for Gareth (again).
45 */
46static int flash_type = -1;
47static float flash_length;
48
49/*
50 * Difficulty levels. I do some macro ickery here to ensure that my 49 * Difficulty levels. I do some macro ickery here to ensure that my
51 * enum and the various forms of my name list always match up. 50 * enum and the various forms of my name list always match up.
52 */ 51 */
@@ -180,7 +179,9 @@ static void decode_params(game_params *params, char const *string)
180 params->n = atoi(p); 179 params->n = atoi(p);
181 while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++; 180 while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++;
182 } else { 181 } else {
183 params->n = params->w * params->h / 8; 182 if (params->h > 0 && params->w > 0 &&
183 params->w <= INT_MAX / params->h)
184 params->n = params->w * params->h / 8;
184 } 185 }
185 if (*p == 'd') { 186 if (*p == 'd') {
186 int i; 187 int i;
@@ -252,6 +253,8 @@ static const char *validate_params(const game_params *params, bool full)
252{ 253{
253 if (params->w < 2 || params->h < 2) 254 if (params->w < 2 || params->h < 2)
254 return "Width and height must be at least two"; 255 return "Width and height must be at least two";
256 if (params->w > INT_MAX / 2 / params->h)
257 return "Width times height must not be unreasonably large";
255 if (params->n < 5) 258 if (params->n < 5)
256 return "Must have at least five regions"; 259 return "Must have at least five regions";
257 if (params->n > params->w * params->h) 260 if (params->n > params->w * params->h)
@@ -1659,6 +1662,10 @@ static char *new_game_desc(const game_params *params, random_state *rs,
1659 } 1662 }
1660 } 1663 }
1661 1664
1665 if (retlen + 10 >= retsize) {
1666 retsize = retlen + 256;
1667 ret = sresize(ret, retsize, char);
1668 }
1662 ret[retlen++] = 'a'-1 + run; 1669 ret[retlen++] = 'a'-1 + run;
1663 ret[retlen++] = ','; 1670 ret[retlen++] = ',';
1664 1671
@@ -1711,8 +1718,8 @@ static const char *parse_edge_list(const game_params *params,
1711 int i, k, pos; 1718 int i, k, pos;
1712 bool state; 1719 bool state;
1713 const char *p = *desc; 1720 const char *p = *desc;
1714 1721 const char *err = NULL;
1715 dsf_init(map+wh, wh); 1722 DSF *dsf = dsf_new(wh);
1716 1723
1717 pos = -1; 1724 pos = -1;
1718 state = false; 1725 state = false;
@@ -1723,8 +1730,10 @@ static const char *parse_edge_list(const game_params *params,
1723 * pairs of squares whenever the edge list shows a non-edge). 1730 * pairs of squares whenever the edge list shows a non-edge).
1724 */ 1731 */
1725 while (*p && *p != ',') { 1732 while (*p && *p != ',') {
1726 if (*p < 'a' || *p > 'z') 1733 if (*p < 'a' || *p > 'z') {
1727 return "Unexpected character in edge list"; 1734 err = "Unexpected character in edge list";
1735 goto out;
1736 }
1728 if (*p == 'z') 1737 if (*p == 'z')
1729 k = 25; 1738 k = 25;
1730 else 1739 else
@@ -1747,10 +1756,12 @@ static const char *parse_edge_list(const game_params *params,
1747 y = (pos - w*(h-1)) % h; 1756 y = (pos - w*(h-1)) % h;
1748 dx = 1; 1757 dx = 1;
1749 dy = 0; 1758 dy = 0;
1750 } else 1759 } else {
1751 return "Too much data in edge list"; 1760 err = "Too much data in edge list";
1761 goto out;
1762 }
1752 if (!state) 1763 if (!state)
1753 dsf_merge(map+wh, y*w+x, (y+dy)*w+(x+dx)); 1764 dsf_merge(dsf, y*w+x, (y+dy)*w+(x+dx));
1754 1765
1755 pos++; 1766 pos++;
1756 } 1767 }
@@ -1759,8 +1770,10 @@ static const char *parse_edge_list(const game_params *params,
1759 p++; 1770 p++;
1760 } 1771 }
1761 assert(pos <= 2*wh-w-h); 1772 assert(pos <= 2*wh-w-h);
1762 if (pos < 2*wh-w-h) 1773 if (pos < 2*wh-w-h) {
1763 return "Too little data in edge list"; 1774 err = "Too little data in edge list";
1775 goto out;
1776 }
1764 1777
1765 /* 1778 /*
1766 * Now go through again and allocate region numbers. 1779 * Now go through again and allocate region numbers.
@@ -1769,17 +1782,22 @@ static const char *parse_edge_list(const game_params *params,
1769 for (i = 0; i < wh; i++) 1782 for (i = 0; i < wh; i++)
1770 map[i] = -1; 1783 map[i] = -1;
1771 for (i = 0; i < wh; i++) { 1784 for (i = 0; i < wh; i++) {
1772 k = dsf_canonify(map+wh, i); 1785 k = dsf_canonify(dsf, i);
1773 if (map[k] < 0) 1786 if (map[k] < 0)
1774 map[k] = pos++; 1787 map[k] = pos++;
1775 map[i] = map[k]; 1788 map[i] = map[k];
1776 } 1789 }
1777 if (pos != n) 1790 if (pos != n) {
1778 return "Edge list defines the wrong number of regions"; 1791 err = "Edge list defines the wrong number of regions";
1792 goto out;
1793 }
1779 1794
1780 *desc = p; 1795 *desc = p;
1796 err = NULL; /* no error */
1781 1797
1782 return NULL; 1798 out:
1799 dsf_free(dsf);
1800 return err;
1783} 1801}
1784 1802
1785static const char *validate_desc(const game_params *params, const char *desc) 1803static const char *validate_desc(const game_params *params, const char *desc)
@@ -1789,7 +1807,7 @@ static const char *validate_desc(const game_params *params, const char *desc)
1789 int *map; 1807 int *map;
1790 const char *ret; 1808 const char *ret;
1791 1809
1792 map = snewn(2*wh, int); 1810 map = snewn(wh, int);
1793 ret = parse_edge_list(params, &desc, map); 1811 ret = parse_edge_list(params, &desc, map);
1794 sfree(map); 1812 sfree(map);
1795 if (ret) 1813 if (ret)
@@ -2252,16 +2270,6 @@ static char *solve_game(const game_state *state, const game_state *currstate,
2252 return dupstr(aux); 2270 return dupstr(aux);
2253} 2271}
2254 2272
2255static bool game_can_format_as_text_now(const game_params *params)
2256{
2257 return true;
2258}
2259
2260static char *game_text_format(const game_state *state)
2261{
2262 return NULL;
2263}
2264
2265struct game_ui { 2273struct game_ui {
2266 /* 2274 /*
2267 * drag_colour: 2275 * drag_colour:
@@ -2275,11 +2283,41 @@ struct game_ui {
2275 int drag_pencil; 2283 int drag_pencil;
2276 int dragx, dragy; 2284 int dragx, dragy;
2277 bool show_numbers; 2285 bool show_numbers;
2286 bool large_stipples;
2278 2287
2279 int cur_x, cur_y, cur_lastmove; 2288 int cur_x, cur_y, cur_lastmove;
2280 bool cur_visible, cur_moved; 2289 bool cur_visible, cur_moved;
2290
2291 /*
2292 * User preference to enable alternative versions of the
2293 * completion flash. Some users have found the colour-cycling
2294 * default version to be a bit eye-twisting.
2295 */
2296 enum {
2297 FLASH_CYCLIC, /* cycle the four colours of the map */
2298 FLASH_EACH_TO_WHITE, /* turn each colour white in turn */
2299 FLASH_ALL_TO_WHITE /* flash the whole map to white in one go */
2300 } flash_type;
2281}; 2301};
2282 2302
2303static void legacy_prefs_override(struct game_ui *ui_out)
2304{
2305 static bool initialised = false;
2306 static int flash_type = -1;
2307
2308 if (!initialised) {
2309 char *env;
2310
2311 initialised = true;
2312
2313 if ((env = getenv("MAP_ALTERNATIVE_FLASH")) != NULL)
2314 flash_type = FLASH_EACH_TO_WHITE;
2315 }
2316
2317 if (flash_type != -1)
2318 ui_out->flash_type = flash_type;
2319}
2320
2283static game_ui *new_ui(const game_state *state) 2321static game_ui *new_ui(const game_state *state)
2284{ 2322{
2285 game_ui *ui = snew(game_ui); 2323 game_ui *ui = snew(game_ui);
@@ -2288,24 +2326,55 @@ static game_ui *new_ui(const game_state *state)
2288 ui->drag_pencil = 0; 2326 ui->drag_pencil = 0;
2289 ui->show_numbers = false; 2327 ui->show_numbers = false;
2290 ui->cur_x = ui->cur_y = 0; 2328 ui->cur_x = ui->cur_y = 0;
2291 ui->cur_visible = false; 2329 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
2292 ui->cur_moved = false; 2330 ui->cur_moved = false;
2293 ui->cur_lastmove = 0; 2331 ui->cur_lastmove = 0;
2332 ui->flash_type = FLASH_CYCLIC;
2333 legacy_prefs_override(ui);
2294 return ui; 2334 return ui;
2295} 2335}
2296 2336
2297static void free_ui(game_ui *ui) 2337static config_item *get_prefs(game_ui *ui)
2298{ 2338{
2299 sfree(ui); 2339 config_item *ret;
2340
2341 ret = snewn(4, config_item);
2342
2343 ret[0].name = "Victory flash effect";
2344 ret[0].kw = "flash-type";
2345 ret[0].type = C_CHOICES;
2346 ret[0].u.choices.choicenames = ":Cyclic:Each to white:All to white";
2347 ret[0].u.choices.choicekws = ":cyclic:each-white:all-white";
2348 ret[0].u.choices.selected = ui->flash_type;
2349
2350 ret[1].name = "Number regions";
2351 ret[1].kw = "show-numbers";
2352 ret[1].type = C_BOOLEAN;
2353 ret[1].u.boolean.bval = ui->show_numbers;
2354
2355 ret[2].name = "Display style for stipple marks";
2356 ret[2].kw = "stipple-style";
2357 ret[2].type = C_CHOICES;
2358 ret[2].u.choices.choicenames = ":Small:Large";
2359 ret[2].u.choices.choicekws = ":small:large";
2360 ret[2].u.choices.selected = ui->large_stipples;
2361
2362 ret[3].name = NULL;
2363 ret[3].type = C_END;
2364
2365 return ret;
2300} 2366}
2301 2367
2302static char *encode_ui(const game_ui *ui) 2368static void set_prefs(game_ui *ui, const config_item *cfg)
2303{ 2369{
2304 return NULL; 2370 ui->flash_type = cfg[0].u.choices.selected;
2371 ui->show_numbers = cfg[1].u.boolean.bval;
2372 ui->large_stipples = cfg[2].u.choices.selected;
2305} 2373}
2306 2374
2307static void decode_ui(game_ui *ui, const char *encoding) 2375static void free_ui(game_ui *ui)
2308{ 2376{
2377 sfree(ui);
2309} 2378}
2310 2379
2311static void game_changed_state(game_ui *ui, const game_state *oldstate, 2380static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -2388,6 +2457,26 @@ static int region_from_ui_cursor(const game_state *state, const game_ui *ui)
2388 EPSILON_Y(ui->cur_lastmove)); 2457 EPSILON_Y(ui->cur_lastmove));
2389} 2458}
2390 2459
2460static const char *current_key_label(const game_ui *ui,
2461 const game_state *state, int button)
2462{
2463 int r;
2464
2465 if (IS_CURSOR_SELECT(button) && ui->cur_visible) {
2466 if (ui->drag_colour == -2) return "Pick";
2467 r = region_from_ui_cursor(state, ui);
2468 if (state->map->immutable[r]) return "Cancel";
2469 if (!ui->cur_moved) return ui->drag_pencil ? "Cancel" : "Clear";
2470 if (button == CURSOR_SELECT2) {
2471 if (state->colouring[r] >= 0) return "Cancel";
2472 if (ui->drag_colour >= 0) return "Stipple";
2473 }
2474 if (ui->drag_pencil) return "Stipple";
2475 return ui->drag_colour >= 0 ? "Fill" : "Clear";
2476 }
2477 return "";
2478}
2479
2391static char *interpret_move(const game_state *state, game_ui *ui, 2480static char *interpret_move(const game_state *state, game_ui *ui,
2392 const game_drawstate *ds, 2481 const game_drawstate *ds,
2393 int x, int y, int button) 2482 int x, int y, int button)
@@ -2401,21 +2490,21 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2401 */ 2490 */
2402 if (button == 'l' || button == 'L') { 2491 if (button == 'l' || button == 'L') {
2403 ui->show_numbers = !ui->show_numbers; 2492 ui->show_numbers = !ui->show_numbers;
2404 return UI_UPDATE; 2493 return MOVE_UI_UPDATE;
2405 } 2494 }
2406 2495
2407 if (IS_CURSOR_MOVE(button)) { 2496 if (IS_CURSOR_MOVE(button)) {
2408 move_cursor(button, &ui->cur_x, &ui->cur_y, state->p.w, state->p.h, 2497 move_cursor(button, &ui->cur_x, &ui->cur_y, state->p.w, state->p.h,
2409 false); 2498 false, NULL);
2410 ui->cur_visible = true; 2499 ui->cur_visible = true;
2411 ui->cur_moved = true; 2500 ui->cur_moved = true;
2412 ui->cur_lastmove = button; 2501 ui->cur_lastmove = button;
2413 return UI_UPDATE; 2502 return MOVE_UI_UPDATE;
2414 } 2503 }
2415 if (IS_CURSOR_SELECT(button)) { 2504 if (IS_CURSOR_SELECT(button)) {
2416 if (!ui->cur_visible) { 2505 if (!ui->cur_visible) {
2417 ui->cur_visible = true; 2506 ui->cur_visible = true;
2418 return UI_UPDATE; 2507 return MOVE_UI_UPDATE;
2419 } 2508 }
2420 if (ui->drag_colour == -2) { /* not currently cursor-dragging, start. */ 2509 if (ui->drag_colour == -2) { /* not currently cursor-dragging, start. */
2421 int r = region_from_ui_cursor(state, ui); 2510 int r = region_from_ui_cursor(state, ui);
@@ -2427,7 +2516,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2427 ui->drag_pencil = 0; 2516 ui->drag_pencil = 0;
2428 } 2517 }
2429 ui->cur_moved = false; 2518 ui->cur_moved = false;
2430 return UI_UPDATE; 2519 return MOVE_UI_UPDATE;
2431 } else { /* currently cursor-dragging; drop the colour in the new region. */ 2520 } else { /* currently cursor-dragging; drop the colour in the new region. */
2432 alt_button = (button == CURSOR_SELECT2); 2521 alt_button = (button == CURSOR_SELECT2);
2433 /* Double-select removes current colour. */ 2522 /* Double-select removes current colour. */
@@ -2452,14 +2541,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2452 ui->dragx = x; 2541 ui->dragx = x;
2453 ui->dragy = y; 2542 ui->dragy = y;
2454 ui->cur_visible = false; 2543 ui->cur_visible = false;
2455 return UI_UPDATE; 2544 return MOVE_UI_UPDATE;
2456 } 2545 }
2457 2546
2458 if ((button == LEFT_DRAG || button == RIGHT_DRAG) && 2547 if ((button == LEFT_DRAG || button == RIGHT_DRAG) &&
2459 ui->drag_colour > -2) { 2548 ui->drag_colour > -2) {
2460 ui->dragx = x; 2549 ui->dragx = x;
2461 ui->dragy = y; 2550 ui->dragy = y;
2462 return UI_UPDATE; 2551 return MOVE_UI_UPDATE;
2463 } 2552 }
2464 2553
2465 if ((button == LEFT_RELEASE || button == RIGHT_RELEASE) && 2554 if ((button == LEFT_RELEASE || button == RIGHT_RELEASE) &&
@@ -2484,18 +2573,18 @@ drag_dropped:
2484 ui->drag_colour = -2; 2573 ui->drag_colour = -2;
2485 2574
2486 if (r < 0) 2575 if (r < 0)
2487 return UI_UPDATE; /* drag into border; do nothing else */ 2576 return MOVE_UI_UPDATE; /* drag into border; do nothing else */
2488 2577
2489 if (state->map->immutable[r]) 2578 if (state->map->immutable[r])
2490 return UI_UPDATE; /* can't change this region */ 2579 return MOVE_UI_UPDATE; /* can't change this region */
2491 2580
2492 if (state->colouring[r] == c && state->pencil[r] == p) 2581 if (state->colouring[r] == c && state->pencil[r] == p)
2493 return UI_UPDATE; /* don't _need_ to change this region */ 2582 return MOVE_UI_UPDATE; /* don't _need_ to change this region */
2494 2583
2495 if (alt_button) { 2584 if (alt_button) {
2496 if (state->colouring[r] >= 0) { 2585 if (state->colouring[r] >= 0) {
2497 /* Can't pencil on a coloured region */ 2586 /* Can't pencil on a coloured region */
2498 return UI_UPDATE; 2587 return MOVE_UI_UPDATE;
2499 } else if (c >= 0) { 2588 } else if (c >= 0) {
2500 /* Right-dragging from colour to blank toggles one pencil */ 2589 /* Right-dragging from colour to blank toggles one pencil */
2501 p = state->pencil[r] ^ (1 << c); 2590 p = state->pencil[r] ^ (1 << c);
@@ -2605,7 +2694,7 @@ static game_state *execute_move(const game_state *state, const char *move)
2605 */ 2694 */
2606 2695
2607static void game_compute_size(const game_params *params, int tilesize, 2696static void game_compute_size(const game_params *params, int tilesize,
2608 int *x, int *y) 2697 const game_ui *ui, int *x, int *y)
2609{ 2698{
2610 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2699 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2611 struct { int tilesize; } ads, *ds = &ads; 2700 struct { int tilesize; } ads, *ds = &ads;
@@ -2729,7 +2818,7 @@ static void draw_error(drawing *dr, game_drawstate *ds, int x, int y)
2729 2818
2730static void draw_square(drawing *dr, game_drawstate *ds, 2819static void draw_square(drawing *dr, game_drawstate *ds,
2731 const game_params *params, struct map *map, 2820 const game_params *params, struct map *map,
2732 int x, int y, unsigned long v) 2821 int x, int y, unsigned long v, bool large_stipples)
2733{ 2822{
2734 int w = params->w, h = params->h, wh = w*h; 2823 int w = params->w, h = params->h, wh = w*h;
2735 int tv, bv, xo, yo, i, j, oldj; 2824 int tv, bv, xo, yo, i, j, oldj;
@@ -2802,7 +2891,8 @@ static void draw_square(drawing *dr, game_drawstate *ds,
2802 2891
2803 draw_circle(dr, COORD(x) + (xo+1)*TILESIZE/5, 2892 draw_circle(dr, COORD(x) + (xo+1)*TILESIZE/5,
2804 COORD(y) + (yo+1)*TILESIZE/5, 2893 COORD(y) + (yo+1)*TILESIZE/5,
2805 TILESIZE/4, COL_0 + c, COL_0 + c); 2894 large_stipples ? TILESIZE/4 : TILESIZE/7,
2895 COL_0 + c, COL_0 + c);
2806 } 2896 }
2807 2897
2808 /* 2898 /*
@@ -2857,6 +2947,11 @@ static void draw_square(drawing *dr, game_drawstate *ds,
2857 draw_update(dr, COORD(x), COORD(y), TILESIZE, TILESIZE); 2947 draw_update(dr, COORD(x), COORD(y), TILESIZE, TILESIZE);
2858} 2948}
2859 2949
2950static float flash_length(const game_ui *ui)
2951{
2952 return (ui->flash_type == FLASH_EACH_TO_WHITE ? 0.50F : 0.30F);
2953}
2954
2860static void game_redraw(drawing *dr, game_drawstate *ds, 2955static void game_redraw(drawing *dr, game_drawstate *ds,
2861 const game_state *oldstate, const game_state *state, 2956 const game_state *oldstate, const game_state *state,
2862 int dir, const game_ui *ui, 2957 int dir, const game_ui *ui,
@@ -2872,29 +2967,18 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2872 ds->drag_visible = false; 2967 ds->drag_visible = false;
2873 } 2968 }
2874 2969
2875 /*
2876 * The initial contents of the window are not guaranteed and
2877 * can vary with front ends. To be on the safe side, all games
2878 * should start by drawing a big background-colour rectangle
2879 * covering the whole window.
2880 */
2881 if (!ds->started) { 2970 if (!ds->started) {
2882 int ww, wh;
2883
2884 game_compute_size(&state->p, TILESIZE, &ww, &wh);
2885 draw_rect(dr, 0, 0, ww, wh, COL_BACKGROUND);
2886 draw_rect(dr, COORD(0), COORD(0), w*TILESIZE+1, h*TILESIZE+1, 2971 draw_rect(dr, COORD(0), COORD(0), w*TILESIZE+1, h*TILESIZE+1,
2887 COL_GRID); 2972 COL_GRID);
2888 2973 draw_update(dr, COORD(0), COORD(0), w*TILESIZE+1, h*TILESIZE+1);
2889 draw_update(dr, 0, 0, ww, wh);
2890 ds->started = true; 2974 ds->started = true;
2891 } 2975 }
2892 2976
2893 if (flashtime) { 2977 if (flashtime) {
2894 if (flash_type == 1) 2978 if (ui->flash_type == FLASH_EACH_TO_WHITE)
2895 flash = (int)(flashtime * FOUR / flash_length); 2979 flash = (int)(flashtime * FOUR / flash_length(ui));
2896 else 2980 else
2897 flash = 1 + (int)(flashtime * THREE / flash_length); 2981 flash = 1 + (int)(flashtime * THREE / flash_length(ui));
2898 } else 2982 } else
2899 flash = -1; 2983 flash = -1;
2900 2984
@@ -2913,12 +2997,12 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2913 bv = FOUR; 2997 bv = FOUR;
2914 2998
2915 if (flash >= 0) { 2999 if (flash >= 0) {
2916 if (flash_type == 1) { 3000 if (ui->flash_type == FLASH_EACH_TO_WHITE) {
2917 if (tv == flash) 3001 if (tv == flash)
2918 tv = FOUR; 3002 tv = FOUR;
2919 if (bv == flash) 3003 if (bv == flash)
2920 bv = FOUR; 3004 bv = FOUR;
2921 } else if (flash_type == 2) { 3005 } else if (ui->flash_type == FLASH_ALL_TO_WHITE) {
2922 if (flash % 2) 3006 if (flash % 2)
2923 tv = bv = FOUR; 3007 tv = bv = FOUR;
2924 } else { 3008 } else {
@@ -2990,7 +3074,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2990 for (x = 0; x < w; x++) { 3074 for (x = 0; x < w; x++) {
2991 unsigned long v = ds->todraw[y*w+x]; 3075 unsigned long v = ds->todraw[y*w+x];
2992 if (ds->drawn[y*w+x] != v) { 3076 if (ds->drawn[y*w+x] != v) {
2993 draw_square(dr, ds, &state->p, state->map, x, y, v); 3077 draw_square(dr, ds, &state->p, state->map, x, y, v, ui->large_stipples);
2994 ds->drawn[y*w+x] = v; 3078 ds->drawn[y*w+x] = v;
2995 } 3079 }
2996 } 3080 }
@@ -3048,15 +3132,7 @@ static float game_flash_length(const game_state *oldstate,
3048{ 3132{
3049 if (!oldstate->completed && newstate->completed && 3133 if (!oldstate->completed && newstate->completed &&
3050 !oldstate->cheated && !newstate->cheated) { 3134 !oldstate->cheated && !newstate->cheated) {
3051 if (flash_type < 0) { 3135 return flash_length(ui);
3052 char *env = getenv("MAP_ALTERNATIVE_FLASH");
3053 if (env)
3054 flash_type = atoi(env);
3055 else
3056 flash_type = 0;
3057 flash_length = (flash_type == 1 ? 0.50F : 0.30F);
3058 }
3059 return flash_length;
3060 } else 3136 } else
3061 return 0.0F; 3137 return 0.0F;
3062} 3138}
@@ -3079,12 +3155,8 @@ static int game_status(const game_state *state)
3079 return state->completed ? +1 : 0; 3155 return state->completed ? +1 : 0;
3080} 3156}
3081 3157
3082static bool game_timing_state(const game_state *state, game_ui *ui) 3158static void game_print_size(const game_params *params, const game_ui *ui,
3083{ 3159 float *x, float *y)
3084 return true;
3085}
3086
3087static void game_print_size(const game_params *params, float *x, float *y)
3088{ 3160{
3089 int pw, ph; 3161 int pw, ph;
3090 3162
@@ -3093,12 +3165,13 @@ static void game_print_size(const game_params *params, float *x, float *y)
3093 * compute this size is to compute the pixel puzzle size at a 3165 * compute this size is to compute the pixel puzzle size at a
3094 * given tile size and then scale. 3166 * given tile size and then scale.
3095 */ 3167 */
3096 game_compute_size(params, 400, &pw, &ph); 3168 game_compute_size(params, 400, ui, &pw, &ph);
3097 *x = pw / 100.0F; 3169 *x = pw / 100.0F;
3098 *y = ph / 100.0F; 3170 *y = ph / 100.0F;
3099} 3171}
3100 3172
3101static void game_print(drawing *dr, const game_state *state, int tilesize) 3173static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
3174 int tilesize)
3102{ 3175{
3103 int w = state->p.w, h = state->p.h, wh = w*h, n = state->p.n; 3176 int w = state->p.w, h = state->p.h, wh = w*h, n = state->p.n;
3104 int ink, c[FOUR], i; 3177 int ink, c[FOUR], i;
@@ -3257,13 +3330,15 @@ const struct game thegame = {
3257 dup_game, 3330 dup_game,
3258 free_game, 3331 free_game,
3259 true, solve_game, 3332 true, solve_game,
3260 false, game_can_format_as_text_now, game_text_format, 3333 false, NULL, NULL, /* can_format_as_text_now, text_format */
3334 get_prefs, set_prefs,
3261 new_ui, 3335 new_ui,
3262 free_ui, 3336 free_ui,
3263 encode_ui, 3337 NULL, /* encode_ui */
3264 decode_ui, 3338 NULL, /* decode_ui */
3265 NULL, /* game_request_keys */ 3339 NULL, /* game_request_keys */
3266 game_changed_state, 3340 game_changed_state,
3341 current_key_label,
3267 interpret_move, 3342 interpret_move,
3268 execute_move, 3343 execute_move,
3269 20, game_compute_size, game_set_size, 3344 20, game_compute_size, game_set_size,
@@ -3277,7 +3352,7 @@ const struct game thegame = {
3277 game_status, 3352 game_status,
3278 true, true, game_print_size, game_print, 3353 true, true, game_print_size, game_print,
3279 false, /* wants_statusbar */ 3354 false, /* wants_statusbar */
3280 false, game_timing_state, 3355 false, NULL, /* timing_state */
3281 0, /* flags */ 3356 0, /* flags */
3282}; 3357};
3283 3358
diff --git a/apps/plugins/puzzles/src/matching.c b/apps/plugins/puzzles/src/matching.c
index 9078f6c36a..aabdae0846 100644
--- a/apps/plugins/puzzles/src/matching.c
+++ b/apps/plugins/puzzles/src/matching.c
@@ -319,35 +319,7 @@ int matching(int nl, int nr, int **adjlists, int *adjsizes,
319 return ret; 319 return ret;
320} 320}
321 321
322#ifdef STANDALONE_MATCHING_TEST 322void matching_witness(void *scratchv, int nl, int nr, int *witness)
323
324/*
325 * Diagnostic routine used in testing this algorithm. It is passed a
326 * pointer to a piece of scratch space that's just been used by
327 * matching_with_scratch, and extracts from it a labelling of the
328 * input graph that acts as a 'witness' to the maximality of the
329 * returned matching.
330 *
331 * The output parameter 'witness' should be an array of (nl+nr)
332 * integers, indexed such that witness[L] corresponds to an L-vertex (for
333 * L=0,1,...,nl-1) and witness[nl+R] corresponds to an R-vertex (for
334 * R=0,1,...,nr-1). On return, this array will assign each vertex a
335 * label which is either 0 or 1, and the following properties will
336 * hold:
337 *
338 * + all vertices not paired up by the matching are type L0 or R1
339 * + every L0->R1 edge is used by the matching
340 * + no L1->R0 edge is used by the matching.
341 *
342 * The mere existence of such a labelling is enough to prove the
343 * maximality of the matching, because if there is any larger matching
344 * then its symmetric difference with this one must include at least
345 * one 'augmenting path', which starts at a free L-vertex and ends at
346 * a free R-vertex, traversing only unused L->R edges and only used
347 * R->L edges. But that would mean it starts at an L0, ends at an R1,
348 * and never follows an edge that can get from an 0 to a 1.
349 */
350static void matching_witness(void *scratchv, int nl, int nr, int *witness)
351{ 323{
352 struct scratch *s = (struct scratch *)scratchv; 324 struct scratch *s = (struct scratch *)scratchv;
353 int i, j; 325 int i, j;
@@ -357,397 +329,3 @@ static void matching_witness(void *scratchv, int nl, int nr, int *witness)
357 for (j = 0; j < nr; j++) 329 for (j = 0; j < nr; j++)
358 witness[nl + j] = s->Rlayer[j] == -1; 330 witness[nl + j] = s->Rlayer[j] == -1;
359} 331}
360
361/*
362 * Standalone tool to run the matching algorithm.
363 */
364
365#include <string.h>
366#include <ctype.h>
367#include <time.h>
368
369#include "tree234.h"
370
371int nl, nr, count;
372int **adjlists, *adjsizes;
373int *adjdata, *outl, *outr, *witness;
374void *scratch;
375random_state *rs;
376
377void allocate(int nl_, int nr_, int maxedges)
378{
379 nl = nl_;
380 nr = nr_;
381 adjdata = snewn(maxedges, int);
382 adjlists = snewn(nl, int *);
383 adjsizes = snewn(nl, int);
384 outl = snewn(nl, int);
385 outr = snewn(nr, int);
386 witness = snewn(nl+nr, int);
387 scratch = smalloc(matching_scratch_size(nl, nr));
388}
389
390void deallocate(void)
391{
392 sfree(adjlists);
393 sfree(adjsizes);
394 sfree(adjdata);
395 sfree(outl);
396 sfree(outr);
397 sfree(witness);
398 sfree(scratch);
399}
400
401void find_and_check_matching(void)
402{
403 int i, j, k;
404
405 count = matching_with_scratch(scratch, nl, nr, adjlists, adjsizes,
406 rs, outl, outr);
407 matching_witness(scratch, nl, nr, witness);
408
409 for (i = j = 0; i < nl; i++) {
410 if (outl[i] != -1) {
411 assert(0 <= outl[i] && outl[i] < nr);
412 assert(outr[outl[i]] == i);
413 j++;
414
415 for (k = 0; k < adjsizes[i]; k++)
416 if (adjlists[i][k] == outl[i])
417 break;
418 assert(k < adjsizes[i]);
419 }
420 }
421 assert(j == count);
422
423 for (i = j = 0; i < nr; i++) {
424 if (outr[i] != -1) {
425 assert(0 <= outr[i] && outr[i] < nl);
426 assert(outl[outr[i]] == i);
427 j++;
428 }
429 }
430 assert(j == count);
431
432 for (i = 0; i < nl; i++) {
433 if (outl[i] == -1)
434 assert(witness[i] == 0);
435 }
436 for (i = 0; i < nr; i++) {
437 if (outr[i] == -1)
438 assert(witness[nl+i] == 1);
439 }
440 for (i = 0; i < nl; i++) {
441 for (j = 0; j < adjsizes[i]; j++) {
442 k = adjlists[i][j];
443
444 if (outl[i] == k)
445 assert(!(witness[i] == 1 && witness[nl+k] == 0));
446 else
447 assert(!(witness[i] == 0 && witness[nl+k] == 1));
448 }
449 }
450}
451
452struct nodename {
453 const char *name;
454 int index;
455};
456
457int compare_nodes(void *av, void *bv)
458{
459 const struct nodename *a = (const struct nodename *)av;
460 const struct nodename *b = (const struct nodename *)bv;
461 return strcmp(a->name, b->name);
462}
463
464int node_index(tree234 *n2i, tree234 *i2n, const char *name)
465{
466 struct nodename *nn, *nn_prev;
467 char *namedup = dupstr(name);
468
469 nn = snew(struct nodename);
470 nn->name = namedup;
471 nn->index = count234(n2i);
472
473 nn_prev = add234(n2i, nn);
474 if (nn_prev != nn) {
475 sfree(nn);
476 sfree(namedup);
477 } else {
478 addpos234(i2n, nn, nn->index);
479 }
480
481 return nn_prev->index;
482}
483
484struct edge {
485 int L, R;
486};
487
488int compare_edges(void *av, void *bv)
489{
490 const struct edge *a = (const struct edge *)av;
491 const struct edge *b = (const struct edge *)bv;
492 if (a->L < b->L) return -1;
493 if (a->L > b->L) return +1;
494 if (a->R < b->R) return -1;
495 if (a->R > b->R) return +1;
496 return 0;
497}
498
499void matching_from_user_input(FILE *fp, const char *filename)
500{
501 tree234 *Ln2i, *Li2n, *Rn2i, *Ri2n, *edges;
502 char *line = NULL;
503 struct edge *e;
504 int i, lineno = 0;
505 int *adjptr;
506
507 Ln2i = newtree234(compare_nodes);
508 Rn2i = newtree234(compare_nodes);
509 Li2n = newtree234(NULL);
510 Ri2n = newtree234(NULL);
511 edges = newtree234(compare_edges);
512
513 while (sfree(line), lineno++, (line = fgetline(fp)) != NULL) {
514 char *p, *Lname, *Rname;
515
516 p = line;
517 while (*p && isspace((unsigned char)*p)) p++;
518 if (!*p)
519 continue;
520
521 Lname = p;
522 while (*p && !isspace((unsigned char)*p)) p++;
523 if (*p)
524 *p++ = '\0';
525 while (*p && isspace((unsigned char)*p)) p++;
526
527 if (!*p) {
528 fprintf(stderr, "%s:%d: expected 2 words, found 1\n",
529 filename, lineno);
530 exit(1);
531 }
532
533 Rname = p;
534 while (*p && !isspace((unsigned char)*p)) p++;
535 if (*p)
536 *p++ = '\0';
537 while (*p && isspace((unsigned char)*p)) p++;
538
539 if (*p) {
540 fprintf(stderr, "%s:%d: expected 2 words, found more\n",
541 filename, lineno);
542 exit(1);
543 }
544
545 e = snew(struct edge);
546 e->L = node_index(Ln2i, Li2n, Lname);
547 e->R = node_index(Rn2i, Ri2n, Rname);
548 if (add234(edges, e) != e) {
549 fprintf(stderr, "%s:%d: duplicate edge\n",
550 filename, lineno);
551 exit(1);
552 }
553 }
554
555 allocate(count234(Ln2i), count234(Rn2i), count234(edges));
556
557 adjptr = adjdata;
558 for (i = 0; i < nl; i++)
559 adjlists[i] = NULL;
560 for (i = 0; (e = index234(edges, i)) != NULL; i++) {
561 if (!adjlists[e->L])
562 adjlists[e->L] = adjptr;
563 *adjptr++ = e->R;
564 adjsizes[e->L] = adjptr - adjlists[e->L];
565 }
566
567 find_and_check_matching();
568
569 for (i = 0; i < nl; i++) {
570 if (outl[i] != -1) {
571 struct nodename *Lnn = index234(Li2n, i);
572 struct nodename *Rnn = index234(Ri2n, outl[i]);
573 printf("%s %s\n", Lnn->name, Rnn->name);
574 }
575 }
576}
577
578void test_subsets(void)
579{
580 int b = 8;
581 int n = 1 << b;
582 int i, j, nruns, expected_size;
583 int *adjptr;
584 int *edgecounts;
585 struct stats {
586 int min, max;
587 double n, sx, sxx;
588 } *stats;
589 static const char seed[] = "fixed random seed for repeatability";
590
591 /*
592 * Generate a graph in which every subset of [b] = {1,...,b}
593 * (represented as a b-bit integer 0 <= i < n) has an edge going
594 * to every subset obtained by removing exactly one element.
595 *
596 * This graph is the disjoint union of the corresponding graph for
597 * each layer (collection of same-sized subset) of the power set
598 * of [b]. Each of those graphs has a matching of size equal to
599 * the smaller of its vertex sets. So we expect the overall size
600 * of the output matching to be less than n by the size of the
601 * largest layer, that is, to be n - binomial(n, floor(n/2)).
602 *
603 * We run the generation repeatedly, randomising it every time,
604 * and we expect to see every possible edge appear sooner or
605 * later.
606 */
607
608 rs = random_new(seed, strlen(seed));
609
610 allocate(n, n, n*b);
611 adjptr = adjdata;
612 expected_size = 0;
613 for (i = 0; i < n; i++) {
614 adjlists[i] = adjptr;
615 for (j = 0; j < b; j++) {
616 if (i & (1 << j))
617 *adjptr++ = i & ~(1 << j);
618 }
619 adjsizes[i] = adjptr - adjlists[i];
620 if (adjsizes[i] != b/2)
621 expected_size++;
622 }
623
624 edgecounts = snewn(n*b, int);
625 for (i = 0; i < n*b; i++)
626 edgecounts[i] = 0;
627
628 stats = snewn(b, struct stats);
629
630 nruns = 0;
631 while (nruns < 10000) {
632 nruns++;
633 find_and_check_matching();
634 assert(count == expected_size);
635
636 for (i = 0; i < n; i++)
637 for (j = 0; j < b; j++)
638 if ((i ^ outl[i]) == (1 << j))
639 edgecounts[b*i+j]++;
640
641 if (nruns % 1000 == 0) {
642 for (i = 0; i < b; i++) {
643 struct stats *st = &stats[i];
644 st->min = st->max = -1;
645 st->n = st->sx = st->sxx = 0;
646 }
647
648 for (i = 0; i < n; i++) {
649 int pop = 0;
650 for (j = 0; j < b; j++)
651 if (i & (1 << j))
652 pop++;
653 pop--;
654
655 for (j = 0; j < b; j++) {
656 if (i & (1 << j)) {
657 struct stats *st = &stats[pop];
658 int x = edgecounts[b*i+j];
659 if (st->max == -1 || st->max < x)
660 st->max = x;
661 if (st->min == -1 || st->min > x)
662 st->min = x;
663 st->n++;
664 st->sx += x;
665 st->sxx += (double)x*x;
666 } else {
667 assert(edgecounts[b*i+j] == 0);
668 }
669 }
670 }
671 }
672 }
673
674 printf("after %d runs:\n", nruns);
675 for (j = 0; j < b; j++) {
676 struct stats *st = &stats[j];
677 printf("edges between layers %d,%d:"
678 " min=%d max=%d mean=%f variance=%f\n",
679 j, j+1, st->min, st->max, st->sx/st->n,
680 (st->sxx - st->sx*st->sx/st->n) / st->n);
681 }
682}
683
684int main(int argc, char **argv)
685{
686 static const char stdin_identifier[] = "<standard input>";
687 const char *infile = NULL;
688 bool doing_opts = true;
689 enum { USER_INPUT, AUTOTEST } mode = USER_INPUT;
690
691 while (--argc > 0) {
692 const char *arg = *++argv;
693
694 if (doing_opts && arg[0] == '-' && arg[1]) {
695 if (!strcmp(arg, "--")) {
696 doing_opts = false;
697 } else if (!strcmp(arg, "--random")) {
698 char buf[64];
699 int len = sprintf(buf, "%lu", (unsigned long)time(NULL));
700 rs = random_new(buf, len);
701 } else if (!strcmp(arg, "--autotest")) {
702 mode = AUTOTEST;
703 } else {
704 fprintf(stderr, "matching: unrecognised option '%s'\n", arg);
705 return 1;
706 }
707 } else {
708 if (!infile) {
709 infile = (!strcmp(arg, "-") ? stdin_identifier : arg);
710 } else {
711 fprintf(stderr, "matching: too many arguments\n");
712 return 1;
713 }
714 }
715 }
716
717 if (mode == USER_INPUT) {
718 FILE *fp;
719
720 if (!infile)
721 infile = stdin_identifier;
722
723 if (infile != stdin_identifier) {
724 fp = fopen(infile, "r");
725 if (!fp) {
726 fprintf(stderr, "matching: could not open input file '%s'\n",
727 infile);
728 return 1;
729 }
730 } else {
731 fp = stdin;
732 }
733
734 matching_from_user_input(fp, infile);
735
736 if (infile != stdin_identifier)
737 fclose(fp);
738 }
739
740 if (mode == AUTOTEST) {
741 if (infile) {
742 fprintf(stderr, "matching: expected no filename argument "
743 "with --autotest\n");
744 return 1;
745 }
746
747 test_subsets();
748 }
749
750 return 0;
751}
752
753#endif /* STANDALONE_MATCHING_TEST */
diff --git a/apps/plugins/puzzles/src/matching.h b/apps/plugins/puzzles/src/matching.h
index a4d3098efa..dbf424d044 100644
--- a/apps/plugins/puzzles/src/matching.h
+++ b/apps/plugins/puzzles/src/matching.h
@@ -77,4 +77,32 @@ size_t matching_scratch_size(int nl, int nr);
77int matching(int nl, int nr, int **adjlists, int *adjsizes, 77int matching(int nl, int nr, int **adjlists, int *adjsizes,
78 random_state *rs, int *outl, int *outr); 78 random_state *rs, int *outl, int *outr);
79 79
80/*
81 * Diagnostic routine used in testing this algorithm. It is passed a
82 * pointer to a piece of scratch space that's just been used by
83 * matching_with_scratch, and extracts from it a labelling of the
84 * input graph that acts as a 'witness' to the maximality of the
85 * returned matching.
86 *
87 * The output parameter 'witness' should be an array of (nl+nr)
88 * integers, indexed such that witness[L] corresponds to an L-vertex (for
89 * L=0,1,...,nl-1) and witness[nl+R] corresponds to an R-vertex (for
90 * R=0,1,...,nr-1). On return, this array will assign each vertex a
91 * label which is either 0 or 1, and the following properties will
92 * hold:
93 *
94 * + all vertices not paired up by the matching are type L0 or R1
95 * + every L0->R1 edge is used by the matching
96 * + no L1->R0 edge is used by the matching.
97 *
98 * The mere existence of such a labelling is enough to prove the
99 * maximality of the matching, because if there is any larger matching
100 * then its symmetric difference with this one must include at least
101 * one 'augmenting path', which starts at a free L-vertex and ends at
102 * a free R-vertex, traversing only unused L->R edges and only used
103 * R->L edges. But that would mean it starts at an L0, ends at an R1,
104 * and never follows an edge that can get from an 0 to a 1.
105 */
106void matching_witness(void *scratch, int nl, int nr, int *witness);
107
80#endif /* MATCHING_MATCHING_H */ 108#endif /* MATCHING_MATCHING_H */
diff --git a/apps/plugins/puzzles/src/midend.c b/apps/plugins/puzzles/src/midend.c
index f2d27d3e31..30fdf1b830 100644
--- a/apps/plugins/puzzles/src/midend.c
+++ b/apps/plugins/puzzles/src/midend.c
@@ -30,6 +30,11 @@ struct midend_serialise_buf {
30 int len, size; 30 int len, size;
31}; 31};
32 32
33struct midend_serialise_buf_read_ctx {
34 struct midend_serialise_buf *ser;
35 int len, pos;
36};
37
33struct midend { 38struct midend {
34 frontend *frontend; 39 frontend *frontend;
35 random_state *random; 40 random_state *random;
@@ -73,6 +78,7 @@ struct midend {
73 78
74 game_params *params, *curparams; 79 game_params *params, *curparams;
75 game_drawstate *drawstate; 80 game_drawstate *drawstate;
81 bool first_draw;
76 game_ui *ui; 82 game_ui *ui;
77 83
78 game_state *oldstate; 84 game_state *oldstate;
@@ -88,10 +94,15 @@ struct midend {
88 94
89 int pressed_mouse_button; 95 int pressed_mouse_button;
90 96
91 int preferred_tilesize, tilesize, winwidth, winheight; 97 struct midend_serialise_buf be_prefs;
98
99 int preferred_tilesize, preferred_tilesize_dpr, tilesize;
100 int winwidth, winheight;
92 101
93 void (*game_id_change_notify_function)(void *); 102 void (*game_id_change_notify_function)(void *);
94 void *game_id_change_notify_ctx; 103 void *game_id_change_notify_ctx;
104
105 bool one_key_shortcuts;
95}; 106};
96 107
97#define ensure(me) do { \ 108#define ensure(me) do { \
@@ -119,21 +130,33 @@ struct deserialise_data {
119}; 130};
120 131
121/* 132/*
122 * Forward reference. 133 * Forward references.
123 */ 134 */
124static const char *midend_deserialise_internal( 135static const char *midend_deserialise_internal(
125 midend *me, bool (*read)(void *ctx, void *buf, int len), void *rctx, 136 midend *me, bool (*read)(void *ctx, void *buf, int len), void *rctx,
126 const char *(*check)(void *ctx, midend *, const struct deserialise_data *), 137 const char *(*check)(void *ctx, midend *, const struct deserialise_data *),
127 void *cctx); 138 void *cctx);
139static void midend_serialise_prefs(
140 midend *me, game_ui *ui,
141 void (*write)(void *ctx, const void *buf, int len), void *wctx);
142static const char *midend_deserialise_prefs(
143 midend *me, game_ui *ui,
144 bool (*read)(void *ctx, void *buf, int len), void *rctx);
145static config_item *midend_get_prefs(midend *me, game_ui *ui);
146static void midend_set_prefs(midend *me, game_ui *ui, config_item *all_prefs);
147static void midend_apply_prefs(midend *me, game_ui *ui);
128 148
129void midend_reset_tilesize(midend *me) 149void midend_reset_tilesize(midend *me)
130{ 150{
131 me->preferred_tilesize = me->ourgame->preferred_tilesize; 151 me->preferred_tilesize = me->ourgame->preferred_tilesize;
152 me->preferred_tilesize_dpr = 1.0;
132 { 153 {
133 /* 154 /*
134 * Allow an environment-based override for the default tile 155 * Allow an environment-based override for the default tile
135 * size by defining a variable along the lines of 156 * size by defining a variable along the lines of
136 * `NET_TILESIZE=15'. 157 * `NET_TILESIZE=15'.
158 *
159 * XXX How should this interact with DPR?
137 */ 160 */
138 161
139 char buf[80], *e; 162 char buf[80], *e;
@@ -196,6 +219,7 @@ midend *midend_new(frontend *fe, const game *ourgame,
196 me->aux_info = NULL; 219 me->aux_info = NULL;
197 me->genmode = GOT_NOTHING; 220 me->genmode = GOT_NOTHING;
198 me->drawstate = NULL; 221 me->drawstate = NULL;
222 me->first_draw = true;
199 me->oldstate = NULL; 223 me->oldstate = NULL;
200 me->preset_menu = NULL; 224 me->preset_menu = NULL;
201 me->anim_time = me->anim_pos = 0.0F; 225 me->anim_time = me->anim_pos = 0.0F;
@@ -212,6 +236,11 @@ midend *midend_new(frontend *fe, const game *ourgame,
212 else 236 else
213 me->drawing = NULL; 237 me->drawing = NULL;
214 238
239 me->be_prefs.buf = NULL;
240 me->be_prefs.size = me->be_prefs.len = 0;
241
242 me->one_key_shortcuts = true;
243
215 midend_reset_tilesize(me); 244 midend_reset_tilesize(me);
216 245
217 sfree(randseed); 246 sfree(randseed);
@@ -280,6 +309,7 @@ void midend_free(midend *me)
280 sfree(me->privdesc); 309 sfree(me->privdesc);
281 sfree(me->seedstr); 310 sfree(me->seedstr);
282 sfree(me->aux_info); 311 sfree(me->aux_info);
312 sfree(me->be_prefs.buf);
283 me->ourgame->free_params(me->params); 313 me->ourgame->free_params(me->params);
284 midend_free_preset_menu(me, me->preset_menu); 314 midend_free_preset_menu(me, me->preset_menu);
285 if (me->ui) 315 if (me->ui)
@@ -297,14 +327,56 @@ static void midend_size_new_drawstate(midend *me)
297 * anyway yet. 327 * anyway yet.
298 */ 328 */
299 if (me->tilesize > 0) { 329 if (me->tilesize > 0) {
300 me->ourgame->compute_size(me->params, me->tilesize, 330 me->ourgame->compute_size(me->params, me->tilesize, me->ui,
301 &me->winwidth, &me->winheight); 331 &me->winwidth, &me->winheight);
302 me->ourgame->set_size(me->drawing, me->drawstate, 332 me->ourgame->set_size(me->drawing, me->drawstate,
303 me->params, me->tilesize); 333 me->params, me->tilesize);
304 } 334 }
305} 335}
306 336
307void midend_size(midend *me, int *x, int *y, bool user_size) 337/*
338 * There is no one correct way to convert tilesizes between device
339 * pixel ratios, because there's only a loosely-defined relationship
340 * between tilesize and the actual size of a puzzle. We define this
341 * function as the canonical conversion function so everything in the
342 * midend will be consistent.
343 */
344static int convert_tilesize(midend *me, int old_tilesize,
345 double old_dpr, double new_dpr)
346{
347 int x, y, rx, ry, min, max;
348 game_params *defaults;
349
350 if (new_dpr == old_dpr)
351 return old_tilesize;
352
353 defaults = me->ourgame->default_params();
354
355 me->ourgame->compute_size(defaults, old_tilesize, me->ui, &x, &y);
356 x *= new_dpr / old_dpr;
357 y *= new_dpr / old_dpr;
358
359 min = max = 1;
360 do {
361 max *= 2;
362 me->ourgame->compute_size(defaults, max, me->ui, &rx, &ry);
363 } while (rx <= x && ry <= y);
364
365 while (max - min > 1) {
366 int mid = (max + min) / 2;
367 me->ourgame->compute_size(defaults, mid, me->ui, &rx, &ry);
368 if (rx <= x && ry <= y)
369 min = mid;
370 else
371 max = mid;
372 }
373
374 me->ourgame->free_params(defaults);
375 return min;
376}
377
378void midend_size(midend *me, int *x, int *y, bool user_size,
379 double device_pixel_ratio)
308{ 380{
309 int min, max; 381 int min, max;
310 int rx, ry; 382 int rx, ry;
@@ -318,6 +390,7 @@ void midend_size(midend *me, int *x, int *y, bool user_size)
318 me->ourgame->free_drawstate(me->drawing, me->drawstate); 390 me->ourgame->free_drawstate(me->drawing, me->drawstate);
319 me->drawstate = me->ourgame->new_drawstate(me->drawing, 391 me->drawstate = me->ourgame->new_drawstate(me->drawing,
320 me->states[0].state); 392 me->states[0].state);
393 me->first_draw = true;
321 } 394 }
322 395
323 /* 396 /*
@@ -333,10 +406,12 @@ void midend_size(midend *me, int *x, int *y, bool user_size)
333 max = 1; 406 max = 1;
334 do { 407 do {
335 max *= 2; 408 max *= 2;
336 me->ourgame->compute_size(me->params, max, &rx, &ry); 409 me->ourgame->compute_size(me->params, max, me->ui, &rx, &ry);
337 } while (rx <= *x && ry <= *y); 410 } while (rx <= *x && ry <= *y);
338 } else 411 } else
339 max = me->preferred_tilesize + 1; 412 max = convert_tilesize(me, me->preferred_tilesize,
413 me->preferred_tilesize_dpr,
414 device_pixel_ratio) + 1;
340 min = 1; 415 min = 1;
341 416
342 /* 417 /*
@@ -347,7 +422,7 @@ void midend_size(midend *me, int *x, int *y, bool user_size)
347 */ 422 */
348 while (max - min > 1) { 423 while (max - min > 1) {
349 int mid = (max + min) / 2; 424 int mid = (max + min) / 2;
350 me->ourgame->compute_size(me->params, mid, &rx, &ry); 425 me->ourgame->compute_size(me->params, mid, me->ui, &rx, &ry);
351 if (rx <= *x && ry <= *y) 426 if (rx <= *x && ry <= *y)
352 min = mid; 427 min = mid;
353 else 428 else
@@ -359,9 +434,11 @@ void midend_size(midend *me, int *x, int *y, bool user_size)
359 */ 434 */
360 435
361 me->tilesize = min; 436 me->tilesize = min;
362 if (user_size) 437 if (user_size) {
363 /* If the user requested a change in size, make it permanent. */ 438 /* If the user requested a change in size, make it permanent. */
364 me->preferred_tilesize = me->tilesize; 439 me->preferred_tilesize = me->tilesize;
440 me->preferred_tilesize_dpr = device_pixel_ratio;
441 }
365 midend_size_new_drawstate(me); 442 midend_size_new_drawstate(me);
366 *x = me->winwidth; 443 *x = me->winwidth;
367 *y = me->winheight; 444 *y = me->winheight;
@@ -380,6 +457,28 @@ game_params *midend_get_params(midend *me)
380 return me->ourgame->dup_params(me->params); 457 return me->ourgame->dup_params(me->params);
381} 458}
382 459
460static char *encode_params(midend *me, const game_params *params, bool full)
461{
462 char *encoded = me->ourgame->encode_params(params, full);
463 int i;
464
465 /* Assert that the params consist of printable ASCII containing
466 * neither '#' nor ':'. */
467 for (i = 0; encoded[i]; i++)
468 assert(encoded[i] >= 32 && encoded[i] < 127 &&
469 encoded[i] != '#' && encoded[i] != ':');
470 return encoded;
471}
472
473static void assert_printable_ascii(char const *s)
474{
475 /* Assert that s is entirely printable ASCII, and hence safe for
476 * writing in a save file. */
477 int i;
478 for (i = 0; s[i]; i++)
479 assert(s[i] >= 32 && s[i] < 127);
480}
481
383static void midend_set_timer(midend *me) 482static void midend_set_timer(midend *me)
384{ 483{
385 me->timing = (me->ourgame->is_timed && 484 me->timing = (me->ourgame->is_timed &&
@@ -397,11 +496,12 @@ void midend_force_redraw(midend *me)
397 me->ourgame->free_drawstate(me->drawing, me->drawstate); 496 me->ourgame->free_drawstate(me->drawing, me->drawstate);
398 me->drawstate = me->ourgame->new_drawstate(me->drawing, 497 me->drawstate = me->ourgame->new_drawstate(me->drawing,
399 me->states[0].state); 498 me->states[0].state);
499 me->first_draw = true;
400 midend_size_new_drawstate(me); 500 midend_size_new_drawstate(me);
401 midend_redraw(me); 501 midend_redraw(me);
402} 502}
403 503
404static void newgame_serialise_write(void *ctx, const void *buf, int len) 504static void midend_serialise_buf_write(void *ctx, const void *buf, int len)
405{ 505{
406 struct midend_serialise_buf *ser = (struct midend_serialise_buf *)ctx; 506 struct midend_serialise_buf *ser = (struct midend_serialise_buf *)ctx;
407 int new_len; 507 int new_len;
@@ -416,6 +516,18 @@ static void newgame_serialise_write(void *ctx, const void *buf, int len)
416 ser->len = new_len; 516 ser->len = new_len;
417} 517}
418 518
519static bool midend_serialise_buf_read(void *ctx, void *buf, int len)
520{
521 struct midend_serialise_buf_read_ctx *const rctx = ctx;
522
523 if (len > rctx->len - rctx->pos)
524 return false;
525
526 memcpy(buf, rctx->ser->buf + rctx->pos, len);
527 rctx->pos += len;
528 return true;
529}
530
419void midend_new_game(midend *me) 531void midend_new_game(midend *me)
420{ 532{
421 me->newgame_undo.len = 0; 533 me->newgame_undo.len = 0;
@@ -435,7 +547,7 @@ void midend_new_game(midend *me)
435 * worse, valid but wrong. 547 * worse, valid but wrong.
436 */ 548 */
437 midend_purge_states(me); 549 midend_purge_states(me);
438 midend_serialise(me, newgame_serialise_write, &me->newgame_undo); 550 midend_serialise(me, midend_serialise_buf_write, &me->newgame_undo);
439 } 551 }
440 552
441 midend_stop_anim(me); 553 midend_stop_anim(me);
@@ -487,6 +599,7 @@ void midend_new_game(midend *me)
487 */ 599 */
488 me->desc = me->ourgame->new_desc(me->curparams, rs, 600 me->desc = me->ourgame->new_desc(me->curparams, rs,
489 &me->aux_info, (me->drawing != NULL)); 601 &me->aux_info, (me->drawing != NULL));
602 assert_printable_ascii(me->desc);
490 me->privdesc = NULL; 603 me->privdesc = NULL;
491 random_free(rs); 604 random_free(rs);
492 } 605 }
@@ -536,6 +649,7 @@ void midend_new_game(midend *me)
536 me->statepos = 1; 649 me->statepos = 1;
537 me->drawstate = me->ourgame->new_drawstate(me->drawing, 650 me->drawstate = me->ourgame->new_drawstate(me->drawing,
538 me->states[0].state); 651 me->states[0].state);
652 me->first_draw = true;
539 midend_size_new_drawstate(me); 653 midend_size_new_drawstate(me);
540 me->elapsed = 0.0F; 654 me->elapsed = 0.0F;
541 me->flash_pos = me->flash_time = 0.0F; 655 me->flash_pos = me->flash_time = 0.0F;
@@ -543,6 +657,7 @@ void midend_new_game(midend *me)
543 if (me->ui) 657 if (me->ui)
544 me->ourgame->free_ui(me->ui); 658 me->ourgame->free_ui(me->ui);
545 me->ui = me->ourgame->new_ui(me->states[0].state); 659 me->ui = me->ourgame->new_ui(me->states[0].state);
660 midend_apply_prefs(me, me->ui);
546 midend_set_timer(me); 661 midend_set_timer(me);
547 me->pressed_mouse_button = 0; 662 me->pressed_mouse_button = 0;
548 663
@@ -552,31 +667,28 @@ void midend_new_game(midend *me)
552 me->newgame_can_store_undo = true; 667 me->newgame_can_store_undo = true;
553} 668}
554 669
555bool midend_can_undo(midend *me) 670const char *midend_load_prefs(
671 midend *me, bool (*read)(void *ctx, void *buf, int len), void *rctx)
556{ 672{
557 return (me->statepos > 1 || me->newgame_undo.len); 673 const char *err = midend_deserialise_prefs(me, NULL, read, rctx);
674 return err;
558} 675}
559 676
560bool midend_can_redo(midend *me) 677void midend_save_prefs(midend *me,
678 void (*write)(void *ctx, const void *buf, int len),
679 void *wctx)
561{ 680{
562 return (me->statepos < me->nstates || me->newgame_redo.len); 681 midend_serialise_prefs(me, NULL, write, wctx);
563} 682}
564 683
565struct newgame_undo_deserialise_read_ctx { 684bool midend_can_undo(midend *me)
566 struct midend_serialise_buf *ser;
567 int len, pos;
568};
569
570static bool newgame_undo_deserialise_read(void *ctx, void *buf, int len)
571{ 685{
572 struct newgame_undo_deserialise_read_ctx *const rctx = ctx; 686 return (me->statepos > 1 || me->newgame_undo.len);
573 687}
574 if (len > rctx->len - rctx->pos)
575 return false;
576 688
577 memcpy(buf, rctx->ser->buf + rctx->pos, len); 689bool midend_can_redo(midend *me)
578 rctx->pos += len; 690{
579 return true; 691 return (me->statepos < me->nstates || me->newgame_redo.len);
580} 692}
581 693
582struct newgame_undo_deserialise_check_ctx { 694struct newgame_undo_deserialise_check_ctx {
@@ -613,8 +725,8 @@ static const char *newgame_undo_deserialise_check(
613 * We check both params and cparams, to be as safe as possible. 725 * We check both params and cparams, to be as safe as possible.
614 */ 726 */
615 727
616 old = me->ourgame->encode_params(me->params, true); 728 old = encode_params(me, me->params, true);
617 new = me->ourgame->encode_params(data->params, true); 729 new = encode_params(me, data->params, true);
618 if (strcmp(old, new)) { 730 if (strcmp(old, new)) {
619 /* Set a flag to distinguish this deserialise failure 731 /* Set a flag to distinguish this deserialise failure
620 * from one due to faulty decoding */ 732 * from one due to faulty decoding */
@@ -622,8 +734,8 @@ static const char *newgame_undo_deserialise_check(
622 return "Undoing this new-game operation would change params"; 734 return "Undoing this new-game operation would change params";
623 } 735 }
624 736
625 old = me->ourgame->encode_params(me->curparams, true); 737 old = encode_params(me, me->curparams, true);
626 new = me->ourgame->encode_params(data->cparams, true); 738 new = encode_params(me, data->cparams, true);
627 if (strcmp(old, new)) { 739 if (strcmp(old, new)) {
628 ctx->refused = true; 740 ctx->refused = true;
629 return "Undoing this new-game operation would change params"; 741 return "Undoing this new-game operation would change params";
@@ -648,7 +760,7 @@ static bool midend_undo(midend *me)
648 me->dir = -1; 760 me->dir = -1;
649 return true; 761 return true;
650 } else if (me->newgame_undo.len) { 762 } else if (me->newgame_undo.len) {
651 struct newgame_undo_deserialise_read_ctx rctx; 763 struct midend_serialise_buf_read_ctx rctx;
652 struct newgame_undo_deserialise_check_ctx cctx; 764 struct newgame_undo_deserialise_check_ctx cctx;
653 struct midend_serialise_buf serbuf; 765 struct midend_serialise_buf serbuf;
654 766
@@ -659,14 +771,14 @@ static bool midend_undo(midend *me)
659 */ 771 */
660 serbuf.buf = NULL; 772 serbuf.buf = NULL;
661 serbuf.len = serbuf.size = 0; 773 serbuf.len = serbuf.size = 0;
662 midend_serialise(me, newgame_serialise_write, &serbuf); 774 midend_serialise(me, midend_serialise_buf_write, &serbuf);
663 775
664 rctx.ser = &me->newgame_undo; 776 rctx.ser = &me->newgame_undo;
665 rctx.len = me->newgame_undo.len; /* copy for reentrancy safety */ 777 rctx.len = me->newgame_undo.len; /* copy for reentrancy safety */
666 rctx.pos = 0; 778 rctx.pos = 0;
667 cctx.refused = false; 779 cctx.refused = false;
668 deserialise_error = midend_deserialise_internal( 780 deserialise_error = midend_deserialise_internal(
669 me, newgame_undo_deserialise_read, &rctx, 781 me, midend_serialise_buf_read, &rctx,
670 newgame_undo_deserialise_check, &cctx); 782 newgame_undo_deserialise_check, &cctx);
671 if (cctx.refused) { 783 if (cctx.refused) {
672 /* 784 /*
@@ -699,7 +811,8 @@ static bool midend_undo(midend *me)
699 * the midend so that we can redo back into it later. 811 * the midend so that we can redo back into it later.
700 */ 812 */
701 me->newgame_redo.len = 0; 813 me->newgame_redo.len = 0;
702 newgame_serialise_write(&me->newgame_redo, serbuf.buf, serbuf.len); 814 midend_serialise_buf_write(&me->newgame_redo,
815 serbuf.buf, serbuf.len);
703 816
704 sfree(serbuf.buf); 817 sfree(serbuf.buf);
705 return true; 818 return true;
@@ -721,7 +834,7 @@ static bool midend_redo(midend *me)
721 me->dir = +1; 834 me->dir = +1;
722 return true; 835 return true;
723 } else if (me->newgame_redo.len) { 836 } else if (me->newgame_redo.len) {
724 struct newgame_undo_deserialise_read_ctx rctx; 837 struct midend_serialise_buf_read_ctx rctx;
725 struct newgame_undo_deserialise_check_ctx cctx; 838 struct newgame_undo_deserialise_check_ctx cctx;
726 struct midend_serialise_buf serbuf; 839 struct midend_serialise_buf serbuf;
727 840
@@ -732,14 +845,14 @@ static bool midend_redo(midend *me)
732 */ 845 */
733 serbuf.buf = NULL; 846 serbuf.buf = NULL;
734 serbuf.len = serbuf.size = 0; 847 serbuf.len = serbuf.size = 0;
735 midend_serialise(me, newgame_serialise_write, &serbuf); 848 midend_serialise(me, midend_serialise_buf_write, &serbuf);
736 849
737 rctx.ser = &me->newgame_redo; 850 rctx.ser = &me->newgame_redo;
738 rctx.len = me->newgame_redo.len; /* copy for reentrancy safety */ 851 rctx.len = me->newgame_redo.len; /* copy for reentrancy safety */
739 rctx.pos = 0; 852 rctx.pos = 0;
740 cctx.refused = false; 853 cctx.refused = false;
741 deserialise_error = midend_deserialise_internal( 854 deserialise_error = midend_deserialise_internal(
742 me, newgame_undo_deserialise_read, &rctx, 855 me, midend_serialise_buf_read, &rctx,
743 newgame_undo_deserialise_check, &cctx); 856 newgame_undo_deserialise_check, &cctx);
744 if (cctx.refused) { 857 if (cctx.refused) {
745 /* 858 /*
@@ -772,7 +885,8 @@ static bool midend_redo(midend *me)
772 * the midend so that we can undo back into it later. 885 * the midend so that we can undo back into it later.
773 */ 886 */
774 me->newgame_undo.len = 0; 887 me->newgame_undo.len = 0;
775 newgame_serialise_write(&me->newgame_undo, serbuf.buf, serbuf.len); 888 midend_serialise_buf_write(&me->newgame_undo,
889 serbuf.buf, serbuf.len);
776 890
777 sfree(serbuf.buf); 891 sfree(serbuf.buf);
778 return true; 892 return true;
@@ -859,12 +973,13 @@ void midend_restart_game(midend *me)
859 midend_set_timer(me); 973 midend_set_timer(me);
860} 974}
861 975
862static bool midend_really_process_key(midend *me, int x, int y, int button) 976static int midend_really_process_key(midend *me, int x, int y, int button)
863{ 977{
864 game_state *oldstate = 978 game_state *oldstate =
865 me->ourgame->dup_game(me->states[me->statepos - 1].state); 979 me->ourgame->dup_game(me->states[me->statepos - 1].state);
866 int type = MOVE; 980 int type = MOVE;
867 bool gottype = false, ret = true; 981 bool gottype = false;
982 int ret = PKR_NO_EFFECT;
868 float anim_time; 983 float anim_time;
869 game_state *s; 984 game_state *s;
870 char *movestr = NULL; 985 char *movestr = NULL;
@@ -875,40 +990,51 @@ static bool midend_really_process_key(midend *me, int x, int y, int button)
875 me->ui, me->drawstate, x, y, button); 990 me->ui, me->drawstate, x, y, button);
876 } 991 }
877 992
878 if (!movestr) { 993 if (movestr == NULL || movestr == MOVE_UNUSED) {
879 if (button == 'n' || button == 'N' || button == '\x0E' || 994 if ((me->one_key_shortcuts && (button == 'n' || button == 'N')) ||
880 button == UI_NEWGAME) { 995 button == '\x0E' || button == UI_NEWGAME) {
881 midend_new_game(me); 996 midend_new_game(me);
882 midend_redraw(me); 997 midend_redraw(me);
998 ret = PKR_SOME_EFFECT;
883 goto done; /* never animate */ 999 goto done; /* never animate */
884 } else if (button == 'u' || button == 'U' || 1000 } else if ((me->one_key_shortcuts && (button=='u' || button=='U')) ||
885 button == '\x1A' || button == '\x1F' || 1001 button == '*' || button == '\x1A' || button == '\x1F' ||
886 button == UI_UNDO) { 1002 button == UI_UNDO) {
887 midend_stop_anim(me); 1003 midend_stop_anim(me);
888 type = me->states[me->statepos-1].movetype; 1004 type = me->states[me->statepos-1].movetype;
889 gottype = true; 1005 gottype = true;
890 if (!midend_undo(me)) 1006 if (!midend_undo(me))
891 goto done; 1007 goto done;
892 } else if (button == 'r' || button == 'R' || 1008 ret = PKR_SOME_EFFECT;
893 button == '\x12' || button == '\x19' || 1009 } else if ((me->one_key_shortcuts && (button=='r' || button=='R')) ||
1010 button == '#' || button == '\x12' || button == '\x19' ||
894 button == UI_REDO) { 1011 button == UI_REDO) {
895 midend_stop_anim(me); 1012 midend_stop_anim(me);
896 if (!midend_redo(me)) 1013 if (!midend_redo(me))
897 goto done; 1014 goto done;
1015 ret = PKR_SOME_EFFECT;
898 } else if ((button == '\x13' || button == UI_SOLVE) && 1016 } else if ((button == '\x13' || button == UI_SOLVE) &&
899 me->ourgame->can_solve) { 1017 me->ourgame->can_solve) {
1018 ret = PKR_SOME_EFFECT;
900 if (midend_solve(me)) 1019 if (midend_solve(me))
901 goto done; 1020 goto done;
902 } else if (button == 'q' || button == 'Q' || button == '\x11' || 1021 } else if ((me->one_key_shortcuts && (button=='q' || button=='Q')) ||
903 button == UI_QUIT) { 1022 button == '\x11' || button == UI_QUIT) {
904 ret = false; 1023 ret = PKR_QUIT;
905 goto done; 1024 goto done;
906 } else 1025 } else {
1026 ret = PKR_UNUSED;
907 goto done; 1027 goto done;
1028 }
1029 } else if (movestr == MOVE_NO_EFFECT) {
1030 ret = PKR_NO_EFFECT;
1031 goto done;
908 } else { 1032 } else {
909 if (movestr == UI_UPDATE) 1033 ret = PKR_SOME_EFFECT;
1034 if (movestr == MOVE_UI_UPDATE)
910 s = me->states[me->statepos-1].state; 1035 s = me->states[me->statepos-1].state;
911 else { 1036 else {
1037 assert_printable_ascii(movestr);
912 s = me->ourgame->execute_move(me->states[me->statepos-1].state, 1038 s = me->ourgame->execute_move(me->states[me->statepos-1].state,
913 movestr); 1039 movestr);
914 assert(s != NULL); 1040 assert(s != NULL);
@@ -975,9 +1101,9 @@ static bool midend_really_process_key(midend *me, int x, int y, int button)
975 return ret; 1101 return ret;
976} 1102}
977 1103
978bool midend_process_key(midend *me, int x, int y, int button) 1104int midend_process_key(midend *me, int x, int y, int button)
979{ 1105{
980 bool ret = true; 1106 int ret = PKR_UNUSED, ret2;
981 1107
982 /* 1108 /*
983 * Harmonise mouse drag and release messages. 1109 * Harmonise mouse drag and release messages.
@@ -1052,6 +1178,10 @@ bool midend_process_key(midend *me, int x, int y, int button)
1052 * of '\n' etc for keyboard-based cursors. The choice of buttons 1178 * of '\n' etc for keyboard-based cursors. The choice of buttons
1053 * here could eventually be controlled by a runtime configuration 1179 * here could eventually be controlled by a runtime configuration
1054 * option. 1180 * option.
1181 *
1182 * We also handle converting MOD_CTRL|'a' etc into '\x01' etc,
1183 * specially recognising Ctrl+Shift+Z, and stripping modifier
1184 * flags off keys that aren't meant to have them.
1055 */ 1185 */
1056 if (IS_MOUSE_DRAG(button) || IS_MOUSE_RELEASE(button)) { 1186 if (IS_MOUSE_DRAG(button) || IS_MOUSE_RELEASE(button)) {
1057 if (me->pressed_mouse_button) { 1187 if (me->pressed_mouse_button) {
@@ -1076,11 +1206,34 @@ bool midend_process_key(midend *me, int x, int y, int button)
1076 /* 1206 /*
1077 * Fabricate a button-up for the previously pressed button. 1207 * Fabricate a button-up for the previously pressed button.
1078 */ 1208 */
1079 ret = ret && midend_really_process_key 1209 ret2 = midend_really_process_key
1080 (me, x, y, (me->pressed_mouse_button + 1210 (me, x, y, (me->pressed_mouse_button +
1081 (LEFT_RELEASE - LEFT_BUTTON))); 1211 (LEFT_RELEASE - LEFT_BUTTON)));
1082 } 1212 ret = min(ret, ret2);
1083 1213 }
1214
1215 /* Canonicalise CTRL+ASCII. */
1216 if ((button & MOD_CTRL) &&
1217 STRIP_BUTTON_MODIFIERS(button) >= 0x40 &&
1218 STRIP_BUTTON_MODIFIERS(button) < 0x80)
1219 button = button & (0x1f | (MOD_MASK & ~MOD_CTRL));
1220 /* Special handling to make CTRL+SHFT+Z into REDO. */
1221 if ((button & (~MOD_MASK | MOD_SHFT)) == (MOD_SHFT | '\x1A'))
1222 button = UI_REDO;
1223 /* interpret_move() expects CTRL and SHFT only on cursor keys, and
1224 * TAB (added as of 7/2024 to support Untangle). */
1225 if (!IS_CURSOR_MOVE(STRIP_BUTTON_MODIFIERS(button))) {
1226 /* reject CTRL+anything odd */
1227 if ((button & MOD_CTRL) && STRIP_BUTTON_MODIFIERS(button) >= 0x20)
1228 return PKR_UNUSED;
1229 /* otherwise strip them, except for tab */
1230 if (STRIP_BUTTON_MODIFIERS(button) != '\t')
1231 button &= ~(MOD_CTRL | MOD_SHFT);
1232 }
1233 /* interpret_move() expects NUM_KEYPAD only on numbers. */
1234 if (STRIP_BUTTON_MODIFIERS(button) < '0' ||
1235 STRIP_BUTTON_MODIFIERS(button) > '9')
1236 button &= ~MOD_NUM_KEYPAD;
1084 /* 1237 /*
1085 * Translate keyboard presses to cursor selection. 1238 * Translate keyboard presses to cursor selection.
1086 */ 1239 */
@@ -1101,7 +1254,8 @@ bool midend_process_key(midend *me, int x, int y, int button)
1101 /* 1254 /*
1102 * Now send on the event we originally received. 1255 * Now send on the event we originally received.
1103 */ 1256 */
1104 ret = ret && midend_really_process_key(me, x, y, button); 1257 ret2 = midend_really_process_key(me, x, y, button);
1258 ret = min(ret, ret2);
1105 1259
1106 /* 1260 /*
1107 * And update the currently pressed button. 1261 * And update the currently pressed button.
@@ -1121,7 +1275,7 @@ key_label *midend_request_keys(midend *me, int *n)
1121 1275
1122 if(me->ourgame->request_keys) 1276 if(me->ourgame->request_keys)
1123 { 1277 {
1124 keys = me->ourgame->request_keys(midend_get_params(me), &nkeys); 1278 keys = me->ourgame->request_keys(me->params, &nkeys);
1125 for(i = 0; i < nkeys; ++i) 1279 for(i = 0; i < nkeys; ++i)
1126 { 1280 {
1127 if(!keys[i].label) 1281 if(!keys[i].label)
@@ -1135,12 +1289,38 @@ key_label *midend_request_keys(midend *me, int *n)
1135 return keys; 1289 return keys;
1136} 1290}
1137 1291
1292/* Return a good label to show next to a key right now. */
1293const char *midend_current_key_label(midend *me, int button)
1294{
1295 assert(IS_CURSOR_SELECT(button));
1296 if (!me->ourgame->current_key_label) return "";
1297 return me->ourgame->current_key_label(
1298 me->ui, me->states[me->statepos-1].state, button);
1299}
1300
1138void midend_redraw(midend *me) 1301void midend_redraw(midend *me)
1139{ 1302{
1140 assert(me->drawing); 1303 assert(me->drawing);
1141 1304
1142 if (me->statepos > 0 && me->drawstate) { 1305 if (me->statepos > 0 && me->drawstate) {
1306 bool first_draw = me->first_draw;
1307 me->first_draw = false;
1308
1143 start_draw(me->drawing); 1309 start_draw(me->drawing);
1310
1311 if (first_draw) {
1312 /*
1313 * The initial contents of the window are not guaranteed
1314 * by the front end. But we also don't want to require
1315 * every single game to go to the effort of clearing the
1316 * window on setup. So we centralise here the operation of
1317 * covering the whole window with colour 0 (assumed to be
1318 * the puzzle's background colour) the first time we do a
1319 * redraw operation with a new drawstate.
1320 */
1321 draw_rect(me->drawing, 0, 0, me->winwidth, me->winheight, 0);
1322 }
1323
1144 if (me->oldstate && me->anim_time > 0 && 1324 if (me->oldstate && me->anim_time > 0 &&
1145 me->anim_pos < me->anim_time) { 1325 me->anim_pos < me->anim_time) {
1146 assert(me->dir != 0); 1326 assert(me->dir != 0);
@@ -1152,6 +1332,15 @@ void midend_redraw(midend *me)
1152 me->states[me->statepos-1].state, +1 /*shrug*/, 1332 me->states[me->statepos-1].state, +1 /*shrug*/,
1153 me->ui, 0.0, me->flash_pos); 1333 me->ui, 0.0, me->flash_pos);
1154 } 1334 }
1335
1336 if (first_draw) {
1337 /*
1338 * Call a big draw_update on the whole window, in case the
1339 * game backend didn't.
1340 */
1341 draw_update(me->drawing, 0, 0, me->winwidth, me->winheight);
1342 }
1343
1155 end_draw(me->drawing); 1344 end_draw(me->drawing);
1156 } 1345 }
1157} 1346}
@@ -1201,6 +1390,7 @@ float *midend_colours(midend *me, int *ncolours)
1201 float *ret; 1390 float *ret;
1202 1391
1203 ret = me->ourgame->colours(me->frontend, ncolours); 1392 ret = me->ourgame->colours(me->frontend, ncolours);
1393 assert(*ncolours >= 1);
1204 1394
1205 { 1395 {
1206 int i; 1396 int i;
@@ -1227,6 +1417,9 @@ float *midend_colours(midend *me, int *ncolours)
1227 ret[i*3 + 1] = g / 255.0F; 1417 ret[i*3 + 1] = g / 255.0F;
1228 ret[i*3 + 2] = b / 255.0F; 1418 ret[i*3 + 2] = b / 255.0F;
1229 } 1419 }
1420 assert(0.0F <= ret[i*3 + 0] && ret[i*3 + 0] <= 1.0F);
1421 assert(0.0F <= ret[i*3 + 1] && ret[i*3 + 1] <= 1.0F);
1422 assert(0.0F <= ret[i*3 + 2] && ret[i*3 + 2] <= 1.0F);
1230 } 1423 }
1231 } 1424 }
1232 1425
@@ -1359,7 +1552,7 @@ static void preset_menu_encode_params(midend *me, struct preset_menu *menu)
1359 for (i = 0; i < menu->n_entries; i++) { 1552 for (i = 0; i < menu->n_entries; i++) {
1360 if (menu->entries[i].params) { 1553 if (menu->entries[i].params) {
1361 me->encoded_presets[menu->entries[i].id] = 1554 me->encoded_presets[menu->entries[i].id] =
1362 me->ourgame->encode_params(menu->entries[i].params, true); 1555 encode_params(me, menu->entries[i].params, true);
1363 } else { 1556 } else {
1364 preset_menu_encode_params(me, menu->entries[i].submenu); 1557 preset_menu_encode_params(me, menu->entries[i].submenu);
1365 } 1558 }
@@ -1438,7 +1631,7 @@ struct preset_menu *midend_get_presets(midend *me, int *id_limit)
1438 1631
1439int midend_which_preset(midend *me) 1632int midend_which_preset(midend *me)
1440{ 1633{
1441 char *encoding = me->ourgame->encode_params(me->params, true); 1634 char *encoding = encode_params(me, me->params, true);
1442 int i, ret; 1635 int i, ret;
1443 1636
1444 ret = -1; 1637 ret = -1;
@@ -1496,6 +1689,10 @@ bool midend_get_cursor_location(midend *me,
1496void midend_supersede_game_desc(midend *me, const char *desc, 1689void midend_supersede_game_desc(midend *me, const char *desc,
1497 const char *privdesc) 1690 const char *privdesc)
1498{ 1691{
1692 /* Assert that the descriptions consists only of printable ASCII. */
1693 assert_printable_ascii(desc);
1694 if (privdesc)
1695 assert_printable_ascii(privdesc);
1499 sfree(me->desc); 1696 sfree(me->desc);
1500 sfree(me->privdesc); 1697 sfree(me->privdesc);
1501 me->desc = dupstr(desc); 1698 me->desc = dupstr(desc);
@@ -1545,7 +1742,7 @@ config_item *midend_get_config(midend *me, int which, char **wintitle)
1545 * the former is likely to persist across many code 1742 * the former is likely to persist across many code
1546 * changes). 1743 * changes).
1547 */ 1744 */
1548 parstr = me->ourgame->encode_params(me->curparams, which == CFG_SEED); 1745 parstr = encode_params(me, me->curparams, which == CFG_SEED);
1549 assert(parstr); 1746 assert(parstr);
1550 if (which == CFG_DESC) { 1747 if (which == CFG_DESC) {
1551 rest = me->desc ? me->desc : ""; 1748 rest = me->desc ? me->desc : "";
@@ -1562,6 +1759,10 @@ config_item *midend_get_config(midend *me, int which, char **wintitle)
1562 ret[1].name = NULL; 1759 ret[1].name = NULL;
1563 1760
1564 return ret; 1761 return ret;
1762 case CFG_PREFS:
1763 sprintf(titlebuf, "%s preferences", me->ourgame->name);
1764 *wintitle = titlebuf;
1765 return midend_get_prefs(me, NULL);
1565 } 1766 }
1566 1767
1567 assert(!"We shouldn't be here"); 1768 assert(!"We shouldn't be here");
@@ -1670,6 +1871,7 @@ static const char *midend_game_id_int(midend *me, const char *id, int defmode)
1670 newcurparams = me->ourgame->default_params(); 1871 newcurparams = me->ourgame->default_params();
1671 } 1872 }
1672 me->ourgame->decode_params(newcurparams, par); 1873 me->ourgame->decode_params(newcurparams, par);
1874 sfree(par);
1673 error = me->ourgame->validate_params(newcurparams, desc == NULL); 1875 error = me->ourgame->validate_params(newcurparams, desc == NULL);
1674 if (error) { 1876 if (error) {
1675 me->ourgame->free_params(newcurparams); 1877 me->ourgame->free_params(newcurparams);
@@ -1689,7 +1891,7 @@ static const char *midend_game_id_int(midend *me, const char *id, int defmode)
1689 1891
1690 newparams = me->ourgame->dup_params(me->params); 1892 newparams = me->ourgame->dup_params(me->params);
1691 1893
1692 tmpstr = me->ourgame->encode_params(newcurparams, false); 1894 tmpstr = encode_params(me, newcurparams, false);
1693 me->ourgame->decode_params(newparams, tmpstr); 1895 me->ourgame->decode_params(newparams, tmpstr);
1694 1896
1695 sfree(tmpstr); 1897 sfree(tmpstr);
@@ -1745,8 +1947,6 @@ static const char *midend_game_id_int(midend *me, const char *id, int defmode)
1745 me->genmode = GOT_SEED; 1947 me->genmode = GOT_SEED;
1746 } 1948 }
1747 1949
1748 sfree(par);
1749
1750 me->newgame_can_store_undo = false; 1950 me->newgame_can_store_undo = false;
1751 1951
1752 return NULL; 1952 return NULL;
@@ -1761,7 +1961,7 @@ char *midend_get_game_id(midend *me)
1761{ 1961{
1762 char *parstr, *ret; 1962 char *parstr, *ret;
1763 1963
1764 parstr = me->ourgame->encode_params(me->curparams, false); 1964 parstr = encode_params(me, me->curparams, false);
1765 assert(parstr); 1965 assert(parstr);
1766 assert(me->desc); 1966 assert(me->desc);
1767 ret = snewn(strlen(parstr) + strlen(me->desc) + 2, char); 1967 ret = snewn(strlen(parstr) + strlen(me->desc) + 2, char);
@@ -1777,7 +1977,7 @@ char *midend_get_random_seed(midend *me)
1777 if (!me->seedstr) 1977 if (!me->seedstr)
1778 return NULL; 1978 return NULL;
1779 1979
1780 parstr = me->ourgame->encode_params(me->curparams, true); 1980 parstr = encode_params(me, me->curparams, true);
1781 assert(parstr); 1981 assert(parstr);
1782 ret = snewn(strlen(parstr) + strlen(me->seedstr) + 2, char); 1982 ret = snewn(strlen(parstr) + strlen(me->seedstr) + 2, char);
1783 sprintf(ret, "%s#%s", parstr, me->seedstr); 1983 sprintf(ret, "%s#%s", parstr, me->seedstr);
@@ -1811,6 +2011,10 @@ const char *midend_set_config(midend *me, int which, config_item *cfg)
1811 if (error) 2011 if (error)
1812 return error; 2012 return error;
1813 break; 2013 break;
2014
2015 case CFG_PREFS:
2016 midend_set_prefs(me, me->ui, cfg);
2017 break;
1814 } 2018 }
1815 2019
1816 return NULL; 2020 return NULL;
@@ -1849,12 +2053,13 @@ const char *midend_solve(midend *me)
1849 movestr = me->ourgame->solve(me->states[0].state, 2053 movestr = me->ourgame->solve(me->states[0].state,
1850 me->states[me->statepos-1].state, 2054 me->states[me->statepos-1].state,
1851 me->aux_info, &msg); 2055 me->aux_info, &msg);
1852 assert(movestr != UI_UPDATE); 2056 assert(movestr != MOVE_UI_UPDATE);
1853 if (!movestr) { 2057 if (!movestr) {
1854 if (!msg) 2058 if (!msg)
1855 msg = "Solve operation failed"; /* _shouldn't_ happen, but can */ 2059 msg = "Solve operation failed"; /* _shouldn't_ happen, but can */
1856 return msg; 2060 return msg;
1857 } 2061 }
2062 assert_printable_ascii(movestr);
1858 s = me->ourgame->execute_move(me->states[me->statepos-1].state, movestr); 2063 s = me->ourgame->execute_move(me->states[me->statepos-1].state, movestr);
1859 assert(s); 2064 assert(s);
1860 2065
@@ -1961,7 +2166,9 @@ void midend_serialise(midend *me,
1961 char lbuf[9]; \ 2166 char lbuf[9]; \
1962 copy_left_justified(lbuf, sizeof(lbuf), h); \ 2167 copy_left_justified(lbuf, sizeof(lbuf), h); \
1963 sprintf(hbuf, "%s:%d:", lbuf, (int)strlen(str)); \ 2168 sprintf(hbuf, "%s:%d:", lbuf, (int)strlen(str)); \
2169 assert_printable_ascii(hbuf); \
1964 write(wctx, hbuf, strlen(hbuf)); \ 2170 write(wctx, hbuf, strlen(hbuf)); \
2171 assert_printable_ascii(str); \
1965 write(wctx, str, strlen(str)); \ 2172 write(wctx, str, strlen(str)); \
1966 write(wctx, "\n", 1); \ 2173 write(wctx, "\n", 1); \
1967} while (0) 2174} while (0)
@@ -1986,7 +2193,7 @@ void midend_serialise(midend *me,
1986 * The current long-term parameters structure, in full. 2193 * The current long-term parameters structure, in full.
1987 */ 2194 */
1988 if (me->params) { 2195 if (me->params) {
1989 char *s = me->ourgame->encode_params(me->params, true); 2196 char *s = encode_params(me, me->params, true);
1990 wr("PARAMS", s); 2197 wr("PARAMS", s);
1991 sfree(s); 2198 sfree(s);
1992 } 2199 }
@@ -1995,7 +2202,7 @@ void midend_serialise(midend *me,
1995 * The current short-term parameters structure, in full. 2202 * The current short-term parameters structure, in full.
1996 */ 2203 */
1997 if (me->curparams) { 2204 if (me->curparams) {
1998 char *s = me->ourgame->encode_params(me->curparams, true); 2205 char *s = encode_params(me, me->curparams, true);
1999 wr("CPARAMS", s); 2206 wr("CPARAMS", s);
2000 sfree(s); 2207 sfree(s);
2001 } 2208 }
@@ -2003,8 +2210,27 @@ void midend_serialise(midend *me,
2003 /* 2210 /*
2004 * The current game description, the privdesc, and the random seed. 2211 * The current game description, the privdesc, and the random seed.
2005 */ 2212 */
2006 if (me->seedstr) 2213 if (me->seedstr) {
2007 wr("SEED", me->seedstr); 2214 /*
2215 * Random seeds are not necessarily printable ASCII.
2216 * Hex-encode the seed if necessary. Printable ASCII seeds
2217 * are emitted unencoded for compatibility with older
2218 * versions.
2219 */
2220 int i;
2221
2222 for (i = 0; me->seedstr[i]; i++)
2223 if (me->seedstr[i] < 32 || me->seedstr[i] >= 127)
2224 break;
2225 if (me->seedstr[i]) {
2226 char *hexseed = bin2hex((unsigned char *)me->seedstr,
2227 strlen(me->seedstr));
2228
2229 wr("HEXSEED", hexseed);
2230 sfree(hexseed);
2231 } else
2232 wr("SEED", me->seedstr);
2233 }
2008 if (me->desc) 2234 if (me->desc)
2009 wr("DESC", me->desc); 2235 wr("DESC", me->desc);
2010 if (me->privdesc) 2236 if (me->privdesc)
@@ -2036,7 +2262,7 @@ void midend_serialise(midend *me,
2036 /* 2262 /*
2037 * Any required serialisation of the game_ui. 2263 * Any required serialisation of the game_ui.
2038 */ 2264 */
2039 if (me->ui) { 2265 if (me->ui && me->ourgame->encode_ui) {
2040 char *s = me->ourgame->encode_ui(me->ui); 2266 char *s = me->ourgame->encode_ui(me->ui);
2041 if (s) { 2267 if (s) {
2042 wr("UI", s); 2268 wr("UI", s);
@@ -2049,7 +2275,7 @@ void midend_serialise(midend *me,
2049 */ 2275 */
2050 if (me->ourgame->is_timed) { 2276 if (me->ourgame->is_timed) {
2051 char buf[80]; 2277 char buf[80];
2052 ftoa(buf, me->elapsed); 2278 sprintf(buf, "%g", me->elapsed);
2053 wr("TIME", buf); 2279 wr("TIME", buf);
2054 } 2280 }
2055 2281
@@ -2060,6 +2286,7 @@ void midend_serialise(midend *me,
2060 char buf[80]; 2286 char buf[80];
2061 sprintf(buf, "%d", me->nstates); 2287 sprintf(buf, "%d", me->nstates);
2062 wr("NSTATES", buf); 2288 wr("NSTATES", buf);
2289 assert(me->statepos >= 1 && me->statepos <= me->nstates);
2063 sprintf(buf, "%d", me->statepos); 2290 sprintf(buf, "%d", me->statepos);
2064 wr("STATEPOS", buf); 2291 wr("STATEPOS", buf);
2065 } 2292 }
@@ -2159,7 +2386,7 @@ static const char *midend_deserialise_internal(
2159 2386
2160 if (c == ':') { 2387 if (c == ':') {
2161 break; 2388 break;
2162 } else if (c >= '0' && c <= '9') { 2389 } else if (c >= '0' && c <= '9' && len < (INT_MAX - 10) / 10) {
2163 len = (len * 10) + (c - '0'); 2390 len = (len * 10) + (c - '0');
2164 } else { 2391 } else {
2165 if (started) 2392 if (started)
@@ -2171,10 +2398,17 @@ static const char *midend_deserialise_internal(
2171 2398
2172 val = snewn(len+1, char); 2399 val = snewn(len+1, char);
2173 if (!read(rctx, val, len)) { 2400 if (!read(rctx, val, len)) {
2174 if (started) 2401 /* unexpected EOF */
2175 goto cleanup; 2402 goto cleanup;
2176 } 2403 }
2177 val[len] = '\0'; 2404 val[len] = '\0';
2405 /* Validate that all values (apart from SEED) are printable ASCII. */
2406 if (strcmp(key, "SEED"))
2407 for (i = 0; val[i]; i++)
2408 if (val[i] < 32 || val[i] >= 127) {
2409 ret = "Forbidden characters in saved game file";
2410 goto cleanup;
2411 }
2178 2412
2179 if (!started) { 2413 if (!started) {
2180 if (strcmp(key, "SAVEFILE") || strcmp(val, SERIALISE_MAGIC)) { 2414 if (strcmp(key, "SAVEFILE") || strcmp(val, SERIALISE_MAGIC)) {
@@ -2204,6 +2438,15 @@ static const char *midend_deserialise_internal(
2204 sfree(data.cparstr); 2438 sfree(data.cparstr);
2205 data.cparstr = val; 2439 data.cparstr = val;
2206 val = NULL; 2440 val = NULL;
2441 } else if (!strcmp(key, "HEXSEED")) {
2442 unsigned char *tmp;
2443 int len = strlen(val) / 2; /* length in bytes */
2444 tmp = hex2bin(val, len);
2445 sfree(data.seed);
2446 data.seed = snewn(len + 1, char);
2447 memcpy(data.seed, tmp, len);
2448 data.seed[len] = '\0';
2449 sfree(tmp);
2207 } else if (!strcmp(key, "SEED")) { 2450 } else if (!strcmp(key, "SEED")) {
2208 sfree(data.seed); 2451 sfree(data.seed);
2209 data.seed = val; 2452 data.seed = val;
@@ -2234,15 +2477,15 @@ static const char *midend_deserialise_internal(
2234 } else if (!strcmp(key, "TIME")) { 2477 } else if (!strcmp(key, "TIME")) {
2235 data.elapsed = (float)atof(val); 2478 data.elapsed = (float)atof(val);
2236 } else if (!strcmp(key, "NSTATES")) { 2479 } else if (!strcmp(key, "NSTATES")) {
2480 if (data.states) {
2481 ret = "Two state counts provided in save file";
2482 goto cleanup;
2483 }
2237 data.nstates = atoi(val); 2484 data.nstates = atoi(val);
2238 if (data.nstates <= 0) { 2485 if (data.nstates <= 0) {
2239 ret = "Number of states in save file was negative"; 2486 ret = "Number of states in save file was negative";
2240 goto cleanup; 2487 goto cleanup;
2241 } 2488 }
2242 if (data.states) {
2243 ret = "Two state counts provided in save file";
2244 goto cleanup;
2245 }
2246 data.states = snewn(data.nstates, struct midend_state_entry); 2489 data.states = snewn(data.nstates, struct midend_state_entry);
2247 for (i = 0; i < data.nstates; i++) { 2490 for (i = 0; i < data.nstates; i++) {
2248 data.states[i].state = NULL; 2491 data.states[i].state = NULL;
@@ -2251,19 +2494,25 @@ static const char *midend_deserialise_internal(
2251 } 2494 }
2252 } else if (!strcmp(key, "STATEPOS")) { 2495 } else if (!strcmp(key, "STATEPOS")) {
2253 data.statepos = atoi(val); 2496 data.statepos = atoi(val);
2254 } else if (!strcmp(key, "MOVE")) { 2497 } else if (!strcmp(key, "MOVE") ||
2255 gotstates++; 2498 !strcmp(key, "SOLVE") ||
2256 data.states[gotstates].movetype = MOVE; 2499 !strcmp(key, "RESTART")) {
2257 data.states[gotstates].movestr = val; 2500 if (!data.states) {
2258 val = NULL; 2501 ret = "No state count provided in save file";
2259 } else if (!strcmp(key, "SOLVE")) { 2502 goto cleanup;
2260 gotstates++; 2503 }
2261 data.states[gotstates].movetype = SOLVE; 2504 if (data.statepos < 0) {
2262 data.states[gotstates].movestr = val; 2505 ret = "No game position provided in save file";
2263 val = NULL; 2506 goto cleanup;
2264 } else if (!strcmp(key, "RESTART")) { 2507 }
2265 gotstates++; 2508 gotstates++;
2266 data.states[gotstates].movetype = RESTART; 2509 assert(gotstates < data.nstates);
2510 if (!strcmp(key, "MOVE"))
2511 data.states[gotstates].movetype = MOVE;
2512 else if (!strcmp(key, "SOLVE"))
2513 data.states[gotstates].movetype = SOLVE;
2514 else
2515 data.states[gotstates].movetype = RESTART;
2267 data.states[gotstates].movestr = val; 2516 data.states[gotstates].movestr = val;
2268 val = NULL; 2517 val = NULL;
2269 } 2518 }
@@ -2274,12 +2523,20 @@ static const char *midend_deserialise_internal(
2274 } 2523 }
2275 2524
2276 data.params = me->ourgame->default_params(); 2525 data.params = me->ourgame->default_params();
2526 if (!data.parstr) {
2527 ret = "Long-term parameters in save file are missing";
2528 goto cleanup;
2529 }
2277 me->ourgame->decode_params(data.params, data.parstr); 2530 me->ourgame->decode_params(data.params, data.parstr);
2278 if (me->ourgame->validate_params(data.params, true)) { 2531 if (me->ourgame->validate_params(data.params, true)) {
2279 ret = "Long-term parameters in save file are invalid"; 2532 ret = "Long-term parameters in save file are invalid";
2280 goto cleanup; 2533 goto cleanup;
2281 } 2534 }
2282 data.cparams = me->ourgame->default_params(); 2535 data.cparams = me->ourgame->default_params();
2536 if (!data.cparstr) {
2537 ret = "Short-term parameters in save file are missing";
2538 goto cleanup;
2539 }
2283 me->ourgame->decode_params(data.cparams, data.cparstr); 2540 me->ourgame->decode_params(data.cparams, data.cparstr);
2284 if (me->ourgame->validate_params(data.cparams, false)) { 2541 if (me->ourgame->validate_params(data.cparams, false)) {
2285 ret = "Short-term parameters in save file are invalid"; 2542 ret = "Short-term parameters in save file are invalid";
@@ -2305,12 +2562,18 @@ static const char *midend_deserialise_internal(
2305 ret = "Game private description in save file is invalid"; 2562 ret = "Game private description in save file is invalid";
2306 goto cleanup; 2563 goto cleanup;
2307 } 2564 }
2308 if (data.statepos < 0 || data.statepos >= data.nstates) { 2565 if (data.statepos < 1 || data.statepos > data.nstates) {
2309 ret = "Game position in save file is out of range"; 2566 ret = "Game position in save file is out of range";
2567 goto cleanup;
2310 } 2568 }
2311 2569
2570 if (!data.states) {
2571 ret = "No state count provided in save file";
2572 goto cleanup;
2573 }
2312 data.states[0].state = me->ourgame->new_game( 2574 data.states[0].state = me->ourgame->new_game(
2313 me, data.cparams, data.privdesc ? data.privdesc : data.desc); 2575 me, data.cparams, data.privdesc ? data.privdesc : data.desc);
2576
2314 for (i = 1; i < data.nstates; i++) { 2577 for (i = 1; i < data.nstates; i++) {
2315 assert(data.states[i].movetype != NEWGAME); 2578 assert(data.states[i].movetype != NEWGAME);
2316 switch (data.states[i].movetype) { 2579 switch (data.states[i].movetype) {
@@ -2336,7 +2599,10 @@ static const char *midend_deserialise_internal(
2336 } 2599 }
2337 2600
2338 data.ui = me->ourgame->new_ui(data.states[0].state); 2601 data.ui = me->ourgame->new_ui(data.states[0].state);
2339 me->ourgame->decode_ui(data.ui, data.uistr); 2602 midend_apply_prefs(me, data.ui);
2603 if (data.uistr && me->ourgame->decode_ui)
2604 me->ourgame->decode_ui(data.ui, data.uistr,
2605 data.states[data.statepos-1].state);
2340 2606
2341 /* 2607 /*
2342 * Run the externally provided check function, and abort if it 2608 * Run the externally provided check function, and abort if it
@@ -2429,6 +2695,7 @@ static const char *midend_deserialise_internal(
2429 me->drawstate = 2695 me->drawstate =
2430 me->ourgame->new_drawstate(me->drawing, 2696 me->ourgame->new_drawstate(me->drawing,
2431 me->states[me->statepos-1].state); 2697 me->states[me->statepos-1].state);
2698 me->first_draw = true;
2432 midend_size_new_drawstate(me); 2699 midend_size_new_drawstate(me);
2433 if (me->game_id_change_notify_function) 2700 if (me->game_id_change_notify_function)
2434 me->game_id_change_notify_function(me->game_id_change_notify_ctx); 2701 me->game_id_change_notify_function(me->game_id_change_notify_ctx);
@@ -2528,7 +2795,7 @@ const char *identify_game(char **name,
2528 2795
2529 if (c == ':') { 2796 if (c == ':') {
2530 break; 2797 break;
2531 } else if (c >= '0' && c <= '9') { 2798 } else if (c >= '0' && c <= '9' && len < (INT_MAX - 10) / 10) {
2532 len = (len * 10) + (c - '0'); 2799 len = (len * 10) + (c - '0');
2533 } else { 2800 } else {
2534 if (started) 2801 if (started)
@@ -2540,7 +2807,7 @@ const char *identify_game(char **name,
2540 2807
2541 val = snewn(len+1, char); 2808 val = snewn(len+1, char);
2542 if (!read(rctx, val, len)) { 2809 if (!read(rctx, val, len)) {
2543 if (started) 2810 /* unexpected EOF */
2544 goto cleanup; 2811 goto cleanup;
2545 } 2812 }
2546 val[len] = '\0'; 2813 val[len] = '\0';
@@ -2605,14 +2872,340 @@ const char *midend_print_puzzle(midend *me, document *doc, bool with_soln)
2605 soln = NULL; 2872 soln = NULL;
2606 2873
2607 /* 2874 /*
2608 * This call passes over ownership of the two game_states and 2875 * This call passes over ownership of the two game_states, the
2609 * the game_params. Hence we duplicate the ones we want to 2876 * game_params and the game_ui. Hence we duplicate the ones we
2610 * keep, and we don't have to bother freeing soln if it was 2877 * want to keep, and we don't have to bother freeing soln if it
2611 * non-NULL. 2878 * was non-NULL.
2612 */ 2879 */
2880 game_ui *ui = me->ourgame->new_ui(me->states[0].state);
2881 midend_apply_prefs(me, ui);
2613 document_add_puzzle(doc, me->ourgame, 2882 document_add_puzzle(doc, me->ourgame,
2614 me->ourgame->dup_params(me->curparams), 2883 me->ourgame->dup_params(me->curparams), ui,
2615 me->ourgame->dup_game(me->states[0].state), soln); 2884 me->ourgame->dup_game(me->states[0].state), soln);
2616 2885
2617 return NULL; 2886 return NULL;
2618} 2887}
2888
2889static void midend_apply_prefs(midend *me, game_ui *ui)
2890{
2891 struct midend_serialise_buf_read_ctx rctx[1];
2892 rctx->ser = &me->be_prefs;
2893 rctx->len = me->be_prefs.len;
2894 rctx->pos = 0;
2895 const char *err = midend_deserialise_prefs(
2896 me, ui, midend_serialise_buf_read, rctx);
2897 /* This should have come from our own serialise function, so
2898 * it should never be invalid. */
2899 assert(!err && "Bad internal serialisation of preferences");
2900}
2901
2902static config_item *midend_get_prefs(midend *me, game_ui *ui)
2903{
2904 int n_be_prefs, n_me_prefs, pos, i;
2905 config_item *all_prefs, *be_prefs;
2906
2907 be_prefs = NULL;
2908 n_be_prefs = 0;
2909 if (me->ourgame->get_prefs) {
2910 if (ui) {
2911 be_prefs = me->ourgame->get_prefs(ui);
2912 } else if (me->ui) {
2913 be_prefs = me->ourgame->get_prefs(me->ui);
2914 } else {
2915 game_ui *tmp_ui = me->ourgame->new_ui(NULL);
2916 be_prefs = me->ourgame->get_prefs(tmp_ui);
2917 me->ourgame->free_ui(tmp_ui);
2918 }
2919 while (be_prefs[n_be_prefs].type != C_END)
2920 n_be_prefs++;
2921 }
2922
2923 n_me_prefs = 1;
2924 all_prefs = snewn(n_me_prefs + n_be_prefs + 1, config_item);
2925
2926 pos = 0;
2927
2928 assert(pos < n_me_prefs);
2929 all_prefs[pos].name = "Keyboard shortcuts without Ctrl";
2930 all_prefs[pos].kw = "one-key-shortcuts";
2931 all_prefs[pos].type = C_BOOLEAN;
2932 all_prefs[pos].u.boolean.bval = me->one_key_shortcuts;
2933 pos++;
2934
2935 for (i = 0; i < n_be_prefs; i++) {
2936 all_prefs[pos] = be_prefs[i]; /* structure copy */
2937 pos++;
2938 }
2939
2940 all_prefs[pos].name = NULL;
2941 all_prefs[pos].type = C_END;
2942
2943 if (be_prefs)
2944 /* We already copied each element, so don't free those with
2945 free_cfg(). */
2946 sfree(be_prefs);
2947
2948 return all_prefs;
2949}
2950
2951static void midend_set_prefs(midend *me, game_ui *ui, config_item *all_prefs)
2952{
2953 int pos = 0;
2954 game_ui *tmpui = NULL;
2955
2956 me->one_key_shortcuts = all_prefs[pos].u.boolean.bval;
2957 pos++;
2958
2959 if (me->ourgame->get_prefs) {
2960 if (!ui)
2961 ui = tmpui = me->ourgame->new_ui(NULL);
2962 me->ourgame->set_prefs(ui, all_prefs + pos);
2963 }
2964
2965 me->be_prefs.len = 0;
2966 midend_serialise_prefs(me, ui, midend_serialise_buf_write, &me->be_prefs);
2967
2968 if (tmpui)
2969 me->ourgame->free_ui(tmpui);
2970}
2971
2972static void midend_serialise_prefs(
2973 midend *me, game_ui *ui,
2974 void (*write)(void *ctx, const void *buf, int len), void *wctx)
2975{
2976 config_item *cfg;
2977 int i;
2978
2979 cfg = midend_get_prefs(me, ui);
2980
2981 assert(cfg);
2982
2983 for (i = 0; cfg[i].type != C_END; i++) {
2984 config_item *it = &cfg[i];
2985
2986 /* Expect keywords to be made up only of simple characters */
2987 assert(it->kw[strspn(it->kw, "abcdefghijklmnopqrstuvwxyz-")] == '\0');
2988
2989 write(wctx, it->kw, strlen(it->kw));
2990 write(wctx, "=", 1);
2991
2992 switch (it->type) {
2993 case C_BOOLEAN:
2994 if (it->u.boolean.bval)
2995 write(wctx, "true", 4);
2996 else
2997 write(wctx, "false", 5);
2998 break;
2999 case C_STRING: {
3000 const char *p = it->u.string.sval;
3001 while (*p) {
3002 char c = *p++;
3003 write(wctx, &c, 1);
3004 if (c == '\n')
3005 write(wctx, " ", 1);
3006 }
3007 break;
3008 }
3009 case C_CHOICES: {
3010 int n = it->u.choices.selected;
3011 const char *p = it->u.choices.choicekws;
3012 char sepstr[2];
3013
3014 sepstr[0] = *p++;
3015 sepstr[1] = '\0';
3016
3017 while (n > 0) {
3018 const char *q = strchr(p, sepstr[0]);
3019 assert(q != NULL && "Value out of range in C_CHOICES");
3020 p = q+1;
3021 n--;
3022 }
3023
3024 write(wctx, p, strcspn(p, sepstr));
3025 break;
3026 }
3027 }
3028
3029 write(wctx, "\n", 1);
3030 }
3031
3032 free_cfg(cfg);
3033}
3034
3035struct buffer {
3036 char *data;
3037 size_t len, size;
3038};
3039
3040static void buffer_append(struct buffer *buf, char c)
3041{
3042 if (buf->len + 2 > buf->size) {
3043 size_t new_size = buf->size + buf->size / 4 + 128;
3044 assert(new_size > buf->size);
3045 buf->data = sresize(buf->data, new_size, char);
3046 buf->size = new_size;
3047 assert(buf->len < buf->size);
3048 }
3049 buf->data[buf->len++] = c;
3050 assert(buf->len < buf->size);
3051 buf->data[buf->len] = '\0';
3052}
3053
3054static const char *midend_deserialise_prefs(
3055 midend *me, game_ui *ui,
3056 bool (*read)(void *ctx, void *buf, int len), void *rctx)
3057{
3058 config_item *cfg, *it;
3059 int i;
3060 struct buffer buf[1] = {{ NULL, 0, 0 }};
3061 const char *errmsg = NULL;
3062 char read_char;
3063 char ungot_char = '\0';
3064 bool have_ungot_a_char = false, eof = false;
3065
3066 cfg = midend_get_prefs(me, ui);
3067
3068 while (!eof) {
3069 if (have_ungot_a_char) {
3070 read_char = ungot_char;
3071 have_ungot_a_char = false;
3072 } else {
3073 if (!read(rctx, &read_char, 1))
3074 goto out; /* EOF at line start == success */
3075 }
3076
3077 if (read_char == '#' || read_char == '\n') {
3078 /* Skip comment or blank line */
3079 while (read_char != '\n') {
3080 if (!read(rctx, &read_char, 1))
3081 goto out; /* EOF during boring line == success */
3082 }
3083 continue;
3084 }
3085
3086 buf->len = 0;
3087 while (true) {
3088 buffer_append(buf, read_char);
3089 if (!read(rctx, &read_char, 1)) {
3090 errmsg = "Partial line at end of preferences file";
3091 goto out;
3092 }
3093 if (read_char == '\n') {
3094 errmsg = "Expected '=' after keyword";
3095 goto out;
3096 }
3097 if (read_char == '=')
3098 break;
3099 }
3100
3101 it = NULL;
3102 for (i = 0; cfg[i].type != C_END; i++)
3103 if (!strcmp(buf->data, cfg[i].kw))
3104 it = &cfg[i];
3105
3106 buf->len = 0;
3107 while (true) {
3108 if (!read(rctx, &read_char, 1)) {
3109 /* We tolerate missing \n at the end of the file, so
3110 * this is taken to mean we've got a complete config
3111 * directive. But set the eof flag so that we stop
3112 * after processing it. */
3113 eof = true;
3114 break;
3115 } else if (read_char == '\n') {
3116 /* Newline _might_ be the end of this config
3117 * directive, unless it's followed by a space, in
3118 * which case it's a space-stuffed line
3119 * continuation. */
3120 if (read(rctx, &read_char, 1)) {
3121 if (read_char == ' ') {
3122 buffer_append(buf, '\n');
3123 continue;
3124 } else {
3125 /* But if the next character wasn't a space,
3126 * then we must unget it so that it'll be
3127 * available to the next iteration of our
3128 * outer loop as the first character of the
3129 * next keyword. */
3130 ungot_char = read_char;
3131 have_ungot_a_char = true;
3132 break;
3133 }
3134 } else {
3135 /* And if the newline was followed by EOF, then we
3136 * should finish this iteration of the outer
3137 * loop normally, and then not go round again. */
3138 eof = true;
3139 break;
3140 }
3141 } else {
3142 /* Any other character is just added to the buffer. */
3143 buffer_append(buf, read_char);
3144 }
3145 }
3146
3147 if (!it) {
3148 /*
3149 * Tolerate unknown keywords in a preferences file, on the
3150 * assumption that they're from a different (probably
3151 * later) version of the game.
3152 */
3153 continue;
3154 }
3155
3156 switch (it->type) {
3157 case C_BOOLEAN:
3158 if (!strcmp(buf->data, "true"))
3159 it->u.boolean.bval = true;
3160 else if (!strcmp(buf->data, "false"))
3161 it->u.boolean.bval = false;
3162 else {
3163 errmsg = "Value for boolean was not 'true' or 'false'";
3164 goto out;
3165 }
3166 break;
3167 case C_STRING:
3168 sfree(it->u.string.sval);
3169 it->u.string.sval = buf->data;
3170 buf->data = NULL;
3171 buf->len = buf->size = 0;
3172 break;
3173 case C_CHOICES: {
3174 int n = 0;
3175 bool found = false;
3176 const char *p = it->u.choices.choicekws;
3177 char sepstr[2];
3178
3179 sepstr[0] = *p;
3180 sepstr[1] = '\0';
3181
3182 while (*p++) {
3183 int len = strcspn(p, sepstr);
3184 if (buf->len == len && !memcmp(p, buf->data, len)) {
3185 it->u.choices.selected = n;
3186 found = true;
3187 break;
3188 }
3189 p += len;
3190 n++;
3191 }
3192
3193 if (!found) {
3194 errmsg = "Invalid value for enumeration";
3195 goto out;
3196 }
3197
3198 break;
3199 }
3200 }
3201 }
3202
3203 out:
3204
3205 if (!errmsg)
3206 midend_set_prefs(me, ui, cfg);
3207
3208 free_cfg(cfg);
3209 sfree(buf->data);
3210 return errmsg;
3211}
diff --git a/apps/plugins/puzzles/src/mines.R b/apps/plugins/puzzles/src/mines.R
deleted file mode 100644
index 275c76c7ad..0000000000
--- a/apps/plugins/puzzles/src/mines.R
+++ /dev/null
@@ -1,24 +0,0 @@
1# -*- makefile -*-
2
3MINES_EXTRA = tree234
4
5mines : [X] GTK COMMON mines MINES_EXTRA mines-icon|no-icon
6
7mines : [G] WINDOWS COMMON mines MINES_EXTRA mines.res|noicon.res
8
9mineobfusc : [U] mines[STANDALONE_OBFUSCATOR] MINES_EXTRA STANDALONE
10mineobfusc : [C] mines[STANDALONE_OBFUSCATOR] MINES_EXTRA STANDALONE
11
12ALL += mines[COMBINED] MINES_EXTRA
13
14!begin am gtk
15GAMES += mines
16!end
17
18!begin >list.c
19 A(mines) \
20!end
21
22!begin >gamedesc.txt
23mines:mines.exe:Mines:Mine-finding puzzle:Find all the mines without treading on any of them.
24!end
diff --git a/apps/plugins/puzzles/src/mines.c b/apps/plugins/puzzles/src/mines.c
index 706777c4f1..e1441fae13 100644
--- a/apps/plugins/puzzles/src/mines.c
+++ b/apps/plugins/puzzles/src/mines.c
@@ -3,8 +3,7 @@
3 * 3 *
4 * Still TODO: 4 * Still TODO:
5 * 5 *
6 * - think about configurably supporting question marks. Once, 6 * - think about configurably supporting question marks.
7 * that is, we've thought about configurability in general!
8 */ 7 */
9 8
10#include <stdio.h> 9#include <stdio.h>
@@ -12,7 +11,12 @@
12#include <string.h> 11#include <string.h>
13#include <assert.h> 12#include <assert.h>
14#include <ctype.h> 13#include <ctype.h>
15#include <math.h> 14#include <limits.h>
15#ifdef NO_TGMATH_H
16# include <math.h>
17#else
18# include <tgmath.h>
19#endif
16 20
17#include "tree234.h" 21#include "tree234.h"
18#include "puzzles.h" 22#include "puzzles.h"
@@ -34,8 +38,8 @@ enum {
34#else 38#else
35#define BORDER (TILE_SIZE * 3 / 2) 39#define BORDER (TILE_SIZE * 3 / 2)
36#endif 40#endif
37#define HIGHLIGHT_WIDTH (TILE_SIZE / 10) 41#define HIGHLIGHT_WIDTH (TILE_SIZE / 10 ? TILE_SIZE / 10 : 1)
38#define OUTER_HIGHLIGHT_WIDTH (BORDER / 10) 42#define OUTER_HIGHLIGHT_WIDTH (BORDER / 10 ? BORDER / 10 : 1)
39#define COORD(x) ( (x) * TILE_SIZE + BORDER ) 43#define COORD(x) ( (x) * TILE_SIZE + BORDER )
40#define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 ) 44#define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 )
41 45
@@ -162,7 +166,9 @@ static void decode_params(game_params *params, char const *string)
162 params->n = atoi(p); 166 params->n = atoi(p);
163 while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++; 167 while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++;
164 } else { 168 } else {
165 params->n = params->w * params->h / 10; 169 if (params->h > 0 && params->w > 0 &&
170 params->w <= INT_MAX / params->h)
171 params->n = params->w * params->h / 10;
166 } 172 }
167 173
168 while (*p) { 174 while (*p) {
@@ -250,7 +256,7 @@ static const char *validate_params(const game_params *params, bool full)
250 * blocking the way and no idea what's behind them, or one mine 256 * blocking the way and no idea what's behind them, or one mine
251 * and no way to know which of the two rows it's in. If the 257 * and no way to know which of the two rows it's in. If the
252 * mine count is even you can create a soluble grid by packing 258 * mine count is even you can create a soluble grid by packing
253 * all the mines at one end (so what when you hit a two-mine 259 * all the mines at one end (so that when you hit a two-mine
254 * wall there are only as many covered squares left as there 260 * wall there are only as many covered squares left as there
255 * are mines); but if it's odd, you are doomed, because you 261 * are mines); but if it's odd, you are doomed, because you
256 * _have_ to have a gap somewhere which you can't determine the 262 * _have_ to have a gap somewhere which you can't determine the
@@ -258,12 +264,25 @@ static const char *validate_params(const game_params *params, bool full)
258 */ 264 */
259 if (full && params->unique && (params->w <= 2 || params->h <= 2)) 265 if (full && params->unique && (params->w <= 2 || params->h <= 2))
260 return "Width and height must both be greater than two"; 266 return "Width and height must both be greater than two";
267 if (params->w < 1 || params->h < 1)
268 return "Width and height must both be at least one";
269 if (params->w > SHRT_MAX || params->h > SHRT_MAX)
270 return "Neither width nor height may be unreasonably large";
271 /*
272 * We use random_upto() to place mines, and its maximum limit is 2^28-1.
273 */
274#if (1<<28)-1 < INT_MAX
275 if (params->w > ((1<<28)-1) / params->h)
276#else
277 if (params->w > INT_MAX / params->h)
278#endif
279 return "Width times height must not be unreasonably large";
261 if (params->n < 0) 280 if (params->n < 0)
262 return "Mine count may not be negative"; 281 return "Mine count may not be negative";
263 if (params->n > params->w * params->h - 9)
264 return "Too many mines for grid size";
265 if (params->n < 1) 282 if (params->n < 1)
266 return "Number of mines must be greater than zero"; 283 return "Number of mines must be greater than zero";
284 if (params->n > params->w * params->h - 9)
285 return "Too many mines for grid size";
267 286
268 /* 287 /*
269 * FIXME: Need more constraints here. Not sure what the 288 * FIXME: Need more constraints here. Not sure what the
@@ -428,7 +447,9 @@ static void ss_add(struct setstore *ss, int x, int y, int mask, int mines)
428 * Create a set structure and add it to the tree. 447 * Create a set structure and add it to the tree.
429 */ 448 */
430 s = snew(struct set); 449 s = snew(struct set);
450 assert(SHRT_MIN <= x && x <= SHRT_MAX);
431 s->x = x; 451 s->x = x;
452 assert(SHRT_MIN <= y && y <= SHRT_MAX);
432 s->y = y; 453 s->y = y;
433 s->mask = mask; 454 s->mask = mask;
434 s->mines = mines; 455 s->mines = mines;
@@ -499,7 +520,9 @@ static struct set **ss_overlap(struct setstore *ss, int x, int y, int mask)
499 /* 520 /*
500 * Find the first set with these top left coordinates. 521 * Find the first set with these top left coordinates.
501 */ 522 */
523 assert(SHRT_MIN <= xx && xx <= SHRT_MAX);
502 stmp.x = xx; 524 stmp.x = xx;
525 assert(SHRT_MIN <= yy && yy <= SHRT_MAX);
503 stmp.y = yy; 526 stmp.y = yy;
504 stmp.mask = 0; 527 stmp.mask = 0;
505 528
@@ -1880,72 +1903,7 @@ static char *describe_layout(bool *grid, int area, int x, int y,
1880static bool *new_mine_layout(int w, int h, int n, int x, int y, bool unique, 1903static bool *new_mine_layout(int w, int h, int n, int x, int y, bool unique,
1881 random_state *rs, char **game_desc) 1904 random_state *rs, char **game_desc)
1882{ 1905{
1883 bool *grid; 1906 bool *grid = minegen(w, h, n, x, y, unique, rs);
1884
1885#ifdef TEST_OBFUSCATION
1886 static int tested_obfuscation = false;
1887 if (!tested_obfuscation) {
1888 /*
1889 * A few simple test vectors for the obfuscator.
1890 *
1891 * First test: the 28-bit stream 1234567. This divides up
1892 * into 1234 and 567[0]. The SHA of 56 70 30 (appending
1893 * "0") is 15ce8ab946640340bbb99f3f48fd2c45d1a31d30. Thus,
1894 * we XOR the 16-bit string 15CE into the input 1234 to get
1895 * 07FA. Next, we SHA that with "0": the SHA of 07 FA 30 is
1896 * 3370135c5e3da4fed937adc004a79533962b6391. So we XOR the
1897 * 12-bit string 337 into the input 567 to get 650. Thus
1898 * our output is 07FA650.
1899 */
1900 {
1901 unsigned char bmp1[] = "\x12\x34\x56\x70";
1902 obfuscate_bitmap(bmp1, 28, false);
1903 printf("test 1 encode: %s\n",
1904 memcmp(bmp1, "\x07\xfa\x65\x00", 4) ? "failed" : "passed");
1905 obfuscate_bitmap(bmp1, 28, true);
1906 printf("test 1 decode: %s\n",
1907 memcmp(bmp1, "\x12\x34\x56\x70", 4) ? "failed" : "passed");
1908 }
1909 /*
1910 * Second test: a long string to make sure we switch from
1911 * one SHA to the next correctly. My input string this time
1912 * is simply fifty bytes of zeroes.
1913 */
1914 {
1915 unsigned char bmp2[50];
1916 unsigned char bmp2a[50];
1917 memset(bmp2, 0, 50);
1918 memset(bmp2a, 0, 50);
1919 obfuscate_bitmap(bmp2, 50 * 8, false);
1920 /*
1921 * SHA of twenty-five zero bytes plus "0" is
1922 * b202c07b990c01f6ff2d544707f60e506019b671. SHA of
1923 * twenty-five zero bytes plus "1" is
1924 * fcb1d8b5a2f6b592fe6780b36aa9d65dd7aa6db9. Thus our
1925 * first half becomes
1926 * b202c07b990c01f6ff2d544707f60e506019b671fcb1d8b5a2.
1927 *
1928 * SHA of that lot plus "0" is
1929 * 10b0af913db85d37ca27f52a9f78bba3a80030db. SHA of the
1930 * same string plus "1" is
1931 * 3d01d8df78e76d382b8106f480135a1bc751d725. So the
1932 * second half becomes
1933 * 10b0af913db85d37ca27f52a9f78bba3a80030db3d01d8df78.
1934 */
1935 printf("test 2 encode: %s\n",
1936 memcmp(bmp2, "\xb2\x02\xc0\x7b\x99\x0c\x01\xf6\xff\x2d\x54"
1937 "\x47\x07\xf6\x0e\x50\x60\x19\xb6\x71\xfc\xb1\xd8"
1938 "\xb5\xa2\x10\xb0\xaf\x91\x3d\xb8\x5d\x37\xca\x27"
1939 "\xf5\x2a\x9f\x78\xbb\xa3\xa8\x00\x30\xdb\x3d\x01"
1940 "\xd8\xdf\x78", 50) ? "failed" : "passed");
1941 obfuscate_bitmap(bmp2, 50 * 8, true);
1942 printf("test 2 decode: %s\n",
1943 memcmp(bmp2, bmp2a, 50) ? "failed" : "passed");
1944 }
1945 }
1946#endif
1947
1948 grid = minegen(w, h, n, x, y, unique, rs);
1949 1907
1950 if (game_desc) 1908 if (game_desc)
1951 *game_desc = describe_layout(grid, w * h, x, y, true); 1909 *game_desc = describe_layout(grid, w * h, x, y, true);
@@ -2001,6 +1959,8 @@ static const char *validate_desc(const game_params *params, const char *desc)
2001 desc++; 1959 desc++;
2002 if (!*desc || !isdigit((unsigned char)*desc)) 1960 if (!*desc || !isdigit((unsigned char)*desc))
2003 return "No initial mine count in game description"; 1961 return "No initial mine count in game description";
1962 if (atoi(desc) > wh - 9)
1963 return "Too many mines for grid size";
2004 while (*desc && isdigit((unsigned char)*desc)) 1964 while (*desc && isdigit((unsigned char)*desc))
2005 desc++; /* skip over mine count */ 1965 desc++; /* skip over mine count */
2006 if (*desc != ',') 1966 if (*desc != ',')
@@ -2139,6 +2099,8 @@ static int open_square(game_state *state, int x, int y)
2139 break; 2099 break;
2140 } 2100 }
2141 2101
2102 /* If the player has already lost, don't let them win as well. */
2103 if (state->dead) return 0;
2142 /* 2104 /*
2143 * Finally, scan the grid and see if exactly as many squares 2105 * Finally, scan the grid and see if exactly as many squares
2144 * are still covered as there are mines. If so, set the `won' 2106 * are still covered as there are mines. If so, set the `won'
@@ -2365,7 +2327,7 @@ static game_ui *new_ui(const game_state *state)
2365 ui->completed = false; 2327 ui->completed = false;
2366 ui->flash_is_death = false; /* *shrug* */ 2328 ui->flash_is_death = false; /* *shrug* */
2367 ui->cur_x = ui->cur_y = 0; 2329 ui->cur_x = ui->cur_y = 0;
2368 ui->cur_visible = false; 2330 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
2369 return ui; 2331 return ui;
2370} 2332}
2371 2333
@@ -2387,7 +2349,8 @@ static char *encode_ui(const game_ui *ui)
2387 return dupstr(buf); 2349 return dupstr(buf);
2388} 2350}
2389 2351
2390static void decode_ui(game_ui *ui, const char *encoding) 2352static void decode_ui(game_ui *ui, const char *encoding,
2353 const game_state *state)
2391{ 2354{
2392 int p= 0; 2355 int p= 0;
2393 sscanf(encoding, "D%d%n", &ui->deaths, &p); 2356 sscanf(encoding, "D%d%n", &ui->deaths, &p);
@@ -2402,6 +2365,35 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
2402 ui->completed = true; 2365 ui->completed = true;
2403} 2366}
2404 2367
2368static const char *current_key_label(const game_ui *ui,
2369 const game_state *state, int button)
2370{
2371 int cx = ui->cur_x, cy = ui->cur_y;
2372 int v = state->grid[cy * state->w + cx];
2373
2374 if (state->dead || state->won || !ui->cur_visible) return "";
2375 if (button == CURSOR_SELECT2) {
2376 if (v == -2) return "Mark";
2377 if (v == -1) return "Unmark";
2378 return "";
2379 }
2380 if (button == CURSOR_SELECT) {
2381 int dy, dx, n = 0;
2382 if (v == -2 || v == -3) return "Uncover";
2383 if (v == 0) return "";
2384 /* Count mine markers. */
2385 for (dy = -1; dy <= +1; dy++)
2386 for (dx = -1; dx <= +1; dx++)
2387 if (cx+dx >= 0 && cx+dx < state->w &&
2388 cy+dy >= 0 && cy+dy < state->h) {
2389 if (state->grid[(cy+dy)*state->w+(cx+dx)] == -1)
2390 n++;
2391 }
2392 if (n == v) return "Clear";
2393 }
2394 return "";
2395}
2396
2405struct game_drawstate { 2397struct game_drawstate {
2406 int w, h, tilesize, bg; 2398 int w, h, tilesize, bg;
2407 bool started; 2399 bool started;
@@ -2432,22 +2424,20 @@ static char *interpret_move(const game_state *from, game_ui *ui,
2432 cx = FROMCOORD(x); 2424 cx = FROMCOORD(x);
2433 cy = FROMCOORD(y); 2425 cy = FROMCOORD(y);
2434 2426
2435 if (IS_CURSOR_MOVE(button)) { 2427 if (IS_CURSOR_MOVE(button))
2436 move_cursor(button, &ui->cur_x, &ui->cur_y, from->w, from->h, false); 2428 return move_cursor(button, &ui->cur_x, &ui->cur_y, from->w, from->h,
2437 ui->cur_visible = true; 2429 false, &ui->cur_visible);
2438 return UI_UPDATE;
2439 }
2440 if (IS_CURSOR_SELECT(button)) { 2430 if (IS_CURSOR_SELECT(button)) {
2441 int v = from->grid[ui->cur_y * from->w + ui->cur_x]; 2431 int v = from->grid[ui->cur_y * from->w + ui->cur_x];
2442 2432
2443 if (!ui->cur_visible) { 2433 if (!ui->cur_visible) {
2444 ui->cur_visible = true; 2434 ui->cur_visible = true;
2445 return UI_UPDATE; 2435 return MOVE_UI_UPDATE;
2446 } 2436 }
2447 if (button == CURSOR_SELECT2) { 2437 if (button == CURSOR_SELECT2) {
2448 /* As for RIGHT_BUTTON; only works on covered square. */ 2438 /* As for RIGHT_BUTTON; only works on covered square. */
2449 if (v != -2 && v != -1) 2439 if (v != -2 && v != -1)
2450 return NULL; 2440 return MOVE_NO_EFFECT;
2451 sprintf(buf, "F%d,%d", ui->cur_x, ui->cur_y); 2441 sprintf(buf, "F%d,%d", ui->cur_x, ui->cur_y);
2452 return dupstr(buf); 2442 return dupstr(buf);
2453 } 2443 }
@@ -2468,7 +2458,7 @@ static char *interpret_move(const game_state *from, game_ui *ui,
2468 if (button == LEFT_BUTTON || button == LEFT_DRAG || 2458 if (button == LEFT_BUTTON || button == LEFT_DRAG ||
2469 button == MIDDLE_BUTTON || button == MIDDLE_DRAG) { 2459 button == MIDDLE_BUTTON || button == MIDDLE_DRAG) {
2470 if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h) 2460 if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h)
2471 return NULL; 2461 return MOVE_UNUSED;
2472 2462
2473 /* 2463 /*
2474 * Mouse-downs and mouse-drags just cause highlighting 2464 * Mouse-downs and mouse-drags just cause highlighting
@@ -2482,12 +2472,12 @@ static char *interpret_move(const game_state *from, game_ui *ui,
2482 else if (button == MIDDLE_BUTTON) 2472 else if (button == MIDDLE_BUTTON)
2483 ui->validradius = 1; 2473 ui->validradius = 1;
2484 ui->cur_visible = false; 2474 ui->cur_visible = false;
2485 return UI_UPDATE; 2475 return MOVE_UI_UPDATE;
2486 } 2476 }
2487 2477
2488 if (button == RIGHT_BUTTON) { 2478 if (button == RIGHT_BUTTON) {
2489 if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h) 2479 if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h)
2490 return NULL; 2480 return MOVE_UNUSED;
2491 2481
2492 /* 2482 /*
2493 * Right-clicking only works on a covered square, and it 2483 * Right-clicking only works on a covered square, and it
@@ -2498,7 +2488,7 @@ static char *interpret_move(const game_state *from, game_ui *ui,
2498 */ 2488 */
2499 if (from->grid[cy * from->w + cx] != -2 && 2489 if (from->grid[cy * from->w + cx] != -2 &&
2500 from->grid[cy * from->w + cx] != -1) 2490 from->grid[cy * from->w + cx] != -1)
2501 return NULL; 2491 return MOVE_NO_EFFECT;
2502 2492
2503 sprintf(buf, "F%d,%d", cx, cy); 2493 sprintf(buf, "F%d,%d", cx, cy);
2504 return dupstr(buf); 2494 return dupstr(buf);
@@ -2509,11 +2499,12 @@ static char *interpret_move(const game_state *from, game_ui *ui,
2509 ui->hradius = 0; 2499 ui->hradius = 0;
2510 2500
2511 /* 2501 /*
2512 * At this stage we must never return NULL: we have adjusted 2502 * At this stage we must never return MOVE_UNUSED or
2513 * the ui, so at worst we return UI_UPDATE. 2503 * MOVE_NO_EFFECT: we have adjusted the ui, so at worst we
2504 * return MOVE_UI_UPDATE.
2514 */ 2505 */
2515 if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h) 2506 if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h)
2516 return UI_UPDATE; 2507 return MOVE_UI_UPDATE;
2517 2508
2518 /* 2509 /*
2519 * Left-clicking on a covered square opens a tile. Not 2510 * Left-clicking on a covered square opens a tile. Not
@@ -2533,7 +2524,7 @@ static char *interpret_move(const game_state *from, game_ui *ui,
2533 } 2524 }
2534 goto uncover; 2525 goto uncover;
2535 } 2526 }
2536 return NULL; 2527 return MOVE_UNUSED;
2537 2528
2538uncover: 2529uncover:
2539 { 2530 {
@@ -2591,7 +2582,7 @@ uncover:
2591 } 2582 }
2592 } 2583 }
2593 2584
2594 return UI_UPDATE; 2585 return MOVE_UI_UPDATE;
2595 } 2586 }
2596} 2587}
2597 2588
@@ -2603,6 +2594,7 @@ static game_state *execute_move(const game_state *from, const char *move)
2603 if (!strcmp(move, "S")) { 2594 if (!strcmp(move, "S")) {
2604 int yy, xx; 2595 int yy, xx;
2605 2596
2597 if (!from->layout->mines) return NULL; /* Game not started. */
2606 ret = dup_game(from); 2598 ret = dup_game(from);
2607 if (!ret->dead) { 2599 if (!ret->dead) {
2608 /* 2600 /*
@@ -2656,12 +2648,17 @@ static game_state *execute_move(const game_state *from, const char *move)
2656 2648
2657 return ret; 2649 return ret;
2658 } else { 2650 } else {
2651 /* Dead players should stop trying to move. */
2652 if (from->dead)
2653 return NULL;
2659 ret = dup_game(from); 2654 ret = dup_game(from);
2660 2655
2661 while (*move) { 2656 while (*move) {
2662 if (move[0] == 'F' && 2657 if (move[0] == 'F' &&
2663 sscanf(move+1, "%d,%d", &cx, &cy) == 2 && 2658 sscanf(move+1, "%d,%d", &cx, &cy) == 2 &&
2664 cx >= 0 && cx < from->w && cy >= 0 && cy < from->h) { 2659 cx >= 0 && cx < from->w && cy >= 0 && cy < from->h &&
2660 (ret->grid[cy * from->w + cx] == -1 ||
2661 ret->grid[cy * from->w + cx] == -2)) {
2665 ret->grid[cy * from->w + cx] ^= (-2 ^ -1); 2662 ret->grid[cy * from->w + cx] ^= (-2 ^ -1);
2666 } else if (move[0] == 'O' && 2663 } else if (move[0] == 'O' &&
2667 sscanf(move+1, "%d,%d", &cx, &cy) == 2 && 2664 sscanf(move+1, "%d,%d", &cx, &cy) == 2 &&
@@ -2697,7 +2694,7 @@ static game_state *execute_move(const game_state *from, const char *move)
2697 */ 2694 */
2698 2695
2699static void game_compute_size(const game_params *params, int tilesize, 2696static void game_compute_size(const game_params *params, int tilesize,
2700 int *x, int *y) 2697 const game_ui *ui, int *x, int *y)
2701{ 2698{
2702 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2699 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2703 struct { int tilesize; } ads, *ds = &ads; 2700 struct { int tilesize; } ads, *ds = &ads;
@@ -2870,12 +2867,12 @@ static void draw_tile(drawing *dr, game_drawstate *ds,
2870 coords[(n)*2+0] = x + (int)(TILE_SIZE * (dx)); \ 2867 coords[(n)*2+0] = x + (int)(TILE_SIZE * (dx)); \
2871 coords[(n)*2+1] = y + (int)(TILE_SIZE * (dy)); \ 2868 coords[(n)*2+1] = y + (int)(TILE_SIZE * (dy)); \
2872} while (0) 2869} while (0)
2873 SETCOORD(0, 0.6F, 0.7F); 2870 SETCOORD(0, 0.6F, 0.35F);
2874 SETCOORD(1, 0.8F, 0.8F); 2871 SETCOORD(1, 0.6F, 0.7F);
2875 SETCOORD(2, 0.25F, 0.8F); 2872 SETCOORD(2, 0.8F, 0.8F);
2876 SETCOORD(3, 0.55F, 0.7F); 2873 SETCOORD(3, 0.25F, 0.8F);
2877 SETCOORD(4, 0.55F, 0.35F); 2874 SETCOORD(4, 0.55F, 0.7F);
2878 SETCOORD(5, 0.6F, 0.35F); 2875 SETCOORD(5, 0.55F, 0.35F);
2879 draw_polygon(dr, coords, 6, COL_FLAGBASE, COL_FLAGBASE); 2876 draw_polygon(dr, coords, 6, COL_FLAGBASE, COL_FLAGBASE);
2880 2877
2881 SETCOORD(0, 0.6F, 0.2F); 2878 SETCOORD(0, 0.6F, 0.2F);
@@ -2980,13 +2977,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2980 if (!ds->started) { 2977 if (!ds->started) {
2981 int coords[10]; 2978 int coords[10];
2982 2979
2983 draw_rect(dr, 0, 0,
2984 TILE_SIZE * state->w + 2 * BORDER,
2985 TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND);
2986 draw_update(dr, 0, 0,
2987 TILE_SIZE * state->w + 2 * BORDER,
2988 TILE_SIZE * state->h + 2 * BORDER);
2989
2990 /* 2980 /*
2991 * Recessed area containing the whole puzzle. 2981 * Recessed area containing the whole puzzle.
2992 */ 2982 */
@@ -3182,14 +3172,6 @@ static bool game_timing_state(const game_state *state, game_ui *ui)
3182 return true; 3172 return true;
3183} 3173}
3184 3174
3185static void game_print_size(const game_params *params, float *x, float *y)
3186{
3187}
3188
3189static void game_print(drawing *dr, const game_state *state, int tilesize)
3190{
3191}
3192
3193#ifdef COMBINED 3175#ifdef COMBINED
3194#define thegame mines 3176#define thegame mines
3195#endif 3177#endif
@@ -3211,12 +3193,14 @@ const struct game thegame = {
3211 free_game, 3193 free_game,
3212 true, solve_game, 3194 true, solve_game,
3213 true, game_can_format_as_text_now, game_text_format, 3195 true, game_can_format_as_text_now, game_text_format,
3196 NULL, NULL, /* get_prefs, set_prefs */
3214 new_ui, 3197 new_ui,
3215 free_ui, 3198 free_ui,
3216 encode_ui, 3199 encode_ui,
3217 decode_ui, 3200 decode_ui,
3218 NULL, /* game_request_keys */ 3201 NULL, /* game_request_keys */
3219 game_changed_state, 3202 game_changed_state,
3203 current_key_label,
3220 interpret_move, 3204 interpret_move,
3221 execute_move, 3205 execute_move,
3222 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 3206 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -3228,7 +3212,7 @@ const struct game thegame = {
3228 game_flash_length, 3212 game_flash_length,
3229 game_get_cursor_location, 3213 game_get_cursor_location,
3230 game_status, 3214 game_status,
3231 false, false, game_print_size, game_print, 3215 false, false, NULL, NULL, /* print_size, print */
3232 true, /* wants_statusbar */ 3216 true, /* wants_statusbar */
3233 true, game_timing_state, 3217 true, game_timing_state,
3234 BUTTON_BEATS(LEFT_BUTTON, RIGHT_BUTTON) | REQUIRE_RBUTTON, 3218 BUTTON_BEATS(LEFT_BUTTON, RIGHT_BUTTON) | REQUIRE_RBUTTON,
diff --git a/apps/plugins/puzzles/src/misc.c b/apps/plugins/puzzles/src/misc.c
index ed31acbbe4..f9eaf5d9b8 100644
--- a/apps/plugins/puzzles/src/misc.c
+++ b/apps/plugins/puzzles/src/misc.c
@@ -3,13 +3,21 @@
3 */ 3 */
4 4
5#include <assert.h> 5#include <assert.h>
6#include <ctype.h>
7#ifdef NO_TGMATH_H
8# include <math.h>
9#else
10# include <tgmath.h>
11#endif
6#include <stdlib.h> 12#include <stdlib.h>
7#include <string.h> 13#include <string.h>
8#include <stdio.h> 14#include <stdio.h>
9 15
10#include "puzzles.h" 16#include "puzzles.h"
11 17
12char UI_UPDATE[] = ""; 18char MOVE_UI_UPDATE[] = "";
19char MOVE_NO_EFFECT[] = "";
20char MOVE_UNUSED[] = "";
13 21
14void free_cfg(config_item *cfg) 22void free_cfg(config_item *cfg)
15{ 23{
@@ -197,30 +205,85 @@ char *fgetline(FILE *fp)
197 return ret; 205 return ret;
198} 206}
199 207
208int getenv_bool(const char *name, int dflt)
209{
210 char *env = getenv(name);
211 if (env == NULL) return dflt;
212 if (strchr("yYtT", env[0])) return true;
213 return false;
214}
215
216/* Utility functions for colour manipulation. */
217
218static float colour_distance(const float a[3], const float b[3])
219{
220 return (float)sqrt((a[0]-b[0]) * (a[0]-b[0]) +
221 (a[1]-b[1]) * (a[1]-b[1]) +
222 (a[2]-b[2]) * (a[2]-b[2]));
223}
224
225void colour_mix(const float src1[3], const float src2[3], float p, float dst[3])
226{
227 int i;
228 for (i = 0; i < 3; i++)
229 dst[i] = src1[i] * (1.0F - p) + src2[i] * p;
230}
231
200void game_mkhighlight_specific(frontend *fe, float *ret, 232void game_mkhighlight_specific(frontend *fe, float *ret,
201 int background, int highlight, int lowlight) 233 int background, int highlight, int lowlight)
202{ 234{
203 float max; 235 static const float black[3] = { 0.0F, 0.0F, 0.0F };
236 static const float white[3] = { 1.0F, 1.0F, 1.0F };
237 float db, dw;
204 int i; 238 int i;
205
206 /* 239 /*
207 * Drop the background colour so that the highlight is 240 * New geometric highlight-generation algorithm: Draw a line from
208 * noticeably brighter than it while still being under 1. 241 * the base colour to white. The point K distance along this line
242 * from the base colour is the highlight colour. Similarly, draw
243 * a line from the base colour to black. The point on this line
244 * at a distance K from the base colour is the shadow. If either
245 * of these colours is imaginary (for reasonable K at most one
246 * will be), _extrapolate_ the base colour along the same line
247 * until it's a distance K from white (or black) and start again
248 * with that as the base colour.
249 *
250 * This preserves the hue of the base colour, ensures that of the
251 * three the base colour is the most saturated, and only ever
252 * flattens the highlight and shadow to pure white or pure black.
253 *
254 * K must be at most sqrt(3)/2, or mid grey would be too close to
255 * both white and black. Here K is set to sqrt(3)/6 so that this
256 * code produces the same results as the former code in the common
257 * case where the background is grey and the highlight saturates
258 * to white.
209 */ 259 */
210 max = ret[background*3]; 260 const float k = sqrt(3)/6.0F;
211 for (i = 1; i < 3; i++) 261 if (lowlight >= 0) {
212 if (ret[background*3+i] > max) 262 db = colour_distance(&ret[background*3], black);
213 max = ret[background*3+i]; 263 if (db < k) {
214 if (max * 1.2F > 1.0F) { 264 for (i = 0; i < 3; i++) ret[lowlight*3+i] = black[i];
215 for (i = 0; i < 3; i++) 265 if (db == 0.0F)
216 ret[background*3+i] /= (max * 1.2F); 266 colour_mix(black, white, k/sqrt(3), &ret[background*3]);
267 else
268 colour_mix(black, &ret[background*3], k/db, &ret[background*3]);
269 } else {
270 colour_mix(&ret[background*3], black, k/db, &ret[lowlight*3]);
271 }
217 } 272 }
218 273 if (highlight >= 0) {
219 for (i = 0; i < 3; i++) { 274 dw = colour_distance(&ret[background*3], white);
220 if (highlight >= 0) 275 if (dw < k) {
221 ret[highlight * 3 + i] = ret[background * 3 + i] * 1.2F; 276 for (i = 0; i < 3; i++) ret[highlight*3+i] = white[i];
222 if (lowlight >= 0) 277 if (dw == 0.0F)
223 ret[lowlight * 3 + i] = ret[background * 3 + i] * 0.8F; 278 colour_mix(white, black, k/sqrt(3), &ret[background*3]);
279 else
280 colour_mix(white, &ret[background*3], k/dw, &ret[background*3]);
281 /* Background has changed; recalculate lowlight. */
282 if (lowlight >= 0)
283 colour_mix(&ret[background*3], black, k/db, &ret[lowlight*3]);
284 } else {
285 colour_mix(&ret[background*3], white, k/dw, &ret[highlight*3]);
286 }
224 } 287 }
225} 288}
226 289
@@ -231,7 +294,7 @@ void game_mkhighlight(frontend *fe, float *ret,
231 game_mkhighlight_specific(fe, ret, background, highlight, lowlight); 294 game_mkhighlight_specific(fe, ret, background, highlight, lowlight);
232} 295}
233 296
234static void swap_regions(void *av, void *bv, int size) 297void swap_regions(void *av, void *bv, size_t size)
235{ 298{
236 char tmpbuf[512]; 299 char tmpbuf[512];
237 char *a = av, *b = bv; 300 char *a = av, *b = bv;
@@ -288,15 +351,16 @@ void draw_rect_corners(drawing *dr, int cx, int cy, int r, int col)
288 draw_line(dr, cx + r, cy + r, cx + r/2, cy + r, col); 351 draw_line(dr, cx + r, cy + r, cx + r/2, cy + r, col);
289} 352}
290 353
291void move_cursor(int button, int *x, int *y, int maxw, int maxh, bool wrap) 354char *move_cursor(int button, int *x, int *y, int maxw, int maxh, bool wrap,
355 bool *visible)
292{ 356{
293 int dx = 0, dy = 0; 357 int dx = 0, dy = 0, ox = *x, oy = *y;
294 switch (button) { 358 switch (button) {
295 case CURSOR_UP: dy = -1; break; 359 case CURSOR_UP: dy = -1; break;
296 case CURSOR_DOWN: dy = 1; break; 360 case CURSOR_DOWN: dy = 1; break;
297 case CURSOR_RIGHT: dx = 1; break; 361 case CURSOR_RIGHT: dx = 1; break;
298 case CURSOR_LEFT: dx = -1; break; 362 case CURSOR_LEFT: dx = -1; break;
299 default: return; 363 default: return MOVE_UNUSED;
300 } 364 }
301 if (wrap) { 365 if (wrap) {
302 *x = (*x + dx + maxw) % maxw; 366 *x = (*x + dx + maxw) % maxw;
@@ -305,6 +369,13 @@ void move_cursor(int button, int *x, int *y, int maxw, int maxh, bool wrap)
305 *x = min(max(*x+dx, 0), maxw - 1); 369 *x = min(max(*x+dx, 0), maxw - 1);
306 *y = min(max(*y+dy, 0), maxh - 1); 370 *y = min(max(*y+dy, 0), maxh - 1);
307 } 371 }
372 if (visible != NULL && !*visible) {
373 *visible = true;
374 return MOVE_UI_UPDATE;
375 }
376 if (*x != ox || *y != oy)
377 return MOVE_UI_UPDATE;
378 return MOVE_NO_EFFECT;
308} 379}
309 380
310/* Used in netslide.c and sixteen.c for cursor movement around edge. */ 381/* Used in netslide.c and sixteen.c for cursor movement around edge. */
@@ -402,12 +473,6 @@ void copy_left_justified(char *buf, size_t sz, const char *str)
402 buf[sz - 1] = 0; 473 buf[sz - 1] = 0;
403} 474}
404 475
405/* another kludge for platforms without %g support in *printf() */
406int ftoa(char *buf, float f)
407{
408 return sprintf(buf, "%d.%06d", (int)f, abs((int)((f - (int)f)*1e6)));
409}
410
411/* Returns a dynamically allocated label for a generic button. 476/* Returns a dynamically allocated label for a generic button.
412 * Game-specific buttons should go into the `label' field of key_label 477 * Game-specific buttons should go into the `label' field of key_label
413 * instead. */ 478 * instead. */
@@ -446,4 +511,161 @@ char *button2label(int button)
446 return NULL; 511 return NULL;
447} 512}
448 513
514char *make_prefs_path(const char *dir, const char *sep,
515 const game *game, const char *suffix)
516{
517 size_t dirlen = strlen(dir);
518 size_t seplen = strlen(sep);
519 size_t gamelen = strlen(game->name);
520 size_t suffixlen = strlen(suffix);
521 char *path, *p;
522 const char *q;
523
524 if (!dir || !sep || !game || !suffix)
525 return NULL;
526
527 path = snewn(dirlen + seplen + gamelen + suffixlen + 1, char);
528 p = path;
529
530 memcpy(p, dir, dirlen);
531 p += dirlen;
532
533 memcpy(p, sep, seplen);
534 p += seplen;
535
536 for (q = game->name; *q; q++)
537 if (*q != ' ')
538 *p++ = tolower((unsigned char)*q);
539
540 memcpy(p, suffix, suffixlen);
541 p += suffixlen;
542
543 *p = '\0';
544 return path;
545}
546
547/*
548 * Calculate the nearest integer to n*sqrt(k), via a bitwise algorithm
549 * that avoids floating point.
550 *
551 * (It would probably be OK in practice to use floating point, but I
552 * felt like overengineering it for fun. With FP, there's at least a
553 * theoretical risk of rounding the wrong way, due to the three
554 * successive roundings involved - rounding sqrt(k), rounding its
555 * product with n, and then rounding to the nearest integer. This
556 * approach avoids that: it's exact.)
557 */
558int n_times_root_k(int n_signed, int k)
559{
560 unsigned x, r, m;
561 int sign = n_signed < 0 ? -1 : +1;
562 unsigned n = n_signed * sign;
563 unsigned bitpos;
564
565 /*
566 * Method:
567 *
568 * We transform m gradually from zero into n, by multiplying it by
569 * 2 in each step and optionally adding 1, so that it's always
570 * floor(n/2^something).
571 *
572 * At the start of each step, x is the largest integer less than
573 * or equal to m*sqrt(k). We transform m to 2m+bit, and therefore
574 * we must transform x to 2x+something to match. The 'something'
575 * we add to 2x is at most floor(sqrt(k))+2. (Worst case is if m
576 * sqrt(k) was equal to x + 1-eps for some tiny eps, and then the
577 * incoming bit of m is 1, so that (2m+1)sqrt(k) =
578 * 2x+2+sqrt(k)-2eps.)
579 *
580 * To compute this, we also track the residual value r such that
581 * x^2+r = km^2.
582 *
583 * The algorithm below is very similar to the usual approach for
584 * taking the square root of an integer in binary. The wrinkle is
585 * that we have an integer multiplier, i.e. we're computing
586 * n*sqrt(k) rather than just sqrt(k). Of course in principle we
587 * could just take sqrt(n^2k), but we'd need an integer twice the
588 * width to hold n^2. Pulling out n and treating it specially
589 * makes overflow less likely.
590 */
591
592 x = r = m = 0;
593
594 for (bitpos = UINT_MAX & ~(UINT_MAX >> 1); bitpos; bitpos >>= 1) {
595 unsigned a, b = (n & bitpos) ? 1 : 0;
596
597 /*
598 * Check invariants. We expect that x^2 + r = km^2 (i.e. our
599 * residual term is correct), and also that r < 2x+1 (because
600 * if not, then we could replace x with x+1 and still get a
601 * value that made r non-negative, i.e. x would not be the
602 * _largest_ integer less than m sqrt(k)).
603 */
604 assert(x*x + r == k*m*m);
605 assert(r < 2*x+1);
606
607 /*
608 * We're going to replace m with 2m+b, and x with 2x+a for
609 * some a we haven't decided on yet.
610 *
611 * The new value of the residual will therefore be
612 *
613 * k (2m+b)^2 - (2x+a)^2
614 * = (4km^2 + 4kmb + kb^2) - (4x^2 + 4xa + a^2)
615 * = 4 (km^2 - x^2) + 4kmb + kb^2 - 4xa - a^2
616 * = 4r + 4kmb + kb^2 - 4xa - a^2 (because r = km^2 - x^2)
617 * = 4r + (4m + 1)kb - 4xa - a^2 (b is 0 or 1, so b = b^2)
618 */
619 for (a = 0;; a++) {
620 /* If we made this routine handle square roots of numbers
621 * significantly bigger than 3 or 5 then it would be
622 * sensible to make this a binary search. Here, it hardly
623 * seems important. */
624 unsigned pos = 4*r + k*b*(4*m + 1);
625 unsigned neg = 4*a*x + a*a;
626 if (pos < neg)
627 break; /* this value of a is too big */
628 }
629
630 /* The above loop will have terminated with a one too big. So
631 * now decrementing a will give us the right value to add. */
632 a--;
633
634 r = 4*r + b*k*(4*m + 1) - (4*a*x + a*a);
635 m = 2*m+b;
636 x = 2*x+a;
637 }
638
639 /*
640 * Finally, round to the nearest integer. At present, x is the
641 * largest integer that is _at most_ m sqrt(k). But we want the
642 * _nearest_ integer, whether that's rounded up or down. So check
643 * whether (x + 1/2) is still less than m sqrt(k), i.e. whether
644 * (x + 1/2)^2 < km^2; if it is, then we increment x.
645 *
646 * We have km^2 - (x + 1/2)^2 = km^2 - x^2 - x - 1/4
647 * = r - x - 1/4
648 *
649 * and since r and x are integers, this is greater than 0 if and
650 * only if r > x.
651 *
652 * (There's no need to worry about tie-breaking exact halfway
653 * rounding cases. sqrt(k) is irrational, so none such exist.)
654 */
655 if (r > x)
656 x++;
657
658 /*
659 * Put the sign back on, and convert back from unsigned to int.
660 */
661 if (sign == +1) {
662 return x;
663 } else {
664 /* Be a little careful to avoid compilers deciding I've just
665 * perpetrated signed-integer overflow. This should optimise
666 * down to no actual code. */
667 return INT_MIN + (int)(-x - (unsigned)INT_MIN);
668 }
669}
670
449/* vim: set shiftwidth=4 tabstop=8: */ 671/* vim: set shiftwidth=4 tabstop=8: */
diff --git a/apps/plugins/puzzles/src/mosaic.c b/apps/plugins/puzzles/src/mosaic.c
new file mode 100644
index 0000000000..05a339ded5
--- /dev/null
+++ b/apps/plugins/puzzles/src/mosaic.c
@@ -0,0 +1,1626 @@
1/*
2 * mosaic.c: A puzzle based on a square grid, with some of the tiles
3 * having clues as to how many black squares are around them.
4 * the purpose of the game is to find what should be on all tiles (black or
5 * unmarked)
6 *
7 * The game is also known as: ArtMosaico, Count and Darken, Cuenta Y Sombrea,
8 * Fill-a-Pix, Fill-In, Komsu Karala, Magipic, Majipiku, Mosaico, Mosaik,
9 * Mozaiek, Nampre Puzzle, Nurie-Puzzle, Oekaki-Pix, Voisimage.
10 *
11 * Implementation is loosely based on https://github.com/mordechaim/Mosaic, UI
12 * interaction is based on the range puzzle in the collection.
13 */
14
15#include <assert.h>
16#include <ctype.h>
17#ifdef NO_TGMATH_H
18# include <math.h>
19#else
20# include <tgmath.h>
21#endif
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include "puzzles.h"
27
28#define DEFAULT_SIZE 10
29#define DEFAULT_AGGRESSIVENESS true
30#define MAX_TILES 10000
31#define MAX_TILES_ERROR "Maximum size is 10000 tiles"
32#define DEFAULT_TILE_SIZE 32
33#define DEBUG_IMAGE 1
34#undef DEBUG_IMAGE
35#define FLASH_TIME 0.5F
36/* To enable debug prints define DEBUG_PRINTS */
37
38/* Getting the coordinates and returning NULL when out of scope
39 * The parentheses are needed to avoid order of operations issues
40 */
41#define get_coords(params, array, x, y) \
42 (((x) >= 0 && (y) >= 0) && ((x) < params->width && (y) < params->height)) \
43 ? array + ((y)*params->width) + x \
44 : NULL
45
46#define COORD_FROM_CELL(d) ((d * ds->tilesize) + ds->tilesize / 2) - 1
47
48enum {
49 COL_BACKGROUND = 0,
50 COL_UNMARKED,
51 COL_GRID,
52 COL_MARKED,
53 COL_BLANK,
54 COL_TEXT_SOLVED,
55 COL_ERROR,
56 COL_CURSOR,
57 NCOLOURS,
58 COL_TEXT_DARK = COL_MARKED,
59 COL_TEXT_LIGHT = COL_BLANK
60};
61
62enum cell_state {
63 STATE_UNMARKED = 0,
64 STATE_MARKED = 1,
65 STATE_BLANK = 2,
66 STATE_SOLVED = 4,
67 STATE_ERROR = 8,
68 STATE_UNMARKED_ERROR = STATE_ERROR | STATE_UNMARKED,
69 STATE_MARKED_ERROR = STATE_ERROR | STATE_MARKED,
70 STATE_BLANK_ERROR = STATE_ERROR | STATE_BLANK,
71 STATE_BLANK_SOLVED = STATE_SOLVED | STATE_BLANK,
72 STATE_MARKED_SOLVED = STATE_MARKED | STATE_SOLVED,
73 STATE_OK_NUM = STATE_BLANK | STATE_MARKED
74};
75
76struct game_params {
77 int width;
78 int height;
79 bool aggressive;
80};
81
82typedef struct board_state board_state;
83
84typedef struct needed_list_item needed_list_item;
85
86struct needed_list_item {
87 int x, y;
88 needed_list_item *next;
89};
90
91struct game_state {
92 bool cheating;
93 int not_completed_clues;
94 int width;
95 int height;
96 char *cells_contents;
97 board_state *board;
98};
99
100struct board_state {
101 unsigned int references;
102 struct board_cell *actual_board;
103};
104
105struct board_cell {
106 signed char clue;
107 bool shown;
108};
109
110struct solution_cell {
111 signed char cell;
112 bool solved;
113 bool needed;
114};
115
116struct desc_cell {
117 char clue;
118 bool shown;
119 bool value;
120 bool full;
121 bool empty;
122};
123
124struct game_ui {
125 bool solved;
126 bool in_progress;
127 int last_x, last_y, last_state;
128 int cur_x, cur_y;
129 bool cur_visible;
130};
131
132struct game_drawstate {
133 int tilesize;
134 int *state;
135};
136
137static game_params *default_params(void)
138{
139 game_params *ret = snew(game_params);
140
141 ret->width = DEFAULT_SIZE;
142 ret->height = DEFAULT_SIZE;
143 ret->aggressive = DEFAULT_AGGRESSIVENESS;
144
145 return ret;
146}
147
148static bool game_fetch_preset(int i, char **name, game_params **params)
149{
150 const int sizes[6] = { 3, 5, 10, 15, 25, 50 };
151 const bool aggressiveness[6] = { true, true, true, true, true, false };
152 if (i < 0 || i > 5) {
153 return false;
154 }
155 game_params *res = snew(game_params);
156 res->height = sizes[i];
157 res->width = sizes[i];
158 res->aggressive = aggressiveness[i];
159 *params = res;
160
161 char value[80];
162 sprintf(value, "Size: %dx%d", sizes[i], sizes[i]);
163 *name = dupstr(value);
164 return true;
165}
166
167static void free_params(game_params *params)
168{
169 sfree(params);
170}
171
172static game_params *dup_params(const game_params *params)
173{
174 game_params *ret = snew(game_params);
175 *ret = *params; /* structure copy */
176 return ret;
177}
178
179static void decode_params(game_params *params, char const *string)
180{
181 params->width = params->height = atoi(string);
182 while (*string && isdigit((unsigned char)*string)) string++;
183 if (*string == 'x') {
184 string++;
185 params->height = atoi(string);
186 while (*string && isdigit((unsigned char)*string)) string++;
187 }
188 if (*string == 'h') {
189 string++;
190 params->aggressive = atoi(string);
191 while (*string && isdigit((unsigned char)*string)) string++;
192 }
193}
194
195static char *encode_params(const game_params *params, bool full)
196{
197 char encoded[128];
198 int pos = 0;
199 pos += sprintf(encoded + pos, "%dx%d", params->width, params->height);
200 if (full) {
201 if (params->aggressive != DEFAULT_AGGRESSIVENESS)
202 pos += sprintf(encoded + pos, "h%d", params->aggressive);
203 }
204 return dupstr(encoded);
205}
206
207static config_item *game_configure(const game_params *params)
208{
209 config_item *config = snewn(4, config_item);
210 char value[80];
211
212 config[0].type = C_STRING;
213 config[0].name = "Height";
214 sprintf(value, "%d", params->height);
215 config[0].u.string.sval = dupstr(value);
216
217 config[1].type = C_STRING;
218 config[1].name = "Width";
219 sprintf(value, "%d", params->width);
220 config[1].u.string.sval = dupstr(value);
221
222 config[2].name = "Aggressive generation (longer)";
223 config[2].type = C_BOOLEAN;
224 config[2].u.boolean.bval = params->aggressive;
225
226 config[3].type = C_END;
227
228 return config;
229}
230
231static game_params *custom_params(const config_item *cfg)
232{
233 game_params *res = snew(game_params);
234 res->height = atol(cfg[0].u.string.sval);
235 res->width = atol(cfg[1].u.string.sval);
236 res->aggressive = cfg[2].u.boolean.bval;
237 return res;
238}
239
240static const char *validate_params(const game_params *params, bool full)
241{
242 if (params->height < 3 || params->width < 3) {
243 return "Minimal size is 3x3";
244 }
245 if (params->height > MAX_TILES / params->width) {
246 return MAX_TILES_ERROR;
247 }
248 return NULL;
249}
250
251static bool get_pixel(const game_params *params, const bool *image,
252 const int x, const int y)
253{
254 const bool *pixel;
255 pixel = get_coords(params, image, x, y);
256 if (pixel) {
257 return *pixel;
258 }
259 return 0;
260}
261
262static void populate_cell(const game_params *params, const bool *image,
263 const int x, const int y, bool edge,
264 struct desc_cell *desc)
265{
266 int clue = 0;
267 bool xEdge = false;
268 bool yEdge = false;
269 if (edge) {
270 if (x > 0) {
271 clue += get_pixel(params, image, x - 1, y);
272 if (y > 0) {
273 clue += get_pixel(params, image, x - 1, y - 1);
274 }
275 if (y < params->height - 1) {
276 clue += get_pixel(params, image, x - 1, y + 1);
277 }
278 } else {
279 xEdge = true;
280 }
281
282 if (y > 0) {
283 clue += get_pixel(params, image, x, y - 1);
284 } else {
285 yEdge = true;
286 }
287 if (x < params->width - 1) {
288 clue += get_pixel(params, image, x + 1, y);
289 if (y > 0) {
290 clue += get_pixel(params, image, x + 1, y - 1);
291 }
292 if (y < params->height - 1) {
293 clue += get_pixel(params, image, x + 1, y + 1);
294 }
295 } else {
296 xEdge = true;
297 }
298 if (y < params->height - 1) {
299 clue += get_pixel(params, image, x, y + 1);
300 } else {
301 yEdge = true;
302 }
303 } else {
304 clue += get_pixel(params, image, x - 1, y - 1);
305 clue += get_pixel(params, image, x - 1, y);
306 clue += get_pixel(params, image, x - 1, y + 1);
307 clue += get_pixel(params, image, x, y - 1);
308 clue += get_pixel(params, image, x, y + 1);
309 clue += get_pixel(params, image, x + 1, y - 1);
310 clue += get_pixel(params, image, x + 1, y);
311 clue += get_pixel(params, image, x + 1, y + 1);
312 }
313
314 desc->value = get_pixel(params, image, x, y);
315 clue += desc->value;
316 if (clue == 0) {
317 desc->empty = true;
318 desc->full = false;
319 } else {
320 desc->empty = false;
321 /* setting the default */
322 desc->full = false;
323 if (clue == 9) {
324 desc->full = true;
325 } else if (edge && ((xEdge && yEdge && clue == 4) ||
326 ((xEdge || yEdge) && clue == 6))) {
327
328 desc->full = true;
329 }
330 }
331 desc->shown = true;
332 desc->clue = clue;
333}
334
335static void count_around(const game_params *params,
336 struct solution_cell *sol, int x, int y,
337 int *marked, int *blank, int *total)
338{
339 int i, j;
340 struct solution_cell *curr = NULL;
341 (*total) = 0;
342 (*blank) = 0;
343 (*marked) = 0;
344
345 for (i = -1; i < 2; i++) {
346 for (j = -1; j < 2; j++) {
347 curr = get_coords(params, sol, x + i, y + j);
348 if (curr) {
349 (*total)++;
350 if ((curr->cell & STATE_BLANK) != 0) {
351 (*blank)++;
352 } else if ((curr->cell & STATE_MARKED) != 0) {
353 (*marked)++;
354 }
355 }
356 }
357 }
358}
359
360static void count_around_state(const game_state *state, int x, int y,
361 int *marked, int *blank, int *total)
362{
363 int i, j;
364 char *curr = NULL;
365 (*total) = 0;
366 (*blank) = 0;
367 (*marked) = 0;
368
369 for (i = -1; i < 2; i++) {
370 for (j = -1; j < 2; j++) {
371 curr = get_coords(state, state->cells_contents, x + i, y + j);
372 if (curr) {
373 (*total)++;
374 if ((*curr & STATE_BLANK) != 0) {
375 (*blank)++;
376 } else if ((*curr & STATE_MARKED) != 0) {
377 (*marked)++;
378 }
379 }
380 }
381 }
382}
383
384static void count_clues_around(const game_params *params,
385 struct desc_cell *desc, int x, int y,
386 int *clues, int *total)
387{
388 int i, j;
389 struct desc_cell *curr = NULL;
390 (*total) = 0;
391 (*clues) = 0;
392
393 for (i = -1; i < 2; i++) {
394 for (j = -1; j < 2; j++) {
395 curr = get_coords(params, desc, x + i, y + j);
396 if (curr) {
397 (*total)++;
398 if (curr->shown) {
399 (*clues)++;
400 }
401 }
402 }
403 }
404}
405
406static void mark_around(const game_params *params,
407 struct solution_cell *sol, int x, int y, int mark)
408{
409 int i, j;
410 struct solution_cell *curr;
411
412 for (i = -1; i < 2; i++) {
413 for (j = -1; j < 2; j++) {
414 curr = get_coords(params, sol, x + i, y + j);
415 if (curr) {
416 if (curr->cell == STATE_UNMARKED) {
417 curr->cell = mark;
418 }
419 }
420 }
421 }
422}
423
424static char solve_cell(const game_params *params, struct desc_cell *desc,
425 struct board_cell *board, struct solution_cell *sol,
426 int x, int y)
427{
428 struct desc_cell curr;
429
430 if (desc) {
431 curr.shown = desc[(y * params->width) + x].shown;
432 curr.clue = desc[(y * params->width) + x].clue;
433 curr.full = desc[(y * params->width) + x].full;
434 curr.empty = desc[(y * params->width) + x].empty;
435 } else {
436 curr.shown = board[(y * params->width) + x].shown;
437 curr.clue = board[(y * params->width) + x].clue;
438 curr.full = false;
439 curr.empty = false;
440 }
441 int marked = 0, total = 0, blank = 0;
442
443 if (sol[(y * params->width) + x].solved) {
444 return 0;
445 }
446 count_around(params, sol, x, y, &marked, &blank, &total);
447 if (curr.full && curr.shown) {
448 sol[(y * params->width) + x].solved = true;
449 if (marked + blank < total) {
450 sol[(y * params->width) + x].needed = true;
451 }
452 mark_around(params, sol, x, y, STATE_MARKED);
453 return 1;
454 }
455 if (curr.empty && curr.shown) {
456 sol[(y * params->width) + x].solved = true;
457 if (marked + blank < total) {
458 sol[(y * params->width) + x].needed = true;
459 }
460 mark_around(params, sol, x, y, STATE_BLANK);
461 return 1;
462 }
463 if (curr.shown) {
464 if (!sol[(y * params->width) + x].solved) {
465 if (marked == curr.clue) {
466 sol[(y * params->width) + x].solved = true;
467 if (total != marked + blank) {
468 sol[(y * params->width) + x].needed = true;
469 }
470 mark_around(params, sol, x, y, STATE_BLANK);
471 } else if (curr.clue == (total - blank)) {
472 sol[(y * params->width) + x].solved = true;
473 if (total != marked + blank) {
474 sol[(y * params->width) + x].needed = true;
475 }
476 mark_around(params, sol, x, y, STATE_MARKED);
477 } else if (total == marked + blank) {
478 return -1;
479 } else {
480 return 0;
481 }
482 return 1;
483 }
484 return 0;
485 } else if (total == marked + blank) {
486 sol[(y * params->width) + x].solved = true;
487 return 1;
488 } else {
489 return 0;
490 }
491}
492
493static bool solve_check(const game_params *params, struct desc_cell *desc,
494 random_state *rs, struct solution_cell **sol_return)
495{
496 int x, y, i;
497 int board_size = params->height * params->width;
498 struct solution_cell *sol = snewn(board_size, struct solution_cell),
499 *curr_sol;
500 bool made_progress = true, error = false;
501 int solved = 0, curr = 0, shown = 0;
502 needed_list_item *head = NULL, *curr_needed, **needed_array;
503 struct desc_cell *curr_desc;
504
505 memset(sol, 0, board_size * sizeof(*sol));
506 for (y = 0; y < params->height; y++) {
507 for (x = 0; x < params->width; x++) {
508 curr_desc = get_coords(params, desc, x, y);
509 if (curr_desc->shown) {
510 curr_needed = snew(needed_list_item);
511 curr_needed->next = head;
512 head = curr_needed;
513 curr_needed->x = x;
514 curr_needed->y = y;
515 shown++;
516 }
517 }
518 }
519 needed_array = snewn(shown, needed_list_item *);
520 curr_needed = head;
521 i = 0;
522 while (curr_needed) {
523 needed_array[i] = curr_needed;
524 curr_needed = curr_needed->next;
525 i++;
526 }
527 if (rs) {
528 shuffle(needed_array, shown, sizeof(*needed_array), rs);
529 }
530 solved = 0;
531 while (solved < shown && made_progress && !error) {
532 made_progress = false;
533 for (i = 0; i < shown; i++) {
534 curr = solve_cell(params, desc, NULL, sol, needed_array[i]->x,
535 needed_array[i]->y);
536 if (curr < 0) {
537 error = true;
538#ifdef DEBUG_PRINTS
539 printf("error in cell x=%d, y=%d\n", needed_array[i]->x,
540 needed_array[i]->y);
541#endif
542 break;
543 }
544 if (curr > 0) {
545 solved++;
546 made_progress = true;
547 }
548 }
549 }
550 while (head) {
551 curr_needed = head;
552 head = curr_needed->next;
553 sfree(curr_needed);
554 }
555 sfree(needed_array);
556 solved = 0;
557 /* verifying all the board is solved */
558 if (made_progress) {
559 for (y = 0; y < params->height; y++) {
560 for (x = 0; x < params->width; x++) {
561 curr_sol = get_coords(params, sol, x, y);
562 if ((curr_sol->cell & (STATE_MARKED | STATE_BLANK)) > 0) {
563 solved++;
564 }
565 }
566 }
567 }
568 if (sol_return) {
569 *sol_return = sol;
570 } else {
571 sfree(sol);
572 }
573 return solved == board_size;
574}
575
576static bool solve_game_actual(const game_params *params,
577 struct board_cell *desc,
578 struct solution_cell **sol_return)
579{
580 int x, y;
581 int board_size = params->height * params->width;
582 struct solution_cell *sol = snewn(board_size, struct solution_cell);
583 bool made_progress = true, error = false;
584 int solved = 0, curr = 0;
585
586 memset(sol, 0, params->height * params->width * sizeof(*sol));
587 solved = 0;
588 while (solved < params->height * params->width && made_progress
589 && !error) {
590 for (y = 0; y < params->height; y++) {
591 for (x = 0; x < params->width; x++) {
592 curr = solve_cell(params, NULL, desc, sol, x, y);
593 if (curr < 0) {
594 error = true;
595#ifdef DEBUG_PRINTS
596 printf("error in cell x=%d, y=%d\n", x, y);
597#endif
598 break;
599 }
600 if (curr > 0) {
601 made_progress = true;
602 }
603 solved += curr;
604 }
605 }
606 }
607 if (sol_return) {
608 *sol_return = sol;
609 } else {
610 sfree(sol);
611 }
612 return solved == params->height * params->width;
613}
614
615static void hide_clues(const game_params *params, struct desc_cell *desc,
616 random_state *rs)
617{
618 int shown, total, x, y, i;
619 int needed = 0;
620 struct desc_cell *curr;
621 struct solution_cell *sol = NULL, *curr_sol = NULL;
622 needed_list_item *head = NULL, *curr_needed, **needed_array;
623
624#ifdef DEBUG_PRINTS
625 printf("Hiding clues\n");
626#endif
627 solve_check(params, desc, rs, &sol);
628 for (y = 0; y < params->height; y++) {
629 for (x = 0; x < params->width; x++) {
630 count_clues_around(params, desc, x, y, &shown, &total);
631 curr = get_coords(params, desc, x, y);
632 curr_sol = get_coords(params, sol, x, y);
633 if (curr_sol->needed && params->aggressive) {
634 curr_needed = snew(needed_list_item);
635 curr_needed->x = x;
636 curr_needed->y = y;
637 curr_needed->next = head;
638 head = curr_needed;
639 needed++;
640 } else if (!curr_sol->needed) {
641 curr->shown = false;
642 }
643 }
644 }
645 if (params->aggressive) {
646 curr_needed = head;
647 needed_array = snewn(needed, needed_list_item *);
648 memset(needed_array, 0, needed * sizeof(*needed_array));
649 i = 0;
650 while (curr_needed) {
651 needed_array[i] = curr_needed;
652 curr_needed = curr_needed->next;
653 i++;
654 }
655 shuffle(needed_array, needed, sizeof(*needed_array), rs);
656 for (i = 0; i < needed; i++) {
657 curr_needed = needed_array[i];
658 curr =
659 get_coords(params, desc, curr_needed->x, curr_needed->y);
660 if (curr) {
661 curr->shown = false;
662 if (!solve_check(params, desc, NULL, NULL)) {
663#ifdef DEBUG_PRINTS
664 printf("Hiding cell %d, %d not possible.\n",
665 curr_needed->x, curr_needed->y);
666#endif
667 curr->shown = true;
668 }
669 sfree(curr_needed);
670 needed_array[i] = NULL;
671 }
672 curr_needed = NULL;
673 }
674 sfree(needed_array);
675 }
676#ifdef DEBUG_PRINTS
677 printf("needed %d\n", needed);
678#endif
679 sfree(sol);
680}
681
682static bool start_point_check(size_t size, struct desc_cell *desc)
683{
684 int i;
685 for (i = 0; i < size; i++) {
686 if (desc[i].empty || desc[i].full) {
687 return true;
688 }
689 }
690 return false;
691}
692
693static void game_get_cursor_location(const game_ui *ui,
694 const game_drawstate *ds,
695 const game_state *state,
696 const game_params *params, int *x,
697 int *y, int *w, int *h)
698{
699 if (ui->cur_visible) {
700 *x = COORD_FROM_CELL(ui->cur_x);
701 *y = COORD_FROM_CELL(ui->cur_y);
702 *w = *h = ds->tilesize;
703 }
704}
705
706static void generate_image(const game_params *params, random_state *rs,
707 bool *image)
708{
709 int x, y;
710 for (y = 0; y < params->height; y++) {
711 for (x = 0; x < params->width; x++) {
712 image[(y * params->width) + x] = random_bits(rs, 1);
713 }
714 }
715}
716
717static char *new_game_desc(const game_params *params, random_state *rs,
718 char **aux, bool interactive)
719{
720 bool *image = snewn(params->height * params->width, bool);
721 bool valid = false;
722 char *desc_string = snewn((params->height * params->width) + 1, char);
723 char *compressed_desc =
724 snewn((params->height * params->width) + 1, char);
725 char space_count;
726
727 struct desc_cell *desc =
728 snewn(params->height * params->width, struct desc_cell);
729 int x, y, location_in_str;
730
731 while (!valid) {
732 generate_image(params, rs, image);
733#ifdef DEBUG_IMAGE
734 image[0] = 1;
735 image[1] = 1;
736 image[2] = 0;
737 image[3] = 1;
738 image[4] = 1;
739 image[5] = 0;
740 image[6] = 0;
741 image[7] = 0;
742 image[8] = 0;
743#endif
744
745 for (y = 0; y < params->height; y++) {
746 for (x = 0; x < params->width; x++) {
747 populate_cell(params, image, x, y,
748 x * y == 0 || y == params->height - 1 ||
749 x == params->width - 1,
750 &desc[(y * params->width) + x]);
751 }
752 }
753 valid =
754 start_point_check((params->height - 1) * (params->width - 1),
755 desc);
756 if (!valid) {
757#ifdef DEBUG_PRINTS
758 printf("Not valid, regenerating.\n");
759#endif
760 } else {
761 valid = solve_check(params, desc, rs, NULL);
762 if (!valid) {
763#ifdef DEBUG_PRINTS
764 printf("Couldn't solve, regenerating.");
765#endif
766 } else {
767 hide_clues(params, desc, rs);
768 }
769 }
770 }
771 location_in_str = 0;
772 for (y = 0; y < params->height; y++) {
773 for (x = 0; x < params->width; x++) {
774 if (desc[(y * params->width) + x].shown) {
775#ifdef DEBUG_PRINTS
776 printf("%d(%d)", desc[(y * params->width) + x].value,
777 desc[(y * params->width) + x].clue);
778#endif
779 sprintf(desc_string + location_in_str, "%d",
780 desc[(y * params->width) + x].clue);
781 } else {
782#ifdef DEBUG_PRINTS
783 printf("%d( )", desc[(y * params->width) + x].value);
784#endif
785 sprintf(desc_string + location_in_str, " ");
786 }
787 location_in_str += 1;
788 }
789#ifdef DEBUG_PRINTS
790 printf("\n");
791#endif
792 }
793 location_in_str = 0;
794 space_count = 'a' - 1;
795 for (y = 0; y < params->height; y++) {
796 for (x = 0; x < params->width; x++) {
797 if (desc[(y * params->width) + x].shown) {
798 if (space_count >= 'a') {
799 sprintf(compressed_desc + location_in_str, "%c",
800 space_count);
801 location_in_str++;
802 space_count = 'a' - 1;
803 }
804 sprintf(compressed_desc + location_in_str, "%d",
805 desc[(y * params->width) + x].clue);
806 location_in_str++;
807 } else {
808 if (space_count <= 'z') {
809 space_count++;
810 } else {
811 sprintf(compressed_desc + location_in_str, "%c",
812 space_count);
813 location_in_str++;
814 space_count = 'a' - 1;
815 }
816 }
817 }
818 }
819 if (space_count >= 'a') {
820 sprintf(compressed_desc + location_in_str, "%c", space_count);
821 location_in_str++;
822 }
823 compressed_desc[location_in_str] = '\0';
824#ifdef DEBUG_PRINTS
825 printf("compressed_desc: %s\n", compressed_desc);
826#endif
827 return compressed_desc;
828}
829
830static const char *validate_desc(const game_params *params,
831 const char *desc)
832{
833 int size_dest = params->height * params->width;
834 int length;
835 length = 0;
836
837 while (*desc != '\0') {
838 if (*desc >= 'a' && *desc <= 'z') {
839 length += *desc - 'a';
840 } else if (*desc < '0' || *desc > '9')
841 return "Invalid character in game description";
842 length++;
843 desc++;
844 }
845
846 if (length != size_dest) {
847 return "Desc size mismatch";
848 }
849 return NULL;
850}
851
852static game_state *new_game(midend *me, const game_params *params,
853 const char *desc)
854{
855 game_state *state = snew(game_state);
856 char *curr_desc = dupstr(desc);
857 char *desc_base = curr_desc;
858 int dest_loc;
859 int spaces, total_spaces;
860
861 state->cheating = false;
862 state->not_completed_clues = 0;
863 dest_loc = 0;
864 state->height = params->height;
865 state->width = params->width;
866 state->cells_contents = snewn(params->height * params->width, char);
867 memset(state->cells_contents, 0, params->height * params->width);
868 state->board = snew(board_state);
869 state->board->references = 1;
870 state->board->actual_board =
871 snewn(params->height * params->width, struct board_cell);
872
873 while (*curr_desc != '\0') {
874 if (*curr_desc >= '0' && *curr_desc <= '9') {
875 state->board->actual_board[dest_loc].shown = true;
876 state->not_completed_clues++;
877 state->board->actual_board[dest_loc].clue = *curr_desc - '0';
878 } else {
879 if (*curr_desc != ' ') {
880 total_spaces = *curr_desc - 'a' + 1;
881 } else {
882 total_spaces = 1;
883 }
884 spaces = 0;
885 while (spaces < total_spaces) {
886 state->board->actual_board[dest_loc].shown = false;
887 state->board->actual_board[dest_loc].clue = -1;
888 spaces++;
889 if (spaces < total_spaces) {
890 dest_loc++;
891 }
892 }
893 }
894 curr_desc++;
895 dest_loc++;
896 }
897
898 sfree(desc_base);
899 return state;
900}
901
902static game_state *dup_game(const game_state *state)
903{
904 game_state *ret = snew(game_state);
905
906 ret->cheating = state->cheating;
907 ret->not_completed_clues = state->not_completed_clues;
908 ret->width = state->width;
909 ret->height = state->height;
910 ret->cells_contents = snewn(state->height * state->width, char);
911 memcpy(ret->cells_contents, state->cells_contents,
912 state->height * state->width);
913 ret->board = state->board;
914 ret->board->references++;
915
916 return ret;
917}
918
919static void free_game(game_state *state)
920{
921 sfree(state->cells_contents);
922 state->cells_contents = NULL;
923 if (state->board->references <= 1) {
924 sfree(state->board->actual_board);
925 sfree(state->board);
926 state->board = NULL;
927 } else {
928 state->board->references--;
929 }
930 sfree(state);
931}
932
933static char *solve_game(const game_state *state,
934 const game_state *currstate, const char *aux,
935 const char **error)
936{
937 struct solution_cell *sol = NULL;
938 game_params param;
939 bool solved;
940 char *ret = NULL;
941 unsigned int curr_ret;
942 int i, bits, ret_loc = 1;
943 int size = state->width * state->height;
944
945 param.width = state->width;
946 param.height = state->height;
947 solved = solve_game_actual(&param, state->board->actual_board, &sol);
948 if (!solved) {
949 *error = dupstr("Could not solve this board");
950 sfree(sol);
951 return NULL;
952 }
953
954 ret = snewn((size / 4) + 3, char);
955
956 ret[0] = 's';
957 i = 0;
958 while (i < size) {
959 curr_ret = 0;
960 bits = 0;
961 while (bits < 8 && i < size) {
962 curr_ret <<= 1;
963 curr_ret |= sol[i].cell == STATE_MARKED;
964 i++;
965 bits++;
966 }
967 curr_ret <<= 8 - bits;
968 sprintf(ret + ret_loc, "%02x", curr_ret);
969 ret_loc += 2;
970 }
971
972 sfree(sol);
973 return ret;
974}
975
976static bool game_can_format_as_text_now(const game_params *params)
977{
978 return true;
979}
980
981static char *game_text_format(const game_state *state)
982{
983 char *desc_string =
984 snewn((state->height * state->width) * 3 + 1, char);
985 int location_in_str = 0, x, y;
986 for (y = 0; y < state->height; y++) {
987 for (x = 0; x < state->width; x++) {
988 if (state->board->actual_board[(y * state->width) + x].shown) {
989 sprintf(desc_string + location_in_str, "|%d|",
990 state->board->actual_board[(y * state->width) +
991 x].clue);
992 } else {
993 sprintf(desc_string + location_in_str, "| |");
994 }
995 location_in_str += 3;
996 }
997 sprintf(desc_string + location_in_str, "\n");
998 location_in_str += 1;
999 }
1000 return desc_string;
1001}
1002
1003static game_ui *new_ui(const game_state *state)
1004{
1005 game_ui *ui = snew(game_ui);
1006 ui->last_x = -1;
1007 ui->last_y = -1;
1008 ui->last_state = 0;
1009 ui->solved = false;
1010 ui->cur_x = ui->cur_y = 0;
1011 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1012 return ui;
1013}
1014
1015static void free_ui(game_ui *ui)
1016{
1017 sfree(ui);
1018}
1019
1020static void game_changed_state(game_ui *ui, const game_state *oldstate,
1021 const game_state *newstate)
1022{
1023}
1024
1025static const char *current_key_label(const game_ui *ui,
1026 const game_state *state, int button)
1027{
1028 char *cell;
1029
1030 if (IS_CURSOR_SELECT(button)) {
1031 if (!ui->cur_visible || state->not_completed_clues == 0) return "";
1032 cell = get_coords(state, state->cells_contents, ui->cur_x, ui->cur_y);
1033 switch (*cell & STATE_OK_NUM) {
1034 case STATE_UNMARKED:
1035 return button == CURSOR_SELECT ? "Black" : "White";
1036 case STATE_MARKED:
1037 return button == CURSOR_SELECT ? "White" : "Empty";
1038 case STATE_BLANK:
1039 return button == CURSOR_SELECT ? "Empty" : "Black";
1040 }
1041 }
1042 return "";
1043}
1044
1045static char *interpret_move(const game_state *state, game_ui *ui,
1046 const game_drawstate *ds, int x, int y,
1047 int button)
1048{
1049 int srcX = ui->last_x, srcY = ui->last_y;
1050 int offsetX, offsetY, gameX, gameY, i;
1051 int dirX, dirY, diff;
1052 char move_type;
1053 char move_desc[80];
1054 char *ret = NULL;
1055 const char *cell_state;
1056 bool changed = false;
1057 if (state->not_completed_clues == 0 && !IS_CURSOR_MOVE(button)) {
1058 return NULL;
1059 }
1060 offsetX = x - (ds->tilesize / 2);
1061 offsetY = y - (ds->tilesize / 2);
1062 gameX = offsetX / ds->tilesize;
1063 gameY = offsetY / ds->tilesize;
1064 if ((IS_MOUSE_DOWN(button) || IS_MOUSE_DRAG(button) || IS_MOUSE_RELEASE(button))
1065 && ((offsetX < 0) || (offsetY < 0)))
1066 return NULL;
1067 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
1068 cell_state =
1069 get_coords(state, state->cells_contents, gameX, gameY);
1070 if (cell_state) {
1071 ui->last_state = *cell_state & (STATE_BLANK | STATE_MARKED);
1072 ui->last_state =
1073 (ui->last_state +
1074 ((button ==
1075 RIGHT_BUTTON) ? 2 : 1)) % (STATE_BLANK | STATE_MARKED);
1076 }
1077 if (button == RIGHT_BUTTON) {
1078 /* Right button toggles twice */
1079 move_type = 'T';
1080 } else {
1081 move_type = 't';
1082 }
1083 if (gameX >= 0 && gameY >= 0 && gameX < state->width &&
1084 gameY < state->height) {
1085 sprintf(move_desc, "%c%d,%d", move_type, gameX, gameY);
1086 ui->last_x = gameX;
1087 ui->last_y = gameY;
1088 ret = dupstr(move_desc);
1089 } else {
1090 ui->last_x = -1;
1091 ui->last_y = -1;
1092 }
1093 changed = true;
1094 ui->cur_visible = false;
1095 } else if (button == LEFT_DRAG || button == RIGHT_DRAG) {
1096 move_type = 'd';
1097 /* allowing only drags in straight lines */
1098 if (gameX >= 0 && gameY >= 0 && gameX < state->width &&
1099 gameY < state->height && ui->last_x >= 0 && ui->last_y >= 0 &&
1100 (gameY == ui->last_y || gameX == ui->last_x)) {
1101 sprintf(move_desc, "%c%d,%d,%d,%d,%d", move_type, gameX, gameY,
1102 ui->last_x, ui->last_y, ui->last_state);
1103 if (srcX == gameX && srcY != gameY) {
1104 dirX = 0;
1105 diff = srcY - gameY;
1106 if (diff < 0) {
1107 dirY = -1;
1108 diff *= -1;
1109 } else {
1110 dirY = 1;
1111 }
1112 } else {
1113 diff = srcX - gameX;
1114 dirY = 0;
1115 if (diff < 0) {
1116 dirX = -1;
1117 diff *= -1;
1118 } else {
1119 dirX = 1;
1120 }
1121 }
1122 for (i = 0; i < diff; i++) {
1123 cell_state = get_coords(state, state->cells_contents,
1124 gameX + (dirX * i),
1125 gameY + (dirY * i));
1126 if (cell_state && (*cell_state & STATE_OK_NUM) == 0
1127 && ui->last_state > 0) {
1128 changed = true;
1129 break;
1130 }
1131 }
1132 ui->last_x = gameX;
1133 ui->last_y = gameY;
1134 if (changed) {
1135 ret = dupstr(move_desc);
1136 }
1137 } else {
1138 ui->last_x = -1;
1139 ui->last_y = -1;
1140 }
1141 ui->cur_visible = false;
1142 } else if (button == LEFT_RELEASE || button == RIGHT_RELEASE) {
1143 move_type = 'e';
1144 if (gameX >= 0 && gameY >= 0 && gameX < state->width &&
1145 gameY < state->height && ui->last_x >= 0 && ui->last_y >= 0 &&
1146 (gameY == ui->last_y || gameX == ui->last_x)) {
1147 sprintf(move_desc, "%c%d,%d,%d,%d,%d", move_type, gameX, gameY,
1148 ui->last_x, ui->last_y, ui->last_state);
1149 if (srcX == gameX && srcY != gameY) {
1150 dirX = 0;
1151 diff = srcY - gameY;
1152 if (diff < 0) {
1153 dirY = -1;
1154 diff *= -1;
1155 } else {
1156 dirY = 1;
1157 }
1158 } else {
1159 diff = srcX - gameX;
1160 dirY = 0;
1161 if (diff < 0) {
1162 dirX = -1;
1163 diff *= -1;
1164 } else {
1165 dirX = 1;
1166 }
1167 }
1168 for (i = 0; i < diff; i++) {
1169 cell_state = get_coords(state, state->cells_contents,
1170 gameX + (dirX * i),
1171 gameY + (dirY * i));
1172 if (cell_state && (*cell_state & STATE_OK_NUM) == 0
1173 && ui->last_state > 0) {
1174 changed = true;
1175 break;
1176 }
1177 }
1178 if (changed) {
1179 ret = dupstr(move_desc);
1180 }
1181 } else {
1182 ui->last_x = -1;
1183 ui->last_y = -1;
1184 }
1185 ui->cur_visible = false;
1186 } else if (IS_CURSOR_MOVE(button)) {
1187 return move_cursor(button, &ui->cur_x, &ui->cur_y, state->width,
1188 state->height, false, &ui->cur_visible);
1189 } else if (IS_CURSOR_SELECT(button)) {
1190 if (!ui->cur_visible) {
1191 ui->cur_x = 0;
1192 ui->cur_y = 0;
1193 ui->cur_visible = true;
1194 return MOVE_UI_UPDATE;
1195 }
1196
1197 if (button == CURSOR_SELECT2) {
1198 sprintf(move_desc, "T%d,%d", ui->cur_x, ui->cur_y);
1199 ret = dupstr(move_desc);
1200 } else {
1201 /* Otherwise, treat as LEFT_BUTTON, for a single square. */
1202 sprintf(move_desc, "t%d,%d", ui->cur_x, ui->cur_y);
1203 ret = dupstr(move_desc);
1204 }
1205 }
1206 return ret;
1207}
1208
1209static void update_board_state_around(game_state *state, int x, int y)
1210{
1211 int i, j;
1212 struct board_cell *curr;
1213 char *curr_state;
1214 int total;
1215 int blank;
1216 int marked;
1217
1218 for (i = -1; i < 2; i++) {
1219 for (j = -1; j < 2; j++) {
1220 curr =
1221 get_coords(state, state->board->actual_board, x + i,
1222 y + j);
1223 if (curr && curr->shown) {
1224 curr_state =
1225 get_coords(state, state->cells_contents, x + i, y + j);
1226 count_around_state(state, x + i, y + j, &marked, &blank,
1227 &total);
1228 if (curr->clue == marked && (total - marked - blank) == 0) {
1229 *curr_state &= STATE_MARKED | STATE_BLANK;
1230 *curr_state |= STATE_SOLVED;
1231 } else if (curr->clue < marked
1232 || curr->clue > (total - blank)) {
1233 *curr_state &= STATE_MARKED | STATE_BLANK;
1234 *curr_state |= STATE_ERROR;
1235 } else {
1236 *curr_state &= STATE_MARKED | STATE_BLANK;
1237 }
1238 }
1239 }
1240 }
1241}
1242
1243static game_state *execute_move(const game_state *state, const char *move)
1244{
1245 game_state *new_state = dup_game(state);
1246 int i = 0, x = -1, y = -1, clues_left = 0;
1247 int srcX = -1, srcY = -1, size = state->height * state->width;
1248 const char *p;
1249 char *cell, sol_char;
1250 int steps = 1, bits, sol_location, dirX, dirY, diff,
1251 last_state = STATE_UNMARKED;
1252 unsigned int sol_value;
1253 struct board_cell *curr_cell;
1254 char move_type;
1255 int nparams = 0, move_params[5];
1256
1257 p = move;
1258 move_type = *p++;
1259 switch (move_type) {
1260 case 't':
1261 case 'T':
1262 nparams = 2;
1263 break;
1264 case 'd':
1265 case 'e':
1266 nparams = 5;
1267 break;
1268 }
1269
1270 for (i = 0; i < nparams; i++) {
1271 move_params[i] = atoi(p);
1272 while (*p && isdigit((unsigned char)*p)) p++;
1273 if (i+1 < nparams) {
1274 if (*p != ',') {
1275 free_game(new_state);
1276 return NULL;
1277 }
1278 p++;
1279 }
1280 }
1281
1282 if (move_type == 't' || move_type == 'T') {
1283 if (move_type == 'T') {
1284 steps++;
1285 }
1286 x = move_params[0];
1287 y = move_params[1];
1288 if (x == -1 || y == -1) {
1289 return new_state;
1290 }
1291 cell = get_coords(new_state, new_state->cells_contents, x, y);
1292 if (cell == NULL) {
1293 free_game(new_state);
1294 return NULL;
1295 }
1296 if (*cell >= STATE_OK_NUM) {
1297 *cell &= STATE_OK_NUM;
1298 }
1299 *cell = (*cell + steps) % STATE_OK_NUM;
1300 update_board_state_around(new_state, x, y);
1301 } else if (move_type == 's') {
1302 new_state->not_completed_clues = 0;
1303 new_state->cheating = true;
1304 sol_location = 0;
1305 bits = 0;
1306 i = 1;
1307 while (i < strlen(move)) {
1308 sol_value = 0;
1309 while (bits < 8) {
1310 sol_value <<= 4;
1311 sol_char = move[i];
1312 if (sol_char >= '0' && sol_char <= '9') {
1313 sol_value |= sol_char - '0';
1314 } else {
1315 sol_value |= (sol_char - 'a') + 10;
1316 }
1317 bits += 4;
1318 i++;
1319 }
1320 while (bits > 0 && sol_location < size) {
1321 if (sol_value & 0x80) {
1322 new_state->cells_contents[sol_location] =
1323 STATE_MARKED_SOLVED;
1324 } else {
1325 new_state->cells_contents[sol_location] =
1326 STATE_BLANK_SOLVED;
1327 }
1328 sol_value <<= 1;
1329 bits--;
1330 sol_location++;
1331 }
1332 }
1333 return new_state;
1334 } else if (move_type == 'd' || move_type == 'e') {
1335 x = move_params[0];
1336 y = move_params[1];
1337 srcX = move_params[2];
1338 srcY = move_params[3];
1339 last_state = move_params[4];
1340 if (srcX == x && srcY != y) {
1341 dirX = 0;
1342 diff = srcY - y;
1343 if (diff < 0) {
1344 dirY = -1;
1345 diff *= -1;
1346 } else {
1347 dirY = 1;
1348 }
1349 } else {
1350 diff = srcX - x;
1351 dirY = 0;
1352 if (diff < 0) {
1353 dirX = -1;
1354 diff *= -1;
1355 } else {
1356 dirX = 1;
1357 }
1358 }
1359 for (i = 0; i < diff; i++) {
1360 cell = get_coords(new_state, new_state->cells_contents,
1361 x + (dirX * i), y + (dirY * i));
1362 if (cell == NULL) {
1363 free_game(new_state);
1364 return NULL;
1365 }
1366 if ((*cell & STATE_OK_NUM) == 0) {
1367 *cell = last_state;
1368 update_board_state_around(new_state, x + (dirX * i),
1369 y + (dirY * i));
1370 }
1371 }
1372 }
1373 for (y = 0; y < state->height; y++) {
1374 for (x = 0; x < state->width; x++) {
1375 cell = get_coords(new_state, new_state->cells_contents, x, y);
1376 curr_cell = get_coords(new_state, new_state->board->actual_board,
1377 x, y);
1378 if (curr_cell->shown && ((*cell & STATE_SOLVED) == 0)) {
1379 clues_left++;
1380 }
1381 }
1382 }
1383 new_state->not_completed_clues = clues_left;
1384 return new_state;
1385}
1386
1387/* ----------------------------------------------------------------------
1388 * Drawing routines.
1389 */
1390
1391static void game_compute_size(const game_params *params, int tilesize,
1392 const game_ui *ui, int *x, int *y)
1393{
1394 *x = (params->width + 1) * tilesize;
1395 *y = (params->height + 1) * tilesize;
1396}
1397
1398static void game_set_size(drawing *dr, game_drawstate *ds,
1399 const game_params *params, int tilesize)
1400{
1401 ds->tilesize = tilesize;
1402}
1403
1404#define COLOUR(ret, i, r, g, b) \
1405 ((ret[3 * (i) + 0] = (r)), (ret[3 * (i) + 1] = (g)), (ret[3 * (i) + 2] = (b)))
1406
1407static float *game_colours(frontend *fe, int *ncolours)
1408{
1409 float *ret = snewn(3 * NCOLOURS, float);
1410
1411 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
1412 COLOUR(ret, COL_GRID, 0.0F, 102 / 255.0F, 99 / 255.0F);
1413 COLOUR(ret, COL_ERROR, 1.0F, 0.0F, 0.0F);
1414 COLOUR(ret, COL_BLANK, 236 / 255.0F, 236 / 255.0F, 236 / 255.0F);
1415 COLOUR(ret, COL_MARKED, 20 / 255.0F, 20 / 255.0F, 20 / 255.0F);
1416 COLOUR(ret, COL_UNMARKED, 148 / 255.0F, 196 / 255.0F, 190 / 255.0F);
1417 COLOUR(ret, COL_TEXT_SOLVED, 100 / 255.0F, 100 / 255.0F, 100 / 255.0F);
1418 COLOUR(ret, COL_CURSOR, 255 / 255.0F, 200 / 255.0F, 200 / 255.0F);
1419
1420 *ncolours = NCOLOURS;
1421 return ret;
1422}
1423
1424/* Extra flags in game_drawstate entries, not in main game state */
1425#define DRAWFLAG_CURSOR 0x100
1426#define DRAWFLAG_CURSOR_U 0x200
1427#define DRAWFLAG_CURSOR_L 0x400
1428#define DRAWFLAG_CURSOR_UL 0x800
1429#define DRAWFLAG_MARGIN_R 0x1000
1430#define DRAWFLAG_MARGIN_D 0x2000
1431
1432static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1433{
1434 struct game_drawstate *ds = snew(game_drawstate);
1435 int i;
1436
1437 ds->tilesize = 0;
1438 ds->state = NULL;
1439 ds->state = snewn((state->width + 1) * (state->height + 1), int);
1440 for (i = 0; i < (state->width + 1) * (state->height + 1); i++)
1441 ds->state[i] = -1;
1442
1443 return ds;
1444}
1445
1446static void game_free_drawstate(drawing *dr, game_drawstate *ds)
1447{
1448 sfree(ds->state);
1449 sfree(ds);
1450}
1451
1452static void draw_cell(drawing *dr, int cell, int ts, signed char clue_val,
1453 int x, int y)
1454{
1455 int startX = ((x * ts) + ts / 2) - 1, startY = ((y * ts) + ts / 2) - 1;
1456 int color, text_color = COL_TEXT_DARK;
1457
1458 clip(dr, startX - 1, startY - 1, ts, ts);
1459 if (!(cell & DRAWFLAG_MARGIN_R))
1460 draw_rect(dr, startX - 1, startY - 1, ts, 1,
1461 (cell & (DRAWFLAG_CURSOR | DRAWFLAG_CURSOR_U) ?
1462 COL_CURSOR : COL_GRID));
1463 if (!(cell & DRAWFLAG_MARGIN_D))
1464 draw_rect(dr, startX - 1, startY - 1, 1, ts,
1465 (cell & (DRAWFLAG_CURSOR | DRAWFLAG_CURSOR_L) ?
1466 COL_CURSOR : COL_GRID));
1467 if (cell & DRAWFLAG_CURSOR_UL)
1468 draw_rect(dr, startX - 1, startY - 1, 1, 1, COL_CURSOR);
1469
1470 if (!(cell & (DRAWFLAG_MARGIN_R | DRAWFLAG_MARGIN_D))) {
1471 if (cell & STATE_MARKED) {
1472 color = COL_MARKED;
1473 text_color = COL_TEXT_LIGHT;
1474 } else if (cell & STATE_BLANK) {
1475 text_color = COL_TEXT_DARK;
1476 color = COL_BLANK;
1477 } else {
1478 text_color = COL_TEXT_DARK;
1479 color = COL_UNMARKED;
1480 }
1481 if (cell & STATE_ERROR) {
1482 text_color = COL_ERROR;
1483 } else if (cell & STATE_SOLVED) {
1484 text_color = COL_TEXT_SOLVED;
1485 }
1486
1487 draw_rect(dr, startX, startY, ts - 1, ts - 1, color);
1488 if (clue_val >= 0) {
1489 char clue[80];
1490 sprintf(clue, "%d", clue_val);
1491 draw_text(dr, startX + ts / 2, startY + ts / 2, 1, ts * 3 / 5,
1492 ALIGN_VCENTRE | ALIGN_HCENTRE, text_color, clue);
1493 }
1494 }
1495
1496 unclip(dr);
1497 draw_update(dr, startX - 1, startY - 1, ts, ts);
1498}
1499
1500static void game_redraw(drawing *dr, game_drawstate *ds,
1501 const game_state *oldstate,
1502 const game_state *state, int dir,
1503 const game_ui *ui, float animtime,
1504 float flashtime)
1505{
1506 int x, y;
1507 char status[80];
1508 signed char clue_val;
1509 bool flashing = (flashtime > 0 && (flashtime <= FLASH_TIME / 3 ||
1510 flashtime > 2*FLASH_TIME / 3));
1511
1512 for (y = 0; y <= state->height; y++) {
1513 for (x = 0; x <= state->width; x++) {
1514 bool inbounds = x < state->width && y < state->height;
1515 int cell = (inbounds ?
1516 state->cells_contents[(y * state->width) + x] : 0);
1517 if (x == state->width)
1518 cell |= DRAWFLAG_MARGIN_R;
1519 if (y == state->height)
1520 cell |= DRAWFLAG_MARGIN_D;
1521 if (flashing)
1522 cell ^= (STATE_BLANK | STATE_MARKED);
1523 if (ui->cur_visible) {
1524 if (ui->cur_x == x && ui->cur_y == y)
1525 cell |= DRAWFLAG_CURSOR;
1526 if (ui->cur_x == x-1 && ui->cur_y == y)
1527 cell |= DRAWFLAG_CURSOR_L;
1528 if (ui->cur_x == x && ui->cur_y == y-1)
1529 cell |= DRAWFLAG_CURSOR_U;
1530 if (ui->cur_x == x-1 && ui->cur_y == y-1)
1531 cell |= DRAWFLAG_CURSOR_UL;
1532 }
1533
1534 if (inbounds &&
1535 state->board->actual_board[(y * state->width) + x].shown) {
1536 clue_val = state->board->actual_board[
1537 (y * state->width) + x].clue;
1538 } else {
1539 clue_val = -1;
1540 }
1541
1542 if (ds->state[(y * (state->width+1)) + x] != cell) {
1543 draw_cell(dr, cell, ds->tilesize, clue_val, x, y);
1544 ds->state[(y * (state->width+1)) + x] = cell;
1545 }
1546 }
1547 }
1548 sprintf(status, "Clues left: %d", state->not_completed_clues);
1549 if (state->not_completed_clues == 0 && !state->cheating) {
1550 sprintf(status, "COMPLETED!");
1551 } else if (state->not_completed_clues == 0 && state->cheating) {
1552 sprintf(status, "Auto solved");
1553 }
1554 status_bar(dr, status);
1555}
1556
1557static float game_anim_length(const game_state *oldstate,
1558 const game_state *newstate, int dir,
1559 game_ui *ui)
1560{
1561 return 0.0F;
1562}
1563
1564static float game_flash_length(const game_state *oldstate,
1565 const game_state *newstate, int dir,
1566 game_ui *ui)
1567{
1568 if (!oldstate->cheating && oldstate->not_completed_clues > 0 &&
1569 newstate->not_completed_clues == 0) {
1570 return FLASH_TIME;
1571 }
1572 return 0.0F;
1573}
1574
1575static int game_status(const game_state *state)
1576{
1577 if (state->not_completed_clues == 0)
1578 return +1;
1579 return 0;
1580}
1581
1582#ifdef COMBINED
1583#define thegame mosaic
1584#endif
1585
1586const struct game thegame = {
1587 "Mosaic", "games.mosaic", "mosaic",
1588 default_params,
1589 game_fetch_preset, NULL,
1590 decode_params,
1591 encode_params,
1592 free_params,
1593 dup_params,
1594 true, game_configure, custom_params,
1595 validate_params,
1596 new_game_desc,
1597 validate_desc,
1598 new_game,
1599 dup_game,
1600 free_game,
1601 true, solve_game,
1602 true, game_can_format_as_text_now, game_text_format,
1603 NULL, NULL, /* get_prefs, set_prefs */
1604 new_ui,
1605 free_ui,
1606 NULL, /* encode_ui */
1607 NULL, /* decode_ui */
1608 NULL, /* game_request_keys */
1609 game_changed_state,
1610 current_key_label,
1611 interpret_move,
1612 execute_move,
1613 DEFAULT_TILE_SIZE, game_compute_size, game_set_size,
1614 game_colours,
1615 game_new_drawstate,
1616 game_free_drawstate,
1617 game_redraw,
1618 game_anim_length,
1619 game_flash_length,
1620 game_get_cursor_location,
1621 game_status,
1622 false, false, NULL, NULL, /* print_size, print */
1623 true, /* wants_statusbar */
1624 false, NULL, /* timing_state */
1625 0, /* flags */
1626};
diff --git a/apps/plugins/puzzles/src/nestedvm.c b/apps/plugins/puzzles/src/nestedvm.c
index 947abe0fae..0a9fdbcfed 100644
--- a/apps/plugins/puzzles/src/nestedvm.c
+++ b/apps/plugins/puzzles/src/nestedvm.c
@@ -206,7 +206,7 @@ int jcallback_key_event(int x, int y, int keyval)
206 if (fe->ox == -1) 206 if (fe->ox == -1)
207 return 1; 207 return 1;
208 if (keyval >= 0 && 208 if (keyval >= 0 &&
209 !midend_process_key(fe->me, x - fe->ox, y - fe->oy, keyval)) 209 midend_process_key(fe->me, x - fe->ox, y - fe->oy, keyval) == PKR_QUIT)
210 return 42; 210 return 42;
211 return 1; 211 return 1;
212} 212}
@@ -217,7 +217,7 @@ int jcallback_resize(int width, int height)
217 int x, y; 217 int x, y;
218 x = width; 218 x = width;
219 y = height; 219 y = height;
220 midend_size(fe->me, &x, &y, true); 220 midend_size(fe->me, &x, &y, true, 1.0);
221 fe->ox = (width - x) / 2; 221 fe->ox = (width - x) / 2;
222 fe->oy = (height - y) / 2; 222 fe->oy = (height - y) / 2;
223 fe->w = x; 223 fe->w = x;
@@ -323,7 +323,7 @@ static bool get_config(frontend *fe, int which)
323int jcallback_newgame_event(void) 323int jcallback_newgame_event(void)
324{ 324{
325 frontend *fe = (frontend *)_fe; 325 frontend *fe = (frontend *)_fe;
326 if (!midend_process_key(fe->me, 0, 0, UI_NEWGAME)) 326 if (midend_process_key(fe->me, 0, 0, UI_NEWGAME) == PKR_QUIT)
327 return 42; 327 return 42;
328 return 0; 328 return 0;
329} 329}
@@ -331,7 +331,7 @@ int jcallback_newgame_event(void)
331int jcallback_undo_event(void) 331int jcallback_undo_event(void)
332{ 332{
333 frontend *fe = (frontend *)_fe; 333 frontend *fe = (frontend *)_fe;
334 if (!midend_process_key(fe->me, 0, 0, UI_UNDO)) 334 if (midend_process_key(fe->me, 0, 0, UI_UNDO) == PKR_QUIT)
335 return 42; 335 return 42;
336 return 0; 336 return 0;
337} 337}
@@ -339,7 +339,7 @@ int jcallback_undo_event(void)
339int jcallback_redo_event(void) 339int jcallback_redo_event(void)
340{ 340{
341 frontend *fe = (frontend *)_fe; 341 frontend *fe = (frontend *)_fe;
342 if (!midend_process_key(fe->me, 0, 0, UI_REDO)) 342 if (midend_process_key(fe->me, 0, 0, UI_REDO) == PKR_QUIT)
343 return 42; 343 return 42;
344 return 0; 344 return 0;
345} 345}
@@ -347,7 +347,7 @@ int jcallback_redo_event(void)
347int jcallback_quit_event(void) 347int jcallback_quit_event(void)
348{ 348{
349 frontend *fe = (frontend *)_fe; 349 frontend *fe = (frontend *)_fe;
350 if (!midend_process_key(fe->me, 0, 0, UI_QUIT)) 350 if (midend_process_key(fe->me, 0, 0, UI_QUIT) == PKR_QUIT)
351 return 42; 351 return 42;
352 return 0; 352 return 0;
353} 353}
@@ -358,7 +358,7 @@ static void resize_fe(frontend *fe)
358 358
359 x = INT_MAX; 359 x = INT_MAX;
360 y = INT_MAX; 360 y = INT_MAX;
361 midend_size(fe->me, &x, &y, false); 361 midend_size(fe->me, &x, &y, false, 1.0);
362 _call_java(3, x, y, 0); 362 _call_java(3, x, y, 0);
363} 363}
364 364
diff --git a/apps/plugins/puzzles/src/net.R b/apps/plugins/puzzles/src/net.R
deleted file mode 100644
index 8e98216e03..0000000000
--- a/apps/plugins/puzzles/src/net.R
+++ /dev/null
@@ -1,23 +0,0 @@
1# -*- makefile -*-
2
3NET_EXTRA = tree234 dsf findloop
4
5net : [X] GTK COMMON net NET_EXTRA net-icon|no-icon
6
7# The Windows Net shouldn't be called `net.exe' since Windows
8# already has a reasonably important utility program by that name!
9netgame : [G] WINDOWS COMMON net NET_EXTRA net.res|noicon.res
10
11ALL += net[COMBINED] NET_EXTRA
12
13!begin am gtk
14GAMES += net
15!end
16
17!begin >list.c
18 A(net) \
19!end
20
21!begin >gamedesc.txt
22net:netgame.exe:Net:Network jigsaw puzzle:Rotate each tile to reassemble the network.
23!end
diff --git a/apps/plugins/puzzles/src/net.c b/apps/plugins/puzzles/src/net.c
index d3032b6fe2..3200253ef9 100644
--- a/apps/plugins/puzzles/src/net.c
+++ b/apps/plugins/puzzles/src/net.c
@@ -7,7 +7,12 @@
7#include <string.h> 7#include <string.h>
8#include <assert.h> 8#include <assert.h>
9#include <ctype.h> 9#include <ctype.h>
10#include <math.h> 10#include <limits.h>
11#ifdef NO_TGMATH_H
12# include <math.h>
13#else
14# include <tgmath.h>
15#endif
11 16
12#include "puzzles.h" 17#include "puzzles.h"
13#include "tree234.h" 18#include "tree234.h"
@@ -249,10 +254,7 @@ static char *encode_params(const game_params *params, bool full)
249 if (params->wrapping) 254 if (params->wrapping)
250 ret[len++] = 'w'; 255 ret[len++] = 'w';
251 if (full && params->barrier_probability) 256 if (full && params->barrier_probability)
252 { 257 len += sprintf(ret+len, "b%g", params->barrier_probability);
253 len += sprintf(ret+len, "b");
254 len += ftoa(ret + len, params->barrier_probability);
255 }
256 if (full && !params->unique) 258 if (full && !params->unique)
257 ret[len++] = 'a'; 259 ret[len++] = 'a';
258 assert(len < lenof(ret)); 260 assert(len < lenof(ret));
@@ -284,7 +286,7 @@ static config_item *game_configure(const game_params *params)
284 286
285 ret[3].name = "Barrier probability"; 287 ret[3].name = "Barrier probability";
286 ret[3].type = C_STRING; 288 ret[3].type = C_STRING;
287 ftoa(buf, params->barrier_probability); 289 sprintf(buf, "%g", params->barrier_probability);
288 ret[3].u.string.sval = dupstr(buf); 290 ret[3].u.string.sval = dupstr(buf);
289 291
290 ret[4].name = "Ensure unique solution"; 292 ret[4].name = "Ensure unique solution";
@@ -316,6 +318,8 @@ static const char *validate_params(const game_params *params, bool full)
316 return "Width and height must both be greater than zero"; 318 return "Width and height must both be greater than zero";
317 if (params->width <= 1 && params->height <= 1) 319 if (params->width <= 1 && params->height <= 1)
318 return "At least one of width and height must be greater than one"; 320 return "At least one of width and height must be greater than one";
321 if (params->width > INT_MAX / params->height)
322 return "Width times height must not be unreasonably large";
319 if (params->barrier_probability < 0) 323 if (params->barrier_probability < 0)
320 return "Barrier probability may not be negative"; 324 return "Barrier probability may not be negative";
321 if (params->barrier_probability > 1) 325 if (params->barrier_probability > 1)
@@ -458,7 +462,7 @@ static int net_solver(int w, int h, unsigned char *tiles,
458 unsigned char *tilestate; 462 unsigned char *tilestate;
459 unsigned char *edgestate; 463 unsigned char *edgestate;
460 int *deadends; 464 int *deadends;
461 int *equivalence; 465 DSF *equivalence;
462 struct todo *todo; 466 struct todo *todo;
463 int i, j, x, y; 467 int i, j, x, y;
464 int area; 468 int area;
@@ -543,7 +547,7 @@ static int net_solver(int w, int h, unsigned char *tiles,
543 * classes) by finding the representative of each tile and 547 * classes) by finding the representative of each tile and
544 * setting equivalence[one]=the_other. 548 * setting equivalence[one]=the_other.
545 */ 549 */
546 equivalence = snew_dsf(w * h); 550 equivalence = dsf_new(w * h);
547 551
548 /* 552 /*
549 * On a non-wrapping grid, we instantly know that all the edges 553 * On a non-wrapping grid, we instantly know that all the edges
@@ -828,7 +832,7 @@ static int net_solver(int w, int h, unsigned char *tiles,
828 sfree(tilestate); 832 sfree(tilestate);
829 sfree(edgestate); 833 sfree(edgestate);
830 sfree(deadends); 834 sfree(deadends);
831 sfree(equivalence); 835 dsf_free(equivalence);
832 836
833 return j; 837 return j;
834} 838}
@@ -1131,7 +1135,8 @@ static void perturb(int w, int h, unsigned char *tiles, bool wrapping,
1131 1135
1132static int *compute_loops_inner(int w, int h, bool wrapping, 1136static int *compute_loops_inner(int w, int h, bool wrapping,
1133 const unsigned char *tiles, 1137 const unsigned char *tiles,
1134 const unsigned char *barriers); 1138 const unsigned char *barriers,
1139 bool include_unlocked_squares);
1135 1140
1136static char *new_game_desc(const game_params *params, random_state *rs, 1141static char *new_game_desc(const game_params *params, random_state *rs,
1137 char **aux, bool interactive) 1142 char **aux, bool interactive)
@@ -1460,7 +1465,8 @@ static char *new_game_desc(const game_params *params, random_state *rs,
1460 */ 1465 */
1461 prev_loopsquares = w*h+1; 1466 prev_loopsquares = w*h+1;
1462 while (1) { 1467 while (1) {
1463 loops = compute_loops_inner(w, h, params->wrapping, tiles, NULL); 1468 loops = compute_loops_inner(w, h, params->wrapping, tiles, NULL,
1469 true);
1464 this_loopsquares = 0; 1470 this_loopsquares = 0;
1465 for (i = 0; i < w*h; i++) { 1471 for (i = 0; i < w*h; i++) {
1466 if (loops[i]) { 1472 if (loops[i]) {
@@ -1848,16 +1854,6 @@ static char *solve_game(const game_state *state, const game_state *currstate,
1848 return ret; 1854 return ret;
1849} 1855}
1850 1856
1851static bool game_can_format_as_text_now(const game_params *params)
1852{
1853 return true;
1854}
1855
1856static char *game_text_format(const game_state *state)
1857{
1858 return NULL;
1859}
1860
1861/* ---------------------------------------------------------------------- 1857/* ----------------------------------------------------------------------
1862 * Utility routine. 1858 * Utility routine.
1863 */ 1859 */
@@ -1878,6 +1874,8 @@ static unsigned char *compute_active(const game_state *state, int cx, int cy)
1878 active = snewn(state->width * state->height, unsigned char); 1874 active = snewn(state->width * state->height, unsigned char);
1879 memset(active, 0, state->width * state->height); 1875 memset(active, 0, state->width * state->height);
1880 1876
1877 assert(0 <= cx && cx < state->width);
1878 assert(0 <= cy && cy < state->height);
1881 /* 1879 /*
1882 * We only store (x,y) pairs in todo, but it's easier to reuse 1880 * We only store (x,y) pairs in todo, but it's easier to reuse
1883 * xyd_cmp and just store direction 0 every time. 1881 * xyd_cmp and just store direction 0 every time.
@@ -1923,6 +1921,7 @@ struct net_neighbour_ctx {
1923 int w, h; 1921 int w, h;
1924 const unsigned char *tiles, *barriers; 1922 const unsigned char *tiles, *barriers;
1925 int i, n, neighbours[4]; 1923 int i, n, neighbours[4];
1924 bool include_unlocked_squares;
1926}; 1925};
1927static int net_neighbour(int vertex, void *vctx) 1926static int net_neighbour(int vertex, void *vctx)
1928{ 1927{
@@ -1943,6 +1942,9 @@ static int net_neighbour(int vertex, void *vctx)
1943 continue; 1942 continue;
1944 OFFSETWH(x1, y1, x, y, dir, ctx->w, ctx->h); 1943 OFFSETWH(x1, y1, x, y, dir, ctx->w, ctx->h);
1945 v1 = y1 * ctx->w + x1; 1944 v1 = y1 * ctx->w + x1;
1945 if (!ctx->include_unlocked_squares &&
1946 !(tile & ctx->tiles[v1] & LOCKED))
1947 continue;
1946 if (ctx->tiles[v1] & F(dir)) 1948 if (ctx->tiles[v1] & F(dir))
1947 ctx->neighbours[ctx->n++] = v1; 1949 ctx->neighbours[ctx->n++] = v1;
1948 } 1950 }
@@ -1956,32 +1958,39 @@ static int net_neighbour(int vertex, void *vctx)
1956 1958
1957static int *compute_loops_inner(int w, int h, bool wrapping, 1959static int *compute_loops_inner(int w, int h, bool wrapping,
1958 const unsigned char *tiles, 1960 const unsigned char *tiles,
1959 const unsigned char *barriers) 1961 const unsigned char *barriers,
1962 bool include_unlocked_squares)
1960{ 1963{
1961 struct net_neighbour_ctx ctx; 1964 struct net_neighbour_ctx ctx;
1962 struct findloopstate *fls; 1965 struct findloopstate *fls;
1963 int *loops; 1966 int *loops;
1964 int x, y; 1967 int x, y, v;
1965 1968
1966 fls = findloop_new_state(w*h); 1969 fls = findloop_new_state(w*h);
1967 ctx.w = w; 1970 ctx.w = w;
1968 ctx.h = h; 1971 ctx.h = h;
1969 ctx.tiles = tiles; 1972 ctx.tiles = tiles;
1970 ctx.barriers = barriers; 1973 ctx.barriers = barriers;
1974 ctx.include_unlocked_squares = include_unlocked_squares;
1971 findloop_run(fls, w*h, net_neighbour, &ctx); 1975 findloop_run(fls, w*h, net_neighbour, &ctx);
1972 1976
1973 loops = snewn(w*h, int); 1977 loops = snewn(w*h, int);
1974 1978
1975 for (y = 0; y < h; y++) { 1979 for (y = 0; y < h; y++) {
1976 for (x = 0; x < w; x++) { 1980 for (x = 0; x < w; x++) {
1977 int x1, y1, dir; 1981 int x1, y1, v1, dir;
1978 int flags = 0; 1982 int flags = 0;
1979 1983
1984 v = y * w + x;
1980 for (dir = 1; dir < 0x10; dir <<= 1) { 1985 for (dir = 1; dir < 0x10; dir <<= 1) {
1981 if ((tiles[y*w+x] & dir) && 1986 if ((tiles[v] & dir) &&
1982 !(barriers && (barriers[y*w+x] & dir))) { 1987 !(barriers && (barriers[y*w+x] & dir))) {
1983 OFFSETWH(x1, y1, x, y, dir, w, h); 1988 OFFSETWH(x1, y1, x, y, dir, w, h);
1984 if ((tiles[y1*w+x1] & F(dir)) && 1989 v1 = y1 * w + x1;
1990 if (!include_unlocked_squares &&
1991 !(tiles[v] & tiles[v1] & LOCKED))
1992 continue;
1993 if ((tiles[v1] & F(dir)) &&
1985 findloop_is_loop_edge(fls, y*w+x, y1*w+x1)) 1994 findloop_is_loop_edge(fls, y*w+x, y1*w+x1))
1986 flags |= ERR(dir); 1995 flags |= ERR(dir);
1987 } 1996 }
@@ -1994,10 +2003,12 @@ static int *compute_loops_inner(int w, int h, bool wrapping,
1994 return loops; 2003 return loops;
1995} 2004}
1996 2005
1997static int *compute_loops(const game_state *state) 2006static int *compute_loops(const game_state *state,
2007 bool include_unlocked_squares)
1998{ 2008{
1999 return compute_loops_inner(state->width, state->height, state->wrapping, 2009 return compute_loops_inner(state->width, state->height, state->wrapping,
2000 state->tiles, state->imm->barriers); 2010 state->tiles, state->imm->barriers,
2011 include_unlocked_squares);
2001} 2012}
2002 2013
2003struct game_ui { 2014struct game_ui {
@@ -2010,6 +2021,8 @@ struct game_ui {
2010 int dragtilex, dragtiley, dragstartx, dragstarty; 2021 int dragtilex, dragtiley, dragstartx, dragstarty;
2011 bool dragged; 2022 bool dragged;
2012#endif 2023#endif
2024
2025 bool unlocked_loops;
2013}; 2026};
2014 2027
2015static game_ui *new_ui(const game_state *state) 2028static game_ui *new_ui(const game_state *state)
@@ -2017,20 +2030,31 @@ static game_ui *new_ui(const game_state *state)
2017 void *seed; 2030 void *seed;
2018 int seedsize; 2031 int seedsize;
2019 game_ui *ui = snew(game_ui); 2032 game_ui *ui = snew(game_ui);
2020 ui->org_x = ui->org_y = 0; 2033
2021 ui->cur_x = ui->cx = state->width / 2; 2034 ui->unlocked_loops = true;
2022 ui->cur_y = ui->cy = state->height / 2; 2035
2023 ui->cur_visible = false; 2036 if (state) {
2024 get_random_seed(&seed, &seedsize); 2037 ui->org_x = ui->org_y = 0;
2025 ui->rs = random_new(seed, seedsize); 2038 ui->cur_x = ui->cx = state->width / 2;
2026 sfree(seed); 2039 ui->cur_y = ui->cy = state->height / 2;
2040 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
2041 get_random_seed(&seed, &seedsize);
2042 ui->rs = random_new(seed, seedsize);
2043 sfree(seed);
2044#ifdef USE_DRAGGING
2045 ui->dragstartx = ui->dragstarty = ui->dragtilex = ui->dragtiley = -1;
2046#endif
2047 } else {
2048 ui->rs = NULL;
2049 }
2027 2050
2028 return ui; 2051 return ui;
2029} 2052}
2030 2053
2031static void free_ui(game_ui *ui) 2054static void free_ui(game_ui *ui)
2032{ 2055{
2033 random_free(ui->rs); 2056 if (ui->rs)
2057 random_free(ui->rs);
2034 sfree(ui); 2058 sfree(ui);
2035} 2059}
2036 2060
@@ -2045,10 +2069,45 @@ static char *encode_ui(const game_ui *ui)
2045 return dupstr(buf); 2069 return dupstr(buf);
2046} 2070}
2047 2071
2048static void decode_ui(game_ui *ui, const char *encoding) 2072static void decode_ui(game_ui *ui, const char *encoding,
2073 const game_state *state)
2049{ 2074{
2050 sscanf(encoding, "O%d,%d;C%d,%d", 2075 int org_x, org_y, cx, cy;
2051 &ui->org_x, &ui->org_y, &ui->cx, &ui->cy); 2076
2077 if (sscanf(encoding, "O%d,%d;C%d,%d", &org_x, &org_y, &cx, &cy) == 4) {
2078 if (0 <= org_x && org_x < state->width &&
2079 0 <= org_y && org_y < state->height) {
2080 ui->org_x = org_x;
2081 ui->org_y = org_y;
2082 }
2083 if (0 <= cx && cx < state->width &&
2084 0 <= cy && cy < state->height) {
2085 ui->cx = cx;
2086 ui->cy = cy;
2087 }
2088 }
2089}
2090
2091static config_item *get_prefs(game_ui *ui)
2092{
2093 config_item *ret;
2094
2095 ret = snewn(2, config_item);
2096
2097 ret[0].name = "Highlight loops involving unlocked squares";
2098 ret[0].kw = "unlocked-loops";
2099 ret[0].type = C_BOOLEAN;
2100 ret[0].u.boolean.bval = ui->unlocked_loops;
2101
2102 ret[1].name = NULL;
2103 ret[1].type = C_END;
2104
2105 return ret;
2106}
2107
2108static void set_prefs(game_ui *ui, const config_item *cfg)
2109{
2110 ui->unlocked_loops = cfg[0].u.boolean.bval;
2052} 2111}
2053 2112
2054static void game_changed_state(game_ui *ui, const game_state *oldstate, 2113static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -2056,8 +2115,19 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
2056{ 2115{
2057} 2116}
2058 2117
2118static const char *current_key_label(const game_ui *ui,
2119 const game_state *state, int button)
2120{
2121 if (tile(state, ui->cur_x, ui->cur_y) & LOCKED) {
2122 if (button == CURSOR_SELECT2) return "Unlock";
2123 } else {
2124 if (button == CURSOR_SELECT) return "Rotate";
2125 if (button == CURSOR_SELECT2) return "Lock";
2126 }
2127 return "";
2128}
2129
2059struct game_drawstate { 2130struct game_drawstate {
2060 bool started;
2061 int width, height; 2131 int width, height;
2062 int tilesize; 2132 int tilesize;
2063 unsigned long *visible, *to_draw; 2133 unsigned long *visible, *to_draw;
@@ -2078,7 +2148,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2078 MOVE_ORIGIN, MOVE_SOURCE, MOVE_ORIGIN_AND_SOURCE, MOVE_CURSOR 2148 MOVE_ORIGIN, MOVE_SOURCE, MOVE_ORIGIN_AND_SOURCE, MOVE_CURSOR
2079 } action; 2149 } action;
2080 2150
2081 button &= ~MOD_MASK; 2151 button = STRIP_BUTTON_MODIFIERS(button);
2082 nullret = NULL; 2152 nullret = NULL;
2083 action = NONE; 2153 action = NONE;
2084 2154
@@ -2094,7 +2164,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2094 2164
2095 if (ui->cur_visible) { 2165 if (ui->cur_visible) {
2096 ui->cur_visible = false; 2166 ui->cur_visible = false;
2097 nullret = UI_UPDATE; 2167 nullret = MOVE_UI_UPDATE;
2098 } 2168 }
2099 2169
2100 /* 2170 /*
@@ -2102,12 +2172,22 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2102 */ 2172 */
2103 x -= WINDOW_OFFSET + LINE_THICK; 2173 x -= WINDOW_OFFSET + LINE_THICK;
2104 y -= WINDOW_OFFSET + LINE_THICK; 2174 y -= WINDOW_OFFSET + LINE_THICK;
2105 if (x < 0 || y < 0)
2106 return nullret;
2107 tx = x / TILE_SIZE; 2175 tx = x / TILE_SIZE;
2108 ty = y / TILE_SIZE; 2176 ty = y / TILE_SIZE;
2109 if (tx >= state->width || ty >= state->height) 2177 if (x < 0 || y < 0 || tx >= state->width || ty >= state->height) {
2178#ifdef USE_DRAGGING
2179 if (IS_MOUSE_DOWN(button)) {
2180 ui->dragstartx = ui->dragstarty = ui->dragtilex = ui->dragtiley = -1;
2181 return nullret;
2182 }
2183 /*
2184 * else: Despite the mouse moving off the grid, let drags and releases
2185 * continue to manipulate the tile they started from.
2186 */
2187#else
2110 return nullret; 2188 return nullret;
2189#endif
2190 }
2111 /* Transform from physical to game coords */ 2191 /* Transform from physical to game coords */
2112 tx = (tx + ui->org_x) % state->width; 2192 tx = (tx + ui->org_x) % state->width;
2113 ty = (ty + ui->org_y) % state->height; 2193 ty = (ty + ui->org_y) % state->height;
@@ -2145,6 +2225,9 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2145 || button == RIGHT_DRAG 2225 || button == RIGHT_DRAG
2146#endif 2226#endif
2147 ) { 2227 ) {
2228 if (ui->dragtilex < 0)
2229 return nullret;
2230
2148 /* 2231 /*
2149 * Find the new drag point and see if it necessitates a 2232 * Find the new drag point and see if it necessitates a
2150 * rotation. 2233 * rotation.
@@ -2198,7 +2281,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2198 || button == RIGHT_RELEASE 2281 || button == RIGHT_RELEASE
2199#endif 2282#endif
2200 ) { 2283 ) {
2201 if (!ui->dragged) { 2284 if (!ui->dragged && ui->dragtilex >= 0) {
2202 /* 2285 /*
2203 * There was a click but no perceptible drag: 2286 * There was a click but no perceptible drag:
2204 * revert to single-click behaviour. 2287 * revert to single-click behaviour.
@@ -2334,7 +2417,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2334 OFFSET(ui->cur_x, ui->cur_y, ui->cur_x, ui->cur_y, dir, state); 2417 OFFSET(ui->cur_x, ui->cur_y, ui->cur_x, ui->cur_y, dir, state);
2335 ui->cur_visible = true; 2418 ui->cur_visible = true;
2336 } 2419 }
2337 return UI_UPDATE; 2420 return MOVE_UI_UPDATE;
2338 } else { 2421 } else {
2339 return NULL; 2422 return NULL;
2340 } 2423 }
@@ -2444,7 +2527,6 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
2444 game_drawstate *ds = snew(game_drawstate); 2527 game_drawstate *ds = snew(game_drawstate);
2445 int i, ncells; 2528 int i, ncells;
2446 2529
2447 ds->started = false;
2448 ds->width = state->width; 2530 ds->width = state->width;
2449 ds->height = state->height; 2531 ds->height = state->height;
2450 ncells = (state->width+2) * (state->height+2); 2532 ncells = (state->width+2) * (state->height+2);
@@ -2464,11 +2546,12 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
2464static void game_free_drawstate(drawing *dr, game_drawstate *ds) 2546static void game_free_drawstate(drawing *dr, game_drawstate *ds)
2465{ 2547{
2466 sfree(ds->visible); 2548 sfree(ds->visible);
2549 sfree(ds->to_draw);
2467 sfree(ds); 2550 sfree(ds);
2468} 2551}
2469 2552
2470static void game_compute_size(const game_params *params, int tilesize, 2553static void game_compute_size(const game_params *params, int tilesize,
2471 int *x, int *y) 2554 const game_ui *ui, int *x, int *y)
2472{ 2555{
2473 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2556 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2474 struct { int tilesize; } ads, *ds = &ads; 2557 struct { int tilesize; } ads, *ds = &ads;
@@ -2605,8 +2688,8 @@ static void draw_wires(drawing *dr, int cx, int cy, int radius,
2605 2688
2606 for (i = 0; i < npoints; i++) { 2689 for (i = 0; i < npoints; i++) {
2607 rotated_coords(&xf, &yf, matrix, cx, cy, fpoints[2*i], fpoints[2*i+1]); 2690 rotated_coords(&xf, &yf, matrix, cx, cy, fpoints[2*i], fpoints[2*i+1]);
2608 points[2*i] = 0.5 + xf; 2691 points[2*i] = 0.5F + xf;
2609 points[2*i+1] = 0.5 + yf; 2692 points[2*i+1] = 0.5F + yf;
2610 } 2693 }
2611 2694
2612 draw_polygon(dr, points, npoints, colour, colour); 2695 draw_polygon(dr, points, npoints, colour, colour);
@@ -2746,8 +2829,8 @@ static void draw_tile(drawing *dr, game_drawstate *ds, int x, int y,
2746 * rotated by an arbitrary angle about that centre point. 2829 * rotated by an arbitrary angle about that centre point.
2747 */ 2830 */
2748 if (tile & TILE_ROTATING) { 2831 if (tile & TILE_ROTATING) {
2749 matrix[0] = (float)cos(angle * PI / 180.0); 2832 matrix[0] = (float)cos(angle * (float)PI / 180.0F);
2750 matrix[2] = (float)sin(angle * PI / 180.0); 2833 matrix[2] = (float)sin(angle * (float)PI / 180.0F);
2751 } else { 2834 } else {
2752 matrix[0] = 1.0F; 2835 matrix[0] = 1.0F;
2753 matrix[2] = 0.0F; 2836 matrix[2] = 0.0F;
@@ -2786,8 +2869,8 @@ static void draw_tile(drawing *dr, game_drawstate *ds, int x, int y,
2786 float x, y; 2869 float x, y;
2787 rotated_coords(&x, &y, matrix, cx, cy, 2870 rotated_coords(&x, &y, matrix, cx, cy,
2788 boxr * points[i], boxr * points[i+1]); 2871 boxr * points[i], boxr * points[i+1]);
2789 points[i] = x + 0.5; 2872 points[i] = x + 0.5F;
2790 points[i+1] = y + 0.5; 2873 points[i+1] = y + 0.5F;
2791 } 2874 }
2792 2875
2793 draw_polygon(dr, points, 4, col, COL_WIRE); 2876 draw_polygon(dr, points, 4, col, COL_WIRE);
@@ -2841,23 +2924,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2841 int *loops; 2924 int *loops;
2842 float angle = 0.0; 2925 float angle = 0.0;
2843 2926
2844 /*
2845 * Clear the screen on our first call.
2846 */
2847 if (!ds->started) {
2848 int w, h;
2849 game_params params;
2850
2851 ds->started = true;
2852
2853 params.width = ds->width;
2854 params.height = ds->height;
2855 game_compute_size(&params, TILE_SIZE, &w, &h);
2856
2857 draw_rect(dr, 0, 0, w, h, COL_BACKGROUND);
2858 draw_update(dr, 0, 0, w, h);
2859 }
2860
2861 tx = ty = -1; 2927 tx = ty = -1;
2862 last_rotate_dir = dir==-1 ? oldstate->last_rotate_dir : 2928 last_rotate_dir = dir==-1 ? oldstate->last_rotate_dir :
2863 state->last_rotate_dir; 2929 state->last_rotate_dir;
@@ -2888,7 +2954,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2888 * of barriers. 2954 * of barriers.
2889 */ 2955 */
2890 active = compute_active(state, ui->cx, ui->cy); 2956 active = compute_active(state, ui->cx, ui->cy);
2891 loops = compute_loops(state); 2957 loops = compute_loops(state, ui->unlocked_loops);
2892 2958
2893 for (dy = -1; dy < ds->height+1; dy++) { 2959 for (dy = -1; dy < ds->height+1; dy++) {
2894 for (dx = -1; dx < ds->width+1; dx++) { 2960 for (dx = -1; dx < ds->width+1; dx++) {
@@ -3109,19 +3175,15 @@ static int game_status(const game_state *state)
3109 return state->completed ? +1 : 0; 3175 return state->completed ? +1 : 0;
3110} 3176}
3111 3177
3112static bool game_timing_state(const game_state *state, game_ui *ui) 3178static void game_print_size(const game_params *params, const game_ui *ui,
3113{ 3179 float *x, float *y)
3114 return true;
3115}
3116
3117static void game_print_size(const game_params *params, float *x, float *y)
3118{ 3180{
3119 int pw, ph; 3181 int pw, ph;
3120 3182
3121 /* 3183 /*
3122 * I'll use 8mm squares by default. 3184 * I'll use 8mm squares by default.
3123 */ 3185 */
3124 game_compute_size(params, 800, &pw, &ph); 3186 game_compute_size(params, 800, ui, &pw, &ph);
3125 *x = pw / 100.0F; 3187 *x = pw / 100.0F;
3126 *y = ph / 100.0F; 3188 *y = ph / 100.0F;
3127} 3189}
@@ -3172,7 +3234,8 @@ static void draw_diagram(drawing *dr, game_drawstate *ds, int x, int y,
3172 } 3234 }
3173} 3235}
3174 3236
3175static void game_print(drawing *dr, const game_state *state, int tilesize) 3237static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
3238 int tilesize)
3176{ 3239{
3177 int w = state->width, h = state->height; 3240 int w = state->width, h = state->height;
3178 int ink = print_mono_colour(dr, 0); 3241 int ink = print_mono_colour(dr, 0);
@@ -3269,13 +3332,15 @@ const struct game thegame = {
3269 dup_game, 3332 dup_game,
3270 free_game, 3333 free_game,
3271 true, solve_game, 3334 true, solve_game,
3272 false, game_can_format_as_text_now, game_text_format, 3335 false, NULL, NULL, /* can_format_as_text_now, text_format */
3336 get_prefs, set_prefs,
3273 new_ui, 3337 new_ui,
3274 free_ui, 3338 free_ui,
3275 encode_ui, 3339 encode_ui,
3276 decode_ui, 3340 decode_ui,
3277 NULL, /* game_request_keys */ 3341 NULL, /* game_request_keys */
3278 game_changed_state, 3342 game_changed_state,
3343 current_key_label,
3279 interpret_move, 3344 interpret_move,
3280 execute_move, 3345 execute_move,
3281 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 3346 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -3289,6 +3354,6 @@ const struct game thegame = {
3289 game_status, 3354 game_status,
3290 true, false, game_print_size, game_print, 3355 true, false, game_print_size, game_print,
3291 true, /* wants_statusbar */ 3356 true, /* wants_statusbar */
3292 false, game_timing_state, 3357 false, NULL, /* timing_state */
3293 0, /* flags */ 3358 0, /* flags */
3294}; 3359};
diff --git a/apps/plugins/puzzles/src/netslide.R b/apps/plugins/puzzles/src/netslide.R
deleted file mode 100644
index ecfe7c3df8..0000000000
--- a/apps/plugins/puzzles/src/netslide.R
+++ /dev/null
@@ -1,21 +0,0 @@
1# -*- makefile -*-
2
3NETSLIDE_EXTRA = tree234
4
5netslide : [X] GTK COMMON netslide NETSLIDE_EXTRA netslide-icon|no-icon
6
7netslide : [G] WINDOWS COMMON netslide NETSLIDE_EXTRA netslide.res|noicon.res
8
9ALL += netslide[COMBINED] NETSLIDE_EXTRA
10
11!begin am gtk
12GAMES += netslide
13!end
14
15!begin >list.c
16 A(netslide) \
17!end
18
19!begin >gamedesc.txt
20netslide:netslide.exe:Netslide:Toroidal sliding network puzzle:Slide a row at a time to reassemble the network.
21!end
diff --git a/apps/plugins/puzzles/src/netslide.c b/apps/plugins/puzzles/src/netslide.c
index 14af2a689d..4e6e82b39f 100644
--- a/apps/plugins/puzzles/src/netslide.c
+++ b/apps/plugins/puzzles/src/netslide.c
@@ -8,7 +8,12 @@
8#include <string.h> 8#include <string.h>
9#include <assert.h> 9#include <assert.h>
10#include <ctype.h> 10#include <ctype.h>
11#include <math.h> 11#include <limits.h>
12#ifdef NO_TGMATH_H
13# include <math.h>
14#else
15# include <tgmath.h>
16#endif
12 17
13#include "puzzles.h" 18#include "puzzles.h"
14#include "tree234.h" 19#include "tree234.h"
@@ -242,10 +247,7 @@ static char *encode_params(const game_params *params, bool full)
242 if (params->wrapping) 247 if (params->wrapping)
243 ret[len++] = 'w'; 248 ret[len++] = 'w';
244 if (full && params->barrier_probability) 249 if (full && params->barrier_probability)
245 { 250 len += sprintf(ret+len, "b%g", params->barrier_probability);
246 len += sprintf(ret+len, "b");
247 len += ftoa(ret + len, params->barrier_probability);
248 }
249 /* Shuffle limit is part of the limited parameters, because we have to 251 /* Shuffle limit is part of the limited parameters, because we have to
250 * provide the target move count. */ 252 * provide the target move count. */
251 if (params->movetarget) 253 if (params->movetarget)
@@ -279,7 +281,7 @@ static config_item *game_configure(const game_params *params)
279 281
280 ret[3].name = "Barrier probability"; 282 ret[3].name = "Barrier probability";
281 ret[3].type = C_STRING; 283 ret[3].type = C_STRING;
282 ftoa(buf, params->barrier_probability); 284 sprintf(buf, "%g", params->barrier_probability);
283 ret[3].u.string.sval = dupstr(buf); 285 ret[3].u.string.sval = dupstr(buf);
284 286
285 ret[4].name = "Number of shuffling moves"; 287 ret[4].name = "Number of shuffling moves";
@@ -310,6 +312,8 @@ static const char *validate_params(const game_params *params, bool full)
310{ 312{
311 if (params->width <= 1 || params->height <= 1) 313 if (params->width <= 1 || params->height <= 1)
312 return "Width and height must both be greater than one"; 314 return "Width and height must both be greater than one";
315 if (params->width > INT_MAX / params->height)
316 return "Width times height must not be unreasonably large";
313 if (params->barrier_probability < 0) 317 if (params->barrier_probability < 0)
314 return "Barrier probability may not be negative"; 318 return "Barrier probability may not be negative";
315 if (params->barrier_probability > 1) 319 if (params->barrier_probability > 1)
@@ -895,16 +899,6 @@ static char *solve_game(const game_state *state, const game_state *currstate,
895 return dupstr(aux); 899 return dupstr(aux);
896} 900}
897 901
898static bool game_can_format_as_text_now(const game_params *params)
899{
900 return true;
901}
902
903static char *game_text_format(const game_state *state)
904{
905 return NULL;
906}
907
908/* ---------------------------------------------------------------------- 902/* ----------------------------------------------------------------------
909 * Utility routine. 903 * Utility routine.
910 */ 904 */
@@ -981,7 +975,7 @@ static game_ui *new_ui(const game_state *state)
981 game_ui *ui = snew(game_ui); 975 game_ui *ui = snew(game_ui);
982 ui->cur_x = 0; 976 ui->cur_x = 0;
983 ui->cur_y = -1; 977 ui->cur_y = -1;
984 ui->cur_visible = false; 978 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
985 979
986 return ui; 980 return ui;
987} 981}
@@ -991,15 +985,6 @@ static void free_ui(game_ui *ui)
991 sfree(ui); 985 sfree(ui);
992} 986}
993 987
994static char *encode_ui(const game_ui *ui)
995{
996 return NULL;
997}
998
999static void decode_ui(game_ui *ui, const char *encoding)
1000{
1001}
1002
1003/* ---------------------------------------------------------------------- 988/* ----------------------------------------------------------------------
1004 * Process a move. 989 * Process a move.
1005 */ 990 */
@@ -1009,7 +994,9 @@ static void slide_row_int(int w, int h, unsigned char *tiles, int dir, int row)
1009 int x = dir > 0 ? -1 : w; 994 int x = dir > 0 ? -1 : w;
1010 int tx = x + dir; 995 int tx = x + dir;
1011 int n = w - 1; 996 int n = w - 1;
1012 unsigned char endtile = tiles[row * w + tx]; 997 unsigned char endtile;
998 assert(0 <= tx && tx < w);
999 endtile = tiles[row * w + tx];
1013 do { 1000 do {
1014 x = tx; 1001 x = tx;
1015 tx = (x + dir + w) % w; 1002 tx = (x + dir + w) % w;
@@ -1023,7 +1010,9 @@ static void slide_col_int(int w, int h, unsigned char *tiles, int dir, int col)
1023 int y = dir > 0 ? -1 : h; 1010 int y = dir > 0 ? -1 : h;
1024 int ty = y + dir; 1011 int ty = y + dir;
1025 int n = h - 1; 1012 int n = h - 1;
1026 unsigned char endtile = tiles[ty * w + col]; 1013 unsigned char endtile;
1014 assert(0 <= ty && ty < h);
1015 endtile = tiles[ty * w + col];
1027 do { 1016 do {
1028 y = ty; 1017 y = ty;
1029 ty = (y + dir + h) % h; 1018 ty = (y + dir + h) % h;
@@ -1055,6 +1044,14 @@ struct game_drawstate {
1055 int cur_x, cur_y; 1044 int cur_x, cur_y;
1056}; 1045};
1057 1046
1047static const char *current_key_label(const game_ui *ui,
1048 const game_state *state, int button)
1049{
1050 if (IS_CURSOR_SELECT(button) && ui->cur_visible)
1051 return "Slide";
1052 return "";
1053}
1054
1058static char *interpret_move(const game_state *state, game_ui *ui, 1055static char *interpret_move(const game_state *state, game_ui *ui,
1059 const game_drawstate *ds, 1056 const game_drawstate *ds,
1060 int x, int y, int button) 1057 int x, int y, int button)
@@ -1063,7 +1060,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1063 int dx, dy; 1060 int dx, dy;
1064 char buf[80]; 1061 char buf[80];
1065 1062
1066 button &= ~MOD_MASK; 1063 button = STRIP_BUTTON_MODIFIERS(button);
1067 1064
1068 if (IS_CURSOR_MOVE(button)) { 1065 if (IS_CURSOR_MOVE(button)) {
1069 int cpos, diff = 0; 1066 int cpos, diff = 0;
@@ -1078,7 +1075,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1078 } 1075 }
1079 1076
1080 ui->cur_visible = true; 1077 ui->cur_visible = true;
1081 return UI_UPDATE; 1078 return MOVE_UI_UPDATE;
1082 } 1079 }
1083 1080
1084 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { 1081 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
@@ -1092,7 +1089,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1092 } else { 1089 } else {
1093 /* 'click' when cursor is invisible just makes cursor visible. */ 1090 /* 'click' when cursor is invisible just makes cursor visible. */
1094 ui->cur_visible = true; 1091 ui->cur_visible = true;
1095 return UI_UPDATE; 1092 return MOVE_UI_UPDATE;
1096 } 1093 }
1097 } else 1094 } else
1098 return NULL; 1095 return NULL;
@@ -1136,7 +1133,9 @@ static game_state *execute_move(const game_state *from, const char *move)
1136 1133
1137 if ((move[0] == 'C' || move[0] == 'R') && 1134 if ((move[0] == 'C' || move[0] == 'R') &&
1138 sscanf(move+1, "%d,%d", &c, &d) == 2 && 1135 sscanf(move+1, "%d,%d", &c, &d) == 2 &&
1139 c >= 0 && c < (move[0] == 'C' ? from->width : from->height)) { 1136 c >= 0 && c < (move[0] == 'C' ? from->width : from->height) &&
1137 d <= (move[0] == 'C' ? from->height : from->width) &&
1138 d >= -(move[0] == 'C' ? from->height : from->width) && d != 0) {
1140 col = (move[0] == 'C'); 1139 col = (move[0] == 'C');
1141 } else if (move[0] == 'S' && 1140 } else if (move[0] == 'S' &&
1142 strlen(move) == from->width * from->height + 1) { 1141 strlen(move) == from->width * from->height + 1) {
@@ -1226,7 +1225,7 @@ static void game_free_drawstate(drawing *dr, game_drawstate *ds)
1226} 1225}
1227 1226
1228static void game_compute_size(const game_params *params, int tilesize, 1227static void game_compute_size(const game_params *params, int tilesize,
1229 int *x, int *y) 1228 const game_ui *ui, int *x, int *y)
1230{ 1229{
1231 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 1230 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1232 struct { int tilesize; } ads, *ds = &ads; 1231 struct { int tilesize; } ads, *ds = &ads;
@@ -1490,7 +1489,7 @@ static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state,
1490 vx = (dy ? 1 : 0); 1489 vx = (dy ? 1 : 0);
1491 vy = (dx ? 1 : 0); 1490 vy = (dx ? 1 : 0);
1492 1491
1493 if (xshift == 0.0 && yshift == 0.0 && (tile & dir)) { 1492 if (xshift == 0.0F && yshift == 0.0F && (tile & dir)) {
1494 /* 1493 /*
1495 * If we are fully connected to the other tile, we must 1494 * If we are fully connected to the other tile, we must
1496 * draw right across the tile border. (We can use our 1495 * draw right across the tile border. (We can use our
@@ -1594,22 +1593,13 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1594 int cur_x = -1, cur_y = -1; 1593 int cur_x = -1, cur_y = -1;
1595 1594
1596 /* 1595 /*
1597 * Clear the screen and draw the exterior barrier lines if this 1596 * Draw the exterior barrier lines if this is our first call.
1598 * is our first call.
1599 */ 1597 */
1600 if (!ds->started) { 1598 if (!ds->started) {
1601 int phase; 1599 int phase;
1602 1600
1603 ds->started = true; 1601 ds->started = true;
1604 1602
1605 draw_rect(dr, 0, 0,
1606 BORDER * 2 + WINDOW_OFFSET * 2 + TILE_SIZE * state->width + TILE_BORDER,
1607 BORDER * 2 + WINDOW_OFFSET * 2 + TILE_SIZE * state->height + TILE_BORDER,
1608 COL_BACKGROUND);
1609 draw_update(dr, 0, 0,
1610 BORDER * 2 + WINDOW_OFFSET*2 + TILE_SIZE*state->width + TILE_BORDER,
1611 BORDER * 2 + WINDOW_OFFSET*2 + TILE_SIZE*state->height + TILE_BORDER);
1612
1613 for (phase = 0; phase < 2; phase++) { 1603 for (phase = 0; phase < 2; phase++) {
1614 1604
1615 for (x = 0; x < ds->width; x++) { 1605 for (x = 0; x < ds->width; x++) {
@@ -1703,7 +1693,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1703 /* 1693 /*
1704 * Draw any tile which differs from the way it was last drawn. 1694 * Draw any tile which differs from the way it was last drawn.
1705 */ 1695 */
1706 if (xshift != 0.0 || yshift != 0.0) { 1696 if (xshift != 0.0F || yshift != 0.0F) {
1707 active = compute_active(state, 1697 active = compute_active(state,
1708 state->last_move_row, state->last_move_col); 1698 state->last_move_row, state->last_move_col);
1709 } else { 1699 } else {
@@ -1849,19 +1839,6 @@ static int game_status(const game_state *state)
1849 return state->completed ? +1 : 0; 1839 return state->completed ? +1 : 0;
1850} 1840}
1851 1841
1852static bool game_timing_state(const game_state *state, game_ui *ui)
1853{
1854 return false;
1855}
1856
1857static void game_print_size(const game_params *params, float *x, float *y)
1858{
1859}
1860
1861static void game_print(drawing *dr, const game_state *state, int tilesize)
1862{
1863}
1864
1865#ifdef COMBINED 1842#ifdef COMBINED
1866#define thegame netslide 1843#define thegame netslide
1867#endif 1844#endif
@@ -1882,13 +1859,15 @@ const struct game thegame = {
1882 dup_game, 1859 dup_game,
1883 free_game, 1860 free_game,
1884 true, solve_game, 1861 true, solve_game,
1885 false, game_can_format_as_text_now, game_text_format, 1862 false, NULL, NULL, /* can_format_as_text_now, text_format */
1863 NULL, NULL, /* get_prefs, set_prefs */
1886 new_ui, 1864 new_ui,
1887 free_ui, 1865 free_ui,
1888 encode_ui, 1866 NULL, /* encode_ui */
1889 decode_ui, 1867 NULL, /* decode_ui */
1890 NULL, /* game_request_keys */ 1868 NULL, /* game_request_keys */
1891 game_changed_state, 1869 game_changed_state,
1870 current_key_label,
1892 interpret_move, 1871 interpret_move,
1893 execute_move, 1872 execute_move,
1894 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 1873 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -1900,9 +1879,9 @@ const struct game thegame = {
1900 game_flash_length, 1879 game_flash_length,
1901 game_get_cursor_location, 1880 game_get_cursor_location,
1902 game_status, 1881 game_status,
1903 false, false, game_print_size, game_print, 1882 false, false, NULL, NULL, /* print_size, print */
1904 true, /* wants_statusbar */ 1883 true, /* wants_statusbar */
1905 false, game_timing_state, 1884 false, NULL, /* timing_state */
1906 0, /* flags */ 1885 0, /* flags */
1907}; 1886};
1908 1887
diff --git a/apps/plugins/puzzles/src/no-icon.c b/apps/plugins/puzzles/src/no-icon.c
index 114b2c57c7..5091dca426 100644
--- a/apps/plugins/puzzles/src/no-icon.c
+++ b/apps/plugins/puzzles/src/no-icon.c
@@ -4,5 +4,7 @@
4 * `icons' subdirectory, when they're absent. 4 * `icons' subdirectory, when they're absent.
5 */ 5 */
6 6
7#include "gtk.h"
8
7const char *const *const xpm_icons[] = { 0 }; 9const char *const *const xpm_icons[] = { 0 };
8const int n_xpm_icons = 0; 10const int n_xpm_icons = 0;
diff --git a/apps/plugins/puzzles/src/nullfe.c b/apps/plugins/puzzles/src/nullfe.c
index 7cba4e0c23..9a57832b6e 100644
--- a/apps/plugins/puzzles/src/nullfe.c
+++ b/apps/plugins/puzzles/src/nullfe.c
@@ -9,13 +9,21 @@
9#include "puzzles.h" 9#include "puzzles.h"
10 10
11void frontend_default_colour(frontend *fe, float *output) {} 11void frontend_default_colour(frontend *fe, float *output) {}
12void get_random_seed(void **randseed, int *randseedsize)
13{ char *c = snewn(1, char); *c = 0; *randseed = c; *randseedsize = 1; }
14void deactivate_timer(frontend *fe) {}
15void activate_timer(frontend *fe) {}
16struct drawing { char dummy; };
17drawing *drawing_new(const drawing_api *api, midend *me, void *handle)
18{ return snew(drawing); }
19void drawing_free(drawing *dr) { sfree(dr); }
12void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, 20void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize,
13 int align, int colour, const char *text) {} 21 int align, int colour, const char *text) {}
14void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) {} 22void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) {}
15void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) {} 23void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) {}
16void draw_thick_line(drawing *dr, float thickness, 24void draw_thick_line(drawing *dr, float thickness,
17 float x1, float y1, float x2, float y2, int colour) {} 25 float x1, float y1, float x2, float y2, int colour) {}
18void draw_polygon(drawing *dr, int *coords, int npoints, 26void draw_polygon(drawing *dr, const int *coords, int npoints,
19 int fillcolour, int outlinecolour) {} 27 int fillcolour, int outlinecolour) {}
20void draw_circle(drawing *dr, int cx, int cy, int radius, 28void draw_circle(drawing *dr, int cx, int cy, int radius,
21 int fillcolour, int outlinecolour) {} 29 int fillcolour, int outlinecolour) {}
@@ -26,8 +34,9 @@ void unclip(drawing *dr) {}
26void start_draw(drawing *dr) {} 34void start_draw(drawing *dr) {}
27void draw_update(drawing *dr, int x, int y, int w, int h) {} 35void draw_update(drawing *dr, int x, int y, int w, int h) {}
28void end_draw(drawing *dr) {} 36void end_draw(drawing *dr) {}
29blitter *blitter_new(drawing *dr, int w, int h) {return NULL;} 37struct blitter { char dummy; };
30void blitter_free(drawing *dr, blitter *bl) {} 38blitter *blitter_new(drawing *dr, int w, int h) { return snew(blitter); }
39void blitter_free(drawing *dr, blitter *bl) { sfree(bl); }
31void blitter_save(drawing *dr, blitter *bl, int x, int y) {} 40void blitter_save(drawing *dr, blitter *bl, int x, int y) {}
32void blitter_load(drawing *dr, blitter *bl, int x, int y) {} 41void blitter_load(drawing *dr, blitter *bl, int x, int y) {}
33int print_mono_colour(drawing *dr, int grey) { return 0; } 42int print_mono_colour(drawing *dr, int grey) { return 0; }
@@ -41,14 +50,9 @@ int print_rgb_hatched_colour(drawing *dr, float r, float g, float b, int hatch)
41{ return 0; } 50{ return 0; }
42void print_line_width(drawing *dr, int width) {} 51void print_line_width(drawing *dr, int width) {}
43void print_line_dotted(drawing *dr, bool dotted) {} 52void print_line_dotted(drawing *dr, bool dotted) {}
44void midend_supersede_game_desc(midend *me, const char *desc,
45 const char *privdesc) {}
46void status_bar(drawing *dr, const char *text) {} 53void status_bar(drawing *dr, const char *text) {}
47struct preset_menu *preset_menu_new(void) {return NULL;} 54void document_add_puzzle(document *doc, const game *game, game_params *par,
48struct preset_menu *preset_menu_add_submenu(struct preset_menu *parent, 55 game_ui *ui, game_state *st, game_state *st2) {}
49 char *title) {return NULL;}
50void preset_menu_add_preset(struct preset_menu *parent,
51 char *title, game_params *params) {}
52 56
53void fatal(const char *fmt, ...) 57void fatal(const char *fmt, ...)
54{ 58{
diff --git a/apps/plugins/puzzles/src/nullgame.R b/apps/plugins/puzzles/src/nullgame.R
deleted file mode 100644
index 41bdb85d57..0000000000
--- a/apps/plugins/puzzles/src/nullgame.R
+++ /dev/null
@@ -1,12 +0,0 @@
1# -*- makefile -*-
2
3# The `nullgame' source file is a largely blank one, which contains
4# all the correct function definitions to compile and link, but
5# which defines the null game in which nothing is ever drawn and
6# there are no valid moves. Its main purpose is to act as a
7# template for writing new game definition source files. I include
8# it in the Makefile because it will be worse than useless if it
9# ever fails to compile, so it's important that it should actually
10# be built on a regular basis.
11nullgame : [X] GTK COMMON nullgame nullgame-icon|no-icon
12nullgame : [G] WINDOWS COMMON nullgame nullgame.res|noicon.res
diff --git a/apps/plugins/puzzles/src/nullgame.c b/apps/plugins/puzzles/src/nullgame.c
index d923bc8710..c1c2ed18fd 100644
--- a/apps/plugins/puzzles/src/nullgame.c
+++ b/apps/plugins/puzzles/src/nullgame.c
@@ -16,7 +16,11 @@
16#include <string.h> 16#include <string.h>
17#include <assert.h> 17#include <assert.h>
18#include <ctype.h> 18#include <ctype.h>
19#include <math.h> 19#ifdef NO_TGMATH_H
20# include <math.h>
21#else
22# include <tgmath.h>
23#endif
20 24
21#include "puzzles.h" 25#include "puzzles.h"
22 26
@@ -68,16 +72,6 @@ static char *encode_params(const game_params *params, bool full)
68 return dupstr("FIXME"); 72 return dupstr("FIXME");
69} 73}
70 74
71static config_item *game_configure(const game_params *params)
72{
73 return NULL;
74}
75
76static game_params *custom_params(const config_item *cfg)
77{
78 return NULL;
79}
80
81static const char *validate_params(const game_params *params, bool full) 75static const char *validate_params(const game_params *params, bool full)
82{ 76{
83 return NULL; 77 return NULL;
@@ -118,22 +112,6 @@ static void free_game(game_state *state)
118 sfree(state); 112 sfree(state);
119} 113}
120 114
121static char *solve_game(const game_state *state, const game_state *currstate,
122 const char *aux, const char **error)
123{
124 return NULL;
125}
126
127static bool game_can_format_as_text_now(const game_params *params)
128{
129 return true;
130}
131
132static char *game_text_format(const game_state *state)
133{
134 return NULL;
135}
136
137static game_ui *new_ui(const game_state *state) 115static game_ui *new_ui(const game_state *state)
138{ 116{
139 return NULL; 117 return NULL;
@@ -143,15 +121,6 @@ static void free_ui(game_ui *ui)
143{ 121{
144} 122}
145 123
146static char *encode_ui(const game_ui *ui)
147{
148 return NULL;
149}
150
151static void decode_ui(game_ui *ui, const char *encoding)
152{
153}
154
155static void game_changed_state(game_ui *ui, const game_state *oldstate, 124static void game_changed_state(game_ui *ui, const game_state *oldstate,
156 const game_state *newstate) 125 const game_state *newstate)
157{ 126{
@@ -179,7 +148,7 @@ static game_state *execute_move(const game_state *state, const char *move)
179 */ 148 */
180 149
181static void game_compute_size(const game_params *params, int tilesize, 150static void game_compute_size(const game_params *params, int tilesize,
182 int *x, int *y) 151 const game_ui *ui, int *x, int *y)
183{ 152{
184 *x = *y = 10 * tilesize; /* FIXME */ 153 *x = *y = 10 * tilesize; /* FIXME */
185} 154}
@@ -220,14 +189,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
220 int dir, const game_ui *ui, 189 int dir, const game_ui *ui,
221 float animtime, float flashtime) 190 float animtime, float flashtime)
222{ 191{
223 /*
224 * The initial contents of the window are not guaranteed and
225 * can vary with front ends. To be on the safe side, all games
226 * should start by drawing a big background-colour rectangle
227 * covering the whole window.
228 */
229 draw_rect(dr, 0, 0, 10*ds->tilesize, 10*ds->tilesize, COL_BACKGROUND);
230 draw_update(dr, 0, 0, 10*ds->tilesize, 10*ds->tilesize);
231} 192}
232 193
233static float game_anim_length(const game_state *oldstate, 194static float game_anim_length(const game_state *oldstate,
@@ -255,19 +216,6 @@ static int game_status(const game_state *state)
255 return 0; 216 return 0;
256} 217}
257 218
258static bool game_timing_state(const game_state *state, game_ui *ui)
259{
260 return true;
261}
262
263static void game_print_size(const game_params *params, float *x, float *y)
264{
265}
266
267static void game_print(drawing *dr, const game_state *state, int tilesize)
268{
269}
270
271#ifdef COMBINED 219#ifdef COMBINED
272#define thegame nullgame 220#define thegame nullgame
273#endif 221#endif
@@ -280,21 +228,23 @@ const struct game thegame = {
280 encode_params, 228 encode_params,
281 free_params, 229 free_params,
282 dup_params, 230 dup_params,
283 false, game_configure, custom_params, 231 false, NULL, NULL, /* configure, custom_params */
284 validate_params, 232 validate_params,
285 new_game_desc, 233 new_game_desc,
286 validate_desc, 234 validate_desc,
287 new_game, 235 new_game,
288 dup_game, 236 dup_game,
289 free_game, 237 free_game,
290 false, solve_game, 238 false, NULL, /* solve */
291 false, game_can_format_as_text_now, game_text_format, 239 false, NULL, NULL, /* can_format_as_text_now, text_format */
240 NULL, NULL, /* get_prefs, set_prefs */
292 new_ui, 241 new_ui,
293 free_ui, 242 free_ui,
294 encode_ui, 243 NULL, /* encode_ui */
295 decode_ui, 244 NULL, /* decode_ui */
296 NULL, /* game_request_keys */ 245 NULL, /* game_request_keys */
297 game_changed_state, 246 game_changed_state,
247 NULL, /* current_key_label */
298 interpret_move, 248 interpret_move,
299 execute_move, 249 execute_move,
300 20 /* FIXME */, game_compute_size, game_set_size, 250 20 /* FIXME */, game_compute_size, game_set_size,
@@ -306,8 +256,8 @@ const struct game thegame = {
306 game_flash_length, 256 game_flash_length,
307 game_get_cursor_location, 257 game_get_cursor_location,
308 game_status, 258 game_status,
309 false, false, game_print_size, game_print, 259 false, false, NULL, NULL, /* print_size, print */
310 false, /* wants_statusbar */ 260 false, /* wants_statusbar */
311 false, game_timing_state, 261 false, NULL, /* timing_state */
312 0, /* flags */ 262 0, /* flags */
313}; 263};
diff --git a/apps/plugins/puzzles/src/obfusc.c b/apps/plugins/puzzles/src/obfusc.c
deleted file mode 100644
index c62189c3ad..0000000000
--- a/apps/plugins/puzzles/src/obfusc.c
+++ /dev/null
@@ -1,130 +0,0 @@
1/*
2 * Stand-alone tool to access the Puzzles obfuscation algorithm.
3 *
4 * To deobfuscate, use "obfusc -d":
5 *
6 * obfusc -d reads binary data from stdin, writes to stdout
7 * obfusc -d <hex string> works on the given hex string instead of stdin
8 * obfusc -d -h writes a hex string instead of binary to stdout
9 *
10 * To obfuscate, "obfusc -e":
11 *
12 * obfusc -e reads binary from stdin, writes hex to stdout
13 * obfusc -e <hex string> works on the given hex string instead of stdin
14 * obfusc -e -b writes binary instead of text to stdout
15 *
16 * The default output format is hex for -e and binary for -d
17 * because that's the way obfuscation is generally used in
18 * Puzzles. Either of -b and -h can always be specified to set it
19 * explicitly.
20 *
21 * Data read from standard input is assumed always to be binary;
22 * data provided on the command line is taken to be hex.
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <stdarg.h>
28#include <string.h>
29#include <errno.h>
30
31#include "puzzles.h"
32
33int main(int argc, char **argv)
34{
35 enum { BINARY, DEFAULT, HEX } outputmode = DEFAULT;
36 char *inhex = NULL;
37 unsigned char *data;
38 int datalen;
39 enum { UNKNOWN, DECODE, ENCODE } mode = UNKNOWN;
40 bool doing_opts = true;
41
42 while (--argc > 0) {
43 char *p = *++argv;
44
45 if (doing_opts && *p == '-') {
46 if (!strcmp(p, "--")) {
47 doing_opts = 0;
48 continue;
49 }
50 p++;
51 while (*p) {
52 switch (*p) {
53 case 'e':
54 mode = ENCODE;
55 break;
56 case 'd':
57 mode = DECODE;
58 break;
59 case 'b':
60 outputmode = BINARY;
61 break;
62 case 'h':
63 outputmode = HEX;
64 break;
65 default:
66 fprintf(stderr, "obfusc: unrecognised option '-%c'\n",
67 *p);
68 return 1;
69 }
70 p++;
71 }
72 } else {
73 if (!inhex) {
74 inhex = p;
75 } else {
76 fprintf(stderr, "obfusc: expected at most one argument\n");
77 return 1;
78 }
79 }
80 }
81
82 if (mode == UNKNOWN) {
83 fprintf(stderr, "usage: obfusc < -e | -d > [ -b | -h ] [hex data]\n");
84 return 0;
85 }
86
87 if (outputmode == DEFAULT)
88 outputmode = (mode == DECODE ? BINARY : HEX);
89
90 if (inhex) {
91 datalen = strlen(inhex) / 2;
92 data = hex2bin(inhex, datalen);
93 } else {
94 int datasize = 4096;
95 datalen = 0;
96 data = snewn(datasize, unsigned char);
97 while (1) {
98 int ret = fread(data + datalen, 1, datasize - datalen, stdin);
99 if (ret < 0) {
100 fprintf(stderr, "obfusc: read: %s\n", strerror(errno));
101 return 1;
102 } else if (ret == 0) {
103 break;
104 } else {
105 datalen += ret;
106 if (datasize - datalen < 4096) {
107 datasize = datalen * 5 / 4 + 4096;
108 data = sresize(data, datasize, unsigned char);
109 }
110 }
111 }
112 }
113
114 obfuscate_bitmap(data, datalen * 8, mode == DECODE);
115
116 if (outputmode == BINARY) {
117 int ret = fwrite(data, 1, datalen, stdout);
118 if (ret < 0) {
119 fprintf(stderr, "obfusc: write: %s\n", strerror(errno));
120 return 1;
121 }
122 } else {
123 int i;
124 for (i = 0; i < datalen; i++)
125 printf("%02x", data[i]);
126 printf("\n");
127 }
128
129 return 0;
130}
diff --git a/apps/plugins/puzzles/src/palisade.R b/apps/plugins/puzzles/src/palisade.R
deleted file mode 100644
index de4bd83126..0000000000
--- a/apps/plugins/puzzles/src/palisade.R
+++ /dev/null
@@ -1,21 +0,0 @@
1# -*- makefile -*-
2
3PALISADE_EXTRA = divvy dsf
4
5palisade : [X] GTK COMMON palisade PALISADE_EXTRA palisade-icon|no-icon
6
7palisade : [G] WINDOWS COMMON palisade PALISADE_EXTRA palisade.res|noicon.res
8
9ALL += palisade[COMBINED] PALISADE_EXTRA
10
11!begin am gtk
12GAMES += palisade
13!end
14
15!begin >list.c
16 A(palisade) \
17!end
18
19!begin >gamedesc.txt
20palisade:palisade.exe:Palisade:Grid-division puzzle:Divide the grid into equal-sized areas in accordance with the clues.
21!end
diff --git a/apps/plugins/puzzles/src/palisade.c b/apps/plugins/puzzles/src/palisade.c
index e941661a0e..811204b1fe 100644
--- a/apps/plugins/puzzles/src/palisade.c
+++ b/apps/plugins/puzzles/src/palisade.c
@@ -17,6 +17,7 @@
17 17
18#include <assert.h> 18#include <assert.h>
19#include <ctype.h> 19#include <ctype.h>
20#include <limits.h>
20#include <stdarg.h> 21#include <stdarg.h>
21#include <stdio.h> 22#include <stdio.h>
22#include <stdlib.h> 23#include <stdlib.h>
@@ -46,7 +47,7 @@ struct game_params {
46 int w, h, k; 47 int w, h, k;
47}; 48};
48 49
49typedef char clue; 50typedef signed char clue;
50typedef unsigned char borderflag; 51typedef unsigned char borderflag;
51 52
52typedef struct shared_state { 53typedef struct shared_state {
@@ -156,13 +157,15 @@ static game_params *custom_params(const config_item *cfg)
156 157
157static const char *validate_params(const game_params *params, bool full) 158static const char *validate_params(const game_params *params, bool full)
158{ 159{
159 int w = params->w, h = params->h, k = params->k, wh = w * h; 160 int w = params->w, h = params->h, k = params->k, wh;
160 161
161 if (k < 1) return "Region size must be at least one"; 162 if (k < 1) return "Region size must be at least one";
162 if (w < 1) return "Width must be at least one"; 163 if (w < 1) return "Width must be at least one";
163 if (h < 1) return "Height must be at least one"; 164 if (h < 1) return "Height must be at least one";
165 if (w > INT_MAX / h)
166 return "Width times height must not be unreasonably large";
167 wh = w * h;
164 if (wh % k) return "Region size must divide grid area"; 168 if (wh % k) return "Region size must divide grid area";
165
166 if (!full) return NULL; /* succeed partial validation */ 169 if (!full) return NULL; /* succeed partial validation */
167 170
168 /* MAYBE FIXME: we (just?) don't have the UI for winning these. */ 171 /* MAYBE FIXME: we (just?) don't have the UI for winning these. */
@@ -183,7 +186,7 @@ typedef struct solver_ctx {
183 const game_params *params; /* also in shared_state */ 186 const game_params *params; /* also in shared_state */
184 clue *clues; /* also in shared_state */ 187 clue *clues; /* also in shared_state */
185 borderflag *borders; /* also in game_state */ 188 borderflag *borders; /* also in game_state */
186 int *dsf; /* particular to the solver */ 189 DSF *dsf; /* particular to the solver */
187} solver_ctx; 190} solver_ctx;
188 191
189/* Deductions: 192/* Deductions:
@@ -270,7 +273,7 @@ static void connect(solver_ctx *ctx, int i, int j)
270static bool connected(solver_ctx *ctx, int i, int j, int dir) 273static bool connected(solver_ctx *ctx, int i, int j, int dir)
271{ 274{
272 if (j == COMPUTE_J) j = i + dx[dir] + ctx->params->w*dy[dir]; 275 if (j == COMPUTE_J) j = i + dx[dir] + ctx->params->w*dy[dir];
273 return dsf_canonify(ctx->dsf, i) == dsf_canonify(ctx->dsf, j); 276 return dsf_equivalent(ctx->dsf, i, j);
274} 277}
275 278
276static void disconnect(solver_ctx *ctx, int i, int j, int dir) 279static void disconnect(solver_ctx *ctx, int i, int j, int dir)
@@ -502,19 +505,20 @@ static bool solver_equivalent_edges(solver_ctx *ctx)
502 return changed; 505 return changed;
503} 506}
504 507
505#define UNVISITED 6
506
507/* build connected components in `dsf', along the lines of `borders'. */ 508/* build connected components in `dsf', along the lines of `borders'. */
508static void dfs_dsf(int i, int w, borderflag *border, int *dsf, bool black) 509static void build_dsf(int w, int h, borderflag *border, DSF *dsf, bool black)
509{ 510{
510 int dir; 511 int x, y;
511 for (dir = 0; dir < 4; ++dir) { 512
512 int ii = i + dx[dir] + w*dy[dir], bdir = BORDER(dir); 513 for (y = 0; y < h; y++) {
513 if (black ? (border[i] & bdir) : !(border[i] & DISABLED(bdir))) 514 for (x = 0; x < w; x++) {
514 continue; 515 if (x+1 < w && (black ? !(border[y*w+x] & BORDER_R) :
515 if (dsf[ii] != UNVISITED) continue; 516 (border[y*w+x] & DISABLED(BORDER_R))))
516 dsf_merge(dsf, i, ii); 517 dsf_merge(dsf, y*w+x, y*w+(x+1));
517 dfs_dsf(ii, w, border, dsf, black); 518 if (y+1 < h && (black ? !(border[y*w+x] & BORDER_D) :
519 (border[y*w+x] & DISABLED(BORDER_D))))
520 dsf_merge(dsf, y*w+x, (y+1)*w+x);
521 }
518 } 522 }
519} 523}
520 524
@@ -523,9 +527,9 @@ static bool is_solved(const game_params *params, clue *clues,
523{ 527{
524 int w = params->w, h = params->h, wh = w*h, k = params->k; 528 int w = params->w, h = params->h, wh = w*h, k = params->k;
525 int i, x, y; 529 int i, x, y;
526 int *dsf = snew_dsf(wh); 530 DSF *dsf = dsf_new(wh);
527 531
528 assert (dsf[0] == UNVISITED); /* check: UNVISITED and dsf.c match up */ 532 build_dsf(w, h, border, dsf, true);
529 533
530 /* 534 /*
531 * A game is solved if: 535 * A game is solved if:
@@ -536,7 +540,6 @@ static bool is_solved(const game_params *params, clue *clues,
536 * - the borders also satisfy the clue set 540 * - the borders also satisfy the clue set
537 */ 541 */
538 for (i = 0; i < wh; ++i) { 542 for (i = 0; i < wh; ++i) {
539 if (dsf[i] == UNVISITED) dfs_dsf(i, params->w, border, dsf, true);
540 if (dsf_size(dsf, i) != k) goto error; 543 if (dsf_size(dsf, i) != k) goto error;
541 if (clues[i] == EMPTY) continue; 544 if (clues[i] == EMPTY) continue;
542 if (clues[i] != bitcount[border[i] & BORDER_MASK]) goto error; 545 if (clues[i] != bitcount[border[i] & BORDER_MASK]) goto error;
@@ -554,19 +557,19 @@ static bool is_solved(const game_params *params, clue *clues,
554 for (y = 0; y < h; y++) { 557 for (y = 0; y < h; y++) {
555 for (x = 0; x < w; x++) { 558 for (x = 0; x < w; x++) {
556 if (x+1 < w && (border[y*w+x] & BORDER_R) && 559 if (x+1 < w && (border[y*w+x] & BORDER_R) &&
557 dsf_canonify(dsf, y*w+x) == dsf_canonify(dsf, y*w+(x+1))) 560 dsf_equivalent(dsf, y*w+x, y*w+(x+1)))
558 goto error; 561 goto error;
559 if (y+1 < h && (border[y*w+x] & BORDER_D) && 562 if (y+1 < h && (border[y*w+x] & BORDER_D) &&
560 dsf_canonify(dsf, y*w+x) == dsf_canonify(dsf, (y+1)*w+x)) 563 dsf_equivalent(dsf, y*w+x, (y+1)*w+x))
561 goto error; 564 goto error;
562 } 565 }
563 } 566 }
564 567
565 sfree(dsf); 568 dsf_free(dsf);
566 return true; 569 return true;
567 570
568error: 571error:
569 sfree(dsf); 572 dsf_free(dsf);
570 return false; 573 return false;
571} 574}
572 575
@@ -579,7 +582,7 @@ static bool solver(const game_params *params, clue *clues, borderflag *borders)
579 ctx.params = params; 582 ctx.params = params;
580 ctx.clues = clues; 583 ctx.clues = clues;
581 ctx.borders = borders; 584 ctx.borders = borders;
582 ctx.dsf = snew_dsf(wh); 585 ctx.dsf = dsf_new(wh);
583 586
584 solver_connected_clues_versus_region_size(&ctx); /* idempotent */ 587 solver_connected_clues_versus_region_size(&ctx); /* idempotent */
585 do { 588 do {
@@ -591,7 +594,7 @@ static bool solver(const game_params *params, clue *clues, borderflag *borders)
591 changed |= solver_equivalent_edges(&ctx); 594 changed |= solver_equivalent_edges(&ctx);
592 } while (changed); 595 } while (changed);
593 596
594 sfree(ctx.dsf); 597 dsf_free(ctx.dsf);
595 598
596 return is_solved(params, clues, borders); 599 return is_solved(params, clues, borders);
597} 600}
@@ -622,15 +625,14 @@ static char *new_game_desc(const game_params *params, random_state *rs,
622{ 625{
623 int w = params->w, h = params->h, wh = w*h, k = params->k; 626 int w = params->w, h = params->h, wh = w*h, k = params->k;
624 627
625 clue *numbers = snewn(wh + 1, clue), *p; 628 clue *numbers = snewn(wh + 1, clue);
626 borderflag *rim = snewn(wh, borderflag); 629 borderflag *rim = snewn(wh, borderflag);
627 borderflag *scratch_borders = snewn(wh, borderflag); 630 borderflag *scratch_borders = snewn(wh, borderflag);
628 631
629 char *soln = snewa(*aux, wh + 2); 632 char *soln = snewa(*aux, wh + 2);
630 int *shuf = snewn(wh, int); 633 int *shuf = snewn(wh, int);
631 int *dsf = NULL, i, r, c; 634 DSF *dsf = NULL;
632 635 int i, r, c;
633 int attempts = 0;
634 636
635 for (i = 0; i < wh; ++i) shuf[i] = i; 637 for (i = 0; i < wh; ++i) shuf[i] = i;
636 xshuffle(shuf, wh, rs); 638 xshuffle(shuf, wh, rs);
@@ -642,10 +644,9 @@ static char *new_game_desc(const game_params *params, random_state *rs,
642 soln[wh] = '\0'; 644 soln[wh] = '\0';
643 645
644 do { 646 do {
645 ++attempts;
646 setmem(soln, '@', wh); 647 setmem(soln, '@', wh);
647 648
648 sfree(dsf); 649 dsf_free(dsf);
649 dsf = divvy_rectangle(w, h, k, rs); 650 dsf = divvy_rectangle(w, h, k, rs);
650 651
651 for (r = 0; r < h; ++r) 652 for (r = 0; r < h; ++r)
@@ -655,7 +656,7 @@ static char *new_game_desc(const game_params *params, random_state *rs,
655 for (dir = 0; dir < 4; ++dir) { 656 for (dir = 0; dir < 4; ++dir) {
656 int rr = r + dy[dir], cc = c + dx[dir], ii = rr * w + cc; 657 int rr = r + dy[dir], cc = c + dx[dir], ii = rr * w + cc;
657 if (OUT_OF_BOUNDS(cc, rr, w, h) || 658 if (OUT_OF_BOUNDS(cc, rr, w, h) ||
658 dsf_canonify(dsf, i) != dsf_canonify(dsf, ii)) { 659 !dsf_equivalent(dsf, i, ii)) {
659 ++numbers[i]; 660 ++numbers[i];
660 soln[i] |= BORDER(dir); 661 soln[i] |= BORDER(dir);
661 } 662 }
@@ -680,9 +681,10 @@ static char *new_game_desc(const game_params *params, random_state *rs,
680 sfree(scratch_borders); 681 sfree(scratch_borders);
681 sfree(rim); 682 sfree(rim);
682 sfree(shuf); 683 sfree(shuf);
683 sfree(dsf); 684 dsf_free(dsf);
685
686 char *output = snewn(wh + 1, char), *p = output;
684 687
685 p = numbers;
686 r = 0; 688 r = 0;
687 for (i = 0; i < wh; ++i) { 689 for (i = 0; i < wh; ++i) {
688 if (numbers[i] != EMPTY) { 690 if (numbers[i] != EMPTY) {
@@ -699,7 +701,8 @@ static char *new_game_desc(const game_params *params, random_state *rs,
699 } 701 }
700 *p++ = '\0'; 702 *p++ = '\0';
701 703
702 return sresize(numbers, p - numbers, clue); 704 sfree(numbers);
705 return sresize(output, p - output, char);
703} 706}
704 707
705static const char *validate_desc(const game_params *params, const char *desc) 708static const char *validate_desc(const game_params *params, const char *desc)
@@ -867,14 +870,13 @@ static char *game_text_format(const game_state *state)
867struct game_ui { 870struct game_ui {
868 int x, y; 871 int x, y;
869 bool show; 872 bool show;
870 bool fake_ctrl, fake_shift;
871}; 873};
872 874
873static game_ui *new_ui(const game_state *state) 875static game_ui *new_ui(const game_state *state)
874{ 876{
875 game_ui *ui = snew(game_ui); 877 game_ui *ui = snew(game_ui);
876 ui->x = ui->y = 0; 878 ui->x = ui->y = 0;
877 ui->show = ui->fake_ctrl = ui->fake_shift = false; 879 ui->show = getenv_bool("PUZZLES_SHOW_CURSOR", false);
878 return ui; 880 return ui;
879} 881}
880 882
@@ -883,16 +885,6 @@ static void free_ui(game_ui *ui)
883 sfree(ui); 885 sfree(ui);
884} 886}
885 887
886static char *encode_ui(const game_ui *ui)
887{
888 return NULL;
889}
890
891static void decode_ui(game_ui *ui, const char *encoding)
892{
893 assert (encoding == NULL);
894}
895
896static void game_changed_state(game_ui *ui, const game_state *oldstate, 888static void game_changed_state(game_ui *ui, const game_state *oldstate,
897 const game_state *newstate) 889 const game_state *newstate)
898{ 890{
@@ -907,7 +899,7 @@ struct game_drawstate {
907 899
908#define TILESIZE (ds->tilesize) 900#define TILESIZE (ds->tilesize)
909#define MARGIN (ds->tilesize / 2) 901#define MARGIN (ds->tilesize / 2)
910#define WIDTH (1 + (TILESIZE >= 16) + (TILESIZE >= 32) + (TILESIZE >= 64)) 902#define WIDTH (3*TILESIZE/32 > 1 ? 3*TILESIZE/32 : 1)
911#define CENTER ((ds->tilesize / 2) + WIDTH/2) 903#define CENTER ((ds->tilesize / 2) + WIDTH/2)
912 904
913#define FROMCOORD(x) (((x) - MARGIN) / TILESIZE) 905#define FROMCOORD(x) (((x) - MARGIN) / TILESIZE)
@@ -918,12 +910,9 @@ static char *interpret_move(const game_state *state, game_ui *ui,
918 const game_drawstate *ds, int x, int y, int button) 910 const game_drawstate *ds, int x, int y, int button)
919{ 911{
920 int w = state->shared->params.w, h = state->shared->params.h; 912 int w = state->shared->params.w, h = state->shared->params.h;
921 bool control = (button & MOD_CTRL) | ui->fake_ctrl, shift = (button & MOD_SHFT) | ui->fake_shift; 913 bool control = button & MOD_CTRL, shift = button & MOD_SHFT;
922
923 /* reset */
924 ui->fake_ctrl = ui->fake_shift = false;
925 914
926 button &= ~MOD_MASK; 915 button = STRIP_BUTTON_MODIFIERS(button);
927 916
928 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { 917 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
929 int gx = FROMCOORD(x), gy = FROMCOORD(y), possible = BORDER_MASK; 918 int gx = FROMCOORD(x), gy = FROMCOORD(y), possible = BORDER_MASK;
@@ -974,13 +963,13 @@ static char *interpret_move(const game_state *state, game_ui *ui,
974 } 963 }
975 964
976 if (IS_CURSOR_MOVE(button)) { 965 if (IS_CURSOR_MOVE(button)) {
977 ui->show = true;
978 if (control || shift) { 966 if (control || shift) {
979 borderflag flag = 0, newflag; 967 borderflag flag = 0, newflag;
980 int dir, i = ui->y * w + ui->x; 968 int dir, i = ui->y * w + ui->x;
969 ui->show = true;
981 x = ui->x; 970 x = ui->x;
982 y = ui->y; 971 y = ui->y;
983 move_cursor(button, &x, &y, w, h, false); 972 move_cursor(button, &x, &y, w, h, false, NULL);
984 if (OUT_OF_BOUNDS(x, y, w, h)) return NULL; 973 if (OUT_OF_BOUNDS(x, y, w, h)) return NULL;
985 974
986 for (dir = 0; dir < 4; ++dir) 975 for (dir = 0; dir < 4; ++dir)
@@ -999,20 +988,8 @@ static char *interpret_move(const game_state *state, game_ui *ui,
999 if (shift) newflag |= DISABLED(BORDER(FLIP(dir))); 988 if (shift) newflag |= DISABLED(BORDER(FLIP(dir)));
1000 return string(80, "F%d,%d,%dF%d,%d,%d", 989 return string(80, "F%d,%d,%dF%d,%d,%d",
1001 ui->x, ui->y, flag, x, y, newflag); 990 ui->x, ui->y, flag, x, y, newflag);
1002 } else { 991 } else
1003 move_cursor(button, &ui->x, &ui->y, w, h, false); 992 return move_cursor(button, &ui->x, &ui->y, w, h, false, &ui->show);
1004 return UI_UPDATE;
1005 }
1006 }
1007 else if(IS_CURSOR_SELECT(button)) {
1008 /* CURSOR_SELECT or CURSOR_SELECT2 tells us to toggle whether
1009 * the button press should be interpreted as having CTRL or
1010 * shift pressed along with it, respectively. */
1011 ui->show = true;
1012 if(button == CURSOR_SELECT2)
1013 ui->fake_shift = !ui->fake_shift;
1014 else
1015 ui->fake_ctrl = !ui->fake_ctrl;
1016 } 993 }
1017 994
1018 return NULL; 995 return NULL;
@@ -1022,15 +999,14 @@ static game_state *execute_move(const game_state *state, const char *move)
1022{ 999{
1023 int w = state->shared->params.w, h = state->shared->params.h, wh = w * h; 1000 int w = state->shared->params.w, h = state->shared->params.h, wh = w * h;
1024 game_state *ret = dup_game(state); 1001 game_state *ret = dup_game(state);
1025 int nchars, x, y, flag; 1002 int nchars, x, y, flag, i;
1026 1003
1027 if (*move == 'S') { 1004 if (*move == 'S') {
1028 int i;
1029 ++move; 1005 ++move;
1030 for (i = 0; i < wh && move[i]; ++i) 1006 for (i = 0; i < wh && move[i]; ++i)
1031 ret->borders[i] = 1007 ret->borders[i] =
1032 (move[i] & BORDER_MASK) | DISABLED(~move[i] & BORDER_MASK); 1008 (move[i] & BORDER_MASK) | DISABLED(~move[i] & BORDER_MASK);
1033 if (i < wh || move[i]) return NULL; /* leaks `ret', then we die */ 1009 if (i < wh || move[i]) goto badmove;
1034 ret->cheated = ret->completed = true; 1010 ret->cheated = ret->completed = true;
1035 return ret; 1011 return ret;
1036 } 1012 }
@@ -1038,22 +1014,31 @@ static game_state *execute_move(const game_state *state, const char *move)
1038 while (sscanf(move, "F%d,%d,%d%n", &x, &y, &flag, &nchars) == 3 && 1014 while (sscanf(move, "F%d,%d,%d%n", &x, &y, &flag, &nchars) == 3 &&
1039 !OUT_OF_BOUNDS(x, y, w, h)) { 1015 !OUT_OF_BOUNDS(x, y, w, h)) {
1040 move += nchars; 1016 move += nchars;
1017 for (i = 0; i < 4; i++)
1018 if ((flag & BORDER(i)) &&
1019 OUT_OF_BOUNDS(x+dx[i], y+dy[i], w, h))
1020 /* No toggling the borders of the grid! */
1021 goto badmove;
1041 ret->borders[y*w + x] ^= flag; 1022 ret->borders[y*w + x] ^= flag;
1042 } 1023 }
1043 1024
1044 if (*move) return NULL; /* leaks `ret', then we die */ 1025 if (*move) goto badmove;
1045 1026
1046 if (!ret->completed) 1027 if (!ret->completed)
1047 ret->completed = is_solved(&ret->shared->params, ret->shared->clues, 1028 ret->completed = is_solved(&ret->shared->params, ret->shared->clues,
1048 ret->borders); 1029 ret->borders);
1049 1030
1050 return ret; 1031 return ret;
1032
1033 badmove:
1034 free_game(ret);
1035 return NULL;
1051} 1036}
1052 1037
1053/* --- Drawing routines --------------------------------------------- */ 1038/* --- Drawing routines --------------------------------------------- */
1054 1039
1055static void game_compute_size(const game_params *params, int tilesize, 1040static void game_compute_size(const game_params *params, int tilesize,
1056 int *x, int *y) 1041 const game_ui *ui, int *x, int *y)
1057{ 1042{
1058 *x = (params->w + 1) * tilesize; 1043 *x = (params->w + 1) * tilesize;
1059 *y = (params->h + 1) * tilesize; 1044 *y = (params->h + 1) * tilesize;
@@ -1181,14 +1166,13 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1181 float animtime, float flashtime) 1166 float animtime, float flashtime)
1182{ 1167{
1183 int w = state->shared->params.w, h = state->shared->params.h, wh = w*h; 1168 int w = state->shared->params.w, h = state->shared->params.h, wh = w*h;
1184 int r, c, i, flash = ((int) (flashtime * 5 / FLASH_TIME)) % 2; 1169 int r, c, flash = ((int) (flashtime * 5 / FLASH_TIME)) % 2;
1185 int *black_border_dsf = snew_dsf(wh), *yellow_border_dsf = snew_dsf(wh); 1170 DSF *black_border_dsf = dsf_new(wh), *yellow_border_dsf = dsf_new(wh);
1186 int k = state->shared->params.k; 1171 int k = state->shared->params.k;
1187 1172
1188 if (!ds->grid) { 1173 if (!ds->grid) {
1189 char buf[40]; 1174 char buf[40];
1190 int bgw = (w+1) * ds->tilesize, bgh = (h+1) * ds->tilesize; 1175 int bgw = (w+1) * ds->tilesize, bgh = (h+1) * ds->tilesize;
1191 draw_rect(dr, 0, 0, bgw, bgh, COL_BACKGROUND);
1192 1176
1193 for (r = 0; r <= h; ++r) 1177 for (r = 0; r <= h; ++r)
1194 for (c = 0; c <= w; ++c) 1178 for (c = 0; c <= w; ++c)
@@ -1203,12 +1187,8 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1203 status_bar(dr, buf); 1187 status_bar(dr, buf);
1204 } 1188 }
1205 1189
1206 for (i = 0; i < wh; ++i) { 1190 build_dsf(w, h, state->borders, black_border_dsf, true);
1207 if (black_border_dsf[i] == UNVISITED) 1191 build_dsf(w, h, state->borders, yellow_border_dsf, false);
1208 dfs_dsf(i, w, state->borders, black_border_dsf, true);
1209 if (yellow_border_dsf[i] == UNVISITED)
1210 dfs_dsf(i, w, state->borders, yellow_border_dsf, false);
1211 }
1212 1192
1213 for (r = 0; r < h; ++r) 1193 for (r = 0; r < h; ++r)
1214 for (c = 0; c < w; ++c) { 1194 for (c = 0; c < w; ++c) {
@@ -1268,8 +1248,8 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1268 draw_tile(dr, ds, r, c, ds->grid[i], clue); 1248 draw_tile(dr, ds, r, c, ds->grid[i], clue);
1269 } 1249 }
1270 1250
1271 sfree(black_border_dsf); 1251 dsf_free(black_border_dsf);
1272 sfree(yellow_border_dsf); 1252 dsf_free(yellow_border_dsf);
1273} 1253}
1274 1254
1275static float game_anim_length(const game_state *oldstate, 1255static float game_anim_length(const game_state *oldstate,
@@ -1306,17 +1286,12 @@ static int game_status(const game_state *state)
1306 return state->completed ? +1 : 0; 1286 return state->completed ? +1 : 0;
1307} 1287}
1308 1288
1309static bool game_timing_state(const game_state *state, game_ui *ui) 1289static void game_print_size(const game_params *params, const game_ui *ui,
1310{ 1290 float *x, float *y)
1311 assert (!"this shouldn't get called");
1312 return false; /* placate optimiser */
1313}
1314
1315static void game_print_size(const game_params *params, float *x, float *y)
1316{ 1291{
1317 int pw, ph; 1292 int pw, ph;
1318 1293
1319 game_compute_size(params, 700, &pw, &ph); /* 7mm, like loopy */ 1294 game_compute_size(params, 700, ui, &pw, &ph); /* 7mm, like loopy */
1320 1295
1321 *x = pw / 100.0F; 1296 *x = pw / 100.0F;
1322 *y = ph / 100.0F; 1297 *y = ph / 100.0F;
@@ -1335,7 +1310,8 @@ static void print_line(drawing *dr, int x1, int y1, int x2, int y2,
1335 } else draw_line(dr, x1, y1, x2, y2, colour); 1310 } else draw_line(dr, x1, y1, x2, y2, colour);
1336} 1311}
1337 1312
1338static void game_print(drawing *dr, const game_state *state, int tilesize) 1313static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
1314 int tilesize)
1339{ 1315{
1340 int w = state->shared->params.w, h = state->shared->params.h; 1316 int w = state->shared->params.w, h = state->shared->params.h;
1341 int ink = print_mono_colour(dr, 0); 1317 int ink = print_mono_colour(dr, 0);
@@ -1399,12 +1375,14 @@ const struct game thegame = {
1399 free_game, 1375 free_game,
1400 true, solve_game, 1376 true, solve_game,
1401 true, game_can_format_as_text_now, game_text_format, 1377 true, game_can_format_as_text_now, game_text_format,
1378 NULL, NULL, /* get_prefs, set_prefs */
1402 new_ui, 1379 new_ui,
1403 free_ui, 1380 free_ui,
1404 encode_ui, 1381 NULL, /* encode_ui */
1405 decode_ui, 1382 NULL, /* decode_ui */
1406 NULL, /* game_request_keys */ 1383 NULL, /* game_request_keys */
1407 game_changed_state, 1384 game_changed_state,
1385 NULL, /* current_key_label */
1408 interpret_move, 1386 interpret_move,
1409 execute_move, 1387 execute_move,
1410 48, game_compute_size, game_set_size, 1388 48, game_compute_size, game_set_size,
@@ -1418,6 +1396,6 @@ const struct game thegame = {
1418 game_status, 1396 game_status,
1419 true, false, game_print_size, game_print, 1397 true, false, game_print_size, game_print,
1420 true, /* wants_statusbar */ 1398 true, /* wants_statusbar */
1421 false, game_timing_state, 1399 false, NULL, /* timing_state */
1422 0, /* flags */ 1400 0, /* flags */
1423}; 1401};
diff --git a/apps/plugins/puzzles/src/pattern.R b/apps/plugins/puzzles/src/pattern.R
deleted file mode 100644
index d6695715f9..0000000000
--- a/apps/plugins/puzzles/src/pattern.R
+++ /dev/null
@@ -1,25 +0,0 @@
1# -*- makefile -*-
2
3pattern : [X] GTK COMMON pattern pattern-icon|no-icon
4
5pattern : [G] WINDOWS COMMON pattern pattern.res|noicon.res
6
7patternsolver : [U] pattern[STANDALONE_SOLVER] STANDALONE
8patternsolver : [C] pattern[STANDALONE_SOLVER] STANDALONE
9
10patternpicture : [U] pattern[STANDALONE_PICTURE_GENERATOR] STANDALONE
11patternpicture : [C] pattern[STANDALONE_PICTURE_GENERATOR] STANDALONE
12
13ALL += pattern[COMBINED]
14
15!begin am gtk
16GAMES += pattern
17!end
18
19!begin >list.c
20 A(pattern) \
21!end
22
23!begin >gamedesc.txt
24pattern:pattern.exe:Pattern:Pattern puzzle:Fill in the pattern in the grid, given only the lengths of runs of black squares.
25!end
diff --git a/apps/plugins/puzzles/src/pattern.c b/apps/plugins/puzzles/src/pattern.c
index df720b7d82..b370a3dc2f 100644
--- a/apps/plugins/puzzles/src/pattern.c
+++ b/apps/plugins/puzzles/src/pattern.c
@@ -7,7 +7,12 @@
7#include <string.h> 7#include <string.h>
8#include <assert.h> 8#include <assert.h>
9#include <ctype.h> 9#include <ctype.h>
10#include <math.h> 10#include <limits.h>
11#ifdef NO_TGMATH_H
12# include <math.h>
13#else
14# include <tgmath.h>
15#endif
11 16
12#include "puzzles.h" 17#include "puzzles.h"
13 18
@@ -53,6 +58,7 @@ typedef struct game_state_common {
53 int *rowdata, *rowlen; 58 int *rowdata, *rowlen;
54 bool *immutable; 59 bool *immutable;
55 int refcount; 60 int refcount;
61 enum { FS_SMALL, FS_LARGE } fontsize;
56} game_state_common; 62} game_state_common;
57 63
58struct game_state { 64struct game_state {
@@ -176,7 +182,10 @@ static const char *validate_params(const game_params *params, bool full)
176{ 182{
177 if (params->w <= 0 || params->h <= 0) 183 if (params->w <= 0 || params->h <= 0)
178 return "Width and height must both be greater than zero"; 184 return "Width and height must both be greater than zero";
179 if (params->w * params->w < 2) 185 if (params->w > INT_MAX - 1 || params->h > INT_MAX - 1 ||
186 params->w > INT_MAX / params->h)
187 return "Puzzle must not be unreasonably large";
188 if (params->w * params->h < 2)
180 return "Grid must contain at least two squares"; 189 return "Grid must contain at least two squares";
181 return NULL; 190 return NULL;
182} 191}
@@ -360,7 +369,7 @@ static int compute_rowdata(int *ret, unsigned char *start, int len, int step)
360#define STILL_UNKNOWN 3 369#define STILL_UNKNOWN 3
361 370
362#ifdef STANDALONE_SOLVER 371#ifdef STANDALONE_SOLVER
363bool verbose = false; 372static bool verbose = false;
364#endif 373#endif
365 374
366static bool do_recurse(unsigned char *known, unsigned char *deduced, 375static bool do_recurse(unsigned char *known, unsigned char *deduced,
@@ -441,6 +450,8 @@ static bool do_row(unsigned char *known, unsigned char *deduced,
441 int rowlen, i, freespace; 450 int rowlen, i, freespace;
442 bool done_any; 451 bool done_any;
443 452
453 assert(len >= 0); /* avoid compile warnings about the memsets below */
454
444 freespace = len+1; 455 freespace = len+1;
445 for (rowlen = 0; data[rowlen]; rowlen++) { 456 for (rowlen = 0; data[rowlen]; rowlen++) {
446 minpos_done[rowlen] = minpos_ok[rowlen] = len - 1; 457 minpos_done[rowlen] = minpos_ok[rowlen] = len - 1;
@@ -654,7 +665,7 @@ static bool solve_puzzle(const game_state *state, unsigned char *grid,
654#ifndef STANDALONE_PICTURE_GENERATOR 665#ifndef STANDALONE_PICTURE_GENERATOR
655static unsigned char *generate_soluble(random_state *rs, int w, int h) 666static unsigned char *generate_soluble(random_state *rs, int w, int h)
656{ 667{
657 int i, j, ntries, max; 668 int i, j, max;
658 bool ok; 669 bool ok;
659 unsigned char *grid, *matrix, *workspace; 670 unsigned char *grid, *matrix, *workspace;
660 unsigned int *changed_h, *changed_w; 671 unsigned int *changed_h, *changed_w;
@@ -670,11 +681,7 @@ static unsigned char *generate_soluble(random_state *rs, int w, int h)
670 changed_w = snewn(max+1, unsigned int); 681 changed_w = snewn(max+1, unsigned int);
671 rowdata = snewn(max+1, int); 682 rowdata = snewn(max+1, int);
672 683
673 ntries = 0;
674
675 do { 684 do {
676 ntries++;
677
678 generate(rs, w, h, grid); 685 generate(rs, w, h, grid);
679 686
680 /* 687 /*
@@ -719,7 +726,7 @@ static unsigned char *generate_soluble(random_state *rs, int w, int h)
719#endif 726#endif
720 727
721#ifdef STANDALONE_PICTURE_GENERATOR 728#ifdef STANDALONE_PICTURE_GENERATOR
722unsigned char *picture; 729static unsigned char *picture;
723#endif 730#endif
724 731
725static char *new_game_desc(const game_params *params, random_state *rs, 732static char *new_game_desc(const game_params *params, random_state *rs,
@@ -908,6 +915,10 @@ static const char *validate_desc(const game_params *params, const char *desc)
908 p = desc; 915 p = desc;
909 while (*desc && isdigit((unsigned char)*desc)) desc++; 916 while (*desc && isdigit((unsigned char)*desc)) desc++;
910 n = atoi(p); 917 n = atoi(p);
918 if (n <= 0)
919 return "all clues must be positive";
920 if (n > INT_MAX - 1)
921 return "at least one clue is grossly excessive";
911 rowspace -= n+1; 922 rowspace -= n+1;
912 923
913 if (rowspace < 0) { 924 if (rowspace < 0) {
@@ -965,7 +976,7 @@ static const char *validate_desc(const game_params *params, const char *desc)
965static game_state *new_game(midend *me, const game_params *params, 976static game_state *new_game(midend *me, const game_params *params,
966 const char *desc) 977 const char *desc)
967{ 978{
968 int i; 979 int i, j;
969 const char *p; 980 const char *p;
970 game_state *state = snew(game_state); 981 game_state *state = snew(game_state);
971 982
@@ -1003,6 +1014,26 @@ static game_state *new_game(midend *me, const game_params *params,
1003 } 1014 }
1004 } 1015 }
1005 1016
1017 /*
1018 * Choose a font size based on the clues. If any column clue is
1019 * more than one digit, switch to the smaller size.
1020 */
1021 state->common->fontsize = FS_LARGE;
1022 for (i = 0; i < params->w; i++)
1023 for (j = 0; j < state->common->rowlen[i]; j++)
1024 if (state->common->rowdata[state->common->rowsize * i + j] >= 10)
1025 state->common->fontsize = FS_SMALL;
1026 /*
1027 * We might also need to use the small font if there are lots of
1028 * row clues. We assume that all clues are one digit and that a
1029 * single-digit clue takes up 1.5 tiles, of which the clue is 0.5
1030 * tiles and the space is 1.0 tiles.
1031 */
1032 for (i = params->w; i < params->w + params->h; i++)
1033 if ((state->common->rowlen[i] * 3 - 2) >
1034 TLBORDER(state->common->w) * 2)
1035 state->common->fontsize = FS_SMALL;
1036
1006 if (desc[-1] == ',') { 1037 if (desc[-1] == ',') {
1007 /* 1038 /*
1008 * Optional extra piece of game description which fills in 1039 * Optional extra piece of game description which fills in
@@ -1217,7 +1248,7 @@ static game_ui *new_ui(const game_state *state)
1217 ret = snew(game_ui); 1248 ret = snew(game_ui);
1218 ret->dragging = false; 1249 ret->dragging = false;
1219 ret->cur_x = ret->cur_y = 0; 1250 ret->cur_x = ret->cur_y = 0;
1220 ret->cur_visible = false; 1251 ret->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1221 1252
1222 return ret; 1253 return ret;
1223} 1254}
@@ -1227,18 +1258,26 @@ static void free_ui(game_ui *ui)
1227 sfree(ui); 1258 sfree(ui);
1228} 1259}
1229 1260
1230static char *encode_ui(const game_ui *ui) 1261static void game_changed_state(game_ui *ui, const game_state *oldstate,
1231{ 1262 const game_state *newstate)
1232 return NULL;
1233}
1234
1235static void decode_ui(game_ui *ui, const char *encoding)
1236{ 1263{
1237} 1264}
1238 1265
1239static void game_changed_state(game_ui *ui, const game_state *oldstate, 1266static const char *current_key_label(const game_ui *ui,
1240 const game_state *newstate) 1267 const game_state *state, int button)
1241{ 1268{
1269 if (IS_CURSOR_SELECT(button)) {
1270 if (!ui->cur_visible) return "";
1271 switch (state->grid[ui->cur_y * state->common->w + ui->cur_x]) {
1272 case GRID_UNKNOWN:
1273 return button == CURSOR_SELECT ? "Black" : "White";
1274 case GRID_FULL:
1275 return button == CURSOR_SELECT ? "White" : "Grey";
1276 case GRID_EMPTY:
1277 return button == CURSOR_SELECT ? "Grey" : "Black";
1278 }
1279 }
1280 return "";
1242} 1281}
1243 1282
1244struct game_drawstate { 1283struct game_drawstate {
@@ -1247,6 +1286,7 @@ struct game_drawstate {
1247 int tilesize; 1286 int tilesize;
1248 unsigned char *visible, *numcolours; 1287 unsigned char *visible, *numcolours;
1249 int cur_x, cur_y; 1288 int cur_x, cur_y;
1289 char *strbuf; /* Used for formatting clues. */
1250}; 1290};
1251 1291
1252static char *interpret_move(const game_state *state, game_ui *ui, 1292static char *interpret_move(const game_state *state, game_ui *ui,
@@ -1254,7 +1294,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1254 int x, int y, int button) 1294 int x, int y, int button)
1255{ 1295{
1256 bool control = button & MOD_CTRL, shift = button & MOD_SHFT; 1296 bool control = button & MOD_CTRL, shift = button & MOD_SHFT;
1257 button &= ~MOD_MASK; 1297 button = STRIP_BUTTON_MODIFIERS(button);
1258 1298
1259 x = FROMCOORD(state->common->w, x); 1299 x = FROMCOORD(state->common->w, x);
1260 y = FROMCOORD(state->common->h, y); 1300 y = FROMCOORD(state->common->h, y);
@@ -1294,7 +1334,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1294 ui->drag_start_y = ui->drag_end_y = y; 1334 ui->drag_start_y = ui->drag_end_y = y;
1295 ui->cur_visible = false; 1335 ui->cur_visible = false;
1296 1336
1297 return UI_UPDATE; 1337 return MOVE_UI_UPDATE;
1298 } 1338 }
1299 1339
1300 if (ui->dragging && button == ui->drag) { 1340 if (ui->dragging && button == ui->drag) {
@@ -1323,7 +1363,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1323 ui->drag_end_x = x; 1363 ui->drag_end_x = x;
1324 ui->drag_end_y = y; 1364 ui->drag_end_y = y;
1325 1365
1326 return UI_UPDATE; 1366 return MOVE_UI_UPDATE;
1327 } 1367 }
1328 1368
1329 if (ui->dragging && button == ui->release) { 1369 if (ui->dragging && button == ui->release) {
@@ -1351,20 +1391,21 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1351 x1, y1, x2-x1+1, y2-y1+1); 1391 x1, y1, x2-x1+1, y2-y1+1);
1352 return dupstr(buf); 1392 return dupstr(buf);
1353 } else 1393 } else
1354 return UI_UPDATE; 1394 return MOVE_UI_UPDATE;
1355 } 1395 }
1356 1396
1357 if (IS_CURSOR_MOVE(button)) { 1397 if (IS_CURSOR_MOVE(button)) {
1358 int x = ui->cur_x, y = ui->cur_y, newstate; 1398 int x = ui->cur_x, y = ui->cur_y, newstate;
1359 char buf[80]; 1399 char buf[80], *ret;
1360 move_cursor(button, &ui->cur_x, &ui->cur_y, state->common->w, state->common->h, false); 1400 ret = move_cursor(button, &ui->cur_x, &ui->cur_y,
1361 ui->cur_visible = true; 1401 state->common->w, state->common->h, false,
1362 if (!control && !shift) return UI_UPDATE; 1402 &ui->cur_visible);
1403 if (!control && !shift) return ret;
1363 1404
1364 newstate = control ? shift ? GRID_UNKNOWN : GRID_FULL : GRID_EMPTY; 1405 newstate = control ? shift ? GRID_UNKNOWN : GRID_FULL : GRID_EMPTY;
1365 if (state->grid[y * state->common->w + x] == newstate && 1406 if (state->grid[y * state->common->w + x] == newstate &&
1366 state->grid[ui->cur_y * state->common->w + ui->cur_x] == newstate) 1407 state->grid[ui->cur_y * state->common->w + ui->cur_x] == newstate)
1367 return UI_UPDATE; 1408 return ret;
1368 1409
1369 sprintf(buf, "%c%d,%d,%d,%d", control ? shift ? 'U' : 'F' : 'E', 1410 sprintf(buf, "%c%d,%d,%d,%d", control ? shift ? 'U' : 'F' : 'E',
1370 min(x, ui->cur_x), min(y, ui->cur_y), 1411 min(x, ui->cur_x), min(y, ui->cur_y),
@@ -1379,7 +1420,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1379 1420
1380 if (!ui->cur_visible) { 1421 if (!ui->cur_visible) {
1381 ui->cur_visible = true; 1422 ui->cur_visible = true;
1382 return UI_UPDATE; 1423 return MOVE_UI_UPDATE;
1383 } 1424 }
1384 1425
1385 if (button == CURSOR_SELECT2) 1426 if (button == CURSOR_SELECT2)
@@ -1637,7 +1678,7 @@ static bool check_errors(const game_state *state, int i)
1637 */ 1678 */
1638 1679
1639static void game_compute_size(const game_params *params, int tilesize, 1680static void game_compute_size(const game_params *params, int tilesize,
1640 int *x, int *y) 1681 const game_ui *ui, int *x, int *y)
1641{ 1682{
1642 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 1683 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1643 struct { int tilesize; } ads, *ds = &ads; 1684 struct { int tilesize; } ads, *ds = &ads;
@@ -1692,6 +1733,8 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1692 ds->numcolours = snewn(ds->w + ds->h, unsigned char); 1733 ds->numcolours = snewn(ds->w + ds->h, unsigned char);
1693 memset(ds->numcolours, 255, ds->w + ds->h); 1734 memset(ds->numcolours, 255, ds->w + ds->h);
1694 ds->cur_x = ds->cur_y = 0; 1735 ds->cur_x = ds->cur_y = 0;
1736 ds->strbuf = snewn(state->common->rowsize *
1737 MAX_DIGITS(*state->common->rowdata) + 1, char);
1695 1738
1696 return ds; 1739 return ds;
1697} 1740}
@@ -1699,6 +1742,8 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1699static void game_free_drawstate(drawing *dr, game_drawstate *ds) 1742static void game_free_drawstate(drawing *dr, game_drawstate *ds)
1700{ 1743{
1701 sfree(ds->visible); 1744 sfree(ds->visible);
1745 sfree(ds->numcolours);
1746 sfree(ds->strbuf);
1702 sfree(ds); 1747 sfree(ds);
1703} 1748}
1704 1749
@@ -1743,19 +1788,43 @@ static void draw_numbers(
1743 int *rowdata = state->common->rowdata + state->common->rowsize * i; 1788 int *rowdata = state->common->rowdata + state->common->rowsize * i;
1744 int nfit; 1789 int nfit;
1745 int j; 1790 int j;
1791 int rx, ry, rw, rh;
1792 int fontsize;
1746 1793
1747 if (erase) { 1794 if (i < state->common->w) {
1748 if (i < state->common->w) { 1795 rx = TOCOORD(state->common->w, i);
1749 draw_rect(dr, TOCOORD(state->common->w, i), 0, 1796 ry = 0;
1750 TILE_SIZE, BORDER + TLBORDER(state->common->h) * TILE_SIZE, 1797 rw = TILE_SIZE;
1751 COL_BACKGROUND); 1798 rh = BORDER + TLBORDER(state->common->h) * TILE_SIZE;
1752 } else { 1799 } else {
1753 draw_rect(dr, 0, TOCOORD(state->common->h, i - state->common->w), 1800 rx = 0;
1754 BORDER + TLBORDER(state->common->w) * TILE_SIZE, TILE_SIZE, 1801 ry = TOCOORD(state->common->h, i - state->common->w);
1755 COL_BACKGROUND); 1802 rw = BORDER + TLBORDER(state->common->w) * TILE_SIZE;
1756 } 1803 rh = TILE_SIZE;
1757 } 1804 }
1758 1805
1806 clip(dr, rx, ry, rw, rh);
1807 if (erase)
1808 draw_rect(dr, rx, ry, rw, rh, COL_BACKGROUND);
1809
1810 /*
1811 * Choose a font size that's suitable for the lengths of clue.
1812 * Only column clues are interesting because row clues can be
1813 * spaced out independent of the tile size. For column clues, we
1814 * want to go as large as practical while leaving decent space
1815 * between horizintally adjacent clues. We currently distinguish
1816 * two cases: FS_LARGE is when all column clues are single digits,
1817 * and FS_SMALL in all other cases.
1818 *
1819 * If we assume that a digit is about 0.6em wide, and we want
1820 * about that space between clues, then FS_LARGE should be
1821 * TILESIZE/1.2. If we also assume that clues are at most two
1822 * digits long then the case where adjacent clues are two digits
1823 * long requries FS_SMALL to be TILESIZE/1.8.
1824 */
1825 fontsize = (TILE_SIZE + 0.5F) /
1826 (state->common->fontsize == FS_LARGE ? 1.2F : 1.8F);
1827
1759 /* 1828 /*
1760 * Normally I space the numbers out by the same distance as the 1829 * Normally I space the numbers out by the same distance as the
1761 * tile size. However, if there are more numbers than available 1830 * tile size. However, if there are more numbers than available
@@ -1768,32 +1837,38 @@ static void draw_numbers(
1768 nfit = max(rowlen, nfit) - 1; 1837 nfit = max(rowlen, nfit) - 1;
1769 assert(nfit > 0); 1838 assert(nfit > 0);
1770 1839
1771 for (j = 0; j < rowlen; j++) { 1840 if (i < state->common->w) {
1772 int x, y; 1841 for (j = 0; j < rowlen; j++) {
1773 char str[80]; 1842 int x, y;
1843 char str[MAX_DIGITS(*rowdata) + 1];
1774 1844
1775 if (i < state->common->w) { 1845 x = rx;
1776 x = TOCOORD(state->common->w, i);
1777 y = BORDER + TILE_SIZE * (TLBORDER(state->common->h)-1); 1846 y = BORDER + TILE_SIZE * (TLBORDER(state->common->h)-1);
1778 y -= ((rowlen-j-1)*TILE_SIZE) * (TLBORDER(state->common->h)-1) / nfit; 1847 y -= ((rowlen-j-1)*TILE_SIZE) * (TLBORDER(state->common->h)-1) / nfit;
1779 } else { 1848 sprintf(str, "%d", rowdata[j]);
1780 y = TOCOORD(state->common->h, i - state->common->w); 1849 draw_text(dr, x+TILE_SIZE/2, y+TILE_SIZE/2, FONT_VARIABLE,
1781 x = BORDER + TILE_SIZE * (TLBORDER(state->common->w)-1); 1850 fontsize, ALIGN_HCENTRE | ALIGN_VCENTRE, colour, str);
1782 x -= ((rowlen-j-1)*TILE_SIZE) * (TLBORDER(state->common->w)-1) / nfit;
1783 } 1851 }
1784
1785 sprintf(str, "%d", rowdata[j]);
1786 draw_text(dr, x+TILE_SIZE/2, y+TILE_SIZE/2, FONT_VARIABLE,
1787 TILE_SIZE/2, ALIGN_HCENTRE | ALIGN_VCENTRE, colour, str);
1788 }
1789
1790 if (i < state->common->w) {
1791 draw_update(dr, TOCOORD(state->common->w, i), 0,
1792 TILE_SIZE, BORDER + TLBORDER(state->common->h) * TILE_SIZE);
1793 } else { 1852 } else {
1794 draw_update(dr, 0, TOCOORD(state->common->h, i - state->common->w), 1853 int x, y;
1795 BORDER + TLBORDER(state->common->w) * TILE_SIZE, TILE_SIZE); 1854 size_t off = 0;
1855 const char *spaces = " ";
1856
1857 assert(rowlen <= state->common->rowsize);
1858 *ds->strbuf = '\0';
1859 /* Squish up a bit if there are lots of clues. */
1860 if (rowlen > TLBORDER(state->common->w)) spaces++;
1861 for (j = 0; j < rowlen; j++)
1862 off += sprintf(ds->strbuf + off, "%s%d",
1863 j ? spaces : "", rowdata[j]);
1864 y = ry;
1865 x = BORDER + TILE_SIZE * (TLBORDER(state->common->w)-1);
1866 draw_text(dr, x+TILE_SIZE, y+TILE_SIZE/2, FONT_VARIABLE,
1867 fontsize, ALIGN_HRIGHT | ALIGN_VCENTRE, colour, ds->strbuf);
1796 } 1868 }
1869
1870 unclip(dr);
1871 draw_update(dr, rx, ry, rw, rh);
1797} 1872}
1798 1873
1799static void game_redraw(drawing *dr, game_drawstate *ds, 1874static void game_redraw(drawing *dr, game_drawstate *ds,
@@ -1808,14 +1883,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1808 1883
1809 if (!ds->started) { 1884 if (!ds->started) {
1810 /* 1885 /*
1811 * The initial contents of the window are not guaranteed
1812 * and can vary with front ends. To be on the safe side,
1813 * all games should start by drawing a big background-
1814 * colour rectangle covering the whole window.
1815 */
1816 draw_rect(dr, 0, 0, SIZE(ds->w), SIZE(ds->h), COL_BACKGROUND);
1817
1818 /*
1819 * Draw the grid outline. 1886 * Draw the grid outline.
1820 */ 1887 */
1821 draw_rect(dr, TOCOORD(ds->w, 0) - 1, TOCOORD(ds->h, 0) - 1, 1888 draw_rect(dr, TOCOORD(ds->w, 0) - 1, TOCOORD(ds->h, 0) - 1,
@@ -1936,24 +2003,21 @@ static int game_status(const game_state *state)
1936 return state->completed ? +1 : 0; 2003 return state->completed ? +1 : 0;
1937} 2004}
1938 2005
1939static bool game_timing_state(const game_state *state, game_ui *ui) 2006static void game_print_size(const game_params *params, const game_ui *ui,
1940{ 2007 float *x, float *y)
1941 return true;
1942}
1943
1944static void game_print_size(const game_params *params, float *x, float *y)
1945{ 2008{
1946 int pw, ph; 2009 int pw, ph;
1947 2010
1948 /* 2011 /*
1949 * I'll use 5mm squares by default. 2012 * I'll use 5mm squares by default.
1950 */ 2013 */
1951 game_compute_size(params, 500, &pw, &ph); 2014 game_compute_size(params, 500, ui, &pw, &ph);
1952 *x = pw / 100.0F; 2015 *x = pw / 100.0F;
1953 *y = ph / 100.0F; 2016 *y = ph / 100.0F;
1954} 2017}
1955 2018
1956static void game_print(drawing *dr, const game_state *state, int tilesize) 2019static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2020 int tilesize)
1957{ 2021{
1958 int w = state->common->w, h = state->common->h; 2022 int w = state->common->w, h = state->common->h;
1959 int ink = print_mono_colour(dr, 0); 2023 int ink = print_mono_colour(dr, 0);
@@ -2027,12 +2091,14 @@ const struct game thegame = {
2027 free_game, 2091 free_game,
2028 true, solve_game, 2092 true, solve_game,
2029 true, game_can_format_as_text_now, game_text_format, 2093 true, game_can_format_as_text_now, game_text_format,
2094 NULL, NULL, /* get_prefs, set_prefs */
2030 new_ui, 2095 new_ui,
2031 free_ui, 2096 free_ui,
2032 encode_ui, 2097 NULL, /* encode_ui */
2033 decode_ui, 2098 NULL, /* decode_ui */
2034 NULL, /* game_request_keys */ 2099 NULL, /* game_request_keys */
2035 game_changed_state, 2100 game_changed_state,
2101 current_key_label,
2036 interpret_move, 2102 interpret_move,
2037 execute_move, 2103 execute_move,
2038 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 2104 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -2046,7 +2112,7 @@ const struct game thegame = {
2046 game_status, 2112 game_status,
2047 true, false, game_print_size, game_print, 2113 true, false, game_print_size, game_print,
2048 false, /* wants_statusbar */ 2114 false, /* wants_statusbar */
2049 false, game_timing_state, 2115 false, NULL, /* timing_state */
2050 REQUIRE_RBUTTON, /* flags */ 2116 REQUIRE_RBUTTON, /* flags */
2051}; 2117};
2052 2118
diff --git a/apps/plugins/puzzles/src/pearl.R b/apps/plugins/puzzles/src/pearl.R
deleted file mode 100644
index 79bc7325c7..0000000000
--- a/apps/plugins/puzzles/src/pearl.R
+++ /dev/null
@@ -1,23 +0,0 @@
1# -*- makefile -*-
2
3PEARL_EXTRA = dsf tree234 grid penrose loopgen tdq
4
5pearl : [X] GTK COMMON pearl PEARL_EXTRA pearl-icon|no-icon
6pearl : [G] WINDOWS COMMON pearl PEARL_EXTRA pearl.res?
7
8pearlbench : [U] pearl[STANDALONE_SOLVER] PEARL_EXTRA STANDALONE m.lib
9pearlbench : [C] pearl[STANDALONE_SOLVER] PEARL_EXTRA STANDALONE
10
11ALL += pearl[COMBINED] PEARL_EXTRA
12
13!begin am gtk
14GAMES += pearl
15!end
16
17!begin >list.c
18 A(pearl) \
19!end
20
21!begin >gamedesc.txt
22pearl:pearl.exe:Pearl:Loop-drawing puzzle:Draw a single closed loop, given clues about corner and straight squares.
23!end
diff --git a/apps/plugins/puzzles/src/pearl.c b/apps/plugins/puzzles/src/pearl.c
index 2657d45a67..95993172ca 100644
--- a/apps/plugins/puzzles/src/pearl.c
+++ b/apps/plugins/puzzles/src/pearl.c
@@ -35,7 +35,12 @@
35#include <string.h> 35#include <string.h>
36#include <assert.h> 36#include <assert.h>
37#include <ctype.h> 37#include <ctype.h>
38#include <math.h> 38#include <limits.h>
39#ifdef NO_TGMATH_H
40# include <math.h>
41#else
42# include <tgmath.h>
43#endif
39 44
40#include "puzzles.h" 45#include "puzzles.h"
41#include "grid.h" 46#include "grid.h"
@@ -272,8 +277,12 @@ static const char *validate_params(const game_params *params, bool full)
272{ 277{
273 if (params->w < 5) return "Width must be at least five"; 278 if (params->w < 5) return "Width must be at least five";
274 if (params->h < 5) return "Height must be at least five"; 279 if (params->h < 5) return "Height must be at least five";
280 if (params->w > INT_MAX / params->h)
281 return "Width times height must not be unreasonably large";
275 if (params->difficulty < 0 || params->difficulty >= DIFFCOUNT) 282 if (params->difficulty < 0 || params->difficulty >= DIFFCOUNT)
276 return "Unknown difficulty level"; 283 return "Unknown difficulty level";
284 if (params->difficulty >= DIFF_TRICKY && params->w + params->h < 11)
285 return "Width or height must be at least six for Tricky";
277 286
278 return NULL; 287 return NULL;
279} 288}
@@ -287,7 +296,8 @@ static int pearl_solve(int w, int h, char *clues, char *result,
287{ 296{
288 int W = 2*w+1, H = 2*h+1; 297 int W = 2*w+1, H = 2*h+1;
289 short *workspace; 298 short *workspace;
290 int *dsf, *dsfsize; 299 DSF *dsf;
300 int *dsfsize;
291 int x, y, b, d; 301 int x, y, b, d;
292 int ret = -1; 302 int ret = -1;
293 303
@@ -340,7 +350,7 @@ static int pearl_solve(int w, int h, char *clues, char *result,
340 * We maintain a dsf of connected squares, together with a 350 * We maintain a dsf of connected squares, together with a
341 * count of the size of each equivalence class. 351 * count of the size of each equivalence class.
342 */ 352 */
343 dsf = snewn(w*h, int); 353 dsf = dsf_new(w*h);
344 dsfsize = snewn(w*h, int); 354 dsfsize = snewn(w*h, int);
345 355
346 /* 356 /*
@@ -583,7 +593,7 @@ static int pearl_solve(int w, int h, char *clues, char *result,
583 { 593 {
584 int nonblanks, loopclass; 594 int nonblanks, loopclass;
585 595
586 dsf_init(dsf, w*h); 596 dsf_reinit(dsf);
587 for (x = 0; x < w*h; x++) 597 for (x = 0; x < w*h; x++)
588 dsfsize[x] = 1; 598 dsfsize[x] = 1;
589 599
@@ -850,10 +860,39 @@ cleanup:
850 if (ret == 1) assert(b < 0xD); /* we should have had a break by now */ 860 if (ret == 1) assert(b < 0xD); /* we should have had a break by now */
851 } 861 }
852 } 862 }
863
864 /*
865 * Ensure we haven't left the _data structure_ inconsistent,
866 * regardless of the consistency of the _puzzle_. In
867 * particular, we should never have marked one square as
868 * linked to its neighbour if the neighbour is not
869 * reciprocally linked back to the original square.
870 *
871 * This can happen if we get part way through solving an
872 * impossible puzzle and then give up trying to make further
873 * progress. So here we fix it up to avoid confusing the rest
874 * of the game.
875 */
876 for (y = 0; y < h; y++) {
877 for (x = 0; x < w; x++) {
878 for (d = 1; d <= 8; d += d) {
879 int nx = x + DX(d), ny = y + DY(d);
880 int rlink;
881 if (0 <= nx && nx < w && 0 <= ny && ny < h)
882 rlink = result[ny*w+nx] & F(d);
883 else
884 rlink = 0; /* off-board squares don't link back */
885
886 /* If other square doesn't link to us, don't link to it */
887 if (!rlink)
888 result[y*w+x] &= ~d;
889 }
890 }
891 }
853 } 892 }
854 893
855 sfree(dsfsize); 894 sfree(dsfsize);
856 sfree(dsf); 895 dsf_free(dsf);
857 sfree(workspace); 896 sfree(workspace);
858 assert(ret >= 0); 897 assert(ret >= 0);
859 return ret; 898 return ret;
@@ -941,9 +980,9 @@ static int pearl_loopgen_bias(void *vctx, char *board, int face)
941 * to reprocess the edges for this boundary. 980 * to reprocess the edges for this boundary.
942 */ 981 */
943 if (oldface == c || newface == c) { 982 if (oldface == c || newface == c) {
944 grid_face *f = &g->faces[face]; 983 grid_face *f = g->faces[face];
945 for (k = 0; k < f->order; k++) 984 for (k = 0; k < f->order; k++)
946 tdq_add(b->edges_todo, f->edges[k] - g->edges); 985 tdq_add(b->edges_todo, f->edges[k]->index);
947 } 986 }
948 } 987 }
949 } 988 }
@@ -959,15 +998,15 @@ static int pearl_loopgen_bias(void *vctx, char *board, int face)
959 * the vertextypes_todo list. 998 * the vertextypes_todo list.
960 */ 999 */
961 while ((j = tdq_remove(b->edges_todo)) >= 0) { 1000 while ((j = tdq_remove(b->edges_todo)) >= 0) {
962 grid_edge *e = &g->edges[j]; 1001 grid_edge *e = g->edges[j];
963 int fc1 = e->face1 ? board[e->face1 - g->faces] : FACE_BLACK; 1002 int fc1 = e->face1 ? board[e->face1->index] : FACE_BLACK;
964 int fc2 = e->face2 ? board[e->face2 - g->faces] : FACE_BLACK; 1003 int fc2 = e->face2 ? board[e->face2->index] : FACE_BLACK;
965 bool oldedge = b->edges[j]; 1004 bool oldedge = b->edges[j];
966 bool newedge = (fc1==c) ^ (fc2==c); 1005 bool newedge = (fc1==c) ^ (fc2==c);
967 if (oldedge != newedge) { 1006 if (oldedge != newedge) {
968 b->edges[j] = newedge; 1007 b->edges[j] = newedge;
969 tdq_add(b->vertextypes_todo, e->dot1 - g->dots); 1008 tdq_add(b->vertextypes_todo, e->dot1->index);
970 tdq_add(b->vertextypes_todo, e->dot2 - g->dots); 1009 tdq_add(b->vertextypes_todo, e->dot2->index);
971 } 1010 }
972 } 1011 }
973 1012
@@ -982,7 +1021,7 @@ static int pearl_loopgen_bias(void *vctx, char *board, int face)
982 * old neighbours. 1021 * old neighbours.
983 */ 1022 */
984 while ((j = tdq_remove(b->vertextypes_todo)) >= 0) { 1023 while ((j = tdq_remove(b->vertextypes_todo)) >= 0) {
985 grid_dot *d = &g->dots[j]; 1024 grid_dot *d = g->dots[j];
986 int neighbours[2], type = 0, n = 0; 1025 int neighbours[2], type = 0, n = 0;
987 1026
988 for (k = 0; k < d->order; k++) { 1027 for (k = 0; k < d->order; k++) {
@@ -990,10 +1029,10 @@ static int pearl_loopgen_bias(void *vctx, char *board, int face)
990 grid_dot *d2 = (e->dot1 == d ? e->dot2 : e->dot1); 1029 grid_dot *d2 = (e->dot1 == d ? e->dot2 : e->dot1);
991 /* dir == 0,1,2,3 for an edge going L,U,R,D */ 1030 /* dir == 0,1,2,3 for an edge going L,U,R,D */
992 int dir = (d->y == d2->y) + 2*(d->x+d->y > d2->x+d2->y); 1031 int dir = (d->y == d2->y) + 2*(d->x+d->y > d2->x+d2->y);
993 int ei = e - g->edges; 1032 int ei = e->index;
994 if (b->edges[ei]) { 1033 if (b->edges[ei]) {
995 type |= 1 << dir; 1034 type |= 1 << dir;
996 neighbours[n] = d2 - g->dots; 1035 neighbours[n] = d2->index;
997 n++; 1036 n++;
998 } 1037 }
999 } 1038 }
@@ -1048,9 +1087,8 @@ static int pearl_loopgen_bias(void *vctx, char *board, int face)
1048 return ctx->score; 1087 return ctx->score;
1049} 1088}
1050 1089
1051static void pearl_loopgen(int w, int h, char *lines, random_state *rs) 1090static void pearl_loopgen(int w, int h, char *lines, random_state *rs, grid *g)
1052{ 1091{
1053 grid *g = grid_new(GRID_SQUARE, w-1, h-1, NULL);
1054 char *board = snewn(g->num_faces, char); 1092 char *board = snewn(g->num_faces, char);
1055 int i, s = g->tilesize; 1093 int i, s = g->tilesize;
1056 struct pearl_loopgen_bias_ctx biasctx; 1094 struct pearl_loopgen_bias_ctx biasctx;
@@ -1102,7 +1140,7 @@ static void pearl_loopgen(int w, int h, char *lines, random_state *rs)
1102 } 1140 }
1103 1141
1104 for (i = 0; i < g->num_edges; i++) { 1142 for (i = 0; i < g->num_edges; i++) {
1105 grid_edge *e = g->edges + i; 1143 grid_edge *e = g->edges[i];
1106 enum face_colour c1 = FACE_COLOUR(e->face1); 1144 enum face_colour c1 = FACE_COLOUR(e->face1);
1107 enum face_colour c2 = FACE_COLOUR(e->face2); 1145 enum face_colour c2 = FACE_COLOUR(e->face2);
1108 assert(c1 != FACE_GREY); 1146 assert(c1 != FACE_GREY);
@@ -1130,7 +1168,6 @@ static void pearl_loopgen(int w, int h, char *lines, random_state *rs)
1130 } 1168 }
1131 } 1169 }
1132 1170
1133 grid_free(g);
1134 sfree(board); 1171 sfree(board);
1135 1172
1136#if defined LOOPGEN_DIAGNOSTICS && !defined GENERATION_DIAGNOSTICS 1173#if defined LOOPGEN_DIAGNOSTICS && !defined GENERATION_DIAGNOSTICS
@@ -1153,11 +1190,11 @@ static void pearl_loopgen(int w, int h, char *lines, random_state *rs)
1153} 1190}
1154 1191
1155static int new_clues(const game_params *params, random_state *rs, 1192static int new_clues(const game_params *params, random_state *rs,
1156 char *clues, char *grid) 1193 char *clues, char *grid_out)
1157{ 1194{
1158 int w = params->w, h = params->h, diff = params->difficulty; 1195 int w = params->w, h = params->h, diff = params->difficulty;
1159 int ngen = 0, x, y, d, ret, i; 1196 int ngen = 0, x, y, d, ret, i;
1160 1197 grid *g = grid_new(GRID_SQUARE, w-1, h-1, NULL);
1161 1198
1162 /* 1199 /*
1163 * Difficulty exception: 5x5 Tricky is not generable (the 1200 * Difficulty exception: 5x5 Tricky is not generable (the
@@ -1168,13 +1205,13 @@ static int new_clues(const game_params *params, random_state *rs,
1168 1205
1169 while (1) { 1206 while (1) {
1170 ngen++; 1207 ngen++;
1171 pearl_loopgen(w, h, grid, rs); 1208 pearl_loopgen(w, h, grid_out, rs, g);
1172 1209
1173#ifdef GENERATION_DIAGNOSTICS 1210#ifdef GENERATION_DIAGNOSTICS
1174 printf("grid array:\n"); 1211 printf("grid array:\n");
1175 for (y = 0; y < h; y++) { 1212 for (y = 0; y < h; y++) {
1176 for (x = 0; x < w; x++) { 1213 for (x = 0; x < w; x++) {
1177 int type = grid[y*w+x]; 1214 int type = grid_out[y*w+x];
1178 char s[5], *p = s; 1215 char s[5], *p = s;
1179 if (type & L) *p++ = 'L'; 1216 if (type & L) *p++ = 'L';
1180 if (type & R) *p++ = 'R'; 1217 if (type & R) *p++ = 'R';
@@ -1193,7 +1230,7 @@ static int new_clues(const game_params *params, random_state *rs,
1193 */ 1230 */
1194 for (y = 0; y < h; y++) 1231 for (y = 0; y < h; y++)
1195 for (x = 0; x < w; x++) { 1232 for (x = 0; x < w; x++) {
1196 int type = grid[y*w+x]; 1233 int type = grid_out[y*w+x];
1197 1234
1198 clues[y*w+x] = NOCLUE; 1235 clues[y*w+x] = NOCLUE;
1199 1236
@@ -1207,7 +1244,7 @@ static int new_clues(const game_params *params, random_state *rs,
1207 for (d = 1; d <= 8; d += d) if (type & d) { 1244 for (d = 1; d <= 8; d += d) if (type & d) {
1208 int xx = x + DX(d), yy = y + DY(d); 1245 int xx = x + DX(d), yy = y + DY(d);
1209 assert(xx >= 0 && xx < w && yy >= 0 && yy < h); 1246 assert(xx >= 0 && xx < w && yy >= 0 && yy < h);
1210 if ((bLU|bLD|bRU|bRD) & (1 << grid[yy*w+xx])) 1247 if ((bLU|bLD|bRU|bRD) & (1 << grid_out[yy*w+xx]))
1211 break; 1248 break;
1212 } 1249 }
1213 if (d <= 8) /* we found one */ 1250 if (d <= 8) /* we found one */
@@ -1221,7 +1258,7 @@ static int new_clues(const game_params *params, random_state *rs,
1221 for (d = 1; d <= 8; d += d) if (type & d) { 1258 for (d = 1; d <= 8; d += d) if (type & d) {
1222 int xx = x + DX(d), yy = y + DY(d); 1259 int xx = x + DX(d), yy = y + DY(d);
1223 assert(xx >= 0 && xx < w && yy >= 0 && yy < h); 1260 assert(xx >= 0 && xx < w && yy >= 0 && yy < h);
1224 if (!((bLR|bUD) & (1 << grid[yy*w+xx]))) 1261 if (!((bLR|bUD) & (1 << grid_out[yy*w+xx])))
1225 break; 1262 break;
1226 } 1263 }
1227 if (d > 8) /* we didn't find a counterexample */ 1264 if (d > 8) /* we didn't find a counterexample */
@@ -1247,7 +1284,7 @@ static int new_clues(const game_params *params, random_state *rs,
1247 /* 1284 /*
1248 * See if we can solve the puzzle just like this. 1285 * See if we can solve the puzzle just like this.
1249 */ 1286 */
1250 ret = pearl_solve(w, h, clues, grid, diff, false); 1287 ret = pearl_solve(w, h, clues, grid_out, diff, false);
1251 assert(ret > 0); /* shouldn't be inconsistent! */ 1288 assert(ret > 0); /* shouldn't be inconsistent! */
1252 if (ret != 1) 1289 if (ret != 1)
1253 continue; /* go round and try again */ 1290 continue; /* go round and try again */
@@ -1256,7 +1293,7 @@ static int new_clues(const game_params *params, random_state *rs,
1256 * Check this puzzle isn't too easy. 1293 * Check this puzzle isn't too easy.
1257 */ 1294 */
1258 if (diff > DIFF_EASY) { 1295 if (diff > DIFF_EASY) {
1259 ret = pearl_solve(w, h, clues, grid, diff-1, false); 1296 ret = pearl_solve(w, h, clues, grid_out, diff-1, false);
1260 assert(ret > 0); 1297 assert(ret > 0);
1261 if (ret == 1) 1298 if (ret == 1)
1262 continue; /* too easy: try again */ 1299 continue; /* too easy: try again */
@@ -1323,7 +1360,7 @@ static int new_clues(const game_params *params, random_state *rs,
1323 clue = clues[y*w+x]; 1360 clue = clues[y*w+x];
1324 clues[y*w+x] = 0; /* try removing this clue */ 1361 clues[y*w+x] = 0; /* try removing this clue */
1325 1362
1326 ret = pearl_solve(w, h, clues, grid, diff, false); 1363 ret = pearl_solve(w, h, clues, grid_out, diff, false);
1327 assert(ret > 0); 1364 assert(ret > 0);
1328 if (ret != 1) 1365 if (ret != 1)
1329 clues[y*w+x] = clue; /* oops, put it back again */ 1366 clues[y*w+x] = clue; /* oops, put it back again */
@@ -1344,6 +1381,7 @@ static int new_clues(const game_params *params, random_state *rs,
1344 1381
1345 break; /* got it */ 1382 break; /* got it */
1346 } 1383 }
1384 grid_free(g);
1347 1385
1348 debug(("%d %dx%d loops before finished puzzle.\n", ngen, w, h)); 1386 debug(("%d %dx%d loops before finished puzzle.\n", ngen, w, h));
1349 1387
@@ -1491,29 +1529,35 @@ static char nbits[16] = { 0, 1, 1, 2,
1491 1529
1492#define ERROR_CLUE 16 1530#define ERROR_CLUE 16
1493 1531
1494static void dsf_update_completion(game_state *state, int ax, int ay, char dir, 1532/* Returns false if the state is invalid. */
1495 int *dsf) 1533static bool dsf_update_completion(game_state *state, int ax, int ay, char dir,
1534 DSF *dsf)
1496{ 1535{
1497 int w = state->shared->w /*, h = state->shared->h */; 1536 int w = state->shared->w /*, h = state->shared->h */;
1498 int ac = ay*w+ax, bx, by, bc; 1537 int ac = ay*w+ax, bx, by, bc;
1499 1538
1500 if (!(state->lines[ac] & dir)) return; /* no link */ 1539 if (!(state->lines[ac] & dir)) return true; /* no link */
1501 bx = ax + DX(dir); by = ay + DY(dir); 1540 bx = ax + DX(dir); by = ay + DY(dir);
1502 1541
1503 assert(INGRID(state, bx, by)); /* should not have a link off grid */ 1542 if (!INGRID(state, bx, by))
1543 return false; /* should not have a link off grid */
1504 1544
1505 bc = by*w+bx; 1545 bc = by*w+bx;
1506 assert(state->lines[bc] & F(dir)); /* should have reciprocal link */ 1546 if (!(state->lines[bc] & F(dir)))
1507 if (!(state->lines[bc] & F(dir))) return; 1547 return false; /* should have reciprocal link */
1548 if (!(state->lines[bc] & F(dir))) return true;
1508 1549
1509 dsf_merge(dsf, ac, bc); 1550 dsf_merge(dsf, ac, bc);
1551 return true;
1510} 1552}
1511 1553
1512static void check_completion(game_state *state, bool mark) 1554/* Returns false if the state is invalid. */
1555static bool check_completion(game_state *state, bool mark)
1513{ 1556{
1514 int w = state->shared->w, h = state->shared->h, x, y, i, d; 1557 int w = state->shared->w, h = state->shared->h, x, y, i, d;
1515 bool had_error = false; 1558 bool had_error = false;
1516 int *dsf, *component_state; 1559 DSF *dsf;
1560 int *component_state;
1517 int nsilly, nloop, npath, largest_comp, largest_size, total_pathsize; 1561 int nsilly, nloop, npath, largest_comp, largest_size, total_pathsize;
1518 enum { COMP_NONE, COMP_LOOP, COMP_PATH, COMP_SILLY, COMP_EMPTY }; 1562 enum { COMP_NONE, COMP_LOOP, COMP_PATH, COMP_SILLY, COMP_EMPTY };
1519 1563
@@ -1532,13 +1576,16 @@ static void check_completion(game_state *state, bool mark)
1532 * same reasons, since Loopy and Pearl have basically the same 1576 * same reasons, since Loopy and Pearl have basically the same
1533 * form of expected solution. 1577 * form of expected solution.
1534 */ 1578 */
1535 dsf = snew_dsf(w*h); 1579 dsf = dsf_new(w*h);
1536 1580
1537 /* Build the dsf. */ 1581 /* Build the dsf. */
1538 for (x = 0; x < w; x++) { 1582 for (x = 0; x < w; x++) {
1539 for (y = 0; y < h; y++) { 1583 for (y = 0; y < h; y++) {
1540 dsf_update_completion(state, x, y, R, dsf); 1584 if (!dsf_update_completion(state, x, y, R, dsf) ||
1541 dsf_update_completion(state, x, y, D, dsf); 1585 !dsf_update_completion(state, x, y, D, dsf)) {
1586 dsf_free(dsf);
1587 return false;
1588 }
1542 } 1589 }
1543 } 1590 }
1544 1591
@@ -1619,7 +1666,7 @@ static void check_completion(game_state *state, bool mark)
1619 * part of a single loop, for which our counter variables 1666 * part of a single loop, for which our counter variables
1620 * nsilly,nloop,npath are enough. */ 1667 * nsilly,nloop,npath are enough. */
1621 sfree(component_state); 1668 sfree(component_state);
1622 sfree(dsf); 1669 dsf_free(dsf);
1623 1670
1624 /* 1671 /*
1625 * Check that no clues are contradicted. This code is similar to 1672 * Check that no clues are contradicted. This code is similar to
@@ -1693,6 +1740,7 @@ static void check_completion(game_state *state, bool mark)
1693 if (!had_error) 1740 if (!had_error)
1694 state->completed = true; 1741 state->completed = true;
1695 } 1742 }
1743 return true;
1696} 1744}
1697 1745
1698/* completion check: 1746/* completion check:
@@ -1810,18 +1858,53 @@ struct game_ui {
1810 1858
1811 int curx, cury; /* grid position of keyboard cursor */ 1859 int curx, cury; /* grid position of keyboard cursor */
1812 bool cursor_active; /* true iff cursor is shown */ 1860 bool cursor_active; /* true iff cursor is shown */
1861
1862 /*
1863 * User preference: general visual style of the GUI. GUI_MASYU is
1864 * how this puzzle is traditionally presented, with clue dots in
1865 * the middle of grid squares, and the solution loop connecting
1866 * square-centres. GUI_LOOPY shifts the grid by half a square in
1867 * each direction, so that the clue dots are at _vertices_ of the
1868 * grid and the solution loop follows the grid edges, which you
1869 * could argue is more logical.
1870 */
1871 enum { GUI_MASYU, GUI_LOOPY } gui_style;
1813}; 1872};
1814 1873
1874static void legacy_prefs_override(struct game_ui *ui_out)
1875{
1876 static bool initialised = false;
1877 static int gui_style = -1;
1878
1879 if (!initialised) {
1880 initialised = true;
1881
1882 switch (getenv_bool("PEARL_GUI_LOOPY", -1)) {
1883 case 0:
1884 gui_style = GUI_MASYU;
1885 break;
1886 case 1:
1887 gui_style = GUI_LOOPY;
1888 break;
1889 }
1890 }
1891
1892 if (gui_style != -1)
1893 ui_out->gui_style = gui_style;
1894}
1895
1815static game_ui *new_ui(const game_state *state) 1896static game_ui *new_ui(const game_state *state)
1816{ 1897{
1817 game_ui *ui = snew(game_ui); 1898 game_ui *ui = snew(game_ui);
1818 int sz = state->shared->sz;
1819 1899
1820 ui->ndragcoords = -1; 1900 ui->ndragcoords = -1;
1821 ui->dragcoords = snewn(sz, int); 1901 ui->dragcoords = state ? snewn(state->shared->sz, int) : NULL;
1822 ui->cursor_active = false; 1902 ui->cursor_active = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1823 ui->curx = ui->cury = 0; 1903 ui->curx = ui->cury = 0;
1824 1904
1905 ui->gui_style = GUI_MASYU;
1906 legacy_prefs_override(ui);
1907
1825 return ui; 1908 return ui;
1826} 1909}
1827 1910
@@ -1831,13 +1914,28 @@ static void free_ui(game_ui *ui)
1831 sfree(ui); 1914 sfree(ui);
1832} 1915}
1833 1916
1834static char *encode_ui(const game_ui *ui) 1917static config_item *get_prefs(game_ui *ui)
1835{ 1918{
1836 return NULL; 1919 config_item *ret;
1920
1921 ret = snewn(2, config_item);
1922
1923 ret[0].name = "Puzzle appearance";
1924 ret[0].kw = "appearance";
1925 ret[0].type = C_CHOICES;
1926 ret[0].u.choices.choicenames = ":Traditional:Loopy-style";
1927 ret[0].u.choices.choicekws = ":traditional:loopy";
1928 ret[0].u.choices.selected = ui->gui_style;
1929
1930 ret[1].name = NULL;
1931 ret[1].type = C_END;
1932
1933 return ret;
1837} 1934}
1838 1935
1839static void decode_ui(game_ui *ui, const char *encoding) 1936static void set_prefs(game_ui *ui, const config_item *cfg)
1840{ 1937{
1938 ui->gui_style = cfg[0].u.choices.selected;
1841} 1939}
1842 1940
1843static void game_changed_state(game_ui *ui, const game_state *oldstate, 1941static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -1845,11 +1943,25 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1845{ 1943{
1846} 1944}
1847 1945
1946static const char *current_key_label(const game_ui *ui,
1947 const game_state *state, int button)
1948{
1949 if (IS_CURSOR_SELECT(button) && ui->cursor_active) {
1950 if (button == CURSOR_SELECT) {
1951 if (ui->ndragcoords == -1) return "Start";
1952 return "Stop";
1953 }
1954 if (button == CURSOR_SELECT2 && ui->ndragcoords >= 0)
1955 return "Cancel";
1956 }
1957 return "";
1958}
1959
1848#define PREFERRED_TILE_SIZE 31 1960#define PREFERRED_TILE_SIZE 31
1849#define HALFSZ (ds->halfsz) 1961#define HALFSZ (ds->halfsz)
1850#define TILE_SIZE (ds->halfsz*2 + 1) 1962#define TILE_SIZE (ds->halfsz*2 + 1)
1851 1963
1852#define BORDER ((get_gui_style() == GUI_LOOPY) ? (TILE_SIZE/8) : (TILE_SIZE/2)) 1964#define BORDER ((ui->gui_style == GUI_LOOPY) ? (TILE_SIZE/8) : (TILE_SIZE/2))
1853 1965
1854#define BORDER_WIDTH (max(TILE_SIZE / 32, 1)) 1966#define BORDER_WIDTH (max(TILE_SIZE / 32, 1))
1855 1967
@@ -1865,22 +1977,6 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1865#define DS_FLASH (1 << 21) 1977#define DS_FLASH (1 << 21)
1866#define DS_CURSOR (1 << 22) 1978#define DS_CURSOR (1 << 22)
1867 1979
1868enum { GUI_MASYU, GUI_LOOPY };
1869
1870static int get_gui_style(void)
1871{
1872 static int gui_style = -1;
1873
1874 if (gui_style == -1) {
1875 char *env = getenv("PEARL_GUI_LOOPY");
1876 if (env && (env[0] == 'y' || env[0] == 'Y'))
1877 gui_style = GUI_LOOPY;
1878 else
1879 gui_style = GUI_MASYU;
1880 }
1881 return gui_style;
1882}
1883
1884struct game_drawstate { 1980struct game_drawstate {
1885 int halfsz; 1981 int halfsz;
1886 bool started; 1982 bool started;
@@ -1891,6 +1987,56 @@ struct game_drawstate {
1891 char *draglines; /* size w*h; lines flipped by current drag */ 1987 char *draglines; /* size w*h; lines flipped by current drag */
1892}; 1988};
1893 1989
1990/*
1991 * Routine shared between multiple callers to work out the intended
1992 * effect of a drag path on the grid.
1993 *
1994 * Call it in a loop, like this:
1995 *
1996 * bool clearing = true;
1997 * for (i = 0; i < ui->ndragcoords - 1; i++) {
1998 * int sx, sy, dx, dy, dir, oldstate, newstate;
1999 * interpret_ui_drag(state, ui, &clearing, i, &sx, &sy, &dx, &dy,
2000 * &dir, &oldstate, &newstate);
2001 *
2002 * [do whatever is needed to handle the fact that the drag
2003 * wants the edge from sx,sy to dx,dy (heading in direction
2004 * 'dir' at the sx,sy end) to be changed from state oldstate
2005 * to state newstate, each of which equals either 0 or dir]
2006 * }
2007 */
2008static void interpret_ui_drag(const game_state *state, const game_ui *ui,
2009 bool *clearing, int i, int *sx, int *sy,
2010 int *dx, int *dy, int *dir,
2011 int *oldstate, int *newstate)
2012{
2013 int w = state->shared->w;
2014 int sp = ui->dragcoords[i], dp = ui->dragcoords[i+1];
2015 *sy = sp/w;
2016 *sx = sp%w;
2017 *dy = dp/w;
2018 *dx = dp%w;
2019 *dir = (*dy>*sy ? D : *dy<*sy ? U : *dx>*sx ? R : L);
2020 *oldstate = state->lines[sp] & *dir;
2021 if (*oldstate) {
2022 /*
2023 * The edge we've dragged over was previously
2024 * present. Set it to absent, unless we've already
2025 * stopped doing that.
2026 */
2027 *newstate = *clearing ? 0 : *dir;
2028 } else {
2029 /*
2030 * The edge we've dragged over was previously
2031 * absent. Set it to present, and cancel the
2032 * 'clearing' flag so that all subsequent edges in
2033 * the drag are set rather than cleared.
2034 */
2035 *newstate = *dir;
2036 *clearing = false;
2037 }
2038}
2039
1894static void update_ui_drag(const game_state *state, game_ui *ui, 2040static void update_ui_drag(const game_state *state, game_ui *ui,
1895 int gx, int gy) 2041 int gx, int gy)
1896{ 2042{
@@ -1919,13 +2065,42 @@ static void update_ui_drag(const game_state *state, game_ui *ui,
1919 * the drag path so far has the effect of truncating the path back 2065 * the drag path so far has the effect of truncating the path back
1920 * to that square, so a player can back out part of an uncommitted 2066 * to that square, so a player can back out part of an uncommitted
1921 * drag without having to let go of the mouse. 2067 * drag without having to let go of the mouse.
2068 *
2069 * An exception is that you're allowed to drag round in a loop
2070 * back to the very start of the drag, provided that doesn't
2071 * create a vertex of the wrong degree. This allows a player who's
2072 * after an extra challenge to draw the entire loop in a single
2073 * drag, without it cancelling itself just before release.
1922 */ 2074 */
1923 for (i = 0; i < ui->ndragcoords; i++) 2075 for (i = 1; i < ui->ndragcoords; i++)
1924 if (pos == ui->dragcoords[i]) { 2076 if (pos == ui->dragcoords[i]) {
1925 ui->ndragcoords = i+1; 2077 ui->ndragcoords = i+1;
1926 return; 2078 return;
1927 } 2079 }
1928 2080
2081 if (pos == ui->dragcoords[0]) {
2082 /* More complex check for a loop-shaped drag, which has to go
2083 * through interpret_ui_drag to decide on the final degree of
2084 * the start/end vertex. */
2085 ui->dragcoords[ui->ndragcoords] = pos;
2086 bool clearing = true;
2087 int lines = state->lines[pos] & (L|R|U|D);
2088 for (i = 0; i < ui->ndragcoords; i++) {
2089 int sx, sy, dx, dy, dir, oldstate, newstate;
2090 interpret_ui_drag(state, ui, &clearing, i, &sx, &sy, &dx, &dy,
2091 &dir, &oldstate, &newstate);
2092 if (sx == gx && sy == gy)
2093 lines ^= (oldstate ^ newstate);
2094 if (dx == gx && dy == gy)
2095 lines ^= (F(oldstate) ^ F(newstate));
2096 }
2097 if (NBITS(lines) > 2) {
2098 /* Bad vertex degree: fall back to the backtracking behaviour. */
2099 ui->ndragcoords = 1;
2100 return;
2101 }
2102 }
2103
1929 /* 2104 /*
1930 * Otherwise, dragging the mouse into a square that's a rook-move 2105 * Otherwise, dragging the mouse into a square that's a rook-move
1931 * away from the last one on the path extends the path. 2106 * away from the last one on the path extends the path.
@@ -1958,56 +2133,6 @@ static void update_ui_drag(const game_state *state, game_ui *ui,
1958 */ 2133 */
1959} 2134}
1960 2135
1961/*
1962 * Routine shared between interpret_move and game_redraw to work out
1963 * the intended effect of a drag path on the grid.
1964 *
1965 * Call it in a loop, like this:
1966 *
1967 * bool clearing = true;
1968 * for (i = 0; i < ui->ndragcoords - 1; i++) {
1969 * int sx, sy, dx, dy, dir, oldstate, newstate;
1970 * interpret_ui_drag(state, ui, &clearing, i, &sx, &sy, &dx, &dy,
1971 * &dir, &oldstate, &newstate);
1972 *
1973 * [do whatever is needed to handle the fact that the drag
1974 * wants the edge from sx,sy to dx,dy (heading in direction
1975 * 'dir' at the sx,sy end) to be changed from state oldstate
1976 * to state newstate, each of which equals either 0 or dir]
1977 * }
1978 */
1979static void interpret_ui_drag(const game_state *state, const game_ui *ui,
1980 bool *clearing, int i, int *sx, int *sy,
1981 int *dx, int *dy, int *dir,
1982 int *oldstate, int *newstate)
1983{
1984 int w = state->shared->w;
1985 int sp = ui->dragcoords[i], dp = ui->dragcoords[i+1];
1986 *sy = sp/w;
1987 *sx = sp%w;
1988 *dy = dp/w;
1989 *dx = dp%w;
1990 *dir = (*dy>*sy ? D : *dy<*sy ? U : *dx>*sx ? R : L);
1991 *oldstate = state->lines[sp] & *dir;
1992 if (*oldstate) {
1993 /*
1994 * The edge we've dragged over was previously
1995 * present. Set it to absent, unless we've already
1996 * stopped doing that.
1997 */
1998 *newstate = *clearing ? 0 : *dir;
1999 } else {
2000 /*
2001 * The edge we've dragged over was previously
2002 * absent. Set it to present, and cancel the
2003 * 'clearing' flag so that all subsequent edges in
2004 * the drag are set rather than cleared.
2005 */
2006 *newstate = *dir;
2007 *clearing = false;
2008 }
2009}
2010
2011static char *mark_in_direction(const game_state *state, int x, int y, int dir, 2136static char *mark_in_direction(const game_state *state, int x, int y, int dir,
2012 bool primary, char *buf) 2137 bool primary, char *buf)
2013{ 2138{
@@ -2018,11 +2143,11 @@ static char *mark_in_direction(const game_state *state, int x, int y, int dir,
2018 2143
2019 char ch = primary ? 'F' : 'M', *other; 2144 char ch = primary ? 'F' : 'M', *other;
2020 2145
2021 if (!INGRID(state, x, y) || !INGRID(state, x2, y2)) return UI_UPDATE; 2146 if (!INGRID(state, x, y) || !INGRID(state, x2, y2)) return MOVE_UI_UPDATE;
2022 2147
2023 /* disallow laying a mark over a line, or vice versa. */ 2148 /* disallow laying a mark over a line, or vice versa. */
2024 other = primary ? state->marks : state->lines; 2149 other = primary ? state->marks : state->lines;
2025 if (other[y*w+x] & dir || other[y2*w+x2] & dir2) return UI_UPDATE; 2150 if (other[y*w+x] & dir || other[y2*w+x2] & dir2) return MOVE_UI_UPDATE;
2026 2151
2027 sprintf(buf, "%c%d,%d,%d;%c%d,%d,%d", ch, dir, x, y, ch, dir2, x2, y2); 2152 sprintf(buf, "%c%d,%d,%d;%c%d,%d,%d", ch, dir, x, y, ch, dir2, x2, y2);
2028 return dupstr(buf); 2153 return dupstr(buf);
@@ -2042,26 +2167,26 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2042 char tmpbuf[80]; 2167 char tmpbuf[80];
2043 2168
2044 bool shift = button & MOD_SHFT, control = button & MOD_CTRL; 2169 bool shift = button & MOD_SHFT, control = button & MOD_CTRL;
2045 button &= ~MOD_MASK; 2170 button = STRIP_BUTTON_MODIFIERS(button);
2046 2171
2047 if (IS_MOUSE_DOWN(button)) { 2172 if (IS_MOUSE_DOWN(button)) {
2048 ui->cursor_active = false; 2173 ui->cursor_active = false;
2049 2174
2050 if (!INGRID(state, gx, gy)) { 2175 if (!INGRID(state, gx, gy)) {
2051 ui->ndragcoords = -1; 2176 ui->ndragcoords = -1;
2052 return NULL; 2177 return MOVE_UI_UPDATE;
2053 } 2178 }
2054 2179
2055 ui->clickx = x; ui->clicky = y; 2180 ui->clickx = x; ui->clicky = y;
2056 ui->dragcoords[0] = gy * w + gx; 2181 ui->dragcoords[0] = gy * w + gx;
2057 ui->ndragcoords = 0; /* will be 1 once drag is confirmed */ 2182 ui->ndragcoords = 0; /* will be 1 once drag is confirmed */
2058 2183
2059 return UI_UPDATE; 2184 return MOVE_UI_UPDATE;
2060 } 2185 }
2061 2186
2062 if (button == LEFT_DRAG && ui->ndragcoords >= 0) { 2187 if (button == LEFT_DRAG && ui->ndragcoords >= 0) {
2063 update_ui_drag(state, ui, gx, gy); 2188 update_ui_drag(state, ui, gx, gy);
2064 return UI_UPDATE; 2189 return MOVE_UI_UPDATE;
2065 } 2190 }
2066 2191
2067 if (IS_MOUSE_RELEASE(button)) release = true; 2192 if (IS_MOUSE_RELEASE(button)) release = true;
@@ -2071,42 +2196,48 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2071 ui->cursor_active = true; 2196 ui->cursor_active = true;
2072 } else if (control || shift) { 2197 } else if (control || shift) {
2073 char *move; 2198 char *move;
2074 if (ui->ndragcoords > 0) return NULL; 2199 if (ui->ndragcoords > 0) return MOVE_NO_EFFECT;
2075 ui->ndragcoords = -1; 2200 ui->ndragcoords = -1;
2076 move = mark_in_direction(state, ui->curx, ui->cury, 2201 move = mark_in_direction(state, ui->curx, ui->cury,
2077 KEY_DIRECTION(button), control, tmpbuf); 2202 KEY_DIRECTION(button), control, tmpbuf);
2078 if (control && !shift && *move) 2203 if (control && !shift && *move)
2079 move_cursor(button, &ui->curx, &ui->cury, w, h, false); 2204 move_cursor(button, &ui->curx, &ui->cury, w, h, false, NULL);
2080 return move; 2205 return move;
2081 } else { 2206 } else {
2082 move_cursor(button, &ui->curx, &ui->cury, w, h, false); 2207 move_cursor(button, &ui->curx, &ui->cury, w, h, false, NULL);
2083 if (ui->ndragcoords >= 0) 2208 if (ui->ndragcoords >= 0)
2084 update_ui_drag(state, ui, ui->curx, ui->cury); 2209 update_ui_drag(state, ui, ui->curx, ui->cury);
2085 } 2210 }
2086 return UI_UPDATE; 2211 return MOVE_UI_UPDATE;
2087 } 2212 }
2088 2213
2089 if (IS_CURSOR_SELECT(button)) { 2214 if (IS_CURSOR_SELECT(button)) {
2090 if (!ui->cursor_active) { 2215 if (!ui->cursor_active) {
2091 ui->cursor_active = true; 2216 ui->cursor_active = true;
2092 return UI_UPDATE; 2217 return MOVE_UI_UPDATE;
2093 } else if (button == CURSOR_SELECT) { 2218 } else if (button == CURSOR_SELECT) {
2094 if (ui->ndragcoords == -1) { 2219 if (ui->ndragcoords == -1) {
2095 ui->ndragcoords = 0; 2220 ui->ndragcoords = 0;
2096 ui->dragcoords[0] = ui->cury * w + ui->curx; 2221 ui->dragcoords[0] = ui->cury * w + ui->curx;
2097 ui->clickx = CENTERED_COORD(ui->curx); 2222 ui->clickx = CENTERED_COORD(ui->curx);
2098 ui->clicky = CENTERED_COORD(ui->cury); 2223 ui->clicky = CENTERED_COORD(ui->cury);
2099 return UI_UPDATE; 2224 return MOVE_UI_UPDATE;
2100 } else release = true; 2225 } else release = true;
2101 } else if (button == CURSOR_SELECT2 && ui->ndragcoords >= 0) { 2226 } else if (button == CURSOR_SELECT2) {
2102 ui->ndragcoords = -1; 2227 if (ui->ndragcoords >= 0) {
2103 return UI_UPDATE; 2228 ui->ndragcoords = -1;
2104 } 2229 return MOVE_UI_UPDATE;
2230 }
2231 return MOVE_NO_EFFECT;
2232 }
2105 } 2233 }
2106 2234
2107 if (button == 27 || button == '\b') { 2235 if (button == 27 || button == '\b') {
2108 ui->ndragcoords = -1; 2236 if (ui->ndragcoords >= 0) {
2109 return UI_UPDATE; 2237 ui->ndragcoords = -1;
2238 return MOVE_UI_UPDATE;
2239 }
2240 return MOVE_NO_EFFECT;
2110 } 2241 }
2111 2242
2112 if (release) { 2243 if (release) {
@@ -2138,7 +2269,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2138 2269
2139 ui->ndragcoords = -1; 2270 ui->ndragcoords = -1;
2140 2271
2141 return buf ? buf : UI_UPDATE; 2272 return buf ? buf : MOVE_UI_UPDATE;
2142 } else if (ui->ndragcoords == 0) { 2273 } else if (ui->ndragcoords == 0) {
2143 /* Click (or tiny drag). Work out which edge we were 2274 /* Click (or tiny drag). Work out which edge we were
2144 * closest to. */ 2275 * closest to. */
@@ -2159,12 +2290,12 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2159 cx = CENTERED_COORD(gx); 2290 cx = CENTERED_COORD(gx);
2160 cy = CENTERED_COORD(gy); 2291 cy = CENTERED_COORD(gy);
2161 2292
2162 if (!INGRID(state, gx, gy)) return UI_UPDATE; 2293 if (!INGRID(state, gx, gy)) return MOVE_UI_UPDATE;
2163 2294
2164 if (max(abs(x-cx),abs(y-cy)) < TILE_SIZE/4) { 2295 if (max(abs(x-cx),abs(y-cy)) < TILE_SIZE/4) {
2165 /* TODO closer to centre of grid: process as a cell click not an edge click. */ 2296 /* TODO closer to centre of grid: process as a cell click not an edge click. */
2166 2297
2167 return UI_UPDATE; 2298 return MOVE_UI_UPDATE;
2168 } else { 2299 } else {
2169 int direction; 2300 int direction;
2170 if (abs(x-cx) < abs(y-cy)) { 2301 if (abs(x-cx) < abs(y-cy)) {
@@ -2183,7 +2314,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2183 if (button == 'H' || button == 'h') 2314 if (button == 'H' || button == 'h')
2184 return dupstr("H"); 2315 return dupstr("H");
2185 2316
2186 return NULL; 2317 return MOVE_UNUSED;
2187} 2318}
2188 2319
2189static game_state *execute_move(const game_state *state, const char *move) 2320static game_state *execute_move(const game_state *state, const char *move)
@@ -2246,7 +2377,7 @@ static game_state *execute_move(const game_state *state, const char *move)
2246 goto badmove; 2377 goto badmove;
2247 } 2378 }
2248 2379
2249 check_completion(ret, true); 2380 if (!check_completion(ret, true)) goto badmove;
2250 2381
2251 return ret; 2382 return ret;
2252 2383
@@ -2262,7 +2393,7 @@ badmove:
2262#define FLASH_TIME 0.5F 2393#define FLASH_TIME 0.5F
2263 2394
2264static void game_compute_size(const game_params *params, int tilesize, 2395static void game_compute_size(const game_params *params, int tilesize,
2265 int *x, int *y) 2396 const game_ui *ui, int *x, int *y)
2266{ 2397{
2267 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2398 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2268 struct { int halfsz; } ads, *ds = &ads; 2399 struct { int halfsz; } ads, *ds = &ads;
@@ -2340,8 +2471,8 @@ static void game_free_drawstate(drawing *dr, game_drawstate *ds)
2340} 2471}
2341 2472
2342static void draw_lines_specific(drawing *dr, game_drawstate *ds, 2473static void draw_lines_specific(drawing *dr, game_drawstate *ds,
2343 int x, int y, unsigned int lflags, 2474 const game_ui *ui, int x, int y,
2344 unsigned int shift, int c) 2475 unsigned int lflags, unsigned int shift, int c)
2345{ 2476{
2346 int ox = COORD(x), oy = COORD(y); 2477 int ox = COORD(x), oy = COORD(y);
2347 int t2 = HALFSZ, t16 = HALFSZ/4; 2478 int t2 = HALFSZ, t16 = HALFSZ/4;
@@ -2390,7 +2521,7 @@ static void draw_square(drawing *dr, game_drawstate *ds, const game_ui *ui,
2390 COL_CURSOR_BACKGROUND : COL_BACKGROUND); 2521 COL_CURSOR_BACKGROUND : COL_BACKGROUND);
2391 2522
2392 2523
2393 if (get_gui_style() == GUI_LOOPY) { 2524 if (ui->gui_style == GUI_LOOPY) {
2394 /* Draw small dot, underneath any lines. */ 2525 /* Draw small dot, underneath any lines. */
2395 draw_circle(dr, cx, cy, t16, COL_GRID, COL_GRID); 2526 draw_circle(dr, cx, cy, t16, COL_GRID, COL_GRID);
2396 } else { 2527 } else {
@@ -2417,7 +2548,7 @@ static void draw_square(drawing *dr, game_drawstate *ds, const game_ui *ui,
2417 draw_line(dr, mx-msz, my-msz, mx+msz, my+msz, COL_BLACK); 2548 draw_line(dr, mx-msz, my-msz, mx+msz, my+msz, COL_BLACK);
2418 draw_line(dr, mx-msz, my+msz, mx+msz, my-msz, COL_BLACK); 2549 draw_line(dr, mx-msz, my+msz, mx+msz, my-msz, COL_BLACK);
2419 } else { 2550 } else {
2420 if (get_gui_style() == GUI_LOOPY) { 2551 if (ui->gui_style == GUI_LOOPY) {
2421 /* draw grid lines connecting centre of cells */ 2552 /* draw grid lines connecting centre of cells */
2422 draw_line(dr, cx, cy, cx+xoff, cy+yoff, COL_GRID); 2553 draw_line(dr, cx, cy, cx+xoff, cy+yoff, COL_GRID);
2423 } 2554 }
@@ -2427,11 +2558,11 @@ static void draw_square(drawing *dr, game_drawstate *ds, const game_ui *ui,
2427 /* Draw each of the four directions, where laid (or error, or drag, etc.) 2558 /* Draw each of the four directions, where laid (or error, or drag, etc.)
2428 * Order is important here, specifically for the eventual colours of the 2559 * Order is important here, specifically for the eventual colours of the
2429 * exposed end caps. */ 2560 * exposed end caps. */
2430 draw_lines_specific(dr, ds, x, y, lflags, 0, 2561 draw_lines_specific(dr, ds, ui, x, y, lflags, 0,
2431 (lflags & DS_FLASH ? COL_FLASH : COL_BLACK)); 2562 (lflags & DS_FLASH ? COL_FLASH : COL_BLACK));
2432 draw_lines_specific(dr, ds, x, y, lflags, DS_ESHIFT, COL_ERROR); 2563 draw_lines_specific(dr, ds, ui, x, y, lflags, DS_ESHIFT, COL_ERROR);
2433 draw_lines_specific(dr, ds, x, y, lflags, DS_DSHIFT, COL_DRAGOFF); 2564 draw_lines_specific(dr, ds, ui, x, y, lflags, DS_DSHIFT, COL_DRAGOFF);
2434 draw_lines_specific(dr, ds, x, y, lflags, DS_DSHIFT, COL_DRAGON); 2565 draw_lines_specific(dr, ds, ui, x, y, lflags, DS_DSHIFT, COL_DRAGON);
2435 2566
2436 /* Draw a clue, if present */ 2567 /* Draw a clue, if present */
2437 if (clue != NOCLUE) { 2568 if (clue != NOCLUE) {
@@ -2458,18 +2589,9 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2458 bool force = false; 2589 bool force = false;
2459 2590
2460 if (!ds->started) { 2591 if (!ds->started) {
2461 /* 2592 if (ui->gui_style == GUI_MASYU) {
2462 * The initial contents of the window are not guaranteed and
2463 * can vary with front ends. To be on the safe side, all games
2464 * should start by drawing a big background-colour rectangle
2465 * covering the whole window.
2466 */
2467 draw_rect(dr, 0, 0, w*TILE_SIZE + 2*BORDER, h*TILE_SIZE + 2*BORDER,
2468 COL_BACKGROUND);
2469
2470 if (get_gui_style() == GUI_MASYU) {
2471 /* 2593 /*
2472 * Smaller black rectangle which is the main grid. 2594 * Black rectangle which is the main grid.
2473 */ 2595 */
2474 draw_rect(dr, BORDER - BORDER_WIDTH, BORDER - BORDER_WIDTH, 2596 draw_rect(dr, BORDER - BORDER_WIDTH, BORDER - BORDER_WIDTH,
2475 w*TILE_SIZE + 2*BORDER_WIDTH + 1, 2597 w*TILE_SIZE + 2*BORDER_WIDTH + 1,
@@ -2560,47 +2682,64 @@ static int game_status(const game_state *state)
2560 return state->completed ? +1 : 0; 2682 return state->completed ? +1 : 0;
2561} 2683}
2562 2684
2563static bool game_timing_state(const game_state *state, game_ui *ui) 2685static void game_print_size(const game_params *params, const game_ui *ui,
2564{ 2686 float *x, float *y)
2565 return true;
2566}
2567
2568static void game_print_size(const game_params *params, float *x, float *y)
2569{ 2687{
2570 int pw, ph; 2688 int pw, ph;
2571 2689
2572 /* 2690 /*
2573 * I'll use 6mm squares by default. 2691 * I'll use 6mm squares by default.
2574 */ 2692 */
2575 game_compute_size(params, 600, &pw, &ph); 2693 game_compute_size(params, 600, ui, &pw, &ph);
2576 *x = pw / 100.0F; 2694 *x = pw / 100.0F;
2577 *y = ph / 100.0F; 2695 *y = ph / 100.0F;
2578} 2696}
2579 2697
2580static void game_print(drawing *dr, const game_state *state, int tilesize) 2698static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2699 int tilesize)
2581{ 2700{
2582 int w = state->shared->w, h = state->shared->h, x, y; 2701 int w = state->shared->w, h = state->shared->h, x, y;
2583 int black = print_mono_colour(dr, 0); 2702 int black = print_mono_colour(dr, 0);
2584 int white = print_mono_colour(dr, 1); 2703 int white = print_mono_colour(dr, 1);
2585 2704
2586 /* No GUI_LOOPY here: only use the familiar masyu style. */
2587
2588 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2705 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2589 game_drawstate *ds = game_new_drawstate(dr, state); 2706 game_drawstate *ds = game_new_drawstate(dr, state);
2590 game_set_size(dr, ds, NULL, tilesize); 2707 game_set_size(dr, ds, NULL, tilesize);
2591 2708
2592 /* Draw grid outlines (black). */ 2709 if (ui->gui_style == GUI_MASYU) {
2593 for (x = 0; x <= w; x++) 2710 /* Draw grid outlines (black). */
2594 draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), black); 2711 for (x = 0; x <= w; x++)
2595 for (y = 0; y <= h; y++) 2712 draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), black);
2596 draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), black); 2713 for (y = 0; y <= h; y++)
2714 draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), black);
2715 } else {
2716 /* Draw small dots, and dotted lines connecting them. For
2717 * added clarity, try to start and end the dotted lines a
2718 * little way away from the dots. */
2719 print_line_width(dr, TILE_SIZE / 40);
2720 print_line_dotted(dr, true);
2721 for (x = 0; x < w; x++) {
2722 for (y = 0; y < h; y++) {
2723 int cx = COORD(x) + HALFSZ, cy = COORD(y) + HALFSZ;
2724 draw_circle(dr, cx, cy, tilesize/10, black, black);
2725 if (x+1 < w)
2726 draw_line(dr, cx+tilesize/5, cy,
2727 cx+tilesize-tilesize/5, cy, black);
2728 if (y+1 < h)
2729 draw_line(dr, cx, cy+tilesize/5,
2730 cx, cy+tilesize-tilesize/5, black);
2731 }
2732 }
2733 print_line_dotted(dr, false);
2734 }
2597 2735
2598 for (x = 0; x < w; x++) { 2736 for (x = 0; x < w; x++) {
2599 for (y = 0; y < h; y++) { 2737 for (y = 0; y < h; y++) {
2600 int cx = COORD(x) + HALFSZ, cy = COORD(y) + HALFSZ; 2738 int cx = COORD(x) + HALFSZ, cy = COORD(y) + HALFSZ;
2601 int clue = state->shared->clues[y*w+x]; 2739 int clue = state->shared->clues[y*w+x];
2602 2740
2603 draw_lines_specific(dr, ds, x, y, state->lines[y*w+x], 0, black); 2741 draw_lines_specific(dr, ds, ui, x, y,
2742 state->lines[y*w+x], 0, black);
2604 2743
2605 if (clue != NOCLUE) { 2744 if (clue != NOCLUE) {
2606 int c = (clue == CORNER) ? black : white; 2745 int c = (clue == CORNER) ? black : white;
@@ -2633,12 +2772,14 @@ const struct game thegame = {
2633 free_game, 2772 free_game,
2634 true, solve_game, 2773 true, solve_game,
2635 true, game_can_format_as_text_now, game_text_format, 2774 true, game_can_format_as_text_now, game_text_format,
2775 get_prefs, set_prefs,
2636 new_ui, 2776 new_ui,
2637 free_ui, 2777 free_ui,
2638 encode_ui, 2778 NULL, /* encode_ui */
2639 decode_ui, 2779 NULL, /* decode_ui */
2640 NULL, /* game_request_keys */ 2780 NULL, /* game_request_keys */
2641 game_changed_state, 2781 game_changed_state,
2782 current_key_label,
2642 interpret_move, 2783 interpret_move,
2643 execute_move, 2784 execute_move,
2644 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 2785 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -2652,7 +2793,7 @@ const struct game thegame = {
2652 game_status, 2793 game_status,
2653 true, false, game_print_size, game_print, 2794 true, false, game_print_size, game_print,
2654 false, /* wants_statusbar */ 2795 false, /* wants_statusbar */
2655 false, game_timing_state, 2796 false, NULL, /* timing_state */
2656 0, /* flags */ 2797 0, /* flags */
2657}; 2798};
2658 2799
@@ -2661,7 +2802,7 @@ const struct game thegame = {
2661#include <time.h> 2802#include <time.h>
2662#include <stdarg.h> 2803#include <stdarg.h>
2663 2804
2664const char *quis = NULL; 2805static const char *quis = NULL;
2665 2806
2666static void usage(FILE *out) { 2807static void usage(FILE *out) {
2667 fprintf(out, "usage: %s <params>\n", quis); 2808 fprintf(out, "usage: %s <params>\n", quis);
@@ -2720,7 +2861,7 @@ static void start_soak(game_params *p, random_state *rs, int nsecs)
2720 sfree(clues); 2861 sfree(clues);
2721} 2862}
2722 2863
2723int main(int argc, const char *argv[]) 2864int main(int argc, char *argv[])
2724{ 2865{
2725 game_params *p = NULL; 2866 game_params *p = NULL;
2726 random_state *rs = NULL; 2867 random_state *rs = NULL;
diff --git a/apps/plugins/puzzles/src/pegs.R b/apps/plugins/puzzles/src/pegs.R
deleted file mode 100644
index 1e79e99ca0..0000000000
--- a/apps/plugins/puzzles/src/pegs.R
+++ /dev/null
@@ -1,21 +0,0 @@
1# -*- makefile -*-
2
3PEGS_EXTRA = tree234
4
5pegs : [X] GTK COMMON pegs PEGS_EXTRA pegs-icon|no-icon
6
7pegs : [G] WINDOWS COMMON pegs PEGS_EXTRA pegs.res|noicon.res
8
9ALL += pegs[COMBINED] PEGS_EXTRA
10
11!begin am gtk
12GAMES += pegs
13!end
14
15!begin >list.c
16 A(pegs) \
17!end
18
19!begin >gamedesc.txt
20pegs:pegs.exe:Pegs:Peg solitaire puzzle:Jump pegs over each other to remove all but one.
21!end
diff --git a/apps/plugins/puzzles/src/pegs.c b/apps/plugins/puzzles/src/pegs.c
index ec12aa9552..c770bf3076 100644
--- a/apps/plugins/puzzles/src/pegs.c
+++ b/apps/plugins/puzzles/src/pegs.c
@@ -7,7 +7,12 @@
7#include <string.h> 7#include <string.h>
8#include <assert.h> 8#include <assert.h>
9#include <ctype.h> 9#include <ctype.h>
10#include <math.h> 10#include <limits.h>
11#ifdef NO_TGMATH_H
12# include <math.h>
13#else
14# include <tgmath.h>
15#endif
11 16
12#include "puzzles.h" 17#include "puzzles.h"
13#include "tree234.h" 18#include "tree234.h"
@@ -70,7 +75,11 @@ static game_params *default_params(void)
70} 75}
71 76
72static const struct game_params pegs_presets[] = { 77static const struct game_params pegs_presets[] = {
78 {5, 7, TYPE_CROSS},
73 {7, 7, TYPE_CROSS}, 79 {7, 7, TYPE_CROSS},
80 {5, 9, TYPE_CROSS},
81 {7, 9, TYPE_CROSS},
82 {9, 9, TYPE_CROSS},
74 {7, 7, TYPE_OCTAGON}, 83 {7, 7, TYPE_OCTAGON},
75 {5, 5, TYPE_RANDOM}, 84 {5, 5, TYPE_RANDOM},
76 {7, 7, TYPE_RANDOM}, 85 {7, 7, TYPE_RANDOM},
@@ -89,7 +98,7 @@ static bool game_fetch_preset(int i, char **name, game_params **params)
89 *ret = pegs_presets[i]; 98 *ret = pegs_presets[i];
90 99
91 strcpy(str, pegs_titletypes[ret->type]); 100 strcpy(str, pegs_titletypes[ret->type]);
92 if (ret->type == TYPE_RANDOM) 101 if (ret->type == TYPE_CROSS || ret->type == TYPE_RANDOM)
93 sprintf(str + strlen(str), " %dx%d", ret->w, ret->h); 102 sprintf(str + strlen(str), " %dx%d", ret->w, ret->h);
94 103
95 *name = dupstr(str); 104 *name = dupstr(str);
@@ -182,14 +191,38 @@ static const char *validate_params(const game_params *params, bool full)
182{ 191{
183 if (full && (params->w <= 3 || params->h <= 3)) 192 if (full && (params->w <= 3 || params->h <= 3))
184 return "Width and height must both be greater than three"; 193 return "Width and height must both be greater than three";
194 if (params->w < 1 || params->h < 1)
195 return "Width and height must both be at least one";
196 if (params->w > INT_MAX / params->h)
197 return "Width times height must not be unreasonably large";
198
199 /*
200 * At http://www.gibell.net/pegsolitaire/GenCross/GenCrossBoards0.html
201 * George I. Bell asserts that various generalised cross-shaped
202 * boards are soluble starting (and finishing) with the centre
203 * hole. We permit the symmetric ones. Bell's notation for each
204 * soluble board is listed.
205 */
206 if (full && params->type == TYPE_CROSS) {
207 if (!((params->w == 9 && params->h == 5) || /* (3,1,3,1) */
208 (params->w == 5 && params->h == 9) || /* (1,3,1,3) */
209 (params->w == 9 && params->h == 9) || /* (3,3,3,3) */
210 (params->w == 7 && params->h == 5) || /* (2,1,2,1) */
211 (params->w == 5 && params->h == 7) || /* (1,2,1,2) */
212 (params->w == 9 && params->h == 7) || /* (3,2,3,2) */
213 (params->w == 7 && params->h == 9) || /* (2,3,2,3) */
214 (params->w == 7 && params->h == 7))) /* (2,2,2,2) */
215 return "This board type is only supported at "
216 "5x7, 5x9, 7x7, 7x9, and 9x9";
217 }
185 218
186 /* 219 /*
187 * It might be possible to implement generalisations of Cross 220 * It might be possible to implement generalisations of
188 * and Octagon, but only if I can find a proof that they're all 221 * Octagon, but only if I can find a proof that they're all
189 * soluble. For the moment, therefore, I'm going to disallow 222 * soluble. For the moment, therefore, I'm going to disallow
190 * them at any size other than the standard one. 223 * it at any size other than the standard one.
191 */ 224 */
192 if (full && (params->type == TYPE_CROSS || params->type == TYPE_OCTAGON)) { 225 if (full && params->type == TYPE_OCTAGON) {
193 if (params->w != 7 || params->h != 7) 226 if (params->w != 7 || params->h != 7)
194 return "This board type is only supported at 7x7"; 227 return "This board type is only supported at 7x7";
195 } 228 }
@@ -658,12 +691,23 @@ static char *new_game_desc(const game_params *params, random_state *rs,
658 691
659static const char *validate_desc(const game_params *params, const char *desc) 692static const char *validate_desc(const game_params *params, const char *desc)
660{ 693{
661 int len = params->w * params->h; 694 int len, i, npeg = 0, nhole = 0;
695
696 len = params->w * params->h;
662 697
663 if (len != strlen(desc)) 698 if (len != strlen(desc))
664 return "Game description is wrong length"; 699 return "Game description is wrong length";
665 if (len != strspn(desc, "PHO")) 700 if (len != strspn(desc, "PHO"))
666 return "Invalid character in game description"; 701 return "Invalid character in game description";
702 for (i = 0; i < len; i++) {
703 npeg += desc[i] == 'P';
704 nhole += desc[i] == 'H';
705 }
706 /* The minimal soluble game has two pegs and a hole: "3x1:PPH". */
707 if (npeg < 2)
708 return "Too few pegs in game description";
709 if (nhole < 1)
710 return "Too few holes in game description";
667 711
668 return NULL; 712 return NULL;
669} 713}
@@ -706,12 +750,6 @@ static void free_game(game_state *state)
706 sfree(state); 750 sfree(state);
707} 751}
708 752
709static char *solve_game(const game_state *state, const game_state *currstate,
710 const char *aux, const char **error)
711{
712 return NULL;
713}
714
715static bool game_can_format_as_text_now(const game_params *params) 753static bool game_can_format_as_text_now(const game_params *params)
716{ 754{
717 return true; 755 return true;
@@ -751,7 +789,7 @@ static game_ui *new_ui(const game_state *state)
751 789
752 ui->sx = ui->sy = ui->dx = ui->dy = 0; 790 ui->sx = ui->sy = ui->dx = ui->dy = 0;
753 ui->dragging = false; 791 ui->dragging = false;
754 ui->cur_visible = false; 792 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
755 ui->cur_jumping = false; 793 ui->cur_jumping = false;
756 794
757 /* make sure we start the cursor somewhere on the grid. */ 795 /* make sure we start the cursor somewhere on the grid. */
@@ -775,15 +813,6 @@ static void free_ui(game_ui *ui)
775 sfree(ui); 813 sfree(ui);
776} 814}
777 815
778static char *encode_ui(const game_ui *ui)
779{
780 return NULL;
781}
782
783static void decode_ui(game_ui *ui, const char *encoding)
784{
785}
786
787static void game_changed_state(game_ui *ui, const game_state *oldstate, 816static void game_changed_state(game_ui *ui, const game_state *oldstate,
788 const game_state *newstate) 817 const game_state *newstate)
789{ 818{
@@ -800,6 +829,19 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
800 ui->cur_jumping = false; 829 ui->cur_jumping = false;
801} 830}
802 831
832static const char *current_key_label(const game_ui *ui,
833 const game_state *state, int button)
834{
835 int w = state->w;
836
837 if (IS_CURSOR_SELECT(button)) {
838 if (!ui->cur_visible) return "";
839 if (ui->cur_jumping) return "Cancel";
840 if (state->grid[ui->cur_y*w+ui->cur_x] == GRID_PEG) return "Select";
841 }
842 return "";
843}
844
803#define PREFERRED_TILE_SIZE 33 845#define PREFERRED_TILE_SIZE 33
804#define TILESIZE (ds->tilesize) 846#define TILESIZE (ds->tilesize)
805#define BORDER (TILESIZE / 2) 847#define BORDER (TILESIZE / 2)
@@ -845,16 +887,23 @@ static char *interpret_move(const game_state *state, game_ui *ui,
845 887
846 tx = FROMCOORD(x); 888 tx = FROMCOORD(x);
847 ty = FROMCOORD(y); 889 ty = FROMCOORD(y);
848 if (tx >= 0 && tx < w && ty >= 0 && ty < h && 890 if (tx >= 0 && tx < w && ty >= 0 && ty < h) {
849 state->grid[ty*w+tx] == GRID_PEG) { 891 switch (state->grid[ty*w+tx]) {
850 ui->dragging = true; 892 case GRID_PEG:
851 ui->sx = tx; 893 ui->dragging = true;
852 ui->sy = ty; 894 ui->sx = tx;
853 ui->dx = x; 895 ui->sy = ty;
854 ui->dy = y; 896 ui->dx = x;
855 ui->cur_visible = false; 897 ui->dy = y;
856 ui->cur_jumping = false; 898 ui->cur_visible = false;
857 return UI_UPDATE; 899 ui->cur_jumping = false;
900 return MOVE_UI_UPDATE;
901 case GRID_HOLE:
902 return MOVE_NO_EFFECT;
903 case GRID_OBST:
904 default:
905 return MOVE_UNUSED;
906 }
858 } 907 }
859 } else if (button == LEFT_DRAG && ui->dragging) { 908 } else if (button == LEFT_DRAG && ui->dragging) {
860 /* 909 /*
@@ -862,7 +911,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
862 */ 911 */
863 ui->dx = x; 912 ui->dx = x;
864 ui->dy = y; 913 ui->dy = y;
865 return UI_UPDATE; 914 return MOVE_UI_UPDATE;
866 } else if (button == LEFT_RELEASE && ui->dragging) { 915 } else if (button == LEFT_RELEASE && ui->dragging) {
867 int tx, ty, dx, dy; 916 int tx, ty, dx, dy;
868 917
@@ -874,18 +923,18 @@ static char *interpret_move(const game_state *state, game_ui *ui,
874 tx = FROMCOORD(x); 923 tx = FROMCOORD(x);
875 ty = FROMCOORD(y); 924 ty = FROMCOORD(y);
876 if (tx < 0 || tx >= w || ty < 0 || ty >= h) 925 if (tx < 0 || tx >= w || ty < 0 || ty >= h)
877 return UI_UPDATE; /* target out of range */ 926 return MOVE_UI_UPDATE; /* target out of range */
878 dx = tx - ui->sx; 927 dx = tx - ui->sx;
879 dy = ty - ui->sy; 928 dy = ty - ui->sy;
880 if (max(abs(dx),abs(dy)) != 2 || min(abs(dx),abs(dy)) != 0) 929 if (max(abs(dx),abs(dy)) != 2 || min(abs(dx),abs(dy)) != 0)
881 return UI_UPDATE; /* move length was wrong */ 930 return MOVE_UI_UPDATE; /* move length was wrong */
882 dx /= 2; 931 dx /= 2;
883 dy /= 2; 932 dy /= 2;
884 933
885 if (state->grid[ty*w+tx] != GRID_HOLE || 934 if (state->grid[ty*w+tx] != GRID_HOLE ||
886 state->grid[(ty-dy)*w+(tx-dx)] != GRID_PEG || 935 state->grid[(ty-dy)*w+(tx-dx)] != GRID_PEG ||
887 state->grid[ui->sy*w+ui->sx] != GRID_PEG) 936 state->grid[ui->sy*w+ui->sx] != GRID_PEG)
888 return UI_UPDATE; /* grid contents were invalid */ 937 return MOVE_UI_UPDATE; /* grid contents were invalid */
889 938
890 /* 939 /*
891 * We have a valid move. Encode it simply as source and 940 * We have a valid move. Encode it simply as source and
@@ -898,14 +947,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
898 /* Not jumping; move cursor as usual, making sure we don't 947 /* Not jumping; move cursor as usual, making sure we don't
899 * leave the gameboard (which may be an irregular shape) */ 948 * leave the gameboard (which may be an irregular shape) */
900 int cx = ui->cur_x, cy = ui->cur_y; 949 int cx = ui->cur_x, cy = ui->cur_y;
901 move_cursor(button, &cx, &cy, w, h, false); 950 move_cursor(button, &cx, &cy, w, h, false, NULL);
902 ui->cur_visible = true; 951 ui->cur_visible = true;
903 if (state->grid[cy*w+cx] == GRID_HOLE || 952 if (state->grid[cy*w+cx] == GRID_HOLE ||
904 state->grid[cy*w+cx] == GRID_PEG) { 953 state->grid[cy*w+cx] == GRID_PEG) {
905 ui->cur_x = cx; 954 ui->cur_x = cx;
906 ui->cur_y = cy; 955 ui->cur_y = cy;
907 } 956 }
908 return UI_UPDATE; 957 return MOVE_UI_UPDATE;
909 } else { 958 } else {
910 int dx, dy, mx, my, jx, jy; 959 int dx, dy, mx, my, jx, jy;
911 960
@@ -928,26 +977,26 @@ static char *interpret_move(const game_state *state, game_ui *ui,
928 ui->cur_x = jx; ui->cur_y = jy; 977 ui->cur_x = jx; ui->cur_y = jy;
929 return dupstr(buf); 978 return dupstr(buf);
930 } 979 }
931 return UI_UPDATE; 980 return MOVE_UI_UPDATE;
932 } 981 }
933 } else if (IS_CURSOR_SELECT(button)) { 982 } else if (IS_CURSOR_SELECT(button)) {
934 if (!ui->cur_visible) { 983 if (!ui->cur_visible) {
935 ui->cur_visible = true; 984 ui->cur_visible = true;
936 return UI_UPDATE; 985 return MOVE_UI_UPDATE;
937 } 986 }
938 if (ui->cur_jumping) { 987 if (ui->cur_jumping) {
939 ui->cur_jumping = false; 988 ui->cur_jumping = false;
940 return UI_UPDATE; 989 return MOVE_UI_UPDATE;
941 } 990 }
942 if (state->grid[ui->cur_y*w+ui->cur_x] == GRID_PEG) { 991 if (state->grid[ui->cur_y*w+ui->cur_x] == GRID_PEG) {
943 /* cursor is on peg: next arrow-move wil jump. */ 992 /* cursor is on peg: next arrow-move will jump. */
944 ui->cur_jumping = true; 993 ui->cur_jumping = true;
945 return UI_UPDATE; 994 return MOVE_UI_UPDATE;
946 } 995 }
947 return NULL; 996 return MOVE_NO_EFFECT;
948 } 997 }
949 998
950 return NULL; 999 return MOVE_UNUSED;
951} 1000}
952 1001
953static game_state *execute_move(const game_state *state, const char *move) 1002static game_state *execute_move(const game_state *state, const char *move)
@@ -1006,7 +1055,7 @@ static game_state *execute_move(const game_state *state, const char *move)
1006 */ 1055 */
1007 1056
1008static void game_compute_size(const game_params *params, int tilesize, 1057static void game_compute_size(const game_params *params, int tilesize,
1009 int *x, int *y) 1058 const game_ui *ui, int *x, int *y)
1010{ 1059{
1011 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 1060 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1012 struct { int tilesize; } ads, *ds = &ads; 1061 struct { int tilesize; } ads, *ds = &ads;
@@ -1135,10 +1184,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1135 } 1184 }
1136 1185
1137 if (!ds->started) { 1186 if (!ds->started) {
1138 draw_rect(dr, 0, 0,
1139 TILESIZE * state->w + 2 * BORDER,
1140 TILESIZE * state->h + 2 * BORDER, COL_BACKGROUND);
1141
1142 /* 1187 /*
1143 * Draw relief marks around all the squares that aren't 1188 * Draw relief marks around all the squares that aren't
1144 * GRID_OBST. 1189 * GRID_OBST.
@@ -1302,19 +1347,6 @@ static int game_status(const game_state *state)
1302 return state->completed ? +1 : 0; 1347 return state->completed ? +1 : 0;
1303} 1348}
1304 1349
1305static bool game_timing_state(const game_state *state, game_ui *ui)
1306{
1307 return true;
1308}
1309
1310static void game_print_size(const game_params *params, float *x, float *y)
1311{
1312}
1313
1314static void game_print(drawing *dr, const game_state *state, int tilesize)
1315{
1316}
1317
1318#ifdef COMBINED 1350#ifdef COMBINED
1319#define thegame pegs 1351#define thegame pegs
1320#endif 1352#endif
@@ -1334,14 +1366,16 @@ const struct game thegame = {
1334 new_game, 1366 new_game,
1335 dup_game, 1367 dup_game,
1336 free_game, 1368 free_game,
1337 false, solve_game, 1369 false, NULL, /* solve */
1338 true, game_can_format_as_text_now, game_text_format, 1370 true, game_can_format_as_text_now, game_text_format,
1371 NULL, NULL, /* get_prefs, set_prefs */
1339 new_ui, 1372 new_ui,
1340 free_ui, 1373 free_ui,
1341 encode_ui, 1374 NULL, /* encode_ui */
1342 decode_ui, 1375 NULL, /* decode_ui */
1343 NULL, /* game_request_keys */ 1376 NULL, /* game_request_keys */
1344 game_changed_state, 1377 game_changed_state,
1378 current_key_label,
1345 interpret_move, 1379 interpret_move,
1346 execute_move, 1380 execute_move,
1347 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 1381 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -1353,9 +1387,9 @@ const struct game thegame = {
1353 game_flash_length, 1387 game_flash_length,
1354 game_get_cursor_location, 1388 game_get_cursor_location,
1355 game_status, 1389 game_status,
1356 false, false, game_print_size, game_print, 1390 false, false, NULL, NULL, /* print_size, print */
1357 false, /* wants_statusbar */ 1391 false, /* wants_statusbar */
1358 false, game_timing_state, 1392 false, NULL, /* timing_state */
1359 0, /* flags */ 1393 0, /* flags */
1360}; 1394};
1361 1395
diff --git a/apps/plugins/puzzles/src/penrose-internal.h b/apps/plugins/puzzles/src/penrose-internal.h
new file mode 100644
index 0000000000..984cd35711
--- /dev/null
+++ b/apps/plugins/puzzles/src/penrose-internal.h
@@ -0,0 +1,289 @@
1#include "penrose.h"
2
3static inline unsigned num_subtriangles(char t)
4{
5 return (t == 'A' || t == 'B' || t == 'X' || t == 'Y') ? 3 : 2;
6}
7
8static inline unsigned sibling_edge(char t)
9{
10 switch (t) {
11 case 'A': case 'U': return 2;
12 case 'B': case 'V': return 1;
13 default: return 0;
14 }
15}
16
17/*
18 * Coordinate system for tracking Penrose-tile half-triangles.
19 * PenroseCoords simply stores an array of triangle types.
20 */
21typedef struct PenroseCoords {
22 char *c;
23 size_t nc, csize;
24} PenroseCoords;
25
26PenroseCoords *penrose_coords_new(void);
27void penrose_coords_free(PenroseCoords *pc);
28void penrose_coords_make_space(PenroseCoords *pc, size_t size);
29PenroseCoords *penrose_coords_copy(PenroseCoords *pc_in);
30
31/*
32 * Coordinate system for locating Penrose tiles in the plane.
33 *
34 * The 'Point' structure represents a single point by means of an
35 * integer linear combination of {1, t, t^2, t^3}, where t is the
36 * complex number exp(i pi/5) representing 1/10 of a turn about the
37 * origin.
38 *
39 * The 'PenroseTriangle' structure represents a half-tile triangle,
40 * giving both the locations of its vertices and its combinatorial
41 * coordinates. It also contains a linked-list pointer and a boolean
42 * flag, used during breadth-first search to generate all the tiles in
43 * an area and report them exactly once.
44 */
45typedef struct Point {
46 int coeffs[4];
47} Point;
48typedef struct PenroseTriangle PenroseTriangle;
49struct PenroseTriangle {
50 Point vertices[3];
51 PenroseCoords *pc;
52 PenroseTriangle *next; /* used in breadth-first search */
53 bool reported;
54};
55
56/* Fill in all the coordinates of a triangle starting from any single edge.
57 * Requires tri->pc to have been filled in, so that we know which shape of
58 * triangle we're placing. */
59void penrose_place(PenroseTriangle *tri, Point u, Point v, int index_of_u);
60
61/* Free a PenroseHalf and its contained coordinates, or a whole PenroseTile */
62void penrose_free(PenroseTriangle *tri);
63
64/*
65 * A Point is really a complex number, so we can add, subtract and
66 * multiply them.
67 */
68static inline Point point_add(Point a, Point b)
69{
70 Point r;
71 size_t i;
72 for (i = 0; i < 4; i++)
73 r.coeffs[i] = a.coeffs[i] + b.coeffs[i];
74 return r;
75}
76static inline Point point_sub(Point a, Point b)
77{
78 Point r;
79 size_t i;
80 for (i = 0; i < 4; i++)
81 r.coeffs[i] = a.coeffs[i] - b.coeffs[i];
82 return r;
83}
84static inline Point point_mul_by_t(Point x)
85{
86 Point r;
87 /* Multiply by t by using the identity t^4 - t^3 + t^2 - t + 1 = 0,
88 * so t^4 = t^3 - t^2 + t - 1 */
89 r.coeffs[0] = -x.coeffs[3];
90 r.coeffs[1] = x.coeffs[0] + x.coeffs[3];
91 r.coeffs[2] = x.coeffs[1] - x.coeffs[3];
92 r.coeffs[3] = x.coeffs[2] + x.coeffs[3];
93 return r;
94}
95static inline Point point_mul(Point a, Point b)
96{
97 size_t i, j;
98 Point r;
99
100 /* Initialise r to be a, scaled by b's t^3 term */
101 for (j = 0; j < 4; j++)
102 r.coeffs[j] = a.coeffs[j] * b.coeffs[3];
103
104 /* Now iterate r = t*r + (next coefficient down), by Horner's rule */
105 for (i = 3; i-- > 0 ;) {
106 r = point_mul_by_t(r);
107 for (j = 0; j < 4; j++)
108 r.coeffs[j] += a.coeffs[j] * b.coeffs[i];
109 }
110
111 return r;
112}
113static inline bool point_equal(Point a, Point b)
114{
115 size_t i;
116 for (i = 0; i < 4; i++)
117 if (a.coeffs[i] != b.coeffs[i])
118 return false;
119 return true;
120}
121
122/*
123 * Return the Point corresponding to a rotation of s steps around the
124 * origin, i.e. a rotation by 36*s degrees or s*pi/5 radians.
125 */
126static inline Point point_rot(int s)
127{
128 Point r = {{ 1, 0, 0, 0 }};
129 Point tpower = {{ 0, 1, 0, 0 }};
130
131 /* Reduce to a sensible range */
132 s = s % 10;
133 if (s < 0)
134 s += 10;
135
136 while (true) {
137 if (s & 1)
138 r = point_mul(r, tpower);
139 s >>= 1;
140 if (!s)
141 break;
142 tpower = point_mul(tpower, tpower);
143 }
144
145 return r;
146}
147
148/*
149 * PenroseContext is the shared context of a whole run of the
150 * algorithm. Its 'prototype' PenroseCoords object represents the
151 * coordinates of the starting triangle, and is extended as necessary;
152 * any other PenroseCoord that needs extending will copy the
153 * higher-order values from ctx->prototype as needed, so that once
154 * each choice has been made, it remains consistent.
155 *
156 * When we're inventing a random piece of tiling in the first place,
157 * we append to ctx->prototype by choosing a random (but legal)
158 * higher-level metatile for the current topmost one to turn out to be
159 * part of. When we're replaying a generation whose parameters are
160 * already stored, we don't have a random_state, and we make fixed
161 * decisions if not enough coordinates were provided, as in the
162 * corresponding hat.c system.
163 *
164 * For a normal (non-testing) caller, penrosectx_generate() is the
165 * main useful function. It breadth-first searches a whole area to
166 * generate all the triangles in it, starting from a (typically
167 * central) one with the coordinates of ctx->prototype. It takes two
168 * callback function: one that checks whether a triangle is within the
169 * bounds of the target area (and therefore the search should continue
170 * exploring its neighbours), and another that reports a full Penrose
171 * tile once both of its halves have been found and determined to be
172 * in bounds.
173 */
174typedef struct PenroseContext {
175 random_state *rs;
176 bool must_free_rs;
177 unsigned start_vertex; /* which vertex of 'prototype' is at the origin? */
178 int orientation; /* orientation to put in PenrosePatchParams */
179 PenroseCoords *prototype;
180} PenroseContext;
181
182void penrosectx_init_random(PenroseContext *ctx, random_state *rs, int which);
183void penrosectx_init_from_params(
184 PenroseContext *ctx, const struct PenrosePatchParams *ps);
185void penrosectx_cleanup(PenroseContext *ctx);
186PenroseCoords *penrosectx_initial_coords(PenroseContext *ctx);
187void penrosectx_extend_coords(PenroseContext *ctx, PenroseCoords *pc,
188 size_t n);
189void penrosectx_step(PenroseContext *ctx, PenroseCoords *pc,
190 unsigned edge, unsigned *outedge);
191void penrosectx_generate(
192 PenroseContext *ctx,
193 bool (*inbounds)(void *inboundsctx,
194 const PenroseTriangle *tri), void *inboundsctx,
195 void (*tile)(void *tilectx, const Point *vertices), void *tilectx);
196
197/* Subroutines that step around the tiling specified by a PenroseCtx,
198 * delivering both plane and combinatorial coordinates as they go */
199PenroseTriangle *penrose_initial(PenroseContext *ctx);
200PenroseTriangle *penrose_adjacent(PenroseContext *ctx,
201 const PenroseTriangle *src_spec,
202 unsigned src_edge, unsigned *dst_edge);
203
204/* For extracting the point coordinates */
205typedef struct Coord {
206 int c1, cr5; /* coefficients of 1 and sqrt(5) respectively */
207} Coord;
208
209static inline Coord point_x(Point p)
210{
211 Coord x = {
212 4 * p.coeffs[0] + p.coeffs[1] - p.coeffs[2] + p.coeffs[3],
213 p.coeffs[1] + p.coeffs[2] - p.coeffs[3],
214 };
215 return x;
216}
217
218static inline Coord point_y(Point p)
219{
220 Coord y = {
221 2 * p.coeffs[1] + p.coeffs[2] + p.coeffs[3],
222 p.coeffs[2] + p.coeffs[3],
223 };
224 return y;
225}
226
227static inline int coord_sign(Coord x)
228{
229 if (x.c1 == 0 && x.cr5 == 0)
230 return 0;
231 if (x.c1 >= 0 && x.cr5 >= 0)
232 return +1;
233 if (x.c1 <= 0 && x.cr5 <= 0)
234 return -1;
235
236 if (x.c1 * x.c1 > 5 * x.cr5 * x.cr5)
237 return x.c1 < 0 ? -1 : +1;
238 else
239 return x.cr5 < 0 ? -1 : +1;
240}
241
242static inline Coord coord_construct(int c1, int cr5)
243{
244 Coord c = { c1, cr5 };
245 return c;
246}
247
248static inline Coord coord_integer(int c1)
249{
250 return coord_construct(c1, 0);
251}
252
253static inline Coord coord_add(Coord a, Coord b)
254{
255 Coord sum;
256 sum.c1 = a.c1 + b.c1;
257 sum.cr5 = a.cr5 + b.cr5;
258 return sum;
259}
260
261static inline Coord coord_sub(Coord a, Coord b)
262{
263 Coord diff;
264 diff.c1 = a.c1 - b.c1;
265 diff.cr5 = a.cr5 - b.cr5;
266 return diff;
267}
268
269static inline Coord coord_mul(Coord a, Coord b)
270{
271 Coord prod;
272 prod.c1 = a.c1 * b.c1 + 5 * a.cr5 * b.cr5;
273 prod.cr5 = a.c1 * b.cr5 + a.cr5 * b.c1;
274 return prod;
275}
276
277static inline Coord coord_abs(Coord a)
278{
279 int sign = coord_sign(a);
280 Coord abs;
281 abs.c1 = a.c1 * sign;
282 abs.cr5 = a.cr5 * sign;
283 return abs;
284}
285
286static inline int coord_cmp(Coord a, Coord b)
287{
288 return coord_sign(coord_sub(a, b));
289}
diff --git a/apps/plugins/puzzles/src/penrose-legacy.c b/apps/plugins/puzzles/src/penrose-legacy.c
new file mode 100644
index 0000000000..709d68d7f5
--- /dev/null
+++ b/apps/plugins/puzzles/src/penrose-legacy.c
@@ -0,0 +1,506 @@
1/* penrose-legacy.c: legacy Penrose tile generator.
2 *
3 * Works by choosing a small patch from a recursively expanded large
4 * region of tiling, using one of the two algorithms described at
5 *
6 * https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/aperiodic-tilings/
7 *
8 * This method of generating Penrose tiling fragments is superseded by
9 * the completely different algorithm in penrose.c, using the other
10 * algorithm in that article (the 'combinatorial coordinates' one). We
11 * keep the legacy algorithm around only for interpreting Loopy game
12 * IDs generated by older versions of the code.
13 */
14
15#include <assert.h>
16#include <string.h>
17#ifdef NO_TGMATH_H
18# include <math.h>
19#else
20# include <tgmath.h>
21#endif
22#include <stdio.h>
23
24#include "puzzles.h" /* for malloc routines, and PI */
25#include "penrose-legacy.h"
26
27/* -------------------------------------------------------
28 * 36-degree basis vector arithmetic routines.
29 */
30
31/* Imagine drawing a
32 * ten-point 'clock face' like this:
33 *
34 * -E
35 * -D | A
36 * \ | /
37 * -C. \ | / ,B
38 * `-._\|/_,-'
39 * ,-' /|\ `-.
40 * -B' / | \ `C
41 * / | \
42 * -A | D
43 * E
44 *
45 * In case the ASCII art isn't clear, those are supposed to be ten
46 * vectors of length 1, all sticking out from the origin at equal
47 * angular spacing (hence 36 degrees). Our basis vectors are A,B,C,D (I
48 * choose them to be symmetric about the x-axis so that the final
49 * translation into 2d coordinates will also be symmetric, which I
50 * think will avoid minor rounding uglinesses), so our vector
51 * representation sets
52 *
53 * A = (1,0,0,0)
54 * B = (0,1,0,0)
55 * C = (0,0,1,0)
56 * D = (0,0,0,1)
57 *
58 * The fifth vector E looks at first glance as if it needs to be
59 * another basis vector, but in fact it doesn't, because it can be
60 * represented in terms of the other four. Imagine starting from the
61 * origin and following the path -A, +B, -C, +D: you'll find you've
62 * traced four sides of a pentagram, and ended up one E-vector away
63 * from the origin. So we have
64 *
65 * E = (-1,1,-1,1)
66 *
67 * This tells us that we can rotate any vector in this system by 36
68 * degrees: if we start with a*A + b*B + c*C + d*D, we want to end up
69 * with a*B + b*C + c*D + d*E, and we substitute our identity for E to
70 * turn that into a*B + b*C + c*D + d*(-A+B-C+D). In other words,
71 *
72 * rotate_one_notch_clockwise(a,b,c,d) = (-d, d+a, -d+b, d+c)
73 *
74 * and you can verify for yourself that applying that operation
75 * repeatedly starting with (1,0,0,0) cycles round ten vectors and
76 * comes back to where it started.
77 *
78 * The other operation that may be required is to construct vectors
79 * with lengths that are multiples of phi. That can be done by
80 * observing that the vector C-B is parallel to E and has length 1/phi,
81 * and the vector D-A is parallel to E and has length phi. So this
82 * tells us that given any vector, we can construct one which points in
83 * the same direction and is 1/phi or phi times its length, like this:
84 *
85 * divide_by_phi(vector) = rotate(vector, 2) - rotate(vector, 3)
86 * multiply_by_phi(vector) = rotate(vector, 1) - rotate(vector, 4)
87 *
88 * where rotate(vector, n) means applying the above
89 * rotate_one_notch_clockwise primitive n times. Expanding out the
90 * applications of rotate gives the following direct representation in
91 * terms of the vector coordinates:
92 *
93 * divide_by_phi(a,b,c,d) = (b-d, c+d-b, a+b-c, c-a)
94 * multiply_by_phi(a,b,c,d) = (a+b-d, c+d, a+b, c+d-a)
95 *
96 * and you can verify for yourself that those two operations are
97 * inverses of each other (as you'd hope!).
98 *
99 * Having done all of this, testing for equality between two vectors is
100 * a trivial matter of comparing the four integer coordinates. (Which
101 * it _wouldn't_ have been if we'd kept E as a fifth basis vector,
102 * because then (-1,1,-1,1,0) and (0,0,0,0,1) would have had to be
103 * considered identical. So leaving E out is vital.)
104 */
105
106struct vector { int a, b, c, d; };
107
108static vector v_origin(void)
109{
110 vector v;
111 v.a = v.b = v.c = v.d = 0;
112 return v;
113}
114
115/* We start with a unit vector of B: this means we can easily
116 * draw an isoceles triangle centred on the X axis. */
117#ifdef TEST_VECTORS
118
119static vector v_unit(void)
120{
121 vector v;
122
123 v.b = 1;
124 v.a = v.c = v.d = 0;
125 return v;
126}
127
128#endif
129
130#define COS54 0.5877852
131#define SIN54 0.8090169
132#define COS18 0.9510565
133#define SIN18 0.3090169
134
135/* These two are a bit rough-and-ready for now. Note that B/C are
136 * 18 degrees from the x-axis, and A/D are 54 degrees. */
137double penrose_legacy_vx(vector *vs, int i)
138{
139 return (vs[i].a + vs[i].d) * COS54 +
140 (vs[i].b + vs[i].c) * COS18;
141}
142
143double penrose_legacy_vy(vector *vs, int i)
144{
145 return (vs[i].a - vs[i].d) * SIN54 +
146 (vs[i].b - vs[i].c) * SIN18;
147
148}
149
150static vector v_trans(vector v, vector trans)
151{
152 v.a += trans.a;
153 v.b += trans.b;
154 v.c += trans.c;
155 v.d += trans.d;
156 return v;
157}
158
159static vector v_rotate_36(vector v)
160{
161 vector vv;
162 vv.a = -v.d;
163 vv.b = v.d + v.a;
164 vv.c = -v.d + v.b;
165 vv.d = v.d + v.c;
166 return vv;
167}
168
169static vector v_rotate(vector v, int ang)
170{
171 int i;
172
173 assert((ang % 36) == 0);
174 while (ang < 0) ang += 360;
175 ang = 360-ang;
176 for (i = 0; i < (ang/36); i++)
177 v = v_rotate_36(v);
178 return v;
179}
180
181#ifdef TEST_VECTORS
182
183static vector v_scale(vector v, int sc)
184{
185 v.a *= sc;
186 v.b *= sc;
187 v.c *= sc;
188 v.d *= sc;
189 return v;
190}
191
192#endif
193
194static vector v_growphi(vector v)
195{
196 vector vv;
197 vv.a = v.a + v.b - v.d;
198 vv.b = v.c + v.d;
199 vv.c = v.a + v.b;
200 vv.d = v.c + v.d - v.a;
201 return vv;
202}
203
204static vector v_shrinkphi(vector v)
205{
206 vector vv;
207 vv.a = v.b - v.d;
208 vv.b = v.c + v.d - v.b;
209 vv.c = v.a + v.b - v.c;
210 vv.d = v.c - v.a;
211 return vv;
212}
213
214#ifdef TEST_VECTORS
215
216static const char *v_debug(vector v)
217{
218 static char buf[255];
219 sprintf(buf,
220 "(%d,%d,%d,%d)[%2.2f,%2.2f]",
221 v.a, v.b, v.c, v.d, v_x(&v,0), v_y(&v,0));
222 return buf;
223}
224
225#endif
226
227/* -------------------------------------------------------
228 * Tiling routines.
229 */
230
231static vector xform_coord(vector vo, int shrink, vector vtrans, int ang)
232{
233 if (shrink < 0)
234 vo = v_shrinkphi(vo);
235 else if (shrink > 0)
236 vo = v_growphi(vo);
237
238 vo = v_rotate(vo, ang);
239 vo = v_trans(vo, vtrans);
240
241 return vo;
242}
243
244
245#define XFORM(n,o,s,a) vs[(n)] = xform_coord(v_edge, (s), vs[(o)], (a))
246
247static int penrose_p2_small(penrose_legacy_state *state, int depth, int flip,
248 vector v_orig, vector v_edge);
249
250static int penrose_p2_large(penrose_legacy_state *state, int depth, int flip,
251 vector v_orig, vector v_edge)
252{
253 vector vv_orig, vv_edge;
254
255#ifdef DEBUG_PENROSE
256 {
257 vector vs[3];
258 vs[0] = v_orig;
259 XFORM(1, 0, 0, 0);
260 XFORM(2, 0, 0, -36*flip);
261
262 state->new_tile(state, vs, 3, depth);
263 }
264#endif
265
266 if (flip > 0) {
267 vector vs[4];
268
269 vs[0] = v_orig;
270 XFORM(1, 0, 0, -36);
271 XFORM(2, 0, 0, 0);
272 XFORM(3, 0, 0, 36);
273
274 state->new_tile(state, vs, 4, depth);
275 }
276 if (depth >= state->max_depth) return 0;
277
278 vv_orig = v_trans(v_orig, v_rotate(v_edge, -36*flip));
279 vv_edge = v_rotate(v_edge, 108*flip);
280
281 penrose_p2_small(state, depth+1, flip,
282 v_orig, v_shrinkphi(v_edge));
283
284 penrose_p2_large(state, depth+1, flip,
285 vv_orig, v_shrinkphi(vv_edge));
286 penrose_p2_large(state, depth+1, -flip,
287 vv_orig, v_shrinkphi(vv_edge));
288
289 return 0;
290}
291
292static int penrose_p2_small(penrose_legacy_state *state, int depth, int flip,
293 vector v_orig, vector v_edge)
294{
295 vector vv_orig;
296
297#ifdef DEBUG_PENROSE
298 {
299 vector vs[3];
300 vs[0] = v_orig;
301 XFORM(1, 0, 0, 0);
302 XFORM(2, 0, -1, -36*flip);
303
304 state->new_tile(state, vs, 3, depth);
305 }
306#endif
307
308 if (flip > 0) {
309 vector vs[4];
310
311 vs[0] = v_orig;
312 XFORM(1, 0, 0, -72);
313 XFORM(2, 0, -1, -36);
314 XFORM(3, 0, 0, 0);
315
316 state->new_tile(state, vs, 4, depth);
317 }
318
319 if (depth >= state->max_depth) return 0;
320
321 vv_orig = v_trans(v_orig, v_edge);
322
323 penrose_p2_large(state, depth+1, -flip,
324 v_orig, v_shrinkphi(v_rotate(v_edge, -36*flip)));
325
326 penrose_p2_small(state, depth+1, flip,
327 vv_orig, v_shrinkphi(v_rotate(v_edge, -144*flip)));
328
329 return 0;
330}
331
332static int penrose_p3_small(penrose_legacy_state *state, int depth, int flip,
333 vector v_orig, vector v_edge);
334
335static int penrose_p3_large(penrose_legacy_state *state, int depth, int flip,
336 vector v_orig, vector v_edge)
337{
338 vector vv_orig;
339
340#ifdef DEBUG_PENROSE
341 {
342 vector vs[3];
343 vs[0] = v_orig;
344 XFORM(1, 0, 1, 0);
345 XFORM(2, 0, 0, -36*flip);
346
347 state->new_tile(state, vs, 3, depth);
348 }
349#endif
350
351 if (flip > 0) {
352 vector vs[4];
353
354 vs[0] = v_orig;
355 XFORM(1, 0, 0, -36);
356 XFORM(2, 0, 1, 0);
357 XFORM(3, 0, 0, 36);
358
359 state->new_tile(state, vs, 4, depth);
360 }
361 if (depth >= state->max_depth) return 0;
362
363 vv_orig = v_trans(v_orig, v_edge);
364
365 penrose_p3_large(state, depth+1, -flip,
366 vv_orig, v_shrinkphi(v_rotate(v_edge, 180)));
367
368 penrose_p3_small(state, depth+1, flip,
369 vv_orig, v_shrinkphi(v_rotate(v_edge, -108*flip)));
370
371 vv_orig = v_trans(v_orig, v_growphi(v_edge));
372
373 penrose_p3_large(state, depth+1, flip,
374 vv_orig, v_shrinkphi(v_rotate(v_edge, -144*flip)));
375
376
377 return 0;
378}
379
380static int penrose_p3_small(penrose_legacy_state *state, int depth, int flip,
381 vector v_orig, vector v_edge)
382{
383 vector vv_orig;
384
385#ifdef DEBUG_PENROSE
386 {
387 vector vs[3];
388 vs[0] = v_orig;
389 XFORM(1, 0, 0, 0);
390 XFORM(2, 0, 0, -36*flip);
391
392 state->new_tile(state, vs, 3, depth);
393 }
394#endif
395
396 if (flip > 0) {
397 vector vs[4];
398
399 vs[0] = v_orig;
400 XFORM(1, 0, 0, -36);
401 XFORM(3, 0, 0, 0);
402 XFORM(2, 3, 0, -36);
403
404 state->new_tile(state, vs, 4, depth);
405 }
406 if (depth >= state->max_depth) return 0;
407
408 /* NB these two are identical to the first two of p3_large. */
409 vv_orig = v_trans(v_orig, v_edge);
410
411 penrose_p3_large(state, depth+1, -flip,
412 vv_orig, v_shrinkphi(v_rotate(v_edge, 180)));
413
414 penrose_p3_small(state, depth+1, flip,
415 vv_orig, v_shrinkphi(v_rotate(v_edge, -108*flip)));
416
417 return 0;
418}
419
420/* -------------------------------------------------------
421 * Utility routines.
422 */
423
424double penrose_legacy_side_length(double start_size, int depth)
425{
426 return start_size / pow(PHI, depth);
427}
428
429/*
430 * It turns out that an acute isosceles triangle with sides in ratio 1:phi:phi
431 * has an incentre which is conveniently 2*phi^-2 of the way from the apex to
432 * the base. Why's that convenient? Because: if we situate the incentre of the
433 * triangle at the origin, then we can place the apex at phi^-2 * (B+C), and
434 * the other two vertices at apex-B and apex-C respectively. So that's an acute
435 * triangle with its long sides of unit length, covering a circle about the
436 * origin of radius 1-(2*phi^-2), which is conveniently enough phi^-3.
437 *
438 * (later mail: this is an overestimate by about 5%)
439 */
440
441int penrose_legacy(penrose_legacy_state *state, int which, int angle)
442{
443 vector vo = v_origin();
444 vector vb = v_origin();
445
446 vo.b = vo.c = -state->start_size;
447 vo = v_shrinkphi(v_shrinkphi(vo));
448
449 vb.b = state->start_size;
450
451 vo = v_rotate(vo, angle);
452 vb = v_rotate(vb, angle);
453
454 if (which == PENROSE_P2)
455 return penrose_p2_large(state, 0, 1, vo, vb);
456 else
457 return penrose_p3_small(state, 0, 1, vo, vb);
458}
459
460/*
461 * We're asked for a MxN grid, which just means a tiling fitting into roughly
462 * an MxN space in some kind of reasonable unit - say, the side length of the
463 * two-arrow edges of the tiles. By some reasoning in a previous email, that
464 * means we want to pick some subarea of a circle of radius 3.11*sqrt(M^2+N^2).
465 * To cover that circle, we need to subdivide a triangle large enough that it
466 * contains a circle of that radius.
467 *
468 * Hence: start with those three vectors marking triangle vertices, scale them
469 * all up by phi repeatedly until the radius of the inscribed circle gets
470 * bigger than the target, and then recurse into that triangle with the same
471 * recursion depth as the number of times you scaled up. That will give you
472 * tiles of unit side length, covering a circle big enough that if you randomly
473 * choose an orientation and coordinates within the circle, you'll be able to
474 * get any valid piece of Penrose tiling of size MxN.
475 */
476#define INCIRCLE_RADIUS 0.22426 /* phi^-3 less 5%: see above */
477
478void penrose_legacy_calculate_size(
479 int which, int tilesize, int w, int h,
480 double *required_radius, int *start_size, int *depth)
481{
482 double rradius, size;
483 int n = 0;
484
485 /*
486 * Fudge factor to scale P2 and P3 tilings differently. This
487 * doesn't seem to have much relevance to questions like the
488 * average number of tiles per unit area; it's just aesthetic.
489 */
490 if (which == PENROSE_P2)
491 tilesize = tilesize * 3 / 2;
492 else
493 tilesize = tilesize * 5 / 4;
494
495 rradius = tilesize * 3.11 * sqrt((double)(w*w + h*h));
496 size = tilesize;
497
498 while ((size * INCIRCLE_RADIUS) < rradius) {
499 n++;
500 size = size * PHI;
501 }
502
503 *start_size = (int)size;
504 *depth = n;
505 *required_radius = rradius;
506}
diff --git a/apps/plugins/puzzles/src/penrose-legacy.h b/apps/plugins/puzzles/src/penrose-legacy.h
new file mode 100644
index 0000000000..514fd8b592
--- /dev/null
+++ b/apps/plugins/puzzles/src/penrose-legacy.h
@@ -0,0 +1,63 @@
1/* penrose-legacy.h: legacy Penrose tiling functions.
2 *
3 * Provides an interface with which to generate Penrose tilings
4 * by recursive subdivision of an initial tile of choice (one of the
5 * four sets of two pairs kite/dart, or thin/thick rhombus).
6 *
7 * You supply a callback function and a context pointer, which is
8 * called with each tile in turn: you choose how many times to recurse.
9 *
10 * This method of generating Penrose tiling fragments is superseded by
11 * the completely different algorithm in penrose.c. We keep the legacy
12 * algorithm around only for interpreting Loopy game IDs generated by
13 * older versions of the code.
14 */
15
16#ifndef PUZZLES_PENROSE_LEGACY_H
17#define PUZZLES_PENROSE_LEGACY_H
18
19#ifndef PHI
20#define PHI 1.6180339887
21#endif
22
23typedef struct vector vector;
24
25double penrose_legacy_vx(vector *vs, int i);
26double penrose_legacy_vy(vector *vs, int i);
27
28typedef struct penrose_legacy_state penrose_legacy_state;
29
30/* Return non-zero to clip the tree here (i.e. not recurse
31 * below this tile).
32 *
33 * Parameters are state, vector array, npoints, depth.
34 * ctx is inside state.
35 */
36typedef int (*tile_callback)(penrose_legacy_state *, vector *, int, int);
37
38struct penrose_legacy_state {
39 int start_size; /* initial side length */
40 int max_depth; /* Recursion depth */
41
42 tile_callback new_tile;
43 void *ctx; /* for callback */
44};
45
46#ifndef PENROSE_ENUM_DEFINED
47#define PENROSE_ENUM_DEFINED
48enum { PENROSE_P2, PENROSE_P3 };
49#endif
50
51extern int penrose_legacy(penrose_legacy_state *state, int which, int angle);
52
53/* Returns the side-length of a penrose tile at recursion level
54 * gen, given a starting side length. */
55extern double penrose_legacy_side_length(double start_size, int depth);
56
57/* Calculate start size and recursion depth required to produce a
58 * width-by-height sized patch of penrose tiles with the given tilesize */
59extern void penrose_legacy_calculate_size(
60 int which, int tilesize, int w, int h,
61 double *required_radius, int *start_size, int *depth);
62
63#endif
diff --git a/apps/plugins/puzzles/src/penrose.c b/apps/plugins/puzzles/src/penrose.c
index ccde30d8b4..4d7dcc4347 100644
--- a/apps/plugins/puzzles/src/penrose.c
+++ b/apps/plugins/puzzles/src/penrose.c
@@ -1,629 +1,894 @@
1/* penrose.c 1/*
2 * 2 * Generate Penrose tilings via combinatorial coordinates.
3 * Penrose tile generator.
4 * 3 *
5 * Uses half-tile technique outlined on: 4 * For general explanation of the algorithm:
5 * https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/aperiodic-tilings/
6 * 6 *
7 * http://tartarus.org/simon/20110412-penrose/penrose.xhtml 7 * I use exactly the same indexing system here that's described in the
8 * article. For the P2 tiling, acute isosceles triangles (half-kites)
9 * are assigned letters A,B, and obtuse ones (half-darts) U,V; for P3,
10 * acute triangles (half of a thin rhomb) are C,D and obtuse ones
11 * (half a thick rhomb) are X,Y. Edges of all triangles are indexed
12 * anticlockwise around the triangle, with 0 being the base and 1,2
13 * being the two equal legs.
8 */ 14 */
9 15
10#include <assert.h> 16#include <assert.h>
17#include <stddef.h>
11#include <string.h> 18#include <string.h>
12#include <math.h>
13#include <stdio.h>
14 19
15#include "puzzles.h" /* for malloc routines, and PI */ 20#include "puzzles.h"
16#include "penrose.h" 21#include "penrose.h"
22#include "penrose-internal.h"
23#include "tree234.h"
17 24
18/* ------------------------------------------------------- 25bool penrose_valid_letter(char c, int which)
19 * 36-degree basis vector arithmetic routines. 26{
20 */ 27 switch (c) {
28 case 'A': case 'B': case 'U': case 'V':
29 return which == PENROSE_P2;
30 case 'C': case 'D': case 'X': case 'Y':
31 return which == PENROSE_P3;
32 default:
33 return false;
34 }
35}
21 36
22/* Imagine drawing a 37/*
23 * ten-point 'clock face' like this: 38 * Result of attempting a transition within the coordinate system.
24 * 39 * INTERNAL means we've moved to a different child of the same parent,
25 * -E 40 * so the 'internal' substructure gives the type of the new triangle
26 * -D | A 41 * and which edge of it we came in through; EXTERNAL means we've moved
27 * \ | / 42 * out of the parent entirely, and the 'external' substructure tells
28 * -C. \ | / ,B 43 * us which edge of the parent triangle we left by, and if it's
29 * `-._\|/_,-' 44 * divided in two, which end of that edge (-1 for the left end or +1
30 * ,-' /|\ `-. 45 * for the right end). If the parent edge is undivided, end == 0.
31 * -B' / | \ `C
32 * / | \
33 * -A | D
34 * E
35 *
36 * In case the ASCII art isn't clear, those are supposed to be ten
37 * vectors of length 1, all sticking out from the origin at equal
38 * angular spacing (hence 36 degrees). Our basis vectors are A,B,C,D (I
39 * choose them to be symmetric about the x-axis so that the final
40 * translation into 2d coordinates will also be symmetric, which I
41 * think will avoid minor rounding uglinesses), so our vector
42 * representation sets
43 *
44 * A = (1,0,0,0)
45 * B = (0,1,0,0)
46 * C = (0,0,1,0)
47 * D = (0,0,0,1)
48 *
49 * The fifth vector E looks at first glance as if it needs to be
50 * another basis vector, but in fact it doesn't, because it can be
51 * represented in terms of the other four. Imagine starting from the
52 * origin and following the path -A, +B, -C, +D: you'll find you've
53 * traced four sides of a pentagram, and ended up one E-vector away
54 * from the origin. So we have
55 *
56 * E = (-1,1,-1,1)
57 *
58 * This tells us that we can rotate any vector in this system by 36
59 * degrees: if we start with a*A + b*B + c*C + d*D, we want to end up
60 * with a*B + b*C + c*D + d*E, and we substitute our identity for E to
61 * turn that into a*B + b*C + c*D + d*(-A+B-C+D). In other words,
62 *
63 * rotate_one_notch_clockwise(a,b,c,d) = (-d, d+a, -d+b, d+c)
64 *
65 * and you can verify for yourself that applying that operation
66 * repeatedly starting with (1,0,0,0) cycles round ten vectors and
67 * comes back to where it started.
68 *
69 * The other operation that may be required is to construct vectors
70 * with lengths that are multiples of phi. That can be done by
71 * observing that the vector C-B is parallel to E and has length 1/phi,
72 * and the vector D-A is parallel to E and has length phi. So this
73 * tells us that given any vector, we can construct one which points in
74 * the same direction and is 1/phi or phi times its length, like this:
75 *
76 * divide_by_phi(vector) = rotate(vector, 2) - rotate(vector, 3)
77 * multiply_by_phi(vector) = rotate(vector, 1) - rotate(vector, 4)
78 *
79 * where rotate(vector, n) means applying the above
80 * rotate_one_notch_clockwise primitive n times. Expanding out the
81 * applications of rotate gives the following direct representation in
82 * terms of the vector coordinates:
83 *
84 * divide_by_phi(a,b,c,d) = (b-d, c+d-b, a+b-c, c-a)
85 * multiply_by_phi(a,b,c,d) = (a+b-d, c+d, a+b, c+d-a)
86 *
87 * and you can verify for yourself that those two operations are
88 * inverses of each other (as you'd hope!).
89 * 46 *
90 * Having done all of this, testing for equality between two vectors is 47 * The type FAIL _shouldn't_ ever come up! It occurs if you try to
91 * a trivial matter of comparing the four integer coordinates. (Which 48 * compute an incoming transition with an illegal value of 'end' (i.e.
92 * it _wouldn't_ have been if we'd kept E as a fifth basis vector, 49 * having the wrong idea of whether the edge is divided), or if you
93 * because then (-1,1,-1,1,0) and (0,0,0,0,1) would have had to be 50 * refer to a child triangle type that doesn't exist in that parent.
94 * considered identical. So leaving E out is vital.) 51 * If it ever happens in the production code then an assertion will
52 * fail. But it might be useful to other users of the same code.
95 */ 53 */
96 54typedef struct TransitionResult {
97struct vector { int a, b, c, d; }; 55 enum { INTERNAL, EXTERNAL, FAIL } type;
98 56 union {
99static vector v_origin(void) 57 struct {
58 char new_child;
59 unsigned char new_edge;
60 } internal;
61 struct {
62 unsigned char parent_edge;
63 signed char end;
64 } external;
65 } u;
66} TransitionResult;
67
68/* Construction function to make an INTERNAL-type TransitionResult */
69static inline TransitionResult internal(char new_child, unsigned new_edge)
100{ 70{
101 vector v; 71 TransitionResult tr;
102 v.a = v.b = v.c = v.d = 0; 72 tr.type = INTERNAL;
103 return v; 73 tr.u.internal.new_child = new_child;
74 tr.u.internal.new_edge = new_edge;
75 return tr;
104} 76}
105 77
106/* We start with a unit vector of B: this means we can easily 78/* Construction function to make an EXTERNAL-type TransitionResult */
107 * draw an isoceles triangle centred on the X axis. */ 79static inline TransitionResult external(unsigned parent_edge, int end)
108#ifdef TEST_VECTORS 80{
81 TransitionResult tr;
82 tr.type = EXTERNAL;
83 tr.u.external.parent_edge = parent_edge;
84 tr.u.external.end = end;
85 return tr;
86}
109 87
110static vector v_unit(void) 88/* Construction function to make a FAIL-type TransitionResult */
89static inline TransitionResult fail(void)
111{ 90{
112 vector v; 91 TransitionResult tr;
92 tr.type = FAIL;
93 return tr;
94}
113 95
114 v.b = 1; 96/*
115 v.a = v.c = v.d = 0; 97 * Compute a transition out of a triangle. Can return either INTERNAL
116 return v; 98 * or EXTERNAL types (or FAIL if it gets invalid data).
99 */
100static TransitionResult transition(char parent, char child, unsigned edge)
101{
102 switch (parent) {
103 case 'A':
104 switch (child) {
105 case 'A':
106 switch (edge) {
107 case 0: return external(2, -1);
108 case 1: return external(0, 0);
109 case 2: return internal('B', 1);
110 }
111 case 'B':
112 switch (edge) {
113 case 0: return internal('U', 1);
114 case 1: return internal('A', 2);
115 case 2: return external(1, +1);
116 }
117 case 'U':
118 switch (edge) {
119 case 0: return external(2, +1);
120 case 1: return internal('B', 0);
121 case 2: return external(1, -1);
122 }
123 default:
124 return fail();
125 }
126 case 'B':
127 switch (child) {
128 case 'A':
129 switch (edge) {
130 case 0: return internal('V', 2);
131 case 1: return external(2, -1);
132 case 2: return internal('B', 1);
133 }
134 case 'B':
135 switch (edge) {
136 case 0: return external(1, +1);
137 case 1: return internal('A', 2);
138 case 2: return external(0, 0);
139 }
140 case 'V':
141 switch (edge) {
142 case 0: return external(1, -1);
143 case 1: return external(2, +1);
144 case 2: return internal('A', 0);
145 }
146 default:
147 return fail();
148 }
149 case 'U':
150 switch (child) {
151 case 'B':
152 switch (edge) {
153 case 0: return internal('U', 1);
154 case 1: return external(2, 0);
155 case 2: return external(0, +1);
156 }
157 case 'U':
158 switch (edge) {
159 case 0: return external(1, 0);
160 case 1: return internal('B', 0);
161 case 2: return external(0, -1);
162 }
163 default:
164 return fail();
165 }
166 case 'V':
167 switch (child) {
168 case 'A':
169 switch (edge) {
170 case 0: return internal('V', 2);
171 case 1: return external(0, -1);
172 case 2: return external(1, 0);
173 }
174 case 'V':
175 switch (edge) {
176 case 0: return external(2, 0);
177 case 1: return external(0, +1);
178 case 2: return internal('A', 0);
179 }
180 default:
181 return fail();
182 }
183 case 'C':
184 switch (child) {
185 case 'C':
186 switch (edge) {
187 case 0: return external(1, +1);
188 case 1: return internal('Y', 1);
189 case 2: return external(0, 0);
190 }
191 case 'Y':
192 switch (edge) {
193 case 0: return external(2, 0);
194 case 1: return internal('C', 1);
195 case 2: return external(1, -1);
196 }
197 default:
198 return fail();
199 }
200 case 'D':
201 switch (child) {
202 case 'D':
203 switch (edge) {
204 case 0: return external(2, -1);
205 case 1: return external(0, 0);
206 case 2: return internal('X', 2);
207 }
208 case 'X':
209 switch (edge) {
210 case 0: return external(1, 0);
211 case 1: return external(2, +1);
212 case 2: return internal('D', 2);
213 }
214 default:
215 return fail();
216 }
217 case 'X':
218 switch (child) {
219 case 'C':
220 switch (edge) {
221 case 0: return external(2, +1);
222 case 1: return internal('Y', 1);
223 case 2: return internal('X', 1);
224 }
225 case 'X':
226 switch (edge) {
227 case 0: return external(1, 0);
228 case 1: return internal('C', 2);
229 case 2: return external(0, -1);
230 }
231 case 'Y':
232 switch (edge) {
233 case 0: return external(0, +1);
234 case 1: return internal('C', 1);
235 case 2: return external(2, -1);
236 }
237 default:
238 return fail();
239 }
240 case 'Y':
241 switch (child) {
242 case 'D':
243 switch (edge) {
244 case 0: return external(1, -1);
245 case 1: return internal('Y', 2);
246 case 2: return internal('X', 2);
247 }
248 case 'X':
249 switch (edge) {
250 case 0: return external(0, -1);
251 case 1: return external(1, +1);
252 case 2: return internal('D', 2);
253 }
254 case 'Y':
255 switch (edge) {
256 case 0: return external(2, 0);
257 case 1: return external(0, +1);
258 case 2: return internal('D', 1);
259 }
260 default:
261 return fail();
262 }
263 default:
264 return fail();
265 }
117} 266}
118 267
119#endif 268/*
269 * Compute a transition into a parent triangle, after the above
270 * function reported an EXTERNAL transition out of a neighbouring
271 * parent and we had to recurse. Because we're coming inwards, this
272 * should always return an INTERNAL TransitionResult (or FAIL if it
273 * gets invalid data).
274 */
275static TransitionResult transition_in(char parent, unsigned edge, int end)
276{
277 #define EDGEEND(edge, end) (3 * (edge) + 1 + (end))
278
279 switch (parent) {
280 case 'A':
281 switch (EDGEEND(edge, end)) {
282 case EDGEEND(0, 0): return internal('A', 1);
283 case EDGEEND(1, -1): return internal('B', 2);
284 case EDGEEND(1, +1): return internal('U', 2);
285 case EDGEEND(2, -1): return internal('U', 0);
286 case EDGEEND(2, +1): return internal('A', 0);
287 default:
288 return fail();
289 }
290 case 'B':
291 switch (EDGEEND(edge, end)) {
292 case EDGEEND(0, 0): return internal('B', 2);
293 case EDGEEND(1, -1): return internal('B', 0);
294 case EDGEEND(1, +1): return internal('V', 0);
295 case EDGEEND(2, -1): return internal('V', 1);
296 case EDGEEND(2, +1): return internal('A', 1);
297 default:
298 return fail();
299 }
300 case 'U':
301 switch (EDGEEND(edge, end)) {
302 case EDGEEND(0, -1): return internal('B', 2);
303 case EDGEEND(0, +1): return internal('U', 2);
304 case EDGEEND(1, 0): return internal('U', 0);
305 case EDGEEND(2, 0): return internal('B', 1);
306 default:
307 return fail();
308 }
309 case 'V':
310 switch (EDGEEND(edge, end)) {
311 case EDGEEND(0, -1): return internal('V', 1);
312 case EDGEEND(0, +1): return internal('A', 1);
313 case EDGEEND(1, 0): return internal('A', 2);
314 case EDGEEND(2, 0): return internal('V', 0);
315 default:
316 return fail();
317 }
318 case 'C':
319 switch (EDGEEND(edge, end)) {
320 case EDGEEND(0, 0): return internal('C', 2);
321 case EDGEEND(1, -1): return internal('C', 0);
322 case EDGEEND(1, +1): return internal('Y', 2);
323 case EDGEEND(2, 0): return internal('Y', 0);
324 default:
325 return fail();
326 }
327 case 'D':
328 switch (EDGEEND(edge, end)) {
329 case EDGEEND(0, 0): return internal('D', 1);
330 case EDGEEND(1, 0): return internal('X', 0);
331 case EDGEEND(2, -1): return internal('X', 1);
332 case EDGEEND(2, +1): return internal('D', 0);
333 default:
334 return fail();
335 }
336 case 'X':
337 switch (EDGEEND(edge, end)) {
338 case EDGEEND(0, -1): return internal('Y', 0);
339 case EDGEEND(0, +1): return internal('X', 2);
340 case EDGEEND(1, 0): return internal('X', 0);
341 case EDGEEND(2, -1): return internal('C', 0);
342 case EDGEEND(2, +1): return internal('Y', 2);
343 default:
344 return fail();
345 }
346 case 'Y':
347 switch (EDGEEND(edge, end)) {
348 case EDGEEND(0, +1): return internal('X', 0);
349 case EDGEEND(0, -1): return internal('Y', 1);
350 case EDGEEND(1, -1): return internal('X', 1);
351 case EDGEEND(1, +1): return internal('D', 0);
352 case EDGEEND(2, 0): return internal('Y', 0);
353 default:
354 return fail();
355 }
356 default:
357 return fail();
358 }
120 359
121#define COS54 0.5877852 360 #undef EDGEEND
122#define SIN54 0.8090169 361}
123#define COS18 0.9510565
124#define SIN18 0.3090169
125 362
126/* These two are a bit rough-and-ready for now. Note that B/C are 363PenroseCoords *penrose_coords_new(void)
127 * 18 degrees from the x-axis, and A/D are 54 degrees. */
128double v_x(vector *vs, int i)
129{ 364{
130 return (vs[i].a + vs[i].d) * COS54 + 365 PenroseCoords *pc = snew(PenroseCoords);
131 (vs[i].b + vs[i].c) * COS18; 366 pc->nc = pc->csize = 0;
367 pc->c = NULL;
368 return pc;
132} 369}
133 370
134double v_y(vector *vs, int i) 371void penrose_coords_free(PenroseCoords *pc)
135{ 372{
136 return (vs[i].a - vs[i].d) * SIN54 + 373 if (pc) {
137 (vs[i].b - vs[i].c) * SIN18; 374 sfree(pc->c);
138 375 sfree(pc);
376 }
139} 377}
140 378
141static vector v_trans(vector v, vector trans) 379void penrose_coords_make_space(PenroseCoords *pc, size_t size)
142{ 380{
143 v.a += trans.a; 381 if (pc->csize < size) {
144 v.b += trans.b; 382 pc->csize = pc->csize * 5 / 4 + 16;
145 v.c += trans.c; 383 if (pc->csize < size)
146 v.d += trans.d; 384 pc->csize = size;
147 return v; 385 pc->c = sresize(pc->c, pc->csize, char);
386 }
148} 387}
149 388
150static vector v_rotate_36(vector v) 389PenroseCoords *penrose_coords_copy(PenroseCoords *pc_in)
151{ 390{
152 vector vv; 391 PenroseCoords *pc_out = penrose_coords_new();
153 vv.a = -v.d; 392 penrose_coords_make_space(pc_out, pc_in->nc);
154 vv.b = v.d + v.a; 393 memcpy(pc_out->c, pc_in->c, pc_in->nc * sizeof(*pc_out->c));
155 vv.c = -v.d + v.b; 394 pc_out->nc = pc_in->nc;
156 vv.d = v.d + v.c; 395 return pc_out;
157 return vv;
158} 396}
159 397
160static vector v_rotate(vector v, int ang) 398/*
399 * The main recursive function for computing the next triangle's
400 * combinatorial coordinates.
401 */
402static void penrosectx_step_recurse(
403 PenroseContext *ctx, PenroseCoords *pc, size_t depth,
404 unsigned edge, unsigned *outedge)
161{ 405{
162 int i; 406 TransitionResult tr;
407
408 penrosectx_extend_coords(ctx, pc, depth+2);
409
410 /* Look up the transition out of the starting triangle */
411 tr = transition(pc->c[depth+1], pc->c[depth], edge);
412
413 /* If we've left the parent triangle, recurse to find out what new
414 * triangle we've landed in at the next size up, and then call
415 * transition_in to find out which child of that parent we're
416 * going to */
417 if (tr.type == EXTERNAL) {
418 unsigned parent_outedge;
419 penrosectx_step_recurse(
420 ctx, pc, depth+1, tr.u.external.parent_edge, &parent_outedge);
421 tr = transition_in(pc->c[depth+1], parent_outedge, tr.u.external.end);
422 }
163 423
164 assert((ang % 36) == 0); 424 /* Now we should definitely have ended up in a child of the
165 while (ang < 0) ang += 360; 425 * (perhaps rewritten) parent triangle */
166 ang = 360-ang; 426 assert(tr.type == INTERNAL);
167 for (i = 0; i < (ang/36); i++) 427 pc->c[depth] = tr.u.internal.new_child;
168 v = v_rotate_36(v); 428 *outedge = tr.u.internal.new_edge;
169 return v;
170} 429}
171 430
172#ifdef TEST_VECTORS 431void penrosectx_step(PenroseContext *ctx, PenroseCoords *pc,
173 432 unsigned edge, unsigned *outedge)
174static vector v_scale(vector v, int sc)
175{ 433{
176 v.a *= sc; 434 /* Allow outedge to be NULL harmlessly, just in case */
177 v.b *= sc; 435 unsigned dummy_outedge;
178 v.c *= sc; 436 if (!outedge)
179 v.d *= sc; 437 outedge = &dummy_outedge;
180 return v;
181}
182 438
183#endif 439 penrosectx_step_recurse(ctx, pc, 0, edge, outedge);
440}
184 441
185static vector v_growphi(vector v) 442static Point penrose_triangle_post_edge(char c, unsigned edge)
186{ 443{
187 vector vv; 444 static const Point acute_post_edge[3] = {
188 vv.a = v.a + v.b - v.d; 445 {{-1, 1, 0, 1}}, /* phi * t^3 */
189 vv.b = v.c + v.d; 446 {{-1, 1, -1, 1}}, /* t^4 */
190 vv.c = v.a + v.b; 447 {{-1, 1, 0, 0}}, /* 1/phi * t^3 */
191 vv.d = v.c + v.d - v.a; 448 };
192 return vv; 449 static const Point obtuse_post_edge[3] = {
450 {{0, -1, 1, 0}}, /* 1/phi * t^4 */
451 {{0, 0, 1, 0}}, /* t^2 */
452 {{-1, 0, 0, 1}}, /* phi * t^4 */
453 };
454
455 switch (c) {
456 case 'A': case 'B': case 'C': case 'D':
457 return acute_post_edge[edge];
458 default: /* case 'U': case 'V': case 'X': case 'Y': */
459 return obtuse_post_edge[edge];
460 }
193} 461}
194 462
195static vector v_shrinkphi(vector v) 463void penrose_place(PenroseTriangle *tri, Point u, Point v, int index_of_u)
196{ 464{
197 vector vv; 465 unsigned i;
198 vv.a = v.b - v.d; 466 Point here = u, delta = point_sub(v, u);
199 vv.b = v.c + v.d - v.b; 467
200 vv.c = v.a + v.b - v.c; 468 for (i = 0; i < 3; i++) {
201 vv.d = v.c - v.a; 469 unsigned edge = (index_of_u + i) % 3;
202 return vv; 470 tri->vertices[edge] = here;
471 here = point_add(here, delta);
472 delta = point_mul(delta, penrose_triangle_post_edge(
473 tri->pc->c[0], edge));
474 }
203} 475}
204 476
205#ifdef TEST_VECTORS 477void penrose_free(PenroseTriangle *tri)
206
207static const char *v_debug(vector v)
208{ 478{
209 static char buf[255]; 479 penrose_coords_free(tri->pc);
210 sprintf(buf, 480 sfree(tri);
211 "(%d,%d,%d,%d)[%2.2f,%2.2f]",
212 v.a, v.b, v.c, v.d, v_x(&v,0), v_y(&v,0));
213 return buf;
214} 481}
215 482
216#endif 483static bool penrose_relative_probability(char c)
217
218/* -------------------------------------------------------
219 * Tiling routines.
220 */
221
222static vector xform_coord(vector vo, int shrink, vector vtrans, int ang)
223{ 484{
224 if (shrink < 0) 485 /* Penrose tile probability ratios are always phi, so we can
225 vo = v_shrinkphi(vo); 486 * approximate that very well using two consecutive Fibonacci
226 else if (shrink > 0) 487 * numbers */
227 vo = v_growphi(vo); 488 switch (c) {
228 489 case 'A': case 'B': case 'X': case 'Y':
229 vo = v_rotate(vo, ang); 490 return 165580141;
230 vo = v_trans(vo, vtrans); 491 case 'C': case 'D': case 'U': case 'V':
231 492 return 102334155;
232 return vo; 493 default:
494 return 0;
495 }
233} 496}
234 497
235 498static char penrose_choose_random(const char *possibilities, random_state *rs)
236#define XFORM(n,o,s,a) vs[(n)] = xform_coord(v_edge, (s), vs[(o)], (a))
237
238static int penrose_p2_small(penrose_state *state, int depth, int flip,
239 vector v_orig, vector v_edge);
240
241static int penrose_p2_large(penrose_state *state, int depth, int flip,
242 vector v_orig, vector v_edge)
243{ 499{
244 vector vv_orig, vv_edge; 500 const char *p;
245 501 unsigned long value, limit = 0;
246#ifdef DEBUG_PENROSE 502
247 { 503 for (p = possibilities; *p; p++)
248 vector vs[3]; 504 limit += penrose_relative_probability(*p);
249 vs[0] = v_orig; 505 value = random_upto(rs, limit);
250 XFORM(1, 0, 0, 0); 506 for (p = possibilities; *p; p++) {
251 XFORM(2, 0, 0, -36*flip); 507 unsigned long curr = penrose_relative_probability(*p);
252 508 if (value < curr)
253 state->new_tile(state, vs, 3, depth); 509 return *p;
510 value -= curr;
254 } 511 }
255#endif 512 assert(false && "Probability overflow!");
256 513 return possibilities[0];
257 if (flip > 0) { 514}
258 vector vs[4];
259 515
260 vs[0] = v_orig; 516static const char *penrose_starting_tiles(int which)
261 XFORM(1, 0, 0, -36); 517{
262 XFORM(2, 0, 0, 0); 518 return which == PENROSE_P2 ? "ABUV" : "CDXY";
263 XFORM(3, 0, 0, 36); 519}
264 520
265 state->new_tile(state, vs, 4, depth); 521static const char *penrose_valid_parents(char tile)
522{
523 switch (tile) {
524 case 'A': return "ABV";
525 case 'B': return "ABU";
526 case 'U': return "AU";
527 case 'V': return "BV";
528 case 'C': return "CX";
529 case 'D': return "DY";
530 case 'X': return "DXY";
531 case 'Y': return "CXY";
532 default: return NULL;
266 } 533 }
267 if (depth >= state->max_depth) return 0; 534}
268
269 vv_orig = v_trans(v_orig, v_rotate(v_edge, -36*flip));
270 vv_edge = v_rotate(v_edge, 108*flip);
271
272 penrose_p2_small(state, depth+1, flip,
273 v_orig, v_shrinkphi(v_edge));
274 535
275 penrose_p2_large(state, depth+1, flip, 536void penrosectx_init_random(PenroseContext *ctx, random_state *rs, int which)
276 vv_orig, v_shrinkphi(vv_edge)); 537{
277 penrose_p2_large(state, depth+1, -flip, 538 ctx->rs = rs;
278 vv_orig, v_shrinkphi(vv_edge)); 539 ctx->must_free_rs = false;
540 ctx->prototype = penrose_coords_new();
541 penrose_coords_make_space(ctx->prototype, 1);
542 ctx->prototype->c[0] = penrose_choose_random(
543 penrose_starting_tiles(which), rs);
544 ctx->prototype->nc = 1;
545 ctx->start_vertex = random_upto(rs, 3);
546 ctx->orientation = random_upto(rs, 10);
547}
279 548
280 return 0; 549void penrosectx_init_from_params(
550 PenroseContext *ctx, const struct PenrosePatchParams *ps)
551{
552 size_t i;
553
554 ctx->rs = NULL;
555 ctx->must_free_rs = false;
556 ctx->prototype = penrose_coords_new();
557 penrose_coords_make_space(ctx->prototype, ps->ncoords);
558 for (i = 0; i < ps->ncoords; i++)
559 ctx->prototype->c[i] = ps->coords[i];
560 ctx->prototype->nc = ps->ncoords;
561 ctx->start_vertex = ps->start_vertex;
562 ctx->orientation = ps->orientation;
281} 563}
282 564
283static int penrose_p2_small(penrose_state *state, int depth, int flip, 565void penrosectx_cleanup(PenroseContext *ctx)
284 vector v_orig, vector v_edge)
285{ 566{
286 vector vv_orig; 567 if (ctx->must_free_rs)
568 random_free(ctx->rs);
569 penrose_coords_free(ctx->prototype);
570}
287 571
288#ifdef DEBUG_PENROSE 572PenroseCoords *penrosectx_initial_coords(PenroseContext *ctx)
289 { 573{
290 vector vs[3]; 574 return penrose_coords_copy(ctx->prototype);
291 vs[0] = v_orig; 575}
292 XFORM(1, 0, 0, 0);
293 XFORM(2, 0, -1, -36*flip);
294 576
295 state->new_tile(state, vs, 3, depth); 577void penrosectx_extend_coords(PenroseContext *ctx, PenroseCoords *pc,
578 size_t n)
579{
580 if (ctx->prototype->nc < n) {
581 penrose_coords_make_space(ctx->prototype, n);
582 while (ctx->prototype->nc < n) {
583 if (!ctx->rs) {
584 /*
585 * For safety, similarly to spectre.c, we respond to a
586 * lack of available random_state by making a
587 * deterministic one.
588 */
589 ctx->rs = random_new("dummy", 5);
590 ctx->must_free_rs = true;
591 }
592
593 ctx->prototype->c[ctx->prototype->nc] = penrose_choose_random(
594 penrose_valid_parents(ctx->prototype->c[ctx->prototype->nc-1]),
595 ctx->rs);
596 ctx->prototype->nc++;
597 }
296 } 598 }
297#endif
298
299 if (flip > 0) {
300 vector vs[4];
301
302 vs[0] = v_orig;
303 XFORM(1, 0, 0, -72);
304 XFORM(2, 0, -1, -36);
305 XFORM(3, 0, 0, 0);
306 599
307 state->new_tile(state, vs, 4, depth); 600 penrose_coords_make_space(pc, n);
601 while (pc->nc < n) {
602 pc->c[pc->nc] = ctx->prototype->c[pc->nc];
603 pc->nc++;
308 } 604 }
309
310 if (depth >= state->max_depth) return 0;
311
312 vv_orig = v_trans(v_orig, v_edge);
313
314 penrose_p2_large(state, depth+1, -flip,
315 v_orig, v_shrinkphi(v_rotate(v_edge, -36*flip)));
316
317 penrose_p2_small(state, depth+1, flip,
318 vv_orig, v_shrinkphi(v_rotate(v_edge, -144*flip)));
319
320 return 0;
321} 605}
322 606
323static int penrose_p3_small(penrose_state *state, int depth, int flip, 607static Point penrose_triangle_edge_0_length(char c)
324 vector v_orig, vector v_edge);
325
326static int penrose_p3_large(penrose_state *state, int depth, int flip,
327 vector v_orig, vector v_edge)
328{ 608{
329 vector vv_orig; 609 static const Point one = {{ 1, 0, 0, 0 }};
330 610 static const Point phi = {{ 1, 0, 1, -1 }};
331#ifdef DEBUG_PENROSE 611 static const Point invphi = {{ 0, 0, 1, -1 }};
332 { 612
333 vector vs[3]; 613 switch (c) {
334 vs[0] = v_orig; 614 /* P2 tiling: unit-length edges are the long edges, i.e. edges
335 XFORM(1, 0, 1, 0); 615 * 1,2 of AB and edge 0 of UV. So AB have edge 0 short. */
336 XFORM(2, 0, 0, -36*flip); 616 case 'A': case 'B':
337 617 return invphi;
338 state->new_tile(state, vs, 3, depth); 618 case 'U': case 'V':
619 return one;
620
621 /* P3 tiling: unit-length edges are edges 1,2 of everything,
622 * so CD have edge 0 short and XY have it long. */
623 case 'C': case 'D':
624 return invphi;
625 default: /* case 'X': case 'Y': */
626 return phi;
339 } 627 }
340#endif 628}
341 629
342 if (flip > 0) { 630PenroseTriangle *penrose_initial(PenroseContext *ctx)
343 vector vs[4]; 631{
632 char type = ctx->prototype->c[0];
633 Point origin = {{ 0, 0, 0, 0 }};
634 Point edge0 = penrose_triangle_edge_0_length(type);
635 Point negoffset;
636 size_t i;
637 PenroseTriangle *tri = snew(PenroseTriangle);
638
639 /* Orient the triangle by deciding what vector edge #0 should traverse */
640 edge0 = point_mul(edge0, point_rot(ctx->orientation));
641
642 /* Place the triangle at an arbitrary position, in that orientation */
643 tri->pc = penrose_coords_copy(ctx->prototype);
644 penrose_place(tri, origin, edge0, 0);
645
646 /* Now translate so that the appropriate vertex is at the origin */
647 negoffset = tri->vertices[ctx->start_vertex];
648 for (i = 0; i < 3; i++)
649 tri->vertices[i] = point_sub(tri->vertices[i], negoffset);
650
651 return tri;
652}
344 653
345 vs[0] = v_orig; 654PenroseTriangle *penrose_adjacent(PenroseContext *ctx,
346 XFORM(1, 0, 0, -36); 655 const PenroseTriangle *src_tri,
347 XFORM(2, 0, 1, 0); 656 unsigned src_edge, unsigned *dst_edge_out)
348 XFORM(3, 0, 0, 36); 657{
658 unsigned dst_edge;
659 PenroseTriangle *dst_tri = snew(PenroseTriangle);
660 dst_tri->pc = penrose_coords_copy(src_tri->pc);
661 penrosectx_step(ctx, dst_tri->pc, src_edge, &dst_edge);
662 penrose_place(dst_tri, src_tri->vertices[(src_edge+1) % 3],
663 src_tri->vertices[src_edge], dst_edge);
664 if (dst_edge_out)
665 *dst_edge_out = dst_edge;
666 return dst_tri;
667}
349 668
350 state->new_tile(state, vs, 4, depth); 669static int penrose_cmp(void *av, void *bv)
670{
671 PenroseTriangle *a = (PenroseTriangle *)av, *b = (PenroseTriangle *)bv;
672 size_t i, j;
673
674 /* We should only ever need to compare the first two vertices of
675 * any triangle, because those force the rest */
676 for (i = 0; i < 2; i++) {
677 for (j = 0; j < 4; j++) {
678 int ac = a->vertices[i].coeffs[j], bc = b->vertices[i].coeffs[j];
679 if (ac < bc)
680 return -1;
681 if (ac > bc)
682 return +1;
683 }
351 } 684 }
352 if (depth >= state->max_depth) return 0;
353
354 vv_orig = v_trans(v_orig, v_edge);
355
356 penrose_p3_large(state, depth+1, -flip,
357 vv_orig, v_shrinkphi(v_rotate(v_edge, 180)));
358
359 penrose_p3_small(state, depth+1, flip,
360 vv_orig, v_shrinkphi(v_rotate(v_edge, -108*flip)));
361
362 vv_orig = v_trans(v_orig, v_growphi(v_edge));
363
364 penrose_p3_large(state, depth+1, flip,
365 vv_orig, v_shrinkphi(v_rotate(v_edge, -144*flip)));
366
367 685
368 return 0; 686 return 0;
369} 687}
370 688
371static int penrose_p3_small(penrose_state *state, int depth, int flip, 689static unsigned penrose_sibling_edge_index(char c)
372 vector v_orig, vector v_edge)
373{ 690{
374 vector vv_orig; 691 switch (c) {
375 692 case 'A': case 'U': return 2;
376#ifdef DEBUG_PENROSE 693 case 'B': case 'V': return 1;
377 { 694 default: return 0;
378 vector vs[3];
379 vs[0] = v_orig;
380 XFORM(1, 0, 0, 0);
381 XFORM(2, 0, 0, -36*flip);
382
383 state->new_tile(state, vs, 3, depth);
384 } 695 }
385#endif 696}
386
387 if (flip > 0) {
388 vector vs[4];
389
390 vs[0] = v_orig;
391 XFORM(1, 0, 0, -36);
392 XFORM(3, 0, 0, 0);
393 XFORM(2, 3, 0, -36);
394 697
395 state->new_tile(state, vs, 4, depth); 698void penrosectx_generate(
396 } 699 PenroseContext *ctx,
397 if (depth >= state->max_depth) return 0; 700 bool (*inbounds)(void *inboundsctx,
701 const PenroseTriangle *tri), void *inboundsctx,
702 void (*tile)(void *tilectx, const Point *vertices), void *tilectx)
703{
704 tree234 *placed = newtree234(penrose_cmp);
705 PenroseTriangle *qhead = NULL, *qtail = NULL;
398 706
399 /* NB these two are identical to the first two of p3_large. */ 707 {
400 vv_orig = v_trans(v_orig, v_edge); 708 PenroseTriangle *tri = penrose_initial(ctx);
401 709
402 penrose_p3_large(state, depth+1, -flip, 710 add234(placed, tri);
403 vv_orig, v_shrinkphi(v_rotate(v_edge, 180)));
404 711
405 penrose_p3_small(state, depth+1, flip, 712 tri->next = NULL;
406 vv_orig, v_shrinkphi(v_rotate(v_edge, -108*flip))); 713 tri->reported = false;
407 714
408 return 0; 715 if (inbounds(inboundsctx, tri))
409} 716 qhead = qtail = tri;
717 }
410 718
411/* ------------------------------------------------------- 719 while (qhead) {
412 * Utility routines. 720 PenroseTriangle *tri = qhead;
413 */ 721 unsigned edge;
722 unsigned sibling_edge = penrose_sibling_edge_index(tri->pc->c[0]);
723
724 for (edge = 0; edge < 3; edge++) {
725 PenroseTriangle *new_tri, *found_tri;
726
727 new_tri = penrose_adjacent(ctx, tri, edge, NULL);
728
729 if (!inbounds(inboundsctx, new_tri)) {
730 penrose_free(new_tri);
731 continue;
732 }
733
734 found_tri = find234(placed, new_tri, NULL);
735 if (found_tri) {
736 if (edge == sibling_edge && !tri->reported &&
737 !found_tri->reported) {
738 /*
739 * found_tri and tri are opposite halves of the
740 * same tile; both are in the tree, and haven't
741 * yet been reported as a completed tile.
742 */
743 unsigned new_sibling_edge = penrose_sibling_edge_index(
744 found_tri->pc->c[0]);
745 Point tilevertices[4] = {
746 tri->vertices[(sibling_edge + 1) % 3],
747 tri->vertices[(sibling_edge + 2) % 3],
748 found_tri->vertices[(new_sibling_edge + 1) % 3],
749 found_tri->vertices[(new_sibling_edge + 2) % 3],
750 };
751 tile(tilectx, tilevertices);
752
753 tri->reported = true;
754 found_tri->reported = true;
755 }
756
757 penrose_free(new_tri);
758 continue;
759 }
760
761 add234(placed, new_tri);
762 qtail->next = new_tri;
763 qtail = new_tri;
764 new_tri->next = NULL;
765 new_tri->reported = false;
766 }
414 767
415double penrose_side_length(double start_size, int depth) 768 qhead = qhead->next;
416{ 769 }
417 return start_size / pow(PHI, depth);
418}
419 770
420void penrose_count_tiles(int depth, int *nlarge, int *nsmall) 771 {
421{ 772 PenroseTriangle *tri;
422 /* Steal sgt's fibonacci thingummy. */ 773 while ((tri = delpos234(placed, 0)) != NULL)
774 penrose_free(tri);
775 freetree234(placed);
776 }
423} 777}
424 778
425/* 779const char *penrose_tiling_params_invalid(
426 * It turns out that an acute isosceles triangle with sides in ratio 1:phi:phi 780 const struct PenrosePatchParams *params, int which)
427 * has an incentre which is conveniently 2*phi^-2 of the way from the apex to
428 * the base. Why's that convenient? Because: if we situate the incentre of the
429 * triangle at the origin, then we can place the apex at phi^-2 * (B+C), and
430 * the other two vertices at apex-B and apex-C respectively. So that's an acute
431 * triangle with its long sides of unit length, covering a circle about the
432 * origin of radius 1-(2*phi^-2), which is conveniently enough phi^-3.
433 *
434 * (later mail: this is an overestimate by about 5%)
435 */
436
437int penrose(penrose_state *state, int which, int angle)
438{ 781{
439 vector vo = v_origin(); 782 size_t i;
440 vector vb = v_origin();
441
442 vo.b = vo.c = -state->start_size;
443 vo = v_shrinkphi(v_shrinkphi(vo));
444
445 vb.b = state->start_size;
446 783
447 vo = v_rotate(vo, angle); 784 if (params->ncoords == 0)
448 vb = v_rotate(vb, angle); 785 return "expected at least one coordinate";
449 786
450 if (which == PENROSE_P2) 787 for (i = 0; i < params->ncoords; i++) {
451 return penrose_p2_large(state, 0, 1, vo, vb); 788 if (!penrose_valid_letter(params->coords[i], which))
452 else 789 return "invalid coordinate letter";
453 return penrose_p3_small(state, 0, 1, vo, vb); 790 if (i > 0 && !strchr(penrose_valid_parents(params->coords[i-1]),
454} 791 params->coords[i]))
455 792 return "invalid pair of consecutive coordinates";
456/*
457 * We're asked for a MxN grid, which just means a tiling fitting into roughly
458 * an MxN space in some kind of reasonable unit - say, the side length of the
459 * two-arrow edges of the tiles. By some reasoning in a previous email, that
460 * means we want to pick some subarea of a circle of radius 3.11*sqrt(M^2+N^2).
461 * To cover that circle, we need to subdivide a triangle large enough that it
462 * contains a circle of that radius.
463 *
464 * Hence: start with those three vectors marking triangle vertices, scale them
465 * all up by phi repeatedly until the radius of the inscribed circle gets
466 * bigger than the target, and then recurse into that triangle with the same
467 * recursion depth as the number of times you scaled up. That will give you
468 * tiles of unit side length, covering a circle big enough that if you randomly
469 * choose an orientation and coordinates within the circle, you'll be able to
470 * get any valid piece of Penrose tiling of size MxN.
471 */
472#define INCIRCLE_RADIUS 0.22426 /* phi^-3 less 5%: see above */
473
474void penrose_calculate_size(int which, int tilesize, int w, int h,
475 double *required_radius, int *start_size, int *depth)
476{
477 double rradius, size;
478 int n = 0;
479
480 /*
481 * Fudge factor to scale P2 and P3 tilings differently. This
482 * doesn't seem to have much relevance to questions like the
483 * average number of tiles per unit area; it's just aesthetic.
484 */
485 if (which == PENROSE_P2)
486 tilesize = tilesize * 3 / 2;
487 else
488 tilesize = tilesize * 5 / 4;
489
490 rradius = tilesize * 3.11 * sqrt((double)(w*w + h*h));
491 size = tilesize;
492
493 while ((size * INCIRCLE_RADIUS) < rradius) {
494 n++;
495 size = size * PHI;
496 } 793 }
497 794
498 *start_size = (int)size; 795 return NULL;
499 *depth = n;
500 *required_radius = rradius;
501} 796}
502 797
503/* ------------------------------------------------------- 798struct PenroseOutputCtx {
504 * Test code. 799 int xoff, yoff;
505 */ 800 Coord xmin, xmax, ymin, ymax;
506
507#ifdef TEST_PENROSE
508
509#include <stdio.h>
510#include <string.h>
511 801
512int show_recursion = 0; 802 penrose_tile_callback_fn external_cb;
513int ntiles, nfinal; 803 void *external_cbctx;
804};
514 805
515int test_cb(penrose_state *state, vector *vs, int n, int depth) 806static bool inbounds(void *vctx, const PenroseTriangle *tri)
516{ 807{
517 int i, xoff = 0, yoff = 0; 808 struct PenroseOutputCtx *octx = (struct PenroseOutputCtx *)vctx;
518 double l = penrose_side_length(state->start_size, depth); 809 size_t i;
519 double rball = l / 10.0;
520 const char *col;
521 810
522 ntiles++; 811 for (i = 0; i < 3; i++) {
523 if (state->max_depth == depth) { 812 Coord x = point_x(tri->vertices[i]);
524 col = n == 4 ? "black" : "green"; 813 Coord y = point_y(tri->vertices[i]);
525 nfinal++;
526 } else {
527 if (!show_recursion)
528 return 0;
529 col = n == 4 ? "red" : "blue";
530 }
531 if (n != 4) yoff = state->start_size;
532 814
533 printf("<polygon points=\""); 815 if (coord_cmp(x, octx->xmin) < 0 || coord_cmp(x, octx->xmax) > 0 ||
534 for (i = 0; i < n; i++) { 816 coord_cmp(y, octx->ymin) < 0 || coord_cmp(y, octx->ymax) > 0)
535 printf("%s%f,%f", (i == 0) ? "" : " ", 817 return false;
536 v_x(vs, i) + xoff, v_y(vs, i) + yoff);
537 } 818 }
538 printf("\" style=\"fill: %s; fill-opacity: 0.2; stroke: %s\" />\n", col, col);
539 printf("<ellipse cx=\"%f\" cy=\"%f\" rx=\"%f\" ry=\"%f\" fill=\"%s\" />",
540 v_x(vs, 0) + xoff, v_y(vs, 0) + yoff, rball, rball, col);
541 819
542 return 0; 820 return true;
543} 821}
544 822
545void usage_exit(void) 823static void null_output_tile(void *vctx, const Point *vertices)
546{ 824{
547 fprintf(stderr, "Usage: penrose-test [--recursion] P2|P3 SIZE DEPTH\n");
548 exit(1);
549} 825}
550 826
551int main(int argc, char *argv[]) 827static void really_output_tile(void *vctx, const Point *vertices)
552{ 828{
553 penrose_state ps; 829 struct PenroseOutputCtx *octx = (struct PenroseOutputCtx *)vctx;
554 int which = 0; 830 size_t i;
555 831 int coords[16];
556 while (--argc > 0) { 832
557 char *p = *++argv; 833 for (i = 0; i < 4; i++) {
558 if (!strcmp(p, "-h") || !strcmp(p, "--help")) { 834 Coord x = point_x(vertices[i]);
559 usage_exit(); 835 Coord y = point_y(vertices[i]);
560 } else if (!strcmp(p, "--recursion")) { 836
561 show_recursion = 1; 837 coords[4*i + 0] = x.c1 + octx->xoff;
562 } else if (*p == '-') { 838 coords[4*i + 1] = x.cr5;
563 fprintf(stderr, "Unrecognised option '%s'\n", p); 839 coords[4*i + 2] = y.c1 + octx->yoff;
564 exit(1); 840 coords[4*i + 3] = y.cr5;
565 } else {
566 break;
567 }
568 } 841 }
569 842
570 if (argc < 3) usage_exit(); 843 octx->external_cb(octx->external_cbctx, coords);
571 844}
572 if (strcmp(argv[0], "P2") == 0) which = PENROSE_P2;
573 else if (strcmp(argv[0], "P3") == 0) which = PENROSE_P3;
574 else usage_exit();
575
576 ps.start_size = atoi(argv[1]);
577 ps.max_depth = atoi(argv[2]);
578 ps.new_tile = test_cb;
579
580 ntiles = nfinal = 0;
581
582 printf("\
583<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n\
584<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n\
585\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n\
586\n\
587<svg xmlns=\"http://www.w3.org/2000/svg\"\n\
588xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n\n");
589
590 printf("<g>\n");
591 penrose(&ps, which);
592 printf("</g>\n");
593 845
594 printf("<!-- %d tiles and %d leaf tiles total -->\n", 846static void penrose_set_bounds(struct PenroseOutputCtx *octx, int w, int h)
595 ntiles, nfinal); 847{
848 octx->xoff = w/2;
849 octx->yoff = h/2;
850 octx->xmin.c1 = -octx->xoff;
851 octx->xmax.c1 = -octx->xoff + w;
852 octx->ymin.c1 = octx->yoff - h;
853 octx->ymax.c1 = octx->yoff;
854 octx->xmin.cr5 = 0;
855 octx->xmax.cr5 = 0;
856 octx->ymin.cr5 = 0;
857 octx->ymax.cr5 = 0;
858}
596 859
597 printf("</svg>"); 860void penrose_tiling_randomise(struct PenrosePatchParams *params, int which,
861 int w, int h, random_state *rs)
862{
863 PenroseContext ctx[1];
864 struct PenroseOutputCtx octx[1];
598 865
599 return 0; 866 penrose_set_bounds(octx, w, h);
600}
601 867
602#endif 868 penrosectx_init_random(ctx, rs, which);
869 penrosectx_generate(ctx, inbounds, octx, null_output_tile, NULL);
603 870
604#ifdef TEST_VECTORS 871 params->orientation = ctx->orientation;
872 params->start_vertex = ctx->start_vertex;
873 params->ncoords = ctx->prototype->nc;
874 params->coords = snewn(params->ncoords, char);
875 memcpy(params->coords, ctx->prototype->c, params->ncoords);
605 876
606static void dbgv(const char *msg, vector v) 877 penrosectx_cleanup(ctx);
607{
608 printf("%s: %s\n", msg, v_debug(v));
609} 878}
610 879
611int main(int argc, const char *argv[]) 880void penrose_tiling_generate(
881 const struct PenrosePatchParams *params, int w, int h,
882 penrose_tile_callback_fn cb, void *cbctx)
612{ 883{
613 vector v = v_unit(); 884 PenroseContext ctx[1];
885 struct PenroseOutputCtx octx[1];
614 886
615 dbgv("unit vector", v); 887 penrose_set_bounds(octx, w, h);
616 v = v_rotate(v, 36); 888 octx->external_cb = cb;
617 dbgv("rotated 36", v); 889 octx->external_cbctx = cbctx;
618 v = v_scale(v, 2);
619 dbgv("scaled x2", v);
620 v = v_shrinkphi(v);
621 dbgv("shrunk phi", v);
622 v = v_rotate(v, -36);
623 dbgv("rotated -36", v);
624 890
625 return 0; 891 penrosectx_init_from_params(ctx, params);
892 penrosectx_generate(ctx, inbounds, octx, really_output_tile, octx);
893 penrosectx_cleanup(ctx);
626} 894}
627
628#endif
629/* vim: set shiftwidth=4 tabstop=8: */
diff --git a/apps/plugins/puzzles/src/penrose.h b/apps/plugins/puzzles/src/penrose.h
index ba5ae16f2c..e6e927d618 100644
--- a/apps/plugins/puzzles/src/penrose.h
+++ b/apps/plugins/puzzles/src/penrose.h
@@ -1,59 +1,86 @@
1/* penrose.h 1#ifndef PUZZLES_PENROSE_H
2 * 2#define PUZZLES_PENROSE_H
3 * Penrose tiling functions.
4 *
5 * Provides an interface with which to generate Penrose tilings
6 * by recursive subdivision of an initial tile of choice (one of the
7 * four sets of two pairs kite/dart, or thin/thick rhombus).
8 *
9 * You supply a callback function and a context pointer, which is
10 * called with each tile in turn: you choose how many times to recurse.
11 */
12 3
13#ifndef _PENROSE_H 4struct PenrosePatchParams {
14#define _PENROSE_H 5 /*
6 * A patch of Penrose tiling is identified by giving
7 *
8 * - the coordinates of the starting triangle, using a
9 * combinatorial coordinate system
10 *
11 * - which vertex of that triangle is at the centre point of the
12 * tiling
13 *
14 * - the orientation of the triangle's base edge, as a number
15 * from 0 to 9, measured in tenths of a turn
16 *
17 * Coordinates are a sequence of letters. For a P2 tiling all
18 * letters are from the set {A,B,U,V}; for P3, {C,D,X,Y}.
19 */
20 unsigned start_vertex;
21 int orientation;
22 size_t ncoords;
23 char *coords;
24};
15 25
16#ifndef PHI 26#ifndef PENROSE_ENUM_DEFINED
17#define PHI 1.6180339887 27#define PENROSE_ENUM_DEFINED
28enum { PENROSE_P2, PENROSE_P3 };
18#endif 29#endif
19 30
20typedef struct vector vector; 31bool penrose_valid_letter(char c, int which);
21
22double v_x(vector *vs, int i);
23double v_y(vector *vs, int i);
24 32
25typedef struct penrose_state penrose_state; 33/*
26 34 * Fill in PenrosePatchParams with a randomly selected set of
27/* Return non-zero to clip the tree here (i.e. not recurse 35 * coordinates, in enough detail to generate a patch of tiling filling
28 * below this tile). 36 * a w x h area.
37 *
38 * Units of measurement: the tiling will be oriented such that
39 * horizontal tile edges are possible (and therefore vertical ones are
40 * not). Therefore, all x-coordinates will be rational linear
41 * combinations of 1 and sqrt(5), and all y-coordinates will be
42 * sin(pi/5) times such a rational linear combination. By scaling up
43 * appropriately we can turn those rational combinations into
44 * _integer_ combinations, so we do. Therefore, w is measured in units
45 * of 1/4, and h is measured in units of sin(pi/5)/2, on a scale where
46 * a length of 1 corresponds to the legs of the acute isosceles
47 * triangles in the tiling (hence, the long edges of P2 kites and
48 * darts, or all edges of P3 rhombs).
29 * 49 *
30 * Parameters are state, vector array, npoints, depth. 50 * (In case it's useful, the y scale factor sin(pi/5)/2 is an
31 * ctx is inside state. 51 * algebraic number. Its minimal polynomial is 256x^4 - 80x^2 + 5.)
52 *
53 * The 'coords' field of the structure will be filled in with a new
54 * dynamically allocated array. Any previous pointer in that field
55 * will be overwritten.
32 */ 56 */
33typedef int (*tile_callback)(penrose_state *, vector *, int, int); 57void penrose_tiling_randomise(struct PenrosePatchParams *params, int which,
34 58 int w, int h, random_state *rs);
35struct penrose_state {
36 int start_size; /* initial side length */
37 int max_depth; /* Recursion depth */
38
39 tile_callback new_tile;
40 void *ctx; /* for callback */
41};
42 59
43enum { PENROSE_P2, PENROSE_P3 }; 60/*
44 61 * Validate a PenrosePatchParams to ensure it contains no illegal
45extern int penrose(penrose_state *state, int which, int angle); 62 * coordinates. Returns NULL if it's acceptable, or an error string if
63 * not.
64 */
65const char *penrose_tiling_params_invalid(
66 const struct PenrosePatchParams *params, int which);
46 67
47/* Returns the side-length of a penrose tile at recursion level 68/*
48 * gen, given a starting side length. */ 69 * Generate the actual set of Penrose tiles from a PenrosePatchParams,
49extern double penrose_side_length(double start_size, int depth); 70 * passing each one to a callback. The callback receives the vertices
71 * of each point, in the form of an array of 4*4 integers. Each vertex
72 * is represented by four consecutive integers in this array, with the
73 * first two giving the x coordinate and the last two the y
74 * coordinate. Each pair of integers a,b represent a single coordinate
75 * whose value is a + b*sqrt(5). The units of measurement for x and y
76 * are as described above.
77 */
78typedef void (*penrose_tile_callback_fn)(void *ctx, const int *coords);
50 79
51/* Returns the count of each type of tile at a given recursion depth. */ 80#define PENROSE_NVERTICES 4
52extern void penrose_count_tiles(int gen, int *nlarge, int *nsmall);
53 81
54/* Calculate start size and recursion depth required to produce a 82void penrose_tiling_generate(
55 * width-by-height sized patch of penrose tiles with the given tilesize */ 83 const struct PenrosePatchParams *params, int w, int h,
56extern void penrose_calculate_size(int which, int tilesize, int w, int h, 84 penrose_tile_callback_fn cb, void *cbctx);
57 double *required_radius, int *start_size, int *depth);
58 85
59#endif 86#endif
diff --git a/apps/plugins/puzzles/src/printing.c b/apps/plugins/puzzles/src/printing.c
index d1a3badaaa..0a911949a7 100644
--- a/apps/plugins/puzzles/src/printing.c
+++ b/apps/plugins/puzzles/src/printing.c
@@ -10,6 +10,7 @@
10struct puzzle { 10struct puzzle {
11 const game *game; 11 const game *game;
12 game_params *par; 12 game_params *par;
13 game_ui *ui;
13 game_state *st; 14 game_state *st;
14 game_state *st2; 15 game_state *st2;
15}; 16};
@@ -56,6 +57,7 @@ void document_free(document *doc)
56 57
57 for (i = 0; i < doc->npuzzles; i++) { 58 for (i = 0; i < doc->npuzzles; i++) {
58 doc->puzzles[i].game->free_params(doc->puzzles[i].par); 59 doc->puzzles[i].game->free_params(doc->puzzles[i].par);
60 doc->puzzles[i].game->free_ui(doc->puzzles[i].ui);
59 doc->puzzles[i].game->free_game(doc->puzzles[i].st); 61 doc->puzzles[i].game->free_game(doc->puzzles[i].st);
60 if (doc->puzzles[i].st2) 62 if (doc->puzzles[i].st2)
61 doc->puzzles[i].game->free_game(doc->puzzles[i].st2); 63 doc->puzzles[i].game->free_game(doc->puzzles[i].st2);
@@ -75,7 +77,7 @@ void document_free(document *doc)
75 * another sheet (typically the solution to the first game_state). 77 * another sheet (typically the solution to the first game_state).
76 */ 78 */
77void document_add_puzzle(document *doc, const game *game, game_params *par, 79void document_add_puzzle(document *doc, const game *game, game_params *par,
78 game_state *st, game_state *st2) 80 game_ui *ui, game_state *st, game_state *st2)
79{ 81{
80 if (doc->npuzzles >= doc->puzzlesize) { 82 if (doc->npuzzles >= doc->puzzlesize) {
81 doc->puzzlesize += 32; 83 doc->puzzlesize += 32;
@@ -83,6 +85,7 @@ void document_add_puzzle(document *doc, const game *game, game_params *par,
83 } 85 }
84 doc->puzzles[doc->npuzzles].game = game; 86 doc->puzzles[doc->npuzzles].game = game;
85 doc->puzzles[doc->npuzzles].par = par; 87 doc->puzzles[doc->npuzzles].par = par;
88 doc->puzzles[doc->npuzzles].ui = ui;
86 doc->puzzles[doc->npuzzles].st = st; 89 doc->puzzles[doc->npuzzles].st = st;
87 doc->puzzles[doc->npuzzles].st2 = st2; 90 doc->puzzles[doc->npuzzles].st2 = st2;
88 doc->npuzzles++; 91 doc->npuzzles++;
@@ -96,7 +99,11 @@ static void get_puzzle_size(const document *doc, struct puzzle *pz,
96 float ww, hh, ourscale; 99 float ww, hh, ourscale;
97 100
98 /* Get the preferred size of the game, in mm. */ 101 /* Get the preferred size of the game, in mm. */
99 pz->game->print_size(pz->par, &ww, &hh); 102 {
103 game_ui *ui = pz->game->new_ui(pz->st);
104 pz->game->print_size(pz->par, ui, &ww, &hh);
105 pz->game->free_ui(ui);
106 }
100 107
101 /* Adjust for user-supplied scale factor. */ 108 /* Adjust for user-supplied scale factor. */
102 ourscale = doc->userscale; 109 ourscale = doc->userscale;
@@ -270,9 +277,9 @@ void document_print_page(const document *doc, drawing *dr, int page_nr)
270 * permit each game to choose its own?) 277 * permit each game to choose its own?)
271 */ 278 */
272 tilesize = 512; 279 tilesize = 512;
273 pz->game->compute_size(pz->par, tilesize, &pixw, &pixh); 280 pz->game->compute_size(pz->par, tilesize, pz->ui, &pixw, &pixh);
274 print_begin_puzzle(dr, xm, xc, ym, yc, pixw, pixh, w, scale); 281 print_begin_puzzle(dr, xm, xc, ym, yc, pixw, pixh, w, scale);
275 pz->game->print(dr, pass == 0 ? pz->st : pz->st2, tilesize); 282 pz->game->print(dr, pass == 0 ? pz->st : pz->st2, pz->ui, tilesize);
276 print_end_puzzle(dr); 283 print_end_puzzle(dr);
277 } 284 }
278 285
diff --git a/apps/plugins/puzzles/src/ps.c b/apps/plugins/puzzles/src/ps.c
index ab8a1589f4..d0ea0ff2b5 100644
--- a/apps/plugins/puzzles/src/ps.c
+++ b/apps/plugins/puzzles/src/ps.c
@@ -157,7 +157,7 @@ static void ps_draw_line(void *handle, int x1, int y1, int x2, int y2,
157 ps_stroke(ps, colour); 157 ps_stroke(ps, colour);
158} 158}
159 159
160static void ps_draw_polygon(void *handle, int *coords, int npoints, 160static void ps_draw_polygon(void *handle, const int *coords, int npoints,
161 int fillcolour, int outlinecolour) 161 int fillcolour, int outlinecolour)
162{ 162{
163 psdata *ps = (psdata *)handle; 163 psdata *ps = (psdata *)handle;
diff --git a/apps/plugins/puzzles/src/puzzles.but b/apps/plugins/puzzles/src/puzzles.but
index ee519b8aa1..fb94155eed 100644
--- a/apps/plugins/puzzles/src/puzzles.but
+++ b/apps/plugins/puzzles/src/puzzles.but
@@ -36,7 +36,7 @@
36 36
37This is a collection of small one-player puzzle games. 37This is a collection of small one-player puzzle games.
38 38
39\copyright This manual is copyright 2004-2014 Simon Tatham. All rights 39\copyright This manual is copyright 2004-2024 Simon Tatham. All rights
40reserved. You may distribute this documentation under the MIT licence. 40reserved. You may distribute this documentation under the MIT licence.
41See \k{licence} for the licence text in full. 41See \k{licence} for the licence text in full.
42 42
@@ -130,12 +130,12 @@ current puzzle. (Only for puzzles which make sense to print, of
130course \dash it's hard to think of a sensible printable representation 130course \dash it's hard to think of a sensible printable representation
131of Fifteen!) 131of Fifteen!)
132 132
133\dt \ii\e{Undo} (\q{U}, Ctrl+\q{Z}, Ctrl+\q{_}) 133\dt \ii\e{Undo} (\q{U}, Ctrl+\q{Z}, Ctrl+\q{_}, \q{*})
134 134
135\dd Undoes a single move. (You can undo moves back to the start of the 135\dd Undoes a single move. (You can undo moves back to the start of the
136session.) 136session.)
137 137
138\dt \ii\e{Redo} (\q{R}, Ctrl+\q{R}) 138\dt \ii\e{Redo} (\q{R}, Ctrl+\q{R}, \q{#})
139 139
140\dd Redoes a previously undone move. 140\dd Redoes a previously undone move.
141 141
@@ -177,6 +177,22 @@ solving it yourself after seeing the answer, you can just press Undo.
177 177
178\dd Closes the application entirely. 178\dd Closes the application entirely.
179 179
180\dt \i\e{Preferences}
181
182\dd Where supported, brings up a dialog allowing you to configure
183personal preferences about a particular game. Some of these
184preferences will be specific to a particular game; others will be
185common to all games.
186
187\lcont{
188
189One option common to all games allows you to turn off the one-key
190shortcuts like \q{N} for new game or \q{Q} for quit, so that there's
191less chance of hitting them by accident. You can still access the same
192shortcuts with the Ctrl key.
193
194}
195
180\H{common-id} Specifying games with the \ii{game ID} 196\H{common-id} Specifying games with the \ii{game ID}
181 197
182There are two ways to save a game specification out of a puzzle and 198There are two ways to save a game specification out of a puzzle and
@@ -348,6 +364,11 @@ in which case its behaviour is slightly different; see below.
348 364
349} 365}
350 366
367\dt \cw{--delete-prefs}
368
369\dd This option causes the puzzle to delete the configuration file in
370which its user preferences were stored, if there is one.
371
351\dt \I{printing, on Unix}\cw{--print }\e{w}\cw{x}\e{h} 372\dt \I{printing, on Unix}\cw{--print }\e{w}\cw{x}\e{h}
352 373
353\dd If this option is specified, instead of a puzzle being displayed, 374\dd If this option is specified, instead of a puzzle being displayed,
@@ -535,6 +556,16 @@ feature and risk having ambiguous puzzles. (Also, finding \e{all}
535the possible solutions can be an additional challenge for an 556the possible solutions can be an additional challenge for an
536advanced player.) 557advanced player.)
537 558
559\H{net-prefs} \I{preferences, for Net}Net user preferences
560
561On platforms that support user preferences, the \q{Preferences} option
562on the \q{Game} menu will let you configure when loops are highlighted
563as errors. By default, they're always highlighted; by changing this
564option, you can ask for a loop to be highlighted only if every tile
565forming part of the loop is locked. This avoids the loop highlighting
566acting as a spoiler for available deductions about squares you haven't
567even looked at yet.
568
538 569
539\C{cube} \i{Cube} 570\C{cube} \i{Cube}
540 571
@@ -601,7 +632,8 @@ respectively.
601\cfg{winhelp-topic}{games.fifteen} 632\cfg{winhelp-topic}{games.fifteen}
602 633
603The old ones are the best: this is the good old \q{\i{15-puzzle}} 634The old ones are the best: this is the good old \q{\i{15-puzzle}}
604with sliding tiles. You have a 4\by\.4 square grid; 15 squares 635with sliding tiles, which dates from the 1870s.
636You have a 4\by\.4 square grid; 15 squares
605contain numbered tiles, and the sixteenth is empty. Your move is to 637contain numbered tiles, and the sixteenth is empty. Your move is to
606choose a tile next to the empty space, and slide it into the space. 638choose a tile next to the empty space, and slide it into the space.
607The aim is to end up with the tiles in numerical order, with the 639The aim is to end up with the tiles in numerical order, with the
@@ -620,8 +652,9 @@ A left-click with the mouse in the row or column containing the empty
620space will move as many tiles as necessary to move the space to the 652space will move as many tiles as necessary to move the space to the
621mouse pointer. 653mouse pointer.
622 654
623The arrow keys will move a tile adjacent to the space in the direction 655By default, the arrow keys will move a tile adjacent to the space in
624indicated (moving the space in the \e{opposite} direction). 656the direction indicated (moving the space in the \e{opposite}
657direction).
625 658
626Pressing \q{h} will make a suggested move. Pressing \q{h} enough 659Pressing \q{h} will make a suggested move. Pressing \q{h} enough
627times will solve the game, but it may scramble your progress while 660times will solve the game, but it may scramble your progress while
@@ -635,6 +668,18 @@ The only options available from the \q{Custom...} option on the \q{Type}
635menu are \e{Width} and \e{Height}, which are self-explanatory. (Once 668menu are \e{Width} and \e{Height}, which are self-explanatory. (Once
636you've changed these, it's not a \q{15-puzzle} any more, of course!) 669you've changed these, it's not a \q{15-puzzle} any more, of course!)
637 670
671\H{fifteen-prefs} \I{preferences, for Fifteen}Fifteen user preferences
672
673On platforms that support user preferences, the \q{Preferences} option
674on the \q{Game} menu will let you configure the sense of the arrow
675keys. With the default setting, \q{Move the tile}, the arrow key you
676press indicates the direction that you want a tile to move, so that
677(for example) if you want to move the tile left of the gap rightwards
678into the gap, you'd press Right. With the opposite setting, \q{Move
679the gap}, the behaviour of the arrow keys is reversed, and you would
680press Left to move the tile left of the gap into the gap, so that the
681\e{gap} ends up one square left of where it was.
682
638 683
639\C{sixteen} \i{Sixteen} 684\C{sixteen} \i{Sixteen}
640 685
@@ -785,8 +830,7 @@ quite as good as hand-crafted puzzles would be, but on the plus side
785you get an inexhaustible supply of puzzles tailored to your own 830you get an inexhaustible supply of puzzles tailored to your own
786specification. 831specification.
787 832
788\B{nikoli-rect} \W{http://www.nikoli.co.jp/en/puzzles/shikaku.html}\cw{http://www.nikoli.co.jp/en/puzzles/shikaku.html} 833\B{nikoli-rect} \W{https://www.nikoli.co.jp/en/puzzles/shikaku/}\cw{https://www.nikoli.co.jp/en/puzzles/shikaku/}
789(beware of Flash)
790 834
791\B{puzzle-palace-rect} \W{https://web.archive.org/web/20041024001459/http://www.puzzle.gr.jp/puzzle/sikaku/palm/index.html.en}\cw{https://web.archive.org/web/20041024001459/http://www.puzzle.gr.jp/puzzle/sikaku/palm/index.html.en} 835\B{puzzle-palace-rect} \W{https://web.archive.org/web/20041024001459/http://www.puzzle.gr.jp/puzzle/sikaku/palm/index.html.en}\cw{https://web.archive.org/web/20041024001459/http://www.puzzle.gr.jp/puzzle/sikaku/palm/index.html.en}
792 836
@@ -880,10 +924,10 @@ Netslide was contributed to this collection by Richard Boulton.
880\cfg{winhelp-topic}{games.pattern} 924\cfg{winhelp-topic}{games.pattern}
881 925
882You have a grid of squares, which must all be filled in either black 926You have a grid of squares, which must all be filled in either black
883or white. Beside each row of the grid are listed the lengths of the 927or white. Beside each row of the grid are listed, in order, the
884runs of black squares on that row; above each column are listed the 928lengths of the runs of black squares on that row; above each column
885lengths of the runs of black squares in that column. Your aim is to 929are listed, in order, the lengths of the runs of black squares in that
886fill in the entire grid black or white. 930column. Your aim is to fill in the entire grid black or white.
887 931
888I first saw this puzzle form around 1995, under the name 932I first saw this puzzle form around 1995, under the name
889\q{\i{nonograms}}. I've seen it in various places since then, under 933\q{\i{nonograms}}. I've seen it in various places since then, under
@@ -977,8 +1021,7 @@ of the modern form of the puzzle, and it was first published in
977of the history of the puzzle can be found on Wikipedia 1021of the history of the puzzle can be found on Wikipedia
978\k{wikipedia-solo}. 1022\k{wikipedia-solo}.
979 1023
980\B{nikoli-solo} \W{http://www.nikoli.co.jp/en/puzzles/sudoku.html}\cw{http://www.nikoli.co.jp/en/puzzles/sudoku.html} 1024\B{nikoli-solo} \W{https://www.nikoli.co.jp/en/puzzles/sudoku/}\cw{https://www.nikoli.co.jp/en/puzzles/sudoku/}
981(beware of Flash)
982 1025
983\B{wikipedia-solo} \W{http://en.wikipedia.org/wiki/Sudoku}\cw{http://en.wikipedia.org/wiki/Sudoku} 1026\B{wikipedia-solo} \W{http://en.wikipedia.org/wiki/Sudoku}\cw{http://en.wikipedia.org/wiki/Sudoku}
984 1027
@@ -1337,10 +1380,15 @@ after marking.
1337 1380
1338Alternatively, with the keyboard, the up and down cursor keys can be 1381Alternatively, with the keyboard, the up and down cursor keys can be
1339used to select a peg colour, the left and right keys to select a 1382used to select a peg colour, the left and right keys to select a
1340peg position, and the space bar or Enter key to place a peg of the 1383peg position, and the Enter key to place a peg of the
1341selected colour in the chosen position. \q{D} or Backspace removes a 1384selected colour in the chosen position. \q{D} or Backspace removes a
1342peg, and Space adds a hold marker. 1385peg, and Space adds a hold marker.
1343 1386
1387The number keys can also be used to insert pegs: \q{1} inserts the
1388top-most colour, \q{2} the second one, and so forth. These also
1389move the peg cursor to the right. Pressing \q{L} will label the
1390pegs with their numbers.
1391
1344Pressing \q{h} or \q{?} will fill the current guess with a suggested 1392Pressing \q{h} or \q{?} will fill the current guess with a suggested
1345guess. Using this is not recommended for 10 or more pegs as it is 1393guess. Using this is not recommended for 10 or more pegs as it is
1346slow. 1394slow.
@@ -1395,6 +1443,13 @@ that, use one extra colour.
1395this increases the search space (making things harder), and is turned on by 1443this increases the search space (making things harder), and is turned on by
1396default. 1444default.
1397 1445
1446\H{guess-prefs} \I{preferences, for Guess}Guess user preferences
1447
1448On platforms that support user preferences, the \q{Preferences} option
1449on the \q{Game} menu will let you configure whether pegs are labelled
1450with their numbers. Unlike the \q{L} key, this will persist between
1451games.
1452
1398 1453
1399\C{pegs} \i{Pegs} 1454\C{pegs} \i{Pegs}
1400 1455
@@ -1442,8 +1497,9 @@ These parameters are available from the \q{Custom...} option on the
1442 1497
1443\dd Controls whether you are given a board of a standard shape or a 1498\dd Controls whether you are given a board of a standard shape or a
1444randomly generated shape. The two standard shapes currently 1499randomly generated shape. The two standard shapes currently
1445supported are \q{Cross} and \q{Octagon} (also commonly known as the 1500supported are \q{Cross} (in various sizes) and \q{Octagon}.
1446English and European traditional board layouts respectively). 1501The 7\by\.7 Cross is the traditional English board layout.
1502The Octagon is the traditional French one.
1447Selecting \q{Random} will give you a different board shape every 1503Selecting \q{Random} will give you a different board shape every
1448time (but always one that is known to have a solution). 1504time (but always one that is known to have a solution).
1449 1505
@@ -1530,6 +1586,11 @@ I originally saw this in the form of a Flash game called \i{Planarity}
1530To move a point, click on it with the left mouse button and drag it 1586To move a point, click on it with the left mouse button and drag it
1531into a new position. 1587into a new position.
1532 1588
1589The cursor keys may also be used to navigate amongst the
1590points. Pressing the Enter key will toggle dragging the
1591currently-highlighted point. Pressing Tab or Space will cycle through
1592all the points.
1593
1533(All the actions described in \k{common-actions} are also available.) 1594(All the actions described in \k{common-actions} are also available.)
1534 1595
1535\H{untangle-parameters} \I{parameters, for Untangle}Untangle parameters 1596\H{untangle-parameters} \I{parameters, for Untangle}Untangle parameters
@@ -1714,7 +1775,7 @@ grid because that would immediately cause a loop.)
1714Credit for this puzzle goes to \i{Nikoli} \k{nikoli-slant}. 1775Credit for this puzzle goes to \i{Nikoli} \k{nikoli-slant}.
1715 1776
1716\B{nikoli-slant} 1777\B{nikoli-slant}
1717\W{http://www.nikoli.co.jp/ja/puzzles/gokigen_naname}\cw{http://www.nikoli.co.jp/ja/puzzles/gokigen_naname} 1778\W{https://www.nikoli.co.jp/ja/puzzles/gokigen_naname/}\cw{https://www.nikoli.co.jp/ja/puzzles/gokigen_naname/}
1718(in Japanese) 1779(in Japanese)
1719 1780
1720\H{slant-controls} \i{Slant controls} 1781\H{slant-controls} \i{Slant controls}
@@ -1763,6 +1824,12 @@ don't yet know what that direction is, and this might enable you to
1763deduce something about still other squares.) Even at Hard level, 1824deduce something about still other squares.) Even at Hard level,
1764guesswork and backtracking should never be necessary. 1825guesswork and backtracking should never be necessary.
1765 1826
1827\H{slant-prefs} \I{preferences, for Slant}Slant user preferences
1828
1829On platforms that support user preferences, the \q{Preferences} option
1830on the \q{Game} menu will let you configure which way round the mouse
1831buttons work.
1832
1766 1833
1767\C{lightup} \i{Light Up} 1834\C{lightup} \i{Light Up}
1768 1835
@@ -1792,8 +1859,7 @@ Credit for this puzzle goes to \i{Nikoli} \k{nikoli-lightup}.
1792Light Up was contributed to this collection by James Harvey. 1859Light Up was contributed to this collection by James Harvey.
1793 1860
1794\B{nikoli-lightup} 1861\B{nikoli-lightup}
1795\W{http://www.nikoli.co.jp/en/puzzles/akari.html}\cw{http://www.nikoli.co.jp/en/puzzles/akari.html} 1862\W{https://www.nikoli.co.jp/en/puzzles/akari/}\cw{https://www.nikoli.co.jp/en/puzzles/akari/}
1796(beware of Flash)
1797 1863
1798\H{lightup-controls} \i{Light Up controls} 1864\H{lightup-controls} \i{Light Up controls}
1799 1865
@@ -1847,6 +1913,12 @@ noticeably.)
1847backtracking or guessing, \q{Hard} means that some guesses will 1913backtracking or guessing, \q{Hard} means that some guesses will
1848probably be necessary. 1914probably be necessary.
1849 1915
1916\H{lightup-prefs} \I{preferences, for Light Up}Light Up user preferences
1917
1918On platforms that support user preferences, the \q{Preferences} option
1919on the \q{Game} menu will let you configure whether \q{this is not a
1920light} marks are shown when the square is also lit.
1921
1850 1922
1851\C{map} \i{Map} 1923\C{map} \i{Map}
1852 1924
@@ -1856,7 +1928,7 @@ You are given a map consisting of a number of regions. Your task is
1856to colour each region with one of four colours, in such a way that 1928to colour each region with one of four colours, in such a way that
1857no two regions sharing a boundary have the same colour. You are 1929no two regions sharing a boundary have the same colour. You are
1858provided with some regions already coloured, sufficient to make the 1930provided with some regions already coloured, sufficient to make the
1859remainder of the solution unique. 1931remainder of the solution unique, and these cannot be changed.
1860 1932
1861Only regions which share a length of border are required to be 1933Only regions which share a length of border are required to be
1862different colours. Two regions which meet at only one \e{point} 1934different colours. Two regions which meet at only one \e{point}
@@ -1864,9 +1936,9 @@ different colours. Two regions which meet at only one \e{point}
1864 1936
1865I believe this puzzle is original; I've never seen an implementation 1937I believe this puzzle is original; I've never seen an implementation
1866of it anywhere else. The concept of a \i{four-colouring} puzzle was 1938of it anywhere else. The concept of a \i{four-colouring} puzzle was
1867suggested by Owen Dunn; credit must also go to Nikoli and to Verity 1939suggested by Alexandra Lanes; credit must also go to Nikoli and to Verity
1868Allan for inspiring the train of thought that led to me realising 1940Allan for inspiring the train of thought that led to me realising
1869Owen's suggestion was a viable puzzle. Thanks also to Gareth Taylor 1941Alex's suggestion was a viable puzzle. Thanks also to Gareth Taylor
1870for many detailed suggestions. 1942for many detailed suggestions.
1871 1943
1872\H{map-controls} \i{Map controls} 1944\H{map-controls} \i{Map controls}
@@ -1940,6 +2012,12 @@ Unreasonable puzzles may require guessing and backtracking.
1940 2012
1941} 2013}
1942 2014
2015\H{map-prefs} \I{preferences, for Map}Map user preferences
2016
2017On platforms that support user preferences, the \q{Preferences} option
2018on the \q{Game} menu will let you configure the style of the victory
2019flash and also whether the regions start out labelled with numbers.
2020
1943 2021
1944\C{loopy} \i{Loopy} 2022\C{loopy} \i{Loopy}
1945 2023
@@ -1967,8 +2045,7 @@ and subsequently enhanced to handle various types of non-square grid
1967by Lambros Lambrou. 2045by Lambros Lambrou.
1968 2046
1969\B{nikoli-loopy} 2047\B{nikoli-loopy}
1970\W{http://www.nikoli.co.jp/en/puzzles/slitherlink.html}\cw{http://www.nikoli.co.jp/en/puzzles/slitherlink.html} 2048\W{https://www.nikoli.co.jp/en/puzzles/slitherlink/}\cw{https://www.nikoli.co.jp/en/puzzles/slitherlink/}
1971(beware of Flash)
1972 2049
1973\H{loopy-controls} \i{Loopy controls} 2050\H{loopy-controls} \i{Loopy controls}
1974 2051
@@ -2013,6 +2090,34 @@ same; this makes them the least confusing to play.
2013\#{FIXME: what distinguishes Easy, Medium, and Hard? In particular, 2090\#{FIXME: what distinguishes Easy, Medium, and Hard? In particular,
2014when are backtracking/guesswork required, if ever?} 2091when are backtracking/guesswork required, if ever?}
2015 2092
2093\H{loopy-prefs} \I{preferences, for Loopy}Loopy user preferences
2094
2095On platforms that support user preferences, the \q{Preferences} option
2096on the \q{Game} menu will let you configure the following things:
2097
2098\q{Draw excluded grid lines faintly}. This is on by default: when a
2099line of the grid has been explicitly excluded from the solution by
2100right-clicking it, the line is still drawn, just in a faint grey
2101colour. If you turn this option off, excluded lines are not drawn at
2102all.
2103
2104\q{Auto-follow unique paths of edges}. This is off by default. When
2105it's on, clicking to change the status of a single grid line will
2106potentially propagate the change along multiple lines, if one or both
2107ends of the line you clicked connect to only one other line. (The idea
2108is that if two lines meet at a vertex and no other lines do at all,
2109then those lines are either both part of the loop or neither, so
2110there's no reason you should have to click separately to toggle each
2111one.)
2112
2113In the mode \q{Based on grid only}, the effects of a click will only
2114propagate across vertices that have degree 2 in the underlying grid.
2115For example, in the square grid, the effect will \e{only} occur at the
2116four grid corners.
2117
2118In the mode \q{Based on grid and game state}, the propagation will
2119also take account of edges you've already excluded from the solution,
2120so that it will do even more work for you.
2016 2121
2017\C{inertia} \i{Inertia} 2122\C{inertia} \i{Inertia}
2018 2123
@@ -2171,8 +2276,7 @@ Credit for this puzzle goes to \i{Nikoli} \k{nikoli-bridges}.
2171Bridges was contributed to this collection by James Harvey. 2276Bridges was contributed to this collection by James Harvey.
2172 2277
2173\B{nikoli-bridges} 2278\B{nikoli-bridges}
2174\W{http://www.nikoli.co.jp/en/puzzles/hashiwokakero.html}\cw{http://www.nikoli.co.jp/en/puzzles/hashiwokakero.html} 2279\W{https://www.nikoli.co.jp/en/puzzles/Hashiwokakero/}\cw{https://www.nikoli.co.jp/en/puzzles/Hashiwokakero/}
2175(beware of Flash)
2176 2280
2177\H{bridges-controls} \i{Bridges controls} 2281\H{bridges-controls} \i{Bridges controls}
2178 2282
@@ -2217,6 +2321,9 @@ By pressing a number key, you can jump to the nearest island with that
2217number. Letters \q{a}, ..., \q{f} count as 10, ..., 15 and \q{0} as 2321number. Letters \q{a}, ..., \q{f} count as 10, ..., 15 and \q{0} as
221816. 232216.
2219 2323
2324The \q{G} key will draw a grey line between each pair of islands that
2325could be connected with a bridge or non-bridge but are currently not.
2326
2220Violations of the puzzle rules will be marked in red: 2327Violations of the puzzle rules will be marked in red:
2221 2328
2222\b An island with too many bridges will be highlighted in red. 2329\b An island with too many bridges will be highlighted in red.
@@ -2288,6 +2395,13 @@ tightly-packed islands.
2288 2395
2289} 2396}
2290 2397
2398\H{bridges-prefs} \I{preferences, for Bridges}Bridges user preferences
2399
2400On platforms that support user preferences, the \q{Preferences} option
2401on the \q{Game} menu will let you configure whether possible bridge
2402locations are shown. Unlike the \q{G} key, this will persist between
2403games.
2404
2291 2405
2292\C{unequal} \i{Unequal} 2406\C{unequal} \i{Unequal}
2293 2407
@@ -2416,7 +2530,7 @@ English as \q{Spiral Galaxies}.
2416 2530
2417Galaxies was contributed to this collection by James Harvey. 2531Galaxies was contributed to this collection by James Harvey.
2418 2532
2419\B{nikoli-galaxies} \W{http://www.nikoli.co.jp/en/puzzles/astronomical_show.html}\cw{http://www.nikoli.co.jp/en/puzzles/astronomical_show.html} 2533\B{nikoli-galaxies} \W{https://www.nikoli.co.jp/en/puzzles/tentai_show/}\cw{https://www.nikoli.co.jp/en/puzzles/tentai_show/}
2420 2534
2421\H{galaxies-controls} \i{Galaxies controls} 2535\H{galaxies-controls} \i{Galaxies controls}
2422 2536
@@ -2489,7 +2603,7 @@ Credit for this puzzle goes to \i{Nikoli} \k{nikoli-fillomino}.
2489Filling was contributed to this collection by Jonas K\u00F6{oe}lker. 2603Filling was contributed to this collection by Jonas K\u00F6{oe}lker.
2490 2604
2491\B{nikoli-fillomino} 2605\B{nikoli-fillomino}
2492\W{http://www.nikoli.co.jp/en/puzzles/fillomino.html}\cw{http://www.nikoli.co.jp/en/puzzles/fillomino.html} 2606\W{https://www.nikoli.co.jp/en/puzzles/fillomino/}\cw{https://www.nikoli.co.jp/en/puzzles/fillomino/}
2493 2607
2494\H{filling-controls} \I{controls, for Filling}Filling controls 2608\H{filling-controls} \I{controls, for Filling}Filling controls
2495 2609
@@ -2718,6 +2832,14 @@ level, some backtracking will be required, but the solution should
2718still be unique. The remaining levels require increasingly complex 2832still be unique. The remaining levels require increasingly complex
2719reasoning to avoid having to backtrack. 2833reasoning to avoid having to backtrack.
2720 2834
2835\H{towers-prefs} \I{preferences, for Towers}Towers user preferences
2836
2837On platforms that support user preferences, the \q{Preferences} option
2838on the \q{Game} menu will let you configure the style of the game
2839display. If you don't like the three-dimensional mode, selecting
2840\q{2D} will switch to a simpler display style in which towers are
2841shown by just writing their height in the square.
2842
2721 2843
2722\C{singles} \i{Singles} 2844\C{singles} \i{Singles}
2723 2845
@@ -2741,8 +2863,7 @@ Credit for this puzzle goes to \i{Nikoli} \k{nikoli-hitori} who call it
2741Singles was contributed to this collection by James Harvey. 2863Singles was contributed to this collection by James Harvey.
2742 2864
2743\B{nikoli-hitori} 2865\B{nikoli-hitori}
2744\W{http://www.nikoli.com/en/puzzles/hitori.html}\cw{http://www.nikoli.com/en/puzzles/hitori.html} 2866\W{https://www.nikoli.co.jp/en/puzzles/hitori/}\cw{https://www.nikoli.co.jp/en/puzzles/hitori/}
2745(beware of Flash)
2746 2867
2747\H{singles-controls} \i{Singles controls} 2868\H{singles-controls} \i{Singles controls}
2748 2869
@@ -2750,7 +2871,9 @@ Singles was contributed to this collection by James Harvey.
2750 2871
2751Left-clicking on an empty square will colour it black; left-clicking again 2872Left-clicking on an empty square will colour it black; left-clicking again
2752will restore the number. Right-clicking will add a circle (useful for 2873will restore the number. Right-clicking will add a circle (useful for
2753indicating that a cell is definitely not black). 2874indicating that a cell is definitely not black). Clicking outside the
2875grid will toggle whether black squares completely hide the numbers on
2876them, or display them in dark grey.
2754 2877
2755You can also use the cursor keys to move around the grid. Pressing the 2878You can also use the cursor keys to move around the grid. Pressing the
2756return or space keys will turn a square black or add a circle respectively, 2879return or space keys will turn a square black or add a circle respectively,
@@ -2771,6 +2894,12 @@ These parameters are available from the \q{Custom...} option on the
2771 2894
2772\dd Controls the difficulty of the generated puzzle. 2895\dd Controls the difficulty of the generated puzzle.
2773 2896
2897\H{Singles-prefs} \I{preferences, for Singles}Singles user preferences
2898
2899On platforms that support user preferences, the \q{Preferences} option
2900on the \q{Game} menu will let you configure whether numbers on black
2901squares are visible. Unlike clicking outside the grid, this will
2902persist between games.
2774 2903
2775\C{magnets} \i{Magnets} 2904\C{magnets} \i{Magnets}
2776 2905
@@ -2925,6 +3054,13 @@ These parameters are available from the \q{Custom...} option on the
2925(the start at the top left, and the end at the bottom right). If false the start 3054(the start at the top left, and the end at the bottom right). If false the start
2926and end squares are placed randomly (although always both shown). 3055and end squares are placed randomly (although always both shown).
2927 3056
3057\H{signpost-prefs} \I{preferences, for Signpost}Signpost user preferences
3058
3059On platforms that support user preferences, the \q{Preferences} option
3060on the \q{Game} menu will let you configure the style of the victory
3061effect.
3062
3063
2928\C{range} \i{Range} 3064\C{range} \i{Range}
2929 3065
2930\cfg{winhelp-topic}{games.range} 3066\cfg{winhelp-topic}{games.range}
@@ -2959,7 +3095,7 @@ it \q{Kurodoko}, \q{Kuromasu} or \q{Where is Black Cells}.
2959Range was contributed to this collection by Jonas K\u00F6{oe}lker. 3095Range was contributed to this collection by Jonas K\u00F6{oe}lker.
2960 3096
2961\B{nikoli-range} 3097\B{nikoli-range}
2962\W{http://www.nikoli.co.jp/en/puzzles/where_is_black_cells.html}\cw{http://www.nikoli.co.jp/en/puzzles/where_is_black_cells.html} 3098\W{https://www.nikoli.co.jp/en/puzzles/kurodoko/}\cw{https://www.nikoli.co.jp/en/puzzles/kurodoko/}
2963 3099
2964\H{range-controls} \I{controls, for Range}Range controls 3100\H{range-controls} \I{controls, for Range}Range controls
2965 3101
@@ -2987,6 +3123,13 @@ These parameters are available from the \q{Custom...} option on the
2987 3123
2988\dd Size of grid in squares. 3124\dd Size of grid in squares.
2989 3125
3126\H{range-prefs} \I{preferences, for Range}Range user preferences
3127
3128On platforms that support user preferences, the \q{Preferences} option
3129on the \q{Game} menu will let you configure which way round the mouse
3130buttons work.
3131
3132
2990\C{pearl} \i{Pearl} 3133\C{pearl} \i{Pearl}
2991 3134
2992\cfg{winhelp-topic}{games.pearl} 3135\cfg{winhelp-topic}{games.pearl}
@@ -3019,8 +3162,7 @@ Credit for this puzzle goes to \i{Nikoli}, who call it \q{Masyu}.
3019Thanks to James Harvey for assistance with the implementation. 3162Thanks to James Harvey for assistance with the implementation.
3020 3163
3021\B{nikoli-pearl} 3164\B{nikoli-pearl}
3022\W{http://www.nikoli.co.jp/en/puzzles/masyu.html}\cw{http://www.nikoli.co.jp/en/puzzles/masyu.html} 3165\W{https://www.nikoli.co.jp/en/puzzles/masyu/}\cw{https://www.nikoli.co.jp/en/puzzles/masyu/}
3023(beware of Flash)
3024 3166
3025\H{pearl-controls} \I{controls, for Pearl}Pearl controls 3167\H{pearl-controls} \I{controls, for Pearl}Pearl controls
3026 3168
@@ -3054,6 +3196,41 @@ right click, respectively, on the edge in the direction of the key.
3054These parameters are available from the \q{Custom...} option on the 3196These parameters are available from the \q{Custom...} option on the
3055\q{Type} menu. 3197\q{Type} menu.
3056 3198
3199\dt \e{Width}, \e{Height}
3200
3201\dd Size of grid in squares.
3202
3203\dt \e{Difficulty}
3204
3205\dd Controls the difficulty of the generated puzzle.
3206
3207\dt \e{Allow unsoluble}
3208
3209\dd If this is set, then the game will be generated in the simplest
3210way: every clue square that can possibly be provided will be shown,
3211and the generator will not check whether the puzzle can be uniquely
3212solved.
3213
3214\lcont{
3215
3216This speeds up game generation, and allows much larger grids to be
3217played. At least one possible solution will still always exist, but
3218there's no guarantee that it will be unique, or that it will be
3219possible to deduce it step by step.
3220
3221}
3222
3223\H{pearl-prefs} \I{preferences, for Pearl}Pearl user preferences
3224
3225On platforms that support user preferences, the \q{Preferences} option
3226on the \q{Game} menu will let you configure the style of the game
3227display. \q{Traditional} is the default mode, in which the loop runs
3228between centres of grid squares, and each clue occupies a square.
3229\q{Loopy-style} is an alternative mode that looks more like Loopy
3230(\k{loopy}), in which the loop runs between grid \e{vertices}, and the
3231clues also occupy vertices.
3232
3233
3057\C{undead} \i{Undead} 3234\C{undead} \i{Undead}
3058 3235
3059\cfg{winhelp-topic}{games.undead} 3236\cfg{winhelp-topic}{games.undead}
@@ -3088,12 +3265,13 @@ Undead was contributed to this collection by Steffen Bauer.
3088Undead has a similar control system to Solo, Unequal and Keen. 3265Undead has a similar control system to Solo, Unequal and Keen.
3089 3266
3090To play Undead, click the mouse in any empty square and then type a 3267To play Undead, click the mouse in any empty square and then type a
3091letter on the keyboard indicating the type of monster: \q{G} for a 3268letter or number on the keyboard indicating the type of monster:
3092ghost, \q{V} for a vampire, or \q{Z} for a zombie. If you make a 3269\q{G} or \q{1} for a ghost, \q{V} or \q{2} for a vampire,
3270or \q{Z} or \q{3} for a zombie. If you make a
3093mistake, click the mouse in the incorrect square and press Space to 3271mistake, click the mouse in the incorrect square and press Space to
3094clear it again (or use the Undo feature). 3272clear it again (or use the Undo feature).
3095 3273
3096If you \e{right}-click in a square and then type a letter, the 3274If you \e{right}-click in a square and then type a letter or number, the
3097corresponding monster will be shown in reduced size in that square, as 3275corresponding monster will be shown in reduced size in that square, as
3098a \q{pencil mark}. You can have pencil marks for multiple monsters in 3276a \q{pencil mark}. You can have pencil marks for multiple monsters in
3099the same square. A square containing a full-size monster cannot also 3277the same square. A square containing a full-size monster cannot also
@@ -3106,7 +3284,7 @@ monster, or you can use them as lists of the possible monster in a
3106given square, or anything else you feel like. 3284given square, or anything else you feel like.
3107 3285
3108To erase a single pencil mark, right-click in the square and type 3286To erase a single pencil mark, right-click in the square and type
3109the same letter again. 3287the same letter or number again.
3110 3288
3111All pencil marks in a square are erased when you left-click and type a 3289All pencil marks in a square are erased when you left-click and type a
3112monster letter, or when you left-click and press Space. Right-clicking 3290monster letter, or when you left-click and press Space. Right-clicking
@@ -3114,7 +3292,7 @@ and pressing space will also erase pencil marks.
3114 3292
3115As for Solo, the cursor keys can be used in conjunction with the letter 3293As for Solo, the cursor keys can be used in conjunction with the letter
3116keys to place monsters or pencil marks. Use the cursor keys to move a 3294keys to place monsters or pencil marks. Use the cursor keys to move a
3117highlight around the grid, and type a monster letter to enter it in 3295highlight around the grid, and type a monster letter or number to enter it in
3118the highlighted square. Pressing return toggles the highlight into a 3296the highlighted square. Pressing return toggles the highlight into a
3119mode in which you can enter or remove pencil marks. 3297mode in which you can enter or remove pencil marks.
3120 3298
@@ -3140,6 +3318,13 @@ These parameters are available from the \q{Custom...} option on the
3140 3318
3141\dd Controls the difficulty of the generated puzzle. 3319\dd Controls the difficulty of the generated puzzle.
3142 3320
3321\H{undead-prefs} \I{preferences, for Undead}Undead user preferences
3322
3323On platforms that support user preferences, the \q{Preferences} option
3324on the \q{Game} menu will let you configure whether Undead uses letters
3325or pictures to represent monsters.
3326
3327
3143\C{unruly} \i{Unruly} 3328\C{unruly} \i{Unruly}
3144 3329
3145\cfg{winhelp-topic}{games.unruly} 3330\cfg{winhelp-topic}{games.unruly}
@@ -3257,7 +3442,7 @@ real challenge, set this value to 0 and then try to solve a grid in
3257 3442
3258} 3443}
3259 3444
3260\C{tracks} \i{Tracks} 3445\C{tracks} \i{Train Tracks}
3261 3446
3262\cfg{winhelp-topic}{games.tracks} 3447\cfg{winhelp-topic}{games.tracks}
3263 3448
@@ -3269,9 +3454,9 @@ clues to the top and right of the grid.
3269There are only straight and 90 degree curved rails, and the track may not 3454There are only straight and 90 degree curved rails, and the track may not
3270cross itself. 3455cross itself.
3271 3456
3272Tracks was contributed to this collection by James Harvey. 3457Train Tracks was contributed to this collection by James Harvey.
3273 3458
3274\H{tracks-controls} \I{controls, for Tracks}Tracks controls 3459\H{tracks-controls} \I{controls, for Tracks}Train Tracks controls
3275 3460
3276Left-clicking on an edge between two squares adds a track segment between 3461Left-clicking on an edge between two squares adds a track segment between
3277the two squares. Right-clicking on an edge adds a cross on the edge, 3462the two squares. Right-clicking on an edge adds a cross on the edge,
@@ -3288,7 +3473,7 @@ columns to match the clue.
3288 3473
3289(All the actions described in \k{common-actions} are also available.) 3474(All the actions described in \k{common-actions} are also available.)
3290 3475
3291\H{tracks-parameters} \I{parameters, for Tracks}Tracks parameters 3476\H{tracks-parameters} \I{parameters, for Tracks}Train Tracks parameters
3292 3477
3293These parameters are available from the \q{Custom...} option on the 3478These parameters are available from the \q{Custom...} option on the
3294\q{Type} menu. 3479\q{Type} menu.
@@ -3305,12 +3490,12 @@ that would lead to impossible crossings later.
3305 3490
3306\dt \e{Disallow consecutive 1 clues} 3491\dt \e{Disallow consecutive 1 clues}
3307 3492
3308\dd Controls whether the Tracks game generation permits two adjacent 3493\dd Controls whether the Train Tracks game generation permits two
3309rows or columns to have a 1 clue, or permits the row or column of the 3494adjacent rows or columns to have a 1 clue, or permits the row or
3310track's endpoint to have a 1 clue. By default this is not permitted, 3495column of the track's endpoint to have a 1 clue. By default this is
3311to avoid long straight boring segments of track and make the games 3496not permitted, to avoid long straight boring segments of track and
3312more twiddly and interesting. If you want to restore the possibility, 3497make the games more twiddly and interesting. If you want to restore
3313turn this option off. 3498the possibility, turn this option off.
3314 3499
3315 3500
3316\C{palisade} \i{Palisade} 3501\C{palisade} \i{Palisade}
@@ -3329,7 +3514,7 @@ Credit for this puzzle goes to \i{Nikoli}, who call it \q{Five Cells}.
3329Palisade was contributed to this collection by Jonas K\u00F6{oe}lker. 3514Palisade was contributed to this collection by Jonas K\u00F6{oe}lker.
3330 3515
3331\B{nikoli-palisade} 3516\B{nikoli-palisade}
3332\W{http://nikoli.co.jp/en/puzzles/five_cells.html}\cw{http://nikoli.co.jp/en/puzzles/five_cells.html} 3517\W{https://www.nikoli.co.jp/en/puzzles/five_cells/}\cw{https://www.nikoli.co.jp/en/puzzles/five_cells/}
3333 3518
3334\H{palisade-controls} \I{controls, for Palisade}Palisade controls 3519\H{palisade-controls} \I{controls, for Palisade}Palisade controls
3335 3520
@@ -3354,14 +3539,64 @@ These parameters are available from the \q{Custom...} option on the
3354 3539
3355\dd The size of the regions into which the grid must be subdivided. 3540\dd The size of the regions into which the grid must be subdivided.
3356 3541
3542\C{mosaic} \i{Mosaic}
3543
3544\cfg{winhelp-topic}{games.mosaic}
3545
3546You are given a grid of squares, which you must colour either black or
3547white.
3548
3549Some squares contain clue numbers. Each clue tells you the number of
3550black squares in the 3\times\.3 region surrounding the clue \dash
3551\e{including} the clue square itself.
3552
3553This game is variously known in other locations as: ArtMosaico, Count
3554and Darken, Cuenta Y Sombrea, Fill-a-Pix, Fill-In, Komsu Karala,
3555Magipic, Majipiku, Mosaico, Mosaik, Mozaiek, Nampre Puzzle,
3556Nurie-Puzzle, Oekaki-Pix, Voisimage.
3557
3558Mosaic was contributed to this collection by Didi Kohen. Colour design
3559by Michal Shomer. The implementation is loosely based on
3560\W{https://github.com/mordechaim/Mosaic}\cw{github.com/mordechaim/Mosaic}.
3561
3562\H{mosaic-controls} \I{controls, for Mosaic}Mosaic controls
3563
3564To play Mosaic, click the mouse in a square to change its colour.
3565Left-clicking an empty square will turn it black, and right-clicking
3566will turn it white. Keep clicking the same button to cycle through the
3567three possible states for the square.
3568
3569If you hold down the mouse button and drag, you can colour multiple
3570cells in a single action.
3571
3572You can also use the cursor keys to move around the grid. Pressing the
3573return or space keys will turn an empty square black or white
3574respectively (and then cycle the colours in the same way as the mouse
3575buttons), and pressing Backspace will reset a square to empty.
3576
3577\H{Mosaic-parameters} \I{parameters, for Mosaic}Mosaic parameters
3578
3579These parameters are available from the \q{Custom...} option on the
3580\q{Type} menu.
3581
3582\dt \e{Width}, \e{Height}
3583
3584\dd Size of grid in squares.
3585
3586\dt \e{Aggressive generation}
3587
3588\dd With this option set, the game generator will try harder to
3589eliminate unnecessary clues on the board. This slows down generation,
3590so it's not recommended for boards larger than, say, 30\times\.30.
3591
3357\A{licence} \I{MIT licence}\ii{Licence} 3592\A{licence} \I{MIT licence}\ii{Licence}
3358 3593
3359This software is \i{copyright} 2004-2014 Simon Tatham. 3594This software is \i{copyright} 2004-2024 Simon Tatham.
3360 3595
3361Portions copyright Richard Boulton, James Harvey, Mike Pinna, Jonas 3596Portions copyright Richard Boulton, James Harvey, Mike Pinna, Jonas
3362K\u00F6{oe}lker, Dariusz Olszewski, Michael Schierl, Lambros Lambrou, 3597K\u00F6{oe}lker, Dariusz Olszewski, Michael Schierl, Lambros Lambrou,
3363Bernd Schmidt, Steffen Bauer, Lennard Sprong, Rogier Goossens, Michael 3598Bernd Schmidt, Steffen Bauer, Lennard Sprong, Rogier Goossens, Michael
3364Quevillon and Asher Gordon. 3599Quevillon, Asher Gordon, Didi Kohen, and Ben Harris.
3365 3600
3366Permission is hereby granted, free of charge, to any person 3601Permission is hereby granted, free of charge, to any person
3367obtaining a copy of this software and associated documentation files 3602obtaining a copy of this software and associated documentation files
diff --git a/apps/plugins/puzzles/src/puzzles.h b/apps/plugins/puzzles/src/puzzles.h
index 29b00ddaf0..2c52bc6cde 100644
--- a/apps/plugins/puzzles/src/puzzles.h
+++ b/apps/plugins/puzzles/src/puzzles.h
@@ -18,6 +18,9 @@
18#define STR_INT(x) #x 18#define STR_INT(x) #x
19#define STR(x) STR_INT(x) 19#define STR(x) STR_INT(x)
20 20
21/* An upper bound on the length of sprintf'ed integers (signed or unsigned). */
22#define MAX_DIGITS(x) (sizeof(x) * CHAR_BIT / 3 + 2)
23
21/* NB not perfect because they evaluate arguments multiple times. */ 24/* NB not perfect because they evaluate arguments multiple times. */
22#ifndef max 25#ifndef max
23#define max(x,y) ( (x)>(y) ? (x) : (y) ) 26#define max(x,y) ( (x)>(y) ? (x) : (y) )
@@ -69,6 +72,7 @@ enum {
69 (m) == CURSOR_RIGHT || (m) == CURSOR_LEFT ) 72 (m) == CURSOR_RIGHT || (m) == CURSOR_LEFT )
70#define IS_CURSOR_SELECT(m) ( (m) == CURSOR_SELECT || (m) == CURSOR_SELECT2) 73#define IS_CURSOR_SELECT(m) ( (m) == CURSOR_SELECT || (m) == CURSOR_SELECT2)
71#define IS_UI_FAKE_KEY(m) ( (m) > UI_LOWER_BOUND && (m) < UI_UPPER_BOUND ) 74#define IS_UI_FAKE_KEY(m) ( (m) > UI_LOWER_BOUND && (m) < UI_UPPER_BOUND )
75#define STRIP_BUTTON_MODIFIERS(m) ( (unsigned)(m) & ~MOD_MASK )
72 76
73/* 77/*
74 * Flags in the back end's `flags' word. 78 * Flags in the back end's `flags' word.
@@ -83,14 +87,6 @@ enum {
83#define REQUIRE_NUMPAD ( 1 << 11 ) 87#define REQUIRE_NUMPAD ( 1 << 11 )
84/* end of `flags' word definitions */ 88/* end of `flags' word definitions */
85 89
86#ifdef _WIN32_WCE
87 /* Pocket PC devices have small, portrait screen that requires more vivid colours */
88 #define SMALL_SCREEN
89 #define PORTRAIT_SCREEN
90 #define VIVID_COLOURS
91 #define STYLUS_BASED
92#endif
93
94#define IGNOREARG(x) ( (x) = (x) ) 90#define IGNOREARG(x) ( (x) = (x) )
95 91
96typedef struct frontend frontend; 92typedef struct frontend frontend;
@@ -132,8 +128,13 @@ typedef struct psdata psdata;
132 */ 128 */
133enum { C_STRING, C_CHOICES, C_BOOLEAN, C_END }; 129enum { C_STRING, C_CHOICES, C_BOOLEAN, C_END };
134struct config_item { 130struct config_item {
135 /* Not dynamically allocated */ 131 /* Not dynamically allocated: the GUI display name for the option */
136 const char *name; 132 const char *name;
133 /* Not dynamically allocated: the keyword identifier for the
134 * option. Only examined in the case where this structure is being
135 * used for options that appear in config files, i.e. the
136 * get_prefs method fills this in but configure does not. */
137 const char *kw;
137 /* Value from the above C_* enum */ 138 /* Value from the above C_* enum */
138 int type; 139 int type;
139 union { 140 union {
@@ -151,6 +152,13 @@ struct config_item {
151 */ 152 */
152 const char *choicenames; 153 const char *choicenames;
153 /* 154 /*
155 * choicekws is non-NULL, not dynamically allocated, and
156 * contains a parallel list of keyword strings used to
157 * represent the enumeration in config files. As with 'kw'
158 * above, this is only expected to be set by get_prefs.
159 */
160 const char *choicekws;
161 /*
154 * Indicates the chosen index from the options in 162 * Indicates the chosen index from the options in
155 * choicenames. In the above example, 0==Foo, 1==Bar and 163 * choicenames. In the above example, 0==Foo, 1==Bar and
156 * 2==Baz. 164 * 2==Baz.
@@ -256,7 +264,7 @@ void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize,
256 int align, int colour, const char *text); 264 int align, int colour, const char *text);
257void draw_rect(drawing *dr, int x, int y, int w, int h, int colour); 265void draw_rect(drawing *dr, int x, int y, int w, int h, int colour);
258void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour); 266void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour);
259void draw_polygon(drawing *dr, int *coords, int npoints, 267void draw_polygon(drawing *dr, const int *coords, int npoints,
260 int fillcolour, int outlinecolour); 268 int fillcolour, int outlinecolour);
261void draw_circle(drawing *dr, int cx, int cy, int radius, 269void draw_circle(drawing *dr, int cx, int cy, int radius,
262 int fillcolour, int outlinecolour); 270 int fillcolour, int outlinecolour);
@@ -307,13 +315,16 @@ void midend_free(midend *me);
307const game *midend_which_game(midend *me); 315const game *midend_which_game(midend *me);
308void midend_set_params(midend *me, game_params *params); 316void midend_set_params(midend *me, game_params *params);
309game_params *midend_get_params(midend *me); 317game_params *midend_get_params(midend *me);
310void midend_size(midend *me, int *x, int *y, bool user_size); 318void midend_size(midend *me, int *x, int *y, bool user_size,
319 double device_pixel_ratio);
311void midend_reset_tilesize(midend *me); 320void midend_reset_tilesize(midend *me);
312void midend_new_game(midend *me); 321void midend_new_game(midend *me);
313void midend_restart_game(midend *me); 322void midend_restart_game(midend *me);
314void midend_stop_anim(midend *me); 323void midend_stop_anim(midend *me);
315bool midend_process_key(midend *me, int x, int y, int button); 324enum { PKR_QUIT = 0, PKR_SOME_EFFECT, PKR_NO_EFFECT, PKR_UNUSED };
325int midend_process_key(midend *me, int x, int y, int button);
316key_label *midend_request_keys(midend *me, int *nkeys); 326key_label *midend_request_keys(midend *me, int *nkeys);
327const char *midend_current_key_label(midend *me, int button);
317void midend_force_redraw(midend *me); 328void midend_force_redraw(midend *me);
318void midend_redraw(midend *me); 329void midend_redraw(midend *me);
319float *midend_colours(midend *me, int *ncolours); 330float *midend_colours(midend *me, int *ncolours);
@@ -322,7 +333,7 @@ void midend_timer(midend *me, float tplus);
322struct preset_menu *midend_get_presets(midend *me, int *id_limit); 333struct preset_menu *midend_get_presets(midend *me, int *id_limit);
323int midend_which_preset(midend *me); 334int midend_which_preset(midend *me);
324bool midend_wants_statusbar(midend *me); 335bool midend_wants_statusbar(midend *me);
325enum { CFG_SETTINGS, CFG_SEED, CFG_DESC, CFG_FRONTEND_SPECIFIC }; 336enum { CFG_SETTINGS, CFG_SEED, CFG_DESC, CFG_PREFS, CFG_FRONTEND_SPECIFIC };
326config_item *midend_get_config(midend *me, int which, char **wintitle); 337config_item *midend_get_config(midend *me, int which, char **wintitle);
327const char *midend_set_config(midend *me, int which, config_item *cfg); 338const char *midend_set_config(midend *me, int which, config_item *cfg);
328const char *midend_game_id(midend *me, const char *id); 339const char *midend_game_id(midend *me, const char *id);
@@ -343,6 +354,11 @@ void midend_serialise(midend *me,
343const char *midend_deserialise(midend *me, 354const char *midend_deserialise(midend *me,
344 bool (*read)(void *ctx, void *buf, int len), 355 bool (*read)(void *ctx, void *buf, int len),
345 void *rctx); 356 void *rctx);
357const char *midend_load_prefs(
358 midend *me, bool (*read)(void *ctx, void *buf, int len), void *rctx);
359void midend_save_prefs(midend *me,
360 void (*write)(void *ctx, const void *buf, int len),
361 void *wctx);
346const char *identify_game(char **name, 362const char *identify_game(char **name,
347 bool (*read)(void *ctx, void *buf, int len), 363 bool (*read)(void *ctx, void *buf, int len),
348 void *rctx); 364 void *rctx);
@@ -374,12 +390,22 @@ void free_cfg(config_item *cfg);
374void free_keys(key_label *keys, int nkeys); 390void free_keys(key_label *keys, int nkeys);
375void obfuscate_bitmap(unsigned char *bmp, int bits, bool decode); 391void obfuscate_bitmap(unsigned char *bmp, int bits, bool decode);
376char *fgetline(FILE *fp); 392char *fgetline(FILE *fp);
393char *make_prefs_path(const char *dir, const char *sep,
394 const game *game, const char *suffix);
395int n_times_root_k(int n, int k);
377 396
378/* allocates output each time. len is always in bytes of binary data. 397/* allocates output each time. len is always in bytes of binary data.
379 * May assert (or just go wrong) if lengths are unchecked. */ 398 * May assert (or just go wrong) if lengths are unchecked. */
380char *bin2hex(const unsigned char *in, int inlen); 399char *bin2hex(const unsigned char *in, int inlen);
381unsigned char *hex2bin(const char *in, int outlen); 400unsigned char *hex2bin(const char *in, int outlen);
382 401
402/* Returns 0 or 1 if the environment variable is set, or dflt if not.
403 * dflt may be a third value if it needs to be. */
404int getenv_bool(const char *name, int dflt);
405
406/* Mixes two colours in specified proportions. */
407void colour_mix(const float src1[3], const float src2[3], float p,
408 float dst[3]);
383/* Sets (and possibly dims) background from frontend default colour, 409/* Sets (and possibly dims) background from frontend default colour,
384 * and auto-generates highlight and lowlight colours too. */ 410 * and auto-generates highlight and lowlight colours too. */
385void game_mkhighlight(frontend *fe, float *ret, 411void game_mkhighlight(frontend *fe, float *ret,
@@ -392,14 +418,15 @@ void game_mkhighlight_specific(frontend *fe, float *ret,
392/* Randomly shuffles an array of items. */ 418/* Randomly shuffles an array of items. */
393void shuffle(void *array, int nelts, int eltsize, random_state *rs); 419void shuffle(void *array, int nelts, int eltsize, random_state *rs);
394 420
395/* Draw a rectangle outline, using the drawing API's draw_line. */ 421/* Draw a rectangle outline, using the drawing API's draw_polygon. */
396void draw_rect_outline(drawing *dr, int x, int y, int w, int h, 422void draw_rect_outline(drawing *dr, int x, int y, int w, int h,
397 int colour); 423 int colour);
398 424
399/* Draw a set of rectangle corners (e.g. for a cursor display). */ 425/* Draw a set of rectangle corners (e.g. for a cursor display). */
400void draw_rect_corners(drawing *dr, int cx, int cy, int r, int col); 426void draw_rect_corners(drawing *dr, int cx, int cy, int r, int col);
401 427
402void move_cursor(int button, int *x, int *y, int maxw, int maxh, bool wrap); 428char *move_cursor(int button, int *x, int *y, int maxw, int maxh, bool wrap,
429 bool *visible);
403 430
404/* Used in netslide.c and sixteen.c for cursor movement around edge. */ 431/* Used in netslide.c and sixteen.c for cursor movement around edge. */
405int c2pos(int w, int h, int cx, int cy); 432int c2pos(int w, int h, int cx, int cy);
@@ -416,37 +443,52 @@ void draw_text_outline(drawing *dr, int x, int y, int fonttype,
416 * less than buffer size. */ 443 * less than buffer size. */
417void copy_left_justified(char *buf, size_t sz, const char *str); 444void copy_left_justified(char *buf, size_t sz, const char *str);
418 445
419/* An ugly, but working float-to-string implementation for platforms
420 * that don't have one */
421int ftoa(char *buf, float f);
422
423/* Returns a generic label based on the value of `button.' To be used 446/* Returns a generic label based on the value of `button.' To be used
424 whenever a `label' field returned by the request_keys() game 447 whenever a `label' field returned by the request_keys() game
425 function is NULL. Dynamically allocated, to be freed by caller. */ 448 function is NULL. Dynamically allocated, to be freed by caller. */
426char *button2label(int button); 449char *button2label(int button);
427 450
451/* Swap two regions of memory. The two regions must not
452 * overlap. (Note: the natural name for this might be "memswap", but
453 * the mem* namespace is reserved for future expansion by the C99
454 * standard per clause 7.26.11.1.) */
455void swap_regions(void *av, void *bv, size_t size);
456
428/* 457/*
429 * dsf.c 458 * dsf.c
430 */ 459 */
431int *snew_dsf(int size); 460typedef struct DSF DSF;
432 461DSF *dsf_new(int size);
433void print_dsf(int *dsf, int size); 462void dsf_free(DSF *dsf);
434 463
435/* Return the canonical element of the equivalence class containing element 464void dsf_copy(DSF *to, DSF *from);
436 * val. If 'inverse' is non-NULL, this function will put into it a flag 465
437 * indicating whether the canonical element is inverse to val. */ 466/* Basic dsf operations, return the canonical element of a class,
438int edsf_canonify(int *dsf, int val, bool *inverse); 467 * check if two elements are in the same class, and return the size of
439int dsf_canonify(int *dsf, int val); 468 * a class. These work on all types of dsf. */
440int dsf_size(int *dsf, int val); 469int dsf_canonify(DSF *dsf, int n);
441 470bool dsf_equivalent(DSF *dsf, int n1, int n2);
442/* Allow the caller to specify that two elements should be in the same 471int dsf_size(DSF *dsf, int n);
443 * equivalence class. If 'inverse' is true, the elements are actually opposite 472
444 * to one another in some sense. This function will fail an assertion if the 473/* Merge two elements and their classes. Not legal on a flip dsf. */
445 * caller gives it self-contradictory data, ie if two elements are claimed to 474void dsf_merge(DSF *dsf, int n1, int n2);
446 * be both opposite and non-opposite. */ 475
447void edsf_merge(int *dsf, int v1, int v2, bool inverse); 476/* Special dsf that tracks the minimal element of every equivalence
448void dsf_merge(int *dsf, int v1, int v2); 477 * class, and a function to query it. */
449void dsf_init(int *dsf, int len); 478DSF *dsf_new_min(int size);
479int dsf_minimal(DSF *dsf, int n);
480
481/* Special dsf that tracks whether pairs of elements in the same class
482 * have flipped sense relative to each other. Merge function takes an
483 * argument saying whether n1 and n2 are opposite to each other;
484 * canonify function will report whether n is opposite to the returned
485 * element. */
486DSF *dsf_new_flip(int size);
487void dsf_merge_flip(DSF *dsf, int n1, int n2, bool flip);
488int dsf_canonify_flip(DSF *dsf, int n, bool *flip);
489
490/* Reinitialise a dsf to the starting 'all elements distinct' state. */
491void dsf_reinit(DSF *dsf);
450 492
451/* 493/*
452 * tdq.c 494 * tdq.c
@@ -507,7 +549,7 @@ void random_free(random_state *state);
507char *random_state_encode(random_state *state); 549char *random_state_encode(random_state *state);
508random_state *random_state_decode(const char *input); 550random_state *random_state_decode(const char *input);
509/* random.c also exports SHA, which occasionally comes in useful. */ 551/* random.c also exports SHA, which occasionally comes in useful. */
510#if __STDC_VERSION__ >= 199901L 552#if HAVE_STDINT_H
511#include <stdint.h> 553#include <stdint.h>
512typedef uint32_t uint32; 554typedef uint32_t uint32;
513#elif UINT_MAX >= 4294967295L 555#elif UINT_MAX >= 4294967295L
@@ -532,7 +574,7 @@ void SHA_Simple(const void *p, int len, unsigned char *output);
532document *document_new(int pw, int ph, float userscale); 574document *document_new(int pw, int ph, float userscale);
533void document_free(document *doc); 575void document_free(document *doc);
534void document_add_puzzle(document *doc, const game *game, game_params *par, 576void document_add_puzzle(document *doc, const game *game, game_params *par,
535 game_state *st, game_state *st2); 577 game_ui *ui, game_state *st, game_state *st2);
536int document_npages(const document *doc); 578int document_npages(const document *doc);
537void document_begin(const document *doc, drawing *dr); 579void document_begin(const document *doc, drawing *dr);
538void document_end(const document *doc, drawing *dr); 580void document_end(const document *doc, drawing *dr);
@@ -564,7 +606,9 @@ void free_combi(combi_ctx *combi);
564 * divvy.c 606 * divvy.c
565 */ 607 */
566/* divides w*h rectangle into pieces of size k. Returns w*h dsf. */ 608/* divides w*h rectangle into pieces of size k. Returns w*h dsf. */
567int *divvy_rectangle(int w, int h, int k, random_state *rs); 609DSF *divvy_rectangle(int w, int h, int k, random_state *rs);
610/* Same, but only tries once, and may fail. (Exposed for test program.) */
611DSF *divvy_rectangle_attempt(int w, int h, int k, random_state *rs);
568 612
569/* 613/*
570 * findloop.c 614 * findloop.c
@@ -661,19 +705,24 @@ struct game {
661 bool can_format_as_text_ever; 705 bool can_format_as_text_ever;
662 bool (*can_format_as_text_now)(const game_params *params); 706 bool (*can_format_as_text_now)(const game_params *params);
663 char *(*text_format)(const game_state *state); 707 char *(*text_format)(const game_state *state);
708 config_item *(*get_prefs)(game_ui *ui);
709 void (*set_prefs)(game_ui *ui, const config_item *cfg);
664 game_ui *(*new_ui)(const game_state *state); 710 game_ui *(*new_ui)(const game_state *state);
665 void (*free_ui)(game_ui *ui); 711 void (*free_ui)(game_ui *ui);
666 char *(*encode_ui)(const game_ui *ui); 712 char *(*encode_ui)(const game_ui *ui);
667 void (*decode_ui)(game_ui *ui, const char *encoding); 713 void (*decode_ui)(game_ui *ui, const char *encoding,
714 const game_state *state);
668 key_label *(*request_keys)(const game_params *params, int *nkeys); 715 key_label *(*request_keys)(const game_params *params, int *nkeys);
669 void (*changed_state)(game_ui *ui, const game_state *oldstate, 716 void (*changed_state)(game_ui *ui, const game_state *oldstate,
670 const game_state *newstate); 717 const game_state *newstate);
718 const char *(*current_key_label)(const game_ui *ui,
719 const game_state *state, int button);
671 char *(*interpret_move)(const game_state *state, game_ui *ui, 720 char *(*interpret_move)(const game_state *state, game_ui *ui,
672 const game_drawstate *ds, int x, int y, int button); 721 const game_drawstate *ds, int x, int y, int button);
673 game_state *(*execute_move)(const game_state *state, const char *move); 722 game_state *(*execute_move)(const game_state *state, const char *move);
674 int preferred_tilesize; 723 int preferred_tilesize;
675 void (*compute_size)(const game_params *params, int tilesize, 724 void (*compute_size)(const game_params *params, int tilesize,
676 int *x, int *y); 725 const game_ui *ui, int *x, int *y);
677 void (*set_size)(drawing *dr, game_drawstate *ds, 726 void (*set_size)(drawing *dr, game_drawstate *ds,
678 const game_params *params, int tilesize); 727 const game_params *params, int tilesize);
679 float *(*colours)(frontend *fe, int *ncolours); 728 float *(*colours)(frontend *fe, int *ncolours);
@@ -693,8 +742,10 @@ struct game {
693 int *x, int *y, int *w, int *h); 742 int *x, int *y, int *w, int *h);
694 int (*status)(const game_state *state); 743 int (*status)(const game_state *state);
695 bool can_print, can_print_in_colour; 744 bool can_print, can_print_in_colour;
696 void (*print_size)(const game_params *params, float *x, float *y); 745 void (*print_size)(const game_params *params, const game_ui *ui,
697 void (*print)(drawing *dr, const game_state *state, int tilesize); 746 float *x, float *y);
747 void (*print)(drawing *dr, const game_state *state, const game_ui *ui,
748 int tilesize);
698 bool wants_statusbar; 749 bool wants_statusbar;
699 bool is_timed; 750 bool is_timed;
700 bool (*timing_state)(const game_state *state, game_ui *ui); 751 bool (*timing_state)(const game_state *state, game_ui *ui);
@@ -712,7 +763,7 @@ struct drawing_api {
712 void (*draw_rect)(void *handle, int x, int y, int w, int h, int colour); 763 void (*draw_rect)(void *handle, int x, int y, int w, int h, int colour);
713 void (*draw_line)(void *handle, int x1, int y1, int x2, int y2, 764 void (*draw_line)(void *handle, int x1, int y1, int x2, int y2,
714 int colour); 765 int colour);
715 void (*draw_polygon)(void *handle, int *coords, int npoints, 766 void (*draw_polygon)(void *handle, const int *coords, int npoints,
716 int fillcolour, int outlinecolour); 767 int fillcolour, int outlinecolour);
717 void (*draw_circle)(void *handle, int cx, int cy, int radius, 768 void (*draw_circle)(void *handle, int cx, int cy, int radius,
718 int fillcolour, int outlinecolour); 769 int fillcolour, int outlinecolour);
@@ -750,17 +801,29 @@ struct drawing_api {
750#ifdef COMBINED 801#ifdef COMBINED
751extern const game *gamelist[]; 802extern const game *gamelist[];
752extern const int gamecount; 803extern const int gamecount;
804/* Also pre-declare every individual 'struct game' we expect */
805#define GAME(x) extern const game x;
806#include "generated-games.h"
807#undef GAME
753#else 808#else
754extern const game thegame; 809extern const game thegame;
755#endif 810#endif
756 811
757/* 812/*
758 * Special string value to return from interpret_move in the case 813 * Special string values to return from interpret_move.
759 * where the game UI has been updated but no actual move is being 814 *
760 * appended to the undo chain. Must be declared as a non-const char, 815 * MOVE_UI_UPDATE is for the case where the game UI has been updated
761 * but should never actually be modified by anyone. 816 * but no actual move is being appended to the undo chain.
817 *
818 * MOVE_NO_EFFECT is for when the key was understood by the puzzle,
819 * but it happens that there isn't effect, not even a UI change.
820 *
821 * MOVE_UNUSED is for keys that the puzzle has no use for at all.
822 *
823 * Each must be declared as a non-const char, but should never
824 * actually be modified by anyone.
762 */ 825 */
763extern char UI_UPDATE[]; 826extern char MOVE_UI_UPDATE[], MOVE_NO_EFFECT[], MOVE_UNUSED[];
764 827
765/* A little bit of help to lazy developers */ 828/* A little bit of help to lazy developers */
766#define DEFAULT_STATUSBAR_TEXT "Use status_bar() to fill this in." 829#define DEFAULT_STATUSBAR_TEXT "Use status_bar() to fill this in."
diff --git a/apps/plugins/puzzles/src/random.c b/apps/plugins/puzzles/src/random.c
index fb54560c95..bd11f16601 100644
--- a/apps/plugins/puzzles/src/random.c
+++ b/apps/plugins/puzzles/src/random.c
@@ -109,7 +109,7 @@ void SHA_Init(SHA_State * s)
109 109
110void SHA_Bytes(SHA_State * s, const void *p, int len) 110void SHA_Bytes(SHA_State * s, const void *p, int len)
111{ 111{
112 unsigned char *q = (unsigned char *) p; 112 const unsigned char *q = (const unsigned char *) p;
113 uint32 wordblock[16]; 113 uint32 wordblock[16];
114 uint32 lenw = len; 114 uint32 lenw = len;
115 int i; 115 int i;
@@ -254,12 +254,12 @@ unsigned long random_bits(random_state *state, int bits)
254 } 254 }
255 255
256 /* 256 /*
257 * `(1 << bits) - 1' is not good enough, since if bits==32 on a 257 * `(1UL << bits) - 1' is not good enough, since if bits==32 on a
258 * 32-bit machine, behaviour is undefined and Intel has a nasty 258 * 32-bit machine, behaviour is undefined and Intel has a nasty
259 * habit of shifting left by zero instead. We'll shift by 259 * habit of shifting left by zero instead. We'll shift by
260 * bits-1 and then separately shift by one. 260 * bits-1 and then separately shift by one.
261 */ 261 */
262 ret &= (1 << (bits-1)) * 2 - 1; 262 ret &= (1UL << (bits-1)) * 2 - 1;
263 return ret; 263 return ret;
264} 264}
265 265
diff --git a/apps/plugins/puzzles/src/range.R b/apps/plugins/puzzles/src/range.R
deleted file mode 100644
index f1256efd1e..0000000000
--- a/apps/plugins/puzzles/src/range.R
+++ /dev/null
@@ -1,21 +0,0 @@
1# -*- makefile -*-
2
3RANGE_EXTRA = dsf
4
5range : [X] GTK COMMON range RANGE_EXTRA range-icon|no-icon
6
7range : [G] WINDOWS COMMON range RANGE_EXTRA range.res|noicon.res
8
9ALL += range[COMBINED] RANGE_EXTRA
10
11!begin am gtk
12GAMES += range
13!end
14
15!begin >list.c
16 A(range) \
17!end
18
19!begin >gamedesc.txt
20range:range.exe:Range:Visible-distance puzzle:Place black squares to limit the visible distance from each numbered cell.
21!end
diff --git a/apps/plugins/puzzles/src/range.c b/apps/plugins/puzzles/src/range.c
index fc0a5405f1..bc29f7604b 100644
--- a/apps/plugins/puzzles/src/range.c
+++ b/apps/plugins/puzzles/src/range.c
@@ -58,7 +58,11 @@
58#include <string.h> 58#include <string.h>
59#include <assert.h> 59#include <assert.h>
60#include <ctype.h> 60#include <ctype.h>
61#include <math.h> 61#ifdef NO_TGMATH_H
62# include <math.h>
63#else
64# include <tgmath.h>
65#endif
62 66
63#include "puzzles.h" 67#include "puzzles.h"
64 68
@@ -911,8 +915,8 @@ static const char *validate_params(const game_params *params, bool full)
911 int const w = params->w, h = params->h; 915 int const w = params->w, h = params->h;
912 if (w < 1) return "Error: width is less than 1"; 916 if (w < 1) return "Error: width is less than 1";
913 if (h < 1) return "Error: height is less than 1"; 917 if (h < 1) return "Error: height is less than 1";
918 if (w > SCHAR_MAX - (h - 1)) return "Error: w + h is too big";
914 if (w * h < 1) return "Error: size is less than 1"; 919 if (w * h < 1) return "Error: size is less than 1";
915 if (w + h - 1 > SCHAR_MAX) return "Error: w + h is too big";
916 /* I might be unable to store clues in my puzzle_size *grid; */ 920 /* I might be unable to store clues in my puzzle_size *grid; */
917 if (full) { 921 if (full) {
918 if (w == 2 && h == 2) return "Error: can't create 2x2 puzzles"; 922 if (w == 2 && h == 2) return "Error: can't create 2x2 puzzles";
@@ -1221,28 +1225,101 @@ static char *game_text_format(const game_state *state)
1221struct game_ui { 1225struct game_ui {
1222 puzzle_size r, c; /* cursor position */ 1226 puzzle_size r, c; /* cursor position */
1223 bool cursor_show; 1227 bool cursor_show;
1228
1229 /*
1230 * User preference option to swap the left and right mouse
1231 * buttons.
1232 *
1233 * The original puzzle submitter thought it would be more useful
1234 * to have the left button turn an empty square into a dotted one,
1235 * on the grounds that that was what you did most often; I (SGT)
1236 * felt instinctively that the left button ought to place black
1237 * squares and the right button place dots, on the grounds that
1238 * that was consistent with many other puzzles in which the left
1239 * button fills in the data used by the solution checker while the
1240 * right button places pencil marks for the user's convenience.
1241 *
1242 * My first beta-player wasn't sure either, so I thought I'd
1243 * pre-emptively put in a 'configuration' mechanism just in case.
1244 */
1245 bool swap_buttons;
1224}; 1246};
1225 1247
1248static void legacy_prefs_override(struct game_ui *ui_out)
1249{
1250 static int initialised = false;
1251 static int swap_buttons = -1;
1252
1253 if (!initialised) {
1254 initialised = true;
1255 swap_buttons = getenv_bool("RANGE_SWAP_BUTTONS", -1);
1256 }
1257
1258 if (swap_buttons != -1)
1259 ui_out->swap_buttons = swap_buttons;
1260}
1261
1226static game_ui *new_ui(const game_state *state) 1262static game_ui *new_ui(const game_state *state)
1227{ 1263{
1228 struct game_ui *ui = snew(game_ui); 1264 struct game_ui *ui = snew(game_ui);
1229 ui->r = ui->c = 0; 1265 ui->r = ui->c = 0;
1230 ui->cursor_show = false; 1266 ui->cursor_show = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1267
1268 ui->swap_buttons = false;
1269 legacy_prefs_override(ui);
1270
1231 return ui; 1271 return ui;
1232} 1272}
1233 1273
1234static void free_ui(game_ui *ui) 1274static config_item *get_prefs(game_ui *ui)
1235{ 1275{
1236 sfree(ui); 1276 config_item *ret;
1277
1278 ret = snewn(2, config_item);
1279
1280 ret[0].name = "Mouse button order";
1281 ret[0].kw = "left-mouse-button";
1282 ret[0].type = C_CHOICES;
1283 ret[0].u.choices.choicenames =
1284 ":Left to fill, right to dot:Left to dot, right to fill";
1285 ret[0].u.choices.choicekws = ":fill:dot";
1286 ret[0].u.choices.selected = ui->swap_buttons;
1287
1288 ret[1].name = NULL;
1289 ret[1].type = C_END;
1290
1291 return ret;
1237} 1292}
1238 1293
1239static char *encode_ui(const game_ui *ui) 1294static void set_prefs(game_ui *ui, const config_item *cfg)
1240{ 1295{
1241 return NULL; 1296 ui->swap_buttons = cfg[0].u.choices.selected;
1297}
1298
1299static void free_ui(game_ui *ui)
1300{
1301 sfree(ui);
1242} 1302}
1243 1303
1244static void decode_ui(game_ui *ui, const char *encoding) 1304static const char *current_key_label(const game_ui *ui,
1305 const game_state *state, int button)
1245{ 1306{
1307 int cell;
1308
1309 if (IS_CURSOR_SELECT(button)) {
1310 cell = state->grid[idx(ui->r, ui->c, state->params.w)];
1311 if (!ui->cursor_show || cell > 0) return "";
1312 switch (cell) {
1313 case EMPTY:
1314 return button == CURSOR_SELECT ? "Fill" : "Dot";
1315 case WHITE:
1316 return button == CURSOR_SELECT ? "Empty" : "Fill";
1317 case BLACK:
1318 return button == CURSOR_SELECT ? "Dot" : "Empty";
1319 }
1320 }
1321 return "";
1322
1246} 1323}
1247 1324
1248typedef struct drawcell { 1325typedef struct drawcell {
@@ -1253,7 +1330,6 @@ typedef struct drawcell {
1253struct game_drawstate { 1330struct game_drawstate {
1254 int tilesize; 1331 int tilesize;
1255 drawcell *grid; 1332 drawcell *grid;
1256 bool started;
1257}; 1333};
1258 1334
1259#define TILESIZE (ds->tilesize) 1335#define TILESIZE (ds->tilesize)
@@ -1283,38 +1359,12 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1283 } 1359 }
1284 1360
1285 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { 1361 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
1286 /* 1362 if (ui->swap_buttons) {
1287 * Utterly awful hack, exactly analogous to the one in Slant, 1363 if (button == LEFT_BUTTON)
1288 * to configure the left and right mouse buttons the opposite 1364 button = RIGHT_BUTTON;
1289 * way round. 1365 else
1290 * 1366 button = LEFT_BUTTON;
1291 * The original puzzle submitter thought it would be more 1367 }
1292 * useful to have the left button turn an empty square into a
1293 * dotted one, on the grounds that that was what you did most
1294 * often; I (SGT) felt instinctively that the left button
1295 * ought to place black squares and the right button place
1296 * dots, on the grounds that that was consistent with many
1297 * other puzzles in which the left button fills in the data
1298 * used by the solution checker while the right button places
1299 * pencil marks for the user's convenience.
1300 *
1301 * My first beta-player wasn't sure either, so I thought I'd
1302 * pre-emptively put in a 'configuration' mechanism just in
1303 * case.
1304 */
1305 {
1306 static int swap_buttons = -1;
1307 if (swap_buttons < 0) {
1308 char *env = getenv("RANGE_SWAP_BUTTONS");
1309 swap_buttons = (env && (env[0] == 'y' || env[0] == 'Y'));
1310 }
1311 if (swap_buttons) {
1312 if (button == LEFT_BUTTON)
1313 button = RIGHT_BUTTON;
1314 else
1315 button = LEFT_BUTTON;
1316 }
1317 }
1318 } 1368 }
1319 1369
1320 switch (button) { 1370 switch (button) {
@@ -1355,14 +1405,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1355 else if (do_post) 1405 else if (do_post)
1356 return nfmtstr(40, "W,%d,%d", ui->r, ui->c); 1406 return nfmtstr(40, "W,%d,%d", ui->r, ui->c);
1357 else 1407 else
1358 return UI_UPDATE; 1408 return MOVE_UI_UPDATE;
1359 1409
1360 } else if (!out_of_bounds(ui->r + dr[i], ui->c + dc[i], w, h)) { 1410 } else if (!out_of_bounds(ui->r + dr[i], ui->c + dc[i], w, h)) {
1361 ui->r += dr[i]; 1411 ui->r += dr[i];
1362 ui->c += dc[i]; 1412 ui->c += dc[i];
1363 } 1413 }
1364 } else ui->cursor_show = true; 1414 } else ui->cursor_show = true;
1365 return UI_UPDATE; 1415 return MOVE_UI_UPDATE;
1366 } 1416 }
1367 1417
1368 if (action == hint) { 1418 if (action == hint) {
@@ -1408,7 +1458,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1408static bool find_errors(const game_state *state, bool *report) 1458static bool find_errors(const game_state *state, bool *report)
1409{ 1459{
1410 int const w = state->params.w, h = state->params.h, n = w * h; 1460 int const w = state->params.w, h = state->params.h, n = w * h;
1411 int *dsf; 1461 DSF *dsf;
1412 1462
1413 int r, c, i; 1463 int r, c, i;
1414 1464
@@ -1463,7 +1513,7 @@ static bool find_errors(const game_state *state, bool *report)
1463 /* 1513 /*
1464 * Check that all the white cells form a single connected component. 1514 * Check that all the white cells form a single connected component.
1465 */ 1515 */
1466 dsf = snew_dsf(n); 1516 dsf = dsf_new(n);
1467 for (r = 0; r < h-1; ++r) 1517 for (r = 0; r < h-1; ++r)
1468 for (c = 0; c < w; ++c) 1518 for (c = 0; c < w; ++c)
1469 if (state->grid[r*w+c] != BLACK && 1519 if (state->grid[r*w+c] != BLACK &&
@@ -1474,11 +1524,12 @@ static bool find_errors(const game_state *state, bool *report)
1474 if (state->grid[r*w+c] != BLACK && 1524 if (state->grid[r*w+c] != BLACK &&
1475 state->grid[r*w+(c+1)] != BLACK) 1525 state->grid[r*w+(c+1)] != BLACK)
1476 dsf_merge(dsf, r*w+c, r*w+(c+1)); 1526 dsf_merge(dsf, r*w+c, r*w+(c+1));
1477 if (nblack + dsf_size(dsf, any_white_cell) < n) { 1527 if (any_white_cell != -1 &&
1528 nblack + dsf_size(dsf, any_white_cell) < n) {
1478 int biggest, canonical; 1529 int biggest, canonical;
1479 1530
1480 if (!report) { 1531 if (!report) {
1481 sfree(dsf); 1532 dsf_free(dsf);
1482 goto found_error; 1533 goto found_error;
1483 } 1534 }
1484 1535
@@ -1503,7 +1554,7 @@ static bool find_errors(const game_state *state, bool *report)
1503 if (state->grid[i] != BLACK && dsf_canonify(dsf, i) != canonical) 1554 if (state->grid[i] != BLACK && dsf_canonify(dsf, i) != canonical)
1504 report[i] = true; 1555 report[i] = true;
1505 } 1556 }
1506 sfree(dsf); 1557 dsf_free(dsf);
1507 1558
1508 free_game(dup); 1559 free_game(dup);
1509 return false; /* if report != NULL, this is ignored */ 1560 return false; /* if report != NULL, this is ignored */
@@ -1604,13 +1655,12 @@ enum {
1604 COL_USER = COL_GRID, 1655 COL_USER = COL_GRID,
1605 COL_ERROR, 1656 COL_ERROR,
1606 COL_LOWLIGHT, 1657 COL_LOWLIGHT,
1607 COL_HIGHLIGHT = COL_ERROR, /* mkhighlight needs it, I don't */
1608 COL_CURSOR = COL_LOWLIGHT, 1658 COL_CURSOR = COL_LOWLIGHT,
1609 NCOLOURS 1659 NCOLOURS
1610}; 1660};
1611 1661
1612static void game_compute_size(const game_params *params, int tilesize, 1662static void game_compute_size(const game_params *params, int tilesize,
1613 int *x, int *y) 1663 const game_ui *ui, int *x, int *y)
1614{ 1664{
1615 *x = (1 + params->w) * tilesize; 1665 *x = (1 + params->w) * tilesize;
1616 *y = (1 + params->h) * tilesize; 1666 *y = (1 + params->h) * tilesize;
@@ -1629,7 +1679,7 @@ static float *game_colours(frontend *fe, int *ncolours)
1629{ 1679{
1630 float *ret = snewn(3 * NCOLOURS, float); 1680 float *ret = snewn(3 * NCOLOURS, float);
1631 1681
1632 game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); 1682 game_mkhighlight(fe, ret, COL_BACKGROUND, -1, COL_LOWLIGHT);
1633 COLOUR(ret, COL_GRID, 0.0F, 0.0F, 0.0F); 1683 COLOUR(ret, COL_GRID, 0.0F, 0.0F, 0.0F);
1634 COLOUR(ret, COL_ERROR, 1.0F, 0.0F, 0.0F); 1684 COLOUR(ret, COL_ERROR, 1.0F, 0.0F, 0.0F);
1635 1685
@@ -1655,7 +1705,6 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1655 int i; 1705 int i;
1656 1706
1657 ds->tilesize = 0; 1707 ds->tilesize = 0;
1658 ds->started = false;
1659 1708
1660 ds->grid = snewn(n, drawcell); 1709 ds->grid = snewn(n, drawcell);
1661 for (i = 0; i < n; ++i) 1710 for (i = 0; i < n; ++i)
@@ -1690,7 +1739,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1690 float animtime, float flashtime) 1739 float animtime, float flashtime)
1691{ 1740{
1692 int const w = state->params.w, h = state->params.h, n = w * h; 1741 int const w = state->params.w, h = state->params.h, n = w * h;
1693 int const wpx = (w+1) * ds->tilesize, hpx = (h+1) * ds->tilesize;
1694 int const flash = ((int) (flashtime * 5 / FLASH_TIME)) % 2; 1742 int const flash = ((int) (flashtime * 5 / FLASH_TIME)) % 2;
1695 1743
1696 int r, c, i; 1744 int r, c, i;
@@ -1701,12 +1749,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1701 1749
1702 assert (oldstate == NULL); /* only happens if animating moves */ 1750 assert (oldstate == NULL); /* only happens if animating moves */
1703 1751
1704 if (!ds->started) {
1705 ds->started = true;
1706 draw_rect(dr, 0, 0, wpx, hpx, COL_BACKGROUND);
1707 draw_update(dr, 0, 0, wpx, hpx);
1708 }
1709
1710 for (i = r = 0; r < h; ++r) { 1752 for (i = r = 0; r < h; ++r) {
1711 for (c = 0; c < w; ++c, ++i) { 1753 for (c = 0; c < w; ++c, ++i) {
1712 drawcell cell = makecell(state->grid[i], errors[i], false, flash); 1754 drawcell cell = makecell(state->grid[i], errors[i], false, flash);
@@ -1757,25 +1799,21 @@ static void draw_cell(drawing *draw, game_drawstate *ds, int r, int c,
1757 draw_update(draw, x, y, ts + 1, ts + 1); 1799 draw_update(draw, x, y, ts + 1, ts + 1);
1758} 1800}
1759 1801
1760static bool game_timing_state(const game_state *state, game_ui *ui)
1761{
1762 puts("warning: game_timing_state was called (this shouldn't happen)");
1763 return false; /* the (non-existing) timer should not be running */
1764}
1765
1766/* ---------------------------------------------------------------------- 1802/* ----------------------------------------------------------------------
1767 * User interface: print 1803 * User interface: print
1768 */ 1804 */
1769 1805
1770static void game_print_size(const game_params *params, float *x, float *y) 1806static void game_print_size(const game_params *params, const game_ui *ui,
1807 float *x, float *y)
1771{ 1808{
1772 int print_width, print_height; 1809 int print_width, print_height;
1773 game_compute_size(params, 800, &print_width, &print_height); 1810 game_compute_size(params, 800, ui, &print_width, &print_height);
1774 *x = print_width / 100.0F; 1811 *x = print_width / 100.0F;
1775 *y = print_height / 100.0F; 1812 *y = print_height / 100.0F;
1776} 1813}
1777 1814
1778static void game_print(drawing *dr, const game_state *state, int tilesize) 1815static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
1816 int tilesize)
1779{ 1817{
1780 int const w = state->params.w, h = state->params.h; 1818 int const w = state->params.w, h = state->params.h;
1781 game_drawstate ds_obj, *ds = &ds_obj; 1819 game_drawstate ds_obj, *ds = &ds_obj;
@@ -1821,12 +1859,14 @@ struct game const thegame = {
1821 free_game, 1859 free_game,
1822 true, solve_game, 1860 true, solve_game,
1823 true, game_can_format_as_text_now, game_text_format, 1861 true, game_can_format_as_text_now, game_text_format,
1862 get_prefs, set_prefs,
1824 new_ui, 1863 new_ui,
1825 free_ui, 1864 free_ui,
1826 encode_ui, 1865 NULL, /* encode_ui */
1827 decode_ui, 1866 NULL, /* decode_ui */
1828 NULL, /* game_request_keys */ 1867 NULL, /* game_request_keys */
1829 game_changed_state, 1868 game_changed_state,
1869 current_key_label,
1830 interpret_move, 1870 interpret_move,
1831 execute_move, 1871 execute_move,
1832 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 1872 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -1840,6 +1880,6 @@ struct game const thegame = {
1840 game_status, 1880 game_status,
1841 true, false, game_print_size, game_print, 1881 true, false, game_print_size, game_print,
1842 false, /* wants_statusbar */ 1882 false, /* wants_statusbar */
1843 false, game_timing_state, 1883 false, NULL, /* timing_state */
1844 0, /* flags */ 1884 0, /* flags */
1845}; 1885};
diff --git a/apps/plugins/puzzles/src/rect.R b/apps/plugins/puzzles/src/rect.R
deleted file mode 100644
index 1448c0fa63..0000000000
--- a/apps/plugins/puzzles/src/rect.R
+++ /dev/null
@@ -1,19 +0,0 @@
1# -*- makefile -*-
2
3rect : [X] GTK COMMON rect rect-icon|no-icon
4
5rect : [G] WINDOWS COMMON rect rect.res|noicon.res
6
7ALL += rect[COMBINED]
8
9!begin am gtk
10GAMES += rect
11!end
12
13!begin >list.c
14 A(rect) \
15!end
16
17!begin >gamedesc.txt
18rect:rect.exe:Rectangles:Rectangles puzzle:Divide the grid into rectangles with areas equal to the numbers.
19!end
diff --git a/apps/plugins/puzzles/src/rect.c b/apps/plugins/puzzles/src/rect.c
index b13de75fd4..c3ee1ab478 100644
--- a/apps/plugins/puzzles/src/rect.c
+++ b/apps/plugins/puzzles/src/rect.c
@@ -26,7 +26,11 @@
26#include <string.h> 26#include <string.h>
27#include <assert.h> 27#include <assert.h>
28#include <ctype.h> 28#include <ctype.h>
29#include <math.h> 29#ifdef NO_TGMATH_H
30# include <math.h>
31#else
32# include <tgmath.h>
33#endif
30 34
31#include "puzzles.h" 35#include "puzzles.h"
32 36
@@ -163,10 +167,7 @@ static char *encode_params(const game_params *params, bool full)
163 167
164 sprintf(data, "%dx%d", params->w, params->h); 168 sprintf(data, "%dx%d", params->w, params->h);
165 if (full && params->expandfactor) 169 if (full && params->expandfactor)
166 { 170 sprintf(data + strlen(data), "e%g", params->expandfactor);
167 sprintf(data + strlen(data), "e");
168 ftoa(data + strlen(data), params->expandfactor);
169 }
170 if (full && !params->unique) 171 if (full && !params->unique)
171 strcat(data, "a"); 172 strcat(data, "a");
172 173
@@ -192,7 +193,7 @@ static config_item *game_configure(const game_params *params)
192 193
193 ret[2].name = "Expansion factor"; 194 ret[2].name = "Expansion factor";
194 ret[2].type = C_STRING; 195 ret[2].type = C_STRING;
195 ftoa(buf, params->expandfactor); 196 sprintf(buf, "%g", params->expandfactor);
196 ret[2].u.string.sval = dupstr(buf); 197 ret[2].u.string.sval = dupstr(buf);
197 198
198 ret[3].name = "Ensure unique solution"; 199 ret[3].name = "Ensure unique solution";
@@ -221,6 +222,8 @@ static const char *validate_params(const game_params *params, bool full)
221{ 222{
222 if (params->w <= 0 || params->h <= 0) 223 if (params->w <= 0 || params->h <= 0)
223 return "Width and height must both be greater than zero"; 224 return "Width and height must both be greater than zero";
225 if (params->w > INT_MAX / params->h)
226 return "Width times height must not be unreasonably large";
224 if (params->w*params->h < 2) 227 if (params->w*params->h < 2)
225 return "Grid area must be greater than one"; 228 return "Grid area must be greater than one";
226 if (params->expandfactor < 0.0F) 229 if (params->expandfactor < 0.0F)
@@ -2207,7 +2210,7 @@ static game_ui *new_ui(const game_state *state)
2207 reset_ui(ui); 2210 reset_ui(ui);
2208 ui->erasing = false; 2211 ui->erasing = false;
2209 ui->cur_x = ui->cur_y = 0; 2212 ui->cur_x = ui->cur_y = 0;
2210 ui->cur_visible = false; 2213 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
2211 ui->cur_dragging = false; 2214 ui->cur_dragging = false;
2212 return ui; 2215 return ui;
2213} 2216}
@@ -2217,15 +2220,6 @@ static void free_ui(game_ui *ui)
2217 sfree(ui); 2220 sfree(ui);
2218} 2221}
2219 2222
2220static char *encode_ui(const game_ui *ui)
2221{
2222 return NULL;
2223}
2224
2225static void decode_ui(game_ui *ui, const char *encoding)
2226{
2227}
2228
2229static void coord_round(float x, float y, int *xr, int *yr) 2223static void coord_round(float x, float y, int *xr, int *yr)
2230{ 2224{
2231 float xs, ys, xv, yv, dx, dy, dist; 2225 float xs, ys, xv, yv, dx, dy, dist;
@@ -2377,6 +2371,21 @@ struct game_drawstate {
2377 unsigned long *visible; 2371 unsigned long *visible;
2378}; 2372};
2379 2373
2374static const char *current_key_label(const game_ui *ui,
2375 const game_state *state, int button)
2376{
2377 if (IS_CURSOR_SELECT(button) && ui->cur_visible &&
2378 !(ui->drag_start_x >= 0 && !ui->cur_dragging)) {
2379 if (ui->cur_dragging) {
2380 if (!ui->dragged) return "Cancel";
2381 if ((button == CURSOR_SELECT2) == ui->erasing) return "Done";
2382 return "Cancel";
2383 }
2384 return button == CURSOR_SELECT ? "Mark" : "Erase";
2385 }
2386 return "";
2387}
2388
2380static char *interpret_move(const game_state *from, game_ui *ui, 2389static char *interpret_move(const game_state *from, game_ui *ui,
2381 const game_drawstate *ds, 2390 const game_drawstate *ds,
2382 int x, int y, int button) 2391 int x, int y, int button)
@@ -2385,7 +2394,7 @@ static char *interpret_move(const game_state *from, game_ui *ui,
2385 bool startdrag = false, enddrag = false, active = false, erasing = false; 2394 bool startdrag = false, enddrag = false, active = false, erasing = false;
2386 char buf[80], *ret; 2395 char buf[80], *ret;
2387 2396
2388 button &= ~MOD_MASK; 2397 button = STRIP_BUTTON_MODIFIERS(button);
2389 2398
2390 coord_round(FROMCOORD((float)x), FROMCOORD((float)y), &xc, &yc); 2399 coord_round(FROMCOORD((float)x), FROMCOORD((float)y), &xc, &yc);
2391 2400
@@ -2406,10 +2415,11 @@ static char *interpret_move(const game_state *from, game_ui *ui,
2406 enddrag = true; 2415 enddrag = true;
2407 erasing = (button == RIGHT_RELEASE); 2416 erasing = (button == RIGHT_RELEASE);
2408 } else if (IS_CURSOR_MOVE(button)) { 2417 } else if (IS_CURSOR_MOVE(button)) {
2409 move_cursor(button, &ui->cur_x, &ui->cur_y, from->w, from->h, false); 2418 char *ret;
2410 ui->cur_visible = true; 2419 ret = move_cursor(button, &ui->cur_x, &ui->cur_y, from->w, from->h,
2420 false, &ui->cur_visible);
2411 active = true; 2421 active = true;
2412 if (!ui->cur_dragging) return UI_UPDATE; 2422 if (!ui->cur_dragging || ret != MOVE_UI_UPDATE) return ret;
2413 coord_round((float)ui->cur_x + 0.5F, (float)ui->cur_y + 0.5F, &xc, &yc); 2423 coord_round((float)ui->cur_x + 0.5F, (float)ui->cur_y + 0.5F, &xc, &yc);
2414 } else if (IS_CURSOR_SELECT(button)) { 2424 } else if (IS_CURSOR_SELECT(button)) {
2415 if (ui->drag_start_x >= 0 && !ui->cur_dragging) { 2425 if (ui->drag_start_x >= 0 && !ui->cur_dragging) {
@@ -2422,7 +2432,7 @@ static char *interpret_move(const game_state *from, game_ui *ui,
2422 if (!ui->cur_visible) { 2432 if (!ui->cur_visible) {
2423 assert(!ui->cur_dragging); 2433 assert(!ui->cur_dragging);
2424 ui->cur_visible = true; 2434 ui->cur_visible = true;
2425 return UI_UPDATE; 2435 return MOVE_UI_UPDATE;
2426 } 2436 }
2427 coord_round((float)ui->cur_x + 0.5F, (float)ui->cur_y + 0.5F, &xc, &yc); 2437 coord_round((float)ui->cur_x + 0.5F, (float)ui->cur_y + 0.5F, &xc, &yc);
2428 erasing = (button == CURSOR_SELECT2); 2438 erasing = (button == CURSOR_SELECT2);
@@ -2443,7 +2453,7 @@ static char *interpret_move(const game_state *from, game_ui *ui,
2443 reset_ui(ui); /* cancel keyboard dragging */ 2453 reset_ui(ui); /* cancel keyboard dragging */
2444 ui->cur_dragging = false; 2454 ui->cur_dragging = false;
2445 } 2455 }
2446 return UI_UPDATE; 2456 return MOVE_UI_UPDATE;
2447 } else if (button != LEFT_DRAG && button != RIGHT_DRAG) { 2457 } else if (button != LEFT_DRAG && button != RIGHT_DRAG) {
2448 return NULL; 2458 return NULL;
2449 } 2459 }
@@ -2527,7 +2537,7 @@ static char *interpret_move(const game_state *from, game_ui *ui,
2527 if (ret) 2537 if (ret)
2528 return ret; /* a move has been made */ 2538 return ret; /* a move has been made */
2529 else if (active) 2539 else if (active)
2530 return UI_UPDATE; 2540 return MOVE_UI_UPDATE;
2531 else 2541 else
2532 return NULL; 2542 return NULL;
2533} 2543}
@@ -2621,7 +2631,7 @@ static game_state *execute_move(const game_state *from, const char *move)
2621#define MAX4(x,y,z,w) ( max(max(x,y),max(z,w)) ) 2631#define MAX4(x,y,z,w) ( max(max(x,y),max(z,w)) )
2622 2632
2623static void game_compute_size(const game_params *params, int tilesize, 2633static void game_compute_size(const game_params *params, int tilesize,
2624 int *x, int *y) 2634 const game_ui *ui, int *x, int *y)
2625{ 2635{
2626 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2636 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2627 struct { int tilesize; } ads, *ds = &ads; 2637 struct { int tilesize; } ads, *ds = &ads;
@@ -2796,9 +2806,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2796 } 2806 }
2797 2807
2798 if (!ds->started) { 2808 if (!ds->started) {
2799 draw_rect(dr, 0, 0,
2800 state->w * TILE_SIZE + 2*BORDER + 1,
2801 state->h * TILE_SIZE + 2*BORDER + 1, COL_BACKGROUND);
2802 draw_rect(dr, COORD(0)-1, COORD(0)-1, 2809 draw_rect(dr, COORD(0)-1, COORD(0)-1,
2803 ds->w*TILE_SIZE+3, ds->h*TILE_SIZE+3, COL_LINE); 2810 ds->w*TILE_SIZE+3, ds->h*TILE_SIZE+3, COL_LINE);
2804 ds->started = true; 2811 ds->started = true;
@@ -2901,24 +2908,21 @@ static int game_status(const game_state *state)
2901 return state->completed ? +1 : 0; 2908 return state->completed ? +1 : 0;
2902} 2909}
2903 2910
2904static bool game_timing_state(const game_state *state, game_ui *ui) 2911static void game_print_size(const game_params *params, const game_ui *ui,
2905{ 2912 float *x, float *y)
2906 return true;
2907}
2908
2909static void game_print_size(const game_params *params, float *x, float *y)
2910{ 2913{
2911 int pw, ph; 2914 int pw, ph;
2912 2915
2913 /* 2916 /*
2914 * I'll use 5mm squares by default. 2917 * I'll use 5mm squares by default.
2915 */ 2918 */
2916 game_compute_size(params, 500, &pw, &ph); 2919 game_compute_size(params, 500, ui, &pw, &ph);
2917 *x = pw / 100.0F; 2920 *x = pw / 100.0F;
2918 *y = ph / 100.0F; 2921 *y = ph / 100.0F;
2919} 2922}
2920 2923
2921static void game_print(drawing *dr, const game_state *state, int tilesize) 2924static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2925 int tilesize)
2922{ 2926{
2923 int w = state->w, h = state->h; 2927 int w = state->w, h = state->h;
2924 int ink = print_mono_colour(dr, 0); 2928 int ink = print_mono_colour(dr, 0);
@@ -2992,12 +2996,14 @@ const struct game thegame = {
2992 free_game, 2996 free_game,
2993 true, solve_game, 2997 true, solve_game,
2994 true, game_can_format_as_text_now, game_text_format, 2998 true, game_can_format_as_text_now, game_text_format,
2999 NULL, NULL, /* get_prefs, set_prefs */
2995 new_ui, 3000 new_ui,
2996 free_ui, 3001 free_ui,
2997 encode_ui, 3002 NULL, /* encode_ui */
2998 decode_ui, 3003 NULL, /* decode_ui */
2999 NULL, /* game_request_keys */ 3004 NULL, /* game_request_keys */
3000 game_changed_state, 3005 game_changed_state,
3006 current_key_label,
3001 interpret_move, 3007 interpret_move,
3002 execute_move, 3008 execute_move,
3003 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 3009 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -3011,7 +3017,7 @@ const struct game thegame = {
3011 game_status, 3017 game_status,
3012 true, false, game_print_size, game_print, 3018 true, false, game_print_size, game_print,
3013 true, /* wants_statusbar */ 3019 true, /* wants_statusbar */
3014 false, game_timing_state, 3020 false, NULL, /* timing_state */
3015 0, /* flags */ 3021 0, /* flags */
3016}; 3022};
3017 3023
diff --git a/apps/plugins/puzzles/src/resource.h b/apps/plugins/puzzles/src/resource.h
deleted file mode 100644
index f0bfa16d6d..0000000000
--- a/apps/plugins/puzzles/src/resource.h
+++ /dev/null
@@ -1,20 +0,0 @@
1
2#define IDR_MENUBAR1 101
3
4#define ID_GAME 40005
5#define ID_TYPE 40006
6
7#define IDS_CAP_GAME 40105
8#define IDS_CAP_TYPE 40106
9
10#define IDD_ABOUT 2000
11#define IDC_ABOUT_CAPTION 2001
12#define IDC_ABOUT_LINE 2002
13#define IDC_ABOUT_GAME 2003
14#define IDC_ABOUT_VERSION 2004
15
16#define IDD_CONFIG 2100
17#define IDC_CONFIG_CAPTION 2101
18#define IDC_CONFIG_LINE 2102
19
20#define IDR_PADTOOLBAR 4000
diff --git a/apps/plugins/puzzles/src/samegame.R b/apps/plugins/puzzles/src/samegame.R
deleted file mode 100644
index cc0d350041..0000000000
--- a/apps/plugins/puzzles/src/samegame.R
+++ /dev/null
@@ -1,19 +0,0 @@
1# -*- makefile -*-
2
3samegame : [X] GTK COMMON samegame samegame-icon|no-icon
4
5samegame : [G] WINDOWS COMMON samegame samegame.res|noicon.res
6
7ALL += samegame[COMBINED]
8
9!begin am gtk
10GAMES += samegame
11!end
12
13!begin >list.c
14 A(samegame) \
15!end
16
17!begin >gamedesc.txt
18samegame:samegame.exe:Same Game:Block-clearing puzzle:Clear the grid by removing touching groups of the same colour squares.
19!end
diff --git a/apps/plugins/puzzles/src/samegame.c b/apps/plugins/puzzles/src/samegame.c
index 615c60e0a5..30550e1f1c 100644
--- a/apps/plugins/puzzles/src/samegame.c
+++ b/apps/plugins/puzzles/src/samegame.c
@@ -67,7 +67,12 @@
67#include <string.h> 67#include <string.h>
68#include <assert.h> 68#include <assert.h>
69#include <ctype.h> 69#include <ctype.h>
70#include <math.h> 70#include <limits.h>
71#ifdef NO_TGMATH_H
72# include <math.h>
73#else
74# include <tgmath.h>
75#endif
71 76
72#include "puzzles.h" 77#include "puzzles.h"
73 78
@@ -285,6 +290,8 @@ static const char *validate_params(const game_params *params, bool full)
285{ 290{
286 if (params->w < 1 || params->h < 1) 291 if (params->w < 1 || params->h < 1)
287 return "Width and height must both be positive"; 292 return "Width and height must both be positive";
293 if (params->w > INT_MAX / params->h)
294 return "Width times height must not be unreasonably large";
288 295
289 if (params->ncols > 9) 296 if (params->ncols > 9)
290 return "Maximum of 9 colours"; 297 return "Maximum of 9 colours";
@@ -858,6 +865,8 @@ static void gen_grid(int w, int h, int nc, int *grid, random_state *rs)
858 865
859#if defined GENERATION_DIAGNOSTICS || defined COUNT_FAILURES 866#if defined GENERATION_DIAGNOSTICS || defined COUNT_FAILURES
860 printf("%d failures\n", failures); 867 printf("%d failures\n", failures);
868#else
869 (void)failures;
861#endif 870#endif
862#ifdef GENERATION_DIAGNOSTICS 871#ifdef GENERATION_DIAGNOSTICS
863 { 872 {
@@ -1013,12 +1022,6 @@ static void free_game(game_state *state)
1013 sfree(state); 1022 sfree(state);
1014} 1023}
1015 1024
1016static char *solve_game(const game_state *state, const game_state *currstate,
1017 const char *aux, const char **error)
1018{
1019 return NULL;
1020}
1021
1022static bool game_can_format_as_text_now(const game_params *params) 1025static bool game_can_format_as_text_now(const game_params *params)
1023{ 1026{
1024 return true; 1027 return true;
@@ -1065,7 +1068,7 @@ static game_ui *new_ui(const game_state *state)
1065 ui->nselected = 0; 1068 ui->nselected = 0;
1066 1069
1067 ui->xsel = ui->ysel = 0; 1070 ui->xsel = ui->ysel = 0;
1068 ui->displaysel = false; 1071 ui->displaysel = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1069 1072
1070 return ui; 1073 return ui;
1071} 1074}
@@ -1076,15 +1079,6 @@ static void free_ui(game_ui *ui)
1076 sfree(ui); 1079 sfree(ui);
1077} 1080}
1078 1081
1079static char *encode_ui(const game_ui *ui)
1080{
1081 return NULL;
1082}
1083
1084static void decode_ui(game_ui *ui, const char *encoding)
1085{
1086}
1087
1088static void sel_clear(game_ui *ui, const game_state *state) 1082static void sel_clear(game_ui *ui, const game_state *state)
1089{ 1083{
1090 int i; 1084 int i;
@@ -1099,14 +1093,25 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1099 const game_state *newstate) 1093 const game_state *newstate)
1100{ 1094{
1101 sel_clear(ui, newstate); 1095 sel_clear(ui, newstate);
1096}
1102 1097
1103 /* 1098static const char *current_key_label(const game_ui *ui,
1104 * If the game state has just changed into an unplayable one 1099 const game_state *state, int button)
1105 * (either completed or impossible), we vanish the keyboard- 1100{
1106 * control cursor. 1101 if (IS_CURSOR_SELECT(button)) {
1107 */ 1102 int x = ui->xsel, y = ui->ysel, c = COL(state,x,y);
1108 if (newstate->complete || newstate->impossible) 1103 if (c == 0) return "";
1109 ui->displaysel = false; 1104 if (ISSEL(ui, x, y))
1105 return button == CURSOR_SELECT2 ? "Unselect" : "Remove";
1106 if ((x > 0 && COL(state,x-1,y) == c) ||
1107 (x+1 < state->params.w && COL(state,x+1,y) == c) ||
1108 (y > 0 && COL(state,x,y-1) == c) ||
1109 (y+1 < state->params.h && COL(state,x,y+1) == c))
1110 return "Select";
1111 /* Cursor is over a lone square, so we can't select it. */
1112 if (ui->nselected) return "Unselect";
1113 }
1114 return "";
1110} 1115}
1111 1116
1112static char *sel_movedesc(game_ui *ui, const game_state *state) 1117static char *sel_movedesc(game_ui *ui, const game_state *state)
@@ -1274,30 +1279,25 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1274 int x, int y, int button) 1279 int x, int y, int button)
1275{ 1280{
1276 int tx, ty; 1281 int tx, ty;
1277 char *ret = UI_UPDATE; 1282 char *ret = MOVE_UI_UPDATE;
1278
1279 ui->displaysel = false;
1280 1283
1281 if (button == RIGHT_BUTTON || button == LEFT_BUTTON) { 1284 if (button == RIGHT_BUTTON || button == LEFT_BUTTON) {
1285 ui->displaysel = false;
1282 tx = FROMCOORD(x); ty= FROMCOORD(y); 1286 tx = FROMCOORD(x); ty= FROMCOORD(y);
1283 } else if (IS_CURSOR_MOVE(button)) { 1287 } else if (IS_CURSOR_MOVE(button)) {
1284 int dx = 0, dy = 0; 1288 return move_cursor(button, &ui->xsel, &ui->ysel,
1285 ui->displaysel = true; 1289 state->params.w, state->params.h,
1286 dx = (button == CURSOR_LEFT) ? -1 : ((button == CURSOR_RIGHT) ? +1 : 0); 1290 true, &ui->displaysel);
1287 dy = (button == CURSOR_DOWN) ? +1 : ((button == CURSOR_UP) ? -1 : 0);
1288 ui->xsel = (ui->xsel + state->params.w + dx) % state->params.w;
1289 ui->ysel = (ui->ysel + state->params.h + dy) % state->params.h;
1290 return ret;
1291 } else if (IS_CURSOR_SELECT(button)) { 1291 } else if (IS_CURSOR_SELECT(button)) {
1292 ui->displaysel = true; 1292 ui->displaysel = true;
1293 tx = ui->xsel; 1293 tx = ui->xsel;
1294 ty = ui->ysel; 1294 ty = ui->ysel;
1295 } else 1295 } else
1296 return NULL; 1296 return MOVE_UNUSED;
1297 1297
1298 if (tx < 0 || tx >= state->params.w || ty < 0 || ty >= state->params.h) 1298 if (tx < 0 || tx >= state->params.w || ty < 0 || ty >= state->params.h)
1299 return NULL; 1299 return MOVE_UNUSED;
1300 if (COL(state, tx, ty) == 0) return NULL; 1300 if (COL(state, tx, ty) == 0) return MOVE_NO_EFFECT;
1301 1301
1302 if (ISSEL(ui,tx,ty)) { 1302 if (ISSEL(ui,tx,ty)) {
1303 if (button == RIGHT_BUTTON || button == CURSOR_SELECT2) 1303 if (button == RIGHT_BUTTON || button == CURSOR_SELECT2)
@@ -1324,6 +1324,10 @@ static game_state *execute_move(const game_state *from, const char *move)
1324 move++; 1324 move++;
1325 1325
1326 while (*move) { 1326 while (*move) {
1327 if (!isdigit((unsigned char)*move)) {
1328 free_game(ret);
1329 return NULL;
1330 }
1327 i = atoi(move); 1331 i = atoi(move);
1328 if (i < 0 || i >= ret->n) { 1332 if (i < 0 || i >= ret->n) {
1329 free_game(ret); 1333 free_game(ret);
@@ -1353,12 +1357,12 @@ static game_state *execute_move(const game_state *from, const char *move)
1353static void game_set_size(drawing *dr, game_drawstate *ds, 1357static void game_set_size(drawing *dr, game_drawstate *ds,
1354 const game_params *params, int tilesize) 1358 const game_params *params, int tilesize)
1355{ 1359{
1356 ds->tilegap = 2; 1360 ds->tilegap = (tilesize + 8) / 16;
1357 ds->tileinner = tilesize - ds->tilegap; 1361 ds->tileinner = tilesize - ds->tilegap;
1358} 1362}
1359 1363
1360static void game_compute_size(const game_params *params, int tilesize, 1364static void game_compute_size(const game_params *params, int tilesize,
1361 int *x, int *y) 1365 const game_ui *ui, int *x, int *y)
1362{ 1366{
1363 /* Ick: fake up tile size variables for macro expansion purposes */ 1367 /* Ick: fake up tile size variables for macro expansion purposes */
1364 game_drawstate ads, *ds = &ads; 1368 game_drawstate ads, *ds = &ads;
@@ -1372,7 +1376,7 @@ static float *game_colours(frontend *fe, int *ncolours)
1372{ 1376{
1373 float *ret = snewn(3 * NCOLOURS, float); 1377 float *ret = snewn(3 * NCOLOURS, float);
1374 1378
1375 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); 1379 game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT);
1376 1380
1377 ret[COL_1 * 3 + 0] = 0.0F; 1381 ret[COL_1 * 3 + 0] = 0.0F;
1378 ret[COL_1 * 3 + 1] = 0.0F; 1382 ret[COL_1 * 3 + 1] = 0.0F;
@@ -1386,8 +1390,8 @@ static float *game_colours(frontend *fe, int *ncolours)
1386 ret[COL_3 * 3 + 1] = 0.0F; 1390 ret[COL_3 * 3 + 1] = 0.0F;
1387 ret[COL_3 * 3 + 2] = 0.0F; 1391 ret[COL_3 * 3 + 2] = 0.0F;
1388 1392
1389 ret[COL_4 * 3 + 0] = 1.0F; 1393 ret[COL_4 * 3 + 0] = 0.7F;
1390 ret[COL_4 * 3 + 1] = 1.0F; 1394 ret[COL_4 * 3 + 1] = 0.7F;
1391 ret[COL_4 * 3 + 2] = 0.0F; 1395 ret[COL_4 * 3 + 2] = 0.0F;
1392 1396
1393 ret[COL_5 * 3 + 0] = 1.0F; 1397 ret[COL_5 * 3 + 0] = 1.0F;
@@ -1395,16 +1399,16 @@ static float *game_colours(frontend *fe, int *ncolours)
1395 ret[COL_5 * 3 + 2] = 1.0F; 1399 ret[COL_5 * 3 + 2] = 1.0F;
1396 1400
1397 ret[COL_6 * 3 + 0] = 0.0F; 1401 ret[COL_6 * 3 + 0] = 0.0F;
1398 ret[COL_6 * 3 + 1] = 1.0F; 1402 ret[COL_6 * 3 + 1] = 0.8F;
1399 ret[COL_6 * 3 + 2] = 1.0F; 1403 ret[COL_6 * 3 + 2] = 0.8F;
1400 1404
1401 ret[COL_7 * 3 + 0] = 0.5F; 1405 ret[COL_7 * 3 + 0] = 0.5F;
1402 ret[COL_7 * 3 + 1] = 0.5F; 1406 ret[COL_7 * 3 + 1] = 0.5F;
1403 ret[COL_7 * 3 + 2] = 1.0F; 1407 ret[COL_7 * 3 + 2] = 1.0F;
1404 1408
1405 ret[COL_8 * 3 + 0] = 0.5F; 1409 ret[COL_8 * 3 + 0] = 0.2F;
1406 ret[COL_8 * 3 + 1] = 1.0F; 1410 ret[COL_8 * 3 + 1] = 0.8F;
1407 ret[COL_8 * 3 + 2] = 0.5F; 1411 ret[COL_8 * 3 + 2] = 0.2F;
1408 1412
1409 ret[COL_9 * 3 + 0] = 1.0F; 1413 ret[COL_9 * 3 + 0] = 1.0F;
1410 ret[COL_9 * 3 + 1] = 0.5F; 1414 ret[COL_9 * 3 + 1] = 0.5F;
@@ -1418,14 +1422,6 @@ static float *game_colours(frontend *fe, int *ncolours)
1418 ret[COL_SEL * 3 + 1] = 1.0F; 1422 ret[COL_SEL * 3 + 1] = 1.0F;
1419 ret[COL_SEL * 3 + 2] = 1.0F; 1423 ret[COL_SEL * 3 + 2] = 1.0F;
1420 1424
1421 ret[COL_HIGHLIGHT * 3 + 0] = 1.0F;
1422 ret[COL_HIGHLIGHT * 3 + 1] = 1.0F;
1423 ret[COL_HIGHLIGHT * 3 + 2] = 1.0F;
1424
1425 ret[COL_LOWLIGHT * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 2.0F / 3.0F;
1426 ret[COL_LOWLIGHT * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2.0F / 3.0F;
1427 ret[COL_LOWLIGHT * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2.0F / 3.0F;
1428
1429 *ncolours = NCOLOURS; 1425 *ncolours = NCOLOURS;
1430 return ret; 1426 return ret;
1431} 1427}
@@ -1462,6 +1458,7 @@ static void tile_redraw(drawing *dr, game_drawstate *ds,
1462 int tile, int bgcolour) 1458 int tile, int bgcolour)
1463{ 1459{
1464 int outer = bgcolour, inner = outer, col = tile & TILE_COLMASK; 1460 int outer = bgcolour, inner = outer, col = tile & TILE_COLMASK;
1461 int tile_w, tile_h, outer_w, outer_h;
1465 1462
1466 if (col) { 1463 if (col) {
1467 if (tile & TILE_IMPOSSIBLE) { 1464 if (tile & TILE_IMPOSSIBLE) {
@@ -1474,19 +1471,25 @@ static void tile_redraw(drawing *dr, game_drawstate *ds,
1474 outer = inner = col; 1471 outer = inner = col;
1475 } 1472 }
1476 } 1473 }
1477 draw_rect(dr, COORD(x), COORD(y), TILE_INNER, TILE_INNER, outer); 1474 tile_w = dright ? TILE_SIZE : TILE_INNER;
1478 draw_rect(dr, COORD(x)+TILE_INNER/4, COORD(y)+TILE_INNER/4, 1475 tile_h = dbelow ? TILE_SIZE : TILE_INNER;
1479 TILE_INNER/2, TILE_INNER/2, inner); 1476 outer_w = (tile & TILE_JOINRIGHT) ? tile_w : TILE_INNER;
1480 1477 outer_h = (tile & TILE_JOINDOWN) ? tile_h : TILE_INNER;
1481 if (dright) 1478 /* Draw the background if any of it will be visible. */
1482 draw_rect(dr, COORD(x)+TILE_INNER, COORD(y), TILE_GAP, TILE_INNER, 1479 if (outer_w != tile_w || outer_h != tile_h || outer == bgcolour)
1483 (tile & TILE_JOINRIGHT) ? outer : bgcolour); 1480 draw_rect(dr, COORD(x), COORD(y), tile_w, tile_h, bgcolour);
1484 if (dbelow) 1481 /* Draw the piece. */
1485 draw_rect(dr, COORD(x), COORD(y)+TILE_INNER, TILE_INNER, TILE_GAP, 1482 if (outer != bgcolour)
1486 (tile & TILE_JOINDOWN) ? outer : bgcolour); 1483 draw_rect(dr, COORD(x), COORD(y), outer_w, outer_h, outer);
1487 if (dright && dbelow) 1484 if (inner != outer)
1488 draw_rect(dr, COORD(x)+TILE_INNER, COORD(y)+TILE_INNER, TILE_GAP, TILE_GAP, 1485 draw_rect(dr, COORD(x)+TILE_INNER/4, COORD(y)+TILE_INNER/4,
1489 (tile & TILE_JOINDIAG) ? outer : bgcolour); 1486 TILE_INNER/2, TILE_INNER/2, inner);
1487 /* Reset bottom-right corner if necessary. */
1488 if ((tile & (TILE_JOINRIGHT | TILE_JOINDOWN | TILE_JOINDIAG)) ==
1489 (TILE_JOINRIGHT | TILE_JOINDOWN) && outer != bgcolour &&
1490 TILE_GAP != 0)
1491 draw_rect(dr, COORD(x)+TILE_INNER, COORD(y)+TILE_INNER,
1492 TILE_GAP, TILE_GAP, bgcolour);
1490 1493
1491 if (tile & TILE_HASSEL) { 1494 if (tile & TILE_HASSEL) {
1492 int sx = COORD(x)+2, sy = COORD(y)+2, ssz = TILE_INNER-5; 1495 int sx = COORD(x)+2, sy = COORD(y)+2, ssz = TILE_INNER-5;
@@ -1512,13 +1515,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1512 if (!ds->started) { 1515 if (!ds->started) {
1513 int coords[10]; 1516 int coords[10];
1514 1517
1515 draw_rect(dr, 0, 0,
1516 TILE_SIZE * state->params.w + 2 * BORDER,
1517 TILE_SIZE * state->params.h + 2 * BORDER, COL_BACKGROUND);
1518 draw_update(dr, 0, 0,
1519 TILE_SIZE * state->params.w + 2 * BORDER,
1520 TILE_SIZE * state->params.h + 2 * BORDER);
1521
1522 /* 1518 /*
1523 * Recessed area containing the whole puzzle. 1519 * Recessed area containing the whole puzzle.
1524 */ 1520 */
@@ -1541,7 +1537,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1541 ds->started = true; 1537 ds->started = true;
1542 } 1538 }
1543 1539
1544 if (flashtime > 0.0) { 1540 if (flashtime > 0.0F) {
1545 int frame = (int)(flashtime / FLASH_FRAME); 1541 int frame = (int)(flashtime / FLASH_FRAME);
1546 bgcolour = (frame % 2 ? COL_LOWLIGHT : COL_HIGHLIGHT); 1542 bgcolour = (frame % 2 ? COL_LOWLIGHT : COL_HIGHLIGHT);
1547 } else 1543 } else
@@ -1564,8 +1560,13 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1564 if ((tile & TILE_JOINRIGHT) && (tile & TILE_JOINDOWN) && 1560 if ((tile & TILE_JOINRIGHT) && (tile & TILE_JOINDOWN) &&
1565 COL(state,x+1,y+1) == col) 1561 COL(state,x+1,y+1) == col)
1566 tile |= TILE_JOINDIAG; 1562 tile |= TILE_JOINDIAG;
1567 1563 /*
1568 if (ui->displaysel && ui->xsel == x && ui->ysel == y) 1564 * If the game state is an unplayable one (either
1565 * completed or impossible), we hide the keyboard-control
1566 * cursor.
1567 */
1568 if (ui->displaysel && ui->xsel == x && ui->ysel == y &&
1569 !(state->complete || state->impossible))
1569 tile |= TILE_HASSEL; 1570 tile |= TILE_HASSEL;
1570 1571
1571 /* For now we're never expecting oldstate at all (because we have 1572 /* For now we're never expecting oldstate at all (because we have
@@ -1637,19 +1638,6 @@ static int game_status(const game_state *state)
1637 return state->complete ? +1 : 0; 1638 return state->complete ? +1 : 0;
1638} 1639}
1639 1640
1640static bool game_timing_state(const game_state *state, game_ui *ui)
1641{
1642 return true;
1643}
1644
1645static void game_print_size(const game_params *params, float *x, float *y)
1646{
1647}
1648
1649static void game_print(drawing *dr, const game_state *state, int tilesize)
1650{
1651}
1652
1653#ifdef COMBINED 1641#ifdef COMBINED
1654#define thegame samegame 1642#define thegame samegame
1655#endif 1643#endif
@@ -1669,14 +1657,16 @@ const struct game thegame = {
1669 new_game, 1657 new_game,
1670 dup_game, 1658 dup_game,
1671 free_game, 1659 free_game,
1672 false, solve_game, 1660 false, NULL, /* solve */
1673 true, game_can_format_as_text_now, game_text_format, 1661 true, game_can_format_as_text_now, game_text_format,
1662 NULL, NULL, /* get_prefs, set_prefs */
1674 new_ui, 1663 new_ui,
1675 free_ui, 1664 free_ui,
1676 encode_ui, 1665 NULL, /* encode_ui */
1677 decode_ui, 1666 NULL, /* decode_ui */
1678 NULL, /* game_request_keys */ 1667 NULL, /* game_request_keys */
1679 game_changed_state, 1668 game_changed_state,
1669 current_key_label,
1680 interpret_move, 1670 interpret_move,
1681 execute_move, 1671 execute_move,
1682 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 1672 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -1688,8 +1678,8 @@ const struct game thegame = {
1688 game_flash_length, 1678 game_flash_length,
1689 game_get_cursor_location, 1679 game_get_cursor_location,
1690 game_status, 1680 game_status,
1691 false, false, game_print_size, game_print, 1681 false, false, NULL, NULL, /* print_size, print */
1692 true, /* wants_statusbar */ 1682 true, /* wants_statusbar */
1693 false, game_timing_state, 1683 false, NULL, /* timing_state */
1694 0, /* flags */ 1684 0, /* flags */
1695}; 1685};
diff --git a/apps/plugins/puzzles/src/signpost.R b/apps/plugins/puzzles/src/signpost.R
deleted file mode 100644
index 09ea367d57..0000000000
--- a/apps/plugins/puzzles/src/signpost.R
+++ /dev/null
@@ -1,23 +0,0 @@
1# -*- makefile -*-
2
3SIGNPOST_EXTRA = dsf
4
5signpost : [X] GTK COMMON signpost SIGNPOST_EXTRA signpost-icon|no-icon
6signpost : [G] WINDOWS COMMON signpost SIGNPOST_EXTRA signpost.res|noicon.res
7
8signpostsolver : [U] signpost[STANDALONE_SOLVER] SIGNPOST_EXTRA STANDALONE m.lib
9signpostsolver : [C] signpost[STANDALONE_SOLVER] SIGNPOST_EXTRA STANDALONE
10
11ALL += signpost[COMBINED] SIGNPOST_EXTRA
12
13!begin am gtk
14GAMES += signpost
15!end
16
17!begin >list.c
18 A(signpost) \
19!end
20
21!begin >gamedesc.txt
22signpost:signpost.exe:Signpost:Square-connecting puzzle:Connect the squares into a path following the arrows.
23!end
diff --git a/apps/plugins/puzzles/src/signpost.c b/apps/plugins/puzzles/src/signpost.c
index 9aee255ebe..9aed67bb4a 100644
--- a/apps/plugins/puzzles/src/signpost.c
+++ b/apps/plugins/puzzles/src/signpost.c
@@ -7,7 +7,12 @@
7#include <string.h> 7#include <string.h>
8#include <assert.h> 8#include <assert.h>
9#include <ctype.h> 9#include <ctype.h>
10#include <math.h> 10#include <limits.h>
11#ifdef NO_TGMATH_H
12# include <math.h>
13#else
14# include <tgmath.h>
15#endif
11 16
12#include "puzzles.h" 17#include "puzzles.h"
13 18
@@ -57,7 +62,7 @@ struct game_state {
57 int *nums; /* numbers, size n */ 62 int *nums; /* numbers, size n */
58 unsigned int *flags; /* flags, size n */ 63 unsigned int *flags; /* flags, size n */
59 int *next, *prev; /* links to other cell indexes, size n (-1 absent) */ 64 int *next, *prev; /* links to other cell indexes, size n (-1 absent) */
60 int *dsf; /* connects regions with a dsf. */ 65 DSF *dsf; /* connects regions with a dsf. */
61 int *numsi; /* for each number, which index is it in? (-1 absent) */ 66 int *numsi; /* for each number, which index is it in? (-1 absent) */
62}; 67};
63 68
@@ -168,7 +173,7 @@ static bool isvalidmove(const game_state *state, bool clever,
168 173
169 /* can't create a new connection between cells in the same region 174 /* can't create a new connection between cells in the same region
170 * as that would create a loop. */ 175 * as that would create a loop. */
171 if (dsf_canonify(state->dsf, from) == dsf_canonify(state->dsf, to)) 176 if (dsf_equivalent(state->dsf, from, to))
172 return false; 177 return false;
173 178
174 /* if both cells are actual numbers, can't drag if we're not 179 /* if both cells are actual numbers, can't drag if we're not
@@ -277,7 +282,7 @@ static void strip_nums(game_state *state) {
277 memset(state->next, -1, state->n*sizeof(int)); 282 memset(state->next, -1, state->n*sizeof(int));
278 memset(state->prev, -1, state->n*sizeof(int)); 283 memset(state->prev, -1, state->n*sizeof(int));
279 memset(state->numsi, -1, (state->n+1)*sizeof(int)); 284 memset(state->numsi, -1, (state->n+1)*sizeof(int));
280 dsf_init(state->dsf, state->n); 285 dsf_reinit(state->dsf);
281} 286}
282 287
283static bool check_nums(game_state *orig, game_state *copy, bool only_immutable) 288static bool check_nums(game_state *orig, game_state *copy, bool only_immutable)
@@ -421,6 +426,8 @@ static const char *validate_params(const game_params *params, bool full)
421{ 426{
422 if (params->w < 1) return "Width must be at least one"; 427 if (params->w < 1) return "Width must be at least one";
423 if (params->h < 1) return "Height must be at least one"; 428 if (params->h < 1) return "Height must be at least one";
429 if (params->w > INT_MAX / params->h)
430 return "Width times height must not be unreasonably large";
424 if (full && params->w == 1 && params->h == 1) 431 if (full && params->w == 1 && params->h == 1)
425 /* The UI doesn't let us move these from unsolved to solved, 432 /* The UI doesn't let us move these from unsolved to solved,
426 * so we disallow generating (but not playing) them. */ 433 * so we disallow generating (but not playing) them. */
@@ -454,7 +461,7 @@ static game_state *blank_game(int w, int h)
454 state->flags = snewn(state->n, unsigned int); 461 state->flags = snewn(state->n, unsigned int);
455 state->next = snewn(state->n, int); 462 state->next = snewn(state->n, int);
456 state->prev = snewn(state->n, int); 463 state->prev = snewn(state->n, int);
457 state->dsf = snew_dsf(state->n); 464 state->dsf = dsf_new(state->n);
458 state->numsi = snewn(state->n+1, int); 465 state->numsi = snewn(state->n+1, int);
459 466
460 blank_game_into(state); 467 blank_game_into(state);
@@ -475,7 +482,7 @@ static void dup_game_to(game_state *to, const game_state *from)
475 memcpy(to->next, from->next, to->n*sizeof(int)); 482 memcpy(to->next, from->next, to->n*sizeof(int));
476 memcpy(to->prev, from->prev, to->n*sizeof(int)); 483 memcpy(to->prev, from->prev, to->n*sizeof(int));
477 484
478 memcpy(to->dsf, from->dsf, to->n*sizeof(int)); 485 dsf_copy(to->dsf, from->dsf);
479 memcpy(to->numsi, from->numsi, (to->n+1)*sizeof(int)); 486 memcpy(to->numsi, from->numsi, (to->n+1)*sizeof(int));
480} 487}
481 488
@@ -493,7 +500,7 @@ static void free_game(game_state *state)
493 sfree(state->flags); 500 sfree(state->flags);
494 sfree(state->next); 501 sfree(state->next);
495 sfree(state->prev); 502 sfree(state->prev);
496 sfree(state->dsf); 503 dsf_free(state->dsf);
497 sfree(state->numsi); 504 sfree(state->numsi);
498 sfree(state); 505 sfree(state);
499} 506}
@@ -1011,7 +1018,7 @@ static void connect_numbers(game_state *state)
1011{ 1018{
1012 int i, di, dni; 1019 int i, di, dni;
1013 1020
1014 dsf_init(state->dsf, state->n); 1021 dsf_reinit(state->dsf);
1015 for (i = 0; i < state->n; i++) { 1022 for (i = 0; i < state->n; i++) {
1016 if (state->next[i] != -1) { 1023 if (state->next[i] != -1) {
1017 assert(state->prev[state->next[i]] == i); 1024 assert(state->prev[state->next[i]] == i);
@@ -1028,8 +1035,8 @@ static void connect_numbers(game_state *state)
1028 1035
1029static int compare_heads(const void *a, const void *b) 1036static int compare_heads(const void *a, const void *b)
1030{ 1037{
1031 struct head_meta *ha = (struct head_meta *)a; 1038 const struct head_meta *ha = (const struct head_meta *)a;
1032 struct head_meta *hb = (struct head_meta *)b; 1039 const struct head_meta *hb = (const struct head_meta *)b;
1033 1040
1034 /* Heads with preferred colours first... */ 1041 /* Heads with preferred colours first... */
1035 if (ha->preference && !hb->preference) return -1; 1042 if (ha->preference && !hb->preference) return -1;
@@ -1380,8 +1387,32 @@ struct game_ui {
1380 bool dragging, drag_is_from; 1387 bool dragging, drag_is_from;
1381 int sx, sy; /* grid coords of start cell */ 1388 int sx, sy; /* grid coords of start cell */
1382 int dx, dy; /* pixel coords of drag posn */ 1389 int dx, dy; /* pixel coords of drag posn */
1390
1391 /*
1392 * Trivial and foolish configurable option done on purest whim.
1393 * With this option enabled, the victory flash is done by rotating
1394 * each square in the opposite direction from its immediate
1395 * neighbours, so that they behave like a field of interlocking
1396 * gears. With it disabled, they all rotate in the same direction.
1397 * Choose for yourself which is more brain-twisting :-)
1398 */
1399 bool gear_mode;
1383}; 1400};
1384 1401
1402static void legacy_prefs_override(struct game_ui *ui_out)
1403{
1404 static bool initialised = false;
1405 static int gear_mode = -1;
1406
1407 if (!initialised) {
1408 initialised = true;
1409 gear_mode = getenv_bool("SIGNPOST_GEARS", -1);
1410 }
1411
1412 if (gear_mode != -1)
1413 ui_out->gear_mode = gear_mode;
1414}
1415
1385static game_ui *new_ui(const game_state *state) 1416static game_ui *new_ui(const game_state *state)
1386{ 1417{
1387 game_ui *ui = snew(game_ui); 1418 game_ui *ui = snew(game_ui);
@@ -1390,11 +1421,14 @@ static game_ui *new_ui(const game_state *state)
1390 * copy to clone, there's code that needs fixing in game_redraw too. */ 1421 * copy to clone, there's code that needs fixing in game_redraw too. */
1391 1422
1392 ui->cx = ui->cy = 0; 1423 ui->cx = ui->cy = 0;
1393 ui->cshow = false; 1424 ui->cshow = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1394 1425
1395 ui->dragging = false; 1426 ui->dragging = false;
1396 ui->sx = ui->sy = ui->dx = ui->dy = 0; 1427 ui->sx = ui->sy = ui->dx = ui->dy = 0;
1397 1428
1429 ui->gear_mode = false;
1430 legacy_prefs_override(ui);
1431
1398 return ui; 1432 return ui;
1399} 1433}
1400 1434
@@ -1403,13 +1437,28 @@ static void free_ui(game_ui *ui)
1403 sfree(ui); 1437 sfree(ui);
1404} 1438}
1405 1439
1406static char *encode_ui(const game_ui *ui) 1440static config_item *get_prefs(game_ui *ui)
1407{ 1441{
1408 return NULL; 1442 config_item *ret;
1443
1444 ret = snewn(2, config_item);
1445
1446 ret[0].name = "Victory rotation effect";
1447 ret[0].kw = "flash-type";
1448 ret[0].type = C_CHOICES;
1449 ret[0].u.choices.choicenames = ":Unidirectional:Meshing gears";
1450 ret[0].u.choices.choicekws = ":unidirectional:gears";
1451 ret[0].u.choices.selected = ui->gear_mode;
1452
1453 ret[1].name = NULL;
1454 ret[1].type = C_END;
1455
1456 return ret;
1409} 1457}
1410 1458
1411static void decode_ui(game_ui *ui, const char *encoding) 1459static void set_prefs(game_ui *ui, const config_item *cfg)
1412{ 1460{
1461 ui->gear_mode = cfg[0].u.choices.selected;
1413} 1462}
1414 1463
1415static void game_changed_state(game_ui *ui, const game_state *oldstate, 1464static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -1421,6 +1470,26 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1421 } 1470 }
1422} 1471}
1423 1472
1473static const char *current_key_label(const game_ui *ui,
1474 const game_state *state, int button)
1475{
1476 if (IS_CURSOR_SELECT(button) && ui->cshow) {
1477 if (ui->dragging) {
1478 if (ui->drag_is_from) {
1479 if (isvalidmove(state, false, ui->sx, ui->sy, ui->cx, ui->cy))
1480 return "To here";
1481 } else {
1482 if (isvalidmove(state, false, ui->cx, ui->cy, ui->sx, ui->sy))
1483 return "From here";
1484 }
1485 return "Cancel";
1486 } else {
1487 return button == CURSOR_SELECT ? "From here" : "To here";
1488 }
1489 }
1490 return "";
1491}
1492
1424struct game_drawstate { 1493struct game_drawstate {
1425 int tilesize; 1494 int tilesize;
1426 bool started, solved; 1495 bool started, solved;
@@ -1442,26 +1511,27 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1442 char buf[80]; 1511 char buf[80];
1443 1512
1444 if (IS_CURSOR_MOVE(button)) { 1513 if (IS_CURSOR_MOVE(button)) {
1445 move_cursor(button, &ui->cx, &ui->cy, state->w, state->h, false); 1514 char *ret;
1446 ui->cshow = true; 1515 ret = move_cursor(button, &ui->cx, &ui->cy, state->w, state->h, false,
1516 &ui->cshow);
1447 if (ui->dragging) { 1517 if (ui->dragging) {
1448 ui->dx = COORD(ui->cx) + TILE_SIZE/2; 1518 ui->dx = COORD(ui->cx) + TILE_SIZE/2;
1449 ui->dy = COORD(ui->cy) + TILE_SIZE/2; 1519 ui->dy = COORD(ui->cy) + TILE_SIZE/2;
1450 } 1520 }
1451 return UI_UPDATE; 1521 return ret;
1452 } else if (IS_CURSOR_SELECT(button)) { 1522 } else if (IS_CURSOR_SELECT(button)) {
1453 if (!ui->cshow) 1523 if (!ui->cshow)
1454 ui->cshow = true; 1524 ui->cshow = true;
1455 else if (ui->dragging) { 1525 else if (ui->dragging) {
1456 ui->dragging = false; 1526 ui->dragging = false;
1457 if (ui->sx == ui->cx && ui->sy == ui->cy) return UI_UPDATE; 1527 if (ui->sx == ui->cx && ui->sy == ui->cy) return MOVE_UI_UPDATE;
1458 if (ui->drag_is_from) { 1528 if (ui->drag_is_from) {
1459 if (!isvalidmove(state, false, ui->sx, ui->sy, ui->cx, ui->cy)) 1529 if (!isvalidmove(state, false, ui->sx, ui->sy, ui->cx, ui->cy))
1460 return UI_UPDATE; 1530 return MOVE_UI_UPDATE;
1461 sprintf(buf, "L%d,%d-%d,%d", ui->sx, ui->sy, ui->cx, ui->cy); 1531 sprintf(buf, "L%d,%d-%d,%d", ui->sx, ui->sy, ui->cx, ui->cy);
1462 } else { 1532 } else {
1463 if (!isvalidmove(state, false, ui->cx, ui->cy, ui->sx, ui->sy)) 1533 if (!isvalidmove(state, false, ui->cx, ui->cy, ui->sx, ui->sy))
1464 return UI_UPDATE; 1534 return MOVE_UI_UPDATE;
1465 sprintf(buf, "L%d,%d-%d,%d", ui->cx, ui->cy, ui->sx, ui->sy); 1535 sprintf(buf, "L%d,%d-%d,%d", ui->cx, ui->cy, ui->sx, ui->sy);
1466 } 1536 }
1467 return dupstr(buf); 1537 return dupstr(buf);
@@ -1473,7 +1543,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1473 ui->dy = COORD(ui->cy) + TILE_SIZE/2; 1543 ui->dy = COORD(ui->cy) + TILE_SIZE/2;
1474 ui->drag_is_from = (button == CURSOR_SELECT); 1544 ui->drag_is_from = (button == CURSOR_SELECT);
1475 } 1545 }
1476 return UI_UPDATE; 1546 return MOVE_UI_UPDATE;
1477 } 1547 }
1478 if (IS_MOUSE_DOWN(button)) { 1548 if (IS_MOUSE_DOWN(button)) {
1479 if (ui->cshow) { 1549 if (ui->cshow) {
@@ -1502,19 +1572,19 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1502 ui->dx = mx; 1572 ui->dx = mx;
1503 ui->dy = my; 1573 ui->dy = my;
1504 ui->cshow = false; 1574 ui->cshow = false;
1505 return UI_UPDATE; 1575 return MOVE_UI_UPDATE;
1506 } else if (IS_MOUSE_DRAG(button) && ui->dragging) { 1576 } else if (IS_MOUSE_DRAG(button) && ui->dragging) {
1507 ui->dx = mx; 1577 ui->dx = mx;
1508 ui->dy = my; 1578 ui->dy = my;
1509 return UI_UPDATE; 1579 return MOVE_UI_UPDATE;
1510 } else if (IS_MOUSE_RELEASE(button) && ui->dragging) { 1580 } else if (IS_MOUSE_RELEASE(button) && ui->dragging) {
1511 ui->dragging = false; 1581 ui->dragging = false;
1512 if (ui->sx == x && ui->sy == y) return UI_UPDATE; /* single click */ 1582 if (ui->sx == x && ui->sy == y) return MOVE_UI_UPDATE; /* single click */
1513 1583
1514 if (!INGRID(state, x, y)) { 1584 if (!INGRID(state, x, y)) {
1515 int si = ui->sy*w+ui->sx; 1585 int si = ui->sy*w+ui->sx;
1516 if (state->prev[si] == -1 && state->next[si] == -1) 1586 if (state->prev[si] == -1 && state->next[si] == -1)
1517 return UI_UPDATE; 1587 return MOVE_UI_UPDATE;
1518 sprintf(buf, "%c%d,%d", 1588 sprintf(buf, "%c%d,%d",
1519 (int)(ui->drag_is_from ? 'C' : 'X'), ui->sx, ui->sy); 1589 (int)(ui->drag_is_from ? 'C' : 'X'), ui->sx, ui->sy);
1520 return dupstr(buf); 1590 return dupstr(buf);
@@ -1522,11 +1592,11 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1522 1592
1523 if (ui->drag_is_from) { 1593 if (ui->drag_is_from) {
1524 if (!isvalidmove(state, false, ui->sx, ui->sy, x, y)) 1594 if (!isvalidmove(state, false, ui->sx, ui->sy, x, y))
1525 return UI_UPDATE; 1595 return MOVE_UI_UPDATE;
1526 sprintf(buf, "L%d,%d-%d,%d", ui->sx, ui->sy, x, y); 1596 sprintf(buf, "L%d,%d-%d,%d", ui->sx, ui->sy, x, y);
1527 } else { 1597 } else {
1528 if (!isvalidmove(state, false, x, y, ui->sx, ui->sy)) 1598 if (!isvalidmove(state, false, x, y, ui->sx, ui->sy))
1529 return UI_UPDATE; 1599 return MOVE_UI_UPDATE;
1530 sprintf(buf, "L%d,%d-%d,%d", x, y, ui->sx, ui->sy); 1600 sprintf(buf, "L%d,%d-%d,%d", x, y, ui->sx, ui->sy);
1531 } 1601 }
1532 return dupstr(buf); 1602 return dupstr(buf);
@@ -1535,7 +1605,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1535 else if ((button == 'x' || button == 'X') && ui->cshow) { 1605 else if ((button == 'x' || button == 'X') && ui->cshow) {
1536 int si = ui->cy*w + ui->cx; 1606 int si = ui->cy*w + ui->cx;
1537 if (state->prev[si] == -1 && state->next[si] == -1) 1607 if (state->prev[si] == -1 && state->next[si] == -1)
1538 return UI_UPDATE; 1608 return MOVE_UI_UPDATE;
1539 sprintf(buf, "%c%d,%d", 1609 sprintf(buf, "%c%d,%d",
1540 (int)((button == 'x') ? 'C' : 'X'), ui->cx, ui->cy); 1610 (int)((button == 'x') ? 'C' : 'X'), ui->cx, ui->cy);
1541 return dupstr(buf); 1611 return dupstr(buf);
@@ -1641,7 +1711,7 @@ static game_state *execute_move(const game_state *state, const char *move)
1641 */ 1711 */
1642 1712
1643static void game_compute_size(const game_params *params, int tilesize, 1713static void game_compute_size(const game_params *params, int tilesize,
1644 int *x, int *y) 1714 const game_ui *ui, int *x, int *y)
1645{ 1715{
1646 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 1716 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1647 struct { int tilesize, order; } ads, *ds = &ads; 1717 struct { int tilesize, order; } ads, *ds = &ads;
@@ -1825,9 +1895,8 @@ static void draw_star(drawing *dr, int cx, int cy, int rad, int npoints,
1825 coords = snewn(npoints * 2 * 2, int); 1895 coords = snewn(npoints * 2 * 2, int);
1826 1896
1827 for (n = 0; n < npoints * 2; n++) { 1897 for (n = 0; n < npoints * 2; n++) {
1828 /* hack to accomodate rockbox's concave polygon drawing */ 1898 a = 2.0 * PI * ((double)n / ((double)npoints * 2.0)) + angle_offset;
1829 a = 2.0 * PI * ((double)n / ((double)npoints * 2.0)) + angle_offset - PI / npoints; 1899 r = (n % 2) ? (double)rad/2.0 : (double)rad;
1830 r = (n % 2 == 0) ? (double)rad/2.0 : (double)rad;
1831 1900
1832 /* We're rotating the point at (0, -r) by a degrees */ 1901 /* We're rotating the point at (0, -r) by a degrees */
1833 coords[2*n+0] = cx + (int)( r * sin(a)); 1902 coords[2*n+0] = cx + (int)( r * sin(a));
@@ -2082,7 +2151,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2082 if (!ds->started) { 2151 if (!ds->started) {
2083 int aw = TILE_SIZE * state->w; 2152 int aw = TILE_SIZE * state->w;
2084 int ah = TILE_SIZE * state->h; 2153 int ah = TILE_SIZE * state->h;
2085 draw_rect(dr, 0, 0, aw + 2 * BORDER, ah + 2 * BORDER, COL_BACKGROUND);
2086 draw_rect_outline(dr, BORDER - 1, BORDER - 1, aw + 2, ah + 2, COL_GRID); 2154 draw_rect_outline(dr, BORDER - 1, BORDER - 1, aw + 2, ah + 2, COL_GRID);
2087 draw_update(dr, 0, 0, aw + 2 * BORDER, ah + 2 * BORDER); 2155 draw_update(dr, 0, 0, aw + 2 * BORDER, ah + 2 * BORDER);
2088 } 2156 }
@@ -2127,28 +2195,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2127 if (state->nums[i] != ds->nums[i] || 2195 if (state->nums[i] != ds->nums[i] ||
2128 f != ds->f[i] || dirp != ds->dirp[i] || 2196 f != ds->f[i] || dirp != ds->dirp[i] ||
2129 force || !ds->started) { 2197 force || !ds->started) {
2130 int sign; 2198 int sign = (ui->gear_mode ? 1 - 2 * ((x ^ y) & 1) : 1);
2131 {
2132 /*
2133 * Trivial and foolish configurable option done on
2134 * purest whim. With this option enabled, the
2135 * victory flash is done by rotating each square
2136 * in the opposite direction from its immediate
2137 * neighbours, so that they behave like a field of
2138 * interlocking gears. With it disabled, they all
2139 * rotate in the same direction. Choose for
2140 * yourself which is more brain-twisting :-)
2141 */
2142 static int gear_mode = -1;
2143 if (gear_mode < 0) {
2144 char *env = getenv("SIGNPOST_GEARS");
2145 gear_mode = (env && (env[0] == 'y' || env[0] == 'Y'));
2146 }
2147 if (gear_mode)
2148 sign = 1 - 2 * ((x ^ y) & 1);
2149 else
2150 sign = 1;
2151 }
2152 tile_redraw(dr, ds, 2199 tile_redraw(dr, ds,
2153 BORDER + x * TILE_SIZE, 2200 BORDER + x * TILE_SIZE,
2154 BORDER + y * TILE_SIZE, 2201 BORDER + y * TILE_SIZE,
@@ -2206,21 +2253,18 @@ static int game_status(const game_state *state)
2206 return state->completed ? +1 : 0; 2253 return state->completed ? +1 : 0;
2207} 2254}
2208 2255
2209static bool game_timing_state(const game_state *state, game_ui *ui) 2256static void game_print_size(const game_params *params, const game_ui *ui,
2210{ 2257 float *x, float *y)
2211 return true;
2212}
2213
2214static void game_print_size(const game_params *params, float *x, float *y)
2215{ 2258{
2216 int pw, ph; 2259 int pw, ph;
2217 2260
2218 game_compute_size(params, 1300, &pw, &ph); 2261 game_compute_size(params, 1300, ui, &pw, &ph);
2219 *x = pw / 100.0F; 2262 *x = pw / 100.0F;
2220 *y = ph / 100.0F; 2263 *y = ph / 100.0F;
2221} 2264}
2222 2265
2223static void game_print(drawing *dr, const game_state *state, int tilesize) 2266static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2267 int tilesize)
2224{ 2268{
2225 int ink = print_mono_colour(dr, 0); 2269 int ink = print_mono_colour(dr, 0);
2226 int x, y; 2270 int x, y;
@@ -2273,12 +2317,14 @@ const struct game thegame = {
2273 free_game, 2317 free_game,
2274 true, solve_game, 2318 true, solve_game,
2275 true, game_can_format_as_text_now, game_text_format, 2319 true, game_can_format_as_text_now, game_text_format,
2320 get_prefs, set_prefs,
2276 new_ui, 2321 new_ui,
2277 free_ui, 2322 free_ui,
2278 encode_ui, 2323 NULL, /* encode_ui */
2279 decode_ui, 2324 NULL, /* decode_ui */
2280 NULL, /* game_request_keys */ 2325 NULL, /* game_request_keys */
2281 game_changed_state, 2326 game_changed_state,
2327 current_key_label,
2282 interpret_move, 2328 interpret_move,
2283 execute_move, 2329 execute_move,
2284 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 2330 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -2292,7 +2338,7 @@ const struct game thegame = {
2292 game_status, 2338 game_status,
2293 true, false, game_print_size, game_print, 2339 true, false, game_print_size, game_print,
2294 false, /* wants_statusbar */ 2340 false, /* wants_statusbar */
2295 false, game_timing_state, 2341 false, NULL, /* timing_state */
2296 REQUIRE_RBUTTON, /* flags */ 2342 REQUIRE_RBUTTON, /* flags */
2297}; 2343};
2298 2344
@@ -2301,10 +2347,9 @@ const struct game thegame = {
2301#include <time.h> 2347#include <time.h>
2302#include <stdarg.h> 2348#include <stdarg.h>
2303 2349
2304const char *quis = NULL; 2350static const char *quis = NULL;
2305int verbose = 0;
2306 2351
2307void usage(FILE *out) { 2352static void usage(FILE *out) {
2308 fprintf(out, "usage: %s [--stdin] [--soak] [--seed SEED] <params>|<game id>\n", quis); 2353 fprintf(out, "usage: %s [--stdin] [--soak] [--seed SEED] <params>|<game id>\n", quis);
2309} 2354}
2310 2355
@@ -2405,7 +2450,7 @@ static void process_desc(char *id)
2405 thegame.free_params(p); 2450 thegame.free_params(p);
2406} 2451}
2407 2452
2408int main(int argc, const char *argv[]) 2453int main(int argc, char *argv[])
2409{ 2454{
2410 char *id = NULL, *desc, *aux = NULL; 2455 char *id = NULL, *desc, *aux = NULL;
2411 const char *err; 2456 const char *err;
diff --git a/apps/plugins/puzzles/src/singles.R b/apps/plugins/puzzles/src/singles.R
deleted file mode 100644
index a67aed2fbc..0000000000
--- a/apps/plugins/puzzles/src/singles.R
+++ /dev/null
@@ -1,23 +0,0 @@
1# -*- makefile -*-
2
3SINGLES_EXTRA = dsf LATIN
4
5singles : [X] GTK COMMON singles SINGLES_EXTRA singles-icon|no-icon
6singles : [G] WINDOWS COMMON singles SINGLES_EXTRA singles.res|noicon.res
7
8ALL += singles[COMBINED] SINGLES_EXTRA
9
10singlessolver : [U] singles[STANDALONE_SOLVER] SINGLES_EXTRA STANDALONE
11singlessolver : [C] singles[STANDALONE_SOLVER] SINGLES_EXTRA STANDALONE
12
13!begin am gtk
14GAMES += singles
15!end
16
17!begin >list.c
18 A(singles) \
19!end
20
21!begin >gamedesc.txt
22singles:singles.exe:Singles:Number-removing puzzle:Black out the right set of duplicate numbers.
23!end
diff --git a/apps/plugins/puzzles/src/singles.c b/apps/plugins/puzzles/src/singles.c
index 202ce08b20..07db8361ae 100644
--- a/apps/plugins/puzzles/src/singles.c
+++ b/apps/plugins/puzzles/src/singles.c
@@ -58,13 +58,17 @@
58#include <string.h> 58#include <string.h>
59#include <assert.h> 59#include <assert.h>
60#include <ctype.h> 60#include <ctype.h>
61#include <math.h> 61#ifdef NO_TGMATH_H
62# include <math.h>
63#else
64# include <tgmath.h>
65#endif
62 66
63#include "puzzles.h" 67#include "puzzles.h"
64#include "latin.h" 68#include "latin.h"
65 69
66#ifdef STANDALONE_SOLVER 70#ifdef STANDALONE_SOLVER
67bool verbose = false; 71static bool verbose = false;
68#endif 72#endif
69 73
70#define PREFERRED_TILE_SIZE 32 74#define PREFERRED_TILE_SIZE 32
@@ -82,7 +86,7 @@ bool verbose = false;
82#define FLASH_TIME 0.7F 86#define FLASH_TIME 0.7F
83 87
84enum { 88enum {
85 COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT, 89 COL_BACKGROUND, COL_UNUSED1, COL_LOWLIGHT,
86 COL_BLACK, COL_WHITE, COL_BLACKNUM, COL_GRID, 90 COL_BLACK, COL_WHITE, COL_BLACKNUM, COL_GRID,
87 COL_CURSOR, COL_ERROR, 91 COL_CURSOR, COL_ERROR,
88 NCOLOURS 92 NCOLOURS
@@ -254,7 +258,7 @@ static game_params *custom_params(const config_item *cfg)
254static const char *validate_params(const game_params *params, bool full) 258static const char *validate_params(const game_params *params, bool full)
255{ 259{
256 if (params->w < 2 || params->h < 2) 260 if (params->w < 2 || params->h < 2)
257 return "Width and neight must be at least two"; 261 return "Width and height must be at least two";
258 if (params->w > 10+26+26 || params->h > 10+26+26) 262 if (params->w > 10+26+26 || params->h > 10+26+26)
259 return "Puzzle is too large"; 263 return "Puzzle is too large";
260 if (full) { 264 if (full) {
@@ -417,7 +421,7 @@ static void debug_state(const char *desc, game_state *state) {
417 sfree(dbg); 421 sfree(dbg);
418} 422}
419 423
420static void connect_if_same(game_state *state, int *dsf, int i1, int i2) 424static void connect_if_same(game_state *state, DSF *dsf, int i1, int i2)
421{ 425{
422 int c1, c2; 426 int c1, c2;
423 427
@@ -429,13 +433,13 @@ static void connect_if_same(game_state *state, int *dsf, int i1, int i2)
429 dsf_merge(dsf, c1, c2); 433 dsf_merge(dsf, c1, c2);
430} 434}
431 435
432static void connect_dsf(game_state *state, int *dsf) 436static void connect_dsf(game_state *state, DSF *dsf)
433{ 437{
434 int x, y, i; 438 int x, y, i;
435 439
436 /* Construct a dsf array for connected blocks; connections 440 /* Construct a dsf array for connected blocks; connections
437 * tracked to right and down. */ 441 * tracked to right and down. */
438 dsf_init(dsf, state->n); 442 dsf_reinit(dsf);
439 for (x = 0; x < state->w; x++) { 443 for (x = 0; x < state->w; x++) {
440 for (y = 0; y < state->h; y++) { 444 for (y = 0; y < state->h; y++) {
441 i = y*state->w + x; 445 i = y*state->w + x;
@@ -494,7 +498,7 @@ static int check_rowcol(game_state *state, int starti, int di, int sz, unsigned
494 498
495static bool check_complete(game_state *state, unsigned flags) 499static bool check_complete(game_state *state, unsigned flags)
496{ 500{
497 int *dsf = snewn(state->n, int); 501 DSF *dsf = dsf_new(state->n);
498 int x, y, i, error = 0, nwhite, w = state->w, h = state->h; 502 int x, y, i, error = 0, nwhite, w = state->w, h = state->h;
499 503
500 if (flags & CC_MARK_ERRORS) { 504 if (flags & CC_MARK_ERRORS) {
@@ -543,7 +547,7 @@ static bool check_complete(game_state *state, unsigned flags)
543 int size = dsf_size(dsf, i); 547 int size = dsf_size(dsf, i);
544 if (largest < size) { 548 if (largest < size) {
545 largest = size; 549 largest = size;
546 canonical = i; 550 canonical = dsf_canonify(dsf, i);
547 } 551 }
548 } 552 }
549 553
@@ -558,7 +562,7 @@ static bool check_complete(game_state *state, unsigned flags)
558 } 562 }
559 } 563 }
560 564
561 sfree(dsf); 565 dsf_free(dsf);
562 return !(error > 0); 566 return !(error > 0);
563} 567}
564 568
@@ -1304,9 +1308,10 @@ found:
1304 return j; 1308 return j;
1305} 1309}
1306 1310
1307static char *new_game_desc(const game_params *params, random_state *rs, 1311static char *new_game_desc(const game_params *params_orig, random_state *rs,
1308 char **aux, bool interactive) 1312 char **aux, bool interactive)
1309{ 1313{
1314 game_params *params = dup_params(params_orig);
1310 game_state *state = blank_game(params->w, params->h); 1315 game_state *state = blank_game(params->w, params->h);
1311 game_state *tosolve = blank_game(params->w, params->h); 1316 game_state *tosolve = blank_game(params->w, params->h);
1312 int i, j, *scratch, *rownums, *colnums, x, y, ntries; 1317 int i, j, *scratch, *rownums, *colnums, x, y, ntries;
@@ -1315,6 +1320,12 @@ static char *new_game_desc(const game_params *params, random_state *rs,
1315 digit *latin; 1320 digit *latin;
1316 struct solver_state *ss = solver_state_new(state); 1321 struct solver_state *ss = solver_state_new(state);
1317 1322
1323 /* Downgrade difficulty to Easy for puzzles so tiny that they aren't
1324 * possible to generate at Tricky. These are 2x2, 2x3 and 3x3, i.e.
1325 * any puzzle that doesn't have one dimension at least 4. */
1326 if ((w < 4 || h < 4) && params->diff > DIFF_EASY)
1327 params->diff = DIFF_EASY;
1328
1318 scratch = snewn(state->n, int); 1329 scratch = snewn(state->n, int);
1319 rownums = snewn(h*o, int); 1330 rownums = snewn(h*o, int);
1320 colnums = snewn(w*o, int); 1331 colnums = snewn(w*o, int);
@@ -1408,6 +1419,7 @@ randomise:
1408 1419
1409 free_game(tosolve); 1420 free_game(tosolve);
1410 free_game(state); 1421 free_game(state);
1422 free_params(params);
1411 solver_state_free(ss); 1423 solver_state_free(ss);
1412 sfree(scratch); 1424 sfree(scratch);
1413 sfree(rownums); 1425 sfree(rownums);
@@ -1446,24 +1458,37 @@ static game_ui *new_ui(const game_state *state)
1446 game_ui *ui = snew(game_ui); 1458 game_ui *ui = snew(game_ui);
1447 1459
1448 ui->cx = ui->cy = 0; 1460 ui->cx = ui->cy = 0;
1449 ui->cshow = false; 1461 ui->cshow = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1450 ui->show_black_nums = false; 1462 ui->show_black_nums = false;
1451 1463
1452 return ui; 1464 return ui;
1453} 1465}
1454 1466
1455static void free_ui(game_ui *ui) 1467static config_item *get_prefs(game_ui *ui)
1456{ 1468{
1457 sfree(ui); 1469 config_item *ret;
1470
1471 ret = snewn(2, config_item);
1472
1473 ret[0].name = "Show numbers on black squares";
1474 ret[0].kw = "show-black-nums";
1475 ret[0].type = C_BOOLEAN;
1476 ret[0].u.boolean.bval = ui->show_black_nums;
1477
1478 ret[1].name = NULL;
1479 ret[1].type = C_END;
1480
1481 return ret;
1458} 1482}
1459 1483
1460static char *encode_ui(const game_ui *ui) 1484static void set_prefs(game_ui *ui, const config_item *cfg)
1461{ 1485{
1462 return NULL; 1486 ui->show_black_nums = cfg[0].u.boolean.bval;
1463} 1487}
1464 1488
1465static void decode_ui(game_ui *ui, const char *encoding) 1489static void free_ui(game_ui *ui)
1466{ 1490{
1491 sfree(ui);
1467} 1492}
1468 1493
1469static void game_changed_state(game_ui *ui, const game_state *oldstate, 1494static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -1473,6 +1498,18 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1473 ui->cshow = false; 1498 ui->cshow = false;
1474} 1499}
1475 1500
1501static const char *current_key_label(const game_ui *ui,
1502 const game_state *state, int button)
1503{
1504 if (IS_CURSOR_SELECT(button) && ui->cshow) {
1505 unsigned int f = state->flags[ui->cy * state->w + ui->cx];
1506 if (f & F_BLACK) return "Restore";
1507 if (f & F_CIRCLE) return "Remove";
1508 return button == CURSOR_SELECT ? "Black" : "Circle";
1509 }
1510 return "";
1511}
1512
1476#define DS_BLACK 0x1 1513#define DS_BLACK 0x1
1477#define DS_CIRCLE 0x2 1514#define DS_CIRCLE 0x2
1478#define DS_CURSOR 0x4 1515#define DS_CURSOR 0x4
@@ -1497,11 +1534,10 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1497 int i, x = FROMCOORD(mx), y = FROMCOORD(my); 1534 int i, x = FROMCOORD(mx), y = FROMCOORD(my);
1498 enum { NONE, TOGGLE_BLACK, TOGGLE_CIRCLE, UI } action = NONE; 1535 enum { NONE, TOGGLE_BLACK, TOGGLE_CIRCLE, UI } action = NONE;
1499 1536
1500 if (IS_CURSOR_MOVE(button)) { 1537 if (IS_CURSOR_MOVE(button))
1501 move_cursor(button, &ui->cx, &ui->cy, state->w, state->h, true); 1538 return move_cursor(button, &ui->cx, &ui->cy, state->w, state->h, true,
1502 ui->cshow = true; 1539 &ui->cshow);
1503 action = UI; 1540 else if (IS_CURSOR_SELECT(button)) {
1504 } else if (IS_CURSOR_SELECT(button)) {
1505 x = ui->cx; y = ui->cy; 1541 x = ui->cx; y = ui->cy;
1506 if (!ui->cshow) { 1542 if (!ui->cshow) {
1507 action = UI; 1543 action = UI;
@@ -1519,14 +1555,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1519 } 1555 }
1520 if (!INGRID(state, x, y)) { 1556 if (!INGRID(state, x, y)) {
1521 ui->show_black_nums = !ui->show_black_nums; 1557 ui->show_black_nums = !ui->show_black_nums;
1522 action = UI; /* this wants to be a per-game option. */ 1558 action = UI;
1523 } else if (button == LEFT_BUTTON) { 1559 } else if (button == LEFT_BUTTON) {
1524 action = TOGGLE_BLACK; 1560 action = TOGGLE_BLACK;
1525 } else if (button == RIGHT_BUTTON) { 1561 } else if (button == RIGHT_BUTTON) {
1526 action = TOGGLE_CIRCLE; 1562 action = TOGGLE_CIRCLE;
1527 } 1563 }
1528 } 1564 }
1529 if (action == UI) return UI_UPDATE; 1565 if (action == UI) return MOVE_UI_UPDATE;
1530 1566
1531 if (action == TOGGLE_BLACK || action == TOGGLE_CIRCLE) { 1567 if (action == TOGGLE_BLACK || action == TOGGLE_CIRCLE) {
1532 i = y * state->w + x; 1568 i = y * state->w + x;
@@ -1587,7 +1623,7 @@ badmove:
1587 */ 1623 */
1588 1624
1589static void game_compute_size(const game_params *params, int tilesize, 1625static void game_compute_size(const game_params *params, int tilesize,
1590 int *x, int *y) 1626 const game_ui *ui, int *x, int *y)
1591{ 1627{
1592 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 1628 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1593 struct { int tilesize; } ads, *ds = &ads; 1629 struct { int tilesize; } ads, *ds = &ads;
@@ -1608,12 +1644,13 @@ static float *game_colours(frontend *fe, int *ncolours)
1608 float *ret = snewn(3 * NCOLOURS, float); 1644 float *ret = snewn(3 * NCOLOURS, float);
1609 int i; 1645 int i;
1610 1646
1611 game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); 1647 game_mkhighlight(fe, ret, COL_BACKGROUND, -1, COL_LOWLIGHT);
1612 for (i = 0; i < 3; i++) { 1648 for (i = 0; i < 3; i++) {
1613 ret[COL_BLACK * 3 + i] = 0.0F; 1649 ret[COL_BLACK * 3 + i] = 0.0F;
1614 ret[COL_BLACKNUM * 3 + i] = 0.4F; 1650 ret[COL_BLACKNUM * 3 + i] = 0.4F;
1615 ret[COL_WHITE * 3 + i] = 1.0F; 1651 ret[COL_WHITE * 3 + i] = 1.0F;
1616 ret[COL_GRID * 3 + i] = ret[COL_LOWLIGHT * 3 + i]; 1652 ret[COL_GRID * 3 + i] = ret[COL_LOWLIGHT * 3 + i];
1653 ret[COL_UNUSED1 * 3 + i] = 0.0F; /* To placate an assertion. */
1617 } 1654 }
1618 ret[COL_CURSOR * 3 + 0] = 0.2F; 1655 ret[COL_CURSOR * 3 + 0] = 0.2F;
1619 ret[COL_CURSOR * 3 + 1] = 0.8F; 1656 ret[COL_CURSOR * 3 + 1] = 0.8F;
@@ -1708,7 +1745,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1708 if (!ds->started) { 1745 if (!ds->started) {
1709 int wsz = TILE_SIZE * state->w + 2 * BORDER; 1746 int wsz = TILE_SIZE * state->w + 2 * BORDER;
1710 int hsz = TILE_SIZE * state->h + 2 * BORDER; 1747 int hsz = TILE_SIZE * state->h + 2 * BORDER;
1711 draw_rect(dr, 0, 0, wsz, hsz, COL_BACKGROUND);
1712 draw_rect_outline(dr, COORD(0)-1, COORD(0)-1, 1748 draw_rect_outline(dr, COORD(0)-1, COORD(0)-1,
1713 TILE_SIZE * state->w + 2, TILE_SIZE * state->h + 2, 1749 TILE_SIZE * state->w + 2, TILE_SIZE * state->h + 2,
1714 COL_GRID); 1750 COL_GRID);
@@ -1776,22 +1812,19 @@ static int game_status(const game_state *state)
1776 return state->completed ? +1 : 0; 1812 return state->completed ? +1 : 0;
1777} 1813}
1778 1814
1779static bool game_timing_state(const game_state *state, game_ui *ui) 1815static void game_print_size(const game_params *params, const game_ui *ui,
1780{ 1816 float *x, float *y)
1781 return true;
1782}
1783
1784static void game_print_size(const game_params *params, float *x, float *y)
1785{ 1817{
1786 int pw, ph; 1818 int pw, ph;
1787 1819
1788 /* 8mm squares by default. */ 1820 /* 8mm squares by default. */
1789 game_compute_size(params, 800, &pw, &ph); 1821 game_compute_size(params, 800, ui, &pw, &ph);
1790 *x = pw / 100.0F; 1822 *x = pw / 100.0F;
1791 *y = ph / 100.0F; 1823 *y = ph / 100.0F;
1792} 1824}
1793 1825
1794static void game_print(drawing *dr, const game_state *state, int tilesize) 1826static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
1827 int tilesize)
1795{ 1828{
1796 int ink = print_mono_colour(dr, 0); 1829 int ink = print_mono_colour(dr, 0);
1797 int paper = print_mono_colour(dr, 1); 1830 int paper = print_mono_colour(dr, 1);
@@ -1848,12 +1881,14 @@ const struct game thegame = {
1848 free_game, 1881 free_game,
1849 true, solve_game, 1882 true, solve_game,
1850 true, game_can_format_as_text_now, game_text_format, 1883 true, game_can_format_as_text_now, game_text_format,
1884 get_prefs, set_prefs,
1851 new_ui, 1885 new_ui,
1852 free_ui, 1886 free_ui,
1853 encode_ui, 1887 NULL, /* encode_ui */
1854 decode_ui, 1888 NULL, /* decode_ui */
1855 NULL, /* game_request_keys */ 1889 NULL, /* game_request_keys */
1856 game_changed_state, 1890 game_changed_state,
1891 current_key_label,
1857 interpret_move, 1892 interpret_move,
1858 execute_move, 1893 execute_move,
1859 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 1894 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -1867,7 +1902,7 @@ const struct game thegame = {
1867 game_status, 1902 game_status,
1868 true, false, game_print_size, game_print, 1903 true, false, game_print_size, game_print,
1869 false, /* wants_statusbar */ 1904 false, /* wants_statusbar */
1870 false, game_timing_state, 1905 false, NULL, /* timing_state */
1871 REQUIRE_RBUTTON, /* flags */ 1906 REQUIRE_RBUTTON, /* flags */
1872}; 1907};
1873 1908
diff --git a/apps/plugins/puzzles/src/sixteen.R b/apps/plugins/puzzles/src/sixteen.R
deleted file mode 100644
index c63a27cef8..0000000000
--- a/apps/plugins/puzzles/src/sixteen.R
+++ /dev/null
@@ -1,19 +0,0 @@
1# -*- makefile -*-
2
3sixteen : [X] GTK COMMON sixteen sixteen-icon|no-icon
4
5sixteen : [G] WINDOWS COMMON sixteen sixteen.res|noicon.res
6
7ALL += sixteen[COMBINED]
8
9!begin am gtk
10GAMES += sixteen
11!end
12
13!begin >list.c
14 A(sixteen) \
15!end
16
17!begin >gamedesc.txt
18sixteen:sixteen.exe:Sixteen:Toroidal sliding block puzzle:Slide a row at a time to arrange the tiles into order.
19!end
diff --git a/apps/plugins/puzzles/src/sixteen.c b/apps/plugins/puzzles/src/sixteen.c
index 0b02038c43..38f6711a49 100644
--- a/apps/plugins/puzzles/src/sixteen.c
+++ b/apps/plugins/puzzles/src/sixteen.c
@@ -9,7 +9,12 @@
9#include <string.h> 9#include <string.h>
10#include <assert.h> 10#include <assert.h>
11#include <ctype.h> 11#include <ctype.h>
12#include <math.h> 12#include <limits.h>
13#ifdef NO_TGMATH_H
14# include <math.h>
15#else
16# include <tgmath.h>
17#endif
13 18
14#include "puzzles.h" 19#include "puzzles.h"
15 20
@@ -173,6 +178,8 @@ static const char *validate_params(const game_params *params, bool full)
173{ 178{
174 if (params->w < 2 || params->h < 2) 179 if (params->w < 2 || params->h < 2)
175 return "Width and height must both be at least two"; 180 return "Width and height must both be at least two";
181 if (params->w > INT_MAX / params->h)
182 return "Width times height must not be unreasonably large";
176 if (params->movetarget < 0) 183 if (params->movetarget < 0)
177 return "Number of shuffling moves may not be negative"; 184 return "Number of shuffling moves may not be negative";
178 return NULL; 185 return NULL;
@@ -567,7 +574,7 @@ static game_ui *new_ui(const game_state *state)
567 game_ui *ui = snew(game_ui); 574 game_ui *ui = snew(game_ui);
568 ui->cur_x = 0; 575 ui->cur_x = 0;
569 ui->cur_y = 0; 576 ui->cur_y = 0;
570 ui->cur_visible = false; 577 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
571 ui->cur_mode = unlocked; 578 ui->cur_mode = unlocked;
572 579
573 return ui; 580 return ui;
@@ -578,18 +585,24 @@ static void free_ui(game_ui *ui)
578 sfree(ui); 585 sfree(ui);
579} 586}
580 587
581static char *encode_ui(const game_ui *ui) 588static void game_changed_state(game_ui *ui, const game_state *oldstate,
582{ 589 const game_state *newstate)
583 return NULL;
584}
585
586static void decode_ui(game_ui *ui, const char *encoding)
587{ 590{
588} 591}
589 592
590static void game_changed_state(game_ui *ui, const game_state *oldstate, 593static const char *current_key_label(const game_ui *ui,
591 const game_state *newstate) 594 const game_state *state, int button)
592{ 595{
596 if (IS_CURSOR_SELECT(button) && ui->cur_visible) {
597 if (ui->cur_x == -1 || ui->cur_x == state->w ||
598 ui->cur_y == -1 || ui->cur_y == state->h)
599 return button == CURSOR_SELECT2 ? "Back" : "Slide";
600 if (button == CURSOR_SELECT)
601 return ui->cur_mode == lock_tile ? "Unlock" : "Lock tile";
602 if (button == CURSOR_SELECT2)
603 return ui->cur_mode == lock_position ? "Unlock" : "Lock pos";
604 }
605 return "";
593} 606}
594 607
595struct game_drawstate { 608struct game_drawstate {
@@ -609,12 +622,12 @@ static char *interpret_move(const game_state *state, game_ui *ui,
609 bool shift = button & MOD_SHFT, control = button & MOD_CTRL; 622 bool shift = button & MOD_SHFT, control = button & MOD_CTRL;
610 int pad = button & MOD_NUM_KEYPAD; 623 int pad = button & MOD_NUM_KEYPAD;
611 624
612 button &= ~MOD_MASK; 625 button = STRIP_BUTTON_MODIFIERS(button);
613 626
614 if (IS_CURSOR_MOVE(button) || pad) { 627 if (IS_CURSOR_MOVE(button) || pad) {
615 if (!ui->cur_visible) { 628 if (!ui->cur_visible) {
616 ui->cur_visible = true; 629 ui->cur_visible = true;
617 return UI_UPDATE; 630 return MOVE_UI_UPDATE;
618 } 631 }
619 632
620 if (control || shift || ui->cur_mode) { 633 if (control || shift || ui->cur_mode) {
@@ -622,9 +635,9 @@ static char *interpret_move(const game_state *state, game_ui *ui,
622 if (x < 0 || x >= state->w || y < 0 || y >= state->h) 635 if (x < 0 || x >= state->w || y < 0 || y >= state->h)
623 return NULL; 636 return NULL;
624 move_cursor(button | pad, &x, &y, 637 move_cursor(button | pad, &x, &y,
625 state->w, state->h, false); 638 state->w, state->h, false, NULL);
626 move_cursor(button | pad, &xwrap, &ywrap, 639 move_cursor(button | pad, &xwrap, &ywrap,
627 state->w, state->h, true); 640 state->w, state->h, true, NULL);
628 641
629 if (x != xwrap) { 642 if (x != xwrap) {
630 sprintf(buf, "R%d,%c1", y, x ? '+' : '-'); 643 sprintf(buf, "R%d,%c1", y, x ? '+' : '-');
@@ -645,7 +658,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
645 int x = ui->cur_x + 1, y = ui->cur_y + 1; 658 int x = ui->cur_x + 1, y = ui->cur_y + 1;
646 659
647 move_cursor(button | pad, &x, &y, 660 move_cursor(button | pad, &x, &y,
648 state->w + 2, state->h + 2, false); 661 state->w + 2, state->h + 2, false, NULL);
649 662
650 if (x == 0 && y == 0) { 663 if (x == 0 && y == 0) {
651 int t = ui->cur_x; 664 int t = ui->cur_x;
@@ -669,7 +682,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
669 } 682 }
670 683
671 ui->cur_visible = true; 684 ui->cur_visible = true;
672 return UI_UPDATE; 685 return MOVE_UI_UPDATE;
673 } 686 }
674 } 687 }
675 688
@@ -687,11 +700,11 @@ static char *interpret_move(const game_state *state, game_ui *ui,
687 const enum cursor_mode m = (button == CURSOR_SELECT2 ? 700 const enum cursor_mode m = (button == CURSOR_SELECT2 ?
688 lock_position : lock_tile); 701 lock_position : lock_tile);
689 ui->cur_mode = (ui->cur_mode == m ? unlocked : m); 702 ui->cur_mode = (ui->cur_mode == m ? unlocked : m);
690 return UI_UPDATE; 703 return MOVE_UI_UPDATE;
691 } 704 }
692 } else { 705 } else {
693 ui->cur_visible = true; 706 ui->cur_visible = true;
694 return UI_UPDATE; 707 return MOVE_UI_UPDATE;
695 } 708 }
696 } else { 709 } else {
697 return NULL; 710 return NULL;
@@ -706,7 +719,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
706 else if (cy == state->h && cx >= 0 && cx < state->w) 719 else if (cy == state->h && cx >= 0 && cx < state->w)
707 dy = +1, dx = 0; 720 dy = +1, dx = 0;
708 else 721 else
709 return UI_UPDATE; /* invalid click location */ 722 return MOVE_UI_UPDATE; /* invalid click location */
710 723
711 /* reverse direction if right hand button is pressed */ 724 /* reverse direction if right hand button is pressed */
712 if (button == RIGHT_BUTTON || button == CURSOR_SELECT2) { 725 if (button == RIGHT_BUTTON || button == CURSOR_SELECT2) {
@@ -748,11 +761,11 @@ static game_state *execute_move(const game_state *from, const char *move)
748 } 761 }
749 762
750 if (move[0] == 'R' && sscanf(move+1, "%d,%d", &cy, &dx) == 2 && 763 if (move[0] == 'R' && sscanf(move+1, "%d,%d", &cy, &dx) == 2 &&
751 cy >= 0 && cy < from->h) { 764 cy >= 0 && cy < from->h && -from->h <= dx && dx <= from->w ) {
752 cx = dy = 0; 765 cx = dy = 0;
753 n = from->w; 766 n = from->w;
754 } else if (move[0] == 'C' && sscanf(move+1, "%d,%d", &cx, &dy) == 2 && 767 } else if (move[0] == 'C' && sscanf(move+1, "%d,%d", &cx, &dy) == 2 &&
755 cx >= 0 && cx < from->w) { 768 cx >= 0 && cx < from->w && -from->h <= dy && dy <= from->h) {
756 cy = dx = 0; 769 cy = dx = 0;
757 n = from->h; 770 n = from->h;
758 } else 771 } else
@@ -790,7 +803,7 @@ static game_state *execute_move(const game_state *from, const char *move)
790 */ 803 */
791 804
792static void game_compute_size(const game_params *params, int tilesize, 805static void game_compute_size(const game_params *params, int tilesize,
793 int *x, int *y) 806 const game_ui *ui, int *x, int *y)
794{ 807{
795 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 808 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
796 struct { int tilesize; } ads, *ds = &ads; 809 struct { int tilesize; } ads, *ds = &ads;
@@ -937,13 +950,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
937 if (!ds->started) { 950 if (!ds->started) {
938 int coords[10]; 951 int coords[10];
939 952
940 draw_rect(dr, 0, 0,
941 TILE_SIZE * state->w + 2 * BORDER,
942 TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND);
943 draw_update(dr, 0, 0,
944 TILE_SIZE * state->w + 2 * BORDER,
945 TILE_SIZE * state->h + 2 * BORDER);
946
947 /* 953 /*
948 * Recessed area containing the whole puzzle. 954 * Recessed area containing the whole puzzle.
949 */ 955 */
@@ -1165,19 +1171,6 @@ static int game_status(const game_state *state)
1165 return state->completed ? +1 : 0; 1171 return state->completed ? +1 : 0;
1166} 1172}
1167 1173
1168static bool game_timing_state(const game_state *state, game_ui *ui)
1169{
1170 return true;
1171}
1172
1173static void game_print_size(const game_params *params, float *x, float *y)
1174{
1175}
1176
1177static void game_print(drawing *dr, const game_state *state, int tilesize)
1178{
1179}
1180
1181#ifdef COMBINED 1174#ifdef COMBINED
1182#define thegame sixteen 1175#define thegame sixteen
1183#endif 1176#endif
@@ -1199,12 +1192,14 @@ const struct game thegame = {
1199 free_game, 1192 free_game,
1200 true, solve_game, 1193 true, solve_game,
1201 true, game_can_format_as_text_now, game_text_format, 1194 true, game_can_format_as_text_now, game_text_format,
1195 NULL, NULL, /* get_prefs, set_prefs */
1202 new_ui, 1196 new_ui,
1203 free_ui, 1197 free_ui,
1204 encode_ui, 1198 NULL, /* encode_ui */
1205 decode_ui, 1199 NULL, /* decode_ui */
1206 NULL, /* game_request_keys */ 1200 NULL, /* game_request_keys */
1207 game_changed_state, 1201 game_changed_state,
1202 current_key_label,
1208 interpret_move, 1203 interpret_move,
1209 execute_move, 1204 execute_move,
1210 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 1205 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -1216,9 +1211,9 @@ const struct game thegame = {
1216 game_flash_length, 1211 game_flash_length,
1217 game_get_cursor_location, 1212 game_get_cursor_location,
1218 game_status, 1213 game_status,
1219 false, false, game_print_size, game_print, 1214 false, false, NULL, NULL, /* print_size, print */
1220 true, /* wants_statusbar */ 1215 true, /* wants_statusbar */
1221 false, game_timing_state, 1216 false, NULL, /* timing_state */
1222 0, /* flags */ 1217 0, /* flags */
1223}; 1218};
1224 1219
diff --git a/apps/plugins/puzzles/src/slant.R b/apps/plugins/puzzles/src/slant.R
deleted file mode 100644
index ff0d21f1eb..0000000000
--- a/apps/plugins/puzzles/src/slant.R
+++ /dev/null
@@ -1,24 +0,0 @@
1# -*- makefile -*-
2
3SLANT_EXTRA = dsf findloop
4
5slant : [X] GTK COMMON slant SLANT_EXTRA slant-icon|no-icon
6
7slant : [G] WINDOWS COMMON slant SLANT_EXTRA slant.res|noicon.res
8
9slantsolver : [U] slant[STANDALONE_SOLVER] SLANT_EXTRA STANDALONE
10slantsolver : [C] slant[STANDALONE_SOLVER] SLANT_EXTRA STANDALONE
11
12ALL += slant[COMBINED] SLANT_EXTRA
13
14!begin am gtk
15GAMES += slant
16!end
17
18!begin >list.c
19 A(slant) \
20!end
21
22!begin >gamedesc.txt
23slant:slant.exe:Slant:Maze-drawing puzzle:Draw a maze of slanting lines that matches the clues.
24!end
diff --git a/apps/plugins/puzzles/src/slant.c b/apps/plugins/puzzles/src/slant.c
index ed290fe57d..bd04b786e6 100644
--- a/apps/plugins/puzzles/src/slant.c
+++ b/apps/plugins/puzzles/src/slant.c
@@ -28,7 +28,11 @@
28#include <string.h> 28#include <string.h>
29#include <assert.h> 29#include <assert.h>
30#include <ctype.h> 30#include <ctype.h>
31#include <math.h> 31#ifdef NO_TGMATH_H
32# include <math.h>
33#else
34# include <tgmath.h>
35#endif
32 36
33#include "puzzles.h" 37#include "puzzles.h"
34 38
@@ -51,7 +55,7 @@ enum {
51 */ 55 */
52#if defined STANDALONE_SOLVER 56#if defined STANDALONE_SOLVER
53#define SOLVER_DIAGNOSTICS 57#define SOLVER_DIAGNOSTICS
54bool verbose = false; 58static bool verbose = false;
55#elif defined SOLVER_DIAGNOSTICS 59#elif defined SOLVER_DIAGNOSTICS
56#define verbose true 60#define verbose true
57#endif 61#endif
@@ -226,6 +230,8 @@ static const char *validate_params(const game_params *params, bool full)
226 230
227 if (params->w < 2 || params->h < 2) 231 if (params->w < 2 || params->h < 2)
228 return "Width and height must both be at least two"; 232 return "Width and height must both be at least two";
233 if (params->w > INT_MAX / params->h)
234 return "Width times height must not be unreasonably large";
229 235
230 return NULL; 236 return NULL;
231} 237}
@@ -238,7 +244,7 @@ struct solver_scratch {
238 * Disjoint set forest which tracks the connected sets of 244 * Disjoint set forest which tracks the connected sets of
239 * points. 245 * points.
240 */ 246 */
241 int *connected; 247 DSF *connected;
242 248
243 /* 249 /*
244 * Counts the number of possible exits from each connected set 250 * Counts the number of possible exits from each connected set
@@ -259,7 +265,7 @@ struct solver_scratch {
259 * Another disjoint set forest. This one tracks _squares_ which 265 * Another disjoint set forest. This one tracks _squares_ which
260 * are known to slant in the same direction. 266 * are known to slant in the same direction.
261 */ 267 */
262 int *equiv; 268 DSF *equiv;
263 269
264 /* 270 /*
265 * Stores slash values which we know for an equivalence class. 271 * Stores slash values which we know for an equivalence class.
@@ -306,10 +312,10 @@ static struct solver_scratch *new_scratch(int w, int h)
306{ 312{
307 int W = w+1, H = h+1; 313 int W = w+1, H = h+1;
308 struct solver_scratch *ret = snew(struct solver_scratch); 314 struct solver_scratch *ret = snew(struct solver_scratch);
309 ret->connected = snewn(W*H, int); 315 ret->connected = dsf_new(W*H);
310 ret->exits = snewn(W*H, int); 316 ret->exits = snewn(W*H, int);
311 ret->border = snewn(W*H, bool); 317 ret->border = snewn(W*H, bool);
312 ret->equiv = snewn(w*h, int); 318 ret->equiv = dsf_new(w*h);
313 ret->slashval = snewn(w*h, signed char); 319 ret->slashval = snewn(w*h, signed char);
314 ret->vbitmap = snewn(w*h, unsigned char); 320 ret->vbitmap = snewn(w*h, unsigned char);
315 return ret; 321 return ret;
@@ -319,10 +325,10 @@ static void free_scratch(struct solver_scratch *sc)
319{ 325{
320 sfree(sc->vbitmap); 326 sfree(sc->vbitmap);
321 sfree(sc->slashval); 327 sfree(sc->slashval);
322 sfree(sc->equiv); 328 dsf_free(sc->equiv);
323 sfree(sc->border); 329 sfree(sc->border);
324 sfree(sc->exits); 330 sfree(sc->exits);
325 sfree(sc->connected); 331 dsf_free(sc->connected);
326 sfree(sc); 332 sfree(sc);
327} 333}
328 334
@@ -330,7 +336,7 @@ static void free_scratch(struct solver_scratch *sc)
330 * Wrapper on dsf_merge() which updates the `exits' and `border' 336 * Wrapper on dsf_merge() which updates the `exits' and `border'
331 * arrays. 337 * arrays.
332 */ 338 */
333static void merge_vertices(int *connected, 339static void merge_vertices(DSF *connected,
334 struct solver_scratch *sc, int i, int j) 340 struct solver_scratch *sc, int i, int j)
335{ 341{
336 int exits = -1; 342 int exits = -1;
@@ -376,7 +382,7 @@ static void decr_exits(struct solver_scratch *sc, int i)
376 382
377static void fill_square(int w, int h, int x, int y, int v, 383static void fill_square(int w, int h, int x, int y, int v,
378 signed char *soln, 384 signed char *soln,
379 int *connected, struct solver_scratch *sc) 385 DSF *connected, struct solver_scratch *sc)
380{ 386{
381 int W = w+1 /*, H = h+1 */; 387 int W = w+1 /*, H = h+1 */;
382 388
@@ -466,13 +472,13 @@ static int slant_solve(int w, int h, const signed char *clues,
466 * Establish a disjoint set forest for tracking connectedness 472 * Establish a disjoint set forest for tracking connectedness
467 * between grid points. 473 * between grid points.
468 */ 474 */
469 dsf_init(sc->connected, W*H); 475 dsf_reinit(sc->connected);
470 476
471 /* 477 /*
472 * Establish a disjoint set forest for tracking which squares 478 * Establish a disjoint set forest for tracking which squares
473 * are known to slant in the same direction. 479 * are known to slant in the same direction.
474 */ 480 */
475 dsf_init(sc->equiv, w*h); 481 dsf_reinit(sc->equiv);
476 482
477 /* 483 /*
478 * Clear the slashval array. 484 * Clear the slashval array.
@@ -991,7 +997,8 @@ static void slant_generate(int w, int h, signed char *soln, random_state *rs)
991{ 997{
992 int W = w+1, H = h+1; 998 int W = w+1, H = h+1;
993 int x, y, i; 999 int x, y, i;
994 int *connected, *indices; 1000 DSF *connected;
1001 int *indices;
995 1002
996 /* 1003 /*
997 * Clear the output. 1004 * Clear the output.
@@ -1002,7 +1009,7 @@ static void slant_generate(int w, int h, signed char *soln, random_state *rs)
1002 * Establish a disjoint set forest for tracking connectedness 1009 * Establish a disjoint set forest for tracking connectedness
1003 * between grid points. 1010 * between grid points.
1004 */ 1011 */
1005 connected = snew_dsf(W*H); 1012 connected = dsf_new(W*H);
1006 1013
1007 /* 1014 /*
1008 * Prepare a list of the squares in the grid, and fill them in 1015 * Prepare a list of the squares in the grid, and fill them in
@@ -1058,7 +1065,7 @@ static void slant_generate(int w, int h, signed char *soln, random_state *rs)
1058 } 1065 }
1059 1066
1060 sfree(indices); 1067 sfree(indices);
1061 sfree(connected); 1068 dsf_free(connected);
1062} 1069}
1063 1070
1064static char *new_game_desc(const game_params *params, random_state *rs, 1071static char *new_game_desc(const game_params *params, random_state *rs,
@@ -1574,28 +1581,69 @@ static char *game_text_format(const game_state *state)
1574struct game_ui { 1581struct game_ui {
1575 int cur_x, cur_y; 1582 int cur_x, cur_y;
1576 bool cur_visible; 1583 bool cur_visible;
1584
1585 /*
1586 * User preference option to swap the left and right mouse
1587 * buttons. There isn't a completely obvious mapping of left and
1588 * right buttons to the two directions of slash, and at least one
1589 * player turned out not to have the same intuition as me.
1590 */
1591 bool swap_buttons;
1577}; 1592};
1578 1593
1594static void legacy_prefs_override(struct game_ui *ui_out)
1595{
1596 static bool initialised = false;
1597 static int swap_buttons = -1;
1598
1599 if (!initialised) {
1600 initialised = true;
1601 swap_buttons = getenv_bool("SLANT_SWAP_BUTTONS", -1);
1602 }
1603
1604 if (swap_buttons != -1)
1605 ui_out->swap_buttons = swap_buttons;
1606}
1607
1579static game_ui *new_ui(const game_state *state) 1608static game_ui *new_ui(const game_state *state)
1580{ 1609{
1581 game_ui *ui = snew(game_ui); 1610 game_ui *ui = snew(game_ui);
1582 ui->cur_x = ui->cur_y = 0; 1611 ui->cur_x = ui->cur_y = 0;
1583 ui->cur_visible = false; 1612 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1613
1614 ui->swap_buttons = false;
1615 legacy_prefs_override(ui);
1616
1584 return ui; 1617 return ui;
1585} 1618}
1586 1619
1587static void free_ui(game_ui *ui) 1620static config_item *get_prefs(game_ui *ui)
1588{ 1621{
1589 sfree(ui); 1622 config_item *ret;
1623
1624 ret = snewn(2, config_item);
1625
1626 ret[0].name = "Mouse button order";
1627 ret[0].kw = "left-button";
1628 ret[0].type = C_CHOICES;
1629 ret[0].u.choices.choicenames = ":Left \\, right /:Left /, right \\";
1630 ret[0].u.choices.choicekws = ":\\:/";
1631 ret[0].u.choices.selected = ui->swap_buttons;
1632
1633 ret[1].name = NULL;
1634 ret[1].type = C_END;
1635
1636 return ret;
1590} 1637}
1591 1638
1592static char *encode_ui(const game_ui *ui) 1639static void set_prefs(game_ui *ui, const config_item *cfg)
1593{ 1640{
1594 return NULL; 1641 ui->swap_buttons = cfg[0].u.choices.selected;
1595} 1642}
1596 1643
1597static void decode_ui(game_ui *ui, const char *encoding) 1644static void free_ui(game_ui *ui)
1598{ 1645{
1646 sfree(ui);
1599} 1647}
1600 1648
1601static void game_changed_state(game_ui *ui, const game_state *oldstate, 1649static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -1603,6 +1651,22 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1603{ 1651{
1604} 1652}
1605 1653
1654static const char *current_key_label(const game_ui *ui,
1655 const game_state *state, int button)
1656{
1657 if (IS_CURSOR_SELECT(button) && ui->cur_visible) {
1658 switch (state->soln[ui->cur_y*state->p.w+ui->cur_x]) {
1659 case 0:
1660 return button == CURSOR_SELECT ? "\\" : "/";
1661 case -1:
1662 return button == CURSOR_SELECT ? "/" : "Blank";
1663 case +1:
1664 return button == CURSOR_SELECT ? "Blank" : "\\";
1665 }
1666 }
1667 return "";
1668}
1669
1606#define PREFERRED_TILESIZE 32 1670#define PREFERRED_TILESIZE 32
1607#define TILESIZE (ds->tilesize) 1671#define TILESIZE (ds->tilesize)
1608#define BORDER TILESIZE 1672#define BORDER TILESIZE
@@ -1638,7 +1702,6 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1638 1702
1639struct game_drawstate { 1703struct game_drawstate {
1640 int tilesize; 1704 int tilesize;
1641 bool started;
1642 long *grid; 1705 long *grid;
1643 long *todraw; 1706 long *todraw;
1644}; 1707};
@@ -1653,51 +1716,34 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1653 enum { CLOCKWISE, ANTICLOCKWISE, NONE } action = NONE; 1716 enum { CLOCKWISE, ANTICLOCKWISE, NONE } action = NONE;
1654 1717
1655 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { 1718 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
1656 /* 1719 if (ui->swap_buttons) {
1657 * This is an utterly awful hack which I should really sort out 1720 if (button == LEFT_BUTTON)
1658 * by means of a proper configuration mechanism. One Slant 1721 button = RIGHT_BUTTON;
1659 * player has observed that they prefer the mouse buttons to 1722 else
1660 * function exactly the opposite way round, so here's a 1723 button = LEFT_BUTTON;
1661 * mechanism for environment-based configuration. I cache the 1724 }
1662 * result in a global variable - yuck! - to avoid repeated
1663 * lookups.
1664 */
1665 {
1666 static int swap_buttons = -1;
1667 if (swap_buttons < 0) {
1668 char *env = getenv("SLANT_SWAP_BUTTONS");
1669 swap_buttons = (env && (env[0] == 'y' || env[0] == 'Y'));
1670 }
1671 if (swap_buttons) {
1672 if (button == LEFT_BUTTON)
1673 button = RIGHT_BUTTON;
1674 else
1675 button = LEFT_BUTTON;
1676 }
1677 }
1678 action = (button == LEFT_BUTTON) ? CLOCKWISE : ANTICLOCKWISE; 1725 action = (button == LEFT_BUTTON) ? CLOCKWISE : ANTICLOCKWISE;
1679 1726
1680 x = FROMCOORD(x); 1727 x = FROMCOORD(x);
1681 y = FROMCOORD(y); 1728 y = FROMCOORD(y);
1682 if (x < 0 || y < 0 || x >= w || y >= h) 1729 if (x < 0 || y < 0 || x >= w || y >= h)
1683 return NULL; 1730 return MOVE_UNUSED;
1684 ui->cur_visible = false; 1731 ui->cur_visible = false;
1685 } else if (IS_CURSOR_SELECT(button)) { 1732 } else if (IS_CURSOR_SELECT(button)) {
1686 if (!ui->cur_visible) { 1733 if (!ui->cur_visible) {
1687 ui->cur_visible = true; 1734 ui->cur_visible = true;
1688 return UI_UPDATE; 1735 return MOVE_UI_UPDATE;
1689 } 1736 }
1690 x = ui->cur_x; 1737 x = ui->cur_x;
1691 y = ui->cur_y; 1738 y = ui->cur_y;
1692 1739
1693 action = (button == CURSOR_SELECT2) ? ANTICLOCKWISE : CLOCKWISE; 1740 action = (button == CURSOR_SELECT2) ? ANTICLOCKWISE : CLOCKWISE;
1694 } else if (IS_CURSOR_MOVE(button)) { 1741 } else if (IS_CURSOR_MOVE(button)) {
1695 move_cursor(button, &ui->cur_x, &ui->cur_y, w, h, false); 1742 return move_cursor(button, &ui->cur_x, &ui->cur_y, w, h, false, &ui->cur_visible);
1696 ui->cur_visible = true;
1697 return UI_UPDATE;
1698 } else if (button == '\\' || button == '\b' || button == '/') { 1743 } else if (button == '\\' || button == '\b' || button == '/') {
1699 int x = ui->cur_x, y = ui->cur_y; 1744 int x = ui->cur_x, y = ui->cur_y;
1700 if (button == ("\\" "\b" "/")[state->soln[y*w + x] + 1]) return NULL; 1745 if (button == ("\\" "\b" "/")[state->soln[y*w + x] + 1])
1746 return MOVE_NO_EFFECT;
1701 sprintf(buf, "%c%d,%d", button == '\b' ? 'C' : button, x, y); 1747 sprintf(buf, "%c%d,%d", button == '\b' ? 'C' : button, x, y);
1702 return dupstr(buf); 1748 return dupstr(buf);
1703 } 1749 }
@@ -1723,7 +1769,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1723 return dupstr(buf); 1769 return dupstr(buf);
1724 } 1770 }
1725 1771
1726 return NULL; 1772 return MOVE_UNUSED;
1727} 1773}
1728 1774
1729static game_state *execute_move(const game_state *state, const char *move) 1775static game_state *execute_move(const game_state *state, const char *move)
@@ -1774,7 +1820,7 @@ static game_state *execute_move(const game_state *state, const char *move)
1774 */ 1820 */
1775 1821
1776static void game_compute_size(const game_params *params, int tilesize, 1822static void game_compute_size(const game_params *params, int tilesize,
1777 int *x, int *y) 1823 const game_ui *ui, int *x, int *y)
1778{ 1824{
1779 /* fool the macros */ 1825 /* fool the macros */
1780 struct dummy { int tilesize; } dummy, *ds = &dummy; 1826 struct dummy { int tilesize; } dummy, *ds = &dummy;
@@ -1832,7 +1878,6 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1832 struct game_drawstate *ds = snew(struct game_drawstate); 1878 struct game_drawstate *ds = snew(struct game_drawstate);
1833 1879
1834 ds->tilesize = 0; 1880 ds->tilesize = 0;
1835 ds->started = false;
1836 ds->grid = snewn((w+2)*(h+2), long); 1881 ds->grid = snewn((w+2)*(h+2), long);
1837 ds->todraw = snewn((w+2)*(h+2), long); 1882 ds->todraw = snewn((w+2)*(h+2), long);
1838 for (i = 0; i < (w+2)*(h+2); i++) 1883 for (i = 0; i < (w+2)*(h+2); i++)
@@ -1972,14 +2017,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1972 else 2017 else
1973 flashing = false; 2018 flashing = false;
1974 2019
1975 if (!ds->started) {
1976 int ww, wh;
1977 game_compute_size(&state->p, TILESIZE, &ww, &wh);
1978 draw_rect(dr, 0, 0, ww, wh, COL_BACKGROUND);
1979 draw_update(dr, 0, 0, ww, wh);
1980 ds->started = true;
1981 }
1982
1983 /* 2020 /*
1984 * Loop over the grid and work out where all the slashes are. 2021 * Loop over the grid and work out where all the slashes are.
1985 * We need to do this because a slash in one square affects the 2022 * We need to do this because a slash in one square affects the
@@ -2082,24 +2119,21 @@ static int game_status(const game_state *state)
2082 return state->completed ? +1 : 0; 2119 return state->completed ? +1 : 0;
2083} 2120}
2084 2121
2085static bool game_timing_state(const game_state *state, game_ui *ui) 2122static void game_print_size(const game_params *params, const game_ui *ui,
2086{ 2123 float *x, float *y)
2087 return true;
2088}
2089
2090static void game_print_size(const game_params *params, float *x, float *y)
2091{ 2124{
2092 int pw, ph; 2125 int pw, ph;
2093 2126
2094 /* 2127 /*
2095 * I'll use 6mm squares by default. 2128 * I'll use 6mm squares by default.
2096 */ 2129 */
2097 game_compute_size(params, 600, &pw, &ph); 2130 game_compute_size(params, 600, ui, &pw, &ph);
2098 *x = pw / 100.0F; 2131 *x = pw / 100.0F;
2099 *y = ph / 100.0F; 2132 *y = ph / 100.0F;
2100} 2133}
2101 2134
2102static void game_print(drawing *dr, const game_state *state, int tilesize) 2135static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2136 int tilesize)
2103{ 2137{
2104 int w = state->p.w, h = state->p.h, W = w+1; 2138 int w = state->p.w, h = state->p.h, W = w+1;
2105 int ink = print_mono_colour(dr, 0); 2139 int ink = print_mono_colour(dr, 0);
@@ -2179,12 +2213,14 @@ const struct game thegame = {
2179 free_game, 2213 free_game,
2180 true, solve_game, 2214 true, solve_game,
2181 true, game_can_format_as_text_now, game_text_format, 2215 true, game_can_format_as_text_now, game_text_format,
2216 get_prefs, set_prefs,
2182 new_ui, 2217 new_ui,
2183 free_ui, 2218 free_ui,
2184 encode_ui, 2219 NULL, /* encode_ui */
2185 decode_ui, 2220 NULL, /* decode_ui */
2186 NULL, /* game_request_keys */ 2221 NULL, /* game_request_keys */
2187 game_changed_state, 2222 game_changed_state,
2223 current_key_label,
2188 interpret_move, 2224 interpret_move,
2189 execute_move, 2225 execute_move,
2190 PREFERRED_TILESIZE, game_compute_size, game_set_size, 2226 PREFERRED_TILESIZE, game_compute_size, game_set_size,
@@ -2198,7 +2234,7 @@ const struct game thegame = {
2198 game_status, 2234 game_status,
2199 true, false, game_print_size, game_print, 2235 true, false, game_print_size, game_print,
2200 false, /* wants_statusbar */ 2236 false, /* wants_statusbar */
2201 false, game_timing_state, 2237 false, NULL, /* timing_state */
2202 0, /* flags */ 2238 0, /* flags */
2203}; 2239};
2204 2240
diff --git a/apps/plugins/puzzles/src/solo.R b/apps/plugins/puzzles/src/solo.R
deleted file mode 100644
index 081a76147e..0000000000
--- a/apps/plugins/puzzles/src/solo.R
+++ /dev/null
@@ -1,24 +0,0 @@
1# -*- makefile -*-
2
3SOLO_EXTRA = divvy dsf
4
5solo : [X] GTK COMMON solo SOLO_EXTRA solo-icon|no-icon
6
7solo : [G] WINDOWS COMMON solo SOLO_EXTRA solo.res|noicon.res
8
9solosolver : [U] solo[STANDALONE_SOLVER] SOLO_EXTRA STANDALONE
10solosolver : [C] solo[STANDALONE_SOLVER] SOLO_EXTRA STANDALONE
11
12ALL += solo[COMBINED] SOLO_EXTRA
13
14!begin am gtk
15GAMES += solo
16!end
17
18!begin >list.c
19 A(solo) \
20!end
21
22!begin >gamedesc.txt
23solo:solo.exe:Solo:Number placement puzzle:Fill in the grid so that each row, column and square block contains one of every digit.
24!end
diff --git a/apps/plugins/puzzles/src/solo.c b/apps/plugins/puzzles/src/solo.c
index 49753f41dc..2445501f57 100644
--- a/apps/plugins/puzzles/src/solo.c
+++ b/apps/plugins/puzzles/src/solo.c
@@ -20,7 +20,7 @@
20 * + while I'm revamping this area, filling in the _last_ 20 * + while I'm revamping this area, filling in the _last_
21 * number in a nearly-full row or column should certainly be 21 * number in a nearly-full row or column should certainly be
22 * permitted even at the lowest difficulty level. 22 * permitted even at the lowest difficulty level.
23 * + also Owen noticed that `Basic' grids requiring numeric 23 * + also Alex noticed that `Basic' grids requiring numeric
24 * elimination are actually very hard, so I wonder if a 24 * elimination are actually very hard, so I wonder if a
25 * difficulty gradation between that and positional- 25 * difficulty gradation between that and positional-
26 * elimination-only might be in order 26 * elimination-only might be in order
@@ -87,11 +87,15 @@
87#include <string.h> 87#include <string.h>
88#include <assert.h> 88#include <assert.h>
89#include <ctype.h> 89#include <ctype.h>
90#include <math.h> 90#ifdef NO_TGMATH_H
91# include <math.h>
92#else
93# include <tgmath.h>
94#endif
91 95
92#ifdef STANDALONE_SOLVER 96#ifdef STANDALONE_SOLVER
93#include <stdarg.h> 97#include <stdarg.h>
94int solver_show_working, solver_recurse_depth; 98static int solver_show_working, solver_recurse_depth;
95#endif 99#endif
96 100
97#include "puzzles.h" 101#include "puzzles.h"
@@ -2638,6 +2642,7 @@ static void solver(int cr, struct block_structure *blocks,
2638 sfree(usage->row); 2642 sfree(usage->row);
2639 sfree(usage->col); 2643 sfree(usage->col);
2640 sfree(usage->blk); 2644 sfree(usage->blk);
2645 sfree(usage->diag);
2641 if (usage->kblocks) { 2646 if (usage->kblocks) {
2642 free_block_structure(usage->kblocks); 2647 free_block_structure(usage->kblocks);
2643 free_block_structure(usage->extra_cages); 2648 free_block_structure(usage->extra_cages);
@@ -2969,6 +2974,7 @@ static bool gridgen(int cr, struct block_structure *blocks,
2969 sfree(usage->blk); 2974 sfree(usage->blk);
2970 sfree(usage->col); 2975 sfree(usage->col);
2971 sfree(usage->row); 2976 sfree(usage->row);
2977 sfree(usage->diag);
2972 sfree(usage); 2978 sfree(usage);
2973 2979
2974 return ret; 2980 return ret;
@@ -3222,7 +3228,7 @@ static char *encode_solve_move(int cr, digit *grid)
3222 return ret; 3228 return ret;
3223} 3229}
3224 3230
3225static void dsf_to_blocks(int *dsf, struct block_structure *blocks, 3231static void dsf_to_blocks(DSF *dsf, struct block_structure *blocks,
3226 int min_expected, int max_expected) 3232 int min_expected, int max_expected)
3227{ 3233{
3228 int cr = blocks->c * blocks->r, area = cr * cr; 3234 int cr = blocks->c * blocks->r, area = cr * cr;
@@ -3654,10 +3660,11 @@ static char *new_game_desc(const game_params *params, random_state *rs,
3654 * the puzzle size: all 2x2 puzzles appear to be Trivial 3660 * the puzzle size: all 2x2 puzzles appear to be Trivial
3655 * (DIFF_BLOCK) so we cannot hold out for even a Basic 3661 * (DIFF_BLOCK) so we cannot hold out for even a Basic
3656 * (DIFF_SIMPLE) one. 3662 * (DIFF_SIMPLE) one.
3663 * Jigsaw puzzles of size 2 and 3 are also all trivial.
3657 */ 3664 */
3658 dlev.maxdiff = params->diff; 3665 dlev.maxdiff = params->diff;
3659 dlev.maxkdiff = params->kdiff; 3666 dlev.maxkdiff = params->kdiff;
3660 if (c == 2 && r == 2) 3667 if ((c == 2 && r == 2) || (r == 1 && c < 4))
3661 dlev.maxdiff = DIFF_BLOCK; 3668 dlev.maxdiff = DIFF_BLOCK;
3662 3669
3663 grid = snewn(area, digit); 3670 grid = snewn(area, digit);
@@ -3684,11 +3691,11 @@ static char *new_game_desc(const game_params *params, random_state *rs,
3684 * constructing the block structure. 3691 * constructing the block structure.
3685 */ 3692 */
3686 if (r == 1) { /* jigsaw mode */ 3693 if (r == 1) { /* jigsaw mode */
3687 int *dsf = divvy_rectangle(cr, cr, cr, rs); 3694 DSF *dsf = divvy_rectangle(cr, cr, cr, rs);
3688 3695
3689 dsf_to_blocks (dsf, blocks, cr, cr); 3696 dsf_to_blocks (dsf, blocks, cr, cr);
3690 3697
3691 sfree(dsf); 3698 dsf_free(dsf);
3692 } else { /* basic Sudoku mode */ 3699 } else { /* basic Sudoku mode */
3693 for (y = 0; y < cr; y++) 3700 for (y = 0; y < cr; y++)
3694 for (x = 0; x < cr; x++) 3701 for (x = 0; x < cr; x++)
@@ -3903,14 +3910,14 @@ static const char *spec_to_grid(const char *desc, digit *grid, int area)
3903 * end of the block spec, and return an error string or NULL if everything 3910 * end of the block spec, and return an error string or NULL if everything
3904 * is OK. The DSF is stored in *PDSF. 3911 * is OK. The DSF is stored in *PDSF.
3905 */ 3912 */
3906static const char *spec_to_dsf(const char **pdesc, int **pdsf, 3913static const char *spec_to_dsf(const char **pdesc, DSF **pdsf,
3907 int cr, int area) 3914 int cr, int area)
3908{ 3915{
3909 const char *desc = *pdesc; 3916 const char *desc = *pdesc;
3910 int pos = 0; 3917 int pos = 0;
3911 int *dsf; 3918 DSF *dsf;
3912 3919
3913 *pdsf = dsf = snew_dsf(area); 3920 *pdsf = dsf = dsf_new(area);
3914 3921
3915 while (*desc && *desc != ',') { 3922 while (*desc && *desc != ',') {
3916 int c; 3923 int c;
@@ -3921,7 +3928,7 @@ static const char *spec_to_dsf(const char **pdesc, int **pdsf,
3921 else if (*desc >= 'a' && *desc <= 'z') 3928 else if (*desc >= 'a' && *desc <= 'z')
3922 c = *desc - 'a' + 1; 3929 c = *desc - 'a' + 1;
3923 else { 3930 else {
3924 sfree(dsf); 3931 dsf_free(dsf);
3925 return "Invalid character in game description"; 3932 return "Invalid character in game description";
3926 } 3933 }
3927 desc++; 3934 desc++;
@@ -3936,7 +3943,7 @@ static const char *spec_to_dsf(const char **pdesc, int **pdsf,
3936 * side of it. 3943 * side of it.
3937 */ 3944 */
3938 if (pos >= 2*cr*(cr-1)) { 3945 if (pos >= 2*cr*(cr-1)) {
3939 sfree(dsf); 3946 dsf_free(dsf);
3940 return "Too much data in block structure specification"; 3947 return "Too much data in block structure specification";
3941 } 3948 }
3942 3949
@@ -3966,7 +3973,7 @@ static const char *spec_to_dsf(const char **pdesc, int **pdsf,
3966 * edge at the end. 3973 * edge at the end.
3967 */ 3974 */
3968 if (pos != 2*cr*(cr-1)+1) { 3975 if (pos != 2*cr*(cr-1)+1) {
3969 sfree(dsf); 3976 dsf_free(dsf);
3970 return "Not enough data in block structure specification"; 3977 return "Not enough data in block structure specification";
3971 } 3978 }
3972 3979
@@ -4008,7 +4015,7 @@ static const char *validate_block_desc(const char **pdesc, int cr, int area,
4008 int min_nr_squares, int max_nr_squares) 4015 int min_nr_squares, int max_nr_squares)
4009{ 4016{
4010 const char *err; 4017 const char *err;
4011 int *dsf; 4018 DSF *dsf;
4012 4019
4013 err = spec_to_dsf(pdesc, &dsf, cr, area); 4020 err = spec_to_dsf(pdesc, &dsf, cr, area);
4014 if (err) { 4021 if (err) {
@@ -4037,7 +4044,7 @@ static const char *validate_block_desc(const char **pdesc, int cr, int area,
4037 if (canons[c] == j) { 4044 if (canons[c] == j) {
4038 counts[c]++; 4045 counts[c]++;
4039 if (counts[c] > max_nr_squares) { 4046 if (counts[c] > max_nr_squares) {
4040 sfree(dsf); 4047 dsf_free(dsf);
4041 sfree(canons); 4048 sfree(canons);
4042 sfree(counts); 4049 sfree(counts);
4043 return "A jigsaw block is too big"; 4050 return "A jigsaw block is too big";
@@ -4047,7 +4054,7 @@ static const char *validate_block_desc(const char **pdesc, int cr, int area,
4047 4054
4048 if (c == ncanons) { 4055 if (c == ncanons) {
4049 if (ncanons >= max_nr_blocks) { 4056 if (ncanons >= max_nr_blocks) {
4050 sfree(dsf); 4057 dsf_free(dsf);
4051 sfree(canons); 4058 sfree(canons);
4052 sfree(counts); 4059 sfree(counts);
4053 return "Too many distinct jigsaw blocks"; 4060 return "Too many distinct jigsaw blocks";
@@ -4059,14 +4066,14 @@ static const char *validate_block_desc(const char **pdesc, int cr, int area,
4059 } 4066 }
4060 4067
4061 if (ncanons < min_nr_blocks) { 4068 if (ncanons < min_nr_blocks) {
4062 sfree(dsf); 4069 dsf_free(dsf);
4063 sfree(canons); 4070 sfree(canons);
4064 sfree(counts); 4071 sfree(counts);
4065 return "Not enough distinct jigsaw blocks"; 4072 return "Not enough distinct jigsaw blocks";
4066 } 4073 }
4067 for (c = 0; c < ncanons; c++) { 4074 for (c = 0; c < ncanons; c++) {
4068 if (counts[c] < min_nr_squares) { 4075 if (counts[c] < min_nr_squares) {
4069 sfree(dsf); 4076 dsf_free(dsf);
4070 sfree(canons); 4077 sfree(canons);
4071 sfree(counts); 4078 sfree(counts);
4072 return "A jigsaw block is too small"; 4079 return "A jigsaw block is too small";
@@ -4076,7 +4083,7 @@ static const char *validate_block_desc(const char **pdesc, int cr, int area,
4076 sfree(counts); 4083 sfree(counts);
4077 } 4084 }
4078 4085
4079 sfree(dsf); 4086 dsf_free(dsf);
4080 return NULL; 4087 return NULL;
4081} 4088}
4082 4089
@@ -4161,13 +4168,13 @@ static game_state *new_game(midend *me, const game_params *params,
4161 4168
4162 if (r == 1) { 4169 if (r == 1) {
4163 const char *err; 4170 const char *err;
4164 int *dsf; 4171 DSF *dsf;
4165 assert(*desc == ','); 4172 assert(*desc == ',');
4166 desc++; 4173 desc++;
4167 err = spec_to_dsf(&desc, &dsf, cr, area); 4174 err = spec_to_dsf(&desc, &dsf, cr, area);
4168 assert(err == NULL); 4175 assert(err == NULL);
4169 dsf_to_blocks(dsf, state->blocks, cr, cr); 4176 dsf_to_blocks(dsf, state->blocks, cr, cr);
4170 sfree(dsf); 4177 dsf_free(dsf);
4171 } else { 4178 } else {
4172 int x, y; 4179 int x, y;
4173 4180
@@ -4179,13 +4186,13 @@ static game_state *new_game(midend *me, const game_params *params,
4179 4186
4180 if (params->killer) { 4187 if (params->killer) {
4181 const char *err; 4188 const char *err;
4182 int *dsf; 4189 DSF *dsf;
4183 assert(*desc == ','); 4190 assert(*desc == ',');
4184 desc++; 4191 desc++;
4185 err = spec_to_dsf(&desc, &dsf, cr, area); 4192 err = spec_to_dsf(&desc, &dsf, cr, area);
4186 assert(err == NULL); 4193 assert(err == NULL);
4187 dsf_to_blocks(dsf, state->kblocks, cr, area); 4194 dsf_to_blocks(dsf, state->kblocks, cr, area);
4188 sfree(dsf); 4195 dsf_free(dsf);
4189 make_blocks_from_whichblock(state->kblocks); 4196 make_blocks_from_whichblock(state->kblocks);
4190 4197
4191 assert(*desc == ','); 4198 assert(*desc == ',');
@@ -4550,6 +4557,17 @@ struct game_ui {
4550 * allowed on immutable squares. 4557 * allowed on immutable squares.
4551 */ 4558 */
4552 bool hcursor; 4559 bool hcursor;
4560
4561 /*
4562 * User preference option: if the user right-clicks in a square
4563 * and presses a number or letter key to add/remove a pencil mark,
4564 * do we hide the mouse highlight again afterwards?
4565 *
4566 * Historically our answer was yes. The Android port prefers no.
4567 * There are advantages both ways, depending how much you dislike
4568 * the highlight cluttering your view. So it's a preference.
4569 */
4570 bool pencil_keep_highlight;
4553}; 4571};
4554 4572
4555static game_ui *new_ui(const game_state *state) 4573static game_ui *new_ui(const game_state *state)
@@ -4558,8 +4576,9 @@ static game_ui *new_ui(const game_state *state)
4558 4576
4559 ui->hx = ui->hy = 0; 4577 ui->hx = ui->hy = 0;
4560 ui->hpencil = false; 4578 ui->hpencil = false;
4561 ui->hshow = false; 4579 ui->hshow = ui->hcursor = getenv_bool("PUZZLES_SHOW_CURSOR", false);
4562 ui->hcursor = false; 4580
4581 ui->pencil_keep_highlight = false;
4563 4582
4564 return ui; 4583 return ui;
4565} 4584}
@@ -4569,13 +4588,26 @@ static void free_ui(game_ui *ui)
4569 sfree(ui); 4588 sfree(ui);
4570} 4589}
4571 4590
4572static char *encode_ui(const game_ui *ui) 4591static config_item *get_prefs(game_ui *ui)
4573{ 4592{
4574 return NULL; 4593 config_item *ret;
4594
4595 ret = snewn(2, config_item);
4596
4597 ret[0].name = "Keep mouse highlight after changing a pencil mark";
4598 ret[0].kw = "pencil-keep-highlight";
4599 ret[0].type = C_BOOLEAN;
4600 ret[0].u.boolean.bval = ui->pencil_keep_highlight;
4601
4602 ret[1].name = NULL;
4603 ret[1].type = C_END;
4604
4605 return ret;
4575} 4606}
4576 4607
4577static void decode_ui(game_ui *ui, const char *encoding) 4608static void set_prefs(game_ui *ui, const config_item *cfg)
4578{ 4609{
4610 ui->pencil_keep_highlight = cfg[0].u.boolean.bval;
4579} 4611}
4580 4612
4581static void game_changed_state(game_ui *ui, const game_state *oldstate, 4613static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -4594,6 +4626,14 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
4594 } 4626 }
4595} 4627}
4596 4628
4629static const char *current_key_label(const game_ui *ui,
4630 const game_state *state, int button)
4631{
4632 if (ui->hshow && (button == CURSOR_SELECT))
4633 return ui->hpencil ? "Ink" : "Pencil";
4634 return "";
4635}
4636
4597struct game_drawstate { 4637struct game_drawstate {
4598 bool started, xtype; 4638 bool started, xtype;
4599 int cr; 4639 int cr;
@@ -4613,7 +4653,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
4613 int tx, ty; 4653 int tx, ty;
4614 char buf[80]; 4654 char buf[80];
4615 4655
4616 button &= ~MOD_MASK; 4656 button = STRIP_BUTTON_MODIFIERS(button);
4617 4657
4618 tx = (x + TILE_SIZE - BORDER) / TILE_SIZE - 1; 4658 tx = (x + TILE_SIZE - BORDER) / TILE_SIZE - 1;
4619 ty = (y + TILE_SIZE - BORDER) / TILE_SIZE - 1; 4659 ty = (y + TILE_SIZE - BORDER) / TILE_SIZE - 1;
@@ -4632,7 +4672,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
4632 ui->hpencil = false; 4672 ui->hpencil = false;
4633 } 4673 }
4634 ui->hcursor = false; 4674 ui->hcursor = false;
4635 return UI_UPDATE; 4675 return MOVE_UI_UPDATE;
4636 } 4676 }
4637 if (button == RIGHT_BUTTON) { 4677 if (button == RIGHT_BUTTON) {
4638 /* 4678 /*
@@ -4652,20 +4692,19 @@ static char *interpret_move(const game_state *state, game_ui *ui,
4652 ui->hshow = false; 4692 ui->hshow = false;
4653 } 4693 }
4654 ui->hcursor = false; 4694 ui->hcursor = false;
4655 return UI_UPDATE; 4695 return MOVE_UI_UPDATE;
4656 } 4696 }
4657 } 4697 }
4658 if (IS_CURSOR_MOVE(button)) { 4698 if (IS_CURSOR_MOVE(button)) {
4659 move_cursor(button, &ui->hx, &ui->hy, cr, cr, false);
4660 ui->hshow = true;
4661 ui->hcursor = true; 4699 ui->hcursor = true;
4662 return UI_UPDATE; 4700 return move_cursor(button, &ui->hx, &ui->hy, cr, cr, false,
4701 &ui->hshow);
4663 } 4702 }
4664 if (ui->hshow && 4703 if (ui->hshow &&
4665 (button == CURSOR_SELECT)) { 4704 (button == CURSOR_SELECT)) {
4666 ui->hpencil = !ui->hpencil; 4705 ui->hpencil = !ui->hpencil;
4667 ui->hcursor = true; 4706 ui->hcursor = true;
4668 return UI_UPDATE; 4707 return MOVE_UI_UPDATE;
4669 } 4708 }
4670 4709
4671 if (ui->hshow && 4710 if (ui->hshow &&
@@ -4695,10 +4734,37 @@ static char *interpret_move(const game_state *state, game_ui *ui,
4695 if (ui->hpencil && state->grid[ui->hy*cr+ui->hx]) 4734 if (ui->hpencil && state->grid[ui->hy*cr+ui->hx])
4696 return NULL; 4735 return NULL;
4697 4736
4737 /*
4738 * If you ask to fill a square with what it already contains,
4739 * or blank it when it's already empty, that has no effect...
4740 */
4741 if ((!ui->hpencil || n == 0) && state->grid[ui->hy*cr+ui->hx] == n) {
4742 bool anypencil = false;
4743 int i;
4744 for (i = 0; i < cr; i++)
4745 anypencil = anypencil ||
4746 state->pencil[(ui->hy*cr+ui->hx) * cr + i];
4747 if (!anypencil) {
4748 /* ... expect to remove the cursor in mouse mode. */
4749 if (!ui->hcursor) {
4750 ui->hshow = false;
4751 return MOVE_UI_UPDATE;
4752 }
4753 return NULL;
4754 }
4755 }
4756
4698 sprintf(buf, "%c%d,%d,%d", 4757 sprintf(buf, "%c%d,%d,%d",
4699 (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); 4758 (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n);
4700 4759
4701 if (!ui->hcursor) ui->hshow = false; 4760 /*
4761 * Hide the highlight after a keypress, if it was mouse-
4762 * generated. Also, don't hide it if this move has changed
4763 * pencil marks and the user preference says not to hide the
4764 * highlight in that situation.
4765 */
4766 if (!ui->hcursor && !(ui->hpencil && ui->pencil_keep_highlight))
4767 ui->hshow = false;
4702 4768
4703 return dupstr(buf); 4769 return dupstr(buf);
4704 } 4770 }
@@ -4787,7 +4853,7 @@ static game_state *execute_move(const game_state *from, const char *move)
4787#define GETTILESIZE(cr, w) ( (double)(w-1) / (double)(cr+1) ) 4853#define GETTILESIZE(cr, w) ( (double)(w-1) / (double)(cr+1) )
4788 4854
4789static void game_compute_size(const game_params *params, int tilesize, 4855static void game_compute_size(const game_params *params, int tilesize,
4790 int *x, int *y) 4856 const game_ui *ui, int *x, int *y)
4791{ 4857{
4792 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 4858 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
4793 struct { int tilesize; } ads, *ds = &ads; 4859 struct { int tilesize; } ads, *ds = &ads;
@@ -4920,6 +4986,18 @@ static void draw_number(drawing *dr, game_drawstate *ds,
4920 (ds->xtype && (ondiag0(y*cr+x) || ondiag1(y*cr+x))) ? COL_XDIAGONALS : 4986 (ds->xtype && (ondiag0(y*cr+x) || ondiag1(y*cr+x))) ? COL_XDIAGONALS :
4921 COL_BACKGROUND)); 4987 COL_BACKGROUND));
4922 4988
4989 /* pencil-mode highlight */
4990 if ((hl & 15) == 2) {
4991 int coords[6];
4992 coords[0] = cx;
4993 coords[1] = cy;
4994 coords[2] = cx+cw/2;
4995 coords[3] = cy;
4996 coords[4] = cx;
4997 coords[5] = cy+ch/2;
4998 draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT);
4999 }
5000
4923 /* 5001 /*
4924 * Draw the corners of thick lines in corner-adjacent squares, 5002 * Draw the corners of thick lines in corner-adjacent squares,
4925 * which jut into this square by one pixel. 5003 * which jut into this square by one pixel.
@@ -4933,18 +5011,6 @@ static void draw_number(drawing *dr, game_drawstate *ds,
4933 if (x+1 < cr && y+1 < cr && state->blocks->whichblock[y*cr+x] != state->blocks->whichblock[(y+1)*cr+x+1]) 5011 if (x+1 < cr && y+1 < cr && state->blocks->whichblock[y*cr+x] != state->blocks->whichblock[(y+1)*cr+x+1])
4934 draw_rect(dr, tx+TILE_SIZE-1-2*GRIDEXTRA, ty+TILE_SIZE-1-2*GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); 5012 draw_rect(dr, tx+TILE_SIZE-1-2*GRIDEXTRA, ty+TILE_SIZE-1-2*GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID);
4935 5013
4936 /* pencil-mode highlight */
4937 if ((hl & 15) == 2) {
4938 int coords[6];
4939 coords[0] = cx;
4940 coords[1] = cy;
4941 coords[2] = cx+cw/2;
4942 coords[3] = cy;
4943 coords[4] = cx;
4944 coords[5] = cy+ch/2;
4945 draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT);
4946 }
4947
4948 if (state->kblocks) { 5014 if (state->kblocks) {
4949 int t = GRIDEXTRA * 3; 5015 int t = GRIDEXTRA * 3;
4950 int kcx, kcy, kcw, kch; 5016 int kcx, kcy, kcw, kch;
@@ -5104,7 +5170,7 @@ static void draw_number(drawing *dr, game_drawstate *ds,
5104 fw = (pr - pl) / (float)pw; 5170 fw = (pr - pl) / (float)pw;
5105 fh = (pb - pt) / (float)ph; 5171 fh = (pb - pt) / (float)ph;
5106 fs = min(fw, fh); 5172 fs = min(fw, fh);
5107 if (fs > bestsize) { 5173 if (fs >= bestsize) {
5108 bestsize = fs; 5174 bestsize = fs;
5109 pbest = pw; 5175 pbest = pw;
5110 } 5176 }
@@ -5175,14 +5241,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
5175 5241
5176 if (!ds->started) { 5242 if (!ds->started) {
5177 /* 5243 /*
5178 * The initial contents of the window are not guaranteed
5179 * and can vary with front ends. To be on the safe side,
5180 * all games should start by drawing a big
5181 * background-colour rectangle covering the whole window.
5182 */
5183 draw_rect(dr, 0, 0, SIZE(cr), SIZE(cr), COL_BACKGROUND);
5184
5185 /*
5186 * Draw the grid. We draw it as a big thick rectangle of 5244 * Draw the grid. We draw it as a big thick rectangle of
5187 * COL_GRID initially; individual calls to draw_number() 5245 * COL_GRID initially; individual calls to draw_number()
5188 * will poke the right-shaped holes in it. 5246 * will poke the right-shaped holes in it.
@@ -5315,14 +5373,8 @@ static int game_status(const game_state *state)
5315 return state->completed ? +1 : 0; 5373 return state->completed ? +1 : 0;
5316} 5374}
5317 5375
5318static bool game_timing_state(const game_state *state, game_ui *ui) 5376static void game_print_size(const game_params *params, const game_ui *ui,
5319{ 5377 float *x, float *y)
5320 if (state->completed)
5321 return false;
5322 return true;
5323}
5324
5325static void game_print_size(const game_params *params, float *x, float *y)
5326{ 5378{
5327 int pw, ph; 5379 int pw, ph;
5328 5380
@@ -5331,7 +5383,7 @@ static void game_print_size(const game_params *params, float *x, float *y)
5331 * for this game, because players will want to jot down no end 5383 * for this game, because players will want to jot down no end
5332 * of pencil marks in the squares. 5384 * of pencil marks in the squares.
5333 */ 5385 */
5334 game_compute_size(params, 900, &pw, &ph); 5386 game_compute_size(params, 900, ui, &pw, &ph);
5335 *x = pw / 100.0F; 5387 *x = pw / 100.0F;
5336 *y = ph / 100.0F; 5388 *y = ph / 100.0F;
5337} 5389}
@@ -5505,7 +5557,8 @@ static void outline_block_structure(drawing *dr, game_drawstate *ds,
5505 sfree(coords); 5557 sfree(coords);
5506} 5558}
5507 5559
5508static void game_print(drawing *dr, const game_state *state, int tilesize) 5560static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
5561 int tilesize)
5509{ 5562{
5510 int cr = state->cr; 5563 int cr = state->cr;
5511 int ink = print_mono_colour(dr, 0); 5564 int ink = print_mono_colour(dr, 0);
@@ -5620,12 +5673,14 @@ const struct game thegame = {
5620 free_game, 5673 free_game,
5621 true, solve_game, 5674 true, solve_game,
5622 true, game_can_format_as_text_now, game_text_format, 5675 true, game_can_format_as_text_now, game_text_format,
5676 get_prefs, set_prefs,
5623 new_ui, 5677 new_ui,
5624 free_ui, 5678 free_ui,
5625 encode_ui, 5679 NULL, /* encode_ui */
5626 decode_ui, 5680 NULL, /* decode_ui */
5627 game_request_keys, 5681 game_request_keys,
5628 game_changed_state, 5682 game_changed_state,
5683 current_key_label,
5629 interpret_move, 5684 interpret_move,
5630 execute_move, 5685 execute_move,
5631 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 5686 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -5639,7 +5694,7 @@ const struct game thegame = {
5639 game_status, 5694 game_status,
5640 true, false, game_print_size, game_print, 5695 true, false, game_print_size, game_print,
5641 false, /* wants_statusbar */ 5696 false, /* wants_statusbar */
5642 false, game_timing_state, 5697 false, NULL, /* timing_state */
5643 REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */ 5698 REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */
5644}; 5699};
5645 5700
diff --git a/apps/plugins/puzzles/src/sort.c b/apps/plugins/puzzles/src/sort.c
index d1897b6fdf..e82f4ec6dc 100644
--- a/apps/plugins/puzzles/src/sort.c
+++ b/apps/plugins/puzzles/src/sort.c
@@ -9,26 +9,8 @@
9 9
10#include "puzzles.h" 10#include "puzzles.h"
11 11
12static void memswap(void *av, void *bv, size_t size)
13{
14 char t[4096];
15 char *a = (char *)av, *b = (char *)bv;
16
17 while (size > 0) {
18 size_t thissize = size < sizeof(t) ? size : sizeof(t);
19
20 memcpy(t, a, thissize);
21 memcpy(a, b, thissize);
22 memcpy(b, t, thissize);
23
24 size -= thissize;
25 a += thissize;
26 b += thissize;
27 }
28}
29
30#define PTR(i) ((char *)array + size * (i)) 12#define PTR(i) ((char *)array + size * (i))
31#define SWAP(i,j) memswap(PTR(i), PTR(j), size) 13#define SWAP(i,j) swap_regions(PTR(i), PTR(j), size)
32#define CMP(i,j) cmp(PTR(i), PTR(j), ctx) 14#define CMP(i,j) cmp(PTR(i), PTR(j), ctx)
33 15
34#define LCHILD(i) (2*(i)+1) 16#define LCHILD(i) (2*(i)+1)
@@ -87,74 +69,3 @@ void arraysort_fn(void *array, size_t nmemb, size_t size,
87 downheap(array, i, size, cmp, ctx, 0); 69 downheap(array, i, size, cmp, ctx, 0);
88 } 70 }
89} 71}
90
91#ifdef SORT_TEST
92
93#include <stdlib.h>
94#include <time.h>
95
96int testcmp(const void *av, const void *bv, void *ctx)
97{
98 int a = *(const int *)av, b = *(const int *)bv;
99 const int *keys = (const int *)ctx;
100 return keys[a] < keys[b] ? -1 : keys[a] > keys[b] ? +1 : 0;
101}
102
103int resetcmp(const void *av, const void *bv)
104{
105 int a = *(const int *)av, b = *(const int *)bv;
106 return a < b ? -1 : a > b ? +1 : 0;
107}
108
109int main(int argc, char **argv)
110{
111 typedef int Array[3723];
112 Array data, keys;
113 int iteration;
114 unsigned seed;
115
116 seed = (argc > 1 ? strtoul(argv[1], NULL, 0) : time(NULL));
117 printf("Random seed = %u\n", seed);
118 srand(seed);
119
120 for (iteration = 0; iteration < 10000; iteration++) {
121 int j;
122 const char *fail = NULL;
123
124 for (j = 0; j < lenof(data); j++) {
125 data[j] = j;
126 keys[j] = rand();
127 }
128
129 arraysort(data, lenof(data), testcmp, keys);
130
131 for (j = 1; j < lenof(data); j++) {
132 if (keys[data[j]] < keys[data[j-1]])
133 fail = "output misordered";
134 }
135 if (!fail) {
136 Array reset;
137 memcpy(reset, data, sizeof(data));
138 qsort(reset, lenof(reset), sizeof(*reset), resetcmp);
139 for (j = 0; j < lenof(reset); j++)
140 if (reset[j] != j)
141 fail = "output not permuted";
142 }
143
144 if (fail) {
145 printf("Failed at iteration %d: %s\n", iteration, fail);
146 printf("Key values:\n");
147 for (j = 0; j < lenof(keys); j++)
148 printf(" [%2d] %10d\n", j, keys[j]);
149 printf("Output sorted order:\n");
150 for (j = 0; j < lenof(data); j++)
151 printf(" [%2d] %10d\n", data[j], keys[data[j]]);
152 return 1;
153 }
154 }
155
156 printf("OK\n");
157 return 0;
158}
159
160#endif /* SORT_TEST */
diff --git a/apps/plugins/puzzles/src/spectre-internal.h b/apps/plugins/puzzles/src/spectre-internal.h
new file mode 100644
index 0000000000..e43d30bfef
--- /dev/null
+++ b/apps/plugins/puzzles/src/spectre-internal.h
@@ -0,0 +1,327 @@
1#include "spectre.h"
2
3/*
4 * List macro of the names for hexagon types, which will be reused all
5 * over the place.
6 *
7 * (I have to call the parameter to this list macro something other
8 * than X, because here, X is also one of the macro arguments!)
9 */
10#define HEX_LETTERS(Z) Z(G) Z(D) Z(J) Z(L) Z(X) Z(P) Z(S) Z(F) Z(Y)
11
12typedef enum Hex {
13 #define HEX_ENUM_DECL(x) HEX_##x,
14 HEX_LETTERS(HEX_ENUM_DECL)
15 #undef HEX_ENUM_DECL
16} Hex;
17
18static inline unsigned num_subhexes(Hex h)
19{
20 return h == HEX_G ? 7 : 8;
21}
22
23static inline unsigned num_spectres(Hex h)
24{
25 return h == HEX_G ? 2 : 1;
26}
27
28/*
29 * Data types used in the lookup tables.
30 */
31struct MapEntry {
32 bool internal;
33 unsigned char hi, lo;
34};
35struct MapEdge {
36 unsigned char startindex, len;
37};
38struct Possibility {
39 unsigned char hi, lo;
40 unsigned long prob;
41};
42
43/*
44 * Coordinate system for tracking Spectres and their hexagonal
45 * metatiles.
46 *
47 * SpectreCoords will store the index of a single Spectre within a
48 * smallest-size hexagon, plus an array of HexCoord each indexing a
49 * hexagon within the expansion of a larger hexagon.
50 *
51 * The last coordinate stored, sc->c[sc->nc-1], will have a hex type
52 * but no index (represented by index==-1). This means "we haven't
53 * decided yet what this level of metatile needs to be". If we need to
54 * refer to this level during the hatctx_step algorithm, we make it up
55 * at random, based on a table of what metatiles each type can
56 * possibly be part of, at what index.
57 */
58typedef struct HexCoord {
59 int index; /* index within that tile, or -1 if not yet known */
60 Hex type; /* type of this hexagon */
61} HexCoord;
62
63typedef struct SpectreCoords {
64 int index; /* index of Spectre within the order-0 hexagon */
65 HexCoord *c;
66 size_t nc, csize;
67
68 /* Used by spectre-test to four-colour output tilings, and
69 * maintained unconditionally because it's easier than making it
70 * conditional */
71 unsigned char hex_colour, prev_hex_colour, incoming_hex_edge;
72} SpectreCoords;
73
74SpectreCoords *spectre_coords_new(void);
75void spectre_coords_free(SpectreCoords *hc);
76void spectre_coords_make_space(SpectreCoords *hc, size_t size);
77SpectreCoords *spectre_coords_copy(SpectreCoords *hc_in);
78
79/*
80 * Coordinate system for locating Spectres in the plane.
81 *
82 * The 'Point' structure represents a single point by means of an
83 * integer linear combination of {1, d, d^2, d^3}, where d is the
84 * complex number exp(i pi/6) representing 1/12 of a turn about the
85 * origin.
86 *
87 * The 'Spectre' structure represents an entire Spectre in a tiling,
88 * giving both the locations of all of its vertices and its
89 * combinatorial coordinates. It also contains a linked-list pointer,
90 * used during breadth-first search to generate all the Spectres in an
91 * area.
92 */
93typedef struct Point {
94 int coeffs[4];
95} Point;
96typedef struct Spectre Spectre;
97struct Spectre {
98 Point vertices[14];
99 SpectreCoords *sc;
100 Spectre *next; /* used in breadth-first search */
101};
102
103/* Fill in all the coordinates of a Spectre starting from any single edge */
104void spectre_place(Spectre *spec, Point u, Point v, int index_of_u);
105
106/* Free a Spectre and its contained coordinates */
107void spectre_free(Spectre *spec);
108
109/*
110 * A Point is really a complex number, so we can add, subtract and
111 * multiply them.
112 */
113static inline Point point_add(Point a, Point b)
114{
115 Point r;
116 size_t i;
117 for (i = 0; i < 4; i++)
118 r.coeffs[i] = a.coeffs[i] + b.coeffs[i];
119 return r;
120}
121static inline Point point_sub(Point a, Point b)
122{
123 Point r;
124 size_t i;
125 for (i = 0; i < 4; i++)
126 r.coeffs[i] = a.coeffs[i] - b.coeffs[i];
127 return r;
128}
129static inline Point point_mul_by_d(Point x)
130{
131 Point r;
132 /* Multiply by d by using the identity d^4 - d^2 + 1 = 0, so d^4 = d^2+1 */
133 r.coeffs[0] = -x.coeffs[3];
134 r.coeffs[1] = x.coeffs[0];
135 r.coeffs[2] = x.coeffs[1] + x.coeffs[3];
136 r.coeffs[3] = x.coeffs[2];
137 return r;
138}
139static inline Point point_mul(Point a, Point b)
140{
141 size_t i, j;
142 Point r;
143
144 /* Initialise r to be a, scaled by b's d^3 term */
145 for (j = 0; j < 4; j++)
146 r.coeffs[j] = a.coeffs[j] * b.coeffs[3];
147
148 /* Now iterate r = d*r + (next coefficient down), by Horner's rule */
149 for (i = 3; i-- > 0 ;) {
150 r = point_mul_by_d(r);
151 for (j = 0; j < 4; j++)
152 r.coeffs[j] += a.coeffs[j] * b.coeffs[i];
153 }
154
155 return r;
156}
157static inline bool point_equal(Point a, Point b)
158{
159 size_t i;
160 for (i = 0; i < 4; i++)
161 if (a.coeffs[i] != b.coeffs[i])
162 return false;
163 return true;
164}
165
166/*
167 * Return the Point corresponding to a rotation of s steps around the
168 * origin, i.e. a rotation by 30*s degrees or s*pi/6 radians.
169 */
170static inline Point point_rot(int s)
171{
172 Point r = {{ 1, 0, 0, 0 }};
173 Point dpower = {{ 0, 1, 0, 0 }};
174
175 /* Reduce to a sensible range */
176 s = s % 12;
177 if (s < 0)
178 s += 12;
179
180 while (true) {
181 if (s & 1)
182 r = point_mul(r, dpower);
183 s >>= 1;
184 if (!s)
185 break;
186 dpower = point_mul(dpower, dpower);
187 }
188
189 return r;
190}
191
192/*
193 * SpectreContext is the shared context of a whole run of the
194 * algorithm. Its 'prototype' SpectreCoords object represents the
195 * coordinates of the starting Spectre, and is extended as necessary;
196 * any other SpectreCoord that needs extending will copy the
197 * higher-order values from ctx->prototype as needed, so that once
198 * each choice has been made, it remains consistent.
199 *
200 * When we're inventing a random piece of tiling in the first place,
201 * we append to ctx->prototype by choosing a random (but legal)
202 * higher-level metatile for the current topmost one to turn out to be
203 * part of. When we're replaying a generation whose parameters are
204 * already stored, we don't have a random_state, and we make fixed
205 * decisions if not enough coordinates were provided, as in the
206 * corresponding hat.c system.
207 *
208 * For a normal (non-testing) caller, spectrectx_generate() is the
209 * main useful function. It breadth-first searches a whole area to
210 * generate all the Spectres in it, starting from a (typically
211 * central) one with the coordinates of ctx->prototype. The callback
212 * function processes each Spectre as it's generated, and returns true
213 * or false to indicate whether that Spectre is within the bounds of
214 * the target area (and therefore the search should continue exploring
215 * its neighbours).
216 */
217typedef struct SpectreContext {
218 random_state *rs;
219 bool must_free_rs;
220 Point start_vertices[2]; /* vertices 0,1 of the starting Spectre */
221 int orientation; /* orientation to put in SpectrePatchParams */
222 SpectreCoords *prototype;
223} SpectreContext;
224
225void spectrectx_init_random(SpectreContext *ctx, random_state *rs);
226void spectrectx_init_from_params(
227 SpectreContext *ctx, const struct SpectrePatchParams *ps);
228void spectrectx_cleanup(SpectreContext *ctx);
229SpectreCoords *spectrectx_initial_coords(SpectreContext *ctx);
230void spectrectx_extend_coords(SpectreContext *ctx, SpectreCoords *hc,
231 size_t n);
232void spectrectx_step(SpectreContext *ctx, SpectreCoords *sc,
233 unsigned edge, unsigned *outedge);
234void spectrectx_generate(SpectreContext *ctx,
235 bool (*callback)(void *cbctx, const Spectre *spec),
236 void *cbctx);
237
238/* For spectre-test to directly generate a tiling of hexes */
239void spectrectx_step_hex(SpectreContext *ctx, SpectreCoords *sc,
240 size_t depth, unsigned edge, unsigned *outedge);
241
242/* Subroutines that step around the tiling specified by a SpectreCtx,
243 * delivering both plane and combinatorial coordinates as they go */
244Spectre *spectre_initial(SpectreContext *ctx);
245Spectre *spectre_adjacent(SpectreContext *ctx, const Spectre *src_spec,
246 unsigned src_edge, unsigned *dst_edge);
247
248/* For extracting the point coordinates */
249typedef struct Coord {
250 int c1, cr3; /* coefficients of 1 and sqrt(3) respectively */
251} Coord;
252
253static inline Coord point_x(Point p)
254{
255 Coord x = { 2 * p.coeffs[0] + p.coeffs[2], p.coeffs[1] };
256 return x;
257}
258
259static inline Coord point_y(Point p)
260{
261 Coord y = { 2 * p.coeffs[3] + p.coeffs[1], p.coeffs[2] };
262 return y;
263}
264
265static inline int coord_sign(Coord x)
266{
267 if (x.c1 == 0 && x.cr3 == 0)
268 return 0;
269 if (x.c1 >= 0 && x.cr3 >= 0)
270 return +1;
271 if (x.c1 <= 0 && x.cr3 <= 0)
272 return -1;
273
274 if (x.c1 * x.c1 > 3 * x.cr3 * x.cr3)
275 return x.c1 < 0 ? -1 : +1;
276 else
277 return x.cr3 < 0 ? -1 : +1;
278}
279
280static inline Coord coord_construct(int c1, int cr3)
281{
282 Coord c = { c1, cr3 };
283 return c;
284}
285
286static inline Coord coord_integer(int c1)
287{
288 return coord_construct(c1, 0);
289}
290
291static inline Coord coord_add(Coord a, Coord b)
292{
293 Coord sum;
294 sum.c1 = a.c1 + b.c1;
295 sum.cr3 = a.cr3 + b.cr3;
296 return sum;
297}
298
299static inline Coord coord_sub(Coord a, Coord b)
300{
301 Coord diff;
302 diff.c1 = a.c1 - b.c1;
303 diff.cr3 = a.cr3 - b.cr3;
304 return diff;
305}
306
307static inline Coord coord_mul(Coord a, Coord b)
308{
309 Coord prod;
310 prod.c1 = a.c1 * b.c1 + 3 * a.cr3 * b.cr3;
311 prod.cr3 = a.c1 * b.cr3 + a.cr3 * b.c1;
312 return prod;
313}
314
315static inline Coord coord_abs(Coord a)
316{
317 int sign = coord_sign(a);
318 Coord abs;
319 abs.c1 = a.c1 * sign;
320 abs.cr3 = a.cr3 * sign;
321 return abs;
322}
323
324static inline int coord_cmp(Coord a, Coord b)
325{
326 return coord_sign(coord_sub(a, b));
327}
diff --git a/apps/plugins/puzzles/src/spectre-tables-auto.h b/apps/plugins/puzzles/src/spectre-tables-auto.h
new file mode 100644
index 0000000000..a41c4e1d18
--- /dev/null
+++ b/apps/plugins/puzzles/src/spectre-tables-auto.h
@@ -0,0 +1,1220 @@
1/*
2 * Autogenerated transition tables for the Spectre tiling.
3 * Generated by auxiliary/spectre-gen.c.
4 */
5
6static const struct MapEntry hexmap_G[] = {
7 { true, 2, 5 }, /* edge 0 of hex 0 (F) */
8 { true, 3, 5 }, /* edge 1 of hex 0 (F) */
9 { true, 1, 0 }, /* edge 2 of hex 0 (F) */
10 { false, 2, 0 }, /* edge 3 of hex 0 (F) */
11 { false, 1, 2 }, /* edge 4 of hex 0 (F) */
12 { false, 1, 1 }, /* edge 5 of hex 0 (F) */
13 { true, 0, 2 }, /* edge 0 of hex 1 (X) */
14 { true, 3, 4 }, /* edge 1 of hex 1 (X) */
15 { false, 3, 1 }, /* edge 2 of hex 1 (X) */
16 { false, 3, 0 }, /* edge 3 of hex 1 (X) */
17 { false, 2, 2 }, /* edge 4 of hex 1 (X) */
18 { false, 2, 1 }, /* edge 5 of hex 1 (X) */
19 { false, 1, 0 }, /* edge 0 of hex 2 (G) */
20 { false, 0, 1 }, /* edge 1 of hex 2 (G) */
21 { true, 4, 1 }, /* edge 2 of hex 2 (G) */
22 { true, 5, 1 }, /* edge 3 of hex 2 (G) */
23 { true, 3, 0 }, /* edge 4 of hex 2 (G) */
24 { true, 0, 0 }, /* edge 5 of hex 2 (G) */
25 { true, 2, 4 }, /* edge 0 of hex 3 (S) */
26 { true, 5, 0 }, /* edge 1 of hex 3 (S) */
27 { true, 6, 0 }, /* edge 2 of hex 3 (S) */
28 { false, 3, 2 }, /* edge 3 of hex 3 (S) */
29 { true, 1, 1 }, /* edge 4 of hex 3 (S) */
30 { true, 0, 1 }, /* edge 5 of hex 3 (S) */
31 { true, 5, 2 }, /* edge 0 of hex 4 (P) */
32 { true, 2, 2 }, /* edge 1 of hex 4 (P) */
33 { false, 0, 0 }, /* edge 2 of hex 4 (P) */
34 { false, 5, 1 }, /* edge 3 of hex 4 (P) */
35 { false, 5, 0 }, /* edge 4 of hex 4 (P) */
36 { false, 4, 4 }, /* edge 5 of hex 4 (P) */
37 { true, 3, 1 }, /* edge 0 of hex 5 (D) */
38 { true, 2, 3 }, /* edge 1 of hex 5 (D) */
39 { true, 4, 0 }, /* edge 2 of hex 5 (D) */
40 { false, 4, 3 }, /* edge 3 of hex 5 (D) */
41 { false, 4, 2 }, /* edge 4 of hex 5 (D) */
42 { true, 6, 1 }, /* edge 5 of hex 5 (D) */
43 { true, 3, 2 }, /* edge 0 of hex 6 (J) */
44 { true, 5, 5 }, /* edge 1 of hex 6 (J) */
45 { false, 4, 1 }, /* edge 2 of hex 6 (J) */
46 { false, 4, 0 }, /* edge 3 of hex 6 (J) */
47 { false, 3, 4 }, /* edge 4 of hex 6 (J) */
48 { false, 3, 3 }, /* edge 5 of hex 6 (J) */
49};
50static const struct MapEdge hexedges_G[] = {
51 { 0, 2 },
52 { 2, 3 },
53 { 5, 3 },
54 { 8, 5 },
55 { 13, 5 },
56 { 18, 2 },
57};
58static const struct MapEntry hexin_G[] = {
59 { true, 4, 2 }, /* subedge 0 of edge 0 */
60 { true, 2, 1 }, /* subedge 1 of edge 0 */
61 { true, 2, 0 }, /* subedge 0 of edge 1 */
62 { true, 0, 5 }, /* subedge 1 of edge 1 */
63 { true, 0, 4 }, /* subedge 2 of edge 1 */
64 { true, 0, 3 }, /* subedge 0 of edge 2 */
65 { true, 1, 5 }, /* subedge 1 of edge 2 */
66 { true, 1, 4 }, /* subedge 2 of edge 2 */
67 { true, 1, 3 }, /* subedge 0 of edge 3 */
68 { true, 1, 2 }, /* subedge 1 of edge 3 */
69 { true, 3, 3 }, /* subedge 2 of edge 3 */
70 { true, 6, 5 }, /* subedge 3 of edge 3 */
71 { true, 6, 4 }, /* subedge 4 of edge 3 */
72 { true, 6, 3 }, /* subedge 0 of edge 4 */
73 { true, 6, 2 }, /* subedge 1 of edge 4 */
74 { true, 5, 4 }, /* subedge 2 of edge 4 */
75 { true, 5, 3 }, /* subedge 3 of edge 4 */
76 { true, 4, 5 }, /* subedge 4 of edge 4 */
77 { true, 4, 4 }, /* subedge 0 of edge 5 */
78 { true, 4, 3 }, /* subedge 1 of edge 5 */
79};
80static const struct MapEntry hexmap_D[] = {
81 { true, 2, 5 }, /* edge 0 of hex 0 (F) */
82 { true, 3, 5 }, /* edge 1 of hex 0 (F) */
83 { true, 1, 0 }, /* edge 2 of hex 0 (F) */
84 { false, 1, 3 }, /* edge 3 of hex 0 (F) */
85 { false, 1, 2 }, /* edge 4 of hex 0 (F) */
86 { false, 1, 1 }, /* edge 5 of hex 0 (F) */
87 { true, 0, 2 }, /* edge 0 of hex 1 (P) */
88 { true, 3, 4 }, /* edge 1 of hex 1 (P) */
89 { false, 3, 0 }, /* edge 2 of hex 1 (P) */
90 { false, 2, 1 }, /* edge 3 of hex 1 (P) */
91 { false, 2, 0 }, /* edge 4 of hex 1 (P) */
92 { false, 1, 4 }, /* edge 5 of hex 1 (P) */
93 { false, 1, 0 }, /* edge 0 of hex 2 (G) */
94 { false, 0, 2 }, /* edge 1 of hex 2 (G) */
95 { true, 4, 1 }, /* edge 2 of hex 2 (G) */
96 { true, 5, 1 }, /* edge 3 of hex 2 (G) */
97 { true, 3, 0 }, /* edge 4 of hex 2 (G) */
98 { true, 0, 0 }, /* edge 5 of hex 2 (G) */
99 { true, 2, 4 }, /* edge 0 of hex 3 (S) */
100 { true, 5, 0 }, /* edge 1 of hex 3 (S) */
101 { true, 6, 0 }, /* edge 2 of hex 3 (S) */
102 { false, 3, 1 }, /* edge 3 of hex 3 (S) */
103 { true, 1, 1 }, /* edge 4 of hex 3 (S) */
104 { true, 0, 1 }, /* edge 5 of hex 3 (S) */
105 { true, 5, 2 }, /* edge 0 of hex 4 (X) */
106 { true, 2, 2 }, /* edge 1 of hex 4 (X) */
107 { false, 0, 1 }, /* edge 2 of hex 4 (X) */
108 { false, 0, 0 }, /* edge 3 of hex 4 (X) */
109 { false, 5, 4 }, /* edge 4 of hex 4 (X) */
110 { false, 5, 3 }, /* edge 5 of hex 4 (X) */
111 { true, 3, 1 }, /* edge 0 of hex 5 (D) */
112 { true, 2, 3 }, /* edge 1 of hex 5 (D) */
113 { true, 4, 0 }, /* edge 2 of hex 5 (D) */
114 { false, 5, 2 }, /* edge 3 of hex 5 (D) */
115 { true, 7, 1 }, /* edge 4 of hex 5 (D) */
116 { true, 6, 1 }, /* edge 5 of hex 5 (D) */
117 { true, 3, 2 }, /* edge 0 of hex 6 (F) */
118 { true, 5, 5 }, /* edge 1 of hex 6 (F) */
119 { true, 7, 0 }, /* edge 2 of hex 6 (F) */
120 { false, 4, 0 }, /* edge 3 of hex 6 (F) */
121 { false, 3, 3 }, /* edge 4 of hex 6 (F) */
122 { false, 3, 2 }, /* edge 5 of hex 6 (F) */
123 { true, 6, 2 }, /* edge 0 of hex 7 (X) */
124 { true, 5, 4 }, /* edge 1 of hex 7 (X) */
125 { false, 5, 1 }, /* edge 2 of hex 7 (X) */
126 { false, 5, 0 }, /* edge 3 of hex 7 (X) */
127 { false, 4, 2 }, /* edge 4 of hex 7 (X) */
128 { false, 4, 1 }, /* edge 5 of hex 7 (X) */
129};
130static const struct MapEdge hexedges_D[] = {
131 { 0, 3 },
132 { 3, 5 },
133 { 8, 2 },
134 { 10, 4 },
135 { 14, 3 },
136 { 17, 5 },
137};
138static const struct MapEntry hexin_D[] = {
139 { true, 4, 3 }, /* subedge 0 of edge 0 */
140 { true, 4, 2 }, /* subedge 1 of edge 0 */
141 { true, 2, 1 }, /* subedge 2 of edge 0 */
142 { true, 2, 0 }, /* subedge 0 of edge 1 */
143 { true, 0, 5 }, /* subedge 1 of edge 1 */
144 { true, 0, 4 }, /* subedge 2 of edge 1 */
145 { true, 0, 3 }, /* subedge 3 of edge 1 */
146 { true, 1, 5 }, /* subedge 4 of edge 1 */
147 { true, 1, 4 }, /* subedge 0 of edge 2 */
148 { true, 1, 3 }, /* subedge 1 of edge 2 */
149 { true, 1, 2 }, /* subedge 0 of edge 3 */
150 { true, 3, 3 }, /* subedge 1 of edge 3 */
151 { true, 6, 5 }, /* subedge 2 of edge 3 */
152 { true, 6, 4 }, /* subedge 3 of edge 3 */
153 { true, 6, 3 }, /* subedge 0 of edge 4 */
154 { true, 7, 5 }, /* subedge 1 of edge 4 */
155 { true, 7, 4 }, /* subedge 2 of edge 4 */
156 { true, 7, 3 }, /* subedge 0 of edge 5 */
157 { true, 7, 2 }, /* subedge 1 of edge 5 */
158 { true, 5, 3 }, /* subedge 2 of edge 5 */
159 { true, 4, 5 }, /* subedge 3 of edge 5 */
160 { true, 4, 4 }, /* subedge 4 of edge 5 */
161};
162static const struct MapEntry hexmap_J[] = {
163 { true, 2, 5 }, /* edge 0 of hex 0 (F) */
164 { true, 3, 5 }, /* edge 1 of hex 0 (F) */
165 { true, 1, 0 }, /* edge 2 of hex 0 (F) */
166 { false, 1, 3 }, /* edge 3 of hex 0 (F) */
167 { false, 1, 2 }, /* edge 4 of hex 0 (F) */
168 { false, 1, 1 }, /* edge 5 of hex 0 (F) */
169 { true, 0, 2 }, /* edge 0 of hex 1 (P) */
170 { true, 3, 4 }, /* edge 1 of hex 1 (P) */
171 { false, 3, 0 }, /* edge 2 of hex 1 (P) */
172 { false, 2, 1 }, /* edge 3 of hex 1 (P) */
173 { false, 2, 0 }, /* edge 4 of hex 1 (P) */
174 { false, 1, 4 }, /* edge 5 of hex 1 (P) */
175 { false, 1, 0 }, /* edge 0 of hex 2 (G) */
176 { false, 0, 1 }, /* edge 1 of hex 2 (G) */
177 { true, 4, 1 }, /* edge 2 of hex 2 (G) */
178 { true, 5, 1 }, /* edge 3 of hex 2 (G) */
179 { true, 3, 0 }, /* edge 4 of hex 2 (G) */
180 { true, 0, 0 }, /* edge 5 of hex 2 (G) */
181 { true, 2, 4 }, /* edge 0 of hex 3 (S) */
182 { true, 5, 0 }, /* edge 1 of hex 3 (S) */
183 { true, 6, 0 }, /* edge 2 of hex 3 (S) */
184 { false, 3, 1 }, /* edge 3 of hex 3 (S) */
185 { true, 1, 1 }, /* edge 4 of hex 3 (S) */
186 { true, 0, 1 }, /* edge 5 of hex 3 (S) */
187 { true, 5, 2 }, /* edge 0 of hex 4 (Y) */
188 { true, 2, 2 }, /* edge 1 of hex 4 (Y) */
189 { false, 0, 0 }, /* edge 2 of hex 4 (Y) */
190 { false, 5, 4 }, /* edge 3 of hex 4 (Y) */
191 { false, 5, 3 }, /* edge 4 of hex 4 (Y) */
192 { false, 5, 2 }, /* edge 5 of hex 4 (Y) */
193 { true, 3, 1 }, /* edge 0 of hex 5 (D) */
194 { true, 2, 3 }, /* edge 1 of hex 5 (D) */
195 { true, 4, 0 }, /* edge 2 of hex 5 (D) */
196 { false, 5, 1 }, /* edge 3 of hex 5 (D) */
197 { true, 7, 1 }, /* edge 4 of hex 5 (D) */
198 { true, 6, 1 }, /* edge 5 of hex 5 (D) */
199 { true, 3, 2 }, /* edge 0 of hex 6 (F) */
200 { true, 5, 5 }, /* edge 1 of hex 6 (F) */
201 { true, 7, 0 }, /* edge 2 of hex 6 (F) */
202 { false, 3, 4 }, /* edge 3 of hex 6 (F) */
203 { false, 3, 3 }, /* edge 4 of hex 6 (F) */
204 { false, 3, 2 }, /* edge 5 of hex 6 (F) */
205 { true, 6, 2 }, /* edge 0 of hex 7 (P) */
206 { true, 5, 4 }, /* edge 1 of hex 7 (P) */
207 { false, 5, 0 }, /* edge 2 of hex 7 (P) */
208 { false, 4, 1 }, /* edge 3 of hex 7 (P) */
209 { false, 4, 0 }, /* edge 4 of hex 7 (P) */
210 { false, 3, 5 }, /* edge 5 of hex 7 (P) */
211};
212static const struct MapEdge hexedges_J[] = {
213 { 0, 2 },
214 { 2, 5 },
215 { 7, 2 },
216 { 9, 6 },
217 { 15, 2 },
218 { 17, 5 },
219};
220static const struct MapEntry hexin_J[] = {
221 { true, 4, 2 }, /* subedge 0 of edge 0 */
222 { true, 2, 1 }, /* subedge 1 of edge 0 */
223 { true, 2, 0 }, /* subedge 0 of edge 1 */
224 { true, 0, 5 }, /* subedge 1 of edge 1 */
225 { true, 0, 4 }, /* subedge 2 of edge 1 */
226 { true, 0, 3 }, /* subedge 3 of edge 1 */
227 { true, 1, 5 }, /* subedge 4 of edge 1 */
228 { true, 1, 4 }, /* subedge 0 of edge 2 */
229 { true, 1, 3 }, /* subedge 1 of edge 2 */
230 { true, 1, 2 }, /* subedge 0 of edge 3 */
231 { true, 3, 3 }, /* subedge 1 of edge 3 */
232 { true, 6, 5 }, /* subedge 2 of edge 3 */
233 { true, 6, 4 }, /* subedge 3 of edge 3 */
234 { true, 6, 3 }, /* subedge 4 of edge 3 */
235 { true, 7, 5 }, /* subedge 5 of edge 3 */
236 { true, 7, 4 }, /* subedge 0 of edge 4 */
237 { true, 7, 3 }, /* subedge 1 of edge 4 */
238 { true, 7, 2 }, /* subedge 0 of edge 5 */
239 { true, 5, 3 }, /* subedge 1 of edge 5 */
240 { true, 4, 5 }, /* subedge 2 of edge 5 */
241 { true, 4, 4 }, /* subedge 3 of edge 5 */
242 { true, 4, 3 }, /* subedge 4 of edge 5 */
243};
244static const struct MapEntry hexmap_L[] = {
245 { true, 2, 5 }, /* edge 0 of hex 0 (F) */
246 { true, 3, 5 }, /* edge 1 of hex 0 (F) */
247 { true, 1, 0 }, /* edge 2 of hex 0 (F) */
248 { false, 1, 3 }, /* edge 3 of hex 0 (F) */
249 { false, 1, 2 }, /* edge 4 of hex 0 (F) */
250 { false, 1, 1 }, /* edge 5 of hex 0 (F) */
251 { true, 0, 2 }, /* edge 0 of hex 1 (P) */
252 { true, 3, 4 }, /* edge 1 of hex 1 (P) */
253 { false, 3, 0 }, /* edge 2 of hex 1 (P) */
254 { false, 2, 1 }, /* edge 3 of hex 1 (P) */
255 { false, 2, 0 }, /* edge 4 of hex 1 (P) */
256 { false, 1, 4 }, /* edge 5 of hex 1 (P) */
257 { false, 1, 0 }, /* edge 0 of hex 2 (G) */
258 { false, 0, 1 }, /* edge 1 of hex 2 (G) */
259 { true, 4, 1 }, /* edge 2 of hex 2 (G) */
260 { true, 5, 1 }, /* edge 3 of hex 2 (G) */
261 { true, 3, 0 }, /* edge 4 of hex 2 (G) */
262 { true, 0, 0 }, /* edge 5 of hex 2 (G) */
263 { true, 2, 4 }, /* edge 0 of hex 3 (S) */
264 { true, 5, 0 }, /* edge 1 of hex 3 (S) */
265 { true, 6, 0 }, /* edge 2 of hex 3 (S) */
266 { false, 3, 1 }, /* edge 3 of hex 3 (S) */
267 { true, 1, 1 }, /* edge 4 of hex 3 (S) */
268 { true, 0, 1 }, /* edge 5 of hex 3 (S) */
269 { true, 5, 2 }, /* edge 0 of hex 4 (Y) */
270 { true, 2, 2 }, /* edge 1 of hex 4 (Y) */
271 { false, 0, 0 }, /* edge 2 of hex 4 (Y) */
272 { false, 5, 5 }, /* edge 3 of hex 4 (Y) */
273 { false, 5, 4 }, /* edge 4 of hex 4 (Y) */
274 { false, 5, 3 }, /* edge 5 of hex 4 (Y) */
275 { true, 3, 1 }, /* edge 0 of hex 5 (D) */
276 { true, 2, 3 }, /* edge 1 of hex 5 (D) */
277 { true, 4, 0 }, /* edge 2 of hex 5 (D) */
278 { false, 5, 2 }, /* edge 3 of hex 5 (D) */
279 { true, 7, 1 }, /* edge 4 of hex 5 (D) */
280 { true, 6, 1 }, /* edge 5 of hex 5 (D) */
281 { true, 3, 2 }, /* edge 0 of hex 6 (F) */
282 { true, 5, 5 }, /* edge 1 of hex 6 (F) */
283 { true, 7, 0 }, /* edge 2 of hex 6 (F) */
284 { false, 4, 0 }, /* edge 3 of hex 6 (F) */
285 { false, 3, 3 }, /* edge 4 of hex 6 (F) */
286 { false, 3, 2 }, /* edge 5 of hex 6 (F) */
287 { true, 6, 2 }, /* edge 0 of hex 7 (X) */
288 { true, 5, 4 }, /* edge 1 of hex 7 (X) */
289 { false, 5, 1 }, /* edge 2 of hex 7 (X) */
290 { false, 5, 0 }, /* edge 3 of hex 7 (X) */
291 { false, 4, 2 }, /* edge 4 of hex 7 (X) */
292 { false, 4, 1 }, /* edge 5 of hex 7 (X) */
293};
294static const struct MapEdge hexedges_L[] = {
295 { 0, 2 },
296 { 2, 5 },
297 { 7, 2 },
298 { 9, 4 },
299 { 13, 3 },
300 { 16, 6 },
301};
302static const struct MapEntry hexin_L[] = {
303 { true, 4, 2 }, /* subedge 0 of edge 0 */
304 { true, 2, 1 }, /* subedge 1 of edge 0 */
305 { true, 2, 0 }, /* subedge 0 of edge 1 */
306 { true, 0, 5 }, /* subedge 1 of edge 1 */
307 { true, 0, 4 }, /* subedge 2 of edge 1 */
308 { true, 0, 3 }, /* subedge 3 of edge 1 */
309 { true, 1, 5 }, /* subedge 4 of edge 1 */
310 { true, 1, 4 }, /* subedge 0 of edge 2 */
311 { true, 1, 3 }, /* subedge 1 of edge 2 */
312 { true, 1, 2 }, /* subedge 0 of edge 3 */
313 { true, 3, 3 }, /* subedge 1 of edge 3 */
314 { true, 6, 5 }, /* subedge 2 of edge 3 */
315 { true, 6, 4 }, /* subedge 3 of edge 3 */
316 { true, 6, 3 }, /* subedge 0 of edge 4 */
317 { true, 7, 5 }, /* subedge 1 of edge 4 */
318 { true, 7, 4 }, /* subedge 2 of edge 4 */
319 { true, 7, 3 }, /* subedge 0 of edge 5 */
320 { true, 7, 2 }, /* subedge 1 of edge 5 */
321 { true, 5, 3 }, /* subedge 2 of edge 5 */
322 { true, 4, 5 }, /* subedge 3 of edge 5 */
323 { true, 4, 4 }, /* subedge 4 of edge 5 */
324 { true, 4, 3 }, /* subedge 5 of edge 5 */
325};
326static const struct MapEntry hexmap_X[] = {
327 { true, 2, 5 }, /* edge 0 of hex 0 (F) */
328 { true, 3, 5 }, /* edge 1 of hex 0 (F) */
329 { true, 1, 0 }, /* edge 2 of hex 0 (F) */
330 { false, 2, 0 }, /* edge 3 of hex 0 (F) */
331 { false, 1, 2 }, /* edge 4 of hex 0 (F) */
332 { false, 1, 1 }, /* edge 5 of hex 0 (F) */
333 { true, 0, 2 }, /* edge 0 of hex 1 (Y) */
334 { true, 3, 4 }, /* edge 1 of hex 1 (Y) */
335 { false, 3, 0 }, /* edge 2 of hex 1 (Y) */
336 { false, 2, 3 }, /* edge 3 of hex 1 (Y) */
337 { false, 2, 2 }, /* edge 4 of hex 1 (Y) */
338 { false, 2, 1 }, /* edge 5 of hex 1 (Y) */
339 { false, 1, 0 }, /* edge 0 of hex 2 (G) */
340 { false, 0, 1 }, /* edge 1 of hex 2 (G) */
341 { true, 4, 1 }, /* edge 2 of hex 2 (G) */
342 { true, 5, 1 }, /* edge 3 of hex 2 (G) */
343 { true, 3, 0 }, /* edge 4 of hex 2 (G) */
344 { true, 0, 0 }, /* edge 5 of hex 2 (G) */
345 { true, 2, 4 }, /* edge 0 of hex 3 (S) */
346 { true, 5, 0 }, /* edge 1 of hex 3 (S) */
347 { true, 6, 0 }, /* edge 2 of hex 3 (S) */
348 { false, 3, 1 }, /* edge 3 of hex 3 (S) */
349 { true, 1, 1 }, /* edge 4 of hex 3 (S) */
350 { true, 0, 1 }, /* edge 5 of hex 3 (S) */
351 { true, 5, 2 }, /* edge 0 of hex 4 (Y) */
352 { true, 2, 2 }, /* edge 1 of hex 4 (Y) */
353 { false, 0, 0 }, /* edge 2 of hex 4 (Y) */
354 { false, 5, 4 }, /* edge 3 of hex 4 (Y) */
355 { false, 5, 3 }, /* edge 4 of hex 4 (Y) */
356 { false, 5, 2 }, /* edge 5 of hex 4 (Y) */
357 { true, 3, 1 }, /* edge 0 of hex 5 (D) */
358 { true, 2, 3 }, /* edge 1 of hex 5 (D) */
359 { true, 4, 0 }, /* edge 2 of hex 5 (D) */
360 { false, 5, 1 }, /* edge 3 of hex 5 (D) */
361 { true, 7, 1 }, /* edge 4 of hex 5 (D) */
362 { true, 6, 1 }, /* edge 5 of hex 5 (D) */
363 { true, 3, 2 }, /* edge 0 of hex 6 (F) */
364 { true, 5, 5 }, /* edge 1 of hex 6 (F) */
365 { true, 7, 0 }, /* edge 2 of hex 6 (F) */
366 { false, 3, 4 }, /* edge 3 of hex 6 (F) */
367 { false, 3, 3 }, /* edge 4 of hex 6 (F) */
368 { false, 3, 2 }, /* edge 5 of hex 6 (F) */
369 { true, 6, 2 }, /* edge 0 of hex 7 (P) */
370 { true, 5, 4 }, /* edge 1 of hex 7 (P) */
371 { false, 5, 0 }, /* edge 2 of hex 7 (P) */
372 { false, 4, 1 }, /* edge 3 of hex 7 (P) */
373 { false, 4, 0 }, /* edge 4 of hex 7 (P) */
374 { false, 3, 5 }, /* edge 5 of hex 7 (P) */
375};
376static const struct MapEdge hexedges_X[] = {
377 { 0, 2 },
378 { 2, 3 },
379 { 5, 4 },
380 { 9, 6 },
381 { 15, 2 },
382 { 17, 5 },
383};
384static const struct MapEntry hexin_X[] = {
385 { true, 4, 2 }, /* subedge 0 of edge 0 */
386 { true, 2, 1 }, /* subedge 1 of edge 0 */
387 { true, 2, 0 }, /* subedge 0 of edge 1 */
388 { true, 0, 5 }, /* subedge 1 of edge 1 */
389 { true, 0, 4 }, /* subedge 2 of edge 1 */
390 { true, 0, 3 }, /* subedge 0 of edge 2 */
391 { true, 1, 5 }, /* subedge 1 of edge 2 */
392 { true, 1, 4 }, /* subedge 2 of edge 2 */
393 { true, 1, 3 }, /* subedge 3 of edge 2 */
394 { true, 1, 2 }, /* subedge 0 of edge 3 */
395 { true, 3, 3 }, /* subedge 1 of edge 3 */
396 { true, 6, 5 }, /* subedge 2 of edge 3 */
397 { true, 6, 4 }, /* subedge 3 of edge 3 */
398 { true, 6, 3 }, /* subedge 4 of edge 3 */
399 { true, 7, 5 }, /* subedge 5 of edge 3 */
400 { true, 7, 4 }, /* subedge 0 of edge 4 */
401 { true, 7, 3 }, /* subedge 1 of edge 4 */
402 { true, 7, 2 }, /* subedge 0 of edge 5 */
403 { true, 5, 3 }, /* subedge 1 of edge 5 */
404 { true, 4, 5 }, /* subedge 2 of edge 5 */
405 { true, 4, 4 }, /* subedge 3 of edge 5 */
406 { true, 4, 3 }, /* subedge 4 of edge 5 */
407};
408static const struct MapEntry hexmap_P[] = {
409 { true, 2, 5 }, /* edge 0 of hex 0 (F) */
410 { true, 3, 5 }, /* edge 1 of hex 0 (F) */
411 { true, 1, 0 }, /* edge 2 of hex 0 (F) */
412 { false, 2, 0 }, /* edge 3 of hex 0 (F) */
413 { false, 1, 2 }, /* edge 4 of hex 0 (F) */
414 { false, 1, 1 }, /* edge 5 of hex 0 (F) */
415 { true, 0, 2 }, /* edge 0 of hex 1 (Y) */
416 { true, 3, 4 }, /* edge 1 of hex 1 (Y) */
417 { false, 3, 0 }, /* edge 2 of hex 1 (Y) */
418 { false, 2, 3 }, /* edge 3 of hex 1 (Y) */
419 { false, 2, 2 }, /* edge 4 of hex 1 (Y) */
420 { false, 2, 1 }, /* edge 5 of hex 1 (Y) */
421 { false, 1, 0 }, /* edge 0 of hex 2 (G) */
422 { false, 0, 1 }, /* edge 1 of hex 2 (G) */
423 { true, 4, 1 }, /* edge 2 of hex 2 (G) */
424 { true, 5, 1 }, /* edge 3 of hex 2 (G) */
425 { true, 3, 0 }, /* edge 4 of hex 2 (G) */
426 { true, 0, 0 }, /* edge 5 of hex 2 (G) */
427 { true, 2, 4 }, /* edge 0 of hex 3 (S) */
428 { true, 5, 0 }, /* edge 1 of hex 3 (S) */
429 { true, 6, 0 }, /* edge 2 of hex 3 (S) */
430 { false, 3, 1 }, /* edge 3 of hex 3 (S) */
431 { true, 1, 1 }, /* edge 4 of hex 3 (S) */
432 { true, 0, 1 }, /* edge 5 of hex 3 (S) */
433 { true, 5, 2 }, /* edge 0 of hex 4 (Y) */
434 { true, 2, 2 }, /* edge 1 of hex 4 (Y) */
435 { false, 0, 0 }, /* edge 2 of hex 4 (Y) */
436 { false, 5, 5 }, /* edge 3 of hex 4 (Y) */
437 { false, 5, 4 }, /* edge 4 of hex 4 (Y) */
438 { false, 5, 3 }, /* edge 5 of hex 4 (Y) */
439 { true, 3, 1 }, /* edge 0 of hex 5 (D) */
440 { true, 2, 3 }, /* edge 1 of hex 5 (D) */
441 { true, 4, 0 }, /* edge 2 of hex 5 (D) */
442 { false, 5, 2 }, /* edge 3 of hex 5 (D) */
443 { true, 7, 1 }, /* edge 4 of hex 5 (D) */
444 { true, 6, 1 }, /* edge 5 of hex 5 (D) */
445 { true, 3, 2 }, /* edge 0 of hex 6 (F) */
446 { true, 5, 5 }, /* edge 1 of hex 6 (F) */
447 { true, 7, 0 }, /* edge 2 of hex 6 (F) */
448 { false, 4, 0 }, /* edge 3 of hex 6 (F) */
449 { false, 3, 3 }, /* edge 4 of hex 6 (F) */
450 { false, 3, 2 }, /* edge 5 of hex 6 (F) */
451 { true, 6, 2 }, /* edge 0 of hex 7 (X) */
452 { true, 5, 4 }, /* edge 1 of hex 7 (X) */
453 { false, 5, 1 }, /* edge 2 of hex 7 (X) */
454 { false, 5, 0 }, /* edge 3 of hex 7 (X) */
455 { false, 4, 2 }, /* edge 4 of hex 7 (X) */
456 { false, 4, 1 }, /* edge 5 of hex 7 (X) */
457};
458static const struct MapEdge hexedges_P[] = {
459 { 0, 2 },
460 { 2, 3 },
461 { 5, 4 },
462 { 9, 4 },
463 { 13, 3 },
464 { 16, 6 },
465};
466static const struct MapEntry hexin_P[] = {
467 { true, 4, 2 }, /* subedge 0 of edge 0 */
468 { true, 2, 1 }, /* subedge 1 of edge 0 */
469 { true, 2, 0 }, /* subedge 0 of edge 1 */
470 { true, 0, 5 }, /* subedge 1 of edge 1 */
471 { true, 0, 4 }, /* subedge 2 of edge 1 */
472 { true, 0, 3 }, /* subedge 0 of edge 2 */
473 { true, 1, 5 }, /* subedge 1 of edge 2 */
474 { true, 1, 4 }, /* subedge 2 of edge 2 */
475 { true, 1, 3 }, /* subedge 3 of edge 2 */
476 { true, 1, 2 }, /* subedge 0 of edge 3 */
477 { true, 3, 3 }, /* subedge 1 of edge 3 */
478 { true, 6, 5 }, /* subedge 2 of edge 3 */
479 { true, 6, 4 }, /* subedge 3 of edge 3 */
480 { true, 6, 3 }, /* subedge 0 of edge 4 */
481 { true, 7, 5 }, /* subedge 1 of edge 4 */
482 { true, 7, 4 }, /* subedge 2 of edge 4 */
483 { true, 7, 3 }, /* subedge 0 of edge 5 */
484 { true, 7, 2 }, /* subedge 1 of edge 5 */
485 { true, 5, 3 }, /* subedge 2 of edge 5 */
486 { true, 4, 5 }, /* subedge 3 of edge 5 */
487 { true, 4, 4 }, /* subedge 4 of edge 5 */
488 { true, 4, 3 }, /* subedge 5 of edge 5 */
489};
490static const struct MapEntry hexmap_S[] = {
491 { true, 2, 5 }, /* edge 0 of hex 0 (L) */
492 { true, 3, 5 }, /* edge 1 of hex 0 (L) */
493 { true, 1, 0 }, /* edge 2 of hex 0 (L) */
494 { false, 1, 1 }, /* edge 3 of hex 0 (L) */
495 { false, 1, 0 }, /* edge 4 of hex 0 (L) */
496 { false, 0, 4 }, /* edge 5 of hex 0 (L) */
497 { true, 0, 2 }, /* edge 0 of hex 1 (P) */
498 { true, 3, 4 }, /* edge 1 of hex 1 (P) */
499 { false, 3, 0 }, /* edge 2 of hex 1 (P) */
500 { false, 2, 1 }, /* edge 3 of hex 1 (P) */
501 { false, 2, 0 }, /* edge 4 of hex 1 (P) */
502 { false, 1, 2 }, /* edge 5 of hex 1 (P) */
503 { false, 0, 3 }, /* edge 0 of hex 2 (G) */
504 { false, 0, 2 }, /* edge 1 of hex 2 (G) */
505 { true, 4, 1 }, /* edge 2 of hex 2 (G) */
506 { true, 5, 1 }, /* edge 3 of hex 2 (G) */
507 { true, 3, 0 }, /* edge 4 of hex 2 (G) */
508 { true, 0, 0 }, /* edge 5 of hex 2 (G) */
509 { true, 2, 4 }, /* edge 0 of hex 3 (S) */
510 { true, 5, 0 }, /* edge 1 of hex 3 (S) */
511 { true, 6, 0 }, /* edge 2 of hex 3 (S) */
512 { false, 3, 1 }, /* edge 3 of hex 3 (S) */
513 { true, 1, 1 }, /* edge 4 of hex 3 (S) */
514 { true, 0, 1 }, /* edge 5 of hex 3 (S) */
515 { true, 5, 2 }, /* edge 0 of hex 4 (X) */
516 { true, 2, 2 }, /* edge 1 of hex 4 (X) */
517 { false, 0, 1 }, /* edge 2 of hex 4 (X) */
518 { false, 0, 0 }, /* edge 3 of hex 4 (X) */
519 { false, 5, 4 }, /* edge 4 of hex 4 (X) */
520 { false, 5, 3 }, /* edge 5 of hex 4 (X) */
521 { true, 3, 1 }, /* edge 0 of hex 5 (D) */
522 { true, 2, 3 }, /* edge 1 of hex 5 (D) */
523 { true, 4, 0 }, /* edge 2 of hex 5 (D) */
524 { false, 5, 2 }, /* edge 3 of hex 5 (D) */
525 { true, 7, 1 }, /* edge 4 of hex 5 (D) */
526 { true, 6, 1 }, /* edge 5 of hex 5 (D) */
527 { true, 3, 2 }, /* edge 0 of hex 6 (F) */
528 { true, 5, 5 }, /* edge 1 of hex 6 (F) */
529 { true, 7, 0 }, /* edge 2 of hex 6 (F) */
530 { false, 4, 0 }, /* edge 3 of hex 6 (F) */
531 { false, 3, 3 }, /* edge 4 of hex 6 (F) */
532 { false, 3, 2 }, /* edge 5 of hex 6 (F) */
533 { true, 6, 2 }, /* edge 0 of hex 7 (X) */
534 { true, 5, 4 }, /* edge 1 of hex 7 (X) */
535 { false, 5, 1 }, /* edge 2 of hex 7 (X) */
536 { false, 5, 0 }, /* edge 3 of hex 7 (X) */
537 { false, 4, 2 }, /* edge 4 of hex 7 (X) */
538 { false, 4, 1 }, /* edge 5 of hex 7 (X) */
539};
540static const struct MapEdge hexedges_S[] = {
541 { 0, 5 },
542 { 5, 3 },
543 { 8, 2 },
544 { 10, 4 },
545 { 14, 3 },
546 { 17, 5 },
547};
548static const struct MapEntry hexin_S[] = {
549 { true, 4, 3 }, /* subedge 0 of edge 0 */
550 { true, 4, 2 }, /* subedge 1 of edge 0 */
551 { true, 2, 1 }, /* subedge 2 of edge 0 */
552 { true, 2, 0 }, /* subedge 3 of edge 0 */
553 { true, 0, 5 }, /* subedge 4 of edge 0 */
554 { true, 0, 4 }, /* subedge 0 of edge 1 */
555 { true, 0, 3 }, /* subedge 1 of edge 1 */
556 { true, 1, 5 }, /* subedge 2 of edge 1 */
557 { true, 1, 4 }, /* subedge 0 of edge 2 */
558 { true, 1, 3 }, /* subedge 1 of edge 2 */
559 { true, 1, 2 }, /* subedge 0 of edge 3 */
560 { true, 3, 3 }, /* subedge 1 of edge 3 */
561 { true, 6, 5 }, /* subedge 2 of edge 3 */
562 { true, 6, 4 }, /* subedge 3 of edge 3 */
563 { true, 6, 3 }, /* subedge 0 of edge 4 */
564 { true, 7, 5 }, /* subedge 1 of edge 4 */
565 { true, 7, 4 }, /* subedge 2 of edge 4 */
566 { true, 7, 3 }, /* subedge 0 of edge 5 */
567 { true, 7, 2 }, /* subedge 1 of edge 5 */
568 { true, 5, 3 }, /* subedge 2 of edge 5 */
569 { true, 4, 5 }, /* subedge 3 of edge 5 */
570 { true, 4, 4 }, /* subedge 4 of edge 5 */
571};
572static const struct MapEntry hexmap_F[] = {
573 { true, 2, 5 }, /* edge 0 of hex 0 (F) */
574 { true, 3, 5 }, /* edge 1 of hex 0 (F) */
575 { true, 1, 0 }, /* edge 2 of hex 0 (F) */
576 { false, 1, 3 }, /* edge 3 of hex 0 (F) */
577 { false, 1, 2 }, /* edge 4 of hex 0 (F) */
578 { false, 1, 1 }, /* edge 5 of hex 0 (F) */
579 { true, 0, 2 }, /* edge 0 of hex 1 (P) */
580 { true, 3, 4 }, /* edge 1 of hex 1 (P) */
581 { false, 3, 0 }, /* edge 2 of hex 1 (P) */
582 { false, 2, 1 }, /* edge 3 of hex 1 (P) */
583 { false, 2, 0 }, /* edge 4 of hex 1 (P) */
584 { false, 1, 4 }, /* edge 5 of hex 1 (P) */
585 { false, 1, 0 }, /* edge 0 of hex 2 (G) */
586 { false, 0, 1 }, /* edge 1 of hex 2 (G) */
587 { true, 4, 1 }, /* edge 2 of hex 2 (G) */
588 { true, 5, 1 }, /* edge 3 of hex 2 (G) */
589 { true, 3, 0 }, /* edge 4 of hex 2 (G) */
590 { true, 0, 0 }, /* edge 5 of hex 2 (G) */
591 { true, 2, 4 }, /* edge 0 of hex 3 (S) */
592 { true, 5, 0 }, /* edge 1 of hex 3 (S) */
593 { true, 6, 0 }, /* edge 2 of hex 3 (S) */
594 { false, 3, 1 }, /* edge 3 of hex 3 (S) */
595 { true, 1, 1 }, /* edge 4 of hex 3 (S) */
596 { true, 0, 1 }, /* edge 5 of hex 3 (S) */
597 { true, 5, 2 }, /* edge 0 of hex 4 (Y) */
598 { true, 2, 2 }, /* edge 1 of hex 4 (Y) */
599 { false, 0, 0 }, /* edge 2 of hex 4 (Y) */
600 { false, 5, 4 }, /* edge 3 of hex 4 (Y) */
601 { false, 5, 3 }, /* edge 4 of hex 4 (Y) */
602 { false, 5, 2 }, /* edge 5 of hex 4 (Y) */
603 { true, 3, 1 }, /* edge 0 of hex 5 (D) */
604 { true, 2, 3 }, /* edge 1 of hex 5 (D) */
605 { true, 4, 0 }, /* edge 2 of hex 5 (D) */
606 { false, 5, 1 }, /* edge 3 of hex 5 (D) */
607 { true, 7, 1 }, /* edge 4 of hex 5 (D) */
608 { true, 6, 1 }, /* edge 5 of hex 5 (D) */
609 { true, 3, 2 }, /* edge 0 of hex 6 (F) */
610 { true, 5, 5 }, /* edge 1 of hex 6 (F) */
611 { true, 7, 0 }, /* edge 2 of hex 6 (F) */
612 { false, 4, 0 }, /* edge 3 of hex 6 (F) */
613 { false, 3, 3 }, /* edge 4 of hex 6 (F) */
614 { false, 3, 2 }, /* edge 5 of hex 6 (F) */
615 { true, 6, 2 }, /* edge 0 of hex 7 (Y) */
616 { true, 5, 4 }, /* edge 1 of hex 7 (Y) */
617 { false, 5, 0 }, /* edge 2 of hex 7 (Y) */
618 { false, 4, 3 }, /* edge 3 of hex 7 (Y) */
619 { false, 4, 2 }, /* edge 4 of hex 7 (Y) */
620 { false, 4, 1 }, /* edge 5 of hex 7 (Y) */
621};
622static const struct MapEdge hexedges_F[] = {
623 { 0, 2 },
624 { 2, 5 },
625 { 7, 2 },
626 { 9, 4 },
627 { 13, 4 },
628 { 17, 5 },
629};
630static const struct MapEntry hexin_F[] = {
631 { true, 4, 2 }, /* subedge 0 of edge 0 */
632 { true, 2, 1 }, /* subedge 1 of edge 0 */
633 { true, 2, 0 }, /* subedge 0 of edge 1 */
634 { true, 0, 5 }, /* subedge 1 of edge 1 */
635 { true, 0, 4 }, /* subedge 2 of edge 1 */
636 { true, 0, 3 }, /* subedge 3 of edge 1 */
637 { true, 1, 5 }, /* subedge 4 of edge 1 */
638 { true, 1, 4 }, /* subedge 0 of edge 2 */
639 { true, 1, 3 }, /* subedge 1 of edge 2 */
640 { true, 1, 2 }, /* subedge 0 of edge 3 */
641 { true, 3, 3 }, /* subedge 1 of edge 3 */
642 { true, 6, 5 }, /* subedge 2 of edge 3 */
643 { true, 6, 4 }, /* subedge 3 of edge 3 */
644 { true, 6, 3 }, /* subedge 0 of edge 4 */
645 { true, 7, 5 }, /* subedge 1 of edge 4 */
646 { true, 7, 4 }, /* subedge 2 of edge 4 */
647 { true, 7, 3 }, /* subedge 3 of edge 4 */
648 { true, 7, 2 }, /* subedge 0 of edge 5 */
649 { true, 5, 3 }, /* subedge 1 of edge 5 */
650 { true, 4, 5 }, /* subedge 2 of edge 5 */
651 { true, 4, 4 }, /* subedge 3 of edge 5 */
652 { true, 4, 3 }, /* subedge 4 of edge 5 */
653};
654static const struct MapEntry hexmap_Y[] = {
655 { true, 2, 5 }, /* edge 0 of hex 0 (F) */
656 { true, 3, 5 }, /* edge 1 of hex 0 (F) */
657 { true, 1, 0 }, /* edge 2 of hex 0 (F) */
658 { false, 2, 0 }, /* edge 3 of hex 0 (F) */
659 { false, 1, 2 }, /* edge 4 of hex 0 (F) */
660 { false, 1, 1 }, /* edge 5 of hex 0 (F) */
661 { true, 0, 2 }, /* edge 0 of hex 1 (Y) */
662 { true, 3, 4 }, /* edge 1 of hex 1 (Y) */
663 { false, 3, 0 }, /* edge 2 of hex 1 (Y) */
664 { false, 2, 3 }, /* edge 3 of hex 1 (Y) */
665 { false, 2, 2 }, /* edge 4 of hex 1 (Y) */
666 { false, 2, 1 }, /* edge 5 of hex 1 (Y) */
667 { false, 1, 0 }, /* edge 0 of hex 2 (G) */
668 { false, 0, 1 }, /* edge 1 of hex 2 (G) */
669 { true, 4, 1 }, /* edge 2 of hex 2 (G) */
670 { true, 5, 1 }, /* edge 3 of hex 2 (G) */
671 { true, 3, 0 }, /* edge 4 of hex 2 (G) */
672 { true, 0, 0 }, /* edge 5 of hex 2 (G) */
673 { true, 2, 4 }, /* edge 0 of hex 3 (S) */
674 { true, 5, 0 }, /* edge 1 of hex 3 (S) */
675 { true, 6, 0 }, /* edge 2 of hex 3 (S) */
676 { false, 3, 1 }, /* edge 3 of hex 3 (S) */
677 { true, 1, 1 }, /* edge 4 of hex 3 (S) */
678 { true, 0, 1 }, /* edge 5 of hex 3 (S) */
679 { true, 5, 2 }, /* edge 0 of hex 4 (Y) */
680 { true, 2, 2 }, /* edge 1 of hex 4 (Y) */
681 { false, 0, 0 }, /* edge 2 of hex 4 (Y) */
682 { false, 5, 4 }, /* edge 3 of hex 4 (Y) */
683 { false, 5, 3 }, /* edge 4 of hex 4 (Y) */
684 { false, 5, 2 }, /* edge 5 of hex 4 (Y) */
685 { true, 3, 1 }, /* edge 0 of hex 5 (D) */
686 { true, 2, 3 }, /* edge 1 of hex 5 (D) */
687 { true, 4, 0 }, /* edge 2 of hex 5 (D) */
688 { false, 5, 1 }, /* edge 3 of hex 5 (D) */
689 { true, 7, 1 }, /* edge 4 of hex 5 (D) */
690 { true, 6, 1 }, /* edge 5 of hex 5 (D) */
691 { true, 3, 2 }, /* edge 0 of hex 6 (F) */
692 { true, 5, 5 }, /* edge 1 of hex 6 (F) */
693 { true, 7, 0 }, /* edge 2 of hex 6 (F) */
694 { false, 4, 0 }, /* edge 3 of hex 6 (F) */
695 { false, 3, 3 }, /* edge 4 of hex 6 (F) */
696 { false, 3, 2 }, /* edge 5 of hex 6 (F) */
697 { true, 6, 2 }, /* edge 0 of hex 7 (Y) */
698 { true, 5, 4 }, /* edge 1 of hex 7 (Y) */
699 { false, 5, 0 }, /* edge 2 of hex 7 (Y) */
700 { false, 4, 3 }, /* edge 3 of hex 7 (Y) */
701 { false, 4, 2 }, /* edge 4 of hex 7 (Y) */
702 { false, 4, 1 }, /* edge 5 of hex 7 (Y) */
703};
704static const struct MapEdge hexedges_Y[] = {
705 { 0, 2 },
706 { 2, 3 },
707 { 5, 4 },
708 { 9, 4 },
709 { 13, 4 },
710 { 17, 5 },
711};
712static const struct MapEntry hexin_Y[] = {
713 { true, 4, 2 }, /* subedge 0 of edge 0 */
714 { true, 2, 1 }, /* subedge 1 of edge 0 */
715 { true, 2, 0 }, /* subedge 0 of edge 1 */
716 { true, 0, 5 }, /* subedge 1 of edge 1 */
717 { true, 0, 4 }, /* subedge 2 of edge 1 */
718 { true, 0, 3 }, /* subedge 0 of edge 2 */
719 { true, 1, 5 }, /* subedge 1 of edge 2 */
720 { true, 1, 4 }, /* subedge 2 of edge 2 */
721 { true, 1, 3 }, /* subedge 3 of edge 2 */
722 { true, 1, 2 }, /* subedge 0 of edge 3 */
723 { true, 3, 3 }, /* subedge 1 of edge 3 */
724 { true, 6, 5 }, /* subedge 2 of edge 3 */
725 { true, 6, 4 }, /* subedge 3 of edge 3 */
726 { true, 6, 3 }, /* subedge 0 of edge 4 */
727 { true, 7, 5 }, /* subedge 1 of edge 4 */
728 { true, 7, 4 }, /* subedge 2 of edge 4 */
729 { true, 7, 3 }, /* subedge 3 of edge 4 */
730 { true, 7, 2 }, /* subedge 0 of edge 5 */
731 { true, 5, 3 }, /* subedge 1 of edge 5 */
732 { true, 4, 5 }, /* subedge 2 of edge 5 */
733 { true, 4, 4 }, /* subedge 3 of edge 5 */
734 { true, 4, 3 }, /* subedge 4 of edge 5 */
735};
736static const struct MapEntry specmap_G[] = {
737 { false, 2, 2 }, /* edge 0 of Spectre 0 */
738 { false, 2, 1 }, /* edge 1 of Spectre 0 */
739 { false, 2, 0 }, /* edge 2 of Spectre 0 */
740 { false, 1, 2 }, /* edge 3 of Spectre 0 */
741 { false, 1, 1 }, /* edge 4 of Spectre 0 */
742 { false, 1, 0 }, /* edge 5 of Spectre 0 */
743 { false, 0, 2 }, /* edge 6 of Spectre 0 */
744 { false, 0, 1 }, /* edge 7 of Spectre 0 */
745 { false, 0, 0 }, /* edge 8 of Spectre 0 */
746 { false, 5, 2 }, /* edge 9 of Spectre 0 */
747 { true, 1, 7 }, /* edge 10 of Spectre 0 */
748 { true, 1, 6 }, /* edge 11 of Spectre 0 */
749 { true, 1, 5 }, /* edge 12 of Spectre 0 */
750 { true, 1, 4 }, /* edge 13 of Spectre 0 */
751 { false, 4, 1 }, /* edge 0 of Spectre 1 */
752 { false, 4, 0 }, /* edge 1 of Spectre 1 */
753 { false, 3, 1 }, /* edge 2 of Spectre 1 */
754 { false, 3, 0 }, /* edge 3 of Spectre 1 */
755 { true, 0, 13 }, /* edge 4 of Spectre 1 */
756 { true, 0, 12 }, /* edge 5 of Spectre 1 */
757 { true, 0, 11 }, /* edge 6 of Spectre 1 */
758 { true, 0, 10 }, /* edge 7 of Spectre 1 */
759 { false, 5, 1 }, /* edge 8 of Spectre 1 */
760 { false, 5, 0 }, /* edge 9 of Spectre 1 */
761 { false, 4, 5 }, /* edge 10 of Spectre 1 */
762 { false, 4, 4 }, /* edge 11 of Spectre 1 */
763 { false, 4, 3 }, /* edge 12 of Spectre 1 */
764 { false, 4, 2 }, /* edge 13 of Spectre 1 */
765};
766static const struct MapEdge specedges_G[] = {
767 { 0, 3 },
768 { 3, 3 },
769 { 6, 3 },
770 { 9, 2 },
771 { 11, 6 },
772 { 17, 3 },
773};
774static const struct MapEntry specin_G[] = {
775 { true, 0, 8 }, /* subedge 0 of edge 0 */
776 { true, 0, 7 }, /* subedge 1 of edge 0 */
777 { true, 0, 6 }, /* subedge 2 of edge 0 */
778 { true, 0, 5 }, /* subedge 0 of edge 1 */
779 { true, 0, 4 }, /* subedge 1 of edge 1 */
780 { true, 0, 3 }, /* subedge 2 of edge 1 */
781 { true, 0, 2 }, /* subedge 0 of edge 2 */
782 { true, 0, 1 }, /* subedge 1 of edge 2 */
783 { true, 0, 0 }, /* subedge 2 of edge 2 */
784 { true, 1, 3 }, /* subedge 0 of edge 3 */
785 { true, 1, 2 }, /* subedge 1 of edge 3 */
786 { true, 1, 1 }, /* subedge 0 of edge 4 */
787 { true, 1, 0 }, /* subedge 1 of edge 4 */
788 { true, 1, 13 }, /* subedge 2 of edge 4 */
789 { true, 1, 12 }, /* subedge 3 of edge 4 */
790 { true, 1, 11 }, /* subedge 4 of edge 4 */
791 { true, 1, 10 }, /* subedge 5 of edge 4 */
792 { true, 1, 9 }, /* subedge 0 of edge 5 */
793 { true, 1, 8 }, /* subedge 1 of edge 5 */
794 { true, 0, 9 }, /* subedge 2 of edge 5 */
795};
796static const struct MapEntry specmap_D[] = {
797 { false, 3, 0 }, /* edge 0 of Spectre 0 */
798 { false, 2, 2 }, /* edge 1 of Spectre 0 */
799 { false, 2, 1 }, /* edge 2 of Spectre 0 */
800 { false, 2, 0 }, /* edge 3 of Spectre 0 */
801 { false, 1, 1 }, /* edge 4 of Spectre 0 */
802 { false, 1, 0 }, /* edge 5 of Spectre 0 */
803 { false, 0, 1 }, /* edge 6 of Spectre 0 */
804 { false, 0, 0 }, /* edge 7 of Spectre 0 */
805 { false, 5, 1 }, /* edge 8 of Spectre 0 */
806 { false, 5, 0 }, /* edge 9 of Spectre 0 */
807 { false, 4, 2 }, /* edge 10 of Spectre 0 */
808 { false, 4, 1 }, /* edge 11 of Spectre 0 */
809 { false, 4, 0 }, /* edge 12 of Spectre 0 */
810 { false, 3, 1 }, /* edge 13 of Spectre 0 */
811};
812static const struct MapEdge specedges_D[] = {
813 { 0, 2 },
814 { 2, 2 },
815 { 4, 3 },
816 { 7, 2 },
817 { 9, 3 },
818 { 12, 2 },
819};
820static const struct MapEntry specin_D[] = {
821 { true, 0, 7 }, /* subedge 0 of edge 0 */
822 { true, 0, 6 }, /* subedge 1 of edge 0 */
823 { true, 0, 5 }, /* subedge 0 of edge 1 */
824 { true, 0, 4 }, /* subedge 1 of edge 1 */
825 { true, 0, 3 }, /* subedge 0 of edge 2 */
826 { true, 0, 2 }, /* subedge 1 of edge 2 */
827 { true, 0, 1 }, /* subedge 2 of edge 2 */
828 { true, 0, 0 }, /* subedge 0 of edge 3 */
829 { true, 0, 13 }, /* subedge 1 of edge 3 */
830 { true, 0, 12 }, /* subedge 0 of edge 4 */
831 { true, 0, 11 }, /* subedge 1 of edge 4 */
832 { true, 0, 10 }, /* subedge 2 of edge 4 */
833 { true, 0, 9 }, /* subedge 0 of edge 5 */
834 { true, 0, 8 }, /* subedge 1 of edge 5 */
835};
836static const struct MapEntry specmap_J[] = {
837 { false, 3, 0 }, /* edge 0 of Spectre 0 */
838 { false, 2, 2 }, /* edge 1 of Spectre 0 */
839 { false, 2, 1 }, /* edge 2 of Spectre 0 */
840 { false, 2, 0 }, /* edge 3 of Spectre 0 */
841 { false, 1, 1 }, /* edge 4 of Spectre 0 */
842 { false, 1, 0 }, /* edge 5 of Spectre 0 */
843 { false, 0, 2 }, /* edge 6 of Spectre 0 */
844 { false, 0, 1 }, /* edge 7 of Spectre 0 */
845 { false, 0, 0 }, /* edge 8 of Spectre 0 */
846 { false, 5, 1 }, /* edge 9 of Spectre 0 */
847 { false, 5, 0 }, /* edge 10 of Spectre 0 */
848 { false, 4, 2 }, /* edge 11 of Spectre 0 */
849 { false, 4, 1 }, /* edge 12 of Spectre 0 */
850 { false, 4, 0 }, /* edge 13 of Spectre 0 */
851};
852static const struct MapEdge specedges_J[] = {
853 { 0, 3 },
854 { 3, 2 },
855 { 5, 3 },
856 { 8, 1 },
857 { 9, 3 },
858 { 12, 2 },
859};
860static const struct MapEntry specin_J[] = {
861 { true, 0, 8 }, /* subedge 0 of edge 0 */
862 { true, 0, 7 }, /* subedge 1 of edge 0 */
863 { true, 0, 6 }, /* subedge 2 of edge 0 */
864 { true, 0, 5 }, /* subedge 0 of edge 1 */
865 { true, 0, 4 }, /* subedge 1 of edge 1 */
866 { true, 0, 3 }, /* subedge 0 of edge 2 */
867 { true, 0, 2 }, /* subedge 1 of edge 2 */
868 { true, 0, 1 }, /* subedge 2 of edge 2 */
869 { true, 0, 0 }, /* subedge 0 of edge 3 */
870 { true, 0, 13 }, /* subedge 0 of edge 4 */
871 { true, 0, 12 }, /* subedge 1 of edge 4 */
872 { true, 0, 11 }, /* subedge 2 of edge 4 */
873 { true, 0, 10 }, /* subedge 0 of edge 5 */
874 { true, 0, 9 }, /* subedge 1 of edge 5 */
875};
876static const struct MapEntry specmap_L[] = {
877 { false, 3, 0 }, /* edge 0 of Spectre 0 */
878 { false, 2, 2 }, /* edge 1 of Spectre 0 */
879 { false, 2, 1 }, /* edge 2 of Spectre 0 */
880 { false, 2, 0 }, /* edge 3 of Spectre 0 */
881 { false, 1, 1 }, /* edge 4 of Spectre 0 */
882 { false, 1, 0 }, /* edge 5 of Spectre 0 */
883 { false, 0, 2 }, /* edge 6 of Spectre 0 */
884 { false, 0, 1 }, /* edge 7 of Spectre 0 */
885 { false, 0, 0 }, /* edge 8 of Spectre 0 */
886 { false, 5, 0 }, /* edge 9 of Spectre 0 */
887 { false, 4, 2 }, /* edge 10 of Spectre 0 */
888 { false, 4, 1 }, /* edge 11 of Spectre 0 */
889 { false, 4, 0 }, /* edge 12 of Spectre 0 */
890 { false, 3, 1 }, /* edge 13 of Spectre 0 */
891};
892static const struct MapEdge specedges_L[] = {
893 { 0, 3 },
894 { 3, 2 },
895 { 5, 3 },
896 { 8, 2 },
897 { 10, 3 },
898 { 13, 1 },
899};
900static const struct MapEntry specin_L[] = {
901 { true, 0, 8 }, /* subedge 0 of edge 0 */
902 { true, 0, 7 }, /* subedge 1 of edge 0 */
903 { true, 0, 6 }, /* subedge 2 of edge 0 */
904 { true, 0, 5 }, /* subedge 0 of edge 1 */
905 { true, 0, 4 }, /* subedge 1 of edge 1 */
906 { true, 0, 3 }, /* subedge 0 of edge 2 */
907 { true, 0, 2 }, /* subedge 1 of edge 2 */
908 { true, 0, 1 }, /* subedge 2 of edge 2 */
909 { true, 0, 0 }, /* subedge 0 of edge 3 */
910 { true, 0, 13 }, /* subedge 1 of edge 3 */
911 { true, 0, 12 }, /* subedge 0 of edge 4 */
912 { true, 0, 11 }, /* subedge 1 of edge 4 */
913 { true, 0, 10 }, /* subedge 2 of edge 4 */
914 { true, 0, 9 }, /* subedge 0 of edge 5 */
915};
916static const struct MapEntry specmap_X[] = {
917 { false, 3, 0 }, /* edge 0 of Spectre 0 */
918 { false, 2, 1 }, /* edge 1 of Spectre 0 */
919 { false, 2, 0 }, /* edge 2 of Spectre 0 */
920 { false, 1, 2 }, /* edge 3 of Spectre 0 */
921 { false, 1, 1 }, /* edge 4 of Spectre 0 */
922 { false, 1, 0 }, /* edge 5 of Spectre 0 */
923 { false, 0, 2 }, /* edge 6 of Spectre 0 */
924 { false, 0, 1 }, /* edge 7 of Spectre 0 */
925 { false, 0, 0 }, /* edge 8 of Spectre 0 */
926 { false, 5, 1 }, /* edge 9 of Spectre 0 */
927 { false, 5, 0 }, /* edge 10 of Spectre 0 */
928 { false, 4, 2 }, /* edge 11 of Spectre 0 */
929 { false, 4, 1 }, /* edge 12 of Spectre 0 */
930 { false, 4, 0 }, /* edge 13 of Spectre 0 */
931};
932static const struct MapEdge specedges_X[] = {
933 { 0, 3 },
934 { 3, 3 },
935 { 6, 2 },
936 { 8, 1 },
937 { 9, 3 },
938 { 12, 2 },
939};
940static const struct MapEntry specin_X[] = {
941 { true, 0, 8 }, /* subedge 0 of edge 0 */
942 { true, 0, 7 }, /* subedge 1 of edge 0 */
943 { true, 0, 6 }, /* subedge 2 of edge 0 */
944 { true, 0, 5 }, /* subedge 0 of edge 1 */
945 { true, 0, 4 }, /* subedge 1 of edge 1 */
946 { true, 0, 3 }, /* subedge 2 of edge 1 */
947 { true, 0, 2 }, /* subedge 0 of edge 2 */
948 { true, 0, 1 }, /* subedge 1 of edge 2 */
949 { true, 0, 0 }, /* subedge 0 of edge 3 */
950 { true, 0, 13 }, /* subedge 0 of edge 4 */
951 { true, 0, 12 }, /* subedge 1 of edge 4 */
952 { true, 0, 11 }, /* subedge 2 of edge 4 */
953 { true, 0, 10 }, /* subedge 0 of edge 5 */
954 { true, 0, 9 }, /* subedge 1 of edge 5 */
955};
956static const struct MapEntry specmap_P[] = {
957 { false, 3, 0 }, /* edge 0 of Spectre 0 */
958 { false, 2, 1 }, /* edge 1 of Spectre 0 */
959 { false, 2, 0 }, /* edge 2 of Spectre 0 */
960 { false, 1, 2 }, /* edge 3 of Spectre 0 */
961 { false, 1, 1 }, /* edge 4 of Spectre 0 */
962 { false, 1, 0 }, /* edge 5 of Spectre 0 */
963 { false, 0, 2 }, /* edge 6 of Spectre 0 */
964 { false, 0, 1 }, /* edge 7 of Spectre 0 */
965 { false, 0, 0 }, /* edge 8 of Spectre 0 */
966 { false, 5, 0 }, /* edge 9 of Spectre 0 */
967 { false, 4, 2 }, /* edge 10 of Spectre 0 */
968 { false, 4, 1 }, /* edge 11 of Spectre 0 */
969 { false, 4, 0 }, /* edge 12 of Spectre 0 */
970 { false, 3, 1 }, /* edge 13 of Spectre 0 */
971};
972static const struct MapEdge specedges_P[] = {
973 { 0, 3 },
974 { 3, 3 },
975 { 6, 2 },
976 { 8, 2 },
977 { 10, 3 },
978 { 13, 1 },
979};
980static const struct MapEntry specin_P[] = {
981 { true, 0, 8 }, /* subedge 0 of edge 0 */
982 { true, 0, 7 }, /* subedge 1 of edge 0 */
983 { true, 0, 6 }, /* subedge 2 of edge 0 */
984 { true, 0, 5 }, /* subedge 0 of edge 1 */
985 { true, 0, 4 }, /* subedge 1 of edge 1 */
986 { true, 0, 3 }, /* subedge 2 of edge 1 */
987 { true, 0, 2 }, /* subedge 0 of edge 2 */
988 { true, 0, 1 }, /* subedge 1 of edge 2 */
989 { true, 0, 0 }, /* subedge 0 of edge 3 */
990 { true, 0, 13 }, /* subedge 1 of edge 3 */
991 { true, 0, 12 }, /* subedge 0 of edge 4 */
992 { true, 0, 11 }, /* subedge 1 of edge 4 */
993 { true, 0, 10 }, /* subedge 2 of edge 4 */
994 { true, 0, 9 }, /* subedge 0 of edge 5 */
995};
996static const struct MapEntry specmap_S[] = {
997 { false, 3, 0 }, /* edge 0 of Spectre 0 */
998 { false, 2, 2 }, /* edge 1 of Spectre 0 */
999 { false, 2, 1 }, /* edge 2 of Spectre 0 */
1000 { false, 2, 0 }, /* edge 3 of Spectre 0 */
1001 { false, 0, 3 }, /* edge 4 of Spectre 0 */
1002 { false, 0, 2 }, /* edge 5 of Spectre 0 */
1003 { false, 0, 1 }, /* edge 6 of Spectre 0 */
1004 { false, 0, 0 }, /* edge 7 of Spectre 0 */
1005 { false, 5, 1 }, /* edge 8 of Spectre 0 */
1006 { false, 5, 0 }, /* edge 9 of Spectre 0 */
1007 { false, 4, 2 }, /* edge 10 of Spectre 0 */
1008 { false, 4, 1 }, /* edge 11 of Spectre 0 */
1009 { false, 4, 0 }, /* edge 12 of Spectre 0 */
1010 { false, 3, 1 }, /* edge 13 of Spectre 0 */
1011};
1012static const struct MapEdge specedges_S[] = {
1013 { 0, 6 },
1014 { 6, 2 },
1015 { 8, 3 },
1016 { 11, 2 },
1017 { 13, 3 },
1018 { 16, 2 },
1019};
1020static const struct MapEntry specin_S[] = {
1021 { true, 0, 7 }, /* subedge 0 of edge 0 */
1022 { true, 0, 6 }, /* subedge 1 of edge 0 */
1023 { true, 0, 5 }, /* subedge 2 of edge 0 */
1024 { true, 0, 4 }, /* subedge 3 of edge 0 */
1025 { false, 1, 1 }, /* subedge 4 of edge 0 */
1026 { false, 1, 0 }, /* subedge 5 of edge 0 */
1027 { false, 0, 5 }, /* subedge 0 of edge 1 */
1028 { false, 0, 4 }, /* subedge 1 of edge 1 */
1029 { true, 0, 3 }, /* subedge 0 of edge 2 */
1030 { true, 0, 2 }, /* subedge 1 of edge 2 */
1031 { true, 0, 1 }, /* subedge 2 of edge 2 */
1032 { true, 0, 0 }, /* subedge 0 of edge 3 */
1033 { true, 0, 13 }, /* subedge 1 of edge 3 */
1034 { true, 0, 12 }, /* subedge 0 of edge 4 */
1035 { true, 0, 11 }, /* subedge 1 of edge 4 */
1036 { true, 0, 10 }, /* subedge 2 of edge 4 */
1037 { true, 0, 9 }, /* subedge 0 of edge 5 */
1038 { true, 0, 8 }, /* subedge 1 of edge 5 */
1039};
1040static const struct MapEntry specmap_F[] = {
1041 { false, 3, 0 }, /* edge 0 of Spectre 0 */
1042 { false, 2, 2 }, /* edge 1 of Spectre 0 */
1043 { false, 2, 1 }, /* edge 2 of Spectre 0 */
1044 { false, 2, 0 }, /* edge 3 of Spectre 0 */
1045 { false, 1, 1 }, /* edge 4 of Spectre 0 */
1046 { false, 1, 0 }, /* edge 5 of Spectre 0 */
1047 { false, 0, 2 }, /* edge 6 of Spectre 0 */
1048 { false, 0, 1 }, /* edge 7 of Spectre 0 */
1049 { false, 0, 0 }, /* edge 8 of Spectre 0 */
1050 { false, 5, 1 }, /* edge 9 of Spectre 0 */
1051 { false, 5, 0 }, /* edge 10 of Spectre 0 */
1052 { false, 4, 1 }, /* edge 11 of Spectre 0 */
1053 { false, 4, 0 }, /* edge 12 of Spectre 0 */
1054 { false, 3, 1 }, /* edge 13 of Spectre 0 */
1055};
1056static const struct MapEdge specedges_F[] = {
1057 { 0, 3 },
1058 { 3, 2 },
1059 { 5, 3 },
1060 { 8, 2 },
1061 { 10, 2 },
1062 { 12, 2 },
1063};
1064static const struct MapEntry specin_F[] = {
1065 { true, 0, 8 }, /* subedge 0 of edge 0 */
1066 { true, 0, 7 }, /* subedge 1 of edge 0 */
1067 { true, 0, 6 }, /* subedge 2 of edge 0 */
1068 { true, 0, 5 }, /* subedge 0 of edge 1 */
1069 { true, 0, 4 }, /* subedge 1 of edge 1 */
1070 { true, 0, 3 }, /* subedge 0 of edge 2 */
1071 { true, 0, 2 }, /* subedge 1 of edge 2 */
1072 { true, 0, 1 }, /* subedge 2 of edge 2 */
1073 { true, 0, 0 }, /* subedge 0 of edge 3 */
1074 { true, 0, 13 }, /* subedge 1 of edge 3 */
1075 { true, 0, 12 }, /* subedge 0 of edge 4 */
1076 { true, 0, 11 }, /* subedge 1 of edge 4 */
1077 { true, 0, 10 }, /* subedge 0 of edge 5 */
1078 { true, 0, 9 }, /* subedge 1 of edge 5 */
1079};
1080static const struct MapEntry specmap_Y[] = {
1081 { false, 3, 0 }, /* edge 0 of Spectre 0 */
1082 { false, 2, 1 }, /* edge 1 of Spectre 0 */
1083 { false, 2, 0 }, /* edge 2 of Spectre 0 */
1084 { false, 1, 2 }, /* edge 3 of Spectre 0 */
1085 { false, 1, 1 }, /* edge 4 of Spectre 0 */
1086 { false, 1, 0 }, /* edge 5 of Spectre 0 */
1087 { false, 0, 2 }, /* edge 6 of Spectre 0 */
1088 { false, 0, 1 }, /* edge 7 of Spectre 0 */
1089 { false, 0, 0 }, /* edge 8 of Spectre 0 */
1090 { false, 5, 1 }, /* edge 9 of Spectre 0 */
1091 { false, 5, 0 }, /* edge 10 of Spectre 0 */
1092 { false, 4, 1 }, /* edge 11 of Spectre 0 */
1093 { false, 4, 0 }, /* edge 12 of Spectre 0 */
1094 { false, 3, 1 }, /* edge 13 of Spectre 0 */
1095};
1096static const struct MapEdge specedges_Y[] = {
1097 { 0, 3 },
1098 { 3, 3 },
1099 { 6, 2 },
1100 { 8, 2 },
1101 { 10, 2 },
1102 { 12, 2 },
1103};
1104static const struct MapEntry specin_Y[] = {
1105 { true, 0, 8 }, /* subedge 0 of edge 0 */
1106 { true, 0, 7 }, /* subedge 1 of edge 0 */
1107 { true, 0, 6 }, /* subedge 2 of edge 0 */
1108 { true, 0, 5 }, /* subedge 0 of edge 1 */
1109 { true, 0, 4 }, /* subedge 1 of edge 1 */
1110 { true, 0, 3 }, /* subedge 2 of edge 1 */
1111 { true, 0, 2 }, /* subedge 0 of edge 2 */
1112 { true, 0, 1 }, /* subedge 1 of edge 2 */
1113 { true, 0, 0 }, /* subedge 0 of edge 3 */
1114 { true, 0, 13 }, /* subedge 1 of edge 3 */
1115 { true, 0, 12 }, /* subedge 0 of edge 4 */
1116 { true, 0, 11 }, /* subedge 1 of edge 4 */
1117 { true, 0, 10 }, /* subedge 0 of edge 5 */
1118 { true, 0, 9 }, /* subedge 1 of edge 5 */
1119};
1120static const struct Possibility poss_G[] = {
1121 { HEX_G, 2, PROB_G },
1122 { HEX_D, 2, PROB_D },
1123 { HEX_J, 2, PROB_J },
1124 { HEX_L, 2, PROB_L },
1125 { HEX_X, 2, PROB_X },
1126 { HEX_P, 2, PROB_P },
1127 { HEX_S, 2, PROB_S },
1128 { HEX_F, 2, PROB_F },
1129 { HEX_Y, 2, PROB_Y },
1130};
1131static const struct Possibility poss_D[] = {
1132 { HEX_G, 5, PROB_G },
1133 { HEX_D, 5, PROB_D },
1134 { HEX_J, 5, PROB_J },
1135 { HEX_L, 5, PROB_L },
1136 { HEX_X, 5, PROB_X },
1137 { HEX_P, 5, PROB_P },
1138 { HEX_S, 5, PROB_S },
1139 { HEX_F, 5, PROB_F },
1140 { HEX_Y, 5, PROB_Y },
1141};
1142static const struct Possibility poss_J[] = {
1143 { HEX_G, 6, PROB_G },
1144};
1145static const struct Possibility poss_L[] = {
1146 { HEX_S, 0, PROB_S },
1147};
1148static const struct Possibility poss_X[] = {
1149 { HEX_G, 1, PROB_G },
1150 { HEX_D, 4, PROB_D },
1151 { HEX_D, 7, PROB_D },
1152 { HEX_L, 7, PROB_L },
1153 { HEX_P, 7, PROB_P },
1154 { HEX_S, 4, PROB_S },
1155 { HEX_S, 7, PROB_S },
1156};
1157static const struct Possibility poss_P[] = {
1158 { HEX_G, 4, PROB_G },
1159 { HEX_D, 1, PROB_D },
1160 { HEX_J, 1, PROB_J },
1161 { HEX_J, 7, PROB_J },
1162 { HEX_L, 1, PROB_L },
1163 { HEX_X, 7, PROB_X },
1164 { HEX_S, 1, PROB_S },
1165 { HEX_F, 1, PROB_F },
1166};
1167static const struct Possibility poss_S[] = {
1168 { HEX_G, 3, PROB_G },
1169 { HEX_D, 3, PROB_D },
1170 { HEX_J, 3, PROB_J },
1171 { HEX_L, 3, PROB_L },
1172 { HEX_X, 3, PROB_X },
1173 { HEX_P, 3, PROB_P },
1174 { HEX_S, 3, PROB_S },
1175 { HEX_F, 3, PROB_F },
1176 { HEX_Y, 3, PROB_Y },
1177};
1178static const struct Possibility poss_F[] = {
1179 { HEX_G, 0, PROB_G },
1180 { HEX_D, 0, PROB_D },
1181 { HEX_D, 6, PROB_D },
1182 { HEX_J, 0, PROB_J },
1183 { HEX_J, 6, PROB_J },
1184 { HEX_L, 0, PROB_L },
1185 { HEX_L, 6, PROB_L },
1186 { HEX_X, 0, PROB_X },
1187 { HEX_X, 6, PROB_X },
1188 { HEX_P, 0, PROB_P },
1189 { HEX_P, 6, PROB_P },
1190 { HEX_S, 6, PROB_S },
1191 { HEX_F, 0, PROB_F },
1192 { HEX_F, 6, PROB_F },
1193 { HEX_Y, 0, PROB_Y },
1194 { HEX_Y, 6, PROB_Y },
1195};
1196static const struct Possibility poss_Y[] = {
1197 { HEX_J, 4, PROB_J },
1198 { HEX_L, 4, PROB_L },
1199 { HEX_X, 1, PROB_X },
1200 { HEX_X, 4, PROB_X },
1201 { HEX_P, 1, PROB_P },
1202 { HEX_P, 4, PROB_P },
1203 { HEX_F, 4, PROB_F },
1204 { HEX_F, 7, PROB_F },
1205 { HEX_Y, 1, PROB_Y },
1206 { HEX_Y, 4, PROB_Y },
1207 { HEX_Y, 7, PROB_Y },
1208};
1209static const struct Possibility poss_spectre[] = {
1210 { HEX_G, 0, PROB_G },
1211 { HEX_G, 1, PROB_G },
1212 { HEX_D, 0, PROB_D },
1213 { HEX_J, 0, PROB_J },
1214 { HEX_L, 0, PROB_L },
1215 { HEX_X, 0, PROB_X },
1216 { HEX_P, 0, PROB_P },
1217 { HEX_S, 0, PROB_S },
1218 { HEX_F, 0, PROB_F },
1219 { HEX_Y, 0, PROB_Y },
1220};
diff --git a/apps/plugins/puzzles/src/spectre-tables-manual.h b/apps/plugins/puzzles/src/spectre-tables-manual.h
new file mode 100644
index 0000000000..d57e6597dd
--- /dev/null
+++ b/apps/plugins/puzzles/src/spectre-tables-manual.h
@@ -0,0 +1,160 @@
1/*
2 * Handwritten data tables for the Spectre tiling.
3 *
4 * This file is used by both the final tiling generator in spectre.c,
5 * and by spectre-gen.c which auto-generates further tables to go with
6 * these.
7 */
8
9/*
10 * We generate the Spectre tiling based on the substitution system of
11 * 9 types of marked hexagon shown in the paper.
12 *
13 * The substitution expands each hexagon into 8 others, except for the
14 * G hex which expands to only seven. The layout, numbered with the
15 * indices we use in the arrays here, is as follows:
16 *
17 * 0 1
18 * 2 3
19 * 4 5 6
20 * 7
21 *
22 * That is: the hexes are oriented with a pair of vertical edges.
23 * Hexes 0 and 1 are horizontally adjacent; 2 and 3 are adjacent on
24 * the next row, with 3 nestling between 0 and 1; 4,5,6 are on the
25 * third row with 5 between 2 and 3; and 7 is by itself on a fourth
26 * row, between 5 and 6. In the expansion of the G hex, #7 is the
27 * missing one, so its indices are still consecutive from 0.
28 *
29 * These arrays list the type of each child hex. The hexes also have
30 * orientations, but those aren't listed here, because only
31 * spectre-gen needs to know them - by the time it's finished
32 * autogenerating transition tables, the orientations are baked into
33 * those and don't need to be consulted separately.
34 */
35
36static const Hex subhexes_G[] = {
37 HEX_F,
38 HEX_X,
39 HEX_G,
40 HEX_S,
41 HEX_P,
42 HEX_D,
43 HEX_J,
44 /* hex #7 is not present for this tile */
45};
46static const Hex subhexes_D[] = {
47 HEX_F,
48 HEX_P,
49 HEX_G,
50 HEX_S,
51 HEX_X,
52 HEX_D,
53 HEX_F,
54 HEX_X,
55};
56static const Hex subhexes_J[] = {
57 HEX_F,
58 HEX_P,
59 HEX_G,
60 HEX_S,
61 HEX_Y,
62 HEX_D,
63 HEX_F,
64 HEX_P,
65};
66static const Hex subhexes_L[] = {
67 HEX_F,
68 HEX_P,
69 HEX_G,
70 HEX_S,
71 HEX_Y,
72 HEX_D,
73 HEX_F,
74 HEX_X,
75};
76static const Hex subhexes_X[] = {
77 HEX_F,
78 HEX_Y,
79 HEX_G,
80 HEX_S,
81 HEX_Y,
82 HEX_D,
83 HEX_F,
84 HEX_P,
85};
86static const Hex subhexes_P[] = {
87 HEX_F,
88 HEX_Y,
89 HEX_G,
90 HEX_S,
91 HEX_Y,
92 HEX_D,
93 HEX_F,
94 HEX_X,
95};
96static const Hex subhexes_S[] = {
97 HEX_L,
98 HEX_P,
99 HEX_G,
100 HEX_S,
101 HEX_X,
102 HEX_D,
103 HEX_F,
104 HEX_X,
105};
106static const Hex subhexes_F[] = {
107 HEX_F,
108 HEX_P,
109 HEX_G,
110 HEX_S,
111 HEX_Y,
112 HEX_D,
113 HEX_F,
114 HEX_Y,
115};
116static const Hex subhexes_Y[] = {
117 HEX_F,
118 HEX_Y,
119 HEX_G,
120 HEX_S,
121 HEX_Y,
122 HEX_D,
123 HEX_F,
124 HEX_Y,
125};
126
127/*
128 * Shape of the Spectre itself.
129 *
130 * Vertex 0 is taken to be at the top of the Spectre's "head"; vertex
131 * 1 is the adjacent vertex, in the direction of the shorter edge of
132 * its "cloak".
133 *
134 * This array indicates how far to turn at each vertex, in 1/12 turns.
135 * All edges are the same length (counting the double-edge as two
136 * edges, which we do).
137 */
138static const int spectre_angles[14] = {
139 -3, -2, 3, -2, -3, 2, -3, 2, -3, -2, 0, -2, 3, -2,
140};
141
142/*
143 * The relative probabilities of the nine hex types, in the limit, as
144 * the expansion process is iterated more and more times. Used to
145 * choose the initial hex coordinates as if the segment of tiling came
146 * from the limiting distribution across the whole plane.
147 *
148 * This is obtained by finding the matrix that says how many hexes of
149 * each type are expanded from each starting hex, and taking the
150 * eigenvector that goes with its limiting eigenvalue.
151 */
152#define PROB_G 10000000 /* 1 */
153#define PROB_D 10000000 /* 1 */
154#define PROB_J 1270167 /* 4 - sqrt(15) */
155#define PROB_L 1270167 /* 4 - sqrt(15) */
156#define PROB_X 7459667 /* 2 sqrt(15) - 7 */
157#define PROB_P 7459667 /* 2 sqrt(15) - 7 */
158#define PROB_S 10000000 /* 1 */
159#define PROB_F 17459667 /* 2 sqrt(15) - 6 */
160#define PROB_Y 13810500 /* 13 - 3 sqrt(15) */
diff --git a/apps/plugins/puzzles/src/spectre.c b/apps/plugins/puzzles/src/spectre.c
new file mode 100644
index 0000000000..ba72304ff2
--- /dev/null
+++ b/apps/plugins/puzzles/src/spectre.c
@@ -0,0 +1,599 @@
1/*
2 * Code to generate patches of the aperiodic 'spectre' tiling
3 * discovered in 2023.
4 *
5 * Resources about the tiling from its discoverers:
6 * https://cs.uwaterloo.ca/~csk/spectre/
7 * https://arxiv.org/abs/2305.17743
8 *
9 * Writeup of the generation algorithm:
10 * https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/aperiodic-spectre/
11 */
12
13#include <assert.h>
14#include <string.h>
15
16#include "puzzles.h"
17#include "tree234.h"
18
19#include "spectre-internal.h"
20
21#include "spectre-tables-manual.h"
22#include "spectre-tables-auto.h"
23
24static const char *const letters =
25 #define STRINGIFY(x) #x
26 HEX_LETTERS(STRINGIFY)
27 #undef STRINGIFY
28 ;
29
30bool spectre_valid_hex_letter(char letter)
31{
32 return strchr(letters, letter) != NULL;
33}
34
35static Hex hex_from_letter(char letter)
36{
37 char buf[2];
38 buf[0] = letter;
39 buf[1] = '\0';
40 return strcspn(letters, buf);
41}
42
43static Hex hex_to_letter(unsigned char letter)
44{
45 return letters[letter];
46}
47
48struct HexData {
49 const struct MapEntry *hexmap, *hexin, *specmap, *specin;
50 const struct MapEdge *hexedges, *specedges;
51 const Hex *subhexes;
52 const struct Possibility *poss;
53 size_t nposs;
54};
55
56static const struct HexData hexdata[] = {
57 #define HEXDATA_ENTRY(x) { hexmap_##x, hexin_##x, specmap_##x, \
58 specin_##x, hexedges_##x, specedges_##x, subhexes_##x, \
59 poss_##x, lenof(poss_##x) },
60 HEX_LETTERS(HEXDATA_ENTRY)
61 #undef HEXDATA_ENTRY
62};
63
64static const struct Possibility *choose_poss(
65 random_state *rs, const struct Possibility *poss, size_t nposs)
66{
67 /*
68 * If we needed to do this _efficiently_, we'd rewrite all those
69 * tables above as cumulative frequency tables and use binary
70 * search. But this happens about log n times in a grid of area n,
71 * so it hardly matters, and it's easier to keep the tables
72 * legible.
73 */
74 unsigned long limit = 0, value;
75 size_t i;
76
77 for (i = 0; i < nposs; i++)
78 limit += poss[i].prob;
79
80 value = random_upto(rs, limit);
81
82 for (i = 0; i+1 < nposs; i++) {
83 if (value < poss[i].prob)
84 return &poss[i];
85 value -= poss[i].prob;
86 }
87
88 assert(i == nposs - 1);
89 assert(value < poss[i].prob);
90 return &poss[i];
91}
92
93SpectreCoords *spectre_coords_new(void)
94{
95 SpectreCoords *sc = snew(SpectreCoords);
96 sc->nc = sc->csize = 0;
97 sc->c = NULL;
98 return sc;
99}
100
101void spectre_coords_free(SpectreCoords *sc)
102{
103 if (sc) {
104 sfree(sc->c);
105 sfree(sc);
106 }
107}
108
109void spectre_coords_make_space(SpectreCoords *sc, size_t size)
110{
111 if (sc->csize < size) {
112 sc->csize = sc->csize * 5 / 4 + 16;
113 if (sc->csize < size)
114 sc->csize = size;
115 sc->c = sresize(sc->c, sc->csize, HexCoord);
116 }
117}
118
119SpectreCoords *spectre_coords_copy(SpectreCoords *sc_in)
120{
121 SpectreCoords *sc_out = spectre_coords_new();
122 spectre_coords_make_space(sc_out, sc_in->nc);
123 memcpy(sc_out->c, sc_in->c, sc_in->nc * sizeof(*sc_out->c));
124 sc_out->nc = sc_in->nc;
125 sc_out->index = sc_in->index;
126 sc_out->hex_colour = sc_in->hex_colour;
127 sc_out->prev_hex_colour = sc_in->prev_hex_colour;
128 sc_out->incoming_hex_edge = sc_in->incoming_hex_edge;
129 return sc_out;
130}
131
132void spectre_place(Spectre *spec, Point u, Point v, int index_of_u)
133{
134 size_t i;
135 Point disp;
136
137 /* Vector from u to v */
138 disp = point_sub(v, u);
139
140 for (i = 0; i < 14; i++) {
141 spec->vertices[(i + index_of_u) % 14] = u;
142 u = point_add(u, disp);
143 disp = point_mul(disp, point_rot(
144 spectre_angles[(i + 1 + index_of_u) % 14]));
145 }
146}
147
148Spectre *spectre_initial(SpectreContext *ctx)
149{
150 Spectre *spec = snew(Spectre);
151 spectre_place(spec, ctx->start_vertices[0], ctx->start_vertices[1], 0);
152 spec->sc = spectre_coords_copy(ctx->prototype);
153 return spec;
154}
155
156Spectre *spectre_adjacent(SpectreContext *ctx, const Spectre *src_spec,
157 unsigned src_edge, unsigned *dst_edge_out)
158{
159 unsigned dst_edge;
160 Spectre *dst_spec = snew(Spectre);
161 dst_spec->sc = spectre_coords_copy(src_spec->sc);
162 spectrectx_step(ctx, dst_spec->sc, src_edge, &dst_edge);
163 spectre_place(dst_spec, src_spec->vertices[(src_edge+1) % 14],
164 src_spec->vertices[src_edge], dst_edge);
165 if (dst_edge_out)
166 *dst_edge_out = dst_edge;
167 return dst_spec;
168}
169
170static int spectre_cmp(void *av, void *bv)
171{
172 Spectre *a = (Spectre *)av, *b = (Spectre *)bv;
173 size_t i, j;
174
175 /* We should only ever need to compare the first two vertices of
176 * any Spectre, because those force the rest */
177 for (i = 0; i < 2; i++) {
178 for (j = 0; j < 4; j++) {
179 int ac = a->vertices[i].coeffs[j], bc = b->vertices[i].coeffs[j];
180 if (ac < bc)
181 return -1;
182 if (ac > bc)
183 return +1;
184 }
185 }
186
187 return 0;
188}
189
190void spectre_free(Spectre *spec)
191{
192 spectre_coords_free(spec->sc);
193 sfree(spec);
194}
195
196static void spectrectx_start_vertices(SpectreContext *ctx, int orientation)
197{
198 Point minus_sqrt3 = point_add(point_rot(5), point_rot(-5));
199 Point basicedge = point_mul(point_add(point_rot(0), point_rot(-3)),
200 point_rot(orientation));
201 Point diagonal = point_add(basicedge, point_mul(basicedge, point_rot(-3)));
202 ctx->start_vertices[0] = point_mul(diagonal, minus_sqrt3);
203 ctx->start_vertices[1] = point_add(ctx->start_vertices[0], basicedge);
204 ctx->orientation = orientation;
205}
206
207void spectrectx_init_random(SpectreContext *ctx, random_state *rs)
208{
209 const struct Possibility *poss;
210
211 ctx->rs = rs;
212 ctx->must_free_rs = false;
213 ctx->prototype = spectre_coords_new();
214 spectre_coords_make_space(ctx->prototype, 1);
215 poss = choose_poss(rs, poss_spectre, lenof(poss_spectre));
216 ctx->prototype->index = poss->lo;
217 ctx->prototype->c[0].type = poss->hi;
218 ctx->prototype->c[0].index = -1;
219 ctx->prototype->nc = 1;
220
221 /*
222 * Choose a random orientation for the starting Spectre.
223 *
224 * The obvious thing is to choose the orientation out of all 12
225 * possibilities. But we do it a more complicated way.
226 *
227 * The Spectres in a tiling can be partitioned into two
228 * equivalence classes under the relation 'orientation differs by
229 * a multiple of 1/6 turn'. One class is much more common than the
230 * other class: the 'odd'-orientation Spectres occur rarely (very
231 * like the rare reflected hats in the hats tiling).
232 *
233 * I think it's nicer to arrange that there's a consistent
234 * orientation for the _common_ class of Spectres, so that there
235 * will always be plenty of them in the 'canonical' orientation
236 * with the head upwards. So if the starting Spectre is in the
237 * even class, we pick an even orientation for it, and if it's in
238 * the odd class, we pick an odd orientation.
239 *
240 * An odd-class Spectre is easy to identify from SpectreCoords.
241 * They're precisely the ones expanded from a G hex with index 1,
242 * which means they're the ones that have index 1 _at all_.
243 */
244 spectrectx_start_vertices(ctx, random_upto(rs, 6) * 2 +
245 ctx->prototype->index);
246
247 /* Initialiise the colouring fields deterministically but unhelpfully.
248 * spectre-test will set these up properly if it wants to */
249 ctx->prototype->hex_colour = 0;
250 ctx->prototype->prev_hex_colour = 0;
251 ctx->prototype->incoming_hex_edge = 0;
252}
253
254void spectrectx_init_from_params(
255 SpectreContext *ctx, const struct SpectrePatchParams *ps)
256{
257 size_t i;
258
259 ctx->rs = NULL;
260 ctx->must_free_rs = false;
261 ctx->prototype = spectre_coords_new();
262 spectre_coords_make_space(ctx->prototype, ps->ncoords);
263
264 ctx->prototype->index = ps->coords[0];
265 for (i = 1; i < ps->ncoords; i++)
266 ctx->prototype->c[i-1].index = ps->coords[i];
267 ctx->prototype->c[ps->ncoords-1].index = -1;
268 ctx->prototype->nc = ps->ncoords;
269
270 ctx->prototype->c[ps->ncoords-1].type = hex_from_letter(ps->final_hex);
271 for (i = ps->ncoords - 1; i-- > 0 ;) {
272 const struct HexData *h = &hexdata[ctx->prototype->c[i+1].type];
273 ctx->prototype->c[i].type = h->subhexes[ctx->prototype->c[i].index];
274 }
275
276 spectrectx_start_vertices(ctx, ps->orientation);
277
278 ctx->prototype->hex_colour = 0;
279 ctx->prototype->prev_hex_colour = 0;
280 ctx->prototype->incoming_hex_edge = 0;
281}
282
283void spectrectx_cleanup(SpectreContext *ctx)
284{
285 if (ctx->must_free_rs)
286 random_free(ctx->rs);
287 spectre_coords_free(ctx->prototype);
288}
289
290SpectreCoords *spectrectx_initial_coords(SpectreContext *ctx)
291{
292 return spectre_coords_copy(ctx->prototype);
293}
294
295/*
296 * Extend sc until it has at least n coordinates in, by copying from
297 * ctx->prototype if needed, and extending ctx->prototype if needed in
298 * order to do that.
299 */
300void spectrectx_extend_coords(SpectreContext *ctx, SpectreCoords *sc, size_t n)
301{
302 if (ctx->prototype->nc < n) {
303 spectre_coords_make_space(ctx->prototype, n);
304 while (ctx->prototype->nc < n) {
305 const struct HexData *h = &hexdata[
306 ctx->prototype->c[ctx->prototype->nc-1].type];
307 const struct Possibility *poss;
308
309 if (!ctx->rs) {
310 /*
311 * If there's no random_state available, it must be
312 * because we were given an explicit coordinate string
313 * and ran off the end of it.
314 *
315 * The obvious thing to do here would be to make up an
316 * answer non-randomly. But in fact there's a danger
317 * that this leads to endless recursion within a
318 * single coordinate step, if the hex edge we were
319 * trying to traverse turns into another copy of
320 * itself at the higher level. That happened in early
321 * testing before I put the random_state in at all.
322 *
323 * To avoid that risk, in this situation - which
324 * _shouldn't_ come up at all in sensibly play - we
325 * make up a random_state, and free it when the
326 * context goes away.
327 */
328 ctx->rs = random_new("dummy", 5);
329 ctx->must_free_rs = true;
330 }
331
332 poss = choose_poss(ctx->rs, h->poss, h->nposs);
333 ctx->prototype->c[ctx->prototype->nc-1].index = poss->lo;
334 ctx->prototype->c[ctx->prototype->nc].type = poss->hi;
335 ctx->prototype->c[ctx->prototype->nc].index = -1;
336 ctx->prototype->nc++;
337 }
338 }
339
340 spectre_coords_make_space(sc, n);
341 while (sc->nc < n) {
342 assert(sc->c[sc->nc - 1].index == -1);
343 assert(sc->c[sc->nc - 1].type == ctx->prototype->c[sc->nc - 1].type);
344 sc->c[sc->nc - 1].index = ctx->prototype->c[sc->nc - 1].index;
345 sc->c[sc->nc].index = -1;
346 sc->c[sc->nc].type = ctx->prototype->c[sc->nc].type;
347 sc->nc++;
348 }
349}
350
351void spectrectx_step_hex(SpectreContext *ctx, SpectreCoords *sc,
352 size_t depth, unsigned edge, unsigned *outedge)
353{
354 const struct HexData *h;
355 const struct MapEntry *m;
356
357 spectrectx_extend_coords(ctx, sc, depth+2);
358
359 assert(0 <= sc->c[depth].index);
360 assert(sc->c[depth].index < num_subhexes(sc->c[depth].type));
361 assert(0 <= edge);
362 assert(edge < 6);
363
364 h = &hexdata[sc->c[depth+1].type];
365 m = &h->hexmap[6 * sc->c[depth].index + edge];
366 if (!m->internal) {
367 unsigned recedge;
368 const struct MapEdge *me;
369 spectrectx_step_hex(ctx, sc, depth+1, m->hi, &recedge);
370 assert(recedge < 6);
371 h = &hexdata[sc->c[depth+1].type];
372 me = &h->hexedges[recedge];
373 assert(m->lo < me->len);
374 m = &h->hexin[me->startindex + me->len - 1 - m->lo];
375 assert(m->internal);
376 }
377 sc->c[depth].index = m->hi;
378 sc->c[depth].type = h->subhexes[sc->c[depth].index];
379 *outedge = m->lo;
380
381 if (depth == 0) {
382 /*
383 * Update the colouring fields to track the colour of the new
384 * hexagon.
385 */
386 unsigned char new_hex_colour;
387
388 if (!((edge ^ sc->incoming_hex_edge) & 1)) {
389 /* We're going out via the same parity of edge we came in
390 * on, so the new hex colour is the same as the previous
391 * one. */
392 new_hex_colour = sc->prev_hex_colour;
393 } else {
394 /* We're going out via the opposite parity of edge, so the
395 * new colour is the one of {0,1,2} that is neither this
396 * _nor_ the previous colour. */
397 new_hex_colour = 0+1+2 - sc->hex_colour - sc->prev_hex_colour;
398 }
399
400 sc->prev_hex_colour = sc->hex_colour;
401 sc->hex_colour = new_hex_colour;
402 sc->incoming_hex_edge = m->lo;
403 }
404}
405
406void spectrectx_step(SpectreContext *ctx, SpectreCoords *sc,
407 unsigned edge, unsigned *outedge)
408{
409 const struct HexData *h;
410 const struct MapEntry *m;
411
412 assert(0 <= sc->index);
413 assert(sc->index < num_spectres(sc->c[0].type));
414 assert(0 <= edge);
415 assert(edge < 14);
416
417 h = &hexdata[sc->c[0].type];
418 m = &h->specmap[14 * sc->index + edge];
419
420 while (!m->internal) {
421 unsigned recedge;
422 const struct MapEdge *me;
423 spectrectx_step_hex(ctx, sc, 0, m->hi, &recedge);
424 assert(recedge < 6);
425 h = &hexdata[sc->c[0].type];
426 me = &h->specedges[recedge];
427 assert(m->lo < me->len);
428 m = &h->specin[me->startindex + me->len - 1 - m->lo];
429 }
430 sc->index = m->hi;
431 *outedge = m->lo;
432}
433
434void spectrectx_generate(SpectreContext *ctx,
435 bool (*callback)(void *cbctx, const Spectre *spec),
436 void *cbctx)
437{
438 tree234 *placed = newtree234(spectre_cmp);
439 Spectre *qhead = NULL, *qtail = NULL;
440
441 {
442 Spectre *spec = spectre_initial(ctx);
443
444 add234(placed, spec);
445
446 spec->next = NULL;
447
448 if (callback(cbctx, spec))
449 qhead = qtail = spec;
450 }
451
452 while (qhead) {
453 unsigned edge;
454 Spectre *spec = qhead;
455
456 for (edge = 0; edge < 14; edge++) {
457 Spectre *new_spec;
458
459 new_spec = spectre_adjacent(ctx, spec, edge, NULL);
460
461 if (find234(placed, new_spec, NULL)) {
462 spectre_free(new_spec);
463 continue;
464 }
465
466 if (!callback(cbctx, new_spec)) {
467 spectre_free(new_spec);
468 continue;
469 }
470
471 add234(placed, new_spec);
472 qtail->next = new_spec;
473 qtail = new_spec;
474 new_spec->next = NULL;
475 }
476
477 qhead = qhead->next;
478 }
479
480 {
481 Spectre *spec;
482 while ((spec = delpos234(placed, 0)) != NULL)
483 spectre_free(spec);
484 freetree234(placed);
485 }
486}
487
488const char *spectre_tiling_params_invalid(
489 const struct SpectrePatchParams *params)
490{
491 size_t i;
492 Hex h;
493
494 if (params->ncoords == 0)
495 return "expected at least one numeric coordinate";
496 if (!spectre_valid_hex_letter(params->final_hex))
497 return "invalid final hexagon type";
498
499 h = hex_from_letter(params->final_hex);
500 for (i = params->ncoords; i-- > 0 ;) {
501 unsigned limit = (i == 0) ? num_spectres(h) : num_subhexes(h);
502 if (params->coords[i] >= limit)
503 return "coordinate out of range";
504
505 if (i > 0)
506 h = hexdata[h].subhexes[params->coords[i]];
507 }
508
509 return NULL;
510}
511
512struct SpectreCallbackContext {
513 int xoff, yoff;
514 Coord xmin, xmax, ymin, ymax;
515
516 spectre_tile_callback_fn external_cb;
517 void *external_cbctx;
518};
519
520static bool spectre_internal_callback(void *vctx, const Spectre *spec)
521{
522 struct SpectreCallbackContext *ctx = (struct SpectreCallbackContext *)vctx;
523 size_t i;
524 int output_coords[4*14];
525
526 for (i = 0; i < 14; i++) {
527 Point p = spec->vertices[i];
528 Coord x = point_x(p), y = point_y(p);
529 if (coord_cmp(x, ctx->xmin) < 0 || coord_cmp(x, ctx->xmax) > 0 ||
530 coord_cmp(y, ctx->ymin) < 0 || coord_cmp(y, ctx->ymax) > 0)
531 return false;
532
533 output_coords[4*i + 0] = ctx->xoff + x.c1;
534 output_coords[4*i + 1] = x.cr3;
535 output_coords[4*i + 2] = ctx->yoff - y.c1;
536 output_coords[4*i + 3] = -y.cr3;
537 }
538
539 if (ctx->external_cb)
540 ctx->external_cb(ctx->external_cbctx, output_coords);
541
542 return true;
543}
544
545static void spectre_set_bounds(struct SpectreCallbackContext *cbctx,
546 int w, int h)
547{
548 cbctx->xoff = w/2;
549 cbctx->yoff = h/2;
550 cbctx->xmin.c1 = -cbctx->xoff;
551 cbctx->xmax.c1 = -cbctx->xoff + w;
552 cbctx->ymin.c1 = cbctx->yoff - h;
553 cbctx->ymax.c1 = cbctx->yoff;
554 cbctx->xmin.cr3 = 0;
555 cbctx->xmax.cr3 = 0;
556 cbctx->ymin.cr3 = 0;
557 cbctx->ymax.cr3 = 0;
558}
559
560void spectre_tiling_randomise(struct SpectrePatchParams *ps, int w, int h,
561 random_state *rs)
562{
563 SpectreContext ctx[1];
564 struct SpectreCallbackContext cbctx[1];
565 size_t i;
566
567 spectre_set_bounds(cbctx, w, h);
568 cbctx->external_cb = NULL;
569 cbctx->external_cbctx = NULL;
570
571 spectrectx_init_random(ctx, rs);
572 spectrectx_generate(ctx, spectre_internal_callback, cbctx);
573
574 ps->orientation = ctx->orientation;
575 ps->ncoords = ctx->prototype->nc;
576 ps->coords = snewn(ps->ncoords, unsigned char);
577 ps->coords[0] = ctx->prototype->index;
578 for (i = 1; i < ps->ncoords; i++)
579 ps->coords[i] = ctx->prototype->c[i-1].index;
580 ps->final_hex = hex_to_letter(ctx->prototype->c[ps->ncoords-1].type);
581
582 spectrectx_cleanup(ctx);
583}
584
585void spectre_tiling_generate(
586 const struct SpectrePatchParams *params, int w, int h,
587 spectre_tile_callback_fn external_cb, void *external_cbctx)
588{
589 SpectreContext ctx[1];
590 struct SpectreCallbackContext cbctx[1];
591
592 spectre_set_bounds(cbctx, w, h);
593 cbctx->external_cb = external_cb;
594 cbctx->external_cbctx = external_cbctx;
595
596 spectrectx_init_from_params(ctx, params);
597 spectrectx_generate(ctx, spectre_internal_callback, cbctx);
598 spectrectx_cleanup(ctx);
599}
diff --git a/apps/plugins/puzzles/src/spectre.h b/apps/plugins/puzzles/src/spectre.h
new file mode 100644
index 0000000000..97d7595e3a
--- /dev/null
+++ b/apps/plugins/puzzles/src/spectre.h
@@ -0,0 +1,72 @@
1#ifndef PUZZLES_SPECTRE_H
2#define PUZZLES_SPECTRE_H
3
4struct SpectrePatchParams {
5 /*
6 * A patch of Spectre tiling is identified by giving
7 *
8 * - the coordinates of the central Spectre, using a
9 * combinatorial coordinate system similar to the Hat tiling in
10 * hat.h
11 *
12 * - the orientation of that Spectre, as a number from 0 to 11 (a
13 * multiple of 30 degrees), with 0 representing the 'head' of
14 * the Spectre facing upwards, and numbers counting
15 * anticlockwise.
16 *
17 * Coordinates are a sequence of small non-negative integers. The
18 * valid range for each coordinate depends on the next coordinate,
19 * or on final_hex if it's the last one in the list. The largest
20 * valid range is {0,...,7}.
21 *
22 * 'final_hex' is one of the letters GDJLXPSFY.
23 * spectre_valid_hex_letter() will check that.
24 */
25 int orientation;
26 size_t ncoords;
27 unsigned char *coords;
28 char final_hex;
29};
30
31bool spectre_valid_hex_letter(char c);
32
33/*
34 * Fill in SpectrePatchParams with a randomly selected set of
35 * coordinates, in enough detail to generate a patch of tiling filling
36 * a w x h area. The unit of measurement is 1/(2*sqrt(2)) of a Spectre
37 * edge, i.e. such that a single Spectre edge at 45 degrees would
38 * correspond to the vector (2,2).
39 *
40 * The 'coords' field of the structure will be filled in with a new
41 * dynamically allocated array. Any previous pointer in that field
42 * will be overwritten.
43 */
44void spectre_tiling_randomise(struct SpectrePatchParams *params, int w, int h,
45 random_state *rs);
46
47/*
48 * Validate a SpectrePatchParams to ensure it contains no illegal
49 * coordinates. Returns NULL if it's acceptable, or an error string if
50 * not.
51 */
52const char *spectre_tiling_params_invalid(
53 const struct SpectrePatchParams *params);
54
55/*
56 * Generate the actual set of Spectre tiles from a SpectrePatchParams,
57 * passing each one to a callback. The callback receives the vertices
58 * of each point, in the form of an array of 4*14 integers. Each
59 * vertex is represented by four consecutive integers in this array,
60 * with the first two giving the x coordinate and the last two the y
61 * coordinate. Each pair of integers a,b represent a single coordinate
62 * whose value is a + b*sqrt(3). The unit of measurement is as above.
63 */
64typedef void (*spectre_tile_callback_fn)(void *ctx, const int *coords);
65
66#define SPECTRE_NVERTICES 14
67
68void spectre_tiling_generate(
69 const struct SpectrePatchParams *params, int w, int h,
70 spectre_tile_callback_fn cb, void *cbctx);
71
72#endif
diff --git a/apps/plugins/puzzles/src/tents.R b/apps/plugins/puzzles/src/tents.R
deleted file mode 100644
index 925661c761..0000000000
--- a/apps/plugins/puzzles/src/tents.R
+++ /dev/null
@@ -1,24 +0,0 @@
1# -*- makefile -*-
2
3TENTS_EXTRA = matching dsf
4
5tents : [X] GTK COMMON tents TENTS_EXTRA tents-icon|no-icon
6
7tents : [G] WINDOWS COMMON tents TENTS_EXTRA tents.res|noicon.res
8
9ALL += tents[COMBINED] TENTS_EXTRA
10
11tentssolver : [U] tents[STANDALONE_SOLVER] TENTS_EXTRA STANDALONE
12tentssolver : [C] tents[STANDALONE_SOLVER] TENTS_EXTRA STANDALONE
13
14!begin am gtk
15GAMES += tents
16!end
17
18!begin >list.c
19 A(tents) \
20!end
21
22!begin >gamedesc.txt
23tents:tents.exe:Tents:Tent-placing puzzle:Place a tent next to each tree.
24!end
diff --git a/apps/plugins/puzzles/src/tents.c b/apps/plugins/puzzles/src/tents.c
index ee06172baf..0d40959d26 100644
--- a/apps/plugins/puzzles/src/tents.c
+++ b/apps/plugins/puzzles/src/tents.c
@@ -32,7 +32,12 @@
32#include <string.h> 32#include <string.h>
33#include <assert.h> 33#include <assert.h>
34#include <ctype.h> 34#include <ctype.h>
35#include <math.h> 35#include <limits.h>
36#ifdef NO_TGMATH_H
37# include <math.h>
38#else
39# include <tgmath.h>
40#endif
36 41
37#include "puzzles.h" 42#include "puzzles.h"
38#include "matching.h" 43#include "matching.h"
@@ -229,7 +234,7 @@
229 */ 234 */
230#if defined STANDALONE_SOLVER 235#if defined STANDALONE_SOLVER
231#define SOLVER_DIAGNOSTICS 236#define SOLVER_DIAGNOSTICS
232bool verbose = false; 237static bool verbose = false;
233#elif defined SOLVER_DIAGNOSTICS 238#elif defined SOLVER_DIAGNOSTICS
234#define verbose true 239#define verbose true
235#endif 240#endif
@@ -408,6 +413,8 @@ static const char *validate_params(const game_params *params, bool full)
408 */ 413 */
409 if (params->w < 4 || params->h < 4) 414 if (params->w < 4 || params->h < 4)
410 return "Width and height must both be at least four"; 415 return "Width and height must both be at least four";
416 if (params->w > (INT_MAX - 1) / params->h)
417 return "Width times height must not be unreasonably large";
411 return NULL; 418 return NULL;
412} 419}
413 420
@@ -998,7 +1005,7 @@ static char *new_game_desc(const game_params *params_in, random_state *rs,
998 int dy, dx; 1005 int dy, dx;
999 bool ok = true; 1006 bool ok = true;
1000 1007
1001 which = i + random_upto(rs, j); 1008 which = i + random_upto(rs, w*h - i);
1002 tmp = order[which]; 1009 tmp = order[which];
1003 order[which] = order[i]; 1010 order[which] = order[i];
1004 order[i] = tmp; 1011 order[i] = tmp;
@@ -1188,6 +1195,21 @@ static char *new_game_desc(const game_params *params_in, random_state *rs,
1188 return ret; 1195 return ret;
1189} 1196}
1190 1197
1198/*
1199 * Grid description format:
1200 *
1201 * _ = tree
1202 * a = 1 BLANK then TREE
1203 * ...
1204 * y = 25 BLANKs then TREE
1205 * z = 25 BLANKs
1206 * ! = set previous square to TENT
1207 * - = set previous square to NONTENT
1208 *
1209 * Last character must be one that would insert a tree as the first
1210 * square after the grid.
1211 */
1212
1191static const char *validate_desc(const game_params *params, const char *desc) 1213static const char *validate_desc(const game_params *params, const char *desc)
1192{ 1214{
1193 int w = params->w, h = params->h; 1215 int w = params->w, h = params->h;
@@ -1201,9 +1223,10 @@ static const char *validate_desc(const game_params *params, const char *desc)
1201 area += *desc - 'a' + 2; 1223 area += *desc - 'a' + 2;
1202 else if (*desc == 'z') 1224 else if (*desc == 'z')
1203 area += 25; 1225 area += 25;
1204 else if (*desc == '!' || *desc == '-') 1226 else if (*desc == '!' || *desc == '-') {
1205 /* do nothing */; 1227 if (area == 0 || area > w * h)
1206 else 1228 return "Tent or non-tent placed off the grid";
1229 } else
1207 return "Invalid character in grid specification"; 1230 return "Invalid character in grid specification";
1208 1231
1209 desc++; 1232 desc++;
@@ -1436,7 +1459,7 @@ static game_ui *new_ui(const game_state *state)
1436 ui->drag_button = -1; 1459 ui->drag_button = -1;
1437 ui->drag_ok = false; 1460 ui->drag_ok = false;
1438 ui->cx = ui->cy = 0; 1461 ui->cx = ui->cy = 0;
1439 ui->cdisp = false; 1462 ui->cdisp = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1440 return ui; 1463 return ui;
1441} 1464}
1442 1465
@@ -1445,18 +1468,25 @@ static void free_ui(game_ui *ui)
1445 sfree(ui); 1468 sfree(ui);
1446} 1469}
1447 1470
1448static char *encode_ui(const game_ui *ui) 1471static void game_changed_state(game_ui *ui, const game_state *oldstate,
1449{ 1472 const game_state *newstate)
1450 return NULL;
1451}
1452
1453static void decode_ui(game_ui *ui, const char *encoding)
1454{ 1473{
1455} 1474}
1456 1475
1457static void game_changed_state(game_ui *ui, const game_state *oldstate, 1476static const char *current_key_label(const game_ui *ui,
1458 const game_state *newstate) 1477 const game_state *state, int button)
1459{ 1478{
1479 int w = state->p.w;
1480 int v = state->grid[ui->cy*w+ui->cx];
1481
1482 if (IS_CURSOR_SELECT(button) && ui->cdisp) {
1483 switch (v) {
1484 case BLANK:
1485 return button == CURSOR_SELECT ? "Tent" : "Green";
1486 case TENT: case NONTENT: return "Clear";
1487 }
1488 }
1489 return "";
1460} 1490}
1461 1491
1462struct game_drawstate { 1492struct game_drawstate {
@@ -1546,7 +1576,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1546 char tmpbuf[80]; 1576 char tmpbuf[80];
1547 bool shift = button & MOD_SHFT, control = button & MOD_CTRL; 1577 bool shift = button & MOD_SHFT, control = button & MOD_CTRL;
1548 1578
1549 button &= ~MOD_MASK; 1579 button = STRIP_BUTTON_MODIFIERS(button);
1550 1580
1551 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { 1581 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
1552 x = FROMCOORD(x); 1582 x = FROMCOORD(x);
@@ -1559,7 +1589,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1559 ui->dsy = ui->dey = y; 1589 ui->dsy = ui->dey = y;
1560 ui->drag_ok = true; 1590 ui->drag_ok = true;
1561 ui->cdisp = false; 1591 ui->cdisp = false;
1562 return UI_UPDATE; 1592 return MOVE_UI_UPDATE;
1563 } 1593 }
1564 1594
1565 if ((IS_MOUSE_DRAG(button) || IS_MOUSE_RELEASE(button)) && 1595 if ((IS_MOUSE_DRAG(button) || IS_MOUSE_RELEASE(button)) &&
@@ -1591,14 +1621,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1591 } 1621 }
1592 1622
1593 if (IS_MOUSE_DRAG(button)) 1623 if (IS_MOUSE_DRAG(button))
1594 return UI_UPDATE; 1624 return MOVE_UI_UPDATE;
1595 1625
1596 /* 1626 /*
1597 * The drag has been released. Enact it. 1627 * The drag has been released. Enact it.
1598 */ 1628 */
1599 if (!ui->drag_ok) { 1629 if (!ui->drag_ok) {
1600 ui->drag_button = -1; 1630 ui->drag_button = -1;
1601 return UI_UPDATE; /* drag was just cancelled */ 1631 return MOVE_UI_UPDATE; /* drag was just cancelled */
1602 } 1632 }
1603 1633
1604 xmin = min(ui->dsx, ui->dex); 1634 xmin = min(ui->dsx, ui->dex);
@@ -1636,7 +1666,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1636 1666
1637 if (buflen == 0) { 1667 if (buflen == 0) {
1638 sfree(buf); 1668 sfree(buf);
1639 return UI_UPDATE; /* drag was terminated */ 1669 return MOVE_UI_UPDATE; /* drag was terminated */
1640 } else { 1670 } else {
1641 buf[buflen] = '\0'; 1671 buf[buflen] = '\0';
1642 return buf; 1672 return buf;
@@ -1644,11 +1674,12 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1644 } 1674 }
1645 1675
1646 if (IS_CURSOR_MOVE(button)) { 1676 if (IS_CURSOR_MOVE(button)) {
1647 ui->cdisp = true; 1677 char *ret;
1648 if (shift || control) { 1678 if (shift || control) {
1649 int len = 0, i, indices[2]; 1679 int len = 0, i, indices[2];
1650 indices[0] = ui->cx + w * ui->cy; 1680 indices[0] = ui->cx + w * ui->cy;
1651 move_cursor(button, &ui->cx, &ui->cy, w, h, false); 1681 ret = move_cursor(button, &ui->cx, &ui->cy, w, h, false,
1682 &ui->cdisp);
1652 indices[1] = ui->cx + w * ui->cy; 1683 indices[1] = ui->cx + w * ui->cy;
1653 1684
1654 /* NONTENTify all unique traversed eligible squares */ 1685 /* NONTENTify all unique traversed eligible squares */
@@ -1663,8 +1694,9 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1663 tmpbuf[len] = '\0'; 1694 tmpbuf[len] = '\0';
1664 if (len) return dupstr(tmpbuf); 1695 if (len) return dupstr(tmpbuf);
1665 } else 1696 } else
1666 move_cursor(button, &ui->cx, &ui->cy, w, h, false); 1697 ret = move_cursor(button, &ui->cx, &ui->cy, w, h, false,
1667 return UI_UPDATE; 1698 &ui->cdisp);
1699 return ret;
1668 } 1700 }
1669 if (ui->cdisp) { 1701 if (ui->cdisp) {
1670 char rep = 0; 1702 char rep = 0;
@@ -1691,7 +1723,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1691 } 1723 }
1692 } else if (IS_CURSOR_SELECT(button)) { 1724 } else if (IS_CURSOR_SELECT(button)) {
1693 ui->cdisp = true; 1725 ui->cdisp = true;
1694 return UI_UPDATE; 1726 return MOVE_UI_UPDATE;
1695 } 1727 }
1696 1728
1697 return NULL; 1729 return NULL;
@@ -1875,7 +1907,7 @@ static game_state *execute_move(const game_state *state, const char *move)
1875 */ 1907 */
1876 1908
1877static void game_compute_size(const game_params *params, int tilesize, 1909static void game_compute_size(const game_params *params, int tilesize,
1878 int *x, int *y) 1910 const game_ui *ui, int *x, int *y)
1879{ 1911{
1880 /* fool the macros */ 1912 /* fool the macros */
1881 struct dummy { int tilesize; } dummy, *ds = &dummy; 1913 struct dummy { int tilesize; } dummy, *ds = &dummy;
@@ -1976,7 +2008,8 @@ static int *find_errors(const game_state *state, char *grid)
1976{ 2008{
1977 int w = state->p.w, h = state->p.h; 2009 int w = state->p.w, h = state->p.h;
1978 int *ret = snewn(w*h + w + h, int); 2010 int *ret = snewn(w*h + w + h, int);
1979 int *tmp = snewn(w*h*2, int), *dsf = tmp + w*h; 2011 int *tmp = snewn(w*h, int);
2012 DSF *dsf;
1980 int x, y; 2013 int x, y;
1981 2014
1982 /* 2015 /*
@@ -2193,7 +2226,7 @@ static int *find_errors(const game_state *state, char *grid)
2193 * all the tents in any component which has a smaller tree 2226 * all the tents in any component which has a smaller tree
2194 * count. 2227 * count.
2195 */ 2228 */
2196 dsf_init(dsf, w*h); 2229 dsf = dsf_new(w*h);
2197 /* Construct the equivalence classes. */ 2230 /* Construct the equivalence classes. */
2198 for (y = 0; y < h; y++) { 2231 for (y = 0; y < h; y++) {
2199 for (x = 0; x < w-1; x++) { 2232 for (x = 0; x < w-1; x++) {
@@ -2236,7 +2269,7 @@ static int *find_errors(const game_state *state, char *grid)
2236 * start of the game, before the user had done anything wrong!) 2269 * start of the game, before the user had done anything wrong!)
2237 */ 2270 */
2238#define TENT(x) ((x)==TENT || (x)==BLANK) 2271#define TENT(x) ((x)==TENT || (x)==BLANK)
2239 dsf_init(dsf, w*h); 2272 dsf_reinit(dsf);
2240 /* Construct the equivalence classes. */ 2273 /* Construct the equivalence classes. */
2241 for (y = 0; y < h; y++) { 2274 for (y = 0; y < h; y++) {
2242 for (x = 0; x < w-1; x++) { 2275 for (x = 0; x < w-1; x++) {
@@ -2272,6 +2305,7 @@ static int *find_errors(const game_state *state, char *grid)
2272#undef TENT 2305#undef TENT
2273 2306
2274 sfree(tmp); 2307 sfree(tmp);
2308 dsf_free(dsf);
2275 return ret; 2309 return ret;
2276} 2310}
2277 2311
@@ -2411,14 +2445,6 @@ static void int_redraw(drawing *dr, game_drawstate *ds,
2411 } 2445 }
2412 2446
2413 if (printing || !ds->started) { 2447 if (printing || !ds->started) {
2414 if (!printing) {
2415 int ww, wh;
2416 game_compute_size(&state->p, TILESIZE, &ww, &wh);
2417 draw_rect(dr, 0, 0, ww, wh, COL_BACKGROUND);
2418 draw_update(dr, 0, 0, ww, wh);
2419 ds->started = true;
2420 }
2421
2422 if (printing) 2448 if (printing)
2423 print_line_width(dr, TILESIZE/64); 2449 print_line_width(dr, TILESIZE/64);
2424 2450
@@ -2572,24 +2598,21 @@ static int game_status(const game_state *state)
2572 return state->completed ? +1 : 0; 2598 return state->completed ? +1 : 0;
2573} 2599}
2574 2600
2575static bool game_timing_state(const game_state *state, game_ui *ui) 2601static void game_print_size(const game_params *params, const game_ui *ui,
2576{ 2602 float *x, float *y)
2577 return true;
2578}
2579
2580static void game_print_size(const game_params *params, float *x, float *y)
2581{ 2603{
2582 int pw, ph; 2604 int pw, ph;
2583 2605
2584 /* 2606 /*
2585 * I'll use 6mm squares by default. 2607 * I'll use 6mm squares by default.
2586 */ 2608 */
2587 game_compute_size(params, 600, &pw, &ph); 2609 game_compute_size(params, 600, ui, &pw, &ph);
2588 *x = pw / 100.0F; 2610 *x = pw / 100.0F;
2589 *y = ph / 100.0F; 2611 *y = ph / 100.0F;
2590} 2612}
2591 2613
2592static void game_print(drawing *dr, const game_state *state, int tilesize) 2614static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2615 int tilesize)
2593{ 2616{
2594 int c; 2617 int c;
2595 2618
@@ -2628,12 +2651,14 @@ const struct game thegame = {
2628 free_game, 2651 free_game,
2629 true, solve_game, 2652 true, solve_game,
2630 true, game_can_format_as_text_now, game_text_format, 2653 true, game_can_format_as_text_now, game_text_format,
2654 NULL, NULL, /* get_prefs, set_prefs */
2631 new_ui, 2655 new_ui,
2632 free_ui, 2656 free_ui,
2633 encode_ui, 2657 NULL, /* encode_ui */
2634 decode_ui, 2658 NULL, /* decode_ui */
2635 NULL, /* game_request_keys */ 2659 NULL, /* game_request_keys */
2636 game_changed_state, 2660 game_changed_state,
2661 current_key_label,
2637 interpret_move, 2662 interpret_move,
2638 execute_move, 2663 execute_move,
2639 PREFERRED_TILESIZE, game_compute_size, game_set_size, 2664 PREFERRED_TILESIZE, game_compute_size, game_set_size,
@@ -2647,7 +2672,7 @@ const struct game thegame = {
2647 game_status, 2672 game_status,
2648 true, false, game_print_size, game_print, 2673 true, false, game_print_size, game_print,
2649 false, /* wants_statusbar */ 2674 false, /* wants_statusbar */
2650 false, game_timing_state, 2675 false, NULL, /* timing_state */
2651 REQUIRE_RBUTTON, /* flags */ 2676 REQUIRE_RBUTTON, /* flags */
2652}; 2677};
2653 2678
diff --git a/apps/plugins/puzzles/src/towers.R b/apps/plugins/puzzles/src/towers.R
deleted file mode 100644
index c2bb78a2dc..0000000000
--- a/apps/plugins/puzzles/src/towers.R
+++ /dev/null
@@ -1,25 +0,0 @@
1# -*- makefile -*-
2
3TOWERS_EXTRA = LATIN
4TOWERS_EXTRA_SOLVER = LATIN_SOLVER
5
6towers : [X] GTK COMMON towers TOWERS_EXTRA towers-icon|no-icon
7
8towers : [G] WINDOWS COMMON towers TOWERS_EXTRA towers.res|noicon.res
9
10towerssolver : [U] towers[STANDALONE_SOLVER] TOWERS_EXTRA_SOLVER STANDALONE
11towerssolver : [C] towers[STANDALONE_SOLVER] TOWERS_EXTRA_SOLVER STANDALONE
12
13ALL += towers[COMBINED] TOWERS_EXTRA
14
15!begin am gtk
16GAMES += towers
17!end
18
19!begin >list.c
20 A(towers) \
21!end
22
23!begin >gamedesc.txt
24towers:towers.exe:Towers:Tower-placing Latin square puzzle:Complete the latin square of towers in accordance with the clues.
25!end
diff --git a/apps/plugins/puzzles/src/towers.c b/apps/plugins/puzzles/src/towers.c
index 13c652b819..4dd9484ad9 100644
--- a/apps/plugins/puzzles/src/towers.c
+++ b/apps/plugins/puzzles/src/towers.c
@@ -23,7 +23,11 @@
23#include <string.h> 23#include <string.h>
24#include <assert.h> 24#include <assert.h>
25#include <ctype.h> 25#include <ctype.h>
26#include <math.h> 26#ifdef NO_TGMATH_H
27# include <math.h>
28#else
29# include <tgmath.h>
30#endif
27 31
28#include "puzzles.h" 32#include "puzzles.h"
29#include "latin.h" 33#include "latin.h"
@@ -385,12 +389,12 @@ static int solver_easy(struct latin_solver *solver, void *vctx)
385 return ret; 389 return ret;
386 390
387#ifdef STANDALONE_SOLVER 391#ifdef STANDALONE_SOLVER
388 if (solver_show_working) 392 if (solver_show_working)
389 sprintf(prefix, "%*slower bounds for clue %s %d:\n", 393 sprintf(prefix, "%*slower bounds for clue %s %d:\n",
390 solver_recurse_depth*4, "", 394 solver_recurse_depth*4, "",
391 cluepos[c/w], c%w+1); 395 cluepos[c/w], c%w+1);
392 else 396 else
393 prefix[0] = '\0'; /* placate optimiser */ 397 prefix[0] = '\0'; /* placate optimiser */
394#endif 398#endif
395 399
396 i = 0; 400 i = 0;
@@ -893,6 +897,7 @@ static const char *validate_desc(const game_params *params, const char *desc)
893 return "Too much data to fit in grid"; 897 return "Too much data to fit in grid";
894 } 898 }
895 899
900 if (*p) return "Rubbish at end of game description";
896 return NULL; 901 return NULL;
897} 902}
898 903
@@ -1154,16 +1159,59 @@ struct game_ui {
1154 * allowed on immutable squares. 1159 * allowed on immutable squares.
1155 */ 1160 */
1156 bool hcursor; 1161 bool hcursor;
1162
1163 /*
1164 * User preference option which can be set to FALSE to disable the
1165 * 3D graphical style, and instead just display the puzzle as if
1166 * it was a Sudoku variant, i.e. each square just has a digit in
1167 * it.
1168 *
1169 * I was initially a bit uncertain about whether the 3D style
1170 * would be the right thing, on the basis that it uses up space in
1171 * the cells and makes it hard to use many pencil marks. Actually
1172 * nobody seems to have complained, but having put in the option
1173 * while I was still being uncertain, it seems silly not to leave
1174 * it in just in case.
1175 */
1176 int three_d;
1177
1178 /*
1179 * User preference option: if the user right-clicks in a square
1180 * and presses a number key to add/remove a pencil mark, do we
1181 * hide the mouse highlight again afterwards?
1182 *
1183 * Historically our answer was yes. The Android port prefers no.
1184 * There are advantages both ways, depending how much you dislike
1185 * the highlight cluttering your view. So it's a preference.
1186 */
1187 bool pencil_keep_highlight;
1157}; 1188};
1158 1189
1190static void legacy_prefs_override(struct game_ui *ui_out)
1191{
1192 static bool initialised = false;
1193 static int three_d = -1;
1194
1195 if (!initialised) {
1196 initialised = true;
1197 three_d = getenv_bool("TOWERS_2D", -1);
1198 }
1199
1200 if (three_d != -1)
1201 ui_out->three_d = three_d;
1202}
1203
1159static game_ui *new_ui(const game_state *state) 1204static game_ui *new_ui(const game_state *state)
1160{ 1205{
1161 game_ui *ui = snew(game_ui); 1206 game_ui *ui = snew(game_ui);
1162 1207
1163 ui->hx = ui->hy = 0; 1208 ui->hx = ui->hy = 0;
1164 ui->hpencil = false; 1209 ui->hpencil = false;
1165 ui->hshow = false; 1210 ui->hshow = ui->hcursor = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1166 ui->hcursor = false; 1211
1212 ui->three_d = true;
1213 ui->pencil_keep_highlight = false;
1214 legacy_prefs_override(ui);
1167 1215
1168 return ui; 1216 return ui;
1169} 1217}
@@ -1173,13 +1221,34 @@ static void free_ui(game_ui *ui)
1173 sfree(ui); 1221 sfree(ui);
1174} 1222}
1175 1223
1176static char *encode_ui(const game_ui *ui) 1224static config_item *get_prefs(game_ui *ui)
1177{ 1225{
1178 return NULL; 1226 config_item *ret;
1227
1228 ret = snewn(3, config_item);
1229
1230 ret[0].name = "Keep mouse highlight after changing a pencil mark";
1231 ret[0].kw = "pencil-keep-highlight";
1232 ret[0].type = C_BOOLEAN;
1233 ret[0].u.boolean.bval = ui->pencil_keep_highlight;
1234
1235 ret[1].name = "Puzzle appearance";
1236 ret[1].kw = "appearance";
1237 ret[1].type = C_CHOICES;
1238 ret[1].u.choices.choicenames = ":2D:3D";
1239 ret[1].u.choices.choicekws = ":2d:3d";
1240 ret[1].u.choices.selected = ui->three_d;
1241
1242 ret[2].name = NULL;
1243 ret[2].type = C_END;
1244
1245 return ret;
1179} 1246}
1180 1247
1181static void decode_ui(game_ui *ui, const char *encoding) 1248static void set_prefs(game_ui *ui, const config_item *cfg)
1182{ 1249{
1250 ui->pencil_keep_highlight = cfg[0].u.boolean.bval;
1251 ui->three_d = cfg[1].u.choices.selected;
1183} 1252}
1184 1253
1185static void game_changed_state(game_ui *ui, const game_state *oldstate, 1254static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -1198,6 +1267,14 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1198 } 1267 }
1199} 1268}
1200 1269
1270static const char *current_key_label(const game_ui *ui,
1271 const game_state *state, int button)
1272{
1273 if (ui->hshow && (button == CURSOR_SELECT))
1274 return ui->hpencil ? "Ink" : "Pencil";
1275 return "";
1276}
1277
1201#define PREFERRED_TILESIZE 48 1278#define PREFERRED_TILESIZE 48
1202#define TILESIZE (ds->tilesize) 1279#define TILESIZE (ds->tilesize)
1203#define BORDER (TILESIZE * 9 / 8) 1280#define BORDER (TILESIZE * 9 / 8)
@@ -1221,8 +1298,6 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1221 1298
1222struct game_drawstate { 1299struct game_drawstate {
1223 int tilesize; 1300 int tilesize;
1224 bool three_d; /* default 3D graphics are user-disableable */
1225 bool started;
1226 long *tiles; /* (w+2)*(w+2) temp space */ 1301 long *tiles; /* (w+2)*(w+2) temp space */
1227 long *drawn; /* (w+2)*(w+2)*4: current drawn data */ 1302 long *drawn; /* (w+2)*(w+2)*4: current drawn data */
1228 bool *errtmp; 1303 bool *errtmp;
@@ -1349,12 +1424,12 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1349 int tx, ty; 1424 int tx, ty;
1350 char buf[80]; 1425 char buf[80];
1351 1426
1352 button &= ~MOD_MASK; 1427 button = STRIP_BUTTON_MODIFIERS(button);
1353 1428
1354 tx = FROMCOORD(x); 1429 tx = FROMCOORD(x);
1355 ty = FROMCOORD(y); 1430 ty = FROMCOORD(y);
1356 1431
1357 if (ds->three_d) { 1432 if (ui->three_d) {
1358 /* 1433 /*
1359 * In 3D mode, just locating the mouse click in the natural 1434 * In 3D mode, just locating the mouse click in the natural
1360 * square grid may not be sufficient to tell which tower the 1435 * square grid may not be sufficient to tell which tower the
@@ -1401,7 +1476,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1401 ui->hpencil = false; 1476 ui->hpencil = false;
1402 } 1477 }
1403 ui->hcursor = false; 1478 ui->hcursor = false;
1404 return UI_UPDATE; 1479 return MOVE_UI_UPDATE;
1405 } 1480 }
1406 if (button == RIGHT_BUTTON) { 1481 if (button == RIGHT_BUTTON) {
1407 /* 1482 /*
@@ -1421,7 +1496,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1421 ui->hshow = false; 1496 ui->hshow = false;
1422 } 1497 }
1423 ui->hcursor = false; 1498 ui->hcursor = false;
1424 return UI_UPDATE; 1499 return MOVE_UI_UPDATE;
1425 } 1500 }
1426 } else if (button == LEFT_BUTTON) { 1501 } else if (button == LEFT_BUTTON) {
1427 if (is_clue(state, tx, ty)) { 1502 if (is_clue(state, tx, ty)) {
@@ -1444,16 +1519,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1444 } 1519 }
1445 return NULL; 1520 return NULL;
1446 } 1521 }
1447 move_cursor(button, &ui->hx, &ui->hy, w, w, false);
1448 ui->hshow = true;
1449 ui->hcursor = true; 1522 ui->hcursor = true;
1450 return UI_UPDATE; 1523 return move_cursor(button, &ui->hx, &ui->hy, w, w, false, &ui->hshow);
1451 } 1524 }
1452 if (ui->hshow && 1525 if (ui->hshow &&
1453 (button == CURSOR_SELECT)) { 1526 (button == CURSOR_SELECT)) {
1454 ui->hpencil = !ui->hpencil; 1527 ui->hpencil = !ui->hpencil;
1455 ui->hcursor = true; 1528 ui->hcursor = true;
1456 return UI_UPDATE; 1529 return MOVE_UI_UPDATE;
1457 } 1530 }
1458 1531
1459 if (ui->hshow && 1532 if (ui->hshow &&
@@ -1476,10 +1549,31 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1476 if (state->clues->immutable[ui->hy*w+ui->hx]) 1549 if (state->clues->immutable[ui->hy*w+ui->hx])
1477 return NULL; 1550 return NULL;
1478 1551
1552 /*
1553 * If you ask to fill a square with what it already contains,
1554 * or blank it when it's already empty, that has no effect...
1555 */
1556 if ((!ui->hpencil || n == 0) && state->grid[ui->hy*w+ui->hx] == n &&
1557 state->pencil[ui->hy*w+ui->hx] == 0) {
1558 /* ... expect to remove the cursor in mouse mode. */
1559 if (!ui->hcursor) {
1560 ui->hshow = false;
1561 return MOVE_UI_UPDATE;
1562 }
1563 return NULL;
1564 }
1565
1479 sprintf(buf, "%c%d,%d,%d", 1566 sprintf(buf, "%c%d,%d,%d",
1480 (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); 1567 (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n);
1481 1568
1482 if (!ui->hcursor) ui->hshow = false; 1569 /*
1570 * Hide the highlight after a keypress, if it was mouse-
1571 * generated. Also, don't hide it if this move has changed
1572 * pencil marks and the user preference says not to hide the
1573 * highlight in that situation.
1574 */
1575 if (!ui->hcursor && !(ui->hpencil && ui->pencil_keep_highlight))
1576 ui->hshow = false;
1483 1577
1484 return dupstr(buf); 1578 return dupstr(buf);
1485 } 1579 }
@@ -1558,7 +1652,7 @@ static game_state *execute_move(const game_state *from, const char *move)
1558#define SIZE(w) ((w) * TILESIZE + 2*BORDER) 1652#define SIZE(w) ((w) * TILESIZE + 2*BORDER)
1559 1653
1560static void game_compute_size(const game_params *params, int tilesize, 1654static void game_compute_size(const game_params *params, int tilesize,
1561 int *x, int *y) 1655 const game_ui *ui, int *x, int *y)
1562{ 1656{
1563 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 1657 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1564 struct { int tilesize; } ads, *ds = &ads; 1658 struct { int tilesize; } ads, *ds = &ads;
@@ -1614,8 +1708,6 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1614 int i; 1708 int i;
1615 1709
1616 ds->tilesize = 0; 1710 ds->tilesize = 0;
1617 ds->three_d = !getenv("TOWERS_2D");
1618 ds->started = false;
1619 ds->tiles = snewn((w+2)*(w+2), long); 1711 ds->tiles = snewn((w+2)*(w+2), long);
1620 ds->drawn = snewn((w+2)*(w+2)*4, long); 1712 ds->drawn = snewn((w+2)*(w+2)*4, long);
1621 for (i = 0; i < (w+2)*(w+2)*4; i++) 1713 for (i = 0; i < (w+2)*(w+2)*4; i++)
@@ -1633,8 +1725,8 @@ static void game_free_drawstate(drawing *dr, game_drawstate *ds)
1633 sfree(ds); 1725 sfree(ds);
1634} 1726}
1635 1727
1636static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues, 1728static void draw_tile(drawing *dr, game_drawstate *ds, const game_ui *ui,
1637 int x, int y, long tile) 1729 struct clues *clues, int x, int y, long tile)
1638{ 1730{
1639 int w = clues->w /* , a = w*w */; 1731 int w = clues->w /* , a = w*w */;
1640 int tx, ty, bg; 1732 int tx, ty, bg;
@@ -1646,7 +1738,7 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues,
1646 bg = (tile & DF_HIGHLIGHT) ? COL_HIGHLIGHT : COL_BACKGROUND; 1738 bg = (tile & DF_HIGHLIGHT) ? COL_HIGHLIGHT : COL_BACKGROUND;
1647 1739
1648 /* draw tower */ 1740 /* draw tower */
1649 if (ds->three_d && (tile & DF_PLAYAREA) && (tile & DF_DIGIT_MASK)) { 1741 if (ui->three_d && (tile & DF_PLAYAREA) && (tile & DF_DIGIT_MASK)) {
1650 int coords[8]; 1742 int coords[8];
1651 int xoff = X_3D_DISP(tile & DF_DIGIT_MASK, w); 1743 int xoff = X_3D_DISP(tile & DF_DIGIT_MASK, w);
1652 int yoff = Y_3D_DISP(tile & DF_DIGIT_MASK, w); 1744 int yoff = Y_3D_DISP(tile & DF_DIGIT_MASK, w);
@@ -1747,10 +1839,10 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues,
1747 * to put the pencil marks. 1839 * to put the pencil marks.
1748 */ 1840 */
1749 /* Start with the whole square, minus space for impinging towers */ 1841 /* Start with the whole square, minus space for impinging towers */
1750 pl = tx + (ds->three_d ? X_3D_DISP(w,w) : 0); 1842 pl = tx + (ui->three_d ? X_3D_DISP(w,w) : 0);
1751 pr = tx + TILESIZE; 1843 pr = tx + TILESIZE;
1752 pt = ty; 1844 pt = ty;
1753 pb = ty + TILESIZE - (ds->three_d ? Y_3D_DISP(w,w) : 0); 1845 pb = ty + TILESIZE - (ui->three_d ? Y_3D_DISP(w,w) : 0);
1754 1846
1755 /* 1847 /*
1756 * We arrange our pencil marks in a grid layout, with 1848 * We arrange our pencil marks in a grid layout, with
@@ -1821,20 +1913,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1821 int w = state->par.w /*, a = w*w */; 1913 int w = state->par.w /*, a = w*w */;
1822 int i, x, y; 1914 int i, x, y;
1823 1915
1824 if (!ds->started) {
1825 /*
1826 * The initial contents of the window are not guaranteed and
1827 * can vary with front ends. To be on the safe side, all
1828 * games should start by drawing a big background-colour
1829 * rectangle covering the whole window.
1830 */
1831 draw_rect(dr, 0, 0, SIZE(w), SIZE(w), COL_BACKGROUND);
1832
1833 draw_update(dr, 0, 0, SIZE(w), SIZE(w));
1834
1835 ds->started = true;
1836 }
1837
1838 check_errors(state, ds->errtmp); 1916 check_errors(state, ds->errtmp);
1839 1917
1840 /* 1918 /*
@@ -1900,13 +1978,13 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1900 ds->drawn[i*4+2] != bl || ds->drawn[i*4+3] != br) { 1978 ds->drawn[i*4+2] != bl || ds->drawn[i*4+3] != br) {
1901 clip(dr, COORD(x-1), COORD(y-1), TILESIZE, TILESIZE); 1979 clip(dr, COORD(x-1), COORD(y-1), TILESIZE, TILESIZE);
1902 1980
1903 draw_tile(dr, ds, state->clues, x-1, y-1, tr); 1981 draw_tile(dr, ds, ui, state->clues, x-1, y-1, tr);
1904 if (x > 0) 1982 if (x > 0)
1905 draw_tile(dr, ds, state->clues, x-2, y-1, tl); 1983 draw_tile(dr, ds, ui, state->clues, x-2, y-1, tl);
1906 if (y <= w) 1984 if (y <= w)
1907 draw_tile(dr, ds, state->clues, x-1, y, br); 1985 draw_tile(dr, ds, ui, state->clues, x-1, y, br);
1908 if (x > 0 && y <= w) 1986 if (x > 0 && y <= w)
1909 draw_tile(dr, ds, state->clues, x-2, y, bl); 1987 draw_tile(dr, ds, ui, state->clues, x-2, y, bl);
1910 1988
1911 unclip(dr); 1989 unclip(dr);
1912 draw_update(dr, COORD(x-1), COORD(y-1), TILESIZE, TILESIZE); 1990 draw_update(dr, COORD(x-1), COORD(y-1), TILESIZE, TILESIZE);
@@ -1953,26 +2031,21 @@ static int game_status(const game_state *state)
1953 return state->completed ? +1 : 0; 2031 return state->completed ? +1 : 0;
1954} 2032}
1955 2033
1956static bool game_timing_state(const game_state *state, game_ui *ui) 2034static void game_print_size(const game_params *params, const game_ui *ui,
1957{ 2035 float *x, float *y)
1958 if (state->completed)
1959 return false;
1960 return true;
1961}
1962
1963static void game_print_size(const game_params *params, float *x, float *y)
1964{ 2036{
1965 int pw, ph; 2037 int pw, ph;
1966 2038
1967 /* 2039 /*
1968 * We use 9mm squares by default, like Solo. 2040 * We use 9mm squares by default, like Solo.
1969 */ 2041 */
1970 game_compute_size(params, 900, &pw, &ph); 2042 game_compute_size(params, 900, ui, &pw, &ph);
1971 *x = pw / 100.0F; 2043 *x = pw / 100.0F;
1972 *y = ph / 100.0F; 2044 *y = ph / 100.0F;
1973} 2045}
1974 2046
1975static void game_print(drawing *dr, const game_state *state, int tilesize) 2047static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2048 int tilesize)
1976{ 2049{
1977 int w = state->par.w; 2050 int w = state->par.w;
1978 int ink = print_mono_colour(dr, 0); 2051 int ink = print_mono_colour(dr, 0);
@@ -2058,12 +2131,14 @@ const struct game thegame = {
2058 free_game, 2131 free_game,
2059 true, solve_game, 2132 true, solve_game,
2060 true, game_can_format_as_text_now, game_text_format, 2133 true, game_can_format_as_text_now, game_text_format,
2134 get_prefs, set_prefs,
2061 new_ui, 2135 new_ui,
2062 free_ui, 2136 free_ui,
2063 encode_ui, 2137 NULL, /* encode_ui */
2064 decode_ui, 2138 NULL, /* decode_ui */
2065 game_request_keys, 2139 game_request_keys,
2066 game_changed_state, 2140 game_changed_state,
2141 current_key_label,
2067 interpret_move, 2142 interpret_move,
2068 execute_move, 2143 execute_move,
2069 PREFERRED_TILESIZE, game_compute_size, game_set_size, 2144 PREFERRED_TILESIZE, game_compute_size, game_set_size,
@@ -2077,7 +2152,7 @@ const struct game thegame = {
2077 game_status, 2152 game_status,
2078 true, false, game_print_size, game_print, 2153 true, false, game_print_size, game_print,
2079 false, /* wants_statusbar */ 2154 false, /* wants_statusbar */
2080 false, game_timing_state, 2155 false, NULL, /* timing_state */
2081 REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */ 2156 REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */
2082}; 2157};
2083 2158
diff --git a/apps/plugins/puzzles/src/tracks.R b/apps/plugins/puzzles/src/tracks.R
deleted file mode 100644
index 8b0ac97e0f..0000000000
--- a/apps/plugins/puzzles/src/tracks.R
+++ /dev/null
@@ -1,24 +0,0 @@
1# -*- makefile -*-
2
3TRACKS_EXTRA = dsf findloop
4
5tracks : [X] GTK COMMON tracks TRACKS_EXTRA tracks-icon|no-icon
6
7tracks : [G] WINDOWS COMMON tracks TRACKS_EXTRA tracks.res|noicon.res
8
9ALL += tracks[COMBINED] TRACKS_EXTRA
10
11trackssolver : [U] tracks[STANDALONE_SOLVER] TRACKS_EXTRA STANDALONE
12trackssolver : [C] tracks[STANDALONE_SOLVER] TRACKS_EXTRA STANDALONE
13
14!begin am gtk
15GAMES += tracks
16!end
17
18!begin >list.c
19 A(tracks) \
20!end
21
22!begin >gamedesc.txt
23tracks:tracks.exe:Tracks:Path-finding railway track puzzle:Fill in the railway track according to the clues.
24!end
diff --git a/apps/plugins/puzzles/src/tracks.c b/apps/plugins/puzzles/src/tracks.c
index 3cf5df70a1..a2d4560907 100644
--- a/apps/plugins/puzzles/src/tracks.c
+++ b/apps/plugins/puzzles/src/tracks.c
@@ -20,7 +20,12 @@
20#include <string.h> 20#include <string.h>
21#include <assert.h> 21#include <assert.h>
22#include <ctype.h> 22#include <ctype.h>
23#include <math.h> 23#include <limits.h>
24#ifdef NO_TGMATH_H
25# include <math.h>
26#else
27# include <tgmath.h>
28#endif
24 29
25#include "puzzles.h" 30#include "puzzles.h"
26 31
@@ -196,6 +201,8 @@ static const char *validate_params(const game_params *params, bool full)
196 */ 201 */
197 if (params->w < 4 || params->h < 4) 202 if (params->w < 4 || params->h < 4)
198 return "Width and height must both be at least four"; 203 return "Width and height must both be at least four";
204 if (params->w > INT_MAX / params->h)
205 return "Width times height must not be unreasonably large";
199 return NULL; 206 return NULL;
200} 207}
201 208
@@ -242,6 +249,9 @@ static const int nbits[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
242#define S_CLUE 8 249#define S_CLUE 8
243#define S_MARK 16 250#define S_MARK 16
244 251
252#define S_FLASH_SHIFT 8 /* Position of tile in solved track */
253#define S_FLASH_WIDTH 8 /* Width of above sub-field */
254#define S_FLASH_MASK ((1 << S_FLASH_WIDTH) - 1)
245#define S_TRACK_SHIFT 16 /* U/D/L/R flags for edge track indicators */ 255#define S_TRACK_SHIFT 16 /* U/D/L/R flags for edge track indicators */
246#define S_NOTRACK_SHIFT 20 /* U/D/L/R flags for edge no-track indicators */ 256#define S_NOTRACK_SHIFT 20 /* U/D/L/R flags for edge no-track indicators */
247 257
@@ -904,7 +914,7 @@ static game_state *new_game(midend *me, const game_params *params, const char *d
904} 914}
905 915
906struct solver_scratch { 916struct solver_scratch {
907 int *dsf; 917 DSF *dsf;
908}; 918};
909 919
910static int solve_set_sflag(game_state *state, int x, int y, 920static int solve_set_sflag(game_state *state, int x, int y,
@@ -919,8 +929,8 @@ static int solve_set_sflag(game_state *state, int x, int y,
919 if (state->sflags[i] & (f == S_TRACK ? S_NOTRACK : S_TRACK)) { 929 if (state->sflags[i] & (f == S_TRACK ? S_NOTRACK : S_TRACK)) {
920 solverdebug(("opposite flag already set there, marking IMPOSSIBLE")); 930 solverdebug(("opposite flag already set there, marking IMPOSSIBLE"));
921 state->impossible = true; 931 state->impossible = true;
922 } 932 } else
923 state->sflags[i] |= f; 933 state->sflags[i] |= f;
924 return 1; 934 return 1;
925} 935}
926 936
@@ -937,8 +947,8 @@ static int solve_set_eflag(game_state *state, int x, int y, int d,
937 if (sf & (f == E_TRACK ? E_NOTRACK : E_TRACK)) { 947 if (sf & (f == E_TRACK ? E_NOTRACK : E_TRACK)) {
938 solverdebug(("opposite flag already set there, marking IMPOSSIBLE")); 948 solverdebug(("opposite flag already set there, marking IMPOSSIBLE"));
939 state->impossible = true; 949 state->impossible = true;
940 } 950 } else
941 S_E_SET(state, x, y, d, f); 951 S_E_SET(state, x, y, d, f);
942 return 1; 952 return 1;
943} 953}
944 954
@@ -1306,7 +1316,7 @@ static int solve_check_neighbours(game_state *state, bool both_ways)
1306} 1316}
1307 1317
1308static int solve_check_loop_sub(game_state *state, int x, int y, int dir, 1318static int solve_check_loop_sub(game_state *state, int x, int y, int dir,
1309 int *dsf, int startc, int endc) 1319 DSF *dsf, int startc, int endc)
1310{ 1320{
1311 int w = state->p.w, h = state->p.h, i = y*w+x, j, k; 1321 int w = state->p.w, h = state->p.h, i = y*w+x, j, k;
1312 bool satisfied = true; 1322 bool satisfied = true;
@@ -1358,13 +1368,13 @@ static int solve_check_loop_sub(game_state *state, int x, int y, int dir,
1358static int solve_check_loop(game_state *state) 1368static int solve_check_loop(game_state *state)
1359{ 1369{
1360 int w = state->p.w, h = state->p.h, x, y, i, j, did = 0; 1370 int w = state->p.w, h = state->p.h, x, y, i, j, did = 0;
1361 int *dsf, startc, endc; 1371 DSF *dsf;
1372 int startc, endc;
1362 1373
1363 /* TODO eventually we should pull this out into a solver struct and keep it 1374 /* TODO eventually we should pull this out into a solver struct and keep it
1364 updated as we connect squares. For now we recreate it every time we try 1375 updated as we connect squares. For now we recreate it every time we try
1365 this particular solver step. */ 1376 this particular solver step. */
1366 dsf = snewn(w*h, int); 1377 dsf = dsf_new(w*h);
1367 dsf_init(dsf, w*h);
1368 1378
1369 /* Work out the connectedness of the current loop set. */ 1379 /* Work out the connectedness of the current loop set. */
1370 for (x = 0; x < w; x++) { 1380 for (x = 0; x < w; x++) {
@@ -1402,7 +1412,7 @@ static int solve_check_loop(game_state *state)
1402 } 1412 }
1403 } 1413 }
1404 1414
1405 sfree(dsf); 1415 dsf_free(dsf);
1406 1416
1407 return did; 1417 return did;
1408} 1418}
@@ -1455,8 +1465,8 @@ static int solve_bridge_sub(game_state *state, int x, int y, int d,
1455 assert(d == D || d == R); 1465 assert(d == D || d == R);
1456 1466
1457 if (!sc->dsf) 1467 if (!sc->dsf)
1458 sc->dsf = snew_dsf(wh); 1468 sc->dsf = dsf_new(wh);
1459 dsf_init(sc->dsf, wh); 1469 dsf_reinit(sc->dsf);
1460 1470
1461 for (xi = 0; xi < w; xi++) { 1471 for (xi = 0; xi < w; xi++) {
1462 for (yi = 0; yi < h; yi++) { 1472 for (yi = 0; yi < h; yi++) {
@@ -1595,7 +1605,7 @@ static int tracks_solve(game_state *state, int diff, int *max_diff_out)
1595 break; 1605 break;
1596 } 1606 }
1597 1607
1598 sfree(sc->dsf); 1608 dsf_free(sc->dsf);
1599 1609
1600 if (max_diff_out) 1610 if (max_diff_out)
1601 *max_diff_out = max_diff; 1611 *max_diff_out = max_diff;
@@ -1775,7 +1785,7 @@ static void debug_state(game_state *state, const char *what) {
1775} 1785}
1776 1786
1777static void dsf_update_completion(game_state *state, int ax, int ay, 1787static void dsf_update_completion(game_state *state, int ax, int ay,
1778 char dir, int *dsf) 1788 char dir, DSF *dsf)
1779{ 1789{
1780 int w = state->p.w, ai = ay*w+ax, bx, by, bi; 1790 int w = state->p.w, ai = ay*w+ax, bx, by, bi;
1781 1791
@@ -1820,12 +1830,37 @@ static int tracks_neighbour(int vertex, void *vctx)
1820 return -1; 1830 return -1;
1821} 1831}
1822 1832
1833/*
1834 * The completion flash moves along the track, so we want to label
1835 * each tile with how far along the track it is. This is represented
1836 * as an eight-bit field, which is more than enough when the
1837 * completion flash is only 0.5 s long.
1838 */
1839static void set_flash_data(game_state *state)
1840{
1841 int ntrack = 0, x, y, n, d;
1842 const int w = state->p.w;
1843
1844 for (x = 0; x < w; x++)
1845 ntrack += state->numbers->numbers[x];
1846 n = 0; x = 0; y = state->numbers->row_s; d = R;
1847 do {
1848 state->sflags[y*w + x] &= ~(S_FLASH_MASK << S_FLASH_SHIFT);
1849 state->sflags[y*w + x] |=
1850 n++ * (S_FLASH_MASK / (ntrack - 1)) << S_FLASH_SHIFT;
1851 d = F(d); /* Find the direction we just arrived from. */
1852 d = S_E_DIRS(state, x, y, E_TRACK) & ~d; /* Other track from here. */
1853 x += DX(d); y += DY(d); /* Move to the next tile. */
1854 } while (INGRID(state, x, y));
1855}
1856
1823static bool check_completion(game_state *state, bool mark) 1857static bool check_completion(game_state *state, bool mark)
1824{ 1858{
1825 int w = state->p.w, h = state->p.h, x, y, i, target; 1859 int w = state->p.w, h = state->p.h, x, y, i, target;
1826 bool ret = true; 1860 bool ret = true, pathret;
1827 int ntrack, nnotrack, ntrackcomplete; 1861 int ntrack, nnotrack, ntrackcomplete;
1828 int *dsf, pathclass; 1862 DSF *dsf;
1863 int pathclass;
1829 struct findloopstate *fls; 1864 struct findloopstate *fls;
1830 struct tracks_neighbour_ctx ctx; 1865 struct tracks_neighbour_ctx ctx;
1831 1866
@@ -1844,60 +1879,7 @@ static bool check_completion(game_state *state, bool mark)
1844 } 1879 }
1845 } 1880 }
1846 1881
1847 /* A cell is 'complete', for the purposes of marking the game as 1882 dsf = dsf_new(w*h);
1848 * finished, if it has two edges marked as TRACK. But it only has
1849 * to have one edge marked as TRACK, or be filled in as trackful
1850 * without any specific edges known, to count towards checking
1851 * row/column clue errors. */
1852 for (x = 0; x < w; x++) {
1853 target = state->numbers->numbers[x];
1854 ntrack = nnotrack = ntrackcomplete = 0;
1855 for (y = 0; y < h; y++) {
1856 if (S_E_COUNT(state, x, y, E_TRACK) > 0 ||
1857 state->sflags[y*w+x] & S_TRACK)
1858 ntrack++;
1859 if (S_E_COUNT(state, x, y, E_TRACK) == 2)
1860 ntrackcomplete++;
1861 if (state->sflags[y*w+x] & S_NOTRACK)
1862 nnotrack++;
1863 }
1864 if (mark) {
1865 if (ntrack > target || nnotrack > (h-target)) {
1866 debug(("col %d error: target %d, track %d, notrack %d",
1867 x, target, ntrack, nnotrack));
1868 state->num_errors[x] = 1;
1869 ret = false;
1870 }
1871 }
1872 if (ntrackcomplete != target)
1873 ret = false;
1874 }
1875 for (y = 0; y < h; y++) {
1876 target = state->numbers->numbers[w+y];
1877 ntrack = nnotrack = ntrackcomplete = 0;
1878 for (x = 0; x < w; x++) {
1879 if (S_E_COUNT(state, x, y, E_TRACK) > 0 ||
1880 state->sflags[y*w+x] & S_TRACK)
1881 ntrack++;
1882 if (S_E_COUNT(state, x, y, E_TRACK) == 2)
1883 ntrackcomplete++;
1884 if (state->sflags[y*w+x] & S_NOTRACK)
1885 nnotrack++;
1886 }
1887 if (mark) {
1888 if (ntrack > target || nnotrack > (w-target)) {
1889 debug(("row %d error: target %d, track %d, notrack %d",
1890 y, target, ntrack, nnotrack));
1891 state->num_errors[w+y] = 1;
1892 ret = false;
1893 }
1894 }
1895 if (ntrackcomplete != target)
1896 ret = false;
1897 }
1898
1899 dsf = snewn(w*h, int);
1900 dsf_init(dsf, w*h);
1901 1883
1902 for (x = 0; x < w; x++) { 1884 for (x = 0; x < w; x++) {
1903 for (y = 0; y < h; y++) { 1885 for (y = 0; y < h; y++) {
@@ -1949,9 +1931,75 @@ static bool check_completion(game_state *state, bool mark)
1949 } 1931 }
1950 } 1932 }
1951 1933
1952 if (mark) 1934 /*
1935 * A cell is 'complete', for the purposes of marking the game as
1936 * finished, if it has two edges marked as TRACK. But it only has
1937 * to have one edge marked as TRACK, or be filled in as trackful
1938 * without any specific edges known, to count towards checking
1939 * row/column clue errors.
1940 *
1941 * This changes if we haven't found any other errors by this
1942 * point, so the player has constructed a route from A to B. In
1943 * that case, we highlight any row/column where the actually laid
1944 * tracks don't match the clue.
1945 */
1946 pathret = ret; /* Do we have a plausible solution so far? */
1947 for (x = 0; x < w; x++) {
1948 target = state->numbers->numbers[x];
1949 ntrack = nnotrack = ntrackcomplete = 0;
1950 for (y = 0; y < h; y++) {
1951 if (S_E_COUNT(state, x, y, E_TRACK) > 0 ||
1952 state->sflags[y*w+x] & S_TRACK)
1953 ntrack++;
1954 if (S_E_COUNT(state, x, y, E_TRACK) == 2)
1955 ntrackcomplete++;
1956 if (state->sflags[y*w+x] & S_NOTRACK)
1957 nnotrack++;
1958 }
1959 if (mark) {
1960 if (ntrack > target || nnotrack > (h-target) ||
1961 (pathret && ntrackcomplete != target)) {
1962 debug(("col %d error: target %d, track %d, notrack %d, "
1963 "pathret %d, trackcomplete %d",
1964 x, target, ntrack, nnotrack, pathret, ntrackcomplete));
1965 state->num_errors[x] = 1;
1966 ret = false;
1967 }
1968 }
1969 if (ntrackcomplete != target)
1970 ret = false;
1971 }
1972 for (y = 0; y < h; y++) {
1973 target = state->numbers->numbers[w+y];
1974 ntrack = nnotrack = ntrackcomplete = 0;
1975 for (x = 0; x < w; x++) {
1976 if (S_E_COUNT(state, x, y, E_TRACK) > 0 ||
1977 state->sflags[y*w+x] & S_TRACK)
1978 ntrack++;
1979 if (S_E_COUNT(state, x, y, E_TRACK) == 2)
1980 ntrackcomplete++;
1981 if (state->sflags[y*w+x] & S_NOTRACK)
1982 nnotrack++;
1983 }
1984 if (mark) {
1985 if (ntrack > target || nnotrack > (w-target) ||
1986 (pathret && ntrackcomplete != target)) {
1987 debug(("row %d error: target %d, track %d, notrack %d, "
1988 "pathret %d, trackcomplete %d",
1989 y, target, ntrack, nnotrack, pathret, ntrackcomplete));
1990 state->num_errors[w+y] = 1;
1991 ret = false;
1992 }
1993 }
1994 if (ntrackcomplete != target)
1995 ret = false;
1996 }
1997
1998 if (mark) {
1953 state->completed = ret; 1999 state->completed = ret;
1954 sfree(dsf); 2000 if (ret) set_flash_data(state);
2001 }
2002 dsf_free(dsf);
1955 return ret; 2003 return ret;
1956} 2004}
1957 2005
@@ -1974,7 +2022,7 @@ static game_ui *new_ui(const game_state *state)
1974 ui->notrack = false; 2022 ui->notrack = false;
1975 ui->dragging = false; 2023 ui->dragging = false;
1976 ui->drag_sx = ui->drag_sy = ui->drag_ex = ui->drag_ey = -1; 2024 ui->drag_sx = ui->drag_sy = ui->drag_ex = ui->drag_ey = -1;
1977 ui->cursor_active = false; 2025 ui->cursor_active = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1978 ui->curx = ui->cury = 1; 2026 ui->curx = ui->cury = 1;
1979 2027
1980 return ui; 2028 return ui;
@@ -1985,27 +2033,19 @@ static void free_ui(game_ui *ui)
1985 sfree(ui); 2033 sfree(ui);
1986} 2034}
1987 2035
1988static char *encode_ui(const game_ui *ui)
1989{
1990 return NULL;
1991}
1992
1993static void decode_ui(game_ui *ui, const char *encoding)
1994{
1995}
1996
1997static void game_changed_state(game_ui *ui, const game_state *oldstate, 2036static void game_changed_state(game_ui *ui, const game_state *oldstate,
1998 const game_state *newstate) 2037 const game_state *newstate)
1999{ 2038{
2000} 2039}
2001 2040
2002#define PREFERRED_TILE_SIZE 30 2041#define PREFERRED_TILE_SIZE 33
2003#define HALFSZ (ds->sz6*3) 2042#define HALFSZ (ds->sz6*3)
2004#define THIRDSZ (ds->sz6*2) 2043#define THIRDSZ (ds->sz6*2)
2005#define TILE_SIZE (ds->sz6*6) 2044#define TILE_SIZE (ds->sz6*6)
2006 2045
2007#define BORDER (TILE_SIZE/8) 2046#define MAX_BORDER (TILE_SIZE/8)
2008#define LINE_THICK (TILE_SIZE/16) 2047#define LINE_THICK (TILE_SIZE/16)
2048#define BORDER (ds->border)
2009#define GRID_LINE_TL (ds->grid_line_tl) 2049#define GRID_LINE_TL (ds->grid_line_tl)
2010#define GRID_LINE_BR (ds->grid_line_br) 2050#define GRID_LINE_BR (ds->grid_line_br)
2011#define GRID_LINE_ALL (ds->grid_line_all) 2051#define GRID_LINE_ALL (ds->grid_line_all)
@@ -2028,7 +2068,7 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
2028#define DS_CSHIFT 20 /* R/U/L/D shift, for cursor-on-edge */ 2068#define DS_CSHIFT 20 /* R/U/L/D shift, for cursor-on-edge */
2029 2069
2030struct game_drawstate { 2070struct game_drawstate {
2031 int sz6, grid_line_all, grid_line_tl, grid_line_br; 2071 int sz6, border, grid_line_all, grid_line_tl, grid_line_br;
2032 bool started; 2072 bool started;
2033 2073
2034 int w, h, sz; 2074 int w, h, sz;
@@ -2120,6 +2160,35 @@ static bool ui_can_flip_square(const game_state *state, int x, int y, bool notra
2120 return true; 2160 return true;
2121} 2161}
2122 2162
2163static const char *current_key_label(const game_ui *ui,
2164 const game_state *state, int button)
2165{
2166 if (IS_CURSOR_SELECT(button) && ui->cursor_active) {
2167 int gx = ui->curx / 2, gy = ui->cury / 2;
2168 int w = state->p.w;
2169 int direction =
2170 ((ui->curx % 2) == 0) ? L : ((ui->cury % 2) == 0) ? U : 0;
2171 if (direction &&
2172 ui_can_flip_edge(state, gx, gy, direction,
2173 button == CURSOR_SELECT2)) {
2174 unsigned ef = S_E_FLAGS(state, gx, gy, direction);
2175 switch (button) {
2176 case CURSOR_SELECT: return (ef & E_TRACK) ? "Clear" : "Track";
2177 case CURSOR_SELECT2: return (ef & E_NOTRACK) ? "Clear" : "X";
2178 }
2179 }
2180 if (!direction &&
2181 ui_can_flip_square(state, gx, gy, button == CURSOR_SELECT2)) {
2182 unsigned sf = state->sflags[gy*w+gx];
2183 switch (button) {
2184 case CURSOR_SELECT: return (sf & S_TRACK) ? "Clear" : "Track";
2185 case CURSOR_SELECT2: return (sf & S_NOTRACK) ? "Clear" : "X";
2186 }
2187 }
2188 }
2189 return "";
2190}
2191
2123static char *edge_flip_str(const game_state *state, int x, int y, int dir, bool notrack, char *buf) { 2192static char *edge_flip_str(const game_state *state, int x, int y, int dir, bool notrack, char *buf) {
2124 unsigned ef = S_E_FLAGS(state, x, y, dir); 2193 unsigned ef = S_E_FLAGS(state, x, y, dir);
2125 char c; 2194 char c;
@@ -2193,6 +2262,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2193 2262
2194 if (!INGRID(state, gx, gy)) { 2263 if (!INGRID(state, gx, gy)) {
2195 /* can't drag from off grid */ 2264 /* can't drag from off grid */
2265 ui->drag_sx = ui->drag_sy = -1;
2196 return NULL; 2266 return NULL;
2197 } 2267 }
2198 2268
@@ -2209,13 +2279,13 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2209 ui->drag_sx = ui->drag_ex = gx; 2279 ui->drag_sx = ui->drag_ex = gx;
2210 ui->drag_sy = ui->drag_ey = gy; 2280 ui->drag_sy = ui->drag_ey = gy;
2211 2281
2212 return UI_UPDATE; 2282 return MOVE_UI_UPDATE;
2213 } 2283 }
2214 2284
2215 if (IS_MOUSE_DRAG(button)) { 2285 if (IS_MOUSE_DRAG(button)) {
2216 ui->cursor_active = false; 2286 ui->cursor_active = false;
2217 update_ui_drag(state, ui, gx, gy); 2287 update_ui_drag(state, ui, gx, gy);
2218 return UI_UPDATE; 2288 return MOVE_UI_UPDATE;
2219 } 2289 }
2220 2290
2221 if (IS_MOUSE_RELEASE(button)) { 2291 if (IS_MOUSE_RELEASE(button)) {
@@ -2252,12 +2322,12 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2252 cy = CENTERED_COORD(gy); 2322 cy = CENTERED_COORD(gy);
2253 2323
2254 if (!INGRID(state, gx, gy) || FROMCOORD(x) != gx || FROMCOORD(y) != gy) 2324 if (!INGRID(state, gx, gy) || FROMCOORD(x) != gx || FROMCOORD(y) != gy)
2255 return UI_UPDATE; 2325 return MOVE_UI_UPDATE;
2256 2326
2257 if (max(abs(x-cx),abs(y-cy)) < TILE_SIZE/4) { 2327 if (max(abs(x-cx),abs(y-cy)) < TILE_SIZE/4) {
2258 if (ui_can_flip_square(state, gx, gy, button == RIGHT_RELEASE)) 2328 if (ui_can_flip_square(state, gx, gy, button == RIGHT_RELEASE))
2259 return square_flip_str(state, gx, gy, button == RIGHT_RELEASE, tmpbuf); 2329 return square_flip_str(state, gx, gy, button == RIGHT_RELEASE, tmpbuf);
2260 return UI_UPDATE; 2330 return MOVE_UI_UPDATE;
2261 } else { 2331 } else {
2262 if (abs(x-cx) < abs(y-cy)) { 2332 if (abs(x-cx) < abs(y-cy)) {
2263 /* Closest to top/bottom edge. */ 2333 /* Closest to top/bottom edge. */
@@ -2271,7 +2341,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2271 return edge_flip_str(state, gx, gy, direction, 2341 return edge_flip_str(state, gx, gy, direction,
2272 button == RIGHT_RELEASE, tmpbuf); 2342 button == RIGHT_RELEASE, tmpbuf);
2273 else 2343 else
2274 return UI_UPDATE; 2344 return MOVE_UI_UPDATE;
2275 } 2345 }
2276 } 2346 }
2277 } 2347 }
@@ -2284,7 +2354,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2284 2354
2285 if (!ui->cursor_active) { 2355 if (!ui->cursor_active) {
2286 ui->cursor_active = true; 2356 ui->cursor_active = true;
2287 return UI_UPDATE; 2357 return MOVE_UI_UPDATE;
2288 } 2358 }
2289 2359
2290 ui->curx = ui->curx + dx; 2360 ui->curx = ui->curx + dx;
@@ -2295,17 +2365,17 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2295 } 2365 }
2296 ui->curx = min(max(ui->curx, 1), 2*w-1); 2366 ui->curx = min(max(ui->curx, 1), 2*w-1);
2297 ui->cury = min(max(ui->cury, 1), 2*h-1); 2367 ui->cury = min(max(ui->cury, 1), 2*h-1);
2298 return UI_UPDATE; 2368 return MOVE_UI_UPDATE;
2299 } 2369 }
2300 2370
2301 if (IS_CURSOR_SELECT(button)) { 2371 if (IS_CURSOR_SELECT(button)) {
2302 if (!ui->cursor_active) { 2372 if (!ui->cursor_active) {
2303 ui->cursor_active = true; 2373 ui->cursor_active = true;
2304 return UI_UPDATE; 2374 return MOVE_UI_UPDATE;
2305 } 2375 }
2306 /* click on square corner does nothing (shouldn't get here) */ 2376 /* click on square corner does nothing (shouldn't get here) */
2307 if ((ui->curx % 2) == 0 && (ui->cury % 2 == 0)) 2377 if ((ui->curx % 2) == 0 && (ui->cury % 2 == 0))
2308 return UI_UPDATE; 2378 return MOVE_UI_UPDATE;
2309 2379
2310 gx = ui->curx / 2; 2380 gx = ui->curx / 2;
2311 gy = ui->cury / 2; 2381 gy = ui->cury / 2;
@@ -2317,7 +2387,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2317 else if (!direction && 2387 else if (!direction &&
2318 ui_can_flip_square(state, gx, gy, button == CURSOR_SELECT2)) 2388 ui_can_flip_square(state, gx, gy, button == CURSOR_SELECT2))
2319 return square_flip_str(state, gx, gy, button == CURSOR_SELECT2, tmpbuf); 2389 return square_flip_str(state, gx, gy, button == CURSOR_SELECT2, tmpbuf);
2320 return UI_UPDATE; 2390 return MOVE_UI_UPDATE;
2321 } 2391 }
2322 2392
2323#if 0 2393#if 0
@@ -2334,6 +2404,7 @@ static game_state *execute_move(const game_state *state, const char *move)
2334 int w = state->p.w, x, y, n, i; 2404 int w = state->p.w, x, y, n, i;
2335 char c, d; 2405 char c, d;
2336 unsigned f; 2406 unsigned f;
2407 bool move_is_solve = false;
2337 game_state *ret = dup_game(state); 2408 game_state *ret = dup_game(state);
2338 2409
2339 /* this is breaking the bank on GTK, which vsprintf's into a fixed-size buffer 2410 /* this is breaking the bank on GTK, which vsprintf's into a fixed-size buffer
@@ -2344,6 +2415,7 @@ static game_state *execute_move(const game_state *state, const char *move)
2344 c = *move; 2415 c = *move;
2345 if (c == 'S') { 2416 if (c == 'S') {
2346 ret->used_solve = true; 2417 ret->used_solve = true;
2418 move_is_solve = true;
2347 move++; 2419 move++;
2348 } else if (c == 'T' || c == 't' || c == 'N' || c == 'n') { 2420 } else if (c == 'T' || c == 't' || c == 'N' || c == 'n') {
2349 /* set track, clear track; set notrack, clear notrack */ 2421 /* set track, clear track; set notrack, clear notrack */
@@ -2355,6 +2427,9 @@ static game_state *execute_move(const game_state *state, const char *move)
2355 f = (c == 'T' || c == 't') ? S_TRACK : S_NOTRACK; 2427 f = (c == 'T' || c == 't') ? S_TRACK : S_NOTRACK;
2356 2428
2357 if (d == 'S') { 2429 if (d == 'S') {
2430 if (!ui_can_flip_square(ret, x, y, f == S_NOTRACK) &&
2431 !move_is_solve)
2432 goto badmove;
2358 if (c == 'T' || c == 'N') 2433 if (c == 'T' || c == 'N')
2359 ret->sflags[y*w+x] |= f; 2434 ret->sflags[y*w+x] |= f;
2360 else 2435 else
@@ -2364,6 +2439,9 @@ static game_state *execute_move(const game_state *state, const char *move)
2364 unsigned df = 1<<i; 2439 unsigned df = 1<<i;
2365 2440
2366 if (MOVECHAR(df) == d) { 2441 if (MOVECHAR(df) == d) {
2442 if (!ui_can_flip_edge(ret, x, y, df, f == S_NOTRACK) &&
2443 !move_is_solve)
2444 goto badmove;
2367 if (c == 'T' || c == 'N') 2445 if (c == 'T' || c == 'N')
2368 S_E_SET(ret, x, y, df, f); 2446 S_E_SET(ret, x, y, df, f);
2369 else 2447 else
@@ -2401,13 +2479,21 @@ static game_state *execute_move(const game_state *state, const char *move)
2401#define FLASH_TIME 0.5F 2479#define FLASH_TIME 0.5F
2402 2480
2403static void game_compute_size(const game_params *params, int tilesize, 2481static void game_compute_size(const game_params *params, int tilesize,
2404 int *x, int *y) 2482 const game_ui *ui, int *x, int *y)
2405{ 2483{
2406 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2484 /* Ick: fake up `ds->sz6' and `ds->border` for macro expansion purposes */
2407 struct { 2485 struct {
2408 int sz6; 2486 int sz6, border;
2409 } ads, *ds = &ads; 2487 } ads, *ds = &ads;
2410 ads.sz6 = tilesize/6; 2488 ads.sz6 = tilesize/6;
2489 ads.border = MAX_BORDER;
2490 /*
2491 * Allow a reduced border at small tile sizes because the steps
2492 * are quite large and it's better to have a thin border than
2493 * to go down to a smaller tile size.
2494 */
2495 if (ads.border <= 5)
2496 ads.border = min(tilesize % 6, MAX_BORDER);
2411 *x = (params->w+2) * TILE_SIZE + 2 * BORDER; 2497 *x = (params->w+2) * TILE_SIZE + 2 * BORDER;
2412 *y = (params->h+2) * TILE_SIZE + 2 * BORDER; 2498 *y = (params->h+2) * TILE_SIZE + 2 * BORDER;
2413} 2499}
@@ -2416,14 +2502,16 @@ static void game_set_size(drawing *dr, game_drawstate *ds,
2416 const game_params *params, int tilesize) 2502 const game_params *params, int tilesize)
2417{ 2503{
2418 ds->sz6 = tilesize/6; 2504 ds->sz6 = tilesize/6;
2505 ds->border = MAX_BORDER;
2506 if (ds->border <= 5)
2507 ds->border = min(tilesize % 6, MAX_BORDER);
2419 ds->grid_line_all = max(LINE_THICK, 1); 2508 ds->grid_line_all = max(LINE_THICK, 1);
2420 ds->grid_line_br = ds->grid_line_all / 2; 2509 ds->grid_line_br = ds->grid_line_all / 2;
2421 ds->grid_line_tl = ds->grid_line_all - ds->grid_line_br; 2510 ds->grid_line_tl = ds->grid_line_all - ds->grid_line_br;
2422} 2511}
2423 2512
2424enum { 2513enum {
2425 COL_BACKGROUND, COL_LOWLIGHT, COL_HIGHLIGHT, 2514 COL_BACKGROUND, COL_TRACK_BACKGROUND,
2426 COL_TRACK_BACKGROUND = COL_LOWLIGHT,
2427 COL_GRID, COL_CLUE, COL_CURSOR, 2515 COL_GRID, COL_CLUE, COL_CURSOR,
2428 COL_TRACK, COL_TRACK_CLUE, COL_SLEEPER, 2516 COL_TRACK, COL_TRACK_CLUE, COL_SLEEPER,
2429 COL_DRAGON, COL_DRAGOFF, 2517 COL_DRAGON, COL_DRAGOFF,
@@ -2436,14 +2524,15 @@ static float *game_colours(frontend *fe, int *ncolours)
2436 float *ret = snewn(3 * NCOLOURS, float); 2524 float *ret = snewn(3 * NCOLOURS, float);
2437 int i; 2525 int i;
2438 2526
2439 game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); 2527 game_mkhighlight(fe, ret, COL_BACKGROUND, -1, COL_TRACK_BACKGROUND);
2528 colour_mix(&ret[COL_BACKGROUND*3], &ret[COL_TRACK_BACKGROUND*3], 0.5F,
2529 &ret[COL_GRID*3]);
2440 2530
2441 for (i = 0; i < 3; i++) { 2531 for (i = 0; i < 3; i++) {
2442 ret[COL_TRACK_CLUE * 3 + i] = 0.0F; 2532 ret[COL_TRACK_CLUE * 3 + i] = 0.0F;
2443 ret[COL_TRACK * 3 + i] = 0.5F; 2533 ret[COL_TRACK * 3 + i] = 0.5F;
2444 ret[COL_CLUE * 3 + i] = 0.0F; 2534 ret[COL_CLUE * 3 + i] = 0.0F;
2445 ret[COL_GRID * 3 + i] = 0.75F; 2535 ret[COL_CURSOR * 3 + i] = 0.3F;
2446 ret[COL_CURSOR * 3 + i] = 0.6F;
2447 ret[COL_ERROR_BACKGROUND * 3 + i] = 1.0F; 2536 ret[COL_ERROR_BACKGROUND * 3 + i] = 1.0F;
2448 } 2537 }
2449 2538
@@ -2535,7 +2624,8 @@ static void draw_thick_circle_outline(drawing *dr, float thickness,
2535 x2 = cx + r*(float)cos(th2); 2624 x2 = cx + r*(float)cos(th2);
2536 y1 = cy + r*(float)sin(th); 2625 y1 = cy + r*(float)sin(th);
2537 y2 = cy + r*(float)sin(th2); 2626 y2 = cy + r*(float)sin(th2);
2538 debug(("circ outline: x=%.2f -> %.2f, thick=%.2f", x1, x2, thickness)); 2627 debug(("circ outline: x=%.2f -> %.2f, thick=%.2f\n",
2628 x1, x2, thickness));
2539 draw_thick_line(dr, thickness, x1, y1, x2, y2, colour); 2629 draw_thick_line(dr, thickness, x1, y1, x2, y2, colour);
2540 } 2630 }
2541} 2631}
@@ -2665,7 +2755,7 @@ static void draw_square(drawing *dr, game_drawstate *ds,
2665 curx = ox + TILE_SIZE - off; curw = 2*off + 1; 2755 curx = ox + TILE_SIZE - off; curw = 2*off + 1;
2666 } 2756 }
2667 2757
2668 draw_rect_outline(dr, curx, cury, curw, curh, COL_GRID); 2758 draw_rect_outline(dr, curx, cury, curw, curh, COL_CURSOR);
2669 } 2759 }
2670 2760
2671 /* Draw tracks themselves */ 2761 /* Draw tracks themselves */
@@ -2777,20 +2867,11 @@ static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldst
2777 const game_state *state, int dir, const game_ui *ui, 2867 const game_state *state, int dir, const game_ui *ui,
2778 float animtime, float flashtime) 2868 float animtime, float flashtime)
2779{ 2869{
2780 int i, x, y, flashing = 0, w = ds->w, h = ds->h; 2870 int i, x, y, flashing, w = ds->w, h = ds->h;
2781 bool force = false; 2871 bool force = false;
2782 game_state *drag_state = NULL; 2872 game_state *drag_state = NULL;
2783 2873
2784 if (!ds->started) { 2874 if (!ds->started) {
2785 /*
2786 * The initial contents of the window are not guaranteed and
2787 * can vary with front ends. To be on the safe side, all games
2788 * should start by drawing a big background-colour rectangle
2789 * covering the whole window.
2790 */
2791 draw_rect(dr, 0, 0, (w+2)*TILE_SIZE + 2*BORDER, (h+2)*TILE_SIZE + 2*BORDER,
2792 COL_BACKGROUND);
2793
2794 draw_loop_ends(dr, ds, state, COL_CLUE); 2875 draw_loop_ends(dr, ds, state, COL_CLUE);
2795 2876
2796 draw_rect(dr, COORD(0) - GRID_LINE_BR, COORD(0) - GRID_LINE_BR, 2877 draw_rect(dr, COORD(0) - GRID_LINE_BR, COORD(0) - GRID_LINE_BR,
@@ -2812,11 +2893,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldst
2812 } 2893 }
2813 } 2894 }
2814 2895
2815 if (flashtime > 0 &&
2816 (flashtime <= FLASH_TIME/3 ||
2817 flashtime >= FLASH_TIME*2/3))
2818 flashing = DS_FLASH;
2819
2820 if (ui->dragging) 2896 if (ui->dragging)
2821 drag_state = copy_and_apply_drag(state, ui); 2897 drag_state = copy_and_apply_drag(state, ui);
2822 2898
@@ -2824,6 +2900,16 @@ static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldst
2824 for (y = 0; y < h; y++) { 2900 for (y = 0; y < h; y++) {
2825 unsigned int f, f_d; 2901 unsigned int f, f_d;
2826 2902
2903 flashing = 0;
2904 if (flashtime > 0) {
2905 float flashpos =
2906 (state->sflags[y*w+x] >> S_FLASH_SHIFT & S_FLASH_MASK) /
2907 (float)S_FLASH_MASK;
2908 if (flashtime > FLASH_TIME / 2 * flashpos &&
2909 flashtime <= FLASH_TIME / 2 * (flashpos + 1.0F))
2910 flashing = DS_FLASH;
2911 }
2912
2827 f = s2d_flags(state, x, y, ui) | flashing; 2913 f = s2d_flags(state, x, y, ui) | flashing;
2828 f_d = drag_state ? s2d_flags(drag_state, x, y, ui) : f; 2914 f_d = drag_state ? s2d_flags(drag_state, x, y, ui) : f;
2829 2915
@@ -2890,22 +2976,19 @@ static int game_status(const game_state *state)
2890 return state->completed ? +1 : 0; 2976 return state->completed ? +1 : 0;
2891} 2977}
2892 2978
2893static bool game_timing_state(const game_state *state, game_ui *ui) 2979static void game_print_size(const game_params *params, const game_ui *ui,
2894{ 2980 float *x, float *y)
2895 return true;
2896}
2897
2898static void game_print_size(const game_params *params, float *x, float *y)
2899{ 2981{
2900 int pw, ph; 2982 int pw, ph;
2901 2983
2902 /* The Times uses 7mm squares */ 2984 /* The Times uses 7mm squares */
2903 game_compute_size(params, 700, &pw, &ph); 2985 game_compute_size(params, 700, ui, &pw, &ph);
2904 *x = pw / 100.0F; 2986 *x = pw / 100.0F;
2905 *y = ph / 100.0F; 2987 *y = ph / 100.0F;
2906} 2988}
2907 2989
2908static void game_print(drawing *dr, const game_state *state, int tilesize) 2990static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2991 int tilesize)
2909{ 2992{
2910 int w = state->p.w, h = state->p.h; 2993 int w = state->p.w, h = state->p.h;
2911 int black = print_mono_colour(dr, 0), grey = print_grey_colour(dr, 0.5F); 2994 int black = print_mono_colour(dr, 0), grey = print_grey_colour(dr, 0.5F);
@@ -2948,7 +3031,7 @@ static void game_print(drawing *dr, const game_state *state, int tilesize)
2948#endif 3031#endif
2949 3032
2950const struct game thegame = { 3033const struct game thegame = {
2951 "Tracks", "games.tracks", "tracks", 3034 "Train Tracks", "games.tracks", "tracks",
2952 default_params, 3035 default_params,
2953 game_fetch_preset, NULL, 3036 game_fetch_preset, NULL,
2954 decode_params, 3037 decode_params,
@@ -2964,12 +3047,14 @@ const struct game thegame = {
2964 free_game, 3047 free_game,
2965 true, solve_game, 3048 true, solve_game,
2966 true, game_can_format_as_text_now, game_text_format, 3049 true, game_can_format_as_text_now, game_text_format,
3050 NULL, NULL, /* get_prefs, set_prefs */
2967 new_ui, 3051 new_ui,
2968 free_ui, 3052 free_ui,
2969 encode_ui, 3053 NULL, /* encode_ui */
2970 decode_ui, 3054 NULL, /* decode_ui */
2971 NULL, /* game_request_keys */ 3055 NULL, /* game_request_keys */
2972 game_changed_state, 3056 game_changed_state,
3057 current_key_label,
2973 interpret_move, 3058 interpret_move,
2974 execute_move, 3059 execute_move,
2975 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 3060 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -2983,7 +3068,7 @@ const struct game thegame = {
2983 game_status, 3068 game_status,
2984 true, false, game_print_size, game_print, 3069 true, false, game_print_size, game_print,
2985 false, /* wants_statusbar */ 3070 false, /* wants_statusbar */
2986 false, game_timing_state, 3071 false, NULL, /* timing_state */
2987 0, /* flags */ 3072 0, /* flags */
2988}; 3073};
2989 3074
diff --git a/apps/plugins/puzzles/src/tree234.c b/apps/plugins/puzzles/src/tree234.c
index ad8eb047cd..ef2c3ffaf7 100644
--- a/apps/plugins/puzzles/src/tree234.c
+++ b/apps/plugins/puzzles/src/tree234.c
@@ -29,33 +29,25 @@
29#include <stdlib.h> 29#include <stdlib.h>
30#include <assert.h> 30#include <assert.h>
31 31
32#define TREE234_INTERNALS
32#include "tree234.h" 33#include "tree234.h"
33 34
34#include "puzzles.h" /* for smalloc/sfree */ 35#include "puzzles.h" /* for smalloc/sfree */
35 36
36#ifdef TEST 37#ifdef DEBUG_TREE234
37#define LOG(x) (printf x) 38#include <stdarg.h>
38#define smalloc malloc 39static void logprintf(const char *fmt, ...)
39#define srealloc realloc 40{
40#define sfree free 41 va_list ap;
42 va_start(ap, fmt);
43 vprintf(fmt, ap);
44 va_end(ap);
45}
46#define LOG(x) (logprintf x)
41#else 47#else
42#define LOG(x) 48#define LOG(x)
43#endif 49#endif
44 50
45typedef struct node234_Tag node234;
46
47struct tree234_Tag {
48 node234 *root;
49 cmpfn234 cmp;
50};
51
52struct node234_Tag {
53 node234 *parent;
54 node234 *kids[4];
55 int counts[4];
56 void *elems[3];
57};
58
59/* 51/*
60 * Create a 2-3-4 tree. 52 * Create a 2-3-4 tree.
61 */ 53 */
@@ -327,7 +319,7 @@ static void *add234_internal(tree234 *t, void *e, int index) {
327 } 319 }
328 320
329 n = t->root; 321 n = t->root;
330 while (n) { 322 do {
331 LOG((" node %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", 323 LOG((" node %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n",
332 n, 324 n,
333 n->kids[0], n->counts[0], n->elems[0], 325 n->kids[0], n->counts[0], n->elems[0],
@@ -380,7 +372,7 @@ static void *add234_internal(tree234 *t, void *e, int index) {
380 if (!n->kids[ki]) 372 if (!n->kids[ki])
381 break; 373 break;
382 n = n->kids[ki]; 374 n = n->kids[ki];
383 } 375 } while (n);
384 376
385 add234_insert(NULL, e, NULL, &t->root, n, ki); 377 add234_insert(NULL, e, NULL, &t->root, n, ki);
386 378
@@ -1104,7 +1096,7 @@ static node234 *join234_internal(node234 *left, void *sep,
1104 1096
1105 return root; 1097 return root;
1106} 1098}
1107static int height234(tree234 *t) { 1099int height234(tree234 *t) {
1108 int level = 0; 1100 int level = 0;
1109 node234 *n = t->root; 1101 node234 *n = t->root;
1110 while (n) { 1102 while (n) {
@@ -1452,749 +1444,3 @@ tree234 *copytree234(tree234 *t, copyfn234 copyfn, void *copyfnstate) {
1452 1444
1453 return t2; 1445 return t2;
1454} 1446}
1455
1456#ifdef TEST
1457
1458/*
1459 * Test code for the 2-3-4 tree. This code maintains an alternative
1460 * representation of the data in the tree, in an array (using the
1461 * obvious and slow insert and delete functions). After each tree
1462 * operation, the verify() function is called, which ensures all
1463 * the tree properties are preserved:
1464 * - node->child->parent always equals node
1465 * - tree->root->parent always equals NULL
1466 * - number of kids == 0 or number of elements + 1;
1467 * - tree has the same depth everywhere
1468 * - every node has at least one element
1469 * - subtree element counts are accurate
1470 * - any NULL kid pointer is accompanied by a zero count
1471 * - in a sorted tree: ordering property between elements of a
1472 * node and elements of its children is preserved
1473 * and also ensures the list represented by the tree is the same
1474 * list it should be. (This last check also doubly verifies the
1475 * ordering properties, because the `same list it should be' is by
1476 * definition correctly ordered. It also ensures all nodes are
1477 * distinct, because the enum functions would get caught in a loop
1478 * if not.)
1479 */
1480
1481#include <string.h>
1482#include <stdarg.h>
1483
1484#define srealloc realloc
1485
1486/*
1487 * Error reporting function.
1488 */
1489void error(char *fmt, ...) {
1490 va_list ap;
1491 printf("ERROR: ");
1492 va_start(ap, fmt);
1493 vfprintf(stdout, fmt, ap);
1494 va_end(ap);
1495 printf("\n");
1496}
1497
1498/* The array representation of the data. */
1499void **array;
1500int arraylen, arraysize;
1501cmpfn234 cmp;
1502
1503/* The tree representation of the same data. */
1504tree234 *tree;
1505
1506/*
1507 * Routines to provide a diagnostic printout of a tree. Currently
1508 * relies on every element in the tree being a one-character string
1509 * :-)
1510 */
1511typedef struct {
1512 char **levels;
1513} dispctx;
1514
1515int dispnode(node234 *n, int level, dispctx *ctx) {
1516 if (level == 0) {
1517 int xpos = strlen(ctx->levels[0]);
1518 int len;
1519
1520 if (n->elems[2])
1521 len = sprintf(ctx->levels[0]+xpos, " %s%s%s",
1522 n->elems[0], n->elems[1], n->elems[2]);
1523 else if (n->elems[1])
1524 len = sprintf(ctx->levels[0]+xpos, " %s%s",
1525 n->elems[0], n->elems[1]);
1526 else
1527 len = sprintf(ctx->levels[0]+xpos, " %s",
1528 n->elems[0]);
1529 return xpos + 1 + (len-1) / 2;
1530 } else {
1531 int xpos[4], nkids;
1532 int nodelen, mypos, myleft, x, i;
1533
1534 xpos[0] = dispnode(n->kids[0], level-3, ctx);
1535 xpos[1] = dispnode(n->kids[1], level-3, ctx);
1536 nkids = 2;
1537 if (n->kids[2]) {
1538 xpos[2] = dispnode(n->kids[2], level-3, ctx);
1539 nkids = 3;
1540 }
1541 if (n->kids[3]) {
1542 xpos[3] = dispnode(n->kids[3], level-3, ctx);
1543 nkids = 4;
1544 }
1545
1546 if (nkids == 4)
1547 mypos = (xpos[1] + xpos[2]) / 2;
1548 else if (nkids == 3)
1549 mypos = xpos[1];
1550 else
1551 mypos = (xpos[0] + xpos[1]) / 2;
1552 nodelen = nkids * 2 - 1;
1553 myleft = mypos - ((nodelen-1)/2);
1554 assert(myleft >= xpos[0]);
1555 assert(myleft + nodelen-1 <= xpos[nkids-1]);
1556
1557 x = strlen(ctx->levels[level]);
1558 while (x <= xpos[0] && x < myleft)
1559 ctx->levels[level][x++] = ' ';
1560 while (x < myleft)
1561 ctx->levels[level][x++] = '_';
1562 if (nkids==4)
1563 x += sprintf(ctx->levels[level]+x, ".%s.%s.%s.",
1564 n->elems[0], n->elems[1], n->elems[2]);
1565 else if (nkids==3)
1566 x += sprintf(ctx->levels[level]+x, ".%s.%s.",
1567 n->elems[0], n->elems[1]);
1568 else
1569 x += sprintf(ctx->levels[level]+x, ".%s.",
1570 n->elems[0]);
1571 while (x < xpos[nkids-1])
1572 ctx->levels[level][x++] = '_';
1573 ctx->levels[level][x] = '\0';
1574
1575 x = strlen(ctx->levels[level-1]);
1576 for (i = 0; i < nkids; i++) {
1577 int rpos, pos;
1578 rpos = xpos[i];
1579 if (i > 0 && i < nkids-1)
1580 pos = myleft + 2*i;
1581 else
1582 pos = rpos;
1583 if (rpos < pos)
1584 rpos++;
1585 while (x < pos && x < rpos)
1586 ctx->levels[level-1][x++] = ' ';
1587 if (x == pos)
1588 ctx->levels[level-1][x++] = '|';
1589 while (x < pos || x < rpos)
1590 ctx->levels[level-1][x++] = '_';
1591 if (x == pos)
1592 ctx->levels[level-1][x++] = '|';
1593 }
1594 ctx->levels[level-1][x] = '\0';
1595
1596 x = strlen(ctx->levels[level-2]);
1597 for (i = 0; i < nkids; i++) {
1598 int rpos = xpos[i];
1599
1600 while (x < rpos)
1601 ctx->levels[level-2][x++] = ' ';
1602 ctx->levels[level-2][x++] = '|';
1603 }
1604 ctx->levels[level-2][x] = '\0';
1605
1606 return mypos;
1607 }
1608}
1609
1610void disptree(tree234 *t) {
1611 dispctx ctx;
1612 char *leveldata;
1613 int width = count234(t);
1614 int ht = height234(t) * 3 - 2;
1615 int i;
1616
1617 if (!t->root) {
1618 printf("[empty tree]\n");
1619 }
1620
1621 leveldata = smalloc(ht * (width+2));
1622 ctx.levels = smalloc(ht * sizeof(char *));
1623 for (i = 0; i < ht; i++) {
1624 ctx.levels[i] = leveldata + i * (width+2);
1625 ctx.levels[i][0] = '\0';
1626 }
1627
1628 (void) dispnode(t->root, ht-1, &ctx);
1629
1630 for (i = ht; i-- ;)
1631 printf("%s\n", ctx.levels[i]);
1632
1633 sfree(ctx.levels);
1634 sfree(leveldata);
1635}
1636
1637typedef struct {
1638 int treedepth;
1639 int elemcount;
1640} chkctx;
1641
1642int chknode(chkctx *ctx, int level, node234 *node,
1643 void *lowbound, void *highbound) {
1644 int nkids, nelems;
1645 int i;
1646 int count;
1647
1648 /* Count the non-NULL kids. */
1649 for (nkids = 0; nkids < 4 && node->kids[nkids]; nkids++);
1650 /* Ensure no kids beyond the first NULL are non-NULL. */
1651 for (i = nkids; i < 4; i++)
1652 if (node->kids[i]) {
1653 error("node %p: nkids=%d but kids[%d] non-NULL",
1654 node, nkids, i);
1655 } else if (node->counts[i]) {
1656 error("node %p: kids[%d] NULL but count[%d]=%d nonzero",
1657 node, i, i, node->counts[i]);
1658 }
1659
1660 /* Count the non-NULL elements. */
1661 for (nelems = 0; nelems < 3 && node->elems[nelems]; nelems++);
1662 /* Ensure no elements beyond the first NULL are non-NULL. */
1663 for (i = nelems; i < 3; i++)
1664 if (node->elems[i]) {
1665 error("node %p: nelems=%d but elems[%d] non-NULL",
1666 node, nelems, i);
1667 }
1668
1669 if (nkids == 0) {
1670 /*
1671 * If nkids==0, this is a leaf node; verify that the tree
1672 * depth is the same everywhere.
1673 */
1674 if (ctx->treedepth < 0)
1675 ctx->treedepth = level; /* we didn't know the depth yet */
1676 else if (ctx->treedepth != level)
1677 error("node %p: leaf at depth %d, previously seen depth %d",
1678 node, level, ctx->treedepth);
1679 } else {
1680 /*
1681 * If nkids != 0, then it should be nelems+1, unless nelems
1682 * is 0 in which case nkids should also be 0 (and so we
1683 * shouldn't be in this condition at all).
1684 */
1685 int shouldkids = (nelems ? nelems+1 : 0);
1686 if (nkids != shouldkids) {
1687 error("node %p: %d elems should mean %d kids but has %d",
1688 node, nelems, shouldkids, nkids);
1689 }
1690 }
1691
1692 /*
1693 * nelems should be at least 1.
1694 */
1695 if (nelems == 0) {
1696 error("node %p: no elems", node, nkids);
1697 }
1698
1699 /*
1700 * Add nelems to the running element count of the whole tree.
1701 */
1702 ctx->elemcount += nelems;
1703
1704 /*
1705 * Check ordering property: all elements should be strictly >
1706 * lowbound, strictly < highbound, and strictly < each other in
1707 * sequence. (lowbound and highbound are NULL at edges of tree
1708 * - both NULL at root node - and NULL is considered to be <
1709 * everything and > everything. IYSWIM.)
1710 */
1711 if (cmp) {
1712 for (i = -1; i < nelems; i++) {
1713 void *lower = (i == -1 ? lowbound : node->elems[i]);
1714 void *higher = (i+1 == nelems ? highbound : node->elems[i+1]);
1715 if (lower && higher && cmp(lower, higher) >= 0) {
1716 error("node %p: kid comparison [%d=%s,%d=%s] failed",
1717 node, i, lower, i+1, higher);
1718 }
1719 }
1720 }
1721
1722 /*
1723 * Check parent pointers: all non-NULL kids should have a
1724 * parent pointer coming back to this node.
1725 */
1726 for (i = 0; i < nkids; i++)
1727 if (node->kids[i]->parent != node) {
1728 error("node %p kid %d: parent ptr is %p not %p",
1729 node, i, node->kids[i]->parent, node);
1730 }
1731
1732
1733 /*
1734 * Now (finally!) recurse into subtrees.
1735 */
1736 count = nelems;
1737
1738 for (i = 0; i < nkids; i++) {
1739 void *lower = (i == 0 ? lowbound : node->elems[i-1]);
1740 void *higher = (i >= nelems ? highbound : node->elems[i]);
1741 int subcount = chknode(ctx, level+1, node->kids[i], lower, higher);
1742 if (node->counts[i] != subcount) {
1743 error("node %p kid %d: count says %d, subtree really has %d",
1744 node, i, node->counts[i], subcount);
1745 }
1746 count += subcount;
1747 }
1748
1749 return count;
1750}
1751
1752void verifytree(tree234 *tree, void **array, int arraylen) {
1753 chkctx ctx;
1754 int i;
1755 void *p;
1756
1757 ctx.treedepth = -1; /* depth unknown yet */
1758 ctx.elemcount = 0; /* no elements seen yet */
1759 /*
1760 * Verify validity of tree properties.
1761 */
1762 if (tree->root) {
1763 if (tree->root->parent != NULL)
1764 error("root->parent is %p should be null", tree->root->parent);
1765 chknode(&ctx, 0, tree->root, NULL, NULL);
1766 }
1767 printf("tree depth: %d\n", ctx.treedepth);
1768 /*
1769 * Enumerate the tree and ensure it matches up to the array.
1770 */
1771 for (i = 0; NULL != (p = index234(tree, i)); i++) {
1772 if (i >= arraylen)
1773 error("tree contains more than %d elements", arraylen);
1774 if (array[i] != p)
1775 error("enum at position %d: array says %s, tree says %s",
1776 i, array[i], p);
1777 }
1778 if (ctx.elemcount != i) {
1779 error("tree really contains %d elements, enum gave %d",
1780 ctx.elemcount, i);
1781 }
1782 if (i < arraylen) {
1783 error("enum gave only %d elements, array has %d", i, arraylen);
1784 }
1785 i = count234(tree);
1786 if (ctx.elemcount != i) {
1787 error("tree really contains %d elements, count234 gave %d",
1788 ctx.elemcount, i);
1789 }
1790}
1791void verify(void) { verifytree(tree, array, arraylen); }
1792
1793void internal_addtest(void *elem, int index, void *realret) {
1794 int i, j;
1795 void *retval;
1796
1797 if (arraysize < arraylen+1) {
1798 arraysize = arraylen+1+256;
1799 array = (array == NULL ? smalloc(arraysize*sizeof(*array)) :
1800 srealloc(array, arraysize*sizeof(*array)));
1801 }
1802
1803 i = index;
1804 /* now i points to the first element >= elem */
1805 retval = elem; /* expect elem returned (success) */
1806 for (j = arraylen; j > i; j--)
1807 array[j] = array[j-1];
1808 array[i] = elem; /* add elem to array */
1809 arraylen++;
1810
1811 if (realret != retval) {
1812 error("add: retval was %p expected %p", realret, retval);
1813 }
1814
1815 verify();
1816}
1817
1818void addtest(void *elem) {
1819 int i;
1820 void *realret;
1821
1822 realret = add234(tree, elem);
1823
1824 i = 0;
1825 while (i < arraylen && cmp(elem, array[i]) > 0)
1826 i++;
1827 if (i < arraylen && !cmp(elem, array[i])) {
1828 void *retval = array[i]; /* expect that returned not elem */
1829 if (realret != retval) {
1830 error("add: retval was %p expected %p", realret, retval);
1831 }
1832 } else
1833 internal_addtest(elem, i, realret);
1834}
1835
1836void addpostest(void *elem, int i) {
1837 void *realret;
1838
1839 realret = addpos234(tree, elem, i);
1840
1841 internal_addtest(elem, i, realret);
1842}
1843
1844void delpostest(int i) {
1845 int index = i;
1846 void *elem = array[i], *ret;
1847
1848 /* i points to the right element */
1849 while (i < arraylen-1) {
1850 array[i] = array[i+1];
1851 i++;
1852 }
1853 arraylen--; /* delete elem from array */
1854
1855 if (tree->cmp)
1856 ret = del234(tree, elem);
1857 else
1858 ret = delpos234(tree, index);
1859
1860 if (ret != elem) {
1861 error("del returned %p, expected %p", ret, elem);
1862 }
1863
1864 verify();
1865}
1866
1867void deltest(void *elem) {
1868 int i;
1869
1870 i = 0;
1871 while (i < arraylen && cmp(elem, array[i]) > 0)
1872 i++;
1873 if (i >= arraylen || cmp(elem, array[i]) != 0)
1874 return; /* don't do it! */
1875 delpostest(i);
1876}
1877
1878/* A sample data set and test utility. Designed for pseudo-randomness,
1879 * and yet repeatability. */
1880
1881/*
1882 * This random number generator uses the `portable implementation'
1883 * given in ANSI C99 draft N869. It assumes `unsigned' is 32 bits;
1884 * change it if not.
1885 */
1886int randomnumber(unsigned *seed) {
1887 *seed *= 1103515245;
1888 *seed += 12345;
1889 return ((*seed) / 65536) % 32768;
1890}
1891
1892int mycmp(void *av, void *bv) {
1893 char const *a = (char const *)av;
1894 char const *b = (char const *)bv;
1895 return strcmp(a, b);
1896}
1897
1898char *strings[] = {
1899 "0", "2", "3", "I", "K", "d", "H", "J", "Q", "N", "n", "q", "j", "i",
1900 "7", "G", "F", "D", "b", "x", "g", "B", "e", "v", "V", "T", "f", "E",
1901 "S", "8", "A", "k", "X", "p", "C", "R", "a", "o", "r", "O", "Z", "u",
1902 "6", "1", "w", "L", "P", "M", "c", "U", "h", "9", "t", "5", "W", "Y",
1903 "m", "s", "l", "4",
1904#if 0
1905 "a", "ab", "absque", "coram", "de",
1906 "palam", "clam", "cum", "ex", "e",
1907 "sine", "tenus", "pro", "prae",
1908 "banana", "carrot", "cabbage", "broccoli", "onion", "zebra",
1909 "penguin", "blancmange", "pangolin", "whale", "hedgehog",
1910 "giraffe", "peanut", "bungee", "foo", "bar", "baz", "quux",
1911 "murfl", "spoo", "breen", "flarn", "octothorpe",
1912 "snail", "tiger", "elephant", "octopus", "warthog", "armadillo",
1913 "aardvark", "wyvern", "dragon", "elf", "dwarf", "orc", "goblin",
1914 "pixie", "basilisk", "warg", "ape", "lizard", "newt", "shopkeeper",
1915 "wand", "ring", "amulet"
1916#endif
1917};
1918
1919#define NSTR lenof(strings)
1920
1921void findtest(void) {
1922 static const int rels[] = {
1923 REL234_EQ, REL234_GE, REL234_LE, REL234_LT, REL234_GT
1924 };
1925 static const char *const relnames[] = {
1926 "EQ", "GE", "LE", "LT", "GT"
1927 };
1928 int i, j, rel, index;
1929 char *p, *ret, *realret, *realret2;
1930 int lo, hi, mid, c;
1931
1932 for (i = 0; i < (int)NSTR; i++) {
1933 p = strings[i];
1934 for (j = 0; j < (int)(sizeof(rels)/sizeof(*rels)); j++) {
1935 rel = rels[j];
1936
1937 lo = 0; hi = arraylen-1;
1938 while (lo <= hi) {
1939 mid = (lo + hi) / 2;
1940 c = strcmp(p, array[mid]);
1941 if (c < 0)
1942 hi = mid-1;
1943 else if (c > 0)
1944 lo = mid+1;
1945 else
1946 break;
1947 }
1948
1949 if (c == 0) {
1950 if (rel == REL234_LT)
1951 ret = (mid > 0 ? array[--mid] : NULL);
1952 else if (rel == REL234_GT)
1953 ret = (mid < arraylen-1 ? array[++mid] : NULL);
1954 else
1955 ret = array[mid];
1956 } else {
1957 assert(lo == hi+1);
1958 if (rel == REL234_LT || rel == REL234_LE) {
1959 mid = hi;
1960 ret = (hi >= 0 ? array[hi] : NULL);
1961 } else if (rel == REL234_GT || rel == REL234_GE) {
1962 mid = lo;
1963 ret = (lo < arraylen ? array[lo] : NULL);
1964 } else
1965 ret = NULL;
1966 }
1967
1968 realret = findrelpos234(tree, p, NULL, rel, &index);
1969 if (realret != ret) {
1970 error("find(\"%s\",%s) gave %s should be %s",
1971 p, relnames[j], realret, ret);
1972 }
1973 if (realret && index != mid) {
1974 error("find(\"%s\",%s) gave %d should be %d",
1975 p, relnames[j], index, mid);
1976 }
1977 if (realret && rel == REL234_EQ) {
1978 realret2 = index234(tree, index);
1979 if (realret2 != realret) {
1980 error("find(\"%s\",%s) gave %s(%d) but %d -> %s",
1981 p, relnames[j], realret, index, index, realret2);
1982 }
1983 }
1984#if 0
1985 printf("find(\"%s\",%s) gave %s(%d)\n", p, relnames[j],
1986 realret, index);
1987#endif
1988 }
1989 }
1990
1991 realret = findrelpos234(tree, NULL, NULL, REL234_GT, &index);
1992 if (arraylen && (realret != array[0] || index != 0)) {
1993 error("find(NULL,GT) gave %s(%d) should be %s(0)",
1994 realret, index, array[0]);
1995 } else if (!arraylen && (realret != NULL)) {
1996 error("find(NULL,GT) gave %s(%d) should be NULL",
1997 realret, index);
1998 }
1999
2000 realret = findrelpos234(tree, NULL, NULL, REL234_LT, &index);
2001 if (arraylen && (realret != array[arraylen-1] || index != arraylen-1)) {
2002 error("find(NULL,LT) gave %s(%d) should be %s(0)",
2003 realret, index, array[arraylen-1]);
2004 } else if (!arraylen && (realret != NULL)) {
2005 error("find(NULL,LT) gave %s(%d) should be NULL",
2006 realret, index);
2007 }
2008}
2009
2010void splittest(tree234 *tree, void **array, int arraylen) {
2011 int i;
2012 tree234 *tree3, *tree4;
2013 for (i = 0; i <= arraylen; i++) {
2014 tree3 = copytree234(tree, NULL, NULL);
2015 tree4 = splitpos234(tree3, i, false);
2016 verifytree(tree3, array, i);
2017 verifytree(tree4, array+i, arraylen-i);
2018 join234(tree3, tree4);
2019 freetree234(tree4); /* left empty by join */
2020 verifytree(tree3, array, arraylen);
2021 freetree234(tree3);
2022 }
2023}
2024
2025int main(void) {
2026 int in[NSTR];
2027 int i, j, k;
2028 int tworoot, tmplen;
2029 unsigned seed = 0;
2030 tree234 *tree2, *tree3, *tree4;
2031 int c;
2032
2033 setvbuf(stdout, NULL, _IOLBF, 0);
2034
2035 for (i = 0; i < (int)NSTR; i++) in[i] = 0;
2036 array = NULL;
2037 arraylen = arraysize = 0;
2038 tree = newtree234(mycmp);
2039 cmp = mycmp;
2040
2041 verify();
2042 for (i = 0; i < 10000; i++) {
2043 j = randomnumber(&seed);
2044 j %= NSTR;
2045 printf("trial: %d\n", i);
2046 if (in[j]) {
2047 printf("deleting %s (%d)\n", strings[j], j);
2048 deltest(strings[j]);
2049 in[j] = 0;
2050 } else {
2051 printf("adding %s (%d)\n", strings[j], j);
2052 addtest(strings[j]);
2053 in[j] = 1;
2054 }
2055 disptree(tree);
2056 findtest();
2057 }
2058
2059 while (arraylen > 0) {
2060 j = randomnumber(&seed);
2061 j %= arraylen;
2062 deltest(array[j]);
2063 }
2064
2065 freetree234(tree);
2066
2067 /*
2068 * Now try an unsorted tree. We don't really need to test
2069 * delpos234 because we know del234 is based on it, so it's
2070 * already been tested in the above sorted-tree code; but for
2071 * completeness we'll use it to tear down our unsorted tree
2072 * once we've built it.
2073 */
2074 tree = newtree234(NULL);
2075 cmp = NULL;
2076 verify();
2077 for (i = 0; i < 1000; i++) {
2078 printf("trial: %d\n", i);
2079 j = randomnumber(&seed);
2080 j %= NSTR;
2081 k = randomnumber(&seed);
2082 k %= count234(tree)+1;
2083 printf("adding string %s at index %d\n", strings[j], k);
2084 addpostest(strings[j], k);
2085 }
2086
2087 /*
2088 * While we have this tree in its full form, we'll take a copy
2089 * of it to use in split and join testing.
2090 */
2091 tree2 = copytree234(tree, NULL, NULL);
2092 verifytree(tree2, array, arraylen);/* check the copy is accurate */
2093 /*
2094 * Split tests. Split the tree at every possible point and
2095 * check the resulting subtrees.
2096 */
2097 tworoot = (!tree2->root->elems[1]);/* see if it has a 2-root */
2098 splittest(tree2, array, arraylen);
2099 /*
2100 * Now do the split test again, but on a tree that has a 2-root
2101 * (if the previous one didn't) or doesn't (if the previous one
2102 * did).
2103 */
2104 tmplen = arraylen;
2105 while ((!tree2->root->elems[1]) == tworoot) {
2106 delpos234(tree2, --tmplen);
2107 }
2108 printf("now trying splits on second tree\n");
2109 splittest(tree2, array, tmplen);
2110 freetree234(tree2);
2111
2112 /*
2113 * Back to the main testing of uncounted trees.
2114 */
2115 while (count234(tree) > 0) {
2116 printf("cleanup: tree size %d\n", count234(tree));
2117 j = randomnumber(&seed);
2118 j %= count234(tree);
2119 printf("deleting string %s from index %d\n", (char *)array[j], j);
2120 delpostest(j);
2121 }
2122 freetree234(tree);
2123
2124 /*
2125 * Finally, do some testing on split/join on _sorted_ trees. At
2126 * the same time, we'll be testing split on very small trees.
2127 */
2128 tree = newtree234(mycmp);
2129 cmp = mycmp;
2130 arraylen = 0;
2131 for (i = 0; i < 17; i++) {
2132 tree2 = copytree234(tree, NULL, NULL);
2133 splittest(tree2, array, arraylen);
2134 freetree234(tree2);
2135 if (i < 16)
2136 addtest(strings[i]);
2137 }
2138 freetree234(tree);
2139
2140 /*
2141 * Test silly cases of join: join(emptytree, emptytree), and
2142 * also ensure join correctly spots when sorted trees fail the
2143 * ordering constraint.
2144 */
2145 tree = newtree234(mycmp);
2146 tree2 = newtree234(mycmp);
2147 tree3 = newtree234(mycmp);
2148 tree4 = newtree234(mycmp);
2149 assert(mycmp(strings[0], strings[1]) < 0); /* just in case :-) */
2150 add234(tree2, strings[1]);
2151 add234(tree4, strings[0]);
2152 array[0] = strings[0];
2153 array[1] = strings[1];
2154 verifytree(tree, array, 0);
2155 verifytree(tree2, array+1, 1);
2156 verifytree(tree3, array, 0);
2157 verifytree(tree4, array, 1);
2158
2159 /*
2160 * So:
2161 * - join(tree,tree3) should leave both tree and tree3 unchanged.
2162 * - joinr(tree,tree2) should leave both tree and tree2 unchanged.
2163 * - join(tree4,tree3) should leave both tree3 and tree4 unchanged.
2164 * - join(tree, tree2) should move the element from tree2 to tree.
2165 * - joinr(tree4, tree3) should move the element from tree4 to tree3.
2166 * - join(tree,tree3) should return NULL and leave both unchanged.
2167 * - join(tree3,tree) should work and create a bigger tree in tree3.
2168 */
2169 assert(tree == join234(tree, tree3));
2170 verifytree(tree, array, 0);
2171 verifytree(tree3, array, 0);
2172 assert(tree2 == join234r(tree, tree2));
2173 verifytree(tree, array, 0);
2174 verifytree(tree2, array+1, 1);
2175 assert(tree4 == join234(tree4, tree3));
2176 verifytree(tree3, array, 0);
2177 verifytree(tree4, array, 1);
2178 assert(tree == join234(tree, tree2));
2179 verifytree(tree, array+1, 1);
2180 verifytree(tree2, array, 0);
2181 assert(tree3 == join234r(tree4, tree3));
2182 verifytree(tree3, array, 1);
2183 verifytree(tree4, array, 0);
2184 assert(NULL == join234(tree, tree3));
2185 verifytree(tree, array+1, 1);
2186 verifytree(tree3, array, 1);
2187 assert(tree3 == join234(tree3, tree));
2188 verifytree(tree3, array, 2);
2189 verifytree(tree, array, 0);
2190
2191 return 0;
2192}
2193
2194#endif
2195
2196#if 0 /* sorted list of strings might be useful */
2197{
2198 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x",
2199}
2200#endif
diff --git a/apps/plugins/puzzles/src/tree234.h b/apps/plugins/puzzles/src/tree234.h
index ccd943d69d..b58f939a0a 100644
--- a/apps/plugins/puzzles/src/tree234.h
+++ b/apps/plugins/puzzles/src/tree234.h
@@ -31,7 +31,11 @@
31#include <stdbool.h> 31#include <stdbool.h>
32 32
33/* 33/*
34 * This typedef is opaque outside tree234.c itself. 34 * This typedef is typically opaque outside tree234.c itself. But you
35 * can define TREE234_INTERNALS to get a definition of it and its
36 * subsidiary node structure, as long as you're prepared to commit to
37 * responding to changes in the internals (which probably means you're
38 * tree234.c itself or tree234-test.c).
35 */ 39 */
36typedef struct tree234_Tag tree234; 40typedef struct tree234_Tag tree234;
37 41
@@ -39,6 +43,24 @@ typedef int (*cmpfn234)(void *, void *);
39 43
40typedef void *(*copyfn234)(void *state, void *element); 44typedef void *(*copyfn234)(void *state, void *element);
41 45
46#ifdef TREE234_INTERNALS
47typedef struct node234_Tag node234;
48
49struct tree234_Tag {
50 node234 *root;
51 cmpfn234 cmp;
52};
53
54struct node234_Tag {
55 node234 *parent;
56 node234 *kids[4];
57 int counts[4];
58 void *elems[3];
59};
60
61int height234(tree234 *t);
62#endif
63
42/* 64/*
43 * Create a 2-3-4 tree. If `cmp' is NULL, the tree is unsorted, and 65 * Create a 2-3-4 tree. If `cmp' is NULL, the tree is unsorted, and
44 * lookups by key will fail: you can only look things up by numeric 66 * lookups by key will fail: you can only look things up by numeric
diff --git a/apps/plugins/puzzles/src/twiddle.R b/apps/plugins/puzzles/src/twiddle.R
deleted file mode 100644
index 1495c33181..0000000000
--- a/apps/plugins/puzzles/src/twiddle.R
+++ /dev/null
@@ -1,19 +0,0 @@
1# -*- makefile -*-
2
3twiddle : [X] GTK COMMON twiddle twiddle-icon|no-icon
4
5twiddle : [G] WINDOWS COMMON twiddle twiddle.res|noicon.res
6
7ALL += twiddle[COMBINED]
8
9!begin am gtk
10GAMES += twiddle
11!end
12
13!begin >list.c
14 A(twiddle) \
15!end
16
17!begin >gamedesc.txt
18twiddle:twiddle.exe:Twiddle:Rotational sliding block puzzle:Rotate the tiles around themselves to arrange them into order.
19!end
diff --git a/apps/plugins/puzzles/src/twiddle.c b/apps/plugins/puzzles/src/twiddle.c
index a107925aee..b3aa06f1d5 100644
--- a/apps/plugins/puzzles/src/twiddle.c
+++ b/apps/plugins/puzzles/src/twiddle.c
@@ -10,7 +10,12 @@
10#include <string.h> 10#include <string.h>
11#include <assert.h> 11#include <assert.h>
12#include <ctype.h> 12#include <ctype.h>
13#include <math.h> 13#include <limits.h>
14#ifdef NO_TGMATH_H
15# include <math.h>
16#else
17# include <tgmath.h>
18#endif
14 19
15#include "puzzles.h" 20#include "puzzles.h"
16 21
@@ -123,14 +128,16 @@ static void decode_params(game_params *ret, char const *string)
123 while (*string) { 128 while (*string) {
124 if (*string == 'r') { 129 if (*string == 'r') {
125 ret->rowsonly = true; 130 ret->rowsonly = true;
131 string++;
126 } else if (*string == 'o') { 132 } else if (*string == 'o') {
127 ret->orientable = true; 133 ret->orientable = true;
134 string++;
128 } else if (*string == 'm') { 135 } else if (*string == 'm') {
129 string++; 136 string++;
130 ret->movetarget = atoi(string); 137 ret->movetarget = atoi(string);
131 while (string[1] && isdigit((unsigned char)string[1])) string++; 138 while (*string && isdigit((unsigned char)*string)) string++;
132 } 139 } else
133 string++; 140 string++;
134 } 141 }
135} 142}
136 143
@@ -210,6 +217,8 @@ static const char *validate_params(const game_params *params, bool full)
210 return "Width must be at least the rotating block size"; 217 return "Width must be at least the rotating block size";
211 if (params->h < params->n) 218 if (params->h < params->n)
212 return "Height must be at least the rotating block size"; 219 return "Height must be at least the rotating block size";
220 if (params->w > INT_MAX / params->h)
221 return "Width times height must not be unreasonably large";
213 if (params->movetarget < 0) 222 if (params->movetarget < 0)
214 return "Number of shuffling moves may not be negative"; 223 return "Number of shuffling moves may not be negative";
215 return NULL; 224 return NULL;
@@ -615,7 +624,7 @@ static game_ui *new_ui(const game_state *state)
615 624
616 ui->cur_x = 0; 625 ui->cur_x = 0;
617 ui->cur_y = 0; 626 ui->cur_y = 0;
618 ui->cur_visible = false; 627 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
619 628
620 return ui; 629 return ui;
621} 630}
@@ -625,18 +634,20 @@ static void free_ui(game_ui *ui)
625 sfree(ui); 634 sfree(ui);
626} 635}
627 636
628static char *encode_ui(const game_ui *ui) 637static void game_changed_state(game_ui *ui, const game_state *oldstate,
629{ 638 const game_state *newstate)
630 return NULL;
631}
632
633static void decode_ui(game_ui *ui, const char *encoding)
634{ 639{
635} 640}
636 641
637static void game_changed_state(game_ui *ui, const game_state *oldstate, 642static const char *current_key_label(const game_ui *ui,
638 const game_state *newstate) 643 const game_state *state, int button)
639{ 644{
645 if (!ui->cur_visible) return "";
646 switch (button) {
647 case CURSOR_SELECT: return "Turn left";
648 case CURSOR_SELECT2: return "Turn right";
649 }
650 return "";
640} 651}
641 652
642struct game_drawstate { 653struct game_drawstate {
@@ -657,18 +668,9 @@ static char *interpret_move(const game_state *state, game_ui *ui,
657 668
658 button = button & (~MOD_MASK | MOD_NUM_KEYPAD); 669 button = button & (~MOD_MASK | MOD_NUM_KEYPAD);
659 670
660 if (IS_CURSOR_MOVE(button)) { 671 if (IS_CURSOR_MOVE(button))
661 if (button == CURSOR_LEFT && ui->cur_x > 0) 672 return move_cursor(button, &ui->cur_x, &ui->cur_y, w-n+1, h-n+1,
662 ui->cur_x--; 673 false, &ui->cur_visible);
663 if (button == CURSOR_RIGHT && (ui->cur_x+n) < (w))
664 ui->cur_x++;
665 if (button == CURSOR_UP && ui->cur_y > 0)
666 ui->cur_y--;
667 if (button == CURSOR_DOWN && (ui->cur_y+n) < (h))
668 ui->cur_y++;
669 ui->cur_visible = true;
670 return UI_UPDATE;
671 }
672 674
673 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { 675 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
674 /* 676 /*
@@ -691,7 +693,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
691 dir = (button == CURSOR_SELECT2) ? -1 : +1; 693 dir = (button == CURSOR_SELECT2) ? -1 : +1;
692 } else { 694 } else {
693 ui->cur_visible = true; 695 ui->cur_visible = true;
694 return UI_UPDATE; 696 return MOVE_UI_UPDATE;
695 } 697 }
696 } else if (button == 'a' || button == 'A' || button==MOD_NUM_KEYPAD+'7') { 698 } else if (button == 'a' || button == 'A' || button==MOD_NUM_KEYPAD+'7') {
697 x = y = 0; 699 x = y = 0;
@@ -791,7 +793,7 @@ static game_state *execute_move(const game_state *from, const char *move)
791 */ 793 */
792 794
793static void game_compute_size(const game_params *params, int tilesize, 795static void game_compute_size(const game_params *params, int tilesize,
794 int *x, int *y) 796 const game_ui *ui, int *x, int *y)
795{ 797{
796 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 798 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
797 struct { int tilesize; } ads, *ds = &ads; 799 struct { int tilesize; } ads, *ds = &ads;
@@ -870,8 +872,8 @@ static void rotate(int *xy, struct rotation *rot)
870 xf2 = rot->c * xf + rot->s * yf; 872 xf2 = rot->c * xf + rot->s * yf;
871 yf2 = - rot->s * xf + rot->c * yf; 873 yf2 = - rot->s * xf + rot->c * yf;
872 874
873 xy[0] = (int)(xf2 + rot->ox + 0.5); /* round to nearest */ 875 xy[0] = (int)(xf2 + rot->ox + 0.5F); /* round to nearest */
874 xy[1] = (int)(yf2 + rot->oy + 0.5); /* round to nearest */ 876 xy[1] = (int)(yf2 + rot->oy + 0.5F); /* round to nearest */
875 } 877 }
876} 878}
877 879
@@ -1058,7 +1060,7 @@ static int highlight_colour(float angle)
1058 COL_LOWLIGHT, 1060 COL_LOWLIGHT,
1059 }; 1061 };
1060 1062
1061 return colours[(int)((angle + 2*PI) / (PI/16)) & 31]; 1063 return colours[(int)((angle + 2*(float)PI) / ((float)PI/16)) & 31];
1062} 1064}
1063 1065
1064static float game_anim_length_real(const game_state *oldstate, 1066static float game_anim_length_real(const game_state *oldstate,
@@ -1135,13 +1137,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1135 if (!ds->started) { 1137 if (!ds->started) {
1136 int coords[10]; 1138 int coords[10];
1137 1139
1138 draw_rect(dr, 0, 0,
1139 TILE_SIZE * state->w + 2 * BORDER,
1140 TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND);
1141 draw_update(dr, 0, 0,
1142 TILE_SIZE * state->w + 2 * BORDER,
1143 TILE_SIZE * state->h + 2 * BORDER);
1144
1145 /* 1140 /*
1146 * Recessed area containing the whole puzzle. 1141 * Recessed area containing the whole puzzle.
1147 */ 1142 */
@@ -1189,7 +1184,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1189 rot->cw = rot->ch = TILE_SIZE * state->n; 1184 rot->cw = rot->ch = TILE_SIZE * state->n;
1190 rot->ox = rot->cx + rot->cw/2; 1185 rot->ox = rot->cx + rot->cw/2;
1191 rot->oy = rot->cy + rot->ch/2; 1186 rot->oy = rot->cy + rot->ch/2;
1192 angle = (float)((-PI/2 * lastr) * (1.0 - animtime / anim_max)); 1187 angle = ((-(float)PI/2 * lastr) * (1.0F - animtime / anim_max));
1193 rot->c = (float)cos(angle); 1188 rot->c = (float)cos(angle);
1194 rot->s = (float)sin(angle); 1189 rot->s = (float)sin(angle);
1195 1190
@@ -1282,19 +1277,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1282 } 1277 }
1283} 1278}
1284 1279
1285static bool game_timing_state(const game_state *state, game_ui *ui)
1286{
1287 return true;
1288}
1289
1290static void game_print_size(const game_params *params, float *x, float *y)
1291{
1292}
1293
1294static void game_print(drawing *dr, const game_state *state, int tilesize)
1295{
1296}
1297
1298#ifdef COMBINED 1280#ifdef COMBINED
1299#define thegame twiddle 1281#define thegame twiddle
1300#endif 1282#endif
@@ -1316,12 +1298,14 @@ const struct game thegame = {
1316 free_game, 1298 free_game,
1317 true, solve_game, 1299 true, solve_game,
1318 true, game_can_format_as_text_now, game_text_format, 1300 true, game_can_format_as_text_now, game_text_format,
1301 NULL, NULL, /* get_prefs, set_prefs */
1319 new_ui, 1302 new_ui,
1320 free_ui, 1303 free_ui,
1321 encode_ui, 1304 NULL, /* encode_ui */
1322 decode_ui, 1305 NULL, /* decode_ui */
1323 NULL, /* game_request_keys */ 1306 NULL, /* game_request_keys */
1324 game_changed_state, 1307 game_changed_state,
1308 current_key_label,
1325 interpret_move, 1309 interpret_move,
1326 execute_move, 1310 execute_move,
1327 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 1311 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -1333,9 +1317,9 @@ const struct game thegame = {
1333 game_flash_length, 1317 game_flash_length,
1334 game_get_cursor_location, 1318 game_get_cursor_location,
1335 game_status, 1319 game_status,
1336 false, false, game_print_size, game_print, 1320 false, false, NULL, NULL, /* print_size, print */
1337 true, /* wants_statusbar */ 1321 true, /* wants_statusbar */
1338 false, game_timing_state, 1322 false, NULL, /* timing_state */
1339 0, /* flags */ 1323 0, /* flags */
1340}; 1324};
1341 1325
diff --git a/apps/plugins/puzzles/src/undead.R b/apps/plugins/puzzles/src/undead.R
deleted file mode 100644
index 5907ed6b74..0000000000
--- a/apps/plugins/puzzles/src/undead.R
+++ /dev/null
@@ -1,18 +0,0 @@
1# -*- makefile -*-
2
3undead : [X] GTK COMMON undead undead-icon|no-icon
4undead : [G] WINDOWS COMMON undead undead.res|noicon.res
5
6ALL += undead[COMBINED]
7
8!begin am gtk
9GAMES += undead
10!end
11
12!begin >list.c
13 A(undead) \
14!end
15
16!begin >gamedesc.txt
17undead:undead.exe:Undead:Monster-placing puzzle:Place ghosts, vampires and zombies so that the right numbers of them can be seen in mirrors.
18!end
diff --git a/apps/plugins/puzzles/src/undead.c b/apps/plugins/puzzles/src/undead.c
index 4dba828d48..0213d0e2e4 100644
--- a/apps/plugins/puzzles/src/undead.c
+++ b/apps/plugins/puzzles/src/undead.c
@@ -35,7 +35,11 @@
35#include <string.h> 35#include <string.h>
36#include <assert.h> 36#include <assert.h>
37#include <ctype.h> 37#include <ctype.h>
38#include <math.h> 38#ifdef NO_TGMATH_H
39# include <math.h>
40#else
41# include <tgmath.h>
42#endif
39 43
40#include "puzzles.h" 44#include "puzzles.h"
41 45
@@ -193,9 +197,9 @@ static game_params *custom_params(const config_item *cfg)
193 197
194static const char *validate_params(const game_params *params, bool full) 198static const char *validate_params(const game_params *params, bool full)
195{ 199{
196 if ((params->w * params->h ) > 54) return "Grid is too big";
197 if (params->w < 3) return "Width must be at least 3"; 200 if (params->w < 3) return "Width must be at least 3";
198 if (params->h < 3) return "Height must be at least 3"; 201 if (params->h < 3) return "Height must be at least 3";
202 if (params->w > 54 / params->h) return "Grid is too big";
199 if (params->diff >= DIFFCOUNT) return "Unknown difficulty rating"; 203 if (params->diff >= DIFFCOUNT) return "Unknown difficulty rating";
200 return NULL; 204 return NULL;
201} 205}
@@ -972,7 +976,7 @@ static int path_cmp(const void *a, const void *b) {
972 976
973static char *new_game_desc(const game_params *params, random_state *rs, 977static char *new_game_desc(const game_params *params, random_state *rs,
974 char **aux, bool interactive) { 978 char **aux, bool interactive) {
975 int i,count,c,w,h,r,p,g; 979 int count,c,w,h,r,p,g;
976 game_state *new; 980 game_state *new;
977 981
978 /* Variables for puzzle generation algorithm */ 982 /* Variables for puzzle generation algorithm */
@@ -993,7 +997,6 @@ static char *new_game_desc(const game_params *params, random_state *rs,
993 char *e; 997 char *e;
994 char *desc; 998 char *desc;
995 999
996 i = 0;
997 while (true) { 1000 while (true) {
998 new = new_state(params); 1001 new = new_state(params);
999 abort = false; 1002 abort = false;
@@ -1031,7 +1034,7 @@ static char *new_game_desc(const game_params *params, random_state *rs,
1031 /* Monsters / Mirrors ratio should be balanced */ 1034 /* Monsters / Mirrors ratio should be balanced */
1032 ratio = (float)new->common->num_total / 1035 ratio = (float)new->common->num_total /
1033 (float)(new->common->params.w * new->common->params.h); 1036 (float)(new->common->params.w * new->common->params.h);
1034 if (ratio < 0.48 || ratio > 0.78) { 1037 if (ratio < 0.48F || ratio > 0.78F) {
1035 free_game(new); 1038 free_game(new);
1036 continue; 1039 continue;
1037 } 1040 }
@@ -1253,7 +1256,6 @@ static char *new_game_desc(const game_params *params, random_state *rs,
1253 * difficulty level, free memory and start from scratch */ 1256 * difficulty level, free memory and start from scratch */
1254 sfree(old_guess); 1257 sfree(old_guess);
1255 free_game(new); 1258 free_game(new);
1256 i++;
1257 } 1259 }
1258 1260
1259 /* We have a valid puzzle! */ 1261 /* We have a valid puzzle! */
@@ -1574,6 +1576,8 @@ static char *solve_game(const game_state *state_start, const game_state *currsta
1574 } 1576 }
1575 1577
1576/* printf("Puzzle solved at level %s, iterations %d, ambiguous %d\n", (solved_bruteforce ? "TRICKY" : "NORMAL"), iterative_depth, count_ambiguous); */ 1578/* printf("Puzzle solved at level %s, iterations %d, ambiguous %d\n", (solved_bruteforce ? "TRICKY" : "NORMAL"), iterative_depth, count_ambiguous); */
1579 (void)iterative_depth;
1580 (void)count_ambiguous;
1577 1581
1578 move = snewn(solve_state->common->num_total * 4 +2, char); 1582 move = snewn(solve_state->common->num_total * 4 +2, char);
1579 c = move; 1583 c = move;
@@ -1640,31 +1644,64 @@ struct game_ui {
1640 int hx, hy; /* as for solo.c, highlight pos */ 1644 int hx, hy; /* as for solo.c, highlight pos */
1641 bool hshow, hpencil, hcursor; /* show state, type, and ?cursor. */ 1645 bool hshow, hpencil, hcursor; /* show state, type, and ?cursor. */
1642 bool ascii; 1646 bool ascii;
1647
1648 /*
1649 * User preference option: if the user right-clicks in a square
1650 * and presses a monster key to add/remove a pencil mark, do we
1651 * hide the mouse highlight again afterwards?
1652 *
1653 * Historically our answer was yes. The Android port prefers no.
1654 * There are advantages both ways, depending how much you dislike
1655 * the highlight cluttering your view. So it's a preference.
1656 */
1657 bool pencil_keep_highlight;
1643}; 1658};
1644 1659
1645static game_ui *new_ui(const game_state *state) 1660static game_ui *new_ui(const game_state *state)
1646{ 1661{
1647 game_ui *ui = snew(game_ui); 1662 game_ui *ui = snew(game_ui);
1648 ui->hx = ui->hy = 0;
1649 ui->hpencil = false; 1663 ui->hpencil = false;
1650 ui->hshow = false; 1664 ui->hx = ui->hy = ui->hshow = ui->hcursor =
1651 ui->hcursor = false; 1665 getenv_bool("PUZZLES_SHOW_CURSOR", false);
1652 ui->ascii = false; 1666 ui->ascii = false;
1667
1668 ui->pencil_keep_highlight = false;
1669
1653 return ui; 1670 return ui;
1654} 1671}
1655 1672
1656static void free_ui(game_ui *ui) { 1673static config_item *get_prefs(game_ui *ui)
1657 sfree(ui); 1674{
1658 return; 1675 config_item *ret;
1676
1677 ret = snewn(3, config_item);
1678
1679 ret[0].name = "Keep mouse highlight after changing a pencil mark";
1680 ret[0].kw = "pencil-keep-highlight";
1681 ret[0].type = C_BOOLEAN;
1682 ret[0].u.boolean.bval = ui->pencil_keep_highlight;
1683
1684 ret[1].name = "Monster representation";
1685 ret[1].kw = "monsters";
1686 ret[1].type = C_CHOICES;
1687 ret[1].u.choices.choicenames = ":Pictures:Letters";
1688 ret[1].u.choices.choicekws = ":pictures:letters";
1689 ret[1].u.choices.selected = ui->ascii;
1690
1691 ret[2].name = NULL;
1692 ret[2].type = C_END;
1693
1694 return ret;
1659} 1695}
1660 1696
1661static char *encode_ui(const game_ui *ui) 1697static void set_prefs(game_ui *ui, const config_item *cfg)
1662{ 1698{
1663 return NULL; 1699 ui->pencil_keep_highlight = cfg[0].u.boolean.bval;
1700 ui->ascii = cfg[1].u.choices.selected;
1664} 1701}
1665 1702
1666static void decode_ui(game_ui *ui, const char *encoding) 1703static void free_ui(game_ui *ui) {
1667{ 1704 sfree(ui);
1668 return; 1705 return;
1669} 1706}
1670 1707
@@ -1681,6 +1718,20 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1681 } 1718 }
1682} 1719}
1683 1720
1721static const char *current_key_label(const game_ui *ui,
1722 const game_state *state, int button)
1723{
1724 int xi;
1725
1726 if (ui->hshow && button == CURSOR_SELECT)
1727 return ui->hpencil ? "Ink" : "Pencil";
1728 if (button == CURSOR_SELECT2) {
1729 xi = state->common->xinfo[ui->hx + ui->hy*(state->common->params.w+2)];
1730 if (xi >= 0 && !state->common->fixed[xi]) return "Clear";
1731 }
1732 return "";
1733}
1734
1684struct game_drawstate { 1735struct game_drawstate {
1685 int tilesize; 1736 int tilesize;
1686 bool started, solved; 1737 bool started, solved;
@@ -1743,7 +1794,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1743 1794
1744 if (button == 'a' || button == 'A') { 1795 if (button == 'a' || button == 'A') {
1745 ui->ascii = !ui->ascii; 1796 ui->ascii = !ui->ascii;
1746 return UI_UPDATE; 1797 return MOVE_UI_UPDATE;
1747 } 1798 }
1748 1799
1749 if (button == 'm' || button == 'M') { 1800 if (button == 'm' || button == 'M') {
@@ -1755,22 +1806,30 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1755 if (xi >= 0 && !state->common->fixed[xi]) { 1806 if (xi >= 0 && !state->common->fixed[xi]) {
1756 if (button == 'g' || button == 'G' || button == '1') { 1807 if (button == 'g' || button == 'G' || button == '1') {
1757 if (!ui->hcursor) ui->hshow = false; 1808 if (!ui->hcursor) ui->hshow = false;
1809 if (state->guess[xi] == 1)
1810 return ui->hcursor ? NULL : MOVE_UI_UPDATE;
1758 sprintf(buf,"G%d",xi); 1811 sprintf(buf,"G%d",xi);
1759 return dupstr(buf); 1812 return dupstr(buf);
1760 } 1813 }
1761 if (button == 'v' || button == 'V' || button == '2') { 1814 if (button == 'v' || button == 'V' || button == '2') {
1762 if (!ui->hcursor) ui->hshow = false; 1815 if (!ui->hcursor) ui->hshow = false;
1816 if (state->guess[xi] == 2)
1817 return ui->hcursor ? NULL : MOVE_UI_UPDATE;
1763 sprintf(buf,"V%d",xi); 1818 sprintf(buf,"V%d",xi);
1764 return dupstr(buf); 1819 return dupstr(buf);
1765 } 1820 }
1766 if (button == 'z' || button == 'Z' || button == '3') { 1821 if (button == 'z' || button == 'Z' || button == '3') {
1767 if (!ui->hcursor) ui->hshow = false; 1822 if (!ui->hcursor) ui->hshow = false;
1823 if (state->guess[xi] == 4)
1824 return ui->hcursor ? NULL : MOVE_UI_UPDATE;
1768 sprintf(buf,"Z%d",xi); 1825 sprintf(buf,"Z%d",xi);
1769 return dupstr(buf); 1826 return dupstr(buf);
1770 } 1827 }
1771 if (button == 'e' || button == 'E' || button == CURSOR_SELECT2 || 1828 if (button == 'e' || button == 'E' || button == CURSOR_SELECT2 ||
1772 button == '0' || button == '\b' ) { 1829 button == '0' || button == '\b' ) {
1773 if (!ui->hcursor) ui->hshow = false; 1830 if (!ui->hcursor) ui->hshow = false;
1831 if (state->guess[xi] == 7 && state->pencils[xi] == 0)
1832 return ui->hcursor ? NULL : MOVE_UI_UPDATE;
1774 sprintf(buf,"E%d",xi); 1833 sprintf(buf,"E%d",xi);
1775 return dupstr(buf); 1834 return dupstr(buf);
1776 } 1835 }
@@ -1790,45 +1849,42 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1790 } 1849 }
1791 ui->hshow = true; 1850 ui->hshow = true;
1792 ui->hcursor = true; 1851 ui->hcursor = true;
1793 return UI_UPDATE; 1852 return MOVE_UI_UPDATE;
1794 } 1853 }
1795 if (ui->hshow && button == CURSOR_SELECT) { 1854 if (ui->hshow && button == CURSOR_SELECT) {
1796 ui->hpencil = !ui->hpencil; 1855 ui->hpencil = !ui->hpencil;
1797 ui->hcursor = true; 1856 ui->hcursor = true;
1798 return UI_UPDATE; 1857 return MOVE_UI_UPDATE;
1799 } 1858 }
1800 1859
1801 if (ui->hshow && ui->hpencil) { 1860 if (ui->hshow && ui->hpencil) {
1802 xi = state->common->xinfo[ui->hx + ui->hy*(state->common->params.w+2)]; 1861 xi = state->common->xinfo[ui->hx + ui->hy*(state->common->params.w+2)];
1803 if (xi >= 0 && !state->common->fixed[xi]) { 1862 if (xi >= 0 && !state->common->fixed[xi]) {
1863 buf[0] = '\0';
1864
1804 if (button == 'g' || button == 'G' || button == '1') { 1865 if (button == 'g' || button == 'G' || button == '1') {
1805 sprintf(buf,"g%d",xi); 1866 sprintf(buf,"g%d",xi);
1806 if (!ui->hcursor) { 1867 } else if (button == 'v' || button == 'V' || button == '2') {
1807 ui->hpencil = false;
1808 ui->hshow = false;
1809 }
1810 return dupstr(buf);
1811 }
1812 if (button == 'v' || button == 'V' || button == '2') {
1813 sprintf(buf,"v%d",xi); 1868 sprintf(buf,"v%d",xi);
1814 if (!ui->hcursor) { 1869 } else if (button == 'z' || button == 'Z' || button == '3') {
1815 ui->hpencil = false;
1816 ui->hshow = false;
1817 }
1818 return dupstr(buf);
1819 }
1820 if (button == 'z' || button == 'Z' || button == '3') {
1821 sprintf(buf,"z%d",xi); 1870 sprintf(buf,"z%d",xi);
1822 if (!ui->hcursor) { 1871 } else if (button == 'e' || button == 'E' ||
1823 ui->hpencil = false; 1872 button == CURSOR_SELECT2 || button == '0' ||
1824 ui->hshow = false; 1873 button == '\b') {
1825 } 1874 if (state->pencils[xi] == 0)
1826 return dupstr(buf); 1875 return ui->hcursor ? NULL : MOVE_UI_UPDATE;
1827 }
1828 if (button == 'e' || button == 'E' || button == CURSOR_SELECT2 ||
1829 button == '0' || button == '\b') {
1830 sprintf(buf,"E%d",xi); 1876 sprintf(buf,"E%d",xi);
1831 if (!ui->hcursor) { 1877 }
1878
1879 if (buf[0]) {
1880 /*
1881 * Hide the highlight after a keypress, if it was mouse-
1882 * generated. Also, don't hide it if this move has changed
1883 * pencil marks and the user preference says not to hide the
1884 * highlight in that situation.
1885 */
1886 if (!ui->hcursor &&
1887 !(ui->hpencil && ui->pencil_keep_highlight)) {
1832 ui->hpencil = false; 1888 ui->hpencil = false;
1833 ui->hshow = false; 1889 ui->hshow = false;
1834 } 1890 }
@@ -1847,14 +1903,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1847 ui->hpencil = false; 1903 ui->hpencil = false;
1848 ui->hcursor = false; 1904 ui->hcursor = false;
1849 ui->hx = gx; ui->hy = gy; 1905 ui->hx = gx; ui->hy = gy;
1850 return UI_UPDATE; 1906 return MOVE_UI_UPDATE;
1851 } 1907 }
1852 else if (button == RIGHT_BUTTON && g == 7) { 1908 else if (button == RIGHT_BUTTON && g == 7) {
1853 ui->hshow = true; 1909 ui->hshow = true;
1854 ui->hpencil = true; 1910 ui->hpencil = true;
1855 ui->hcursor = false; 1911 ui->hcursor = false;
1856 ui->hx = gx; ui->hy = gy; 1912 ui->hx = gx; ui->hy = gy;
1857 return UI_UPDATE; 1913 return MOVE_UI_UPDATE;
1858 } 1914 }
1859 } 1915 }
1860 else if (ui->hshow) { 1916 else if (ui->hshow) {
@@ -1865,14 +1921,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1865 ui->hpencil = false; 1921 ui->hpencil = false;
1866 ui->hcursor = false; 1922 ui->hcursor = false;
1867 ui->hx = 0; ui->hy = 0; 1923 ui->hx = 0; ui->hy = 0;
1868 return UI_UPDATE; 1924 return MOVE_UI_UPDATE;
1869 } 1925 }
1870 else { 1926 else {
1871 ui->hshow = true; 1927 ui->hshow = true;
1872 ui->hpencil = false; 1928 ui->hpencil = false;
1873 ui->hcursor = false; 1929 ui->hcursor = false;
1874 ui->hx = gx; ui->hy = gy; 1930 ui->hx = gx; ui->hy = gy;
1875 return UI_UPDATE; 1931 return MOVE_UI_UPDATE;
1876 } 1932 }
1877 } 1933 }
1878 else { 1934 else {
@@ -1880,7 +1936,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1880 ui->hpencil = false; 1936 ui->hpencil = false;
1881 ui->hcursor = false; 1937 ui->hcursor = false;
1882 ui->hx = gx; ui->hy = gy; 1938 ui->hx = gx; ui->hy = gy;
1883 return UI_UPDATE; 1939 return MOVE_UI_UPDATE;
1884 } 1940 }
1885 } 1941 }
1886 else if (button == RIGHT_BUTTON) { 1942 else if (button == RIGHT_BUTTON) {
@@ -1889,7 +1945,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1889 ui->hpencil = true; 1945 ui->hpencil = true;
1890 ui->hcursor = false; 1946 ui->hcursor = false;
1891 ui->hx = gx; ui->hy = gy; 1947 ui->hx = gx; ui->hy = gy;
1892 return UI_UPDATE; 1948 return MOVE_UI_UPDATE;
1893 } 1949 }
1894 else { 1950 else {
1895 if (gx == ui->hx && gy == ui->hy) { 1951 if (gx == ui->hx && gy == ui->hy) {
@@ -1897,14 +1953,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1897 ui->hpencil = false; 1953 ui->hpencil = false;
1898 ui->hcursor = false; 1954 ui->hcursor = false;
1899 ui->hx = 0; ui->hy = 0; 1955 ui->hx = 0; ui->hy = 0;
1900 return UI_UPDATE; 1956 return MOVE_UI_UPDATE;
1901 } 1957 }
1902 else if (g == 7) { 1958 else if (g == 7) {
1903 ui->hshow = true; 1959 ui->hshow = true;
1904 ui->hpencil = true; 1960 ui->hpencil = true;
1905 ui->hcursor = false; 1961 ui->hcursor = false;
1906 ui->hx = gx; ui->hy = gy; 1962 ui->hx = gx; ui->hy = gy;
1907 return UI_UPDATE; 1963 return MOVE_UI_UPDATE;
1908 } 1964 }
1909 } 1965 }
1910 } 1966 }
@@ -2056,11 +2112,11 @@ static game_state *execute_move(const game_state *state, const char *move)
2056 if (c == 'S') { 2112 if (c == 'S') {
2057 move++; 2113 move++;
2058 solver = true; 2114 solver = true;
2059 } 2115 } else if (c == 'G' || c == 'V' || c == 'Z' || c == 'E' ||
2060 if (c == 'G' || c == 'V' || c == 'Z' || c == 'E' || 2116 c == 'g' || c == 'v' || c == 'z') {
2061 c == 'g' || c == 'v' || c == 'z') {
2062 move++; 2117 move++;
2063 sscanf(move, "%d%n", &x, &n); 2118 if (sscanf(move, "%d%n", &x, &n) != 1) goto badmove;
2119 if (x < 0 || x >= ret->common->num_total) goto badmove;
2064 if (c == 'G') ret->guess[x] = 1; 2120 if (c == 'G') ret->guess[x] = 1;
2065 if (c == 'V') ret->guess[x] = 2; 2121 if (c == 'V') ret->guess[x] = 2;
2066 if (c == 'Z') ret->guess[x] = 4; 2122 if (c == 'Z') ret->guess[x] = 4;
@@ -2069,23 +2125,26 @@ static game_state *execute_move(const game_state *state, const char *move)
2069 if (c == 'v') ret->pencils[x] ^= 2; 2125 if (c == 'v') ret->pencils[x] ^= 2;
2070 if (c == 'z') ret->pencils[x] ^= 4; 2126 if (c == 'z') ret->pencils[x] ^= 4;
2071 move += n; 2127 move += n;
2072 } 2128 } else if (c == 'D' && sscanf(move + 1, "%d,%d%n", &x, &y, &n) == 2 &&
2073 if (c == 'D' && sscanf(move + 1, "%d,%d%n", &x, &y, &n) == 2 && 2129 is_clue(ret, x, y)) {
2074 is_clue(ret, x, y)) {
2075 ret->hints_done[clue_index(ret, x, y)] ^= 1; 2130 ret->hints_done[clue_index(ret, x, y)] ^= 1;
2076 move += n + 1; 2131 move += n + 1;
2077 } 2132 } else if (c == 'M') {
2078 if (c == 'M') {
2079 /* 2133 /*
2080 * Fill in absolutely all pencil marks in unfilled 2134 * Fill in absolutely all pencil marks in unfilled
2081 * squares, for those who like to play by the rigorous 2135 * squares, for those who like to play by the rigorous
2082 * approach of starting off in that state and eliminating 2136 * approach of starting off in that state and eliminating
2083 * things. 2137 * things.
2084 */ 2138 */
2085 for (i = 0; i < ret->common->wh; i++) 2139 for (i = 0; i < ret->common->num_total; i++)
2086 if (ret->guess[i] == 7) 2140 if (ret->guess[i] == 7)
2087 ret->pencils[i] = 7; 2141 ret->pencils[i] = 7;
2088 move++; 2142 move++;
2143 } else {
2144 /* Unknown move type. */
2145 badmove:
2146 free_game(ret);
2147 return NULL;
2089 } 2148 }
2090 if (*move == ';') move++; 2149 if (*move == ';') move++;
2091 } 2150 }
@@ -2118,7 +2177,7 @@ static game_state *execute_move(const game_state *state, const char *move)
2118#define PREFERRED_TILE_SIZE 64 2177#define PREFERRED_TILE_SIZE 64
2119 2178
2120static void game_compute_size(const game_params *params, int tilesize, 2179static void game_compute_size(const game_params *params, int tilesize,
2121 int *x, int *y) 2180 const game_ui *ui, int *x, int *y)
2122{ 2181{
2123 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2182 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2124 struct { int tilesize; } ads, *ds = &ads; 2183 struct { int tilesize; } ads, *ds = &ads;
@@ -2402,7 +2461,7 @@ static void draw_monster(drawing *dr, game_drawstate *ds, int x, int y,
2402static void draw_monster_count(drawing *dr, game_drawstate *ds, 2461static void draw_monster_count(drawing *dr, game_drawstate *ds,
2403 const game_state *state, int c, bool hflash) { 2462 const game_state *state, int c, bool hflash) {
2404 int dx,dy; 2463 int dx,dy;
2405 char buf[8]; 2464 char buf[MAX_DIGITS(int) + 1];
2406 char bufm[8]; 2465 char bufm[8];
2407 2466
2408 dy = TILESIZE/4; 2467 dy = TILESIZE/4;
@@ -2447,7 +2506,7 @@ static void draw_path_hint(drawing *dr, game_drawstate *ds,
2447 const struct game_params *params, 2506 const struct game_params *params,
2448 int hint_index, bool hflash, int hint) { 2507 int hint_index, bool hflash, int hint) {
2449 int x, y, color, dx, dy, text_dx, text_dy, text_size; 2508 int x, y, color, dx, dy, text_dx, text_dy, text_size;
2450 char buf[4]; 2509 char buf[MAX_DIGITS(int) + 1];
2451 2510
2452 if (ds->hint_errors[hint_index]) 2511 if (ds->hint_errors[hint_index])
2453 color = COL_ERROR; 2512 color = COL_ERROR;
@@ -2605,8 +2664,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2605 2664
2606 /* Draw static grid components at startup */ 2665 /* Draw static grid components at startup */
2607 if (!ds->started) { 2666 if (!ds->started) {
2608 draw_rect(dr, 0, 0, 2*BORDER+(ds->w+2)*TILESIZE,
2609 2*BORDER+(ds->h+3)*TILESIZE, COL_BACKGROUND);
2610 draw_rect(dr, BORDER+TILESIZE-1, BORDER+2*TILESIZE-1, 2667 draw_rect(dr, BORDER+TILESIZE-1, BORDER+2*TILESIZE-1,
2611 (ds->w)*TILESIZE +3, (ds->h)*TILESIZE +3, COL_GRID); 2668 (ds->w)*TILESIZE +3, (ds->h)*TILESIZE +3, COL_GRID);
2612 for (i=0;i<ds->w;i++) 2669 for (i=0;i<ds->w;i++)
@@ -2745,19 +2802,6 @@ static int game_status(const game_state *state)
2745 return state->solved; 2802 return state->solved;
2746} 2803}
2747 2804
2748static bool game_timing_state(const game_state *state, game_ui *ui)
2749{
2750 return true;
2751}
2752
2753static void game_print_size(const game_params *params, float *x, float *y)
2754{
2755}
2756
2757static void game_print(drawing *dr, const game_state *state, int tilesize)
2758{
2759}
2760
2761#ifdef COMBINED 2805#ifdef COMBINED
2762#define thegame undead 2806#define thegame undead
2763#endif 2807#endif
@@ -2779,12 +2823,14 @@ const struct game thegame = {
2779 free_game, 2823 free_game,
2780 true, solve_game, 2824 true, solve_game,
2781 true, game_can_format_as_text_now, game_text_format, 2825 true, game_can_format_as_text_now, game_text_format,
2826 get_prefs, set_prefs,
2782 new_ui, 2827 new_ui,
2783 free_ui, 2828 free_ui,
2784 encode_ui, 2829 NULL, /* encode_ui */
2785 decode_ui, 2830 NULL, /* decode_ui */
2786 game_request_keys, 2831 game_request_keys,
2787 game_changed_state, 2832 game_changed_state,
2833 current_key_label,
2788 interpret_move, 2834 interpret_move,
2789 execute_move, 2835 execute_move,
2790 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 2836 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -2796,8 +2842,8 @@ const struct game thegame = {
2796 game_flash_length, 2842 game_flash_length,
2797 game_get_cursor_location, 2843 game_get_cursor_location,
2798 game_status, 2844 game_status,
2799 false, false, game_print_size, game_print, 2845 false, false, NULL, NULL, /* print_size, print */
2800 false, /* wants_statusbar */ 2846 false, /* wants_statusbar */
2801 false, game_timing_state, 2847 false, NULL, /* timing_state */
2802 0, /* flags */ 2848 0, /* flags */
2803}; 2849};
diff --git a/apps/plugins/puzzles/src/unequal.R b/apps/plugins/puzzles/src/unequal.R
deleted file mode 100644
index 077407ffff..0000000000
--- a/apps/plugins/puzzles/src/unequal.R
+++ /dev/null
@@ -1,25 +0,0 @@
1# -*- makefile -*-
2
3UNEQUAL_EXTRA = LATIN
4UNEQUAL_EXTRA_SOLVER = LATIN_SOLVER
5
6unequal : [X] GTK COMMON unequal UNEQUAL_EXTRA unequal-icon|no-icon
7
8unequal : [G] WINDOWS COMMON unequal UNEQUAL_EXTRA unequal.res|noicon.res
9
10unequalsolver : [U] unequal[STANDALONE_SOLVER] UNEQUAL_EXTRA_SOLVER STANDALONE
11unequalsolver : [C] unequal[STANDALONE_SOLVER] UNEQUAL_EXTRA_SOLVER STANDALONE
12
13ALL += unequal[COMBINED] UNEQUAL_EXTRA
14
15!begin am gtk
16GAMES += unequal
17!end
18
19!begin >list.c
20 A(unequal) \
21!end
22
23!begin >gamedesc.txt
24unequal:unequal.exe:Unequal:Latin square puzzle:Complete the latin square in accordance with the > signs.
25!end
diff --git a/apps/plugins/puzzles/src/unequal.c b/apps/plugins/puzzles/src/unequal.c
index 153954e510..ab32e4ab79 100644
--- a/apps/plugins/puzzles/src/unequal.c
+++ b/apps/plugins/puzzles/src/unequal.c
@@ -21,7 +21,11 @@
21#include <string.h> 21#include <string.h>
22#include <assert.h> 22#include <assert.h>
23#include <ctype.h> 23#include <ctype.h>
24#include <math.h> 24#ifdef NO_TGMATH_H
25# include <math.h>
26#else
27# include <tgmath.h>
28#endif
25 29
26#include "puzzles.h" 30#include "puzzles.h"
27#include "latin.h" /* contains typedef for digit */ 31#include "latin.h" /* contains typedef for digit */
@@ -84,6 +88,7 @@ struct game_params {
84#define ADJ_TO_SPENT(x) ((x) << 9) 88#define ADJ_TO_SPENT(x) ((x) << 9)
85 89
86#define F_ERROR_MASK (F_ERROR|F_ERROR_UP|F_ERROR_RIGHT|F_ERROR_DOWN|F_ERROR_LEFT) 90#define F_ERROR_MASK (F_ERROR|F_ERROR_UP|F_ERROR_RIGHT|F_ERROR_DOWN|F_ERROR_LEFT)
91#define F_SPENT_MASK (F_SPENT_UP|F_SPENT_RIGHT|F_SPENT_DOWN|F_SPENT_LEFT)
87 92
88struct game_state { 93struct game_state {
89 int order; 94 int order;
@@ -890,13 +895,14 @@ static int solver_state(game_state *state, int maxdiff)
890 struct latin_solver solver; 895 struct latin_solver solver;
891 int diff; 896 int diff;
892 897
893 latin_solver_alloc(&solver, state->nums, state->order); 898 if (latin_solver_alloc(&solver, state->nums, state->order))
894 899 diff = latin_solver_main(&solver, maxdiff,
895 diff = latin_solver_main(&solver, maxdiff, 900 DIFF_LATIN, DIFF_SET, DIFF_EXTREME,
896 DIFF_LATIN, DIFF_SET, DIFF_EXTREME, 901 DIFF_EXTREME, DIFF_RECURSIVE,
897 DIFF_EXTREME, DIFF_RECURSIVE, 902 unequal_solvers, unequal_valid, ctx,
898 unequal_solvers, unequal_valid, ctx, 903 clone_ctx, free_ctx);
899 clone_ctx, free_ctx); 904 else
905 diff = DIFF_IMPOSSIBLE;
900 906
901 memcpy(state->hints, solver.cube, state->order*state->order*state->order); 907 memcpy(state->hints, solver.cube, state->order*state->order*state->order);
902 908
@@ -1073,7 +1079,7 @@ static int gg_best_clue(game_state *state, int *scratch, digit *latin)
1073} 1079}
1074 1080
1075#ifdef STANDALONE_SOLVER 1081#ifdef STANDALONE_SOLVER
1076int maxtries; 1082static int maxtries;
1077#define MAXTRIES maxtries 1083#define MAXTRIES maxtries
1078#else 1084#else
1079#define MAXTRIES 50 1085#define MAXTRIES 50
@@ -1430,6 +1436,17 @@ static char *solve_game(const game_state *state, const game_state *currstate,
1430struct game_ui { 1436struct game_ui {
1431 int hx, hy; /* as for solo.c, highlight pos */ 1437 int hx, hy; /* as for solo.c, highlight pos */
1432 bool hshow, hpencil, hcursor; /* show state, type, and ?cursor. */ 1438 bool hshow, hpencil, hcursor; /* show state, type, and ?cursor. */
1439
1440 /*
1441 * User preference option: if the user right-clicks in a square
1442 * and presses a number key to add/remove a pencil mark, do we
1443 * hide the mouse highlight again afterwards?
1444 *
1445 * Historically our answer was yes. The Android port prefers no.
1446 * There are advantages both ways, depending how much you dislike
1447 * the highlight cluttering your view. So it's a preference.
1448 */
1449 bool pencil_keep_highlight;
1433}; 1450};
1434 1451
1435static game_ui *new_ui(const game_state *state) 1452static game_ui *new_ui(const game_state *state)
@@ -1438,8 +1455,9 @@ static game_ui *new_ui(const game_state *state)
1438 1455
1439 ui->hx = ui->hy = 0; 1456 ui->hx = ui->hy = 0;
1440 ui->hpencil = false; 1457 ui->hpencil = false;
1441 ui->hshow = false; 1458 ui->hshow = ui->hcursor = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1442 ui->hcursor = false; 1459
1460 ui->pencil_keep_highlight = false;
1443 1461
1444 return ui; 1462 return ui;
1445} 1463}
@@ -1449,13 +1467,26 @@ static void free_ui(game_ui *ui)
1449 sfree(ui); 1467 sfree(ui);
1450} 1468}
1451 1469
1452static char *encode_ui(const game_ui *ui) 1470static config_item *get_prefs(game_ui *ui)
1453{ 1471{
1454 return NULL; 1472 config_item *ret;
1473
1474 ret = snewn(2, config_item);
1475
1476 ret[0].name = "Keep mouse highlight after changing a pencil mark";
1477 ret[0].kw = "pencil-keep-highlight";
1478 ret[0].type = C_BOOLEAN;
1479 ret[0].u.boolean.bval = ui->pencil_keep_highlight;
1480
1481 ret[1].name = NULL;
1482 ret[1].type = C_END;
1483
1484 return ret;
1455} 1485}
1456 1486
1457static void decode_ui(game_ui *ui, const char *encoding) 1487static void set_prefs(game_ui *ui, const config_item *cfg)
1458{ 1488{
1489 ui->pencil_keep_highlight = cfg[0].u.boolean.bval;
1459} 1490}
1460 1491
1461static void game_changed_state(game_ui *ui, const game_state *oldstate, 1492static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -1470,6 +1501,14 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1470 } 1501 }
1471} 1502}
1472 1503
1504static const char *current_key_label(const game_ui *ui,
1505 const game_state *state, int button)
1506{
1507 if (ui->hshow && IS_CURSOR_SELECT(button))
1508 return ui->hpencil ? "Ink" : "Pencil";
1509 return "";
1510}
1511
1473struct game_drawstate { 1512struct game_drawstate {
1474 int tilesize, order; 1513 int tilesize, order;
1475 bool started; 1514 bool started;
@@ -1491,7 +1530,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1491 char buf[80]; 1530 char buf[80];
1492 bool shift_or_control = button & (MOD_SHFT | MOD_CTRL); 1531 bool shift_or_control = button & (MOD_SHFT | MOD_CTRL);
1493 1532
1494 button &= ~MOD_MASK; 1533 button = STRIP_BUTTON_MODIFIERS(button);
1495 1534
1496 if (x >= 0 && x < ds->order && y >= 0 && y < ds->order && IS_MOUSE_DOWN(button)) { 1535 if (x >= 0 && x < ds->order && y >= 0 && y < ds->order && IS_MOUSE_DOWN(button)) {
1497 if (oy - COORD(y) > TILE_SIZE && ox - COORD(x) > TILE_SIZE) 1536 if (oy - COORD(y) > TILE_SIZE && ox - COORD(x) > TILE_SIZE)
@@ -1527,7 +1566,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1527 ui->hshow = true; 1566 ui->hshow = true;
1528 } 1567 }
1529 ui->hcursor = false; 1568 ui->hcursor = false;
1530 return UI_UPDATE; 1569 return MOVE_UI_UPDATE;
1531 } 1570 }
1532 if (button == RIGHT_BUTTON) { 1571 if (button == RIGHT_BUTTON) {
1533 /* pencil highlighting for non-filled squares */ 1572 /* pencil highlighting for non-filled squares */
@@ -1541,7 +1580,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1541 ui->hshow = true; 1580 ui->hshow = true;
1542 } 1581 }
1543 ui->hcursor = false; 1582 ui->hcursor = false;
1544 return UI_UPDATE; 1583 return MOVE_UI_UPDATE;
1545 } 1584 }
1546 } 1585 }
1547 1586
@@ -1549,7 +1588,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1549 if (shift_or_control) { 1588 if (shift_or_control) {
1550 int nx = ui->hx, ny = ui->hy, i; 1589 int nx = ui->hx, ny = ui->hy, i;
1551 bool self; 1590 bool self;
1552 move_cursor(button, &nx, &ny, ds->order, ds->order, false); 1591 move_cursor(button, &nx, &ny, ds->order, ds->order, false, NULL);
1553 ui->hshow = true; 1592 ui->hshow = true;
1554 ui->hcursor = true; 1593 ui->hcursor = true;
1555 1594
@@ -1557,12 +1596,12 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1557 ny != ui->hy + adjthan[i].dy); ++i); 1596 ny != ui->hy + adjthan[i].dy); ++i);
1558 1597
1559 if (i == 4) 1598 if (i == 4)
1560 return UI_UPDATE; /* invalid direction, i.e. out of 1599 return MOVE_UI_UPDATE; /* invalid direction, i.e. out of
1561 * the board */ 1600 * the board */
1562 1601
1563 if (!(GRID(state, flags, ui->hx, ui->hy) & adjthan[i].f || 1602 if (!(GRID(state, flags, ui->hx, ui->hy) & adjthan[i].f ||
1564 GRID(state, flags, nx, ny ) & adjthan[i].fo)) 1603 GRID(state, flags, nx, ny ) & adjthan[i].fo))
1565 return UI_UPDATE; /* no clue to toggle */ 1604 return MOVE_UI_UPDATE; /* no clue to toggle */
1566 1605
1567 if (state->mode == MODE_ADJACENT) 1606 if (state->mode == MODE_ADJACENT)
1568 self = (adjthan[i].dx >= 0 && adjthan[i].dy >= 0); 1607 self = (adjthan[i].dx >= 0 && adjthan[i].dy >= 0);
@@ -1570,24 +1609,23 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1570 self = (GRID(state, flags, ui->hx, ui->hy) & adjthan[i].f); 1609 self = (GRID(state, flags, ui->hx, ui->hy) & adjthan[i].f);
1571 1610
1572 if (self) 1611 if (self)
1573 sprintf(buf, "F%d,%d,%d", ui->hx, ui->hy, 1612 sprintf(buf, "F%d,%d,%u", ui->hx, ui->hy,
1574 ADJ_TO_SPENT(adjthan[i].f)); 1613 ADJ_TO_SPENT(adjthan[i].f));
1575 else 1614 else
1576 sprintf(buf, "F%d,%d,%d", nx, ny, 1615 sprintf(buf, "F%d,%d,%u", nx, ny,
1577 ADJ_TO_SPENT(adjthan[i].fo)); 1616 ADJ_TO_SPENT(adjthan[i].fo));
1578 1617
1579 return dupstr(buf); 1618 return dupstr(buf);
1580 } else { 1619 } else {
1581 move_cursor(button, &ui->hx, &ui->hy, ds->order, ds->order, false);
1582 ui->hshow = true;
1583 ui->hcursor = true; 1620 ui->hcursor = true;
1584 return UI_UPDATE; 1621 return move_cursor(button, &ui->hx, &ui->hy, ds->order, ds->order,
1622 false, &ui->hshow);
1585 } 1623 }
1586 } 1624 }
1587 if (ui->hshow && IS_CURSOR_SELECT(button)) { 1625 if (ui->hshow && IS_CURSOR_SELECT(button)) {
1588 ui->hpencil = !ui->hpencil; 1626 ui->hpencil = !ui->hpencil;
1589 ui->hcursor = true; 1627 ui->hcursor = true;
1590 return UI_UPDATE; 1628 return MOVE_UI_UPDATE;
1591 } 1629 }
1592 1630
1593 n = c2n(button, state->order); 1631 n = c2n(button, state->order);
@@ -1604,11 +1642,37 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1604 if (ui->hpencil && GRID(state, nums, ui->hx, ui->hy) > 0) 1642 if (ui->hpencil && GRID(state, nums, ui->hx, ui->hy) > 0)
1605 return NULL; /* can't change hints on filled square (!) */ 1643 return NULL; /* can't change hints on filled square (!) */
1606 1644
1645 /*
1646 * If you ask to fill a square with what it already contains,
1647 * or blank it when it's already empty, that has no effect...
1648 */
1649 if ((!ui->hpencil || n == 0) &&
1650 GRID(state, nums, ui->hx, ui->hy) == n) {
1651 bool anypencil = false;
1652 int i;
1653 for (i = 0; i < state->order; i++)
1654 anypencil = anypencil || HINT(state, ui->hx, ui->hy, i);
1655 if (!anypencil) {
1656 /* ... expect to remove the cursor in mouse mode. */
1657 if (!ui->hcursor) {
1658 ui->hshow = false;
1659 return MOVE_UI_UPDATE;
1660 }
1661 return NULL;
1662 }
1663 }
1607 1664
1608 sprintf(buf, "%c%d,%d,%d", 1665 sprintf(buf, "%c%d,%d,%d",
1609 (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); 1666 (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n);
1610 1667
1611 if (!ui->hcursor) ui->hshow = false; 1668 /*
1669 * Hide the highlight after a keypress, if it was mouse-
1670 * generated. Also, don't hide it if this move has changed
1671 * pencil marks and the user preference says not to hide the
1672 * highlight in that situation.
1673 */
1674 if (!ui->hcursor && !(ui->hpencil && ui->pencil_keep_highlight))
1675 ui->hshow = false;
1612 1676
1613 return dupstr(buf); 1677 return dupstr(buf);
1614 } 1678 }
@@ -1624,7 +1688,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1624static game_state *execute_move(const game_state *state, const char *move) 1688static game_state *execute_move(const game_state *state, const char *move)
1625{ 1689{
1626 game_state *ret = NULL; 1690 game_state *ret = NULL;
1627 int x, y, n, i, rc; 1691 int x, y, n, i;
1628 1692
1629 debug(("execute_move: %s", move)); 1693 debug(("execute_move: %s", move));
1630 1694
@@ -1649,7 +1713,7 @@ static game_state *execute_move(const game_state *state, const char *move)
1649 const char *p; 1713 const char *p;
1650 1714
1651 ret = dup_game(state); 1715 ret = dup_game(state);
1652 ret->completed = ret->cheated = true; 1716 ret->cheated = true;
1653 1717
1654 p = move+1; 1718 p = move+1;
1655 for (i = 0; i < state->order*state->order; i++) { 1719 for (i = 0; i < state->order*state->order; i++) {
@@ -1660,8 +1724,8 @@ static game_state *execute_move(const game_state *state, const char *move)
1660 p++; 1724 p++;
1661 } 1725 }
1662 if (*p) goto badmove; 1726 if (*p) goto badmove;
1663 rc = check_complete(ret->nums, ret, true); 1727 if (!ret->completed && check_complete(ret->nums, ret, true) > 0)
1664 assert(rc > 0); 1728 ret->completed = true;
1665 return ret; 1729 return ret;
1666 } else if (move[0] == 'M') { 1730 } else if (move[0] == 'M') {
1667 ret = dup_game(state); 1731 ret = dup_game(state);
@@ -1678,7 +1742,8 @@ static game_state *execute_move(const game_state *state, const char *move)
1678 check_complete(ret->nums, ret, true); 1742 check_complete(ret->nums, ret, true);
1679 return ret; 1743 return ret;
1680 } else if (move[0] == 'F' && sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 && 1744 } else if (move[0] == 'F' && sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 &&
1681 x >= 0 && x < state->order && y >= 0 && y < state->order) { 1745 x >= 0 && x < state->order && y >= 0 && y < state->order &&
1746 (n & ~F_SPENT_MASK) == 0) {
1682 ret = dup_game(state); 1747 ret = dup_game(state);
1683 GRID(ret, flags, x, y) ^= n; 1748 GRID(ret, flags, x, y) ^= n;
1684 return ret; 1749 return ret;
@@ -1696,7 +1761,7 @@ badmove:
1696#define DRAW_SIZE (TILE_SIZE*ds->order + GAP_SIZE*(ds->order-1) + BORDER*2) 1761#define DRAW_SIZE (TILE_SIZE*ds->order + GAP_SIZE*(ds->order-1) + BORDER*2)
1697 1762
1698static void game_compute_size(const game_params *params, int tilesize, 1763static void game_compute_size(const game_params *params, int tilesize,
1699 int *x, int *y) 1764 const game_ui *ui, int *x, int *y)
1700{ 1765{
1701 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 1766 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1702 struct { int tilesize, order; } ads, *ds = &ads; 1767 struct { int tilesize, order; } ads, *ds = &ads;
@@ -1779,18 +1844,18 @@ static void draw_gt(drawing *dr, int ox, int oy,
1779{ 1844{
1780 int coords[12]; 1845 int coords[12];
1781 int xdx = (dx1+dx2 ? 0 : 1), xdy = (dx1+dx2 ? 1 : 0); 1846 int xdx = (dx1+dx2 ? 0 : 1), xdy = (dx1+dx2 ? 1 : 0);
1782 coords[0] = ox + xdx + dx1; 1847 coords[0] = ox + xdx;
1783 coords[1] = oy + xdy + dy1; 1848 coords[1] = oy + xdy;
1784 coords[2] = ox + xdx + dx1 + dx2; 1849 coords[2] = ox + xdx + dx1;
1785 coords[3] = oy + xdy + dy1 + dy2; 1850 coords[3] = oy + xdy + dy1;
1786 coords[4] = ox - xdx + dx1 + dx2; 1851 coords[4] = ox + xdx + dx1 + dx2;
1787 coords[5] = oy - xdy + dy1 + dy2; 1852 coords[5] = oy + xdy + dy1 + dy2;
1788 coords[6] = ox - xdx + dx1; 1853 coords[6] = ox - xdx + dx1 + dx2;
1789 coords[7] = oy - xdy + dy1; 1854 coords[7] = oy - xdy + dy1 + dy2;
1790 coords[8] = ox - xdx; 1855 coords[8] = ox - xdx + dx1;
1791 coords[9] = oy - xdy; 1856 coords[9] = oy - xdy + dy1;
1792 coords[10] = ox + xdx; 1857 coords[10] = ox - xdx;
1793 coords[11] = oy + xdy; 1858 coords[11] = oy - xdy;
1794 draw_polygon(dr, coords, 6, col, col); 1859 draw_polygon(dr, coords, 6, col, col);
1795} 1860}
1796 1861
@@ -2059,22 +2124,19 @@ static int game_status(const game_state *state)
2059 return state->completed ? +1 : 0; 2124 return state->completed ? +1 : 0;
2060} 2125}
2061 2126
2062static bool game_timing_state(const game_state *state, game_ui *ui) 2127static void game_print_size(const game_params *params, const game_ui *ui,
2063{ 2128 float *x, float *y)
2064 return true;
2065}
2066
2067static void game_print_size(const game_params *params, float *x, float *y)
2068{ 2129{
2069 int pw, ph; 2130 int pw, ph;
2070 2131
2071 /* 10mm squares by default, roughly the same as Grauniad. */ 2132 /* 10mm squares by default, roughly the same as Grauniad. */
2072 game_compute_size(params, 1000, &pw, &ph); 2133 game_compute_size(params, 1000, ui, &pw, &ph);
2073 *x = pw / 100.0F; 2134 *x = pw / 100.0F;
2074 *y = ph / 100.0F; 2135 *y = ph / 100.0F;
2075} 2136}
2076 2137
2077static void game_print(drawing *dr, const game_state *state, int tilesize) 2138static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2139 int tilesize)
2078{ 2140{
2079 int ink = print_mono_colour(dr, 0); 2141 int ink = print_mono_colour(dr, 0);
2080 int x, y, o = state->order, ox, oy, n; 2142 int x, y, o = state->order, ox, oy, n;
@@ -2133,12 +2195,14 @@ const struct game thegame = {
2133 free_game, 2195 free_game,
2134 true, solve_game, 2196 true, solve_game,
2135 true, game_can_format_as_text_now, game_text_format, 2197 true, game_can_format_as_text_now, game_text_format,
2198 get_prefs, set_prefs,
2136 new_ui, 2199 new_ui,
2137 free_ui, 2200 free_ui,
2138 encode_ui, 2201 NULL, /* encode_ui */
2139 decode_ui, 2202 NULL, /* decode_ui */
2140 game_request_keys, 2203 game_request_keys,
2141 game_changed_state, 2204 game_changed_state,
2205 current_key_label,
2142 interpret_move, 2206 interpret_move,
2143 execute_move, 2207 execute_move,
2144 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 2208 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -2152,7 +2216,7 @@ const struct game thegame = {
2152 game_status, 2216 game_status,
2153 true, false, game_print_size, game_print, 2217 true, false, game_print_size, game_print,
2154 false, /* wants_statusbar */ 2218 false, /* wants_statusbar */
2155 false, game_timing_state, 2219 false, NULL, /* timing_state */
2156 REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */ 2220 REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */
2157}; 2221};
2158 2222
@@ -2165,7 +2229,7 @@ const struct game thegame = {
2165#include <time.h> 2229#include <time.h>
2166#include <stdarg.h> 2230#include <stdarg.h>
2167 2231
2168const char *quis = NULL; 2232static const char *quis = NULL;
2169 2233
2170#if 0 /* currently unused */ 2234#if 0 /* currently unused */
2171 2235
@@ -2233,13 +2297,14 @@ static int solve(game_params *p, char *desc, int debug)
2233 solver_show_working = debug; 2297 solver_show_working = debug;
2234 game_debug(state); 2298 game_debug(state);
2235 2299
2236 latin_solver_alloc(&solver, state->nums, state->order); 2300 if (latin_solver_alloc(&solver, state->nums, state->order))
2237 2301 diff = latin_solver_main(&solver, DIFF_RECURSIVE,
2238 diff = latin_solver_main(&solver, DIFF_RECURSIVE, 2302 DIFF_LATIN, DIFF_SET, DIFF_EXTREME,
2239 DIFF_LATIN, DIFF_SET, DIFF_EXTREME, 2303 DIFF_EXTREME, DIFF_RECURSIVE,
2240 DIFF_EXTREME, DIFF_RECURSIVE, 2304 unequal_solvers, unequal_valid, ctx,
2241 unequal_solvers, unequal_valid, ctx, 2305 clone_ctx, free_ctx);
2242 clone_ctx, free_ctx); 2306 else
2307 diff = DIFF_IMPOSSIBLE;
2243 2308
2244 free_ctx(ctx); 2309 free_ctx(ctx);
2245 2310
diff --git a/apps/plugins/puzzles/src/unruly.R b/apps/plugins/puzzles/src/unruly.R
deleted file mode 100644
index 064ccc35ba..0000000000
--- a/apps/plugins/puzzles/src/unruly.R
+++ /dev/null
@@ -1,21 +0,0 @@
1# -*- makefile -*-
2
3unruly : [X] GTK COMMON unruly unruly-icon|no-icon
4unruly : [G] WINDOWS COMMON unruly unruly.res|noicon.res
5
6unrulysolver : [U] unruly[STANDALONE_SOLVER] STANDALONE
7unrulysolver : [C] unruly[STANDALONE_SOLVER] STANDALONE
8
9ALL += unruly[COMBINED]
10
11!begin am gtk
12GAMES += unruly
13!end
14
15!begin >list.c
16 A(unruly) \
17!end
18
19!begin >gamedesc.txt
20unruly:unruly.exe:Unruly:Black and white grid puzzle:Fill in the black and white grid to avoid runs of three.
21!end
diff --git a/apps/plugins/puzzles/src/unruly.c b/apps/plugins/puzzles/src/unruly.c
index a1f06332e0..01685b7838 100644
--- a/apps/plugins/puzzles/src/unruly.c
+++ b/apps/plugins/puzzles/src/unruly.c
@@ -47,12 +47,16 @@
47#include <string.h> 47#include <string.h>
48#include <assert.h> 48#include <assert.h>
49#include <ctype.h> 49#include <ctype.h>
50#include <math.h> 50#ifdef NO_TGMATH_H
51# include <math.h>
52#else
53# include <tgmath.h>
54#endif
51 55
52#include "puzzles.h" 56#include "puzzles.h"
53 57
54#ifdef STANDALONE_SOLVER 58#ifdef STANDALONE_SOLVER
55bool solver_verbose = false; 59static bool solver_verbose = false;
56#endif 60#endif
57 61
58enum { 62enum {
@@ -81,6 +85,7 @@ struct game_params {
81 int diff; 85 int diff;
82}; 86};
83#define DIFFLIST(A) \ 87#define DIFFLIST(A) \
88 A(TRIVIAL,Trivial, t) \
84 A(EASY,Easy, e) \ 89 A(EASY,Easy, e) \
85 A(NORMAL,Normal, n) \ 90 A(NORMAL,Normal, n) \
86 91
@@ -95,6 +100,7 @@ static char const unruly_diffchars[] = DIFFLIST(ENCODE);
95#define DIFFCONFIG DIFFLIST(CONFIG) 100#define DIFFCONFIG DIFFLIST(CONFIG)
96 101
97static const struct game_params unruly_presets[] = { 102static const struct game_params unruly_presets[] = {
103 { 8, 8, false, DIFF_TRIVIAL},
98 { 8, 8, false, DIFF_EASY}, 104 { 8, 8, false, DIFF_EASY},
99 { 8, 8, false, DIFF_NORMAL}, 105 { 8, 8, false, DIFF_NORMAL},
100 {10, 10, false, DIFF_EASY}, 106 {10, 10, false, DIFF_EASY},
@@ -284,6 +290,8 @@ static const char *validate_params(const game_params *params, bool full)
284 return "Width and height must both be even"; 290 return "Width and height must both be even";
285 if (params->w2 < 6 || params->h2 < 6) 291 if (params->w2 < 6 || params->h2 < 6)
286 return "Width and height must be at least 6"; 292 return "Width and height must be at least 6";
293 if (params->w2 > INT_MAX / params->h2)
294 return "Width times height must not be unreasonably large";
287 if (params->unique) { 295 if (params->unique) {
288 static const long A177790[] = { 296 static const long A177790[] = {
289 /* 297 /*
@@ -349,7 +357,7 @@ static const char *validate_desc(const game_params *params, const char *desc)
349 return NULL; 357 return NULL;
350} 358}
351 359
352static game_state *blank_state(int w2, int h2, bool unique) 360static game_state *blank_state(int w2, int h2, bool unique, bool new_common)
353{ 361{
354 game_state *state = snew(game_state); 362 game_state *state = snew(game_state);
355 int s = w2 * h2; 363 int s = w2 * h2;
@@ -358,12 +366,14 @@ static game_state *blank_state(int w2, int h2, bool unique)
358 state->h2 = h2; 366 state->h2 = h2;
359 state->unique = unique; 367 state->unique = unique;
360 state->grid = snewn(s, char); 368 state->grid = snewn(s, char);
361 state->common = snew(unruly_common);
362 state->common->refcount = 1;
363 state->common->immutable = snewn(s, bool);
364
365 memset(state->grid, EMPTY, s); 369 memset(state->grid, EMPTY, s);
366 memset(state->common->immutable, 0, s*sizeof(bool)); 370
371 if (new_common) {
372 state->common = snew(unruly_common);
373 state->common->refcount = 1;
374 state->common->immutable = snewn(s, bool);
375 memset(state->common->immutable, 0, s*sizeof(bool));
376 }
367 377
368 state->completed = state->cheated = false; 378 state->completed = state->cheated = false;
369 379
@@ -376,7 +386,7 @@ static game_state *new_game(midend *me, const game_params *params,
376 int w2 = params->w2, h2 = params->h2; 386 int w2 = params->w2, h2 = params->h2;
377 int s = w2 * h2; 387 int s = w2 * h2;
378 388
379 game_state *state = blank_state(w2, h2, params->unique); 389 game_state *state = blank_state(w2, h2, params->unique, true);
380 390
381 const char *p = desc; 391 const char *p = desc;
382 int pos = 0; 392 int pos = 0;
@@ -413,7 +423,7 @@ static game_state *dup_game(const game_state *state)
413 int w2 = state->w2, h2 = state->h2; 423 int w2 = state->w2, h2 = state->h2;
414 int s = w2 * h2; 424 int s = w2 * h2;
415 425
416 game_state *ret = blank_state(w2, h2, state->unique); 426 game_state *ret = blank_state(w2, h2, state->unique, false);
417 427
418 memcpy(ret->grid, state->grid, s); 428 memcpy(ret->grid, state->grid, s);
419 ret->common = state->common; 429 ret->common = state->common;
@@ -743,6 +753,61 @@ static int unruly_solver_fill_row(game_state *state, int i, bool horizontal,
743 return ret; 753 return ret;
744} 754}
745 755
756static int unruly_solver_check_single_gap(game_state *state,
757 int *complete, bool horizontal,
758 int *rowcount, int *colcount,
759 char fill)
760{
761 int w2 = state->w2, h2 = state->h2;
762 int count = (horizontal ? h2 : w2); /* number of rows to check */
763 int target = (horizontal ? w2 : h2) / 2; /* target number of 0s/1s */
764 int *other = (horizontal ? rowcount : colcount);
765
766 int ret = 0;
767
768 int i;
769 /* Check for completed rows/cols for one number, then fill in the rest */
770 for (i = 0; i < count; i++) {
771 if (complete[i] == target && other[i] == target - 1) {
772#ifdef STANDALONE_SOLVER
773 if (solver_verbose) {
774 printf("Solver: Row %i has only one square left which must be "
775 "%c\n", i, (fill == N_ZERO ? '0' : '1'));
776 }
777#endif
778 ret += unruly_solver_fill_row(state, i, horizontal, rowcount,
779 colcount, fill);
780 }
781 }
782
783 return ret;
784}
785
786static int unruly_solver_check_all_single_gap(game_state *state,
787 struct unruly_scratch *scratch)
788{
789 int ret = 0;
790
791 ret +=
792 unruly_solver_check_single_gap(state, scratch->ones_rows, true,
793 scratch->zeros_rows,
794 scratch->zeros_cols, N_ZERO);
795 ret +=
796 unruly_solver_check_single_gap(state, scratch->ones_cols, false,
797 scratch->zeros_rows,
798 scratch->zeros_cols, N_ZERO);
799 ret +=
800 unruly_solver_check_single_gap(state, scratch->zeros_rows, true,
801 scratch->ones_rows,
802 scratch->ones_cols, N_ONE);
803 ret +=
804 unruly_solver_check_single_gap(state, scratch->zeros_cols, false,
805 scratch->ones_rows,
806 scratch->ones_cols, N_ONE);
807
808 return ret;
809}
810
746static int unruly_solver_check_complete_nums(game_state *state, 811static int unruly_solver_check_complete_nums(game_state *state,
747 int *complete, bool horizontal, 812 int *complete, bool horizontal,
748 int *rowcount, int *colcount, 813 int *rowcount, int *colcount,
@@ -1140,11 +1205,24 @@ static int unruly_solve_game(game_state *state,
1140 1205
1141 /* Keep using the simpler techniques while they produce results */ 1206 /* Keep using the simpler techniques while they produce results */
1142 if (done) { 1207 if (done) {
1143 if (maxdiff < DIFF_EASY) 1208 if (maxdiff < DIFF_TRIVIAL)
1144 maxdiff = DIFF_EASY; 1209 maxdiff = DIFF_TRIVIAL;
1145 continue; 1210 continue;
1146 } 1211 }
1147 1212
1213 /* Check for rows with only one unfilled square */
1214 done += unruly_solver_check_all_single_gap(state, scratch);
1215
1216 if (done) {
1217 if (maxdiff < DIFF_TRIVIAL)
1218 maxdiff = DIFF_TRIVIAL;
1219 continue;
1220 }
1221
1222 /* Easy techniques */
1223 if (diff < DIFF_EASY)
1224 break;
1225
1148 /* Check for completed rows */ 1226 /* Check for completed rows */
1149 done += unruly_solver_check_all_complete_nums(state, scratch); 1227 done += unruly_solver_check_all_complete_nums(state, scratch);
1150 1228
@@ -1302,7 +1380,7 @@ static char *new_game_desc(const game_params *params, random_state *rs,
1302 1380
1303 while (true) { 1381 while (true) {
1304 attempts++; 1382 attempts++;
1305 state = blank_state(w2, h2, params->unique); 1383 state = blank_state(w2, h2, params->unique, true);
1306 scratch = unruly_new_scratch(state); 1384 scratch = unruly_new_scratch(state);
1307 if (unruly_fill_game(state, scratch, rs)) 1385 if (unruly_fill_game(state, scratch, rs))
1308 break; 1386 break;
@@ -1320,6 +1398,8 @@ static char *new_game_desc(const game_params *params, random_state *rs,
1320 temp_verbose = solver_verbose; 1398 temp_verbose = solver_verbose;
1321 solver_verbose = false; 1399 solver_verbose = false;
1322 } 1400 }
1401#else
1402 (void)attempts;
1323#endif 1403#endif
1324 1404
1325 unruly_free_scratch(scratch); 1405 unruly_free_scratch(scratch);
@@ -1439,7 +1519,7 @@ static game_ui *new_ui(const game_state *state)
1439 game_ui *ret = snew(game_ui); 1519 game_ui *ret = snew(game_ui);
1440 1520
1441 ret->cx = ret->cy = 0; 1521 ret->cx = ret->cy = 0;
1442 ret->cursor = false; 1522 ret->cursor = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1443 1523
1444 return ret; 1524 return ret;
1445} 1525}
@@ -1449,18 +1529,30 @@ static void free_ui(game_ui *ui)
1449 sfree(ui); 1529 sfree(ui);
1450} 1530}
1451 1531
1452static char *encode_ui(const game_ui *ui) 1532static void game_changed_state(game_ui *ui, const game_state *oldstate,
1453{ 1533 const game_state *newstate)
1454 return NULL;
1455}
1456
1457static void decode_ui(game_ui *ui, const char *encoding)
1458{ 1534{
1459} 1535}
1460 1536
1461static void game_changed_state(game_ui *ui, const game_state *oldstate, 1537static const char *current_key_label(const game_ui *ui,
1462 const game_state *newstate) 1538 const game_state *state, int button)
1463{ 1539{
1540 int hx = ui->cx, hy = ui->cy;
1541 int w2 = state->w2;
1542 char i = state->grid[hy * w2 + hx];
1543
1544 if (ui->cursor && IS_CURSOR_SELECT(button)) {
1545 if (state->common->immutable[hy * w2 + hx]) return "";
1546 switch (i) {
1547 case EMPTY:
1548 return button == CURSOR_SELECT ? "Black" : "White";
1549 case N_ONE:
1550 return button == CURSOR_SELECT ? "White" : "Empty";
1551 case N_ZERO:
1552 return button == CURSOR_SELECT ? "Empty" : "Black";
1553 }
1554 }
1555 return "";
1464} 1556}
1465 1557
1466struct game_drawstate { 1558struct game_drawstate {
@@ -1520,7 +1612,9 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1520 1612
1521 int w2 = state->w2, h2 = state->h2; 1613 int w2 = state->w2, h2 = state->h2;
1522 1614
1523 button &= ~MOD_MASK; 1615 char *nullret = MOVE_NO_EFFECT;
1616
1617 button = STRIP_BUTTON_MODIFIERS(button);
1524 1618
1525 /* Mouse click */ 1619 /* Mouse click */
1526 if (button == LEFT_BUTTON || button == RIGHT_BUTTON || 1620 if (button == LEFT_BUTTON || button == RIGHT_BUTTON ||
@@ -1529,17 +1623,18 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1529 && oy >= (ds->tilesize / 2) && gy < h2) { 1623 && oy >= (ds->tilesize / 2) && gy < h2) {
1530 hx = gx; 1624 hx = gx;
1531 hy = gy; 1625 hy = gy;
1532 ui->cursor = false; 1626 if (ui->cursor) {
1627 ui->cursor = false;
1628 nullret = MOVE_UI_UPDATE;
1629 }
1533 } else 1630 } else
1534 return NULL; 1631 return MOVE_UNUSED;
1535 } 1632 }
1536 1633
1537 /* Keyboard move */ 1634 /* Keyboard move */
1538 if (IS_CURSOR_MOVE(button)) { 1635 if (IS_CURSOR_MOVE(button))
1539 move_cursor(button, &ui->cx, &ui->cy, w2, h2, false); 1636 return move_cursor(button, &ui->cx, &ui->cy, w2, h2, false,
1540 ui->cursor = true; 1637 &ui->cursor);
1541 return UI_UPDATE;
1542 }
1543 1638
1544 /* Place one */ 1639 /* Place one */
1545 if ((ui->cursor && (button == CURSOR_SELECT || button == CURSOR_SELECT2 1640 if ((ui->cursor && (button == CURSOR_SELECT || button == CURSOR_SELECT2
@@ -1551,7 +1646,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1551 char c, i; 1646 char c, i;
1552 1647
1553 if (state->common->immutable[hy * w2 + hx]) 1648 if (state->common->immutable[hy * w2 + hx])
1554 return NULL; 1649 return nullret;
1555 1650
1556 c = '-'; 1651 c = '-';
1557 i = state->grid[hy * w2 + hx]; 1652 i = state->grid[hy * w2 + hx];
@@ -1571,13 +1666,13 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1571 1666
1572 if (state->grid[hy * w2 + hx] == 1667 if (state->grid[hy * w2 + hx] ==
1573 (c == '0' ? N_ZERO : c == '1' ? N_ONE : EMPTY)) 1668 (c == '0' ? N_ZERO : c == '1' ? N_ONE : EMPTY))
1574 return NULL; /* don't put no-ops on the undo chain */ 1669 return nullret; /* don't put no-ops on the undo chain */
1575 1670
1576 sprintf(buf, "P%c,%d,%d", c, hx, hy); 1671 sprintf(buf, "P%c,%d,%d", c, hx, hy);
1577 1672
1578 return dupstr(buf); 1673 return dupstr(buf);
1579 } 1674 }
1580 return NULL; 1675 return MOVE_UNUSED;
1581} 1676}
1582 1677
1583static game_state *execute_move(const game_state *state, const char *move) 1678static game_state *execute_move(const game_state *state, const char *move)
@@ -1637,7 +1732,7 @@ static game_state *execute_move(const game_state *state, const char *move)
1637 */ 1732 */
1638 1733
1639static void game_compute_size(const game_params *params, int tilesize, 1734static void game_compute_size(const game_params *params, int tilesize,
1640 int *x, int *y) 1735 const game_ui *ui, int *x, int *y)
1641{ 1736{
1642 *x = tilesize * (params->w2 + 1); 1737 *x = tilesize * (params->w2 + 1);
1643 *y = tilesize * (params->h2 + 1); 1738 *y = tilesize * (params->h2 + 1);
@@ -1788,9 +1883,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1788 int x, y, i; 1883 int x, y, i;
1789 1884
1790 if (!ds->started) { 1885 if (!ds->started) {
1791 /* Main window background */
1792 draw_rect(dr, 0, 0, TILE_SIZE * (w2+1), TILE_SIZE * (h2+1),
1793 COL_BACKGROUND);
1794 /* Outer edge of grid */ 1886 /* Outer edge of grid */
1795 draw_rect(dr, COORD(0)-TILE_SIZE/10, COORD(0)-TILE_SIZE/10, 1887 draw_rect(dr, COORD(0)-TILE_SIZE/10, COORD(0)-TILE_SIZE/10,
1796 TILE_SIZE*w2 + 2*(TILE_SIZE/10) - 1, 1888 TILE_SIZE*w2 + 2*(TILE_SIZE/10) - 1,
@@ -1878,22 +1970,19 @@ static int game_status(const game_state *state)
1878 return state->completed ? +1 : 0; 1970 return state->completed ? +1 : 0;
1879} 1971}
1880 1972
1881static bool game_timing_state(const game_state *state, game_ui *ui) 1973static void game_print_size(const game_params *params, const game_ui *ui,
1882{ 1974 float *x, float *y)
1883 return true;
1884}
1885
1886static void game_print_size(const game_params *params, float *x, float *y)
1887{ 1975{
1888 int pw, ph; 1976 int pw, ph;
1889 1977
1890 /* Using 7mm squares */ 1978 /* Using 7mm squares */
1891 game_compute_size(params, 700, &pw, &ph); 1979 game_compute_size(params, 700, ui, &pw, &ph);
1892 *x = pw / 100.0F; 1980 *x = pw / 100.0F;
1893 *y = ph / 100.0F; 1981 *y = ph / 100.0F;
1894} 1982}
1895 1983
1896static void game_print(drawing *dr, const game_state *state, int tilesize) 1984static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
1985 int tilesize)
1897{ 1986{
1898 int w2 = state->w2, h2 = state->h2; 1987 int w2 = state->w2, h2 = state->h2;
1899 int x, y; 1988 int x, y;
@@ -1946,12 +2035,14 @@ const struct game thegame = {
1946 free_game, 2035 free_game,
1947 true, solve_game, 2036 true, solve_game,
1948 true, game_can_format_as_text_now, game_text_format, 2037 true, game_can_format_as_text_now, game_text_format,
2038 NULL, NULL, /* get_prefs, set_prefs */
1949 new_ui, 2039 new_ui,
1950 free_ui, 2040 free_ui,
1951 encode_ui, 2041 NULL, /* encode_ui */
1952 decode_ui, 2042 NULL, /* decode_ui */
1953 NULL, /* game_request_keys */ 2043 NULL, /* game_request_keys */
1954 game_changed_state, 2044 game_changed_state,
2045 current_key_label,
1955 interpret_move, 2046 interpret_move,
1956 execute_move, 2047 execute_move,
1957 DEFAULT_TILE_SIZE, game_compute_size, game_set_size, 2048 DEFAULT_TILE_SIZE, game_compute_size, game_set_size,
@@ -1965,7 +2056,7 @@ const struct game thegame = {
1965 game_status, 2056 game_status,
1966 true, false, game_print_size, game_print, 2057 true, false, game_print_size, game_print,
1967 false, /* wants_statusbar */ 2058 false, /* wants_statusbar */
1968 false, game_timing_state, 2059 false, NULL, /* timing_state */
1969 0, /* flags */ 2060 0, /* flags */
1970}; 2061};
1971 2062
@@ -1979,7 +2070,7 @@ const struct game thegame = {
1979 2070
1980/* Most of the standalone solver code was copied from unequal.c and singles.c */ 2071/* Most of the standalone solver code was copied from unequal.c and singles.c */
1981 2072
1982const char *quis; 2073static const char *quis;
1983 2074
1984static void usage_exit(const char *msg) 2075static void usage_exit(const char *msg)
1985{ 2076{
diff --git a/apps/plugins/puzzles/src/untangle.R b/apps/plugins/puzzles/src/untangle.R
deleted file mode 100644
index a57f1e56fd..0000000000
--- a/apps/plugins/puzzles/src/untangle.R
+++ /dev/null
@@ -1,21 +0,0 @@
1# -*- makefile -*-
2
3UNTANGLE_EXTRA = tree234
4
5untangle : [X] GTK COMMON untangle UNTANGLE_EXTRA untangle-icon|no-icon
6
7untangle : [G] WINDOWS COMMON untangle UNTANGLE_EXTRA untangle.res|noicon.res
8
9ALL += untangle[COMBINED] UNTANGLE_EXTRA
10
11!begin am gtk
12GAMES += untangle
13!end
14
15!begin >list.c
16 A(untangle) \
17!end
18
19!begin >gamedesc.txt
20untangle:untangle.exe:Untangle:Planar graph layout puzzle:Reposition the points so that the lines do not cross.
21!end
diff --git a/apps/plugins/puzzles/src/untangle.c b/apps/plugins/puzzles/src/untangle.c
index 0d3e0e6135..f0647c83e9 100644
--- a/apps/plugins/puzzles/src/untangle.c
+++ b/apps/plugins/puzzles/src/untangle.c
@@ -20,10 +20,6 @@
20 * requirements are adequately expressed by a single scalar tile 20 * requirements are adequately expressed by a single scalar tile
21 * size), and probably complicate the rest of the puzzles' API as a 21 * size), and probably complicate the rest of the puzzles' API as a
22 * result. So I'm not sure I really want to do it. 22 * result. So I'm not sure I really want to do it.
23 *
24 * - It would be nice if we could somehow auto-detect a real `long
25 * long' type on the host platform and use it in place of my
26 * hand-hacked int64s. It'd be faster and more reliable.
27 */ 23 */
28 24
29#include <stdio.h> 25#include <stdio.h>
@@ -31,7 +27,15 @@
31#include <string.h> 27#include <string.h>
32#include <assert.h> 28#include <assert.h>
33#include <ctype.h> 29#include <ctype.h>
34#include <math.h> 30#include <limits.h>
31#ifdef NO_TGMATH_H
32# include <math.h>
33#else
34# include <tgmath.h>
35#endif
36#if HAVE_STDINT_H
37# include <stdint.h>
38#endif
35 39
36#include "puzzles.h" 40#include "puzzles.h"
37#include "tree234.h" 41#include "tree234.h"
@@ -39,7 +43,6 @@
39#define CIRCLE_RADIUS 6 43#define CIRCLE_RADIUS 6
40#define DRAG_THRESHOLD (CIRCLE_RADIUS * 2) 44#define DRAG_THRESHOLD (CIRCLE_RADIUS * 2)
41#define PREFERRED_TILESIZE 64 45#define PREFERRED_TILESIZE 64
42#define CURSOR_GRANULARITY 5
43 46
44#define FLASH_TIME 0.30F 47#define FLASH_TIME 0.30F
45#define ANIM_TIME 0.13F 48#define ANIM_TIME 0.13F
@@ -49,9 +52,7 @@ enum {
49 COL_SYSBACKGROUND, 52 COL_SYSBACKGROUND,
50 COL_BACKGROUND, 53 COL_BACKGROUND,
51 COL_LINE, 54 COL_LINE,
52#ifdef SHOW_CROSSINGS
53 COL_CROSSEDLINE, 55 COL_CROSSEDLINE,
54#endif
55 COL_OUTLINE, 56 COL_OUTLINE,
56 COL_POINT, 57 COL_POINT,
57 COL_DRAGPOINT, 58 COL_DRAGPOINT,
@@ -93,9 +94,7 @@ struct game_state {
93 game_params params; 94 game_params params;
94 int w, h; /* extent of coordinate system only */ 95 int w, h; /* extent of coordinate system only */
95 point *pts; 96 point *pts;
96#ifdef SHOW_CROSSINGS
97 int *crosses; /* mark edges which are crossed */ 97 int *crosses; /* mark edges which are crossed */
98#endif
99 struct graph *graph; 98 struct graph *graph;
100 bool completed, cheated, just_solved; 99 bool completed, cheated, just_solved;
101}; 100};
@@ -208,6 +207,8 @@ static const char *validate_params(const game_params *params, bool full)
208{ 207{
209 if (params->n < 4) 208 if (params->n < 4)
210 return "Number of points must be at least four"; 209 return "Number of points must be at least four";
210 if (params->n > INT_MAX / 3)
211 return "Number of points must not be unreasonably large";
211 return NULL; 212 return NULL;
212} 213}
213 214
@@ -216,6 +217,9 @@ static const char *validate_params(const game_params *params, bool full)
216 * integer overflow at the very core of cross(). 217 * integer overflow at the very core of cross().
217 */ 218 */
218 219
220#if !HAVE_STDINT_H
221/* For prehistoric C implementations, do this the hard way */
222
219typedef struct { 223typedef struct {
220 long hi; 224 long hi;
221 unsigned long lo; 225 unsigned long lo;
@@ -295,6 +299,21 @@ static int64 dotprod64(long a, long b, long p, long q)
295 return ab; 299 return ab;
296} 300}
297 301
302#else /* HAVE_STDINT_H */
303
304typedef int64_t int64;
305#define greater64(i,j) ((i) > (j))
306#define sign64(i) ((i) < 0 ? -1 : (i)==0 ? 0 : +1)
307#define mulu32to64(x,y) ((int64_t)(unsigned long)(x) * (unsigned long)(y))
308#define mul32to64(x,y) ((int64_t)(long)(x) * (long)(y))
309
310static int64 dotprod64(long a, long b, long p, long q)
311{
312 return (int64)a * b + (int64)p * q;
313}
314
315#endif /* HAVE_STDINT_H */
316
298/* 317/*
299 * Determine whether the line segments between a1 and a2, and 318 * Determine whether the line segments between a1 and a2, and
300 * between b1 and b2, intersect. We count it as an intersection if 319 * between b1 and b2, intersect. We count it as an intersection if
@@ -419,7 +438,9 @@ static void addedge(tree234 *edges, int a, int b)
419 e->a = min(a, b); 438 e->a = min(a, b);
420 e->b = max(a, b); 439 e->b = max(a, b);
421 440
422 add234(edges, e); 441 if (add234(edges, e) != e)
442 /* Duplicate edge. */
443 sfree(e);
423} 444}
424 445
425static bool isedge(tree234 *edges, int a, int b) 446static bool isedge(tree234 *edges, int a, int b)
@@ -441,8 +462,8 @@ typedef struct vertex {
441 462
442static int vertcmpC(const void *av, const void *bv) 463static int vertcmpC(const void *av, const void *bv)
443{ 464{
444 const vertex *a = (vertex *)av; 465 const vertex *a = (const vertex *)av;
445 const vertex *b = (vertex *)bv; 466 const vertex *b = (const vertex *)bv;
446 467
447 if (a->param < b->param) 468 if (a->param < b->param)
448 return -1; 469 return -1;
@@ -754,6 +775,8 @@ static const char *validate_desc(const game_params *params, const char *desc)
754 return "Expected ',' after number in game description"; 775 return "Expected ',' after number in game description";
755 desc++; /* eat comma */ 776 desc++; /* eat comma */
756 } 777 }
778 if (a == b)
779 return "Node linked to itself in game description";
757 } 780 }
758 781
759 return NULL; 782 return NULL;
@@ -765,10 +788,8 @@ static void mark_crossings(game_state *state)
765 int i, j; 788 int i, j;
766 edge *e, *e2; 789 edge *e, *e2;
767 790
768#ifdef SHOW_CROSSINGS
769 for (i = 0; (e = index234(state->graph->edges, i)) != NULL; i++) 791 for (i = 0; (e = index234(state->graph->edges, i)) != NULL; i++)
770 state->crosses[i] = false; 792 state->crosses[i] = false;
771#endif
772 793
773 /* 794 /*
774 * Check correctness: for every pair of edges, see whether they 795 * Check correctness: for every pair of edges, see whether they
@@ -782,11 +803,7 @@ static void mark_crossings(game_state *state)
782 if (cross(state->pts[e2->a], state->pts[e2->b], 803 if (cross(state->pts[e2->a], state->pts[e2->b],
783 state->pts[e->a], state->pts[e->b])) { 804 state->pts[e->a], state->pts[e->b])) {
784 ok = false; 805 ok = false;
785#ifdef SHOW_CROSSINGS
786 state->crosses[i] = state->crosses[j] = true; 806 state->crosses[i] = state->crosses[j] = true;
787#else
788 goto done; /* multi-level break - sorry */
789#endif
790 } 807 }
791 } 808 }
792 } 809 }
@@ -795,9 +812,6 @@ static void mark_crossings(game_state *state)
795 * e == NULL if we've gone through all the edge pairs 812 * e == NULL if we've gone through all the edge pairs
796 * without finding a crossing. 813 * without finding a crossing.
797 */ 814 */
798#ifndef SHOW_CROSSINGS
799 done:
800#endif
801 if (ok) 815 if (ok)
802 state->completed = true; 816 state->completed = true;
803} 817}
@@ -834,10 +848,8 @@ static game_state *new_game(midend *me, const game_params *params,
834 addedge(state->graph->edges, a, b); 848 addedge(state->graph->edges, a, b);
835 } 849 }
836 850
837#ifdef SHOW_CROSSINGS
838 state->crosses = snewn(count234(state->graph->edges), int); 851 state->crosses = snewn(count234(state->graph->edges), int);
839 mark_crossings(state); /* sets up `crosses' and `completed' */ 852 mark_crossings(state); /* sets up `crosses' and `completed' */
840#endif
841 853
842 return state; 854 return state;
843} 855}
@@ -857,11 +869,9 @@ static game_state *dup_game(const game_state *state)
857 ret->completed = state->completed; 869 ret->completed = state->completed;
858 ret->cheated = state->cheated; 870 ret->cheated = state->cheated;
859 ret->just_solved = state->just_solved; 871 ret->just_solved = state->just_solved;
860#ifdef SHOW_CROSSINGS
861 ret->crosses = snewn(count234(ret->graph->edges), int); 872 ret->crosses = snewn(count234(ret->graph->edges), int);
862 memcpy(ret->crosses, state->crosses, 873 memcpy(ret->crosses, state->crosses,
863 count234(ret->graph->edges) * sizeof(int)); 874 count234(ret->graph->edges) * sizeof(int));
864#endif
865 875
866 return ret; 876 return ret;
867} 877}
@@ -1025,19 +1035,10 @@ static char *solve_game(const game_state *state, const game_state *currstate,
1025 return ret; 1035 return ret;
1026} 1036}
1027 1037
1028static bool game_can_format_as_text_now(const game_params *params)
1029{
1030 return true;
1031}
1032
1033static char *game_text_format(const game_state *state)
1034{
1035 return NULL;
1036}
1037
1038struct game_ui { 1038struct game_ui {
1039 /* Invariant: at most one of {dragpoint, cursorpoint} may be valid
1040 * at any time. */
1039 int dragpoint; /* point being dragged; -1 if none */ 1041 int dragpoint; /* point being dragged; -1 if none */
1040
1041 int cursorpoint; /* point being highlighted, but 1042 int cursorpoint; /* point being highlighted, but
1042 * not dragged by the cursor, 1043 * not dragged by the cursor,
1043 * again -1 if none */ 1044 * again -1 if none */
@@ -1046,6 +1047,26 @@ struct game_ui {
1046 bool just_dragged; /* reset in game_changed_state */ 1047 bool just_dragged; /* reset in game_changed_state */
1047 bool just_moved; /* _set_ in game_changed_state */ 1048 bool just_moved; /* _set_ in game_changed_state */
1048 float anim_length; 1049 float anim_length;
1050
1051 /*
1052 * User preference option to snap dragged points to a coarse-ish
1053 * grid. Requested by a user who otherwise found themself spending
1054 * too much time struggling to get lines nicely horizontal or
1055 * vertical.
1056 */
1057 bool snap_to_grid;
1058
1059 /*
1060 * User preference option to highlight graph edges involved in a
1061 * crossing.
1062 */
1063 bool show_crossed_edges;
1064
1065 /*
1066 * User preference option to show vertices as numbers instead of
1067 * circular blobs, so you can easily tell them apart.
1068 */
1069 bool vertex_numbers;
1049}; 1070};
1050 1071
1051static game_ui *new_ui(const game_state *state) 1072static game_ui *new_ui(const game_state *state)
@@ -1054,21 +1075,51 @@ static game_ui *new_ui(const game_state *state)
1054 ui->dragpoint = -1; 1075 ui->dragpoint = -1;
1055 ui->cursorpoint = -1; 1076 ui->cursorpoint = -1;
1056 ui->just_moved = ui->just_dragged = false; 1077 ui->just_moved = ui->just_dragged = false;
1078 ui->snap_to_grid = false;
1079 ui->show_crossed_edges = false;
1080 ui->vertex_numbers = false;
1057 return ui; 1081 return ui;
1058} 1082}
1059 1083
1060static void free_ui(game_ui *ui) 1084static config_item *get_prefs(game_ui *ui)
1061{ 1085{
1062 sfree(ui); 1086 config_item *cfg;
1087
1088 cfg = snewn(4, config_item);
1089
1090 cfg[0].name = "Snap points to a grid";
1091 cfg[0].kw = "snap-to-grid";
1092 cfg[0].type = C_BOOLEAN;
1093 cfg[0].u.boolean.bval = ui->snap_to_grid;
1094
1095 cfg[1].name = "Show edges that cross another edge";
1096 cfg[1].kw = "show-crossed-edges";
1097 cfg[1].type = C_BOOLEAN;
1098 cfg[1].u.boolean.bval = ui->show_crossed_edges;
1099
1100 cfg[2].name = "Display style for vertices";
1101 cfg[2].kw = "vertex-style";
1102 cfg[2].type = C_CHOICES;
1103 cfg[2].u.choices.choicenames = ":Circles:Numbers";
1104 cfg[2].u.choices.choicekws = ":circle:number";
1105 cfg[2].u.choices.selected = ui->vertex_numbers;
1106
1107 cfg[3].name = NULL;
1108 cfg[3].type = C_END;
1109
1110 return cfg;
1063} 1111}
1064 1112
1065static char *encode_ui(const game_ui *ui) 1113static void set_prefs(game_ui *ui, const config_item *cfg)
1066{ 1114{
1067 return NULL; 1115 ui->snap_to_grid = cfg[0].u.boolean.bval;
1116 ui->show_crossed_edges = cfg[1].u.boolean.bval;
1117 ui->vertex_numbers = cfg[2].u.choices.selected;
1068} 1118}
1069 1119
1070static void decode_ui(game_ui *ui, const char *encoding) 1120static void free_ui(game_ui *ui)
1071{ 1121{
1122 sfree(ui);
1072} 1123}
1073 1124
1074static void game_changed_state(game_ui *ui, const game_state *oldstate, 1125static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -1085,6 +1136,66 @@ struct game_drawstate {
1085 long *x, *y; 1136 long *x, *y;
1086}; 1137};
1087 1138
1139static void place_dragged_point(const game_state *state, game_ui *ui,
1140 const game_drawstate *ds, int x, int y)
1141{
1142 if (ui->snap_to_grid) {
1143 /*
1144 * We snap points to a grid that has n-1 vertices on each
1145 * side. This should be large enough to permit a straight-
1146 * line drawing of any n-vertex planar graph, and moreover,
1147 * any specific planar embedding of that graph.
1148 *
1149 * Source: David Eppstein's book 'Forbidden Configurations in
1150 * Discrete Geometry' mentions (section 16.3, page 182) that
1151 * the point configuration he describes as GRID(n-1,n-1) -
1152 * that is, the vertices of a square grid with n-1 vertices on
1153 * each side - is universal for n-vertex planar graphs. In
1154 * other words (from definitions earlier in the chapter), if a
1155 * graph G admits any drawing in the plane at all, then it can
1156 * be drawn with straight lines, and with all vertices being
1157 * vertices of that grid.
1158 *
1159 * That fact by itself only says that _some_ planar embedding
1160 * of G can be drawn in this grid. We'd prefer that _all_
1161 * embeddings of G can be so drawn, because 'snap to grid' is
1162 * supposed to be a UI affordance, not an extra puzzle
1163 * challenge, so we don't want to constrain the player's
1164 * choice of planar embedding.
1165 *
1166 * But it doesn't make a difference. Proof: given a specific
1167 * planar embedding of G, triangulate it, by adding extra
1168 * edges to every face of degree > 3. When this process
1169 * terminates with every face a triangle, we have a new graph
1170 * G' such that no edge can be added without it ceasing to be
1171 * planar. Standard theorems say that a maximal planar graph
1172 * is 3-connected, and that a 3-connected planar graph has a
1173 * _unique_ embedding. So any drawing of G' in the plane can
1174 * be converted into a drawing of G in the desired embedding,
1175 * by simply removing all the extra edges that we added to
1176 * turn G into G'. And G' is still an n-vertex planar graph,
1177 * hence it can be drawn in GRID(n-1,n-1). []
1178 */
1179 int d = state->params.n - 1;
1180
1181 /* Calculate position in terms of the snapping grid. */
1182 x = d * x / (state->w * ds->tilesize);
1183 y = d * y / (state->h * ds->tilesize);
1184 /* Convert to standard co-ordinates, applying a half-square offset. */
1185 ui->newpoint.x = (x * 2 + 1) * state->w;
1186 ui->newpoint.y = (y * 2 + 1) * state->h;
1187 ui->newpoint.d = d * 2;
1188 } else {
1189 ui->newpoint.x = x;
1190 ui->newpoint.y = y;
1191 ui->newpoint.d = ds->tilesize;
1192 }
1193}
1194
1195static float normsq(point pt) {
1196 return (pt.x * pt.x + pt.y * pt.y) / (pt.d * pt.d);
1197}
1198
1088static char *interpret_move(const game_state *state, game_ui *ui, 1199static char *interpret_move(const game_state *state, game_ui *ui,
1089 const game_drawstate *ds, 1200 const game_drawstate *ds,
1090 int x, int y, int button) 1201 int x, int y, int button)
@@ -1119,23 +1230,20 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1119 1230
1120 if (bestd <= DRAG_THRESHOLD * DRAG_THRESHOLD) { 1231 if (bestd <= DRAG_THRESHOLD * DRAG_THRESHOLD) {
1121 ui->dragpoint = best; 1232 ui->dragpoint = best;
1122 ui->cursorpoint = -1; 1233 ui->cursorpoint = -1; /* eliminate the cursor point, if any */
1123 ui->newpoint.x = x; 1234 place_dragged_point(state, ui, ds, x, y);
1124 ui->newpoint.y = y; 1235 return MOVE_UI_UPDATE;
1125 ui->newpoint.d = ds->tilesize;
1126 return UI_UPDATE;
1127 } 1236 }
1128 1237 return MOVE_NO_EFFECT;
1129 } else if (IS_MOUSE_DRAG(button) && ui->dragpoint >= 0) { 1238 } else if (IS_MOUSE_DRAG(button) && ui->dragpoint >= 0) {
1130 ui->newpoint.x = x; 1239 place_dragged_point(state, ui, ds, x, y);
1131 ui->newpoint.y = y; 1240 return MOVE_UI_UPDATE;
1132 ui->newpoint.d = ds->tilesize;
1133 return UI_UPDATE;
1134 } else if (IS_MOUSE_RELEASE(button) && ui->dragpoint >= 0) { 1241 } else if (IS_MOUSE_RELEASE(button) && ui->dragpoint >= 0) {
1135 int p = ui->dragpoint; 1242 int p = ui->dragpoint;
1136 char buf[80]; 1243 char buf[80];
1137 1244
1138 ui->dragpoint = -1; /* terminate drag, no matter what */ 1245 ui->dragpoint = -1; /* terminate drag, no matter what */
1246 ui->cursorpoint = -1; /* also eliminate the cursor point */
1139 1247
1140 /* 1248 /*
1141 * First, see if we're within range. The user can cancel a 1249 * First, see if we're within range. The user can cancel a
@@ -1145,7 +1253,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1145 ui->newpoint.x >= (long)state->w*ui->newpoint.d || 1253 ui->newpoint.x >= (long)state->w*ui->newpoint.d ||
1146 ui->newpoint.y < 0 || 1254 ui->newpoint.y < 0 ||
1147 ui->newpoint.y >= (long)state->h*ui->newpoint.d) 1255 ui->newpoint.y >= (long)state->h*ui->newpoint.d)
1148 return UI_UPDATE; 1256 return MOVE_UI_UPDATE;
1149 1257
1150 /* 1258 /*
1151 * We aren't cancelling the drag. Construct a move string 1259 * We aren't cancelling the drag. Construct a move string
@@ -1155,109 +1263,140 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1155 ui->newpoint.x, ui->newpoint.y, ui->newpoint.d); 1263 ui->newpoint.x, ui->newpoint.y, ui->newpoint.d);
1156 ui->just_dragged = true; 1264 ui->just_dragged = true;
1157 return dupstr(buf); 1265 return dupstr(buf);
1266 } else if (IS_MOUSE_DRAG(button) || IS_MOUSE_RELEASE(button)) {
1267 return MOVE_NO_EFFECT;
1158 } 1268 }
1159 else if(IS_CURSOR_MOVE(button)) 1269 else if(IS_CURSOR_MOVE(button)) {
1160 { 1270 if(ui->dragpoint < 0) {
1161 if(ui->dragpoint < 0) 1271 /*
1162 { 1272 * We're selecting a point with the cursor keys.
1163 /* We're selecting a point here. */ 1273 *
1164 /* Search all the points and find the closest one (2-D) in 1274 * If no point is currently highlighted, we assume the "0"
1165 * the given direction. */ 1275 * point is highlighted to begin. Then, we search all the
1166 int i, best; 1276 * points and find the nearest one (by Euclidean distance)
1167 long bestd; 1277 * in the quadrant corresponding to the cursor key
1168 1278 * direction. A point is in the right quadrant if and only
1169 if(ui->cursorpoint < 0) 1279 * if the azimuth angle to that point from the cursor
1170 { 1280 * point is within a [-45 deg, +45 deg] interval from the
1281 * direction vector of the cursor key.
1282 *
1283 * An important corner case here is if another point is in
1284 * the exact same location as the currently highlighted
1285 * point (which is a possibility with the "snap to grid"
1286 * preference). In this case, we do not consider the other
1287 * point as a candidate point, so as to prevent the cursor
1288 * from being "stuck" on any point. The player can still
1289 * select the overlapped point by dragging the highlighted
1290 * point away and then navigating back.
1291 */
1292 int i, best = -1;
1293 float bestd = 0;
1294
1295 if(ui->cursorpoint < 0) {
1171 ui->cursorpoint = 0; 1296 ui->cursorpoint = 0;
1172 } 1297 }
1173 1298
1174 /* 1299 point cur = state->pts[ui->cursorpoint];
1175 * Begin drag. We drag the vertex _nearest_ to the pointer,
1176 * just in case one is nearly on top of another and we want
1177 * to drag the latter. However, we drag nothing at all if
1178 * the nearest vertex is outside DRAG_THRESHOLD.
1179 */
1180 best = -1;
1181 bestd = 0;
1182 1300
1183 for (i = 0; i < n; i++) { 1301 for (i = 0; i < n; i++) {
1184 long px, py, dx, dy, d; 1302 point delta;
1185 float angle; 1303 float distsq;
1186 int right_direction; 1304 point p = state->pts[i];
1305 int right_direction = false;
1306
1187 if(i == ui->cursorpoint) 1307 if(i == ui->cursorpoint)
1188 continue; 1308 continue;
1189 1309
1190 px = state->pts[i].x * ds->tilesize / state->pts[i].d; 1310 /* Compute the vector p - cur. Check that it lies in
1191 py = state->pts[i].y * ds->tilesize / state->pts[i].d; 1311 * the correct quadrant. */
1192 dx = px - state->pts[ui->cursorpoint].x * ds->tilesize / state->pts[ui->cursorpoint].d; 1312 delta.x = p.x * cur.d - cur.x * p.d;
1193 dy = py - state->pts[ui->cursorpoint].y * ds->tilesize / state->pts[ui->cursorpoint].d; 1313 delta.y = p.y * cur.d - cur.y * p.d;
1194 d = dx*dx + dy*dy; 1314 delta.d = cur.d * p.d;
1195 1315
1196 /* Figure out if this point falls into a 90 degree 1316 if(delta.x == 0 && delta.y == 0)
1197 * range extending from the current point */ 1317 continue; /* overlaps cursor point - skip */
1198 1318
1199 angle = atan2(-dy, dx); /* negate y to adjust for raster coordinates */ 1319 switch(button) {
1200 1320 case CURSOR_UP:
1201 /* offset to [0..2*PI] */ 1321 right_direction = (delta.y <= -delta.x) && (delta.y <= delta.x);
1202 if(angle < 0) 1322 break;
1203 angle += 2*PI; 1323 case CURSOR_DOWN:
1324 right_direction = (delta.y >= -delta.x) && (delta.y >= delta.x);
1325 break;
1326 case CURSOR_LEFT:
1327 right_direction = (delta.y >= delta.x) && (delta.y <= -delta.x);
1328 break;
1329 case CURSOR_RIGHT:
1330 right_direction = (delta.y <= delta.x) && (delta.y >= -delta.x);
1331 break;
1332 }
1204 1333
1205 right_direction = false; 1334 if(!right_direction)
1335 continue;
1206 1336
1207 if((button == CURSOR_UP && (1*PI/4 <= angle && angle <= 3*PI/4)) || 1337 /* Compute squared Euclidean distance */
1208 (button == CURSOR_LEFT && (3*PI/4 <= angle && angle <= 5*PI/4)) || 1338 distsq = normsq(delta);
1209 (button == CURSOR_DOWN && (5*PI/4 <= angle && angle <= 7*PI/4)) ||
1210 (button == CURSOR_RIGHT && (angle >= 7*PI/4 || angle <= 1*PI/4)))
1211 right_direction = true;
1212 1339
1213 if ((best == -1 || bestd > d) && right_direction) { 1340 if (best == -1 || distsq < bestd) {
1214 best = i; 1341 best = i;
1215 bestd = d; 1342 bestd = distsq;
1216 } 1343 }
1217 } 1344 }
1218 1345
1219 if(best >= 0) 1346 if(best >= 0) {
1220 {
1221 ui->cursorpoint = best; 1347 ui->cursorpoint = best;
1222 return UI_UPDATE; 1348 return MOVE_UI_UPDATE;
1223 } 1349 }
1224 } 1350 }
1225 else if(ui->dragpoint >= 0) 1351 else if(ui->dragpoint >= 0) {
1226 { 1352 /* Dragging a point with the cursor keys. */
1227 /* dragging */ 1353 int movement_increment = ds->tilesize / 2;
1228 switch(button) 1354 int dx = 0, dy = 0;
1229 { 1355
1356 switch(button) {
1230 case CURSOR_UP: 1357 case CURSOR_UP:
1231 ui->newpoint.y -= ds->tilesize / CURSOR_GRANULARITY; 1358 dy = -movement_increment;
1232 return UI_UPDATE; 1359 break;
1233 case CURSOR_DOWN: 1360 case CURSOR_DOWN:
1234 ui->newpoint.y += ds->tilesize / CURSOR_GRANULARITY; 1361 dy = movement_increment;
1235 return UI_UPDATE; 1362 break;
1236 case CURSOR_LEFT: 1363 case CURSOR_LEFT:
1237 ui->newpoint.x -= ds->tilesize / CURSOR_GRANULARITY; 1364 dx = -movement_increment;
1238 return UI_UPDATE; 1365 break;
1239 case CURSOR_RIGHT: 1366 case CURSOR_RIGHT:
1240 ui->newpoint.x += ds->tilesize / CURSOR_GRANULARITY; 1367 dx = movement_increment;
1241 return UI_UPDATE; 1368 break;
1242 default: 1369 default:
1243 break; 1370 break;
1244 } 1371 }
1372
1373 /* This code has a slightly inconvenient interaction with
1374 * the snap to grid feature: if the point being dragged
1375 * originates on a non-grid point which is in the bottom
1376 * half or right half (or both) of a grid cell (a 75%
1377 * probability), then dragging point right (if it
1378 * originates from the right half) or down (if it
1379 * originates from the bottom half) will cause the point
1380 * to move one more grid cell than intended in that
1381 * direction. I (F. Wei) it wasn't worth handling this
1382 * corner case - if anyone feels inclined, please feel
1383 * free to do so. */
1384 place_dragged_point(state, ui, ds,
1385 ui->newpoint.x * ds->tilesize / ui->newpoint.d + dx,
1386 ui->newpoint.y * ds->tilesize / ui->newpoint.d + dy);
1387 return MOVE_UI_UPDATE;
1245 } 1388 }
1246 } 1389 } else if(button == CURSOR_SELECT) {
1247 else if(IS_CURSOR_SELECT(button)) 1390 if(ui->dragpoint < 0 && ui->cursorpoint >= 0) {
1248 {
1249 if(ui->dragpoint < 0 && ui->cursorpoint >= 0)
1250 {
1251 /* begin drag */ 1391 /* begin drag */
1252 ui->dragpoint = ui->cursorpoint; 1392 ui->dragpoint = ui->cursorpoint;
1253 ui->cursorpoint = -1; 1393 ui->cursorpoint = -1;
1254 ui->newpoint.x = state->pts[ui->dragpoint].x * ds->tilesize / state->pts[ui->dragpoint].d; 1394 ui->newpoint.x = state->pts[ui->dragpoint].x * ds->tilesize / state->pts[ui->dragpoint].d;
1255 ui->newpoint.y = state->pts[ui->dragpoint].y * ds->tilesize / state->pts[ui->dragpoint].d; 1395 ui->newpoint.y = state->pts[ui->dragpoint].y * ds->tilesize / state->pts[ui->dragpoint].d;
1256 ui->newpoint.d = ds->tilesize; 1396 ui->newpoint.d = ds->tilesize;
1257 return UI_UPDATE; 1397 return MOVE_UI_UPDATE;
1258 } 1398 }
1259 else if(ui->dragpoint >= 0) 1399 else if(ui->dragpoint >= 0) {
1260 {
1261 /* end drag */ 1400 /* end drag */
1262 int p = ui->dragpoint; 1401 int p = ui->dragpoint;
1263 char buf[80]; 1402 char buf[80];
@@ -1273,7 +1412,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1273 ui->newpoint.x >= (long)state->w*ui->newpoint.d || 1412 ui->newpoint.x >= (long)state->w*ui->newpoint.d ||
1274 ui->newpoint.y < 0 || 1413 ui->newpoint.y < 0 ||
1275 ui->newpoint.y >= (long)state->h*ui->newpoint.d) 1414 ui->newpoint.y >= (long)state->h*ui->newpoint.d)
1276 return UI_UPDATE; 1415 return MOVE_UI_UPDATE;
1277 1416
1278 /* 1417 /*
1279 * We aren't cancelling the drag. Construct a move string 1418 * We aren't cancelling the drag. Construct a move string
@@ -1284,14 +1423,29 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1284 ui->just_dragged = true; 1423 ui->just_dragged = true;
1285 return dupstr(buf); 1424 return dupstr(buf);
1286 } 1425 }
1287 else if(ui->cursorpoint < 0) 1426 else if(ui->cursorpoint < 0) {
1288 {
1289 ui->cursorpoint = 0; 1427 ui->cursorpoint = 0;
1290 return UI_UPDATE; 1428 return MOVE_UI_UPDATE;
1291 } 1429 }
1430 } else if(STRIP_BUTTON_MODIFIERS(button) == CURSOR_SELECT2 ||
1431 STRIP_BUTTON_MODIFIERS(button) == '\t') {
1432 /* Use spacebar or tab to cycle through the points. Shift
1433 * reverses cycle direction. */
1434 if(ui->dragpoint >= 0)
1435 return MOVE_NO_EFFECT;
1436 if(ui->cursorpoint < 0) {
1437 ui->cursorpoint = 0;
1438 return MOVE_UI_UPDATE;
1439 }
1440 assert(ui->cursorpoint >= 0);
1441
1442 /* cursorpoint is valid - increment it */
1443 int direction = (button & MOD_SHFT) ? -1 : 1;
1444 ui->cursorpoint = (ui->cursorpoint + direction + state->params.n) % state->params.n;
1445 return MOVE_UI_UPDATE;
1292 } 1446 }
1293 1447
1294 return NULL; 1448 return MOVE_UNUSED;
1295} 1449}
1296 1450
1297static game_state *execute_move(const game_state *state, const char *move) 1451static game_state *execute_move(const game_state *state, const char *move)
@@ -1334,7 +1488,7 @@ static game_state *execute_move(const game_state *state, const char *move)
1334 */ 1488 */
1335 1489
1336static void game_compute_size(const game_params *params, int tilesize, 1490static void game_compute_size(const game_params *params, int tilesize,
1337 int *x, int *y) 1491 const game_ui *ui, int *x, int *y)
1338{ 1492{
1339 *x = *y = COORDLIMIT(params->n) * tilesize; 1493 *x = *y = COORDLIMIT(params->n) * tilesize;
1340} 1494}
@@ -1363,11 +1517,9 @@ static float *game_colours(frontend *fe, int *ncolours)
1363 ret[COL_LINE * 3 + 1] = 0.0F; 1517 ret[COL_LINE * 3 + 1] = 0.0F;
1364 ret[COL_LINE * 3 + 2] = 0.0F; 1518 ret[COL_LINE * 3 + 2] = 0.0F;
1365 1519
1366#ifdef SHOW_CROSSINGS
1367 ret[COL_CROSSEDLINE * 3 + 0] = 1.0F; 1520 ret[COL_CROSSEDLINE * 3 + 0] = 1.0F;
1368 ret[COL_CROSSEDLINE * 3 + 1] = 0.0F; 1521 ret[COL_CROSSEDLINE * 3 + 1] = 0.0F;
1369 ret[COL_CROSSEDLINE * 3 + 2] = 0.0F; 1522 ret[COL_CROSSEDLINE * 3 + 2] = 0.0F;
1370#endif
1371 1523
1372 ret[COL_OUTLINE * 3 + 0] = 0.0F; 1524 ret[COL_OUTLINE * 3 + 0] = 0.0F;
1373 ret[COL_OUTLINE * 3 + 1] = 0.0F; 1525 ret[COL_OUTLINE * 3 + 1] = 0.0F;
@@ -1491,15 +1643,16 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1491 ds->y[i] = y; 1643 ds->y[i] = y;
1492 } 1644 }
1493 1645
1494 if (ds->bg == bg && ds->dragpoint == ui->dragpoint && ds->cursorpoint == ui->cursorpoint && !points_moved) 1646 if (ds->bg == bg &&
1647 ds->dragpoint == ui->dragpoint &&
1648 ds->cursorpoint == ui->cursorpoint && !points_moved)
1495 return; /* nothing to do */ 1649 return; /* nothing to do */
1496 1650
1497 ds->dragpoint = ui->dragpoint; 1651 ds->dragpoint = ui->dragpoint;
1652 ds->cursorpoint = ui->cursorpoint;
1498 ds->bg = bg; 1653 ds->bg = bg;
1499 1654
1500 game_compute_size(&state->params, ds->tilesize, &w, &h); 1655 game_compute_size(&state->params, ds->tilesize, ui, &w, &h);
1501
1502 clip(dr, 0, 0, w, h);
1503 draw_rect(dr, 0, 0, w, h, bg); 1656 draw_rect(dr, 0, 0, w, h, bg);
1504 1657
1505 /* 1658 /*
@@ -1508,23 +1661,28 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1508 1661
1509 for (i = 0; (e = index234(state->graph->edges, i)) != NULL; i++) { 1662 for (i = 0; (e = index234(state->graph->edges, i)) != NULL; i++) {
1510 draw_line(dr, ds->x[e->a], ds->y[e->a], ds->x[e->b], ds->y[e->b], 1663 draw_line(dr, ds->x[e->a], ds->y[e->a], ds->x[e->b], ds->y[e->b],
1511#ifdef SHOW_CROSSINGS 1664 ui->show_crossed_edges &&
1512 (oldstate?oldstate:state)->crosses[i] ? 1665 (oldstate?oldstate:state)->crosses[i] ?
1513 COL_CROSSEDLINE : 1666 COL_CROSSEDLINE : COL_LINE);
1514#endif
1515 COL_LINE);
1516 } 1667 }
1517 1668
1518 /* 1669 /*
1519 * Draw the points. 1670 * Draw the points.
1520 * 1671 *
1521 * When dragging, we should not only vary the colours, but 1672 * When dragging, we vary the point colours to highlight the drag
1522 * leave the point being dragged until last. 1673 * point and neighbour points. The draw order is defined so that
1674 * the most relevant points (i.e., the dragged point and cursor
1675 * point) are drawn last, so they appear on top of other points.
1523 */ 1676 */
1677 static const int draw_order[] = {
1678 COL_POINT,
1679 COL_NEIGHBOUR,
1680 COL_CURSORPOINT,
1681 COL_DRAGPOINT
1682 };
1683
1524 for (j = 0; j < 4; j++) { 1684 for (j = 0; j < 4; j++) {
1525 int thisc = (j == 0 ? COL_POINT : 1685 int thisc = draw_order[j];
1526 (j == 1 ? COL_NEIGHBOUR :
1527 j == 2 ? COL_CURSORPOINT : COL_DRAGPOINT));
1528 for (i = 0; i < state->params.n; i++) { 1686 for (i = 0; i < state->params.n; i++) {
1529 int c; 1687 int c;
1530 1688
@@ -1540,19 +1698,17 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1540 } 1698 }
1541 1699
1542 if (c == thisc) { 1700 if (c == thisc) {
1543#ifdef VERTEX_NUMBERS 1701 if (ui->vertex_numbers) {
1544 draw_circle(dr, ds->x[i], ds->y[i], DRAG_THRESHOLD, bg, bg); 1702 char buf[80];
1545 { 1703 draw_circle(dr, ds->x[i], ds->y[i], DRAG_THRESHOLD, bg, bg);
1546 char buf[80]; 1704 sprintf(buf, "%d", i);
1547 sprintf(buf, "%d", i); 1705 draw_text(dr, ds->x[i], ds->y[i], FONT_VARIABLE,
1548 draw_text(dr, ds->x[i], ds->y[i], FONT_VARIABLE,
1549 DRAG_THRESHOLD*3/2, 1706 DRAG_THRESHOLD*3/2,
1550 ALIGN_VCENTRE|ALIGN_HCENTRE, c, buf); 1707 ALIGN_VCENTRE|ALIGN_HCENTRE, c, buf);
1551 } 1708 } else {
1552#else 1709 draw_circle(dr, ds->x[i], ds->y[i], CIRCLE_RADIUS,
1553 draw_circle(dr, ds->x[i], ds->y[i], CIRCLE_RADIUS, 1710 c, COL_OUTLINE);
1554 c, COL_OUTLINE); 1711 }
1555#endif
1556 } 1712 }
1557 } 1713 }
1558 } 1714 }
@@ -1587,17 +1743,20 @@ static void game_get_cursor_location(const game_ui *ui,
1587 const game_params *params, 1743 const game_params *params,
1588 int *x, int *y, int *w, int *h) 1744 int *x, int *y, int *w, int *h)
1589{ 1745{
1590 if(ui->dragpoint >= 0 || ui->cursorpoint >= 0) { 1746 point pt;
1591 int idx = (ui->dragpoint >= 0) ? ui->dragpoint : ui->cursorpoint; 1747 if(ui->dragpoint >= 0)
1748 pt = ui->newpoint;
1749 else if(ui->cursorpoint >= 0)
1750 pt = state->pts[ui->cursorpoint];
1751 else
1752 return;
1592 1753
1593 int cx, cy; 1754 int cx = ds->tilesize * pt.x / pt.d;
1594 cx = ds->x[idx]; 1755 int cy = ds->tilesize * pt.y / pt.d;
1595 cy = ds->y[idx];
1596 1756
1597 *x = cx - CIRCLE_RADIUS; 1757 *x = cx - CIRCLE_RADIUS;
1598 *y = cy - CIRCLE_RADIUS; 1758 *y = cy - CIRCLE_RADIUS;
1599 *w = *h = 2 * CIRCLE_RADIUS + 1; 1759 *w = *h = 2 * CIRCLE_RADIUS + 1;
1600 }
1601} 1760}
1602 1761
1603static int game_status(const game_state *state) 1762static int game_status(const game_state *state)
@@ -1605,19 +1764,6 @@ static int game_status(const game_state *state)
1605 return state->completed ? +1 : 0; 1764 return state->completed ? +1 : 0;
1606} 1765}
1607 1766
1608static bool game_timing_state(const game_state *state, game_ui *ui)
1609{
1610 return true;
1611}
1612
1613static void game_print_size(const game_params *params, float *x, float *y)
1614{
1615}
1616
1617static void game_print(drawing *dr, const game_state *state, int tilesize)
1618{
1619}
1620
1621#ifdef COMBINED 1767#ifdef COMBINED
1622#define thegame untangle 1768#define thegame untangle
1623#endif 1769#endif
@@ -1638,13 +1784,15 @@ const struct game thegame = {
1638 dup_game, 1784 dup_game,
1639 free_game, 1785 free_game,
1640 true, solve_game, 1786 true, solve_game,
1641 false, game_can_format_as_text_now, game_text_format, 1787 false, NULL, NULL, /* can_format_as_text_now, text_format */
1788 get_prefs, set_prefs,
1642 new_ui, 1789 new_ui,
1643 free_ui, 1790 free_ui,
1644 encode_ui, 1791 NULL, /* encode_ui */
1645 decode_ui, 1792 NULL, /* decode_ui */
1646 NULL, /* game_request_keys */ 1793 NULL, /* game_request_keys */
1647 game_changed_state, 1794 game_changed_state,
1795 NULL, /* current_key_label */
1648 interpret_move, 1796 interpret_move,
1649 execute_move, 1797 execute_move,
1650 PREFERRED_TILESIZE, game_compute_size, game_set_size, 1798 PREFERRED_TILESIZE, game_compute_size, game_set_size,
@@ -1656,8 +1804,8 @@ const struct game thegame = {
1656 game_flash_length, 1804 game_flash_length,
1657 game_get_cursor_location, 1805 game_get_cursor_location,
1658 game_status, 1806 game_status,
1659 false, false, game_print_size, game_print, 1807 false, false, NULL, NULL, /* print_size, print */
1660 false, /* wants_statusbar */ 1808 false, /* wants_statusbar */
1661 false, game_timing_state, 1809 false, NULL, /* timing_state */
1662 SOLVE_ANIMATES, /* flags */ 1810 SOLVE_ANIMATES, /* flags */
1663}; 1811};
diff --git a/apps/plugins/puzzles/src/version.c b/apps/plugins/puzzles/src/version.c
index 1cef29feb7..73632f9b37 100644
--- a/apps/plugins/puzzles/src/version.c
+++ b/apps/plugins/puzzles/src/version.c
@@ -2,6 +2,7 @@
2 * Puzzles version numbering. 2 * Puzzles version numbering.
3 */ 3 */
4 4
5#include "puzzles.h"
5#include "version.h" 6#include "version.h"
6 7
7char ver[] = VER; 8char ver[] = VER;
diff --git a/apps/plugins/puzzles/src/version.h b/apps/plugins/puzzles/src/version.h
index 997e00592b..20d2800fee 100644
--- a/apps/plugins/puzzles/src/version.h
+++ b/apps/plugins/puzzles/src/version.h
@@ -9,3 +9,5 @@
9 */ 9 */
10 10
11#define VER "Unidentified build" 11#define VER "Unidentified build"
12
13#define VERSIONINFO_BINARY_VERSION 0,0,0,0
diff --git a/apps/plugins/puzzles/src/windows.c b/apps/plugins/puzzles/src/windows.c
index 38559c5454..5273e17842 100644
--- a/apps/plugins/puzzles/src/windows.c
+++ b/apps/plugins/puzzles/src/windows.c
@@ -7,11 +7,7 @@
7#ifndef NO_HTMLHELP 7#ifndef NO_HTMLHELP
8#include <htmlhelp.h> 8#include <htmlhelp.h>
9#endif /* NO_HTMLHELP */ 9#endif /* NO_HTMLHELP */
10 10#include <io.h>
11#ifdef _WIN32_WCE
12#include <commdlg.h>
13#include <aygshell.h>
14#endif
15 11
16#include <stdio.h> 12#include <stdio.h>
17#include <assert.h> 13#include <assert.h>
@@ -23,10 +19,6 @@
23 19
24#include "puzzles.h" 20#include "puzzles.h"
25 21
26#ifdef _WIN32_WCE
27#include "resource.h"
28#endif
29
30#define IDM_NEW 0x0010 22#define IDM_NEW 0x0010
31#define IDM_RESTART 0x0020 23#define IDM_RESTART 0x0020
32#define IDM_UNDO 0x0030 24#define IDM_UNDO 0x0030
@@ -43,10 +35,14 @@
43#define IDM_SAVE 0x00E0 35#define IDM_SAVE 0x00E0
44#define IDM_LOAD 0x00F0 36#define IDM_LOAD 0x00F0
45#define IDM_PRINT 0x0100 37#define IDM_PRINT 0x0100
46#define IDM_PRESETS 0x0110 38#define IDM_PREFS 0x0110
47#define IDM_GAMES 0x0300
48 39
49#define IDM_KEYEMUL 0x0400 40/* Menu items for preset game_params go up from IDM_PRESET_BASE in
41 * steps of MENUITEM_STEP = 0x20. Menu items for selecting different
42 * games (in -DCOMBINED mode) go up from IDM_GAME_BASE similarly. */
43#define IDM_PRESET_BASE 0x0120
44#define IDM_GAME_BASE 0x0130
45#define MENUITEM_STEP 0x0020
50 46
51#define HELP_FILE_NAME "puzzles.hlp" 47#define HELP_FILE_NAME "puzzles.hlp"
52#define HELP_CNT_NAME "puzzles.cnt" 48#define HELP_CNT_NAME "puzzles.cnt"
@@ -77,56 +73,12 @@ bool help_has_contents;
77#define CLASSNAME thegame.name 73#define CLASSNAME thegame.name
78#endif 74#endif
79 75
80#ifdef _WIN32_WCE
81
82/*
83 * Wrapper implementations of functions not supplied by the
84 * PocketPC API.
85 */
86
87#define SHGetSubMenu(hWndMB,ID_MENU) (HMENU)SendMessage((hWndMB), SHCMBM_GETSUBMENU, (WPARAM)0, (LPARAM)ID_MENU)
88
89#undef MessageBox
90
91int MessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
92{
93 TCHAR wText[2048];
94 TCHAR wCaption[2048];
95
96 MultiByteToWideChar (CP_ACP, 0, lpText, -1, wText, 2048);
97 MultiByteToWideChar (CP_ACP, 0, lpCaption, -1, wCaption, 2048);
98
99 return MessageBoxW (hWnd, wText, wCaption, uType);
100}
101
102BOOL SetDlgItemTextA(HWND hDlg, int nIDDlgItem, LPCSTR lpString)
103{
104 TCHAR wText[256];
105
106 MultiByteToWideChar (CP_ACP, 0, lpString, -1, wText, 256);
107 return SetDlgItemTextW(hDlg, nIDDlgItem, wText);
108}
109
110LPCSTR getenv(LPCSTR buf)
111{
112 return NULL;
113}
114
115BOOL GetKeyboardState(PBYTE pb)
116{
117 return false;
118}
119
120static TCHAR wClassName[256], wGameName[256];
121
122#endif
123
124#ifdef DEBUGGING 76#ifdef DEBUGGING
125static FILE *debug_fp = NULL; 77static FILE *debug_fp = NULL;
126static HANDLE debug_hdl = INVALID_HANDLE_VALUE; 78static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
127static int debug_got_console = 0; 79static int debug_got_console = 0;
128 80
129void dputs(char *buf) 81static void dputs(char *buf)
130{ 82{
131 /*DWORD dw; 83 /*DWORD dw;
132 84
@@ -144,8 +96,8 @@ void dputs(char *buf)
144 WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL); 96 WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL);
145 } 97 }
146 if (debug_fp) { 98 if (debug_fp) {
147 fputs(buf, debug_fp); 99 fputs(buf, debug_fp);
148 fflush(debug_fp); 100 fflush(debug_fp);
149 }*/ 101 }*/
150 OutputDebugString(buf); 102 OutputDebugString(buf);
151} 103}
@@ -157,7 +109,7 @@ void debug_printf(const char *fmt, ...)
157 static int debugging = -1; 109 static int debugging = -1;
158 110
159 if (debugging == -1) 111 if (debugging == -1)
160 debugging = getenv("DEBUG_PUZZLES") ? 1 : 0; 112 debugging = getenv_bool("DEBUG_PUZZLES", false);
161 113
162 if (debugging) { 114 if (debugging) {
163 va_start(ap, fmt); 115 va_start(ap, fmt);
@@ -168,14 +120,12 @@ void debug_printf(const char *fmt, ...)
168} 120}
169#endif 121#endif
170 122
171#ifndef _WIN32_WCE
172#define WINFLAGS (WS_OVERLAPPEDWINDOW &~ \ 123#define WINFLAGS (WS_OVERLAPPEDWINDOW &~ \
173 (WS_MAXIMIZEBOX | WS_OVERLAPPED)) 124 (WS_MAXIMIZEBOX | WS_OVERLAPPED))
174#else
175#define WINFLAGS (WS_CAPTION | WS_SYSMENU)
176#endif
177 125
178static void new_game_size(frontend *fe, float scale); 126static void new_game_size(frontend *fe, float scale);
127static void load_prefs(midend *me);
128static char *save_prefs(midend *me);
179 129
180struct font { 130struct font {
181 HFONT font; 131 HFONT font;
@@ -204,9 +154,6 @@ struct frontend {
204 const game *game; 154 const game *game;
205 midend *me; 155 midend *me;
206 HWND hwnd, statusbar, cfgbox; 156 HWND hwnd, statusbar, cfgbox;
207#ifdef _WIN32_WCE
208 HWND numpad; /* window handle for the numeric pad */
209#endif
210 HINSTANCE inst; 157 HINSTANCE inst;
211 HBITMAP bitmap, prevbm; 158 HBITMAP bitmap, prevbm;
212 RECT bitmapPosition; /* game bitmap position within game window */ 159 RECT bitmapPosition; /* game bitmap position within game window */
@@ -308,19 +255,9 @@ void get_random_seed(void **randseed, int *randseedsize)
308 255
309static void win_status_bar(void *handle, const char *text) 256static void win_status_bar(void *handle, const char *text)
310{ 257{
311#ifdef _WIN32_WCE
312 TCHAR wText[255];
313#endif
314 frontend *fe = (frontend *)handle; 258 frontend *fe = (frontend *)handle;
315 259
316#ifdef _WIN32_WCE
317 MultiByteToWideChar (CP_ACP, 0, text, -1, wText, 255);
318 SendMessage(fe->statusbar, SB_SETTEXT,
319 (WPARAM) 255 | SBT_NOBORDERS,
320 (LPARAM) wText);
321#else
322 SetWindowText(fe->statusbar, text); 260 SetWindowText(fe->statusbar, text);
323#endif
324} 261}
325 262
326static blitter *win_blitter_new(void *handle, int w, int h) 263static blitter *win_blitter_new(void *handle, int w, int h)
@@ -464,13 +401,6 @@ static void win_set_brush(frontend *fe, int colour)
464 if (hatch < 0) { 401 if (hatch < 0) {
465 br = CreateSolidBrush(RGB(r * 255, g * 255, b * 255)); 402 br = CreateSolidBrush(RGB(r * 255, g * 255, b * 255));
466 } else { 403 } else {
467#ifdef _WIN32_WCE
468 /*
469 * This is only ever required during printing, and the
470 * PocketPC port doesn't support printing.
471 */
472 fatal("CreateHatchBrush not supported");
473#else
474 br = CreateHatchBrush(hatch == HATCH_BACKSLASH ? HS_FDIAGONAL : 404 br = CreateHatchBrush(hatch == HATCH_BACKSLASH ? HS_FDIAGONAL :
475 hatch == HATCH_SLASH ? HS_BDIAGONAL : 405 hatch == HATCH_SLASH ? HS_BDIAGONAL :
476 hatch == HATCH_HORIZ ? HS_HORIZONTAL : 406 hatch == HATCH_HORIZ ? HS_HORIZONTAL :
@@ -478,7 +408,6 @@ static void win_set_brush(frontend *fe, int colour)
478 hatch == HATCH_PLUS ? HS_CROSS : 408 hatch == HATCH_PLUS ? HS_CROSS :
479 /* hatch == HATCH_X ? */ HS_DIAGCROSS, 409 /* hatch == HATCH_X ? */ HS_DIAGCROSS,
480 RGB(0,0,0)); 410 RGB(0,0,0));
481#endif
482 } 411 }
483 } else { 412 } else {
484 br = fe->brushes[colour]; 413 br = fe->brushes[colour];
@@ -602,9 +531,6 @@ static void win_draw_text(void *handle, int x, int y, int fonttype,
602 lf.lfPitchAndFamily = (fonttype == FONT_FIXED ? 531 lf.lfPitchAndFamily = (fonttype == FONT_FIXED ?
603 FIXED_PITCH | FF_DONTCARE : 532 FIXED_PITCH | FF_DONTCARE :
604 VARIABLE_PITCH | FF_SWISS); 533 VARIABLE_PITCH | FF_SWISS);
605#ifdef _WIN32_WCE
606 wcscpy(lf.lfFaceName, TEXT("Tahoma"));
607#endif
608 534
609 fe->fonts[i].font = CreateFontIndirect(&lf); 535 fe->fonts[i].font = CreateFontIndirect(&lf);
610 } 536 }
@@ -708,7 +634,7 @@ static void win_draw_circle(void *handle, int cx, int cy, int radius,
708 win_reset_pen(fe); 634 win_reset_pen(fe);
709} 635}
710 636
711static void win_draw_polygon(void *handle, int *coords, int npoints, 637static void win_draw_polygon(void *handle, const int *coords, int npoints,
712 int fillcolour, int outlinecolour) 638 int fillcolour, int outlinecolour)
713{ 639{
714 frontend *fe = (frontend *)handle; 640 frontend *fe = (frontend *)handle;
@@ -754,9 +680,7 @@ static void win_start_draw(void *handle)
754 fe->prevbm = SelectObject(fe->hdc, fe->bitmap); 680 fe->prevbm = SelectObject(fe->hdc, fe->bitmap);
755 ReleaseDC(fe->hwnd, hdc_win); 681 ReleaseDC(fe->hwnd, hdc_win);
756 fe->clip = NULL; 682 fe->clip = NULL;
757#ifndef _WIN32_WCE
758 SetMapMode(fe->hdc, MM_TEXT); 683 SetMapMode(fe->hdc, MM_TEXT);
759#endif
760 fe->drawstatus = DRAWING; 684 fe->drawstatus = DRAWING;
761} 685}
762 686
@@ -999,7 +923,6 @@ const struct drawing_api win_drawing = {
999 923
1000void print(frontend *fe) 924void print(frontend *fe)
1001{ 925{
1002#ifndef _WIN32_WCE
1003 PRINTDLG pd; 926 PRINTDLG pd;
1004 char doctitle[256]; 927 char doctitle[256];
1005 document *doc; 928 document *doc;
@@ -1019,6 +942,7 @@ void print(frontend *fe)
1019 game_params *params; 942 game_params *params;
1020 943
1021 nme = midend_new(NULL, fe->game, NULL, NULL); 944 nme = midend_new(NULL, fe->game, NULL, NULL);
945 load_prefs(nme);
1022 946
1023 /* 947 /*
1024 * Set the non-interactive mid-end to have the same 948 * Set the non-interactive mid-end to have the same
@@ -1090,7 +1014,6 @@ void print(frontend *fe)
1090 1014
1091 DeleteDC(pd.hDC); 1015 DeleteDC(pd.hDC);
1092 document_free(doc); 1016 document_free(doc);
1093#endif
1094} 1017}
1095 1018
1096void deactivate_timer(frontend *fe) 1019void deactivate_timer(frontend *fe)
@@ -1168,7 +1091,6 @@ void write_clip(HWND hwnd, char *data)
1168 */ 1091 */
1169static void init_help(void) 1092static void init_help(void)
1170{ 1093{
1171#ifndef _WIN32_WCE
1172 char b[2048], *p, *q, *r; 1094 char b[2048], *p, *q, *r;
1173 FILE *fp; 1095 FILE *fp;
1174 1096
@@ -1232,11 +1154,8 @@ static void init_help(void)
1232 } 1154 }
1233 1155
1234 help_type = NONE; /* didn't find any */ 1156 help_type = NONE; /* didn't find any */
1235#endif
1236} 1157}
1237 1158
1238#ifndef _WIN32_WCE
1239
1240/* 1159/*
1241 * Start Help. 1160 * Start Help.
1242 */ 1161 */
@@ -1257,7 +1176,7 @@ static void start_help(frontend *fe, const char *topic)
1257 } else { 1176 } else {
1258 cmd = HELP_CONTENTS; 1177 cmd = HELP_CONTENTS;
1259 } 1178 }
1260 WinHelp(fe->hwnd, help_path, cmd, (DWORD)str); 1179 WinHelp(fe->hwnd, help_path, cmd, (ULONG_PTR)str);
1261 fe->help_running = true; 1180 fe->help_running = true;
1262 break; 1181 break;
1263 case CHM: 1182 case CHM:
@@ -1306,8 +1225,6 @@ static void stop_help(frontend *fe)
1306 } 1225 }
1307} 1226}
1308 1227
1309#endif
1310
1311/* 1228/*
1312 * Terminate Help on process exit. 1229 * Terminate Help on process exit.
1313 */ 1230 */
@@ -1338,10 +1255,8 @@ static void adjust_statusbar(frontend *fe, RECT *r)
1338 if (!fe->statusbar) return; 1255 if (!fe->statusbar) return;
1339 1256
1340 sy = get_statusbar_height(fe); 1257 sy = get_statusbar_height(fe);
1341#ifndef _WIN32_WCE
1342 SetWindowPos(fe->statusbar, NULL, 0, r->bottom-r->top-sy, r->right-r->left, 1258 SetWindowPos(fe->statusbar, NULL, 0, r->bottom-r->top-sy, r->right-r->left,
1343 sy, SWP_NOZORDER); 1259 sy, SWP_NOZORDER);
1344#endif
1345} 1260}
1346 1261
1347static void get_menu_size(HWND wh, RECT *r) 1262static void get_menu_size(HWND wh, RECT *r)
@@ -1378,7 +1293,7 @@ static bool check_window_resize(frontend *fe, int cx, int cy,
1378 * See if we actually got the window size we wanted, and adjust 1293 * See if we actually got the window size we wanted, and adjust
1379 * the puzzle size if not. 1294 * the puzzle size if not.
1380 */ 1295 */
1381 midend_size(fe->me, &x, &y, true); 1296 midend_size(fe->me, &x, &y, true, 1.0);
1382 if (x != cx || y != cy) { 1297 if (x != cx || y != cy) {
1383 /* 1298 /*
1384 * Resize the window, now we know what size we _really_ 1299 * Resize the window, now we know what size we _really_
@@ -1416,13 +1331,8 @@ static void check_window_size(frontend *fe, int *px, int *py)
1416 cx = r.right - r.left; 1331 cx = r.right - r.left;
1417 cy = r.bottom - r.top; 1332 cy = r.bottom - r.top;
1418 1333
1419 if (check_window_resize(fe, cx, cy, px, py, &wx, &wy)) { 1334 if (check_window_resize(fe, cx, cy, px, py, &wx, &wy))
1420#ifdef _WIN32_WCE 1335 SetWindowPos(fe->hwnd, NULL, 0, 0, wx, wy, SWP_NOMOVE | SWP_NOZORDER);
1421 SetWindowPos(fe->hwnd, NULL, 0, 0, wx, wy,
1422 SWP_NOMOVE | SWP_NOZORDER);
1423#endif
1424 ;
1425 }
1426 1336
1427 GetClientRect(fe->hwnd, &r); 1337 GetClientRect(fe->hwnd, &r);
1428 adjust_statusbar(fe, &r); 1338 adjust_statusbar(fe, &r);
@@ -1452,23 +1362,6 @@ static void get_max_puzzle_size(frontend *fe, int *x, int *y)
1452 } 1362 }
1453} 1363}
1454 1364
1455#ifdef _WIN32_WCE
1456/* Toolbar buttons on the numeric pad */
1457static TBBUTTON tbNumpadButtons[] =
1458{
1459 {0, IDM_KEYEMUL + '1', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1},
1460 {1, IDM_KEYEMUL + '2', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1},
1461 {2, IDM_KEYEMUL + '3', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1},
1462 {3, IDM_KEYEMUL + '4', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1},
1463 {4, IDM_KEYEMUL + '5', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1},
1464 {5, IDM_KEYEMUL + '6', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1},
1465 {6, IDM_KEYEMUL + '7', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1},
1466 {7, IDM_KEYEMUL + '8', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1},
1467 {8, IDM_KEYEMUL + '9', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1},
1468 {9, IDM_KEYEMUL + ' ', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}
1469};
1470#endif
1471
1472/* 1365/*
1473 * Allocate a new frontend structure and create its main window. 1366 * Allocate a new frontend structure and create its main window.
1474 */ 1367 */
@@ -1502,34 +1395,6 @@ static frontend *frontend_new(HINSTANCE inst)
1502 1395
1503 fe->puzz_scale = 1.0; 1396 fe->puzz_scale = 1.0;
1504 1397
1505 #ifdef _WIN32_WCE
1506 MultiByteToWideChar (CP_ACP, 0, nogame, -1, wGameName, 256);
1507 fe->hwnd = CreateWindowEx(0, wClassName, wGameName,
1508 WS_VISIBLE,
1509 CW_USEDEFAULT, CW_USEDEFAULT,
1510 CW_USEDEFAULT, CW_USEDEFAULT,
1511 NULL, NULL, inst, NULL);
1512
1513 {
1514 SHMENUBARINFO mbi;
1515 RECT rc, rcBar, rcTB, rcClient;
1516
1517 memset (&mbi, 0, sizeof(SHMENUBARINFO));
1518 mbi.cbSize = sizeof(SHMENUBARINFO);
1519 mbi.hwndParent = fe->hwnd;
1520 mbi.nToolBarId = IDR_MENUBAR1;
1521 mbi.hInstRes = inst;
1522
1523 SHCreateMenuBar(&mbi);
1524
1525 GetWindowRect(fe->hwnd, &rc);
1526 GetWindowRect(mbi.hwndMB, &rcBar);
1527 rc.bottom -= rcBar.bottom - rcBar.top;
1528 MoveWindow(fe->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, false);
1529
1530 fe->numpad = NULL;
1531 }
1532#else
1533 fe->hwnd = CreateWindowEx(0, CLASSNAME, nogame, 1398 fe->hwnd = CreateWindowEx(0, CLASSNAME, nogame,
1534 WS_OVERLAPPEDWINDOW &~ 1399 WS_OVERLAPPEDWINDOW &~
1535 (WS_MAXIMIZEBOX), 1400 (WS_MAXIMIZEBOX),
@@ -1540,7 +1405,6 @@ static frontend *frontend_new(HINSTANCE inst)
1540 DWORD lerr = GetLastError(); 1405 DWORD lerr = GetLastError();
1541 printf("no window: 0x%x\n", (unsigned)lerr); 1406 printf("no window: 0x%x\n", (unsigned)lerr);
1542 } 1407 }
1543#endif
1544 1408
1545 fe->gamemenu = NULL; 1409 fe->gamemenu = NULL;
1546 fe->preset_menu = NULL; 1410 fe->preset_menu = NULL;
@@ -1586,6 +1450,7 @@ static midend *midend_for_new_game(frontend *fe, const game *cgame,
1586 if (!arg) { 1450 if (!arg) {
1587 if (me) midend_free(me); 1451 if (me) midend_free(me);
1588 me = midend_new(fe, cgame, &win_drawing, fe); 1452 me = midend_new(fe, cgame, &win_drawing, fe);
1453 load_prefs(me);
1589 midend_new_game(me); 1454 midend_new_game(me);
1590 } else { 1455 } else {
1591 FILE *fp; 1456 FILE *fp;
@@ -1626,6 +1491,7 @@ static midend *midend_for_new_game(frontend *fe, const game *cgame,
1626 if (!err_load) { 1491 if (!err_load) {
1627 if (me) midend_free(me); 1492 if (me) midend_free(me);
1628 me = midend_new(fe, loadgame, &win_drawing, fe); 1493 me = midend_new(fe, loadgame, &win_drawing, fe);
1494 load_prefs(me);
1629 err_load = midend_deserialise(me, savefile_read, fp); 1495 err_load = midend_deserialise(me, savefile_read, fp);
1630 } 1496 }
1631 } else { 1497 } else {
@@ -1638,6 +1504,7 @@ static midend *midend_for_new_game(frontend *fe, const game *cgame,
1638 */ 1504 */
1639 if (me) midend_free(me); 1505 if (me) midend_free(me);
1640 me = midend_new(fe, cgame, &win_drawing, fe); 1506 me = midend_new(fe, cgame, &win_drawing, fe);
1507 load_prefs(me);
1641 err_param = midend_game_id(me, arg); 1508 err_param = midend_game_id(me, arg);
1642 if (!err_param) { 1509 if (!err_param) {
1643 midend_new_game(me); 1510 midend_new_game(me);
@@ -1676,7 +1543,8 @@ static void populate_preset_menu(frontend *fe,
1676 UINT flags = MF_ENABLED; 1543 UINT flags = MF_ENABLED;
1677 1544
1678 if (entry->params) { 1545 if (entry->params) {
1679 id_or_sub = (UINT_PTR)(IDM_PRESETS + 0x10 * entry->id); 1546 id_or_sub = (UINT_PTR)(
1547 IDM_PRESET_BASE + MENUITEM_STEP * entry->id);
1680 1548
1681 fe->preset_menuitems[entry->id].which_menu = winmenu; 1549 fe->preset_menuitems[entry->id].which_menu = winmenu;
1682 fe->preset_menuitems[entry->id].item_index = 1550 fe->preset_menuitems[entry->id].item_index =
@@ -1694,15 +1562,7 @@ static void populate_preset_menu(frontend *fe,
1694 * here. 1562 * here.
1695 */ 1563 */
1696 1564
1697#ifndef _WIN32_WCE
1698 AppendMenu(winmenu, flags, id_or_sub, entry->title); 1565 AppendMenu(winmenu, flags, id_or_sub, entry->title);
1699#else
1700 {
1701 TCHAR wName[255];
1702 MultiByteToWideChar(CP_ACP, 0, entry->title, -1, wName, 255);
1703 AppendMenu(winmenu, flags, id_or_sub, wName);
1704 }
1705#endif
1706 } 1566 }
1707} 1567}
1708 1568
@@ -1763,41 +1623,14 @@ static int fe_set_midend(frontend *fe, midend *me)
1763 fe->statusbar = NULL; 1623 fe->statusbar = NULL;
1764 1624
1765 get_max_puzzle_size(fe, &x, &y); 1625 get_max_puzzle_size(fe, &x, &y);
1766 midend_size(fe->me, &x, &y, false); 1626 midend_size(fe->me, &x, &y, false, 1.0);
1767 1627
1768 r.left = r.top = 0; 1628 r.left = r.top = 0;
1769 r.right = x; 1629 r.right = x;
1770 r.bottom = y; 1630 r.bottom = y;
1771 AdjustWindowRectEx(&r, WINFLAGS, true, 0); 1631 AdjustWindowRectEx(&r, WINFLAGS, true, 0);
1772 1632
1773#ifdef _WIN32_WCE
1774 if (fe->numpad)
1775 DestroyWindow(fe->numpad);
1776 if (fe->game->flags & REQUIRE_NUMPAD)
1777 {
1778 fe->numpad = CreateToolbarEx (fe->hwnd,
1779 WS_VISIBLE | WS_CHILD | CCS_NOPARENTALIGN | TBSTYLE_FLAT,
1780 0, 10, fe->inst, IDR_PADTOOLBAR,
1781 tbNumpadButtons, sizeof (tbNumpadButtons) / sizeof (TBBUTTON),
1782 0, 0, 14, 15, sizeof (TBBUTTON));
1783 GetWindowRect(fe->numpad, &rcTB);
1784 GetClientRect(fe->hwnd, &rcClient);
1785 MoveWindow(fe->numpad,
1786 0,
1787 rcClient.bottom - (rcTB.bottom - rcTB.top) - 1,
1788 rcClient.right,
1789 rcTB.bottom - rcTB.top,
1790 false);
1791 SendMessage(fe->numpad, TB_SETINDENT, (rcClient.right - (10 * 21)) / 2, 0);
1792 }
1793 else {
1794 fe->numpad = NULL;
1795 }
1796 MultiByteToWideChar (CP_ACP, 0, fe->game->name, -1, wGameName, 256);
1797 SetWindowText(fe->hwnd, wGameName);
1798#else
1799 SetWindowText(fe->hwnd, fe->game->name); 1633 SetWindowText(fe->hwnd, fe->game->name);
1800#endif
1801 1634
1802 if (fe->statusbar) 1635 if (fe->statusbar)
1803 DestroyWindow(fe->statusbar); 1636 DestroyWindow(fe->statusbar);
@@ -1807,24 +1640,15 @@ static int fe_set_midend(frontend *fe, midend *me)
1807 WS_CHILD | WS_VISIBLE, 1640 WS_CHILD | WS_VISIBLE,
1808 0, 0, 0, 0, /* status bar does these */ 1641 0, 0, 0, 0, /* status bar does these */
1809 fe->hwnd, NULL, fe->inst, NULL); 1642 fe->hwnd, NULL, fe->inst, NULL);
1810#ifdef _WIN32_WCE
1811 /* Flat status bar looks better on the Pocket PC */
1812 SendMessage(fe->statusbar, SB_SIMPLE, (WPARAM) true, 0);
1813 SendMessage(fe->statusbar, SB_SETTEXT,
1814 (WPARAM) 255 | SBT_NOBORDERS,
1815 (LPARAM) L"");
1816#endif
1817 1643
1818 /* 1644 /*
1819 * Now resize the window to take account of the status bar. 1645 * Now resize the window to take account of the status bar.
1820 */ 1646 */
1821 GetWindowRect(fe->statusbar, &sr); 1647 GetWindowRect(fe->statusbar, &sr);
1822 GetWindowRect(fe->hwnd, &r); 1648 GetWindowRect(fe->hwnd, &r);
1823#ifndef _WIN32_WCE
1824 SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left, 1649 SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left,
1825 r.bottom - r.top + sr.bottom - sr.top, 1650 r.bottom - r.top + sr.bottom - sr.top,
1826 SWP_NOMOVE | SWP_NOZORDER); 1651 SWP_NOMOVE | SWP_NOZORDER);
1827#endif
1828 } else { 1652 } else {
1829 fe->statusbar = NULL; 1653 fe->statusbar = NULL;
1830 } 1654 }
@@ -1832,24 +1656,17 @@ static int fe_set_midend(frontend *fe, midend *me)
1832 { 1656 {
1833 HMENU oldmenu = GetMenu(fe->hwnd); 1657 HMENU oldmenu = GetMenu(fe->hwnd);
1834 1658
1835#ifndef _WIN32_WCE
1836 HMENU bar = CreateMenu(); 1659 HMENU bar = CreateMenu();
1837 HMENU menu = CreateMenu(); 1660 HMENU menu = CreateMenu();
1838 RECT menusize; 1661 RECT menusize;
1839 1662
1840 AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "&Game"); 1663 AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT_PTR)menu, "&Game");
1841#else
1842 HMENU menu = SHGetSubMenu(SHFindMenuBar(fe->hwnd), ID_GAME);
1843 DeleteMenu(menu, 0, MF_BYPOSITION);
1844#endif
1845 fe->gamemenu = menu; 1664 fe->gamemenu = menu;
1846 AppendMenu(menu, MF_ENABLED, IDM_NEW, TEXT("&New")); 1665 AppendMenu(menu, MF_ENABLED, IDM_NEW, TEXT("&New"));
1847 AppendMenu(menu, MF_ENABLED, IDM_RESTART, TEXT("&Restart")); 1666 AppendMenu(menu, MF_ENABLED, IDM_RESTART, TEXT("&Restart"));
1848#ifndef _WIN32_WCE
1849 /* ...here I run out of sensible accelerator characters. */ 1667 /* ...here I run out of sensible accelerator characters. */
1850 AppendMenu(menu, MF_ENABLED, IDM_DESC, TEXT("Speci&fic...")); 1668 AppendMenu(menu, MF_ENABLED, IDM_DESC, TEXT("Speci&fic..."));
1851 AppendMenu(menu, MF_ENABLED, IDM_SEED, TEXT("Rando&m Seed...")); 1669 AppendMenu(menu, MF_ENABLED, IDM_SEED, TEXT("Rando&m Seed..."));
1852#endif
1853 1670
1854 assert(!fe->preset_menu); 1671 assert(!fe->preset_menu);
1855 1672
@@ -1863,14 +1680,9 @@ static int fe_set_midend(frontend *fe, midend *me)
1863 fe->preset_menuitems[i].which_menu = NULL; 1680 fe->preset_menuitems[i].which_menu = NULL;
1864 } 1681 }
1865 if (fe->preset_menu->n_entries > 0 || fe->game->can_configure) { 1682 if (fe->preset_menu->n_entries > 0 || fe->game->can_configure) {
1866#ifndef _WIN32_WCE
1867 HMENU sub = CreateMenu(); 1683 HMENU sub = CreateMenu();
1868 1684
1869 AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)sub, "&Type"); 1685 AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT_PTR)sub, "&Type");
1870#else
1871 HMENU sub = SHGetSubMenu(SHFindMenuBar(fe->hwnd), ID_TYPE);
1872 DeleteMenu(sub, 0, MF_BYPOSITION);
1873#endif
1874 1686
1875 populate_preset_menu(fe, fe->preset_menu, sub); 1687 populate_preset_menu(fe, fe->preset_menu, sub);
1876 1688
@@ -1884,27 +1696,25 @@ static int fe_set_midend(frontend *fe, midend *me)
1884 } 1696 }
1885 1697
1886#ifdef COMBINED 1698#ifdef COMBINED
1887#ifdef _WIN32_WCE
1888#error Windows CE does not support COMBINED build.
1889#endif
1890 { 1699 {
1891 HMENU games = CreateMenu(); 1700 HMENU games = CreateMenu();
1892 int i; 1701 int i;
1893 1702
1894 AppendMenu(menu, MF_SEPARATOR, 0, 0); 1703 AppendMenu(menu, MF_SEPARATOR, 0, 0);
1895 AppendMenu(menu, MF_ENABLED|MF_POPUP, (UINT)games, "&Other"); 1704 AppendMenu(menu, MF_ENABLED|MF_POPUP, (UINT_PTR)games, "&Other");
1896 for (i = 0; i < gamecount; i++) { 1705 for (i = 0; i < gamecount; i++) {
1897 if (strcmp(gamelist[i]->name, fe->game->name) != 0) { 1706 if (strcmp(gamelist[i]->name, fe->game->name) != 0) {
1898 /* only include those games that aren't the same as the 1707 /* only include those games that aren't the same as the
1899 * game we're currently playing. */ 1708 * game we're currently playing. */
1900 AppendMenu(games, MF_ENABLED, IDM_GAMES + i, gamelist[i]->name); 1709 AppendMenu(games, MF_ENABLED,
1710 IDM_GAME_BASE + MENUITEM_STEP * i,
1711 gamelist[i]->name);
1901 } 1712 }
1902 } 1713 }
1903 } 1714 }
1904#endif 1715#endif
1905 1716
1906 AppendMenu(menu, MF_SEPARATOR, 0, 0); 1717 AppendMenu(menu, MF_SEPARATOR, 0, 0);
1907#ifndef _WIN32_WCE
1908 AppendMenu(menu, MF_ENABLED, IDM_LOAD, TEXT("&Load...")); 1718 AppendMenu(menu, MF_ENABLED, IDM_LOAD, TEXT("&Load..."));
1909 AppendMenu(menu, MF_ENABLED, IDM_SAVE, TEXT("&Save...")); 1719 AppendMenu(menu, MF_ENABLED, IDM_SAVE, TEXT("&Save..."));
1910 AppendMenu(menu, MF_SEPARATOR, 0, 0); 1720 AppendMenu(menu, MF_SEPARATOR, 0, 0);
@@ -1912,27 +1722,23 @@ static int fe_set_midend(frontend *fe, midend *me)
1912 AppendMenu(menu, MF_ENABLED, IDM_PRINT, TEXT("&Print...")); 1722 AppendMenu(menu, MF_ENABLED, IDM_PRINT, TEXT("&Print..."));
1913 AppendMenu(menu, MF_SEPARATOR, 0, 0); 1723 AppendMenu(menu, MF_SEPARATOR, 0, 0);
1914 } 1724 }
1915#endif
1916 AppendMenu(menu, MF_ENABLED, IDM_UNDO, TEXT("Undo")); 1725 AppendMenu(menu, MF_ENABLED, IDM_UNDO, TEXT("Undo"));
1917 AppendMenu(menu, MF_ENABLED, IDM_REDO, TEXT("Redo")); 1726 AppendMenu(menu, MF_ENABLED, IDM_REDO, TEXT("Redo"));
1918#ifndef _WIN32_WCE
1919 if (fe->game->can_format_as_text_ever) { 1727 if (fe->game->can_format_as_text_ever) {
1920 AppendMenu(menu, MF_SEPARATOR, 0, 0); 1728 AppendMenu(menu, MF_SEPARATOR, 0, 0);
1921 AppendMenu(menu, MF_ENABLED, IDM_COPY, TEXT("&Copy")); 1729 AppendMenu(menu, MF_ENABLED, IDM_COPY, TEXT("&Copy"));
1922 } 1730 }
1923#endif
1924 if (fe->game->can_solve) { 1731 if (fe->game->can_solve) {
1925 AppendMenu(menu, MF_SEPARATOR, 0, 0); 1732 AppendMenu(menu, MF_SEPARATOR, 0, 0);
1926 AppendMenu(menu, MF_ENABLED, IDM_SOLVE, TEXT("Sol&ve")); 1733 AppendMenu(menu, MF_ENABLED, IDM_SOLVE, TEXT("Sol&ve"));
1927 } 1734 }
1928 AppendMenu(menu, MF_SEPARATOR, 0, 0); 1735 AppendMenu(menu, MF_SEPARATOR, 0, 0);
1929#ifndef _WIN32_WCE 1736 AppendMenu(menu, MF_ENABLED, IDM_PREFS, TEXT("Pre&ferences"));
1737 AppendMenu(menu, MF_SEPARATOR, 0, 0);
1930 AppendMenu(menu, MF_ENABLED, IDM_QUIT, TEXT("E&xit")); 1738 AppendMenu(menu, MF_ENABLED, IDM_QUIT, TEXT("E&xit"));
1931 menu = CreateMenu(); 1739 menu = CreateMenu();
1932 AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, TEXT("&Help")); 1740 AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT_PTR)menu, TEXT("&Help"));
1933#endif
1934 AppendMenu(menu, MF_ENABLED, IDM_ABOUT, TEXT("&About")); 1741 AppendMenu(menu, MF_ENABLED, IDM_ABOUT, TEXT("&About"));
1935#ifndef _WIN32_WCE
1936 if (help_type != NONE) { 1742 if (help_type != NONE) {
1937 char *item; 1743 char *item;
1938 AppendMenu(menu, MF_SEPARATOR, 0, 0); 1744 AppendMenu(menu, MF_SEPARATOR, 0, 0);
@@ -1947,7 +1753,6 @@ static int fe_set_midend(frontend *fe, midend *me)
1947 SetMenu(fe->hwnd, bar); 1753 SetMenu(fe->hwnd, bar);
1948 get_menu_size(fe->hwnd, &menusize); 1754 get_menu_size(fe->hwnd, &menusize);
1949 fe->xmin = (menusize.right - menusize.left) + 25; 1755 fe->xmin = (menusize.right - menusize.left) + 25;
1950#endif
1951 } 1756 }
1952 1757
1953 if (fe->bitmap) DeleteObject(fe->bitmap); 1758 if (fe->bitmap) DeleteObject(fe->bitmap);
@@ -1968,36 +1773,6 @@ static void show_window(frontend *fe)
1968 midend_redraw(fe->me); 1773 midend_redraw(fe->me);
1969} 1774}
1970 1775
1971#ifdef _WIN32_WCE
1972static HFONT dialog_title_font()
1973{
1974 static HFONT hf = NULL;
1975 LOGFONT lf;
1976
1977 if (hf)
1978 return hf;
1979
1980 memset (&lf, 0, sizeof(LOGFONT));
1981 lf.lfHeight = -11; /* - ((8 * GetDeviceCaps(hdc, LOGPIXELSY)) / 72) */
1982 lf.lfWeight = FW_BOLD;
1983 wcscpy(lf.lfFaceName, TEXT("Tahoma"));
1984
1985 return hf = CreateFontIndirect(&lf);
1986}
1987
1988static void make_dialog_full_screen(HWND hwnd)
1989{
1990 SHINITDLGINFO shidi;
1991
1992 /* Make dialog full screen */
1993 shidi.dwMask = SHIDIM_FLAGS;
1994 shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIZEDLGFULLSCREEN |
1995 SHIDIF_EMPTYMENU;
1996 shidi.hDlg = hwnd;
1997 SHInitDialog(&shidi);
1998}
1999#endif
2000
2001static int CALLBACK AboutDlgProc(HWND hwnd, UINT msg, 1776static int CALLBACK AboutDlgProc(HWND hwnd, UINT msg,
2002 WPARAM wParam, LPARAM lParam) 1777 WPARAM wParam, LPARAM lParam)
2003{ 1778{
@@ -2005,39 +1780,15 @@ static int CALLBACK AboutDlgProc(HWND hwnd, UINT msg,
2005 1780
2006 switch (msg) { 1781 switch (msg) {
2007 case WM_INITDIALOG: 1782 case WM_INITDIALOG:
2008#ifdef _WIN32_WCE
2009 {
2010 char title[256];
2011
2012 make_dialog_full_screen(hwnd);
2013
2014 sprintf(title, "About %.250s", fe->game->name);
2015 SetDlgItemTextA(hwnd, IDC_ABOUT_CAPTION, title);
2016
2017 SendDlgItemMessage(hwnd, IDC_ABOUT_CAPTION, WM_SETFONT,
2018 (WPARAM) dialog_title_font(), 0);
2019
2020 SetDlgItemTextA(hwnd, IDC_ABOUT_GAME, fe->game->name);
2021 SetDlgItemTextA(hwnd, IDC_ABOUT_VERSION, ver);
2022 }
2023#endif
2024 return 1; 1783 return 1;
2025 1784
2026 case WM_COMMAND: 1785 case WM_COMMAND:
2027 if (LOWORD(wParam) == IDOK) 1786 if (LOWORD(wParam) == IDOK)
2028#ifdef _WIN32_WCE
2029 EndDialog(hwnd, 1);
2030#else
2031 fe->dlg_done = 1; 1787 fe->dlg_done = 1;
2032#endif
2033 return 0; 1788 return 0;
2034 1789
2035 case WM_CLOSE: 1790 case WM_CLOSE:
2036#ifdef _WIN32_WCE
2037 EndDialog(hwnd, 1);
2038#else
2039 fe->dlg_done = 1; 1791 fe->dlg_done = 1;
2040#endif
2041 return 0; 1792 return 0;
2042 } 1793 }
2043 1794
@@ -2137,119 +1888,6 @@ static const char *frontend_set_config(
2137 } 1888 }
2138} 1889}
2139 1890
2140#ifdef _WIN32_WCE
2141/* Separate version of mkctrl function for the Pocket PC. */
2142/* Control coordinates should be specified in dialog units. */
2143HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2,
2144 LPCTSTR wclass, int wstyle,
2145 int exstyle, const char *wtext, INT_PTR wid)
2146{
2147 RECT rc;
2148 TCHAR wwtext[256];
2149
2150 /* Convert dialog units into pixels */
2151 rc.left = x1; rc.right = x2;
2152 rc.top = y1; rc.bottom = y2;
2153 MapDialogRect(fe->cfgbox, &rc);
2154
2155 MultiByteToWideChar (CP_ACP, 0, wtext, -1, wwtext, 256);
2156
2157 return CreateWindowEx(exstyle, wclass, wwtext,
2158 wstyle | WS_CHILD | WS_VISIBLE,
2159 rc.left, rc.top,
2160 rc.right - rc.left, rc.bottom - rc.top,
2161 fe->cfgbox, (HMENU) wid, fe->inst, NULL);
2162}
2163
2164static void create_config_controls(frontend * fe)
2165{
2166 int id, nctrls;
2167 int col1l, col1r, col2l, col2r, y;
2168 config_item *i;
2169 struct cfg_aux *j;
2170 HWND ctl;
2171
2172 /* Control placement done in dialog units */
2173 col1l = 4; col1r = 96; /* Label column */
2174 col2l = 100; col2r = 154; /* Input column (edit boxes and combo boxes) */
2175
2176 /*
2177 * Count the controls so we can allocate cfgaux.
2178 */
2179 for (nctrls = 0, i = fe->cfg; i->type != C_END; i++)
2180 nctrls++;
2181 fe->cfgaux = snewn(nctrls, struct cfg_aux);
2182
2183 id = 1000;
2184 y = 22; /* Leave some room for the dialog title */
2185 for (i = fe->cfg, j = fe->cfgaux; i->type != C_END; i++, j++) {
2186 switch (i->type) {
2187 case C_STRING:
2188 /*
2189 * Edit box with a label beside it.
2190 */
2191 mkctrl(fe, col1l, col1r, y + 1, y + 11,
2192 TEXT("Static"), SS_LEFTNOWORDWRAP, 0, i->name, id++);
2193 mkctrl(fe, col2l, col2r, y, y + 12,
2194 TEXT("EDIT"), WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,
2195 0, "", (j->ctlid = id++));
2196 SetDlgItemTextA(fe->cfgbox, j->ctlid, i->u.string.sval);
2197 break;
2198
2199 case C_BOOLEAN:
2200 /*
2201 * Simple checkbox.
2202 */
2203 mkctrl(fe, col1l, col2r, y + 1, y + 11, TEXT("BUTTON"),
2204 BS_NOTIFY | BS_AUTOCHECKBOX | WS_TABSTOP,
2205 0, i->name, (j->ctlid = id++));
2206 CheckDlgButton(fe->cfgbox, j->ctlid, (i->u.boolean.bval != 0));
2207 break;
2208
2209 case C_CHOICES:
2210 /*
2211 * Drop-down list with a label beside it.
2212 */
2213 mkctrl(fe, col1l, col1r, y + 1, y + 11,
2214 TEXT("STATIC"), SS_LEFTNOWORDWRAP, 0, i->name, id++);
2215 ctl = mkctrl(fe, col2l, col2r, y, y + 48,
2216 TEXT("COMBOBOX"), WS_BORDER | WS_TABSTOP |
2217 CBS_DROPDOWNLIST | CBS_HASSTRINGS,
2218 0, "", (j->ctlid = id++));
2219 {
2220 char c;
2221 const char *p, *q;
2222 char *str;
2223
2224 p = i->u.choices.choicenames;
2225 c = *p++;
2226 while (*p) {
2227 q = p;
2228 while (*q && *q != c) q++;
2229 str = snewn(q-p+1, char);
2230 strncpy(str, p, q-p);
2231 str[q-p] = '\0';
2232 {
2233 TCHAR ws[50];
2234 MultiByteToWideChar (CP_ACP, 0, str, -1, ws, 50);
2235 SendMessage(ctl, CB_ADDSTRING, 0, (LPARAM)ws);
2236 }
2237
2238 sfree(str);
2239 if (*q) q++;
2240 p = q;
2241 }
2242 }
2243 SendMessage(ctl, CB_SETCURSEL, i->u.choices.selected, 0);
2244 break;
2245 }
2246
2247 y += 15;
2248 }
2249
2250}
2251#endif
2252
2253static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg, 1891static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
2254 WPARAM wParam, LPARAM lParam) 1892 WPARAM wParam, LPARAM lParam)
2255{ 1893{
@@ -2259,25 +1897,6 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
2259 1897
2260 switch (msg) { 1898 switch (msg) {
2261 case WM_INITDIALOG: 1899 case WM_INITDIALOG:
2262#ifdef _WIN32_WCE
2263 {
2264 char *title;
2265
2266 fe = (frontend *) lParam;
2267 SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
2268 fe->cfgbox = hwnd;
2269
2270 fe->cfg = frontend_get_config(fe, fe->cfg_which, &title);
2271
2272 make_dialog_full_screen(hwnd);
2273
2274 SetDlgItemTextA(hwnd, IDC_CONFIG_CAPTION, title);
2275 SendDlgItemMessage(hwnd, IDC_CONFIG_CAPTION, WM_SETFONT,
2276 (WPARAM) dialog_title_font(), 0);
2277
2278 create_config_controls(fe);
2279 }
2280#endif
2281 return 1; 1900 return 1;
2282 1901
2283 case WM_COMMAND: 1902 case WM_COMMAND:
@@ -2293,18 +1912,10 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
2293 MessageBox(hwnd, err, "Validation error", 1912 MessageBox(hwnd, err, "Validation error",
2294 MB_ICONERROR | MB_OK); 1913 MB_ICONERROR | MB_OK);
2295 } else { 1914 } else {
2296#ifdef _WIN32_WCE
2297 EndDialog(hwnd, 2);
2298#else
2299 fe->dlg_done = 2; 1915 fe->dlg_done = 2;
2300#endif
2301 } 1916 }
2302 } else { 1917 } else {
2303#ifdef _WIN32_WCE
2304 EndDialog(hwnd, 1);
2305#else
2306 fe->dlg_done = 1; 1918 fe->dlg_done = 1;
2307#endif
2308 } 1919 }
2309 return 0; 1920 return 0;
2310 } 1921 }
@@ -2321,13 +1932,7 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
2321 1932
2322 if (i->type == C_STRING && HIWORD(wParam) == EN_CHANGE) { 1933 if (i->type == C_STRING && HIWORD(wParam) == EN_CHANGE) {
2323 char buffer[4096]; 1934 char buffer[4096];
2324#ifdef _WIN32_WCE
2325 TCHAR wBuffer[4096];
2326 GetDlgItemText(fe->cfgbox, j->ctlid, wBuffer, 4096);
2327 WideCharToMultiByte(CP_ACP, 0, wBuffer, -1, buffer, 4096, NULL, NULL);
2328#else
2329 GetDlgItemText(fe->cfgbox, j->ctlid, buffer, lenof(buffer)); 1935 GetDlgItemText(fe->cfgbox, j->ctlid, buffer, lenof(buffer));
2330#endif
2331 buffer[lenof(buffer)-1] = '\0'; 1936 buffer[lenof(buffer)-1] = '\0';
2332 sfree(i->u.string.sval); 1937 sfree(i->u.string.sval);
2333 i->u.string.sval = dupstr(buffer); 1938 i->u.string.sval = dupstr(buffer);
@@ -2351,7 +1956,6 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
2351 return 0; 1956 return 0;
2352} 1957}
2353 1958
2354#ifndef _WIN32_WCE
2355HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2, 1959HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2,
2356 char *wclass, int wstyle, 1960 char *wclass, int wstyle,
2357 int exstyle, const char *wtext, INT_PTR wid) 1961 int exstyle, const char *wtext, INT_PTR wid)
@@ -2363,13 +1967,9 @@ HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2,
2363 SendMessage(ret, WM_SETFONT, (WPARAM)fe->cfgfont, MAKELPARAM(true, 0)); 1967 SendMessage(ret, WM_SETFONT, (WPARAM)fe->cfgfont, MAKELPARAM(true, 0));
2364 return ret; 1968 return ret;
2365} 1969}
2366#endif
2367 1970
2368static void about(frontend *fe) 1971static void about(frontend *fe)
2369{ 1972{
2370#ifdef _WIN32_WCE
2371 DialogBox(fe->inst, MAKEINTRESOURCE(IDD_ABOUT), fe->hwnd, AboutDlgProc);
2372#else
2373 int i; 1973 int i;
2374 WNDCLASS wc; 1974 WNDCLASS wc;
2375 MSG msg; 1975 MSG msg;
@@ -2518,19 +2118,10 @@ static void about(frontend *fe)
2518 SetForegroundWindow(fe->hwnd); 2118 SetForegroundWindow(fe->hwnd);
2519 DestroyWindow(fe->cfgbox); 2119 DestroyWindow(fe->cfgbox);
2520 DeleteObject(fe->cfgfont); 2120 DeleteObject(fe->cfgfont);
2521#endif
2522} 2121}
2523 2122
2524static bool get_config(frontend *fe, int which) 2123static bool get_config(frontend *fe, int which)
2525{ 2124{
2526#ifdef _WIN32_WCE
2527 fe->cfg_which = which;
2528
2529 return DialogBoxParam(fe->inst,
2530 MAKEINTRESOURCE(IDD_CONFIG),
2531 fe->hwnd, ConfigDlgProc,
2532 (LPARAM) fe) == 2;
2533#else
2534 config_item *i; 2125 config_item *i;
2535 struct cfg_aux *j; 2126 struct cfg_aux *j;
2536 char *title; 2127 char *title;
@@ -2770,38 +2361,8 @@ static bool get_config(frontend *fe, int which)
2770 sfree(fe->cfgaux); 2361 sfree(fe->cfgaux);
2771 2362
2772 return (fe->dlg_done == 2); 2363 return (fe->dlg_done == 2);
2773#endif
2774} 2364}
2775 2365
2776#ifdef _WIN32_WCE
2777static void calculate_bitmap_position(frontend *fe, int x, int y)
2778{
2779 /* Pocket PC - center the game in the full screen window */
2780 int yMargin;
2781 RECT rcClient;
2782
2783 GetClientRect(fe->hwnd, &rcClient);
2784 fe->bitmapPosition.left = (rcClient.right - x) / 2;
2785 yMargin = rcClient.bottom - y;
2786
2787 if (fe->numpad != NULL) {
2788 RECT rcPad;
2789 GetWindowRect(fe->numpad, &rcPad);
2790 yMargin -= rcPad.bottom - rcPad.top;
2791 }
2792
2793 if (fe->statusbar != NULL) {
2794 RECT rcStatus;
2795 GetWindowRect(fe->statusbar, &rcStatus);
2796 yMargin -= rcStatus.bottom - rcStatus.top;
2797 }
2798
2799 fe->bitmapPosition.top = yMargin / 2;
2800
2801 fe->bitmapPosition.right = fe->bitmapPosition.left + x;
2802 fe->bitmapPosition.bottom = fe->bitmapPosition.top + y;
2803}
2804#else
2805static void calculate_bitmap_position(frontend *fe, int x, int y) 2366static void calculate_bitmap_position(frontend *fe, int x, int y)
2806{ 2367{
2807 /* Plain Windows - position the game in the upper-left corner */ 2368 /* Plain Windows - position the game in the upper-left corner */
@@ -2810,7 +2371,6 @@ static void calculate_bitmap_position(frontend *fe, int x, int y)
2810 fe->bitmapPosition.right = fe->bitmapPosition.left + x; 2371 fe->bitmapPosition.right = fe->bitmapPosition.left + x;
2811 fe->bitmapPosition.bottom = fe->bitmapPosition.top + y; 2372 fe->bitmapPosition.bottom = fe->bitmapPosition.top + y;
2812} 2373}
2813#endif
2814 2374
2815static void new_bitmap(frontend *fe, int x, int y) 2375static void new_bitmap(frontend *fe, int x, int y)
2816{ 2376{
@@ -2830,12 +2390,12 @@ static void new_game_size(frontend *fe, float scale)
2830 int x, y; 2390 int x, y;
2831 2391
2832 get_max_puzzle_size(fe, &x, &y); 2392 get_max_puzzle_size(fe, &x, &y);
2833 midend_size(fe->me, &x, &y, false); 2393 midend_size(fe->me, &x, &y, false, 1.0);
2834 2394
2835 if (scale != 1.0) { 2395 if (scale != 1.0) {
2836 x = (int)((float)x * fe->puzz_scale); 2396 x = (int)((float)x * fe->puzz_scale);
2837 y = (int)((float)y * fe->puzz_scale); 2397 y = (int)((float)y * fe->puzz_scale);
2838 midend_size(fe->me, &x, &y, true); 2398 midend_size(fe->me, &x, &y, true, 1.0);
2839 } 2399 }
2840 fe->ymin = (fe->xmin * y) / x; 2400 fe->ymin = (fe->xmin * y) / x;
2841 2401
@@ -2849,26 +2409,19 @@ static void new_game_size(frontend *fe, float scale)
2849 } else { 2409 } else {
2850 sr.left = sr.right = sr.top = sr.bottom = 0; 2410 sr.left = sr.right = sr.top = sr.bottom = 0;
2851 } 2411 }
2852#ifndef _WIN32_WCE
2853 SetWindowPos(fe->hwnd, NULL, 0, 0, 2412 SetWindowPos(fe->hwnd, NULL, 0, 0,
2854 r.right - r.left, 2413 r.right - r.left,
2855 r.bottom - r.top + sr.bottom - sr.top, 2414 r.bottom - r.top + sr.bottom - sr.top,
2856 SWP_NOMOVE | SWP_NOZORDER); 2415 SWP_NOMOVE | SWP_NOZORDER);
2857#endif
2858 2416
2859 check_window_size(fe, &x, &y); 2417 check_window_size(fe, &x, &y);
2860 2418
2861#ifndef _WIN32_WCE
2862 if (fe->statusbar != NULL) 2419 if (fe->statusbar != NULL)
2863 SetWindowPos(fe->statusbar, NULL, 0, y, x, 2420 SetWindowPos(fe->statusbar, NULL, 0, y, x,
2864 sr.bottom - sr.top, SWP_NOZORDER); 2421 sr.bottom - sr.top, SWP_NOZORDER);
2865#endif
2866 2422
2867 new_bitmap(fe, x, y); 2423 new_bitmap(fe, x, y);
2868 2424
2869#ifdef _WIN32_WCE
2870 InvalidateRect(fe->hwnd, NULL, true);
2871#endif
2872 midend_redraw(fe->me); 2425 midend_redraw(fe->me);
2873} 2426}
2874 2427
@@ -2895,13 +2448,13 @@ static void adjust_game_size(frontend *fe, RECT *proposed, bool isedge,
2895 ydiff = (proposed->bottom - proposed->top) - (wr.bottom - wr.top); 2448 ydiff = (proposed->bottom - proposed->top) - (wr.bottom - wr.top);
2896 2449
2897 if (isedge) { 2450 if (isedge) {
2898 /* These next four lines work around the fact that midend_size 2451 /* These next four lines work around the fact that midend_size
2899 * is happy to shrink _but not grow_ if you change one dimension 2452 * is happy to shrink _but not grow_ if you change one dimension
2900 * but not the other. */ 2453 * but not the other. */
2901 if (xdiff > 0 && ydiff == 0) 2454 if (xdiff > 0 && ydiff == 0)
2902 ydiff = (xdiff * (wr.right - wr.left)) / (wr.bottom - wr.top); 2455 ydiff = (xdiff * (wr.right - wr.left)) / (wr.bottom - wr.top);
2903 if (xdiff == 0 && ydiff > 0) 2456 if (xdiff == 0 && ydiff > 0)
2904 xdiff = (ydiff * (wr.bottom - wr.top)) / (wr.right - wr.left); 2457 xdiff = (ydiff * (wr.bottom - wr.top)) / (wr.right - wr.left);
2905 } 2458 }
2906 2459
2907 if (check_window_resize(fe, 2460 if (check_window_resize(fe,
@@ -2951,6 +2504,138 @@ static void update_type_menu_tick(frontend *fe)
2951 DrawMenuBar(fe->hwnd); 2504 DrawMenuBar(fe->hwnd);
2952} 2505}
2953 2506
2507static char *prefs_dir(void)
2508{
2509 const char *var;
2510 if ((var = getenv("APPDATA")) != NULL) {
2511 size_t size = strlen(var) + 80;
2512 char *dir = snewn(size, char);
2513 sprintf(dir, "%s\\Simon Tatham's Portable Puzzle Collection", var);
2514 return dir;
2515 }
2516 return NULL;
2517}
2518
2519static char *prefs_path_general(const game *game, const char *suffix)
2520{
2521 char *dir, *path;
2522
2523 dir = prefs_dir();
2524 if (!dir)
2525 return NULL;
2526
2527 path = make_prefs_path(dir, "\\", game, suffix);
2528
2529 sfree(dir);
2530 return path;
2531}
2532
2533static char *prefs_path(const game *game)
2534{
2535 return prefs_path_general(game, ".conf");
2536}
2537
2538static char *prefs_tmp_path(const game *game)
2539{
2540 return prefs_path_general(game, ".tmp");
2541}
2542
2543static void load_prefs(midend *me)
2544{
2545 const game *game = midend_which_game(me);
2546 char *path = prefs_path(game);
2547 if (!path)
2548 return;
2549 FILE *fp = fopen(path, "r");
2550 if (!fp)
2551 return;
2552 const char *err = midend_load_prefs(me, savefile_read, fp);
2553 fclose(fp);
2554 if (err)
2555 fprintf(stderr, "Unable to load preferences file %s:\n%s\n",
2556 path, err);
2557 sfree(path);
2558}
2559
2560static char *save_prefs(midend *me)
2561{
2562 const game *game = midend_which_game(me);
2563 char *dir_path = prefs_dir();
2564 char *file_path = prefs_path(game);
2565 char *tmp_path = prefs_tmp_path(game);
2566 HANDLE fh;
2567 FILE *fp;
2568 bool cleanup_dir = false, cleanup_tmpfile = false;
2569 char *err = NULL;
2570
2571 if (!dir_path || !file_path || !tmp_path) {
2572 sprintf(err = snewn(256, char),
2573 "Unable to save preferences:\n"
2574 "Could not determine pathname for configuration files");
2575 goto out;
2576 }
2577
2578 if (!CreateDirectory(dir_path, NULL)) {
2579 /* Ignore errors while trying to make the directory. It may
2580 * well already exist, and even if we got some error code
2581 * other than EEXIST, it's still worth at least _trying_ to
2582 * make the file inside it, and see if that goes wrong. */
2583 } else {
2584 cleanup_dir = true;
2585 }
2586
2587 fh = CreateFile(tmp_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2588 FILE_ATTRIBUTE_NORMAL, NULL);
2589 if (fh == INVALID_HANDLE_VALUE) {
2590 char *os_err = geterrstr();
2591 sprintf(err = snewn(256 + strlen(tmp_path) + strlen(os_err), char),
2592 "Unable to save preferences:\n"
2593 "Unable to create file '%s':\n%s", tmp_path, os_err);
2594 sfree(os_err);
2595 goto out;
2596 } else {
2597 cleanup_tmpfile = true;
2598 }
2599
2600 fp = _fdopen(_open_osfhandle((intptr_t)fh, 0), "w");
2601 SetLastError(0);
2602 midend_save_prefs(me, savefile_write, fp);
2603 fclose(fp);
2604 if (GetLastError()) {
2605 char *os_err = geterrstr();
2606 sprintf(err = snewn(80 + strlen(tmp_path) + strlen(os_err), char),
2607 "Unable to write file '%s':\n%s", tmp_path, os_err);
2608 sfree(os_err);
2609 goto out;
2610 }
2611
2612 if (MoveFileEx(tmp_path, file_path, MOVEFILE_REPLACE_EXISTING) < 0) {
2613 char *os_err = geterrstr();
2614 sprintf(err = snewn(256 + strlen(tmp_path) + strlen(file_path) +
2615 strlen(os_err), char),
2616 "Unable to save preferences:\n"
2617 "Unable to rename '%s' to '%s':\n%s", tmp_path, file_path,
2618 os_err);
2619 sfree(os_err);
2620 goto out;
2621 } else {
2622 cleanup_dir = false;
2623 cleanup_tmpfile = false;
2624 }
2625
2626 out:
2627 if (cleanup_tmpfile) {
2628 if (!DeleteFile(tmp_path)) { /* can't do anything about this */ }
2629 }
2630 if (cleanup_dir) {
2631 if (!RemoveDirectory(dir_path)) { /* can't do anything about this */ }
2632 }
2633 sfree(dir_path);
2634 sfree(file_path);
2635 sfree(tmp_path);
2636 return err;
2637}
2638
2954static void update_copy_menu_greying(frontend *fe) 2639static void update_copy_menu_greying(frontend *fe)
2955{ 2640{
2956 UINT enable = (midend_can_format_as_text_now(fe->me) ? 2641 UINT enable = (midend_can_format_as_text_now(fe->me) ?
@@ -2990,28 +2675,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
2990 DestroyWindow(hwnd); 2675 DestroyWindow(hwnd);
2991 return 0; 2676 return 0;
2992 case WM_COMMAND: 2677 case WM_COMMAND:
2993#ifdef _WIN32_WCE
2994 /* Numeric pad sends WM_COMMAND messages */
2995 if ((wParam >= IDM_KEYEMUL) && (wParam < IDM_KEYEMUL + 256))
2996 {
2997 midend_process_key(fe->me, 0, 0, wParam - IDM_KEYEMUL);
2998 }
2999#endif
3000 cmd = wParam & ~0xF; /* low 4 bits reserved to Windows */ 2678 cmd = wParam & ~0xF; /* low 4 bits reserved to Windows */
3001 switch (cmd) { 2679 switch (cmd) {
3002 case IDM_NEW: 2680 case IDM_NEW:
3003 if (!midend_process_key(fe->me, 0, 0, UI_NEWGAME)) 2681 if (midend_process_key(fe->me, 0, 0, UI_NEWGAME) == PKR_QUIT)
3004 PostQuitMessage(0); 2682 PostQuitMessage(0);
3005 break; 2683 break;
3006 case IDM_RESTART: 2684 case IDM_RESTART:
3007 midend_restart_game(fe->me); 2685 midend_restart_game(fe->me);
3008 break; 2686 break;
3009 case IDM_UNDO: 2687 case IDM_UNDO:
3010 if (!midend_process_key(fe->me, 0, 0, UI_UNDO)) 2688 if (midend_process_key(fe->me, 0, 0, UI_UNDO) == PKR_QUIT)
3011 PostQuitMessage(0); 2689 PostQuitMessage(0);
3012 break; 2690 break;
3013 case IDM_REDO: 2691 case IDM_REDO:
3014 if (!midend_process_key(fe->me, 0, 0, UI_REDO)) 2692 if (midend_process_key(fe->me, 0, 0, UI_REDO) == PKR_QUIT)
3015 PostQuitMessage(0); 2693 PostQuitMessage(0);
3016 break; 2694 break;
3017 case IDM_COPY: 2695 case IDM_COPY:
@@ -3033,7 +2711,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
3033 } 2711 }
3034 break; 2712 break;
3035 case IDM_QUIT: 2713 case IDM_QUIT:
3036 if (!midend_process_key(fe->me, 0, 0, UI_QUIT)) 2714 if (midend_process_key(fe->me, 0, 0, UI_QUIT) == PKR_QUIT)
3037 PostQuitMessage(0); 2715 PostQuitMessage(0);
3038 break; 2716 break;
3039 case IDM_CONFIG: 2717 case IDM_CONFIG:
@@ -3052,6 +2730,16 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
3052 if (get_config(fe, CFG_PRINT)) 2730 if (get_config(fe, CFG_PRINT))
3053 print(fe); 2731 print(fe);
3054 break; 2732 break;
2733 case IDM_PREFS:
2734 if (get_config(fe, CFG_PREFS)) {
2735 char *prefs_err = save_prefs(fe->me);
2736 if (prefs_err) {
2737 MessageBox(fe->hwnd, prefs_err, "Error saving preferences",
2738 MB_ICONERROR | MB_OK);
2739 sfree(prefs_err);
2740 }
2741 }
2742 break;
3055 case IDM_ABOUT: 2743 case IDM_ABOUT:
3056 about(fe); 2744 about(fe);
3057 break; 2745 break;
@@ -3173,7 +2861,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
3173 } 2861 }
3174 2862
3175 break; 2863 break;
3176#ifndef _WIN32_WCE
3177 case IDM_HELPC: 2864 case IDM_HELPC:
3178 start_help(fe, NULL); 2865 start_help(fe, NULL);
3179 break; 2866 break;
@@ -3182,34 +2869,38 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
3182 start_help(fe, help_type == CHM ? 2869 start_help(fe, help_type == CHM ?
3183 fe->game->htmlhelp_topic : fe->game->winhelp_topic); 2870 fe->game->htmlhelp_topic : fe->game->winhelp_topic);
3184 break; 2871 break;
3185#endif 2872 default: {
3186 default: 2873 unsigned n;
2874
3187#ifdef COMBINED 2875#ifdef COMBINED
3188 if (wParam >= IDM_GAMES && wParam < (IDM_GAMES + (WPARAM)gamecount)) { 2876 n = (wParam - IDM_GAME_BASE) / MENUITEM_STEP;
3189 int p = wParam - IDM_GAMES; 2877 if (n < gamecount && wParam == IDM_GAME_BASE + MENUITEM_STEP * n) {
3190 char *error = NULL; 2878 char *error = NULL;
3191 fe_set_midend(fe, midend_for_new_game(fe, gamelist[p], NULL, 2879 fe_set_midend(fe, midend_for_new_game(fe, gamelist[n], NULL,
3192 false, false, &error)); 2880 false, false, &error));
3193 sfree(error); 2881 sfree(error);
3194 } else 2882 break;
2883 }
3195#endif 2884#endif
3196 { 2885
2886 n = (wParam - IDM_PRESET_BASE) / MENUITEM_STEP;
2887 if (wParam == IDM_PRESET_BASE + MENUITEM_STEP * n) {
3197 game_params *preset = preset_menu_lookup_by_id( 2888 game_params *preset = preset_menu_lookup_by_id(
3198 fe->preset_menu, 2889 fe->preset_menu, n);
3199 ((wParam &~ 0xF) - IDM_PRESETS) / 0x10);
3200 2890
3201 if (preset) { 2891 if (preset) {
3202 midend_set_params(fe->me, preset); 2892 midend_set_params(fe->me, preset);
3203 new_game_type(fe); 2893 new_game_type(fe);
2894 break;
3204 } 2895 }
3205 } 2896 }
3206 break; 2897
2898 break;
2899 }
3207 } 2900 }
3208 break; 2901 break;
3209 case WM_DESTROY: 2902 case WM_DESTROY:
3210#ifndef _WIN32_WCE
3211 stop_help(fe); 2903 stop_help(fe);
3212#endif
3213 frontend_free(fe); 2904 frontend_free(fe);
3214 PostQuitMessage(0); 2905 PostQuitMessage(0);
3215 return 0; 2906 return 0;
@@ -3223,9 +2914,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
3223 hdc = BeginPaint(hwnd, &p); 2914 hdc = BeginPaint(hwnd, &p);
3224 hdc2 = CreateCompatibleDC(hdc); 2915 hdc2 = CreateCompatibleDC(hdc);
3225 prevbm = SelectObject(hdc2, fe->bitmap); 2916 prevbm = SelectObject(hdc2, fe->bitmap);
3226#ifdef _WIN32_WCE
3227 FillRect(hdc, &(p.rcPaint), (HBRUSH) GetStockObject(WHITE_BRUSH));
3228#endif
3229 IntersectRect(&rcDest, &(fe->bitmapPosition), &(p.rcPaint)); 2917 IntersectRect(&rcDest, &(fe->bitmapPosition), &(p.rcPaint));
3230 BitBlt(hdc, 2918 BitBlt(hdc,
3231 rcDest.left, rcDest.top, 2919 rcDest.left, rcDest.top,
@@ -3310,7 +2998,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
3310 } 2998 }
3311 2999
3312 if (key != -1) { 3000 if (key != -1) {
3313 if (!midend_process_key(fe->me, 0, 0, key)) 3001 if (midend_process_key(fe->me, 0, 0, key) == PKR_QUIT)
3314 PostQuitMessage(0); 3002 PostQuitMessage(0);
3315 } else { 3003 } else {
3316 MSG m; 3004 MSG m;
@@ -3338,32 +3026,12 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
3338 else if (message == WM_RBUTTONDOWN || is_alt_pressed()) 3026 else if (message == WM_RBUTTONDOWN || is_alt_pressed())
3339 button = RIGHT_BUTTON; 3027 button = RIGHT_BUTTON;
3340 else 3028 else
3341#ifndef _WIN32_WCE
3342 button = LEFT_BUTTON; 3029 button = LEFT_BUTTON;
3343#else
3344 if ((fe->game->flags & REQUIRE_RBUTTON) == 0)
3345 button = LEFT_BUTTON;
3346 else
3347 {
3348 SHRGINFO shrgi;
3349
3350 shrgi.cbSize = sizeof(SHRGINFO);
3351 shrgi.hwndClient = hwnd;
3352 shrgi.ptDown.x = (signed short)LOWORD(lParam);
3353 shrgi.ptDown.y = (signed short)HIWORD(lParam);
3354 shrgi.dwFlags = SHRG_RETURNCMD;
3355
3356 if (GN_CONTEXTMENU == SHRecognizeGesture(&shrgi))
3357 button = RIGHT_BUTTON;
3358 else
3359 button = LEFT_BUTTON;
3360 }
3361#endif
3362 3030
3363 if (!midend_process_key(fe->me, 3031 if (midend_process_key(fe->me,
3364 (signed short)LOWORD(lParam) - fe->bitmapPosition.left, 3032 (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
3365 (signed short)HIWORD(lParam) - fe->bitmapPosition.top, 3033 (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
3366 button)) 3034 button) == PKR_QUIT)
3367 PostQuitMessage(0); 3035 PostQuitMessage(0);
3368 3036
3369 SetCapture(hwnd); 3037 SetCapture(hwnd);
@@ -3387,10 +3055,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
3387 else 3055 else
3388 button = LEFT_RELEASE; 3056 button = LEFT_RELEASE;
3389 3057
3390 if (!midend_process_key(fe->me, 3058 if (midend_process_key(fe->me,
3391 (signed short)LOWORD(lParam) - fe->bitmapPosition.left, 3059 (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
3392 (signed short)HIWORD(lParam) - fe->bitmapPosition.top, 3060 (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
3393 button)) 3061 button) == PKR_QUIT)
3394 PostQuitMessage(0); 3062 PostQuitMessage(0);
3395 3063
3396 ReleaseCapture(); 3064 ReleaseCapture();
@@ -3407,10 +3075,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
3407 else 3075 else
3408 button = LEFT_DRAG; 3076 button = LEFT_DRAG;
3409 3077
3410 if (!midend_process_key(fe->me, 3078 if (midend_process_key(fe->me,
3411 (signed short)LOWORD(lParam) - fe->bitmapPosition.left, 3079 (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
3412 (signed short)HIWORD(lParam) - fe->bitmapPosition.top, 3080 (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
3413 button)) 3081 button) == PKR_QUIT)
3414 PostQuitMessage(0); 3082 PostQuitMessage(0);
3415 } 3083 }
3416 break; 3084 break;
@@ -3424,7 +3092,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
3424 (keystate[VK_CONTROL] & 0x80)) 3092 (keystate[VK_CONTROL] & 0x80))
3425 key = UI_REDO; 3093 key = UI_REDO;
3426 } 3094 }
3427 if (!midend_process_key(fe->me, 0, 0, key)) 3095 if (midend_process_key(fe->me, 0, 0, key) == PKR_QUIT)
3428 PostQuitMessage(0); 3096 PostQuitMessage(0);
3429 } 3097 }
3430 return 0; 3098 return 0;
@@ -3436,7 +3104,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
3436 fe->timer_last_tickcount = now; 3104 fe->timer_last_tickcount = now;
3437 } 3105 }
3438 return 0; 3106 return 0;
3439#ifndef _WIN32_WCE
3440 case WM_SIZING: 3107 case WM_SIZING:
3441 { 3108 {
3442 RECT *sr = (RECT *)lParam; 3109 RECT *sr = (RECT *)lParam;
@@ -3468,29 +3135,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
3468 return true; 3135 return true;
3469 } 3136 }
3470 break; 3137 break;
3471#endif
3472 } 3138 }
3473 3139
3474 return DefWindowProc(hwnd, message, wParam, lParam); 3140 return DefWindowProc(hwnd, message, wParam, lParam);
3475} 3141}
3476 3142
3477#ifdef _WIN32_WCE
3478static int FindPreviousInstance()
3479{
3480 /* Check if application is running. If it's running then focus on the window */
3481 HWND hOtherWnd = NULL;
3482
3483 hOtherWnd = FindWindow (wGameName, wGameName);
3484 if (hOtherWnd)
3485 {
3486 SetForegroundWindow (hOtherWnd);
3487 return true;
3488 }
3489
3490 return false;
3491}
3492#endif
3493
3494/* 3143/*
3495 * Split a complete command line into argc/argv, attempting to do it 3144 * Split a complete command line into argc/argv, attempting to do it
3496 * exactly the same way the Visual Studio C library would do it (so 3145 * exactly the same way the Visual Studio C library would do it (so
@@ -3723,12 +3372,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
3723 3372
3724 split_into_argv(cmdline, &argc, &argv, NULL); 3373 split_into_argv(cmdline, &argc, &argv, NULL);
3725 3374
3726#ifdef _WIN32_WCE
3727 MultiByteToWideChar (CP_ACP, 0, CLASSNAME, -1, wClassName, 256);
3728 if (FindPreviousInstance ())
3729 return 0;
3730#endif
3731
3732 InitCommonControls(); 3375 InitCommonControls();
3733 3376
3734 if (!prev) { 3377 if (!prev) {
@@ -3740,18 +3383,12 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
3740 wndclass.cbWndExtra = 0; 3383 wndclass.cbWndExtra = 0;
3741 wndclass.hInstance = inst; 3384 wndclass.hInstance = inst;
3742 wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(200)); 3385 wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(200));
3743#ifndef _WIN32_WCE
3744 if (!wndclass.hIcon) /* in case resource file is absent */ 3386 if (!wndclass.hIcon) /* in case resource file is absent */
3745 wndclass.hIcon = LoadIcon(inst, IDI_APPLICATION); 3387 wndclass.hIcon = LoadIcon(inst, IDI_APPLICATION);
3746#endif
3747 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); 3388 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
3748 wndclass.hbrBackground = NULL; 3389 wndclass.hbrBackground = NULL;
3749 wndclass.lpszMenuName = NULL; 3390 wndclass.lpszMenuName = NULL;
3750#ifdef _WIN32_WCE
3751 wndclass.lpszClassName = wClassName;
3752#else
3753 wndclass.lpszClassName = CLASSNAME; 3391 wndclass.lpszClassName = CLASSNAME;
3754#endif
3755 3392
3756 RegisterClass(&wndclass); 3393 RegisterClass(&wndclass);
3757 } 3394 }