Compare commits

...

167 Commits

Author SHA1 Message Date
ad6a39e82a move env.h -> scripts/ 2023-12-29 18:37:52 +01:00
3a857e4d53 2022 day 16 (C): use same eval() for parts 1 & 2. 2023-04-20 08:31:16 +02:00
f80a051177 2022 day 17 init 2023-04-19 14:09:42 +02:00
129fa07787 2022 day 16: Part 2, sooo slooowww (6m40s) 2023-04-18 17:12:41 +02:00
1472082c86 2022 day 16 part 1 (C) - before cleaning useless permutation code 2023-04-11 09:42:58 +02:00
e8bed49e13 2022 day 16 (C): first parse and helper functions 2023-04-09 12:00:41 +02:00
83d70dcc7a 2022: update (C) notices 2023-04-09 11:59:26 +02:00
56d2e63fac 2022 day 15 (C): remove hash for part 1, simplify code 2023-04-03 18:15:37 +02:00
5c91de5d40 2022 day 15: final version (C) 2023-04-02 20:57:44 +02:00
40a9c7b12e 2022 day 15 part 2: improved solution (20,000 times faster) 2023-04-02 19:50:00 +02:00
34b6cd7b57 2022 day 15 part 2 (C). First version: 18s, ~30,000,000 func calls 2023-04-02 19:45:55 +02:00
5ad5c87fd8 2022: init day 16 2023-04-01 13:54:28 +02:00
11e7b45676 2022 day 15: start part 2 data structure 2023-03-30 10:38:03 +02:00
3f2a5648df debug: add debug_level_get() 2023-03-25 13:32:03 +01:00
0a3b404c4c 2022 day 15: part 2 (C) 2023-03-25 13:31:40 +01:00
a214d2b70d common C code: add "-t" option for test mode. 2023-03-22 08:43:46 +01:00
f490c2353e 2022 day 15 (C) part 1 (dirty and even more) 2023-03-21 11:17:04 +01:00
2ed6284bcd 2022 day 15 init 2023-03-18 17:50:59 +01:00
5fc204744a 2022 day 14 (C): final version. Too hacky for me... 2023-03-18 17:30:26 +01:00
d1cf8d96b8 2022 day 14, parts 1 & 2, before cleaning 2023-03-18 16:35:08 +01:00
b285f74997 2022 day 14: init 2023-01-20 20:25:55 +01:00
c949c64da2 day 22 day 13 (C) simplify/comment code 2023-01-12 10:34:32 +01:00
357e8ce087 fix wrong org conversion (brackets become links in code blocks) 2023-01-11 20:16:51 +01:00
5cde9051ec 2022 day 13 (C) final version - more cleanup needed 2023-01-10 22:14:59 +01:00
111fde4fbd 2022 day 13 (C) before cleaning 2023-01-10 22:00:55 +01:00
f54479189b 2022 day 13 part 1 (C) 2023-01-07 18:17:02 +01:00
8e00fec33c PJW hash: add credits 2023-01-07 18:16:18 +01:00
d0376f21c3 2022 day 12 (C, parts 1 & 2) 2022-12-24 21:06:10 +01:00
04a856dc47 Makefile: clean keeps compile_commands.json 2022-12-24 21:05:33 +01:00
0658ffdd7d 2022 day 13 init 2022-12-23 11:41:30 +01:00
efe0dec8f0 2022 day 12 Bash final version 2022-12-22 21:38:26 +01:00
6d4a8dd85b Bash 2022 day 12 (parts 1 & 2), before cleaning code 2022-12-22 21:33:29 +01:00
11cb3c5c64 2022 day 11 final (C) 2022-12-21 15:46:07 +01:00
7e0a21704e 2022 day 11: C first version (parts 1 and 2) 2022-12-21 13:34:28 +01:00
008599e79c 2022 day 11, Bash speedup (40-50%) 2022-12-20 17:29:47 +01:00
fe381ae7f0 Bash: 2022 day 11. Part 2 is ~29 secs 2022-12-20 15:03:42 +01:00
4a0749999e 2022 day 11: Bash parts 1 & 2, before cleaning 2022-12-20 14:47:29 +01:00
18720b9e09 2022 day 10: C, parts 1 and 2. Should be useful if this "machine"...
... comes back in next days puzzles (my guess is that it will ;-)
2022-12-18 14:33:45 +01:00
17e140f235 br.h: add __unused and __used macros 2022-12-18 14:22:18 +01:00
a1e436babc C: remove dead code in 2022/day 9 2022-12-17 18:50:10 +01:00
02a1dda786 2022 day 10: Bash parts 1 & 2 2022-12-17 16:05:49 +01:00
ef29ca28a1 2022: init day 10 2022-12-17 12:25:11 +01:00
c1b3e83c68 2022 day 9: C parts 1 and 2 2022-12-17 11:28:12 +01:00
bd2548fca9 pjwhash: char* to void* 2022-12-17 11:27:40 +01:00
3f5b282883 2022 day 9 Bash: reduce code by 40%, increase speed by 40% 2022-12-13 19:33:29 +01:00
38ef781f0a 2022 day 9: Bash part 2, same code for both part (slower #1) 2022-12-13 18:38:24 +01:00
13d183de79 2022 day 9, Bash part 1 2022-12-13 16:02:50 +01:00
dfe2207e8e init day 9 2022-12-12 20:47:45 +01:00
31a255a9ac 2020 day 8 (C, both parts. No inspiration here) 2022-12-12 20:46:09 +01:00
25d25b399e 2022 day 8: bash final 2022-12-11 18:44:55 +01:00
f5ebb5c5cc 2022 day 8: Bash parts 1 & 2 2022-12-11 18:36:21 +01:00
c608f6dcde 2022 day 8 init 2022-12-10 16:53:33 +01:00
9e3a875e37 2022 day 7: C final version (parts 1 & 2) 2022-12-10 16:43:34 +01:00
4c0f6e3025 2022 day 7: C, parts 1 & 2 2022-12-10 14:56:46 +01:00
68f200ff65 2022: add PJW hash (lib) 2022-12-10 14:56:31 +01:00
8aff410ff4 2020 / day 7: final Bash cleanup 2022-12-10 07:43:14 +01:00
16da47600c 2022 day 7: clean bash code & remove file size info (50% speed) 2022-12-09 20:34:05 +01:00
8b68bf4449 2022 day 7: Bash parts 1 and 2 (messy, tons of debug) 2022-12-09 20:23:26 +01:00
c86517897e 2022 day 7 init 2022-12-09 16:42:45 +01:00
9c999e9717 2022 day 6: C (parts 1 and 2) 2022-12-09 16:25:56 +01:00
05643127c2 2022 day 6: Bash part 2 (lucky me: part 1 code worked) + optimizations 2022-12-09 14:38:21 +01:00
6a5a0da435 2022 day 6 init + bash part 1 2022-12-09 14:14:58 +01:00
3dd072c53e 2022 day 5 (C) 2022-12-09 11:47:32 +01:00
8f09fcf13f 2022 day 5 bash: simplify code (final ?) 2022-12-08 16:52:58 +01:00
8f444d7341 fix day # in comment 2022-12-08 16:30:55 +01:00
d7fa1c4fb5 Bash: 2022 day 5 (both parts, brute code) 2022-12-08 16:09:32 +01:00
0c787d9a51 2022/bash: move LANG=C to common.bash 2022-12-08 12:52:54 +01:00
64ad068ec8 2022/day 5 init 2022-12-08 12:45:04 +01:00
ab73311d6b 2022 day 4: C, parts 1 & 2 (lazy way: same algo as Bash) 2022-12-08 12:21:12 +01:00
d116b98ae9 Bash 2022/day4: remove nearly everything :-) 2022-12-08 11:45:40 +01:00
325c8254b8 Bash: 2022 day 4 part 2 2022-12-08 09:50:06 +01:00
76ab3d0c5b Bash: 2022/day 4 part 1 2022-12-08 09:43:43 +01:00
bc2b2ac726 C: 2022/Day 3 final cleanup + more comments 2022-12-08 08:19:57 +01:00
b7c0b1fa01 C 2022/Day 4 init 2022-12-08 08:18:27 +01:00
487766c0a2 C: 2022 day 3, remove useless code / variables 2022-12-07 22:21:19 +01:00
a0fddb5f44 2022 day 3 / cleanup some C code, update RESULTS.txt 2022-12-07 21:49:48 +01:00
f68d5b319e 2020 / day 3: C first working version (parts 1 & 2) 2022-12-07 21:38:46 +01:00
9455b99342 bash: 2022 day 3 (final 2 parts) 2022-12-07 19:07:16 +01:00
ea4967bfcd 2022 day 3 (bash, working version before cleanup) 2022-12-07 18:45:52 +01:00
d1026e8f59 2022 day 3 part 1 (bash) 2022-12-07 17:31:29 +01:00
01cdce6608 C: 2022 day 2 2022-12-07 15:37:00 +01:00
b8f6763a3b forgot 2022-12-07 13:40:01 +01:00
81a58c6266 update lib from tools repo (some fixed for 32 bits) 2022-12-07 13:20:48 +01:00
ca06a4a355 typo in printf 2022-12-07 13:20:29 +01:00
9d375aecfc 2022 day 2 (bash) 2022-12-07 13:18:58 +01:00
d412824317 2020 day 10 (C): fix for 32 bits architecture (ooops !) 2022-12-06 17:18:22 +01:00
d8e05b0fca 2020/day2: fix for 32 bits arch 2022-12-06 15:45:00 +01:00
a49a2ed073 debug.h: tentatively build on 32 bits arch 2022-12-06 15:17:04 +01:00
2c14abff21 bits.h: move popcount32() up 2022-12-06 14:43:16 +01:00
50919df627 bits.h: tentatively build on 32 bits arch 2022-12-06 14:41:28 +01:00
73c9fa8150 typo 2022-12-06 14:39:06 +01:00
b949e11314 2020: update lib source files (trying to compile on 32 bits arch) 2022-12-06 14:27:10 +01:00
f003511e10 pool.c: please valgrind 2022-12-03 14:50:37 +01:00
36f763830f 2020: Tentative C & Bash frameworks (common functions) 2022-12-03 14:42:37 +01:00
c7553e7849 plist.h: add some reverse macros 2022-12-03 14:40:35 +01:00
Bruno
6012d4d375 2022/day 1 (C) - save from laptop 2022-12-02 10:32:02 +01:00
ce446be296 cleanup code 2022-12-01 10:48:09 +01:00
a8cab0c7c3 2022 day1: fix global Makefile, RESULTS.txt 2022-12-01 10:31:17 +01:00
dbff06e5da 2022 day 1: prepare bash common code + bash solutions 2022-12-01 10:28:40 +01:00
0fb4219c92 init AoC 2022, cleanup useless files 2022-12-01 07:50:35 +01:00
58ba8b4ab8 2020 day 21: init for C version 2022-11-30 20:24:23 +01:00
cca3d6fbe5 2020 day 22: release memory 2022-11-30 13:17:57 +01:00
cfba08b197 typo 2022-11-29 21:00:11 +01:00
ca8de49d5e 2020 day 22/2 (C) - clean code 2022-11-29 20:53:07 +01:00
ea9c144127 2020 day 22 part 2 (C, 1st version) 2022-11-29 19:14:53 +01:00
d4d5af0cb6 2020 day 22 part 1 (C) 2022-10-28 12:08:59 +02:00
5ee230df69 2020 day 22: init for C version 2022-10-27 20:24:37 +02:00
9fe7b64263 typo 2022-10-27 20:08:38 +02:00
8df13f9713 2020/19 (C): cleanup code 2022-10-27 16:14:48 +02:00
74ab0ba990 2020 part 2 (C). 2022-10-27 15:22:44 +02:00
46dee29af6 cleanup README.org 2022-10-26 19:21:39 +02:00
ad7c6f3042 add len in message (for future CYK implementation) 2022-10-26 19:19:41 +02:00
d485983efc 2020/19, add C results for part 1. 2022-10-24 20:37:02 +02:00
23c33894a5 2020 day 19 part 1 (C) - won't work for part 2 !! 2022-10-24 20:15:25 +02:00
9bd03e0650 day 23: typos 2022-10-24 20:14:53 +02:00
6de646f0d1 C: 2020 day 23, part 1 and 2 2022-10-22 18:37:37 +02:00
a525ab6338 change name 2022-10-22 18:36:50 +02:00
2de0c3c9c8 list.h: add list_bulk_move() 2022-10-22 18:35:37 +02:00
6e4c64db39 2020/23 (C) update Makefile, switch to .org readme 2022-10-20 10:12:09 +02:00
b73db03da9 add env.sh 2022-10-20 10:05:16 +02:00
f6d1fe7b9d 2020/23 bash: unify the 2 parts code 2022-10-20 08:51:10 +02:00
30cdb5e1a4 update repo README 2022-10-19 19:19:05 +02:00
b4a2603c7b C: 2020 day 24 - switch to 32 bits hash, rename some var/fct. 2022-10-19 19:02:03 +02:00
abcc4af572 C: day 24 final version + RESULTS.txt cleanup 2022-10-19 18:14:02 +02:00
94f0d95544 C: 2020 day 24 part 2 (dirty code) 2022-10-19 17:16:20 +02:00
452a912fe5 2020 library 2022-10-18 18:11:53 +02:00
46d6b77596 2020 day 24 part 1: C 2022-10-18 17:52:19 +02:00
65c03075f1 switch README to org-mode / add ccls compile_commands.json generation 2022-10-11 20:47:43 +02:00
4a565af1c2 Copy Makefile from 2019 2022-10-11 20:22:33 +02:00
0a03bc557b git-ignoire compile_commands.json 2022-10-11 18:44:38 +02:00
282d55c3cd 2020 day 25 (C): just copied my (lazy/brute-force) bash solution 2022-10-11 18:37:25 +02:00
920f830fac Re-use 2019 latest Makefile 2022-10-11 17:44:06 +02:00
e3d6b622dc 2020 day 25 (C): just copied my (lazy/brute-force) bash solution 2022-10-11 16:51:06 +02:00
5795d24ab4 2020 day 24: Add hexagon page link, for my future needs ;-) 2022-10-11 15:13:50 +02:00
86a62f0b2d update readme (2020 bash finished) 2022-10-10 19:46:29 +02:00
f3ae028751 2020 day 25 (bash) 2022-10-10 18:29:39 +02:00
d2b5a9dc34 2020 day 24 part 2 (bash) 2022-10-10 16:09:24 +02:00
563798871a 2020 day 24 (bash) part 1: simplify code 2022-10-09 14:34:50 +02:00
cced357154 2020 day 24 (bash) part 1. 2022-10-09 14:28:58 +02:00
4653101623 2020 day 24 init 2022-10-09 10:38:25 +02:00
0fb3d8832f typo 2022-10-08 22:00:22 +02:00
c30ca858e4 update README 2022-10-08 21:59:28 +02:00
cd41685cb5 Day 23 (bash) part 2 (~7mn run) 2022-10-08 21:34:13 +02:00
d2d66dc763 2020 day 23 part 1: re-use part 2 (unfinished) code 2022-10-08 20:56:50 +02:00
284eeb3dea 2020 day 23 part 1 (bash). Ooops. This won't do part 2 :-( 2022-10-06 16:42:30 +02:00
f74a1ffb8a delete .projectile and .dir-locals.el 2022-10-05 16:36:57 +02:00
b001690c95 delete .projectile and .dir-locals.el 2022-10-05 16:31:28 +02:00
0fe04e43dc 2019 day 9: cleanup code (see TODO in commit notes)
TODO:
- rename peek/poke
- remove the costly test on valid instruction in run()
- use array for i/o instead of input and output.
   Then merge prg_{add,get}_{input,output}
- add a pipe function to move one program output to (another) input
- remember in next AoC to use _unused to keep interesting unused functions
2022-10-04 22:49:01 +02:00
bd851b6524 2019 day 09: parts 1 & 2 2022-10-04 22:04:50 +02:00
Bruno
1cfd1c81f0 day 19 day 9: save unfinished work from laptop 2022-10-04 12:12:48 +02:00
Bruno
130f2a4d54 2019 day 9 init from day 7 2022-10-04 07:34:29 +02:00
625966f5b8 2019 day 8: parts 1 & 2 2022-10-03 10:54:54 +02:00
521e6e1bca 2019 day 8 init 2022-10-01 19:52:56 +02:00
bacbc6eded typo 2022-10-01 19:49:43 +02:00
5694883ef5 2019 day 6: remove count of allocated tries/objects 2022-10-01 19:07:05 +02:00
6a43725e30 fix copyright year 2022-10-01 18:34:20 +02:00
4d938b6cd7 2019 day6: simplify code, remove forgotten outputs 2022-10-01 18:31:52 +02:00
0c9b93b42a update copyright 2022-10-01 18:20:02 +02:00
04fcca5829 update copyright 2022-10-01 18:19:19 +02:00
ddfa8cf05b 2019 day 7, final version + update RESULTS.txt 2022-10-01 16:39:34 +02:00
5008963937 2019 day 7 part 2, before cleanup 2022-10-01 15:50:33 +02:00
155e066ed2 2019 day 7, part 1 2022-09-30 19:22:12 +02:00
626bd1df41 init 2019 day 7 with day 5 source, typo in day 6 2022-09-30 16:28:22 +02:00
8ed39e52b7 simplify part 2: use depths difference instead of two parent lists 2022-09-29 20:08:50 +02:00
e83b690822 2019 day 6 : add structure diagrams (Thanks Emacs' artist-mode !) 2022-09-29 19:41:51 +02:00
0004b2091e 2019 day 6: remove dead code, trie contains object ptr instead of object 2022-09-28 18:47:20 +02:00
a201283599 2019 day 6: parts 1 and 2, before cleaning (lots of printf ;-) 2022-09-28 15:25:01 +02:00
296 changed files with 34561 additions and 1360 deletions

9
.gitignore vendored
View File

@@ -2,6 +2,8 @@ ex*-c
aoc-c
core*
.ccls*
.projectile
.dir-locals.el
gmon.out
*.o
ex*-cob
@@ -9,8 +11,5 @@ lib/
GPATH
GRTAGS
GTAGS
2020/day23/
FOO*
BAR*
QUAX*
TOTO*
README.html
compile_commands.json

View File

@@ -1,4 +0,0 @@
((nil . ((eval . (let ((root (expand-file-name (projectile-project-root))))
(setq-local
flycheck-gcc-include-path (list (concat root "include"))
compile-command (concat "make -C " root " all")))))))

View File

View File

@@ -1,6 +1,6 @@
# AOC Makefile - GNU make only.
#
# Copyright (C) 2021 Bruno Raoult ("br")
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#

View File

@@ -67,3 +67,66 @@ aoc-c : res=10987514
aoc-c : res=14195011
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+87
=========================================
================= day06 =================
=========================================
+++++++++++++++++ part 1
compiling aoc-c.c
aoc-c : res=453028
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+417
+++++++++++++++++ part 2
aoc-c : res=562
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+417
=========================================
================= day07 =================
=========================================
+++++++++++++++++ part 1
aoc-c : res=65464
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+94
+++++++++++++++++ part 2
aoc-c : res=1518124
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+94
=========================================
================= day08 =================
=========================================
+++++++++++++++++ part 1
aoc-c : res=2250
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+93
+++++++++++++++++ part 2
#### # # ## # # #
# # # # # # #
### #### # # # #
# # # # # # #
# # # # # # # #
# # # ## ## ####
aoc-c : res=0
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+90
=========================================
================= day09 =================
=========================================
+++++++++++++++++ part 1
aoc-c : res=2682107844
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+92
+++++++++++++++++ part 2
aoc-c : res=34738
time: 0:00.01 real, 0.01 user, 0.00 sys
context-switch: 1+1, page-faults: 0+95

View File

@@ -1,6 +1,6 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021 Bruno Raoult ("br")
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#

View File

@@ -1,6 +1,6 @@
/* aoc-c.c: Advent of Code 2019, day 1 parts 1 & 2
*
* Copyright (C) 2021 Bruno Raoult ("br")
* Copyright (C) 2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*

View File

@@ -1,6 +1,6 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021 Bruno Raoult ("br")
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#

View File

@@ -1,6 +1,6 @@
/* aoc-c.c: Advent of Code 2019, day 2 parts 1 & 2
*
* Copyright (C) 2021 Bruno Raoult ("br")
* Copyright (C) 2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*

View File

@@ -1,6 +1,6 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021 Bruno Raoult ("br")
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#

View File

@@ -1,6 +1,6 @@
/* aoc-c.c: Advent of Code 2019, day 3 parts 1 & 2
*
* Copyright (C) 2021 Bruno Raoult ("br")
* Copyright (C) 2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*

View File

@@ -1,6 +1,6 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021 Bruno Raoult ("br")
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#

View File

@@ -1,6 +1,6 @@
/* aoc-c.c: Advent of Code 2019, day 4 parts 1 & 2
*
* Copyright (C) 2021 Bruno Raoult ("br")
* Copyright (C) 2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*

View File

@@ -1,6 +1,6 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021 Bruno Raoult ("br")
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#

View File

@@ -1,6 +1,6 @@
/* aoc-c.c: Advent of Code 2019, day 5 parts 1 & 2
*
* Copyright (C) 2021 Bruno Raoult ("br")
* Copyright (C) 2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*

13
2019/day06/EXAMPLE2.txt Normal file
View File

@@ -0,0 +1,13 @@
COM)B
B)C
C)D
D)E
E)F
B)G
G)H
D)I
E)J
J)K
K)L
K)YOU
I)SAN

View File

@@ -1,6 +1,6 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021 Bruno Raoult ("br")
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#

View File

@@ -76,3 +76,72 @@ The total number of direct and indirect orbits in this example is =42=.
/What is the total number of direct and indirect orbits/ in your map
data?
Your puzzle answer was =453028=.
** --- Part Two ---
Now, you just need to figure out how many /orbital transfers/ you
(=YOU=) need to take to get to Santa (=SAN=).
You start at the object =YOU= are orbiting; your destination is the
object =SAN= is orbiting. An orbital transfer lets you move from any
object to an object orbiting or orbited by that object.
For example, suppose you have the following map:
#+BEGIN_EXAMPLE
COM)B
B)C
C)D
D)E
E)F
B)G
G)H
D)I
E)J
J)K
K)L
K)YOU
I)SAN
#+END_EXAMPLE
Visually, the above map of orbits looks like this:
#+BEGIN_EXAMPLE
YOU
/
G - H J - K - L
/ /
COM - B - C - D - E - F
\
I - SAN
#+END_EXAMPLE
In this example, =YOU= are in orbit around =K=, and =SAN= is in orbit
around =I=. To move from =K= to =I=, a minimum of =4= orbital transfers
are required:
- =K= to =J=
- =J= to =E=
- =E= to =D=
- =D= to =I=
Afterward, the map of orbits looks like this:
#+BEGIN_EXAMPLE
G - H J - K - L
/ /
COM - B - C - D - E - F
\
I - SAN
\
YOU
#+END_EXAMPLE
/What is the minimum number of orbital transfers required/ to move from
the object =YOU= are orbiting to the object =SAN= is orbiting? (Between
the objects they are orbiting - /not/ between =YOU= and =SAN=.)
Your puzzle answer was =562=.
Both parts of this puzzle are complete! They provide two gold stars: **

270
2019/day06/aoc-c.c Normal file
View File

@@ -0,0 +1,270 @@
/* aoc-c.c: Advent of Code 2019, day 6 parts 1 & 2
*
* Copyright (C) 2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*/
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <malloc.h>
#include <getopt.h>
#include <stdlib.h>
#include "br.h"
#include "debug.h"
#include "pool.h"
/**
* As the character set is [1-9A-Z], the trie arrays size will be 26 + 9 = 35,
* organized as:
* char: 1 2 ... 8 9 A B ... Y Z
* index: 0 1 ... 7 8 9 10 ... 33 34
*/
#define TRIESIZE ('Z' - 'A' + 1 + '9' - '1' + 1)
#define c2index(c) ((c) >= 'A'? (c) - 'A' + 9: (c) - '1')
#define index2c(c) ((c) >= 9? (c) + 'A' - 9: (c) + '1')
/**
* object_t - object representation
* @parent: a pointer to the object we orbit around
* @sibling: a list of objects orbiting around @parent
* @child: a list of object orbiting around this object
* @name: the object name
*
* Example: if N1 and N2 orbit around O and S orbits around N1, we will
* have :
* +---------+
* +---->| 0 |<---------+
* | |---------| |
* | | parent |--->NIL |
* | |---------| |
* +-------------------+---->| child |<---------+-----------------+
* | | |---------| | |
* | | +-->| sibling |<--+ | |
* | | | +---------+ | | |
* | | | | | |
* | +---------+ | +-----------------+ | +---------+ |
* | | N1 |<---+-----+ | | N2 | |
* | |---------| | | | |---------| |
* | | parent |----+ | +--| parent | |
* | |---------| | |---------| |
* | +->| child |<---------+----+ NIL<---| child | |
* | | |---------| | | |---------| |
* +-+->| sibling |<---------+----+----------------->| sibling |<---+
* | +---------+ | | +---------+
* | | |
* | +---------+ | |
* | | S | | |
* | |---------| | |
* | | parent |----------+ |
* | |---------| |
* | | child |--->NIL |
* | |---------| |
* +->| sibling |<--------------+
* +---------+
*
*/
typedef struct object {
struct object *parent;
struct list_head sibling, child;
char name[8];
} object_t;
/**
* trie_t - trie node
* @child: array of pointers to trie_t children of current node
* @object: pointer to object data (NULL if node only)
*
* For example, if objects N1, N2, and S exist, the structure will be:
*
* Root trie
* +--------+-------------------------------------+
* | object | 0 | 1 | ... | N | ... | S | ... | Z |
* +--------+---------------+---------------------+
* | | | | |
* v v | | v
* NIL NIL | | NIL
* +----------------------------+ +-----+
* | "N" trie | "S" trie
* | +--------+-------------+ | +--------------------------+
* +-->| object | 0 | ... | Z | +->| object | 0 | 1 | 2 | ... |
* +--------+-------------+ +--------------------------+
* | | | | | | |
* | v v v v | |
* | NIL NIL NIL NIL | |
* | +---------------------------------+ |
* | | +-----------+
* | | "S1" trie | "S2" trie
* | | +------------------+ | +------------------+
* | +-->| object | 0 | ... | +-->| object | 0 | ... |
* | +------------------+ +------------------+
* | | | | |
* | | v | v
* v v NIL v NIL
* +-----------+ +-----------+ +-----------+
* | Object N | | Object S1 | | Object S2 |
* +-----------+ +-----------+ +-----------+
*/
typedef struct trie {
struct trie *child[TRIESIZE];
object_t *object;
} trie_t;
static pool_t *pool_tries, *pool_objects;
static trie_t *trie_get(trie_t *parent, char *name, int pos)
{
trie_t *trie;
if ((trie = pool_get(pool_tries))) {
for (int i = 0; i < TRIESIZE; ++i)
trie->child[i] = NULL;
trie->object = NULL;
if (parent)
parent->child[c2index(name[pos])] = trie;
}
return trie;
}
static trie_t *trie_find(trie_t *root, char *name)
{
int len = strlen(name);
for (int i = 0; i < len; ++i) {
int ind = c2index(name[i]);
root = root->child[ind] ? root->child[ind]: trie_get(root, name, i);
}
return root;
}
static object_t *object_find(trie_t *root, char *name)
{
trie_t *trie = trie_find(root, name);
if (!trie->object) {
trie->object = pool_get(pool_objects);
trie->object->parent = NULL;
strcpy(trie->object->name, name);
INIT_LIST_HEAD(&trie->object->child);
INIT_LIST_HEAD(&trie->object->sibling);
}
return trie->object;
}
/**
* get_orbits - get all orbits (direct and indirect) around an object
* @object: object address
* @depth: depth of current object
*/
static int get_orbits(object_t *object, int depth)
{
int ret = depth;
object_t *cur;
if (!list_empty(&object->child))
list_for_each_entry(cur, &object->child, sibling)
ret += get_orbits(cur, depth + 1);
return ret;
}
static int part1(trie_t *root, char *name)
{
object_t *object = object_find(root, name);
return get_orbits(object, 0);
}
/**
* get_depth - get depth of an object in a tree
* @object: object address
* Return: object depth
*/
static int get_depth(object_t *obj)
{
int res = 0;
for (; obj; obj = obj->parent)
res++;
return res;
}
static int part2(trie_t *root, char *name1, char *name2)
{
object_t *obj1 = object_find(root, name1), *obj2 = object_find(root, name2);
int count = 0, depth1, depth2;
depth1 = get_depth(obj1);
depth2 = get_depth(obj2);
/* ensure highest depth is obj1
*/
if (depth1 < depth2) {
swap(obj1, obj2);
swap(depth1, depth2);
}
/* make the 2 depths equal
*/
for (; depth1 > depth2; count++, depth1--)
obj1 = obj1->parent;
/* find common parent
*/
for (; obj1 != obj2; count += 2) {
obj1 = obj1->parent;
obj2 = obj2->parent;
}
return count - 2; /* coz' we want parents objects */
}
static void parse(trie_t *root)
{
char str1[8], str2[8];
while (scanf(" %7[^)])%s", str1, str2) == 2) {
object_t *star = object_find(root, str1);
object_t *planet = object_find(root, str2);
/* link planet to star, add planet to star's planets list
*/
planet->parent = star;
list_add(&planet->sibling, &star->child);
}
}
static int usage(char *prg)
{
fprintf(stderr, "Usage: %s [-d debug_level] [-p part]\n", prg);
return 1;
}
int main(int ac, char **av)
{
int opt, part = 1;
while ((opt = getopt(ac, av, "d:p:")) != -1) {
switch (opt) {
case 'd':
debug_level_set(atoi(optarg));
break;
case 'p': /* 1 or 2 */
part = atoi(optarg);
if (part < 1 || part > 2)
default:
return usage(*av);
}
}
if (optind < ac)
return usage(*av);
pool_tries = pool_create("tries", 1024, sizeof(trie_t));
pool_objects = pool_create("objects", 1024, sizeof(object_t));
trie_t *root = trie_get(NULL, NULL, 0);
parse(root);
printf("%s : res=%d\n", *av,
part == 1 ? part1(root, "COM") : part2(root, "YOU", "SAN"));
pool_destroy(pool_tries);
pool_destroy(pool_objects);
exit (0);
}

1
2019/day07/EXAMPLE.txt Normal file
View File

@@ -0,0 +1 @@
3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0

1
2019/day07/EXAMPLE1.txt Normal file
View File

@@ -0,0 +1 @@
3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,0,0

1
2019/day07/EXAMPLE2.txt Normal file
View File

@@ -0,0 +1 @@
3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0

1
2019/day07/INPUT.txt Normal file
View File

@@ -0,0 +1 @@
3,8,1001,8,10,8,105,1,0,0,21,30,39,64,81,102,183,264,345,426,99999,3,9,1001,9,2,9,4,9,99,3,9,1002,9,4,9,4,9,99,3,9,1002,9,5,9,101,2,9,9,102,3,9,9,1001,9,2,9,1002,9,2,9,4,9,99,3,9,1002,9,3,9,1001,9,5,9,1002,9,3,9,4,9,99,3,9,102,4,9,9,1001,9,3,9,102,4,9,9,1001,9,5,9,4,9,99,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,99,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,99,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,101,1,9,9,4,9,99

93
2019/day07/Makefile Normal file
View File

@@ -0,0 +1,93 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := INPUT.txt
SHELL := /bin/bash
CC := gcc
LIB := aoc_$(shell uname -m)
INCDIR := ../include
LIBDIR := ../lib
LDFLAGS := -L$(LIBDIR)
#LDLIB := -l$(LIB) -lm
LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
#CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations
CFLAGS += -Wno-unused-result
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
--sigill-diagnostics=yes --quiet --show-error-list=yes
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH)
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
all: README.org ex1 ex2
memcheck: memcheck1 memcheck2
memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
memcheck2: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
compile: aoc-c
assembly: aoc-c.s
ex1: aoc-c
@$(TIME) aoc-c -p 1 < $(INPUT)
ex2: aoc-c
@$(TIME) aoc-c -p 2 < $(INPUT)
clean:
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
.c:
@echo compiling $<
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
# generate pre-processed file (.i) and assembler (.s)
%.i: %.c
@echo generating $@
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
%.s: %.c
@echo generating $@
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
# generate README.org from README.html (must cleanup !)
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@

167
2019/day07/README.org Normal file
View File

@@ -0,0 +1,167 @@
** --- Day 7: Amplification Circuit ---
Based on the navigational maps, you're going to need to send more power
to your ship's thrusters to reach Santa in time. To do this, you'll need
to configure a series of
[[https://en.wikipedia.org/wiki/Amplifier][amplifiers]] already
installed on the ship.
There are five amplifiers connected in series; each one receives an
input signal and produces an output signal. They are connected such that
the first amplifier's output leads to the second amplifier's input, the
second amplifier's output leads to the third amplifier's input, and so
on. The first amplifier's input value is =0=, and the last amplifier's
output leads to your ship's thrusters.
#+BEGIN_EXAMPLE
O-------O O-------O O-------O O-------O O-------O
0 ->| Amp A |->| Amp B |->| Amp C |->| Amp D |->| Amp E |-> (to thrusters)
O-------O O-------O O-------O O-------O O-------O
#+END_EXAMPLE
The Elves have sent you some /Amplifier Controller Software/ (your
puzzle input), a program that should run on your [[file:5][existing
Intcode computer]]. Each amplifier will need to run a copy of the
program.
When a copy of the program starts running on an amplifier, it will first
use an input instruction to ask the amplifier for its current /phase
setting/ (an integer from =0= to =4=). Each phase setting is used
/exactly once/, but the Elves can't remember which amplifier needs which
phase setting.
The program will then call another input instruction to get the
amplifier's input signal, compute the correct output signal, and supply
it back to the amplifier with an output instruction. (If the amplifier
has not yet received an input signal, it waits until one arrives.)
Your job is to /find the largest output signal that can be sent to the
thrusters/ by trying every possible combination of phase settings on the
amplifiers. Make sure that memory is not shared or reused between copies
of the program.
For example, suppose you want to try the phase setting sequence
=3,1,2,4,0=, which would mean setting amplifier =A= to phase setting
=3=, amplifier =B= to setting =1=, =C= to =2=, =D= to =4=, and =E= to
=0=. Then, you could determine the output signal that gets sent from
amplifier =E= to the thrusters with the following steps:
- Start the copy of the amplifier controller software that will run on
amplifier =A=. At its first input instruction, provide it the
amplifier's phase setting, =3=. At its second input instruction,
provide it the input signal, =0=. After some calculations, it will use
an output instruction to indicate the amplifier's output signal.
- Start the software for amplifier =B=. Provide it the phase setting
(=1=) and then whatever output signal was produced from amplifier =A=.
It will then produce a new output signal destined for amplifier =C=.
- Start the software for amplifier =C=, provide the phase setting (=2=)
and the value from amplifier =B=, then collect its output signal.
- Run amplifier =D='s software, provide the phase setting (=4=) and
input value, and collect its output signal.
- Run amplifier =E='s software, provide the phase setting (=0=) and
input value, and collect its output signal.
The final output signal from amplifier =E= would be sent to the
thrusters. However, this phase setting sequence may not have been the
best one; another sequence might have sent a higher signal to the
thrusters.
Here are some example programs:
- Max thruster signal /=43210=/ (from phase setting sequence
=4,3,2,1,0=):
#+BEGIN_EXAMPLE
3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0
#+END_EXAMPLE
- Max thruster signal /=54321=/ (from phase setting sequence
=0,1,2,3,4=):
#+BEGIN_EXAMPLE
3,23,3,24,1002,24,10,24,1002,23,-1,23,
101,5,23,23,1,24,23,23,4,23,99,0,0
#+END_EXAMPLE
- Max thruster signal /=65210=/ (from phase setting sequence
=1,0,4,3,2=):
#+BEGIN_EXAMPLE
3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,
1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0
#+END_EXAMPLE
Try every combination of phase settings on the amplifiers. /What is the
highest signal that can be sent to the thrusters?/
Your puzzle answer was =65464=.
** --- Part Two ---
It's no good - in this configuration, the amplifiers can't generate a
large enough output signal to produce the thrust you'll need. The Elves
quickly talk you through rewiring the amplifiers into a /feedback loop/:
#+BEGIN_EXAMPLE
O-------O O-------O O-------O O-------O O-------O
0 -+->| Amp A |->| Amp B |->| Amp C |->| Amp D |->| Amp E |-.
| O-------O O-------O O-------O O-------O O-------O |
| |
'--------------------------------------------------------+
|
v
(to thrusters)
#+END_EXAMPLE
Most of the amplifiers are connected as they were before; amplifier
=A='s output is connected to amplifier =B='s input, and so on.
/However,/ the output from amplifier =E= is now connected into amplifier
=A='s input. This creates the feedback loop: the signal will be sent
through the amplifiers /many times/.
In feedback loop mode, the amplifiers need /totally different phase
settings/: integers from =5= to =9=, again each used exactly once. These
settings will cause the Amplifier Controller Software to repeatedly take
input and produce output many times before halting. Provide each
amplifier its phase setting at its first input instruction; all further
input/output instructions are for signals.
Don't restart the Amplifier Controller Software on any amplifier during
this process. Each one should continue receiving and sending signals
until it halts.
All signals sent or received in this process will be between pairs of
amplifiers except the very first signal and the very last signal. To
start the process, a =0= signal is sent to amplifier =A='s input
/exactly once/.
Eventually, the software on the amplifiers will halt after they have
processed the final loop. When this happens, the last output signal from
amplifier =E= is sent to the thrusters. Your job is to /find the largest
output signal that can be sent to the thrusters/ using the new phase
settings and feedback loop arrangement.
Here are some example programs:
- Max thruster signal /=139629729=/ (from phase setting sequence
=9,8,7,6,5=):
#+BEGIN_EXAMPLE
3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,
27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5
#+END_EXAMPLE
- Max thruster signal /=18216=/ (from phase setting sequence
=9,7,8,5,6=):
#+BEGIN_EXAMPLE
3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54,
-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4,
53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10
#+END_EXAMPLE
Try every combination of the new phase settings on the amplifier
feedback loop. /What is the highest signal that can be sent to the
thrusters?/
Your puzzle answer was =1518124=.
Both parts of this puzzle are complete! They provide two gold stars: **

257
2019/day07/aoc-c.c Normal file
View File

@@ -0,0 +1,257 @@
/* aoc-c.c: Advent of Code 2019, day 7 parts 1 & 2
*
* Copyright (C) 2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "br.h"
#include "bits.h"
#include "debug.h"
#include "list.h"
#include "pool.h"
/* operators codes
*/
typedef enum {
ADD = 1, MUL = 2, /* CALC: add and mult */
INP = 3, OUT = 4, /* I/O: input and output value */
JMP_T = 5, JMP_F = 6, /* JUMPS: jump if true / if false */
SET_LT = 7, SET_EQ = 8, /* COND SETS: set if true/false */
HLT = 99 /* HALT */
} opcode_t;
/**
* ops - array of op-codes, mnemo, and number of parameters
* @op: An integer, the opcode
* @length: Next instruction offset
*/
typedef struct {
int op;
u8 length;
} ops_t;
typedef struct input {
int val;
struct list_head list;
} input_t;
#define MAXOPS 1024
typedef struct {
int length; /* total program length */
int cur; /* current position */
struct list_head input; /* process input queue */
int mem [MAXOPS]; /* should really be dynamic */
} program_t;
static ops_t ops[] = {
[ADD] = { ADD, 4 }, [MUL] = { MUL, 4 },
[INP] = { INP, 2 }, [OUT] = { OUT, 2 },
[JMP_T] = { JMP_T, 3 }, [JMP_F] = { JMP_F, 3 },
[SET_LT] = { SET_LT, 4 }, [SET_EQ] = { SET_EQ, 4 },
[HLT] = { HLT, 1 }
};
static int _flag_pow10[] = {1, 100, 1000, 10000};
#define OP(p, n) ((p->mem[n]) % 100)
#define ISDIRECT(p, n, i) ((((p->mem[n]) / _flag_pow10[i]) % 10))
#define DIRECT(p, i) ((p)->mem[i])
#define INDIRECT(p, i) (DIRECT(p, DIRECT(p, i)))
#define peek(p, n, i) (ISDIRECT(p, n, i)? DIRECT(p, n + i): INDIRECT(p, n + i))
#define poke(p, n, i, val) do { \
INDIRECT(p, n + i) = val; } \
while (0)
static pool_t *pool_input;
static __always_inline int prg_add_input(program_t *prg, int in)
{
input_t *input = pool_get(pool_input);
input->val = in;
list_add_tail(&input->list, &prg->input);
return in;
}
static __always_inline int prg_get_input(program_t *prg, int *out)
{
input_t *input = list_first_entry_or_null(&prg->input, input_t, list);
if (!input)
return 0;
*out = input->val;
list_del(&input->list);
pool_add(pool_input, input);
return 1;
}
/**
* permute - get next permutation of an array of integers
* @len: length of array
* @array: address of array
*
* Algorithm: lexicographic permutations
* https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
* Before the initial call, the array must be sorted (e.g. 0 2 3 5)
*
* Return: 1 if next permutation was found, 0 if no more permutation.
*
*/
static int permute_next(int len, int *array)
{
int k, l;
/* 1. Find the largest index k such that a[k] < a[k + 1] */
for (k = len - 2; k >= 0 && array[k] >= array[k + 1]; k--)
;
/* No more permutations */
if (k < 0)
return 0;
/* 2. Find the largest index l greater than k such that a[k] < a[l] */
for (l = len - 1; array[l] <= array[k]; l--)
;
/* 3. Swap the value of a[k] with that of a[l] */
swap(array[k], array[l]);
/* 4. Reverse sequence from a[k + 1] up to the final element */
for (l = len - 1, k++; k < l; k++, l--)
swap(array[k], array[l]);
return 1;
}
static int run(program_t *p, int *end)
{
int out = -1;
while (1) {
int op = OP(p, p->cur), cur = p->cur, input;
if (!(ops[op].op)) {
fprintf(stderr, "PANIC: illegal instruction %d at %d.\n", op, p->cur);
return -1;
}
switch (op) {
case ADD:
poke(p, p->cur, 3, peek(p, p->cur, 1) + peek(p, p->cur, 2));
break;
case MUL:
poke(p, p->cur, 3, peek(p, p->cur, 1) * peek(p, p->cur, 2));
break;
case INP:
if (prg_get_input(p, &input))
poke(p, p->cur, 1, input);
else
/* we need an input which is not yet avalaible, so we need
* to put the program in "waiting mode": We stop it (and
* return output value) without setting end flag.
*/
goto sleep;
break;
case OUT:
out = peek(p, p->cur, 1);
break;
case JMP_T:
if (peek(p, p->cur, 1))
p->cur = peek(p, p->cur, 2);
break;
case JMP_F:
if (!peek(p, p->cur, 1))
p->cur = peek(p, p->cur, 2);
break;
case SET_LT:
poke(p, p->cur, 3, peek(p, p->cur, 1) < peek(p, p->cur, 2) ? 1: 0);
break;
case SET_EQ:
poke(p, p->cur, 3, peek(p, p->cur, 1) == peek(p, p->cur, 2) ? 1: 0);
break;
case HLT:
*end = 1;
sleep:
return out;
}
if (p->cur == cur)
p->cur += ops[op].length;
}
}
static void parse(program_t *prog)
{
while (scanf("%d%*c", &prog->mem[prog->length++]) > 0)
;
}
static int usage(char *prg)
{
fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg);
return 1;
}
int main(int ac, char **av)
{
int phase1[] = {0, 1, 2, 3, 4}, phase2[] = {5, 6, 7, 8, 9}, *phase;
int opt, max = 0, part = 1;
program_t p = { 0 }, prg[5];
while ((opt = getopt(ac, av, "d:p:o:")) != -1) {
switch (opt) {
case 'd':
debug_level_set(atoi(optarg));
break;
case 'o':
for (ulong i = 0; i < strlen(optarg); ++i)
phase1[i] = optarg[i] - '0';
break;
case 'p': /* 1 or 2 */
part = atoi(optarg);
if (part < 1 || part > 2)
return usage(*av);
break;
default:
return usage(*av);
}
}
pool_input = pool_create("input", 128, sizeof(input_t));
if (optind < ac)
return usage(*av);
phase = part == 1? phase1: phase2;
parse(&p);
do {
int out = 0, end = 0;
/* reset programs initial state, and add phase to their input
*/
for (unsigned i = 0; i < ARRAY_SIZE(prg); ++i) {
prg[i] = p;
INIT_LIST_HEAD(&prg[i].input);
prg_add_input(&prg[i], phase[i]);
}
/* run the 5 processes in order (0, 1, 2, 3, 4, 0, 1, etc...),
* until end flag is set by the process 4 (HLT instruction)
*/
while (!end) {
for (int i = 0; i < 5; ++i) {
/* add last process output in current process input queue
*/
prg_add_input(&prg[i], out);
out = run(&prg[i], &end);
}
}
max = max(max, out);
} while (permute_next(5, phase));
printf("%s : res=%d\n", *av, max);
pool_destroy(pool_input);
exit(0);
}

1
2019/day08/EXAMPLE.txt Normal file
View File

@@ -0,0 +1 @@
0222112222120000

1
2019/day08/INPUT.txt Normal file

File diff suppressed because one or more lines are too long

93
2019/day08/Makefile Normal file
View File

@@ -0,0 +1,93 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := INPUT.txt
SHELL := /bin/bash
CC := gcc
LIB := aoc_$(shell uname -m)
INCDIR := ../include
LIBDIR := ../lib
LDFLAGS := -L$(LIBDIR)
#LDLIB := -l$(LIB) -lm
LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
#CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations
CFLAGS += -Wno-unused-result
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
--sigill-diagnostics=yes --quiet --show-error-list=yes
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH)
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
all: README.org ex1 ex2
memcheck: memcheck1 memcheck2
memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
memcheck2: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
compile: aoc-c
assembly: aoc-c.s
ex1: aoc-c
@$(TIME) aoc-c -p 1 < $(INPUT)
ex2: aoc-c
@$(TIME) aoc-c -p 2 < $(INPUT)
clean:
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
.c:
@echo compiling $<
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
# generate pre-processed file (.i) and assembler (.s)
%.i: %.c
@echo generating $@
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
%.s: %.c
@echo generating $@
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
# generate README.org from README.html (must cleanup !)
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@

99
2019/day08/README.org Normal file
View File

@@ -0,0 +1,99 @@
** --- Day 8: Space Image Format ---
The Elves' spirits are lifted when they realize you have an opportunity
to reboot one of their Mars rovers, and so they are curious if you would
spend a brief sojourn on Mars. You land your ship near the rover.
When you reach the rover, you discover that it's already in the process
of rebooting! It's just waiting for someone to enter a
[[https://en.wikipedia.org/wiki/BIOS][BIOS]] password. The Elf
responsible for the rover takes a picture of the password (your puzzle
input) and sends it to you via the Digital Sending Network.
Unfortunately, images sent via the Digital Sending Network aren't
encoded with any normal encoding; instead, they're encoded in a special
Space Image Format. None of the Elves seem to remember why this is the
case. They send you the instructions to decode it.
Images are sent as a series of digits that each represent the color of a
single pixel. The digits fill each row of the image left-to-right, then
move downward to the next row, filling rows top-to-bottom until every
pixel of the image is filled.
Each image actually consists of a series of identically-sized /layers/
that are filled in this way. So, the first digit corresponds to the
top-left pixel of the first layer, the second digit corresponds to the
pixel to the right of that on the same layer, and so on until the last
digit, which corresponds to the bottom-right pixel of the last layer.
For example, given an image =3= pixels wide and =2= pixels tall, the
image data =123456789012= corresponds to the following image layers:
#+BEGIN_EXAMPLE
Layer 1: 123
456
Layer 2: 789
012
#+END_EXAMPLE
The image you received is /=25= pixels wide and =6= pixels tall/.
To make sure the image wasn't corrupted during transmission, the Elves
would like you to find the layer that contains the /fewest =0= digits/.
On that layer, what is /the number of =1= digits multiplied by the
number of =2= digits?/
Your puzzle answer was =2250=.
** --- Part Two ---
Now you're ready to decode the image. The image is rendered by stacking
the layers and aligning the pixels with the same positions in each
layer. The digits indicate the color of the corresponding pixel: =0= is
black, =1= is white, and =2= is transparent.
The layers are rendered with the first layer in front and the last layer
in back. So, if a given position has a transparent pixel in the first
and second layers, a black pixel in the third layer, and a white pixel
in the fourth layer, the final image would have a /black/ pixel at that
position.
For example, given an image =2= pixels wide and =2= pixels tall, the
image data =0222112222120000= corresponds to the following image layers:
#+BEGIN_EXAMPLE
Layer 1: 02
22
Layer 2: 11
22
Layer 3: 22
12
Layer 4: 00
00
#+END_EXAMPLE
Then, the full image can be found by determining the top visible pixel
in each position:
- The top-left pixel is /black/ because the top layer is =0=.
- The top-right pixel is /white/ because the top layer is =2=
(transparent), but the second layer is =1=.
- The bottom-left pixel is /white/ because the top two layers are =2=,
but the third layer is =1=.
- The bottom-right pixel is /black/ because the only visible pixel in
that position is =0= (from layer 4).
So, the final image looks like this:
#+BEGIN_EXAMPLE
01
10
#+END_EXAMPLE
/What message is produced after decoding your image?/
Your puzzle answer was =FHJUL=.
Both parts of this puzzle are complete! They provide two gold stars: **

120
2019/day08/aoc-c.c Normal file
View File

@@ -0,0 +1,120 @@
/* aoc-c.c: Advent of Code 2019, day 8 parts 1 & 2
*
* Copyright (C) 2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "br.h"
#include "bits.h"
#include "debug.h"
#include "list.h"
#include "pool.h"
struct input {
int len;
char *buf;
};
static int part1(struct input *input, int width, int height)
{
int depth = input->len / width / height;
int minzero = input->len, n1n2;
for (int i = 0; i < depth; ++i) {
char *layer = input->buf + i * (width * height);
int tmp[10] = {0};
for (int j = 0; j < width*height; ++j) {
tmp[layer[j] - '0'] ++;
}
if (tmp[0] < minzero) {
minzero = tmp[0];
n1n2 = tmp[1] * tmp[2];
}
}
return n1n2;
}
static int part2(struct input *input, int width, int height)
{
for (int line = 0; line < height; line++) {
for (int pixel = 0; pixel < width; ++pixel) {
char *pos = input->buf + line * width + pixel;
while (pos < input->buf + input->len && *pos == '2')
pos += width * height;
putchar(*pos == '0'? ' ': '#');
}
putchar('\n');
}
return 0;
}
static int parse(struct input *input)
{
size_t alloc = 0;
ssize_t buflen;
char *buf = NULL;
if ((buflen = getline(&buf, &alloc, stdin)) <= 0) {
fprintf(stderr, "error reading file.\n");
return 0;
}
buf[buflen--] = 0;
input->buf = buf;
input->len = buflen;
return buflen;
}
static int usage(char *prg)
{
fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg);
return 1;
}
int main(int ac, char **av)
{
int opt, part = 1, width = 25, height = 6;
struct input input = { 0 };
while ((opt = getopt(ac, av, "d:p:w:h:")) != -1) {
switch (opt) {
case 'd':
debug_level_set(atoi(optarg));
break;
case 'w':
width = atoi(optarg);
break;
case 'h':
height = atoi(optarg);
break;
case 'p': /* 1 or 2 */
part = atoi(optarg);
if (part < 1 || part > 2)
return usage(*av);
break;
default:
return usage(*av);
}
}
if (optind < ac)
return usage(*av);
parse(&input);
printf("%s : res=%d\n", *av,
part == 1?
part1(&input, width, height) :
part2(&input, width, height));
free(input.buf);
exit(0);
}

1
2019/day09/EXAMPLE.txt Normal file
View File

@@ -0,0 +1 @@
109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99

1
2019/day09/EXAMPLE2.txt Normal file
View File

@@ -0,0 +1 @@
1102,34915192,34915192,7,4,7,99,0

1
2019/day09/EXAMPLE3.txt Normal file
View File

@@ -0,0 +1 @@
104,1125899906842624,99

1
2019/day09/INPUT.txt Normal file
View File

@@ -0,0 +1 @@
1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1102,3,1,1000,109,988,209,12,9,1000,209,6,209,3,203,0,1008,1000,1,63,1005,63,65,1008,1000,2,63,1005,63,904,1008,1000,0,63,1005,63,58,4,25,104,0,99,4,0,104,0,99,4,17,104,0,99,0,0,1101,20,0,1007,1101,0,197,1022,1102,475,1,1028,1102,30,1,1008,1101,25,0,1010,1102,1,23,1009,1101,0,22,1013,1101,470,0,1029,1102,24,1,1014,1102,1,39,1005,1101,31,0,1003,1101,807,0,1026,1101,0,26,1018,1102,1,804,1027,1101,0,0,1020,1102,1,38,1017,1101,0,27,1016,1102,443,1,1024,1101,0,36,1006,1102,21,1,1015,1101,28,0,1001,1102,33,1,1019,1102,1,37,1011,1102,1,190,1023,1101,0,434,1025,1101,34,0,1004,1102,1,1,1021,1101,0,29,1012,1102,1,32,1002,1101,35,0,1000,109,30,2105,1,-7,1001,64,1,64,1105,1,199,4,187,1002,64,2,64,109,-23,2101,0,-5,63,1008,63,32,63,1005,63,225,4,205,1001,64,1,64,1105,1,225,1002,64,2,64,109,7,2102,1,-5,63,1008,63,23,63,1005,63,251,4,231,1001,64,1,64,1106,0,251,1002,64,2,64,109,-16,2101,0,2,63,1008,63,33,63,1005,63,275,1001,64,1,64,1106,0,277,4,257,1002,64,2,64,109,10,21102,40,1,4,1008,1012,40,63,1005,63,299,4,283,1106,0,303,1001,64,1,64,1002,64,2,64,109,7,2102,1,-9,63,1008,63,33,63,1005,63,327,1001,64,1,64,1105,1,329,4,309,1002,64,2,64,109,-17,2107,34,2,63,1005,63,347,4,335,1105,1,351,1001,64,1,64,1002,64,2,64,109,1,1201,8,0,63,1008,63,23,63,1005,63,375,1001,64,1,64,1106,0,377,4,357,1002,64,2,64,109,-4,2108,31,8,63,1005,63,395,4,383,1105,1,399,1001,64,1,64,1002,64,2,64,109,3,1201,8,0,63,1008,63,36,63,1005,63,421,4,405,1105,1,425,1001,64,1,64,1002,64,2,64,109,25,2105,1,1,4,431,1001,64,1,64,1105,1,443,1002,64,2,64,109,-3,1205,0,459,1001,64,1,64,1106,0,461,4,449,1002,64,2,64,109,-2,2106,0,10,4,467,1106,0,479,1001,64,1,64,1002,64,2,64,109,12,1206,-9,495,1001,64,1,64,1106,0,497,4,485,1002,64,2,64,109,-39,1207,9,36,63,1005,63,519,4,503,1001,64,1,64,1105,1,519,1002,64,2,64,109,11,1202,-1,1,63,1008,63,28,63,1005,63,541,4,525,1105,1,545,1001,64,1,64,1002,64,2,64,109,6,2107,24,1,63,1005,63,565,1001,64,1,64,1106,0,567,4,551,1002,64,2,64,109,1,1207,-3,35,63,1005,63,583,1106,0,589,4,573,1001,64,1,64,1002,64,2,64,109,1,21102,41,1,5,1008,1015,40,63,1005,63,613,1001,64,1,64,1105,1,615,4,595,1002,64,2,64,109,-2,2108,22,1,63,1005,63,635,1001,64,1,64,1105,1,637,4,621,1002,64,2,64,109,-10,1208,4,33,63,1005,63,653,1106,0,659,4,643,1001,64,1,64,1002,64,2,64,109,16,1206,6,673,4,665,1106,0,677,1001,64,1,64,1002,64,2,64,109,-4,1202,-8,1,63,1008,63,35,63,1005,63,701,1001,64,1,64,1105,1,703,4,683,1002,64,2,64,109,13,21108,42,42,-8,1005,1015,721,4,709,1105,1,725,1001,64,1,64,1002,64,2,64,109,-18,21107,43,44,5,1005,1010,743,4,731,1106,0,747,1001,64,1,64,1002,64,2,64,109,-11,1208,8,32,63,1005,63,765,4,753,1106,0,769,1001,64,1,64,1002,64,2,64,109,15,21101,44,0,5,1008,1014,47,63,1005,63,789,1105,1,795,4,775,1001,64,1,64,1002,64,2,64,109,13,2106,0,5,1106,0,813,4,801,1001,64,1,64,1002,64,2,64,109,-12,21108,45,43,0,1005,1010,829,1106,0,835,4,819,1001,64,1,64,1002,64,2,64,109,-4,21107,46,45,10,1005,1016,855,1001,64,1,64,1106,0,857,4,841,1002,64,2,64,109,3,21101,47,0,5,1008,1014,47,63,1005,63,883,4,863,1001,64,1,64,1106,0,883,1002,64,2,64,109,10,1205,2,901,4,889,1001,64,1,64,1105,1,901,4,64,99,21102,27,1,1,21102,915,1,0,1106,0,922,21201,1,13433,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21101,0,942,0,1106,0,922,22102,1,1,-1,21201,-2,-3,1,21102,1,957,0,1105,1,922,22201,1,-1,-2,1106,0,968,21202,-2,1,-2,109,-3,2106,0,0

93
2019/day09/Makefile Normal file
View File

@@ -0,0 +1,93 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := INPUT.txt
SHELL := /bin/bash
CC := gcc
LIB := aoc_$(shell uname -m)
INCDIR := ../include
LIBDIR := ../lib
LDFLAGS := -L$(LIBDIR)
#LDLIB := -l$(LIB) -lm
LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
#CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations
CFLAGS += -Wno-unused-result
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
--sigill-diagnostics=yes --quiet --show-error-list=yes
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH)
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
all: README.org ex1 ex2
memcheck: memcheck1 memcheck2
memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
memcheck2: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
compile: aoc-c
assembly: aoc-c.s
ex1: aoc-c
@$(TIME) aoc-c -p 1 < $(INPUT)
ex2: aoc-c
@$(TIME) aoc-c -p 2 < $(INPUT)
clean:
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
.c:
@echo compiling $<
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
# generate pre-processed file (.i) and assembler (.s)
%.i: %.c
@echo generating $@
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
%.s: %.c
@echo generating $@
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
# generate README.org from README.html (must cleanup !)
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@

94
2019/day09/README.org Normal file
View File

@@ -0,0 +1,94 @@
** --- Day 9: Sensor Boost ---
You've just said goodbye to the rebooted rover and left Mars when you
receive a faint distress signal coming from the asteroid belt. It must
be the Ceres monitoring station!
In order to lock on to the signal, you'll need to boost your sensors.
The Elves send up the latest /BOOST/ program - Basic Operation Of System
Test.
While BOOST (your puzzle input) is capable of boosting your sensors, for
tenuous safety reasons, it refuses to do so until the computer it runs
on passes some checks to demonstrate it is a /complete Intcode
computer/.
[[file:5][Your existing Intcode computer]] is missing one key feature:
it needs support for parameters in /relative mode/.
Parameters in mode =2=, /relative mode/, behave very similarly to
parameters in /position mode/: the parameter is interpreted as a
position. Like position mode, parameters in relative mode can be read
from or written to.
The important difference is that relative mode parameters don't count
from address =0=. Instead, they count from a value called the /relative
base/. The /relative base/ starts at =0=.
The address a relative mode parameter refers to is itself /plus/ the
current /relative base/. When the relative base is =0=, relative mode
parameters and position mode parameters with the same value refer to the
same address.
For example, given a relative base of =50=, a relative mode parameter of
=-7= refers to memory address =50 + -7 = 43=.
The relative base is modified with the /relative base offset/
instruction:
- Opcode =9= /adjusts the relative base/ by the value of its only
parameter. The relative base increases (or decreases, if the value is
negative) by the value of the parameter.
For example, if the relative base is =2000=, then after the instruction
=109,19=, the relative base would be =2019=. If the next instruction
were =204,-34=, then the value at address =1985= would be output.
Your Intcode computer will also need a few other capabilities:
- The computer's available memory should be much larger than the initial
program. Memory beyond the initial program starts with the value =0=
and can be read or written like any other memory. (It is invalid to
try to access memory at a negative address, though.)
- The computer should have support for large numbers. Some instructions
near the beginning of the BOOST program will verify this capability.
Here are some example programs that use these features:
- =109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99= takes no
input and produces a
[[https://en.wikipedia.org/wiki/Quine_(computing)][copy of itself]] as
output.
- =1102,34915192,34915192,7,4,7,99,0= should output a 16-digit number.
- =104,1125899906842624,99= should output the large number in the
middle.
The BOOST program will ask for a single input; run it in test mode by
providing it the value =1=. It will perform a series of checks on each
opcode, output any opcodes (and the associated parameter modes) that
seem to be functioning incorrectly, and finally output a BOOST keycode.
Once your Intcode computer is fully functional, the BOOST program should
report no malfunctioning opcodes when run in test mode; it should only
output a single value, the BOOST keycode. /What BOOST keycode does it
produce?/
Your puzzle answer was =2682107844=.
** --- Part Two ---
/You now have a complete Intcode computer./
Finally, you can lock on to the Ceres distress signal! You just need to
boost your sensors using the BOOST program.
The program runs in sensor boost mode by providing the input instruction
the value =2=. Once run, it will boost the sensors automatically, but it
might take a few seconds to complete the operation on slower hardware.
In sensor boost mode, the program will output a single value: /the
coordinates of the distress signal/.
Run the BOOST program in sensor boost mode. /What are the coordinates of
the distress signal?/
Your puzzle answer was =34738=.
Both parts of this puzzle are complete! They provide two gold stars: **

258
2019/day09/aoc-c.c Normal file
View File

@@ -0,0 +1,258 @@
/* aoc-c.c: Advent of Code 2019, day 9 parts 1 & 2
*
* Copyright (C) 2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "br.h"
#include "bits.h"
#include "debug.h"
#include "list.h"
#include "pool.h"
#define _unused __attribute__((unused))
/* operators codes
*/
typedef enum {
ADD = 1, MUL = 2, /* CALC: add and mult */
INP = 3, OUT = 4, /* I/O: input and output value */
JMP_T = 5, JMP_F = 6, /* JUMPS: jump if true / if false */
SET_LT = 7, SET_EQ = 8, /* COND SETS: set if true/false */
ADJ_RL = 9, /* ADDRESSING: adjust relative addr */
HLT = 99 /* HALT */
} opcode_t;
/**
* ops - array of op-codes, mnemo, and number of parameters
* @op: An integer, the opcode
* @length: Next instruction offset
*/
typedef struct {
int op;
u8 length;
} ops_t;
typedef struct io {
s64 val;
struct list_head list;
} io_t;
#define MAXOPS 2048
typedef struct {
s64 length; /* total program length */
s64 cur; /* current instruction */
s64 rel; /* current relative memory */
struct list_head input; /* process input queue */
struct list_head output; /* process output queue */
s64 mem [MAXOPS]; /* should really be dynamic */
} program_t;
static ops_t ops[] = {
[ADD] = { ADD, 4 }, [MUL] = { MUL, 4 },
[INP] = { INP, 2 }, [OUT] = { OUT, 2 },
[JMP_T] = { JMP_T, 3 }, [JMP_F] = { JMP_F, 3 },
[SET_LT] = { SET_LT, 4 }, [SET_EQ] = { SET_EQ, 4 },
[ADJ_RL] = { ADJ_RL, 2 },
[HLT] = { HLT, 1 }
};
typedef enum {
IND = 0,
DIR = 1,
REL = 2
} param_t;
static __always_inline int getop(program_t *prg, int addr)
{
return prg->mem[addr] % 100;
}
static __always_inline param_t paramtype(program_t *prg, int addr, int param)
{
static int _flag_pow10[] = {1, 100, 1000, 10000};
return prg->mem[addr] / _flag_pow10[param] % 10;
}
#define DIRECT(p, i) ((p)->mem[i])
#define INDIRECT(p, i) (DIRECT(p, DIRECT(p, i)))
#define RELATIVE(p, i) (DIRECT(p, DIRECT(p, i) + p->rel))
static __always_inline s64 peek(program_t *prg, s64 cur, s64 param)
{
switch(paramtype(prg, cur, param)) {
case IND:
return INDIRECT(prg, cur + param);
case REL:
return RELATIVE(prg, cur + param);
case DIR:
return DIRECT(prg, cur + param);
}
return 0; /* not reached */
}
static __always_inline void poke(program_t *prg, int cur, int param, s64 val)
{
if (paramtype(prg, cur, param) == REL)
RELATIVE(prg, cur + param) = val;
else
INDIRECT(prg, cur + param) = val;
}
static pool_t *pool_io;
static inline int prg_add_input(program_t *prg, s64 in)
{
io_t *input = pool_get(pool_io);
input->val = in;
list_add_tail(&input->list, &prg->input);
return in;
}
static inline s64 prg_add_output(program_t *prg, s64 out)
{
io_t *output = pool_get(pool_io);
output->val = out;
list_add_tail(&output->list, &prg->output);
return out;
}
static inline int prg_get_input(program_t *prg, s64 *in)
{
io_t *input = list_first_entry_or_null(&prg->input, io_t, list);
if (!input)
return 0;
*in = input->val;
list_del(&input->list);
pool_add(pool_io, input);
return 1;
}
static inline _unused int prg_get_output(program_t *prg, s64 *out)
{
io_t *output = list_first_entry_or_null(&prg->output, io_t, list);
if (!output)
return 0;
*out = output->val;
list_del(&output->list);
pool_add(pool_io, output);
return 1;
}
static s64 run(program_t *p, int *end)
{
s64 out = -1, input;
while (1) {
int cur = p->cur;
opcode_t op = getop(p, p->cur);
if (!(ops[op].op)) {
fprintf(stderr, "PANIC: illegal instruction %d at %ld.\n", op, p->cur);
return -1;
}
switch (op) {
case ADD:
poke(p, p->cur, 3, peek(p, p->cur, 1) + peek(p, p->cur, 2));
break;
case MUL:
poke(p, p->cur, 3, peek(p, p->cur, 1) * peek(p, p->cur, 2));
break;
case INP:
if (prg_get_input(p, &input))
poke(p, p->cur, 1, input);
else
/* we need an input which is not yet avalaible, so we need
* to put the program in "waiting mode": We stop it (and
* return output value) without setting end flag.
*/
goto sleep;
break;
case OUT:
prg_add_output(p, out = peek(p, p->cur, 1));
break;
case JMP_T:
if (peek(p, p->cur, 1))
p->cur = peek(p, p->cur, 2);
break;
case JMP_F:
if (!peek(p, p->cur, 1))
p->cur = peek(p, p->cur, 2);
break;
case SET_LT:
poke(p, p->cur, 3, peek(p, p->cur, 1) < peek(p, p->cur, 2) ? 1: 0);
break;
case SET_EQ:
poke(p, p->cur, 3, peek(p, p->cur, 1) == peek(p, p->cur, 2) ? 1: 0);
break;
case ADJ_RL:
p->rel += peek(p, p->cur, 1);
break;
case HLT:
*end = 1;
sleep:
return out;
}
if (p->cur == cur)
p->cur += ops[op].length;
}
}
static void parse(program_t *prog)
{
while (scanf("%ld%*c", &prog->mem[prog->length++]) > 0)
;
}
static int usage(char *prg)
{
fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg);
return 1;
}
int main(int ac, char **av)
{
int opt, part = 1;
while ((opt = getopt(ac, av, "d:p:")) != -1) {
switch (opt) {
case 'd':
debug_level_set(atoi(optarg));
break;
case 'p': /* 1 or 2 */
part = atoi(optarg);
if (part < 1 || part > 2)
return usage(*av);
break;
default:
return usage(*av);
}
}
if (optind < ac)
return usage(*av);
int end = 0;
program_t p = { 0 };
pool_io = pool_create("i/o", 128, sizeof(io_t));
INIT_LIST_HEAD(&p.input);
INIT_LIST_HEAD(&p.output);
prg_add_input(&p, part);
parse(&p);
printf("%s : res=%ld\n", *av, run(&p, &end));
pool_destroy(pool_io);
exit(0);
}

View File

@@ -1,6 +1,6 @@
/* pool.h - A simple memory pool manager.
*
* Copyright (C) 2021 Bruno Raoult ("br")
* Copyright (C) 2021-2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*

View File

@@ -1,25 +1,87 @@
# AOC Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
SUBDIRS := $(shell echo day??)
EXCLUDE := --exclude 'cob-01/'
CC = gcc
.PHONY: clean $(SUBDIRS)
#LIBS = -lreadline -lncurses
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
#CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
INCDIR := ./include
LIBSRCDIR := ./libsrc
LIBDIR := ./lib
LIB := libaoc_$(shell uname -m)
SLIB := $(LIBDIR)/$(LIB).a
DLIB := $(LIBDIR)/$(LIB).so
LIBSRC := $(wildcard $(LIBSRCDIR)/*.c)
LIBOBJ := $(patsubst %.c,%.o,$(LIBSRC))
LDFLAGS := -L$(LIBDIR)
LDLIB := -l$(LIB)
.PHONY: clean cleanlib cleanall all redo output lib $(SUBDIRS)
all: lib $(SUBDIRS)
clean:
for dir in $(SUBDIRS) ; do \
make -C $$dir clean ; \
@for dir in $(SUBDIRS) ; do \
$(MAKE) --no-print-directory -C $$dir clean ; \
done
all: $(SUBDIRS)
cleanlib: clean
@$(RM) -f $(SLIB) $(DLIB) $(LIBOBJ)
cleanall: clean cleanlib
redo: cleanall all
$(SUBDIRS):
@echo "========================================="
@echo "================= $@ ================="
@echo "========================================="
@echo
@echo "+++++++++++++++++ ex1"
@$(MAKE) --no-print-directory -C $@ ex1 2>&1
@echo "+++++++++++++++++ ex2"
@$(MAKE) --no-print-directory -C $@ ex2 2>&1
@echo "+++++++++++++++++ part 1"
+@$(MAKE) --no-print-directory -C $@ ex1 2>&1
@echo "+++++++++++++++++ part 2"
+@$(MAKE) --no-print-directory -C $@ ex2 2>&1
output:
@$(MAKE) --no-print-directory all >OUTPUT 2>&1
lib: $(DLIB) $(SLIB)
$(SLIB): $(LIBOBJ)
@echo building $@ static library.
@mkdir -p $(LIBDIR)
@$(AR) $(ARFLAGS) -o $@ $^
$(DLIB): CFLAGS += -fPIC
$(DLIB): LDFLAGS += -shared
$(DLIB): $(LIBOBJ)
@echo building $@ shared library.
@mkdir -p $(LIBDIR)
@$(CC) $(LDFLAGS) $^ -o $@
.c.o:
@echo compiling $<.
@$(CC) -c $(CFLAGS) $(LDFLAGS) -I $(INCDIR) -o $@ $<

View File

@@ -439,11 +439,20 @@ ex1.bash : res=285
time: 0:00.56 real, 0.55 user, 0.00 sys
context-switch: 12+1, page-faults: 0+5967
aoc-c : res=285
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+94
+++++++++++++++++ ex2
ex2.bash : res=412
time: 0:03.37 real, 3.34 user, 0.03 sys
context-switch: 19+1, page-faults: 0+11909
aoc-c : res=412
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+95
=========================================
================= day20 =================
=========================================
@@ -481,7 +490,72 @@ ex1.bash: res=31314
time: 0:00.07 real, 0.06 user, 0.00 sys
context-switch: 2+1, page-faults: 0+168
aoc-c : res=31314
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+89
+++++++++++++++++ ex2
ex2.bash: res=32760
time: 1:21.92 real, 81.89 user, 0.01 sys
context-switch: 462+1, page-faults: 0+5135
aoc-c : res=32760
time: 0:01.11 real, 1.09 user, 0.01 sys
context-switch: 70+1, page-faults: 0+1933
=========================================
================= day23 =================
=========================================
+++++++++++++++++ ex1
ex1.bash: res=75893264
time: 0:00.01 real, 0.01 user, 0.00 sys
context-switch: 0+1, page-faults: 0+166
aoc-c : res=75893264
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+83
+++++++++++++++++ ex2
ex2.bash: res=38162588308
time: 6:52.50 real, 412.30 user, 0.14 sys
context-switch: 2219+1, page-faults: 0+30233
aoc-c : res=38162588308
time: 0:01.33 real, 1.32 user, 0.01 sys
context-switch: 3+1, page-faults: 0+3992
=========================================
================= day24 =================
=========================================
+++++++++++++++++ ex1
ex1.bash: res=450
time: 0:00.17 real, 0.16 user, 0.00 sys
context-switch: 1+1, page-faults: 0+177
aoc-c : res=450
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+100
+++++++++++++++++ ex2
ex2.bash: res=4059
time: 0:22.35 real, 22.22 user, 0.07 sys
context-switch: 1102+1, page-faults: 0+858
aoc-c : res=4059
time: 0:00.04 real, 0.04 user, 0.00 sys
context-switch: 16+1, page-faults: 0+215
=========================================
================= day25 =================
=========================================
+++++++++++++++++ ex1
ex1.bash: res=9620012
time: 2:42.30 real, 162.05 user, 0.08 sys
context-switch: 3634+1, page-faults: 0+163
ex1-c : res=9620012
time: 0:00.08 real, 0.08 user, 0.00 sys
context-switch: 2+1, page-faults: 0+79

View File

@@ -28,7 +28,7 @@ ex2: ex2-c ex2-sort-cob ex2-pure-sort-cob
@$(TIME) ex2-c < $(INPUT)
clean:
@rm -f ex1-c ex2-c core ex2-galoisgirl-cob ex2-cob
@rm -f ex1-c ex2-c core ex*-cob
output:
$(MAKE) --no-print-directory all >OUTPUT 2>&1

View File

@@ -1,36 +0,0 @@
ex1.bash : 33:1701 180:319 sum=2020 mul=542619
time: 0:00.06 real, 0.06 user, 0.00 sys
context-switch: 20+4, page-faults: 0+305
ex1-cob : res= 542619
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+172
ex1-c : 33:1701 180:319 sum=2020 mul=542619
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+73
ex2.bash : 80:1450 94:43 185:527 sum=2020 mul=32858450
time: 0:10.00 real, 10.00 user, 0.00 sys
context-switch: 1005+3, page-faults: 0+302
ex2-sort.bash : 0:43 2:527 81:1450 sum=2020 mul=32858450
time: 0:00.01 real, 0.01 user, 0.00 sys
context-switch: 2+7, page-faults: 0+479
ex2-pure-sort.bash : 0:43 2:527 81:1450 sum=2020 mul=32858450
time: 0:00.50 real, 0.50 user, 0.00 sys
context-switch: 62+4, page-faults: 0+311
ex2-sort-cob : res= 32858450
time: 0:00.01 real, 0.01 user, 0.00 sys
context-switch: 1+1, page-faults: 0+170
ex2-pure-sort-cob : res= 32858450
time: 0:00.01 real, 0.01 user, 0.00 sys
context-switch: 1+1, page-faults: 0+173
ex2-c : 80:1450 94:43 185:527 sum=2020 mul=32858450
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+75

View File

@@ -1,12 +0,0 @@
ex1.bash : lines: 1000 matched:607
time: 0:00.03 real, 0.03 user, 0.00 sys
ex1-c : lines: 1000 matched:607
time: 0:00.00 real, 0.00 user, 0.00 sys
ex2.bash : lines: 1000 matched:321
time: 0:00.03 real, 0.03 user, 0.00 sys
ex2-c : lines: 1000 matched:321
time: 0:00.00 real, 0.00 user, 0.00 sys

View File

@@ -1,12 +0,0 @@
ex1.bash : lines:322 pos=966 found:169
time: 0:00.01 real, 0.01 user, 0.00 sys
ex1-c : lines:322 pos:966 found:169
time: 0:00.00 real, 0.00 user, 0.00 sys
ex2.bash : lines=323 res=6847128288
time: 0:00.04 real, 0.03 user, 0.00 sys
ex2-c : lines=323 res=6847128288
time: 0:00.00 real, 0.00 user, 0.00 sys

View File

@@ -32,7 +32,7 @@ int main(ac, av)
char **av;
{
int line=1, linelen=0, mod=0, i;
unsigned long res=1;
unsigned long long res=1;
char str[80];
scanf("%s", str); /* ignore 1st line */
@@ -51,6 +51,6 @@ int main(ac, av)
}
for (i=0; set[i].dx != -1; ++i)
res*=set[i].count;
printf ("%s : lines=%d res=%lu\n", *av, line, res);
printf ("%s : lines=%d res=%llu\n", *av, line, res);
exit (0);
}

View File

@@ -1,12 +0,0 @@
ex1.bash : valid=182/251
time: 0:00.06 real, 0.06 user, 0.00 sys
ex1-c : valid=182/251
time: 0:00.00 real, 0.00 user, 0.00 sys
ex2.bash : valid=109/251
time: 0:00.16 real, 0.16 user, 0.00 sys
ex2-c : valid=109/251
time: 0:00.00 real, 0.00 user, 0.00 sys

View File

@@ -1,12 +0,0 @@
ex1.bash : lines=743 max=838
time: 0:00.94 real, 0.62 user, 0.41 sys
ex1-c : lines=743 max=838
time: 0:00.00 real, 0.00 user, 0.00 sys
ex2.bash : lines=743 seat=714
time: 0:00.99 real, 0.65 user, 0.43 sys
ex2-c : lines=743 seat=714
time: 0:00.00 real, 0.00 user, 0.00 sys

View File

@@ -1,24 +0,0 @@
ex1.bash : groups=484 count=6585
time: 0:01.42 real, 1.26 user, 0.20 sys
context-switch: 135+1393, page-faults: 0+59578
ex1-bis.bash : groups=484 count=6585
time: 0:01.22 real, 1.09 user, 0.16 sys
context-switch: 145+1311, page-faults: 0+60076
ex1-c : groups=484 count=6585
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+71
ex2.bash : groups=484 count=3276
time: 0:01.35 real, 1.18 user, 0.20 sys
context-switch: 139+1360, page-faults: 0+59397
ex2-bis.bash : groups=484 count=3276
time: 0:01.30 real, 1.11 user, 0.22 sys
context-switch: 112+1356, page-faults: 0+57986
ex2-c : groups=484 count=3276
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+72

View File

@@ -1,4 +0,0 @@
#! /bin/bash
PATH=.:$PATH
IN="$1"
time { ex1.bash < $IN; ex2.bash < $IN; } 2>&1

View File

@@ -1,5 +0,0 @@
#! /bin/bash
PATH=.:$PATH
IN="$1"
echo IN=$IN
time for i in ex1-c ex2-c; do "$i" < "$IN"; done 2>&1

View File

@@ -1,20 +0,0 @@
ex1.bash : target=shinygold nkeys=594 res=287
time: 0:06.99 real, 6.99 user, 0.00 sys
context-switch: 720+1, page-faults: 0+403
ex1-bis.bash : target=shinygold res=287
time: 0:00.12 real, 0.12 user, 0.00 sys
context-switch: 14+1, page-faults: 0+209
ex1-c : target=shinygold nkeys=594 res=287
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+117
ex2.bash : target=shinygold res=48160
time: 0:00.34 real, 0.28 user, 0.06 sys
context-switch: 37+253, page-faults: 0+12039
ex2-c : target=shinygold nkeys=594 res=48160
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+118

View File

@@ -1,16 +0,0 @@
ex1.bash : res=1594
time: 0:00.01 real, 0.01 user, 0.00 sys
context-switch: 0+4, page-faults: 0+303
ex1-c : res=1594
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 1+0, page-faults: 0+79
ex2.bash : res:758
time: 0:02.26 real, 2.12 user, 0.16 sys
context-switch: 212+1084, page-faults: 0+43039
ex2-c : res=758
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 1+1, page-faults: 0+78

View File

@@ -1,16 +0,0 @@
ex1.bash : res=167829540
time: 0:00.42 real, 0.42 user, 0.00 sys
context-switch: 57+1, page-faults: 0+172
ex1-c : res=167829540
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+76
ex2.bash : res=167829540 sum=28045630
time: 0:03.22 real, 3.01 user, 0.21 sys
context-switch: 359+921, page-faults: 0+49208
ex2-c : res=167829540 sum=28045630
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+75

View File

@@ -1,16 +0,0 @@
ex1.bash : diff1=71 diff2=27 res=1917
time: 0:00.01 real, 0.01 user, 0.00 sys
context-switch: 7+1, page-faults: 0+234
ex1-c : diff1=71 diff2=27 res=1917
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+73
ex2.bash : size=99 res=113387824750592
time: 0:00.02 real, 0.02 user, 0.00 sys
context-switch: 10+1, page-faults: 0+236
ex2-c : size=99 res=113387824750592
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+74

View File

@@ -63,7 +63,6 @@ struct list *add_val(list, val)
struct list *list;
unsigned long long val;
{
//int val;
unsigned cur, size;
unsigned long long *ptr;
@@ -80,7 +79,6 @@ struct list *add_val(list, val)
size+=BLOCKSIZE;
list->size=size;
list->list=realloc(list->list, sizeof(unsigned long long)*size);
fprintf(stderr, "realloc buf: cur=%d size=%d ptr=%p\n", cur, size, list->list);
}
ptr=list->list+cur;
@@ -91,10 +89,10 @@ struct list *add_val(list, val)
return list;
}
unsigned *calc(list)
unsigned long long *calc(list)
struct list *list;
{
static unsigned res[4];
static unsigned long long res[4];
unsigned long long *ptr=list->list;
unsigned last=list->last, i;
@@ -113,10 +111,9 @@ int main(ac, av)
{
char line[80];
struct list *list=NULL;
unsigned long long res, last;
unsigned *result;
unsigned long long res, last, *result;
list=add_val(list, 0);
list=add_val(list, 0llu);
while (fgets(line, sizeof line, stdin)) {
sscanf(line, "%llu", &res);
list=add_val(list, res);
@@ -126,7 +123,7 @@ int main(ac, av)
list=add_val(list, last+3);
//print_list(list);
result=calc(list);
printf("%s : diff1=%u diff2=%u res=%u\n", *av, result[1], result[3],
printf("%s : diff1=%llu diff2=%llu res=%llu\n", *av, result[1], result[3],
result[1]*result[3]);
exit (0);
}

View File

@@ -131,7 +131,7 @@ int main(ac, av)
struct list *list=NULL;
unsigned long long res, last;
list=add_val(list, 0);
list=add_val(list, 0ll);
while (fgets(line, sizeof line, stdin)) {
sscanf(line, "%llu", &res);
list=add_val(list, res);

View File

@@ -1,16 +0,0 @@
ex1.bash : res=2386
time: 0:33.55 real, 33.12 user, 0.42 sys
context-switch: 179+18, page-faults: 0+1948
ex1-c : res=2386
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+90
ex2.bash : res=2091
time: 1:08.60 real, 68.56 user, 0.02 sys
context-switch: 530+10, page-faults: 0+1480
ex2-c : res=2091
time: 0:00.01 real, 0.01 user, 0.00 sys
context-switch: 6+1, page-faults: 0+90

View File

@@ -12,9 +12,9 @@ declare floor
function adj() {
local -i r="$1" n="$2" c="$3" count=0
local -a prow=(${rows[r-1]})
local -a row=(${rows[r]})
local -a nrow=(${rows[r+1]})
local -a prow=("${rows[r-1]}")
local -a row=("${rows[r]}")
local -a nrow=("${rows[r+1]}")
#echo
#echo p="${prow[*]}"
#echo r="${row[*]}"
@@ -51,7 +51,7 @@ function run() {
changed=0
seated=0
for ((r=1; r<=NROWS; ++r)); do
row=(${rows[r]})
row=("${rows[r]}")
newrow=(0)
for ((c=1; c<=RLENGTH; ++c)); do
newrow+=("${row[c]}")
@@ -61,13 +61,13 @@ function run() {
case ${row[c]} in
0) continue
;;
1) if (( $(adj $r $c 2) == 0 )); then
1) if (( $(adj "$r" "$c" 2) == 0 )); then
((++changed))
newrow[c]=2
fi
#printf "[%d][%d]: %s %s %d\n" $r $c "${row[c]}" "${newrow[c]}" $(adj $r $c 2)
;;
2) if (( $(adj $r $c 2) >= 4 )); then
2) if (( $(adj "$r" "$c" 2) >= 4 )); then
((++changed))
newrow[c]=1
fi

View File

@@ -1,16 +0,0 @@
ex1.bash : res=1457
time: 0:00.02 real, 0.02 user, 0.00 sys
context-switch: 5+1, page-faults: 0+152
ex1-c : res=1457
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+72
ex2.bash : res=106860
time: 0:00.09 real, 0.08 user, 0.00 sys
context-switch: 10+1, page-faults: 0+153
ex2-c : res=106860
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 1+1, page-faults: 0+75

View File

@@ -1,16 +0,0 @@
ex1.bash : res=410
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 2+1, page-faults: 0+154
ex1-c : res=410
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+76
ex2.bash : res=600691418730595
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 1+1, page-faults: 0+156
ex2-c : res=600691418730595
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 1+1, page-faults: 0+76

View File

@@ -1,16 +0,0 @@
ex1.bash : res=10035335144067
time: 0:00.06 real, 0.04 user, 0.01 sys
context-switch: 5+1, page-faults: 0+200
ex1-c : res=10035335144067
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+80
ex2.bash : res=3817372618036
time: 0:06.69 real, 6.68 user, 0.00 sys
context-switch: 689+1, page-faults: 0+5949
ex2-c : res=3817372618036
time: 0:00.06 real, 0.05 user, 0.00 sys
context-switch: 6+1, page-faults: 0+662

View File

@@ -1,15 +0,0 @@
ex1.bash : res[2020]=1618
time: 0:00.03 real, 0.02 user, 0.00 sys
context-switch: 6+1, page-faults: 0+158
ex1-c : res[2020]=1618
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+77
ex1.bash : res[30000000]=548531
time: 12:22:02 real, 44488.91 user, 2.70 sys
context-switch: 4552388+2, page-faults: 0+98912
ex1-c : res[30000000]=548531
time: 0:00.56 real, 0.49 user, 0.06 sys
context-switch: 55+1, page-faults: 0+29369

View File

@@ -1,8 +0,0 @@
ex1.bash : res=1618
time: 0:00.07 real, 0.07 user, 0.00 sys
context-switch: 7+1, page-faults: 0+172
ex3.bash : res=548531
time: 12:22:02 real, 44488.91 user, 2.70 sys
context-switch: 4552388+2, page-faults: 0+98912

View File

@@ -1,18 +0,0 @@
cc -w -O3 ex1-c.c -o ex1-c
ex1.bash : res=21996
time: 0:00.14 real, 0.11 user, 0.02 sys
context-switch: 12+120, page-faults: 0+7974
ex1-c : res=21996
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+76
cc -w -O3 ex2-c.c -o ex2-c
ex2.bash : res=650080463519
time: 0:06.58 real, 6.54 user, 0.04 sys
context-switch: 201+114, page-faults: 0+8893
ex2-c : res=650080463519
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+74

View File

@@ -1,20 +0,0 @@
ex1-v1.bash : res=263
time: 1:47.86 real, 74.63 user, 39.28 sys
context-switch: 6224+166221, page-faults: 0+7568225
ex1.bash : res=263
time: 0:00.37 real, 0.36 user, 0.00 sys
context-switch: 1+1, page-faults: 0+322
ex1-c : res=263
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+150
ex2.bash : res=1680
time: 0:06.47 real, 6.47 user, 0.00 sys
context-switch: 23+1, page-faults: 0+2852
ex2-c : res=1680
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+1634

View File

@@ -24,7 +24,7 @@ ex2: ex12-c
@$(TIME) ex12-c 2 < $(INPUT) 2>&1
clean:
@rm -f ex1-c ex2-c core
@rm -f ex12-c core
deploy:
@$(MAKE) -C .. deploy

View File

@@ -1,16 +0,0 @@
ex1.bash : res=650217205854
time: 0:01.80 real, 1.78 user, 0.01 sys
context-switch: 28+1, page-faults: 0+190
ex12-c : res=650217205854
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+75
ex2.bash : res=20394514442037
time: 0:01.56 real, 1.55 user, 0.01 sys
context-switch: 16+1, page-faults: 0+196
ex12-c : res=20394514442037
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+74

View File

@@ -1,30 +1,108 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := INPUT.txt
SHELL := /bin/bash
CFLAGS := -w -g
#CFLAGS := -w -g -pg
#CFLAGS := -w -O3
CC := gcc
BEAR := bear
CCLSFILE:= compile_commands.json
LIB := aoc_$(shell uname -m)
INCDIR := ../include
LIBDIR := ../lib
LDFLAGS := -L$(LIBDIR)
#LDLIB := -l$(LIB) -lm
LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
# CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations
CFLAGS += -Wno-unused-result
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
--sigill-diagnostics=yes --quiet --show-error-list=yes
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH)
.PHONY: clean all compile deploy ex1 ex2
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 ccls
all: ex1 ex2
all: README.org ccls ex1 ex2
output:
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
memcheck: memcheck1 memcheck2
compile: ex1-c ex2-c
memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
ex1:
@$(TIME) ex1.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
memcheck2: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
ex2:
@$(TIME) ex2.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1
compile: aoc-c
cpp: aoc-c.i
assembly: aoc-c.s
ex1: aoc-c
@$(TIME) ex1.bash -p 1 < $(INPUT)
@$(TIME) aoc-c -p 1 < $(INPUT)
ex2: aoc-c
@$(TIME) ex2.bash -p 2 < $(INPUT)
@$(TIME) aoc-c -p 2 < $(INPUT)
ccls: $(CCLSFILE)
clean:
@rm -f ex1-c ex2-c core
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
deploy:
@$(MAKE) -C .. deploy
.c:
@echo compiling $<
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
# generate pre-processed file (.i) and assembler (.s)
%.i: %.c
@echo generating $@
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
%.s: %.c
@echo generating $@
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
# generate README.org from README.html (must cleanup !)
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@
# generate compile_commands.json
$(CCLSFILE): aoc-c.c Makefile
$(BEAR) -- make clean compile
bear: clean
@$(BEAR) -- make compile
@touch .ccls-root

View File

@@ -1,8 +0,0 @@
ex1.bash : res=285
time: 0:00.56 real, 0.55 user, 0.00 sys
context-switch: 12+1, page-faults: 0+5967
ex2.bash : res=412
time: 0:03.37 real, 3.34 user, 0.03 sys
context-switch: 19+1, page-faults: 0+11909

View File

@@ -1,145 +0,0 @@
--- Day 19: Monster Messages ---
You land in an airport surrounded by dense forest. As you walk to your high-speed train, the Elves at the Mythical Information Bureau contact you again. They think their satellite has collected an image of a sea monster! Unfortunately, the connection to the satellite is having problems, and many of the messages sent back from the satellite have been corrupted.
They sent you a list of the rules valid messages should obey and a list of received messages they've collected so far (your puzzle input).
The rules for valid messages (the top part of your puzzle input) are numbered and build upon each other. For example:
0: 1 2
1: "a"
2: 1 3 | 3 1
3: "b"
Some rules, like 3: "b", simply match a single character (in this case, b).
The remaining rules list the sub-rules that must be followed; for example, the rule 0: 1 2 means that to match rule 0, the text being checked must match rule 1, and the text after the part that matched rule 1 must then match rule 2.
Some of the rules have multiple lists of sub-rules separated by a pipe (|). This means that at least one list of sub-rules must match. (The ones that match might be different each time the rule is encountered.) For example, the rule 2: 1 3 | 3 1 means that to match rule 2, the text being checked must match rule 1 followed by rule 3 or it must match rule 3 followed by rule 1.
Fortunately, there are no loops in the rules, so the list of possible matches will be finite. Since rule 1 matches a and rule 3 matches b, rule 2 matches either ab or ba. Therefore, rule 0 matches aab or aba.
Here's a more interesting example:
0: 4 1 5
1: 2 3 | 3 2
2: 4 4 | 5 5
3: 4 5 | 5 4
4: "a"
5: "b"
Here, because rule 4 matches a and rule 5 matches b, rule 2 matches two letters that are the same (aa or bb), and rule 3 matches two letters that are different (ab or ba).
Since rule 1 matches rules 2 and 3 once each in either order, it must match two pairs of letters, one pair with matching letters and one pair with different letters. This leaves eight possibilities: aaab, aaba, bbab, bbba, abaa, abbb, baaa, or babb.
Rule 0, therefore, matches a (rule 4), then any of the eight options from rule 1, then b (rule 5): aaaabb, aaabab, abbabb, abbbab, aabaab, aabbbb, abaaab, or ababbb.
The received messages (the bottom part of your puzzle input) need to be checked against the rules so you can determine which are valid and which are corrupted. Including the rules and the messages together, this might look like:
0: 4 1 5
1: 2 3 | 3 2
2: 4 4 | 5 5
3: 4 5 | 5 4
4: "a"
5: "b"
ababbb
bababa
abbbab
aaabbb
aaaabbb
Your goal is to determine the number of messages that completely match rule 0. In the above example, ababbb and abbbab match, but bababa, aaabbb, and aaaabbb do not, producing the answer 2. The whole message must match all of rule 0; there can't be extra unmatched characters in the message. (For example, aaaabbb might appear to match rule 0 above, but it has an extra unmatched b on the end.)
How many messages completely match rule 0?
Your puzzle answer was 285.
--- Part Two ---
As you look over the list of messages, you realize your matching rules aren't quite right. To fix them, completely replace rules 8: 42 and 11: 42 31 with the following:
8: 42 | 42 8
11: 42 31 | 42 11 31
This small change has a big impact: now, the rules do contain loops, and the list of messages they could hypothetically match is infinite. You'll need to determine how these changes affect which messages are valid.
Fortunately, many of the rules are unaffected by this change; it might help to start by looking at which rules always match the same set of values and how those rules (especially rules 42 and 31) are used by the new versions of rules 8 and 11.
(Remember, you only need to handle the rules you have; building a solution that could handle any hypothetical combination of rules would be significantly more difficult.)
For example:
42: 9 14 | 10 1
9: 14 27 | 1 26
10: 23 14 | 28 1
1: "a"
11: 42 31
5: 1 14 | 15 1
19: 14 1 | 14 14
12: 24 14 | 19 1
16: 15 1 | 14 14
31: 14 17 | 1 13
6: 14 14 | 1 14
2: 1 24 | 14 4
0: 8 11
13: 14 3 | 1 12
15: 1 | 14
17: 14 2 | 1 7
23: 25 1 | 22 14
28: 16 1
4: 1 1
20: 14 14 | 1 15
3: 5 14 | 16 1
27: 1 6 | 14 18
14: "b"
21: 14 1 | 1 14
25: 1 1 | 1 14
22: 14 14
8: 42
26: 14 22 | 1 20
18: 15 15
7: 14 5 | 1 21
24: 14 1
abbbbbabbbaaaababbaabbbbabababbbabbbbbbabaaaa
bbabbbbaabaabba
babbbbaabbbbbabbbbbbaabaaabaaa
aaabbbbbbaaaabaababaabababbabaaabbababababaaa
bbbbbbbaaaabbbbaaabbabaaa
bbbababbbbaaaaaaaabbababaaababaabab
ababaaaaaabaaab
ababaaaaabbbaba
baabbaaaabbaaaababbaababb
abbbbabbbbaaaababbbbbbaaaababb
aaaaabbaabaaaaababaa
aaaabbaaaabbaaa
aaaabbaabbaaaaaaabbbabbbaaabbaabaaa
babaaabbbaaabaababbaabababaaab
aabbbbbaabbbaaaaaabbbbbababaaaaabbaaabba
Without updating rules 8 and 11, these rules only match three messages: bbabbbbaabaabba, ababaaaaaabaaab, and ababaaaaabbbaba.
However, after updating rules 8 and 11, a total of 12 messages match:
bbabbbbaabaabba
babbbbaabbbbbabbbbbbaabaaabaaa
aaabbbbbbaaaabaababaabababbabaaabbababababaaa
bbbbbbbaaaabbbbaaabbabaaa
bbbababbbbaaaaaaaabbababaaababaabab
ababaaaaaabaaab
ababaaaaabbbaba
baabbaaaabbaaaababbaababb
abbbbabbbbaaaababbbbbbaaaababb
aaaaabbaabaaaaababaa
aaaabbaabbaaaaaaabbbabbbaaabbaabaaa
aabbbbbaabbbaaaaaabbbbbababaaaaabbaaabba
After updating rules 8 and 11, how many messages completely match rule 0?
Your puzzle answer was 412.
Both parts of this puzzle are complete! They provide two gold stars: **
At this point, you should return to your Advent calendar and try another puzzle.
If you still want to see it, you can get your puzzle input.

200
2020/day19/README.org Normal file
View File

@@ -0,0 +1,200 @@
** --- Day 19: Monster Messages ---
You land in an airport surrounded by dense forest. As you walk to your
high-speed train, the Elves at the Mythical Information Bureau contact
you again. They think their satellite has collected an image of a /sea
monster/! Unfortunately, the connection to the satellite is having
problems, and many of the messages sent back from the satellite have
been corrupted.
They sent you a list of /the rules valid messages should obey/ and a
list of /received messages/ they've collected so far (your puzzle
input).
The /rules for valid messages/ (the top part of your puzzle input) are
numbered and build upon each other. For example:
#+BEGIN_EXAMPLE
0: 1 2
1: "a"
2: 1 3 | 3 1
3: "b"
#+END_EXAMPLE
Some rules, like =3: "b"=, simply match a single character (in this
case, =b=).
The remaining rules list the sub-rules that must be followed; for
example, the rule =0: 1 2= means that to match rule =0=, the text being
checked must match rule =1=, and the text after the part that matched
rule =1= must then match rule =2=.
Some of the rules have multiple lists of sub-rules separated by a pipe
(=|=). This means that /at least one/ list of sub-rules must match. (The
ones that match might be different each time the rule is encountered.)
For example, the rule =2: 1 3 | 3 1= means that to match rule =2=, the
text being checked must match rule =1= followed by rule =3= /or/ it must
match rule =3= followed by rule =1=.
Fortunately, there are no loops in the rules, so the list of possible
matches will be finite. Since rule =1= matches =a= and rule =3= matches
=b=, rule =2= matches either =ab= or =ba=. Therefore, rule =0= matches
=aab= or =aba=.
Here's a more interesting example:
#+BEGIN_EXAMPLE
0: 4 1 5
1: 2 3 | 3 2
2: 4 4 | 5 5
3: 4 5 | 5 4
4: "a"
5: "b"
#+END_EXAMPLE
Here, because rule =4= matches =a= and rule =5= matches =b=, rule =2=
matches two letters that are the same (=aa= or =bb=), and rule =3=
matches two letters that are different (=ab= or =ba=).
Since rule =1= matches rules =2= and =3= once each in either order, it
must match two pairs of letters, one pair with matching letters and one
pair with different letters. This leaves eight possibilities: =aaab=,
=aaba=, =bbab=, =bbba=, =abaa=, =abbb=, =baaa=, or =babb=.
Rule =0=, therefore, matches =a= (rule =4=), then any of the eight
options from rule =1=, then =b= (rule =5=): =aaaabb=, =aaabab=,
=abbabb=, =abbbab=, =aabaab=, =aabbbb=, =abaaab=, or =ababbb=.
The /received messages/ (the bottom part of your puzzle input) need to
be checked against the rules so you can determine which are valid and
which are corrupted. Including the rules and the messages together, this
might look like:
#+BEGIN_EXAMPLE
0: 4 1 5
1: 2 3 | 3 2
2: 4 4 | 5 5
3: 4 5 | 5 4
4: "a"
5: "b"
ababbb
bababa
abbbab
aaabbb
aaaabbb
#+END_EXAMPLE
Your goal is to determine /the number of messages that completely match
rule =0=/. In the above example, =ababbb= and =abbbab= match, but
=bababa=, =aaabbb=, and =aaaabbb= do not, producing the answer /=2=/.
The whole message must match all of rule =0=; there can't be extra
unmatched characters in the message. (For example, =aaaabbb= might
appear to match rule =0= above, but it has an extra unmatched =b= on the
end.)
/How many messages completely match rule =0=?/
Your puzzle answer was =285=.
** --- Part Two ---
As you look over the list of messages, you realize your matching rules
aren't quite right. To fix them, completely replace rules =8: 42= and
=11: 42 31= with the following:
#+BEGIN_EXAMPLE
8: 42 | 42 8
11: 42 31 | 42 11 31
#+END_EXAMPLE
This small change has a big impact: now, the rules /do/ contain loops,
and the list of messages they could hypothetically match is infinite.
You'll need to determine how these changes affect which messages are
valid.
Fortunately, many of the rules are unaffected by this change; it might
help to start by looking at which rules always match the same set of
values and how /those/ rules (especially rules =42= and =31=) are used
by the new versions of rules =8= and =11=.
(Remember, /you only need to handle the rules you have/; building a
solution that could handle any hypothetical combination of rules would
be [[https://en.wikipedia.org/wiki/Formal_grammar][significantly more
difficult]].)
For example:
#+BEGIN_EXAMPLE
42: 9 14 | 10 1
9: 14 27 | 1 26
10: 23 14 | 28 1
1: "a"
11: 42 31
5: 1 14 | 15 1
19: 14 1 | 14 14
12: 24 14 | 19 1
16: 15 1 | 14 14
31: 14 17 | 1 13
6: 14 14 | 1 14
2: 1 24 | 14 4
0: 8 11
13: 14 3 | 1 12
15: 1 | 14
17: 14 2 | 1 7
23: 25 1 | 22 14
28: 16 1
4: 1 1
20: 14 14 | 1 15
3: 5 14 | 16 1
27: 1 6 | 14 18
14: "b"
21: 14 1 | 1 14
25: 1 1 | 1 14
22: 14 14
8: 42
26: 14 22 | 1 20
18: 15 15
7: 14 5 | 1 21
24: 14 1
abbbbbabbbaaaababbaabbbbabababbbabbbbbbabaaaa
bbabbbbaabaabba
babbbbaabbbbbabbbbbbaabaaabaaa
aaabbbbbbaaaabaababaabababbabaaabbababababaaa
bbbbbbbaaaabbbbaaabbabaaa
bbbababbbbaaaaaaaabbababaaababaabab
ababaaaaaabaaab
ababaaaaabbbaba
baabbaaaabbaaaababbaababb
abbbbabbbbaaaababbbbbbaaaababb
aaaaabbaabaaaaababaa
aaaabbaaaabbaaa
aaaabbaabbaaaaaaabbbabbbaaabbaabaaa
babaaabbbaaabaababbaabababaaab
aabbbbbaabbbaaaaaabbbbbababaaaaabbaaabba
#+END_EXAMPLE
Without updating rules =8= and =11=, these rules only match three
messages: =bbabbbbaabaabba=, =ababaaaaaabaaab=, and =ababaaaaabbbaba=.
However, after updating rules =8= and =11=, a total of /=12=/ messages
match:
- =bbabbbbaabaabba=
- =babbbbaabbbbbabbbbbbaabaaabaaa=
- =aaabbbbbbaaaabaababaabababbabaaabbababababaaa=
- =bbbbbbbaaaabbbbaaabbabaaa=
- =bbbababbbbaaaaaaaabbababaaababaabab=
- =ababaaaaaabaaab=
- =ababaaaaabbbaba=
- =baabbaaaabbaaaababbaababb=
- =abbbbabbbbaaaababbbbbbaaaababb=
- =aaaaabbaabaaaaababaa=
- =aaaabbaabbaaaaaaabbbabbbaaabbaabaaa=
- =aabbbbbaabbbaaaaaabbbbbababaaaaabbaaabba=
/After updating rules =8= and =11=, how many messages completely match
rule =0=?/
Your puzzle answer was =412=.
Both parts of this puzzle are complete! They provide two gold stars: **

165
2020/day19/aoc-c.c Normal file
View File

@@ -0,0 +1,165 @@
/* aoc-c.c: Advent2020, day 19, parts 1 and 2
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include "list.h"
#include "debug.h"
#define MAX_RULES 256
#define MAX_MSG 512
/* to simplify code, we consider here that :
* - a rule has no more than 3 sub-rules
* - there are at most 2 possible sub-rules per rule
*/
struct subrule {
int rule[2][3];
};
static struct rule {
enum type {
SUB,
CHR
} type;
struct subrule sub;
int str;
} rules[MAX_RULES] = {
[0 ... (MAX_RULES-1)] = {
.sub.rule = {{-1, -1, -1}, {-1, -1, -1}}
}
};
static struct mesg {
int len;
char *str;
} mesg[MAX_MSG];
static int nrules, nmesg;
static int match(struct mesg *msg, int *pos, int rule)
{
struct rule *r = rules + rule;
int found = 0, postmp, recurse = 0;
if (r->type == CHR)
return rules[rule].str == msg->str[(*pos)++];
for (int side = 0; side < 2; ++side, recurse = 0, found = 0) {
if (r->sub.rule[side][0] == -1)
break;
postmp = *pos;
found = 1;
for (int sub = 0; sub < 3 && r->sub.rule[side][sub] >= 0; ++sub) {
if (*pos == msg->len)
return recurse;
recurse = r->sub.rule[side][sub] == rule;
if (!match(msg, pos, r->sub.rule[side][sub])) {
found = 0;
*pos = postmp; /* roll back */
break;
}
}
if (found)
break;
}
return found;
}
static long part1()
{
int ret = 0;
for (int msg = 0, pos = 0; msg < nmesg; ++msg, pos = 0)
if (match(mesg + msg, &pos, 0))
ret += pos == mesg[msg].len;
return ret;
}
static long part2()
{
static const struct subrule new[2] = {
{{{42, -1, -1}, {42, 8, -1}}},
{{{42, 31, -1}, {42, 11, 31}}}
};
rules[8].sub = new[0];
rules[11].sub = new[1];
return part1();
}
static void parse()
{
size_t alloc;
ssize_t len;
char *buf = NULL, *tok;
int rule;
while ((len = getline(&buf, &alloc, stdin)) > 0) {
int set = 0, sub = 0;
buf[--len] = 0;
if (len == 0)
continue;
if (isalpha(*buf)) { /* message */
mesg[nmesg].len = len;
mesg[nmesg++].str = strdup(buf);
} else { /* rule */
if (!(tok = strtok(buf, ": "))) /* rule number */
continue;
nrules++;
rule = atoi(tok);
while ((tok = strtok(NULL, ":\" "))) {
switch (*tok) {
case 'a': /* final rule */
case 'b':
rules[rule].type = CHR;
rules[rule].str = *tok;
break;
case '|': /* second ruleset */
set++;
sub = 0;
break;
default:
rules[rule].type = SUB;
rules[rule].sub.rule[set][sub] = atoi(tok);
sub++;
break;
}
}
}
}
free(buf);
}
static int usage(char *prg)
{
fprintf(stderr, "Usage: %s [-d debug_level] [-p part]\n", prg);
return 1;
}
int main(ac, av)
int ac;
char **av;
{
int opt, part = 1;
while ((opt = getopt(ac, av, "d:p:")) != -1) {
switch (opt) {
case 'd':
debug_level_set(atoi(optarg));
break;
case 'p': /* 1 or 2 */
part = atoi(optarg);
if (part < 1 || part > 2)
default:
return usage(*av);
}
}
parse();
printf("%s : res=%ld\n", *av, part == 1? part1(): part2());
exit (0);
}

View File

@@ -1,203 +0,0 @@
/* ex1-c: Advent2020 game, day 18/tasks 1 & 2
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define T_LPAR (-'(')
#define T_RPAR (-')')
#define T_PLUS (-'+')
#define T_MULT (-'*')
#define T_ERR (-'E')
#define T_OK (-'O')
#define T_END (-'$')
#define LEN_MAX 1024
#define NPUSH(n) (push(&nstack, (n)))
#define OPUSH(o) (push(&ostack, (o)))
#define NPOP() (pop(&nstack))
#define OPOP() (pop(&ostack))
#define NTOP() (top(&nstack))
#define OTOP() (top(&ostack))
#define OEMPTY() (empty(&ostack))
#define DIGIT(c) (((c) >= '0') && ((c) <= '9'))
static struct stack {
int last;
long elt[LEN_MAX];
} nstack, ostack;
static char *saveptr=NULL;
static int prio_1(long op)
{
return op==T_PLUS || op==T_MULT? 1: 0;
}
static int prio_2(long op)
{
return op==T_PLUS? 2: op==T_MULT? 1: 0;
}
static int (*prio)()=&prio_1;
static long push(struct stack *s, long val)
{
s->elt[s->last++]=val;
return val;
}
static long pop(struct stack *s)
{
return s->elt[--s->last];
}
static long top(struct stack *s)
{
return s->elt[s->last-1];
}
static long empty(struct stack *s)
{
return s->last==0;
}
static void print() {
int i;
printf("NSTACK: ");
for (i=0; i<nstack.last; ++i) {
printf("%ld ", nstack.elt[i]);
}
printf("\nOSTACK: ");
for (i=0; i<ostack.last; ++i) {
printf("%c ", (char) -ostack.elt[i]);
}
printf("\n");
}
static long get_tok()
{
char *p, c;
long val=0;
p=saveptr;
while (!val) {
c=*p;
switch (c) {
case ' ':
break;
case '(':
case ')':
case '*':
case '+':
val=-c;
break;
case '\n':
case '\0':
val=T_END;
break;
default:
if (! DIGIT(c)) {
val=T_ERR;
break;
}
while (DIGIT(c)) {
val=(val*10 + c - '0');
p++;
c=*p;
}
p--;
break;
}
p++;
}
saveptr=p;
return val;
}
static long eval_top()
{
long val2 = NPOP();
long val1 = NPOP();
char op = OPOP();
NPUSH(op==T_PLUS? val1+val2: val1*val2);
return NTOP();
}
static long eval_expr()
{
long res=T_LPAR;
res=get_tok();
while (res!=T_ERR && res!=T_END) {
switch (res) {
case T_LPAR:
OPUSH(res);
break;
case T_RPAR:
while(!OEMPTY() && OTOP() != T_LPAR)
eval_top();
if(!OEMPTY()) // remove '('
OPOP();
break;
case T_PLUS:
case T_MULT:
while (!OEMPTY() && (*prio)(OTOP()) >= (*prio)(res))
eval_top();
OPUSH(res);
break;
default:
NPUSH(res);
break;
}
res=get_tok();
//print();
}
while(!OEMPTY())
eval_top();
// return NSTACK's top
//printf("Returning %ld\n", NTOP());
return NPOP();
//end:
// return left;
}
int main(ac, av)
int ac;
char **av;
{
char line[1024];
long res=0, tmp;
if (ac != 2) {
fprintf(stderr, "usage: %s [1|2]\n", *av);
exit (1);
}
if (**(av+1) == '2')
prio=&prio_2;
while (fgets(line, sizeof line, stdin)) {
//gets(line, sizeof line, stdin);
//NPUSH(10);
//NPUSH(100);
//NPUSH(1000);
//print();
//printf("TOP=%ld\n", NTOP());
//NPOP();
//print();
saveptr=line;
//printf("%s", line);
tmp=eval_expr();
//printf("%s : res=%ld\n", line, tmp);
res+=tmp;
}
printf("%s : res=%ld\n", *av, res);
exit (0);
}

View File

@@ -1,8 +0,0 @@
ex1.bash : res=5966506063747
time: 0:00.56 real, 0.56 user, 0.00 sys
context-switch: 4+1, page-faults: 0+224
ex2.bash res=1714
time: 0:02.14 real, 2.05 user, 0.02 sys
context-switch: 1146+1, page-faults: 0+605

View File

@@ -1,30 +1,108 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := INPUT.txt
SHELL := /bin/bash
CFLAGS := -w -g
#CFLAGS := -w -g -pg
#CFLAGS := -w -O3
CC := gcc
BEAR := bear
CCLSFILE:= compile_commands.json
LIB := aoc_$(shell uname -m)
INCDIR := ../include
LIBDIR := ../lib
LDFLAGS := -L$(LIBDIR)
#LDLIB := -l$(LIB) -lm
LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
# CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations
CFLAGS += -Wno-unused-result
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
--sigill-diagnostics=yes --quiet --show-error-list=yes
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH)
.PHONY: clean all compile deploy ex1 ex2
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 ccls
all: ex1 ex2
all: README.org ccls ex1 ex2
output:
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
memcheck: memcheck1 memcheck2
compile: ex1-c ex2-c
memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
ex1:
@$(TIME) ex1.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
memcheck2: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
ex2:
@$(TIME) ex2.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1
compile: aoc-c
cpp: aoc-c.i
assembly: aoc-c.s
ex1: aoc-c
@$(TIME) ex1.bash -p 1 < $(INPUT)
@$(TIME) aoc-c -p 1 < $(INPUT)
ex2: aoc-c
@$(TIME) ex2.bash -p 2 < $(INPUT)
@$(TIME) aoc-c -p 2 < $(INPUT)
ccls: $(CCLSFILE)
clean:
@rm -f ex1-c ex2-c core
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
deploy:
@$(MAKE) -C .. deploy
.c:
@echo compiling $<
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
# generate pre-processed file (.i) and assembler (.s)
%.i: %.c
@echo generating $@
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
%.s: %.c
@echo generating $@
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
# generate README.org from README.html (must cleanup !)
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@
# generate compile_commands.json
$(CCLSFILE): aoc-c.c Makefile
$(BEAR) -- make clean compile
bear: clean
@$(BEAR) -- make compile
@touch .ccls-root

View File

@@ -1,8 +0,0 @@
ex1.bash: res=2211
time: 0:01.72 real, 1.71 user, 0.00 sys
context-switch: 9+1, page-faults: 0+1090
ex2.bash: res=vv,nlxsmb,rnbhjk,bvnkk,ttxvphb,qmkz,trmzkcfg,jpvz
time: 0:01.75 real, 1.74 user, 0.00 sys
context-switch: 36+4, page-faults: 0+1388

View File

@@ -1,45 +0,0 @@
--- Day 21: Allergen Assessment ---
You reach the train's last stop and the closest you can get to your vacation island without getting wet. There aren't even any boats here, but nothing can stop you now: you build a raft. You just need a few days' worth of food for your journey.
You don't speak the local language, so you can't read any ingredients lists. However, sometimes, allergens are listed in a language you do understand. You should be able to use this information to determine which ingredient contains which allergen and work out which foods are safe to take with you on your trip.
You start by compiling a list of foods (your puzzle input), one food per line. Each line includes that food's ingredients list followed by some or all of the allergens the food contains.
Each allergen is found in exactly one ingredient. Each ingredient contains zero or one allergen. Allergens aren't always marked; when they're listed (as in (contains nuts, shellfish) after an ingredients list), the ingredient that contains each listed allergen will be somewhere in the corresponding ingredients list. However, even if an allergen isn't listed, the ingredient that contains that allergen could still be present: maybe they forgot to label it, or maybe it was labeled in a language you don't know.
For example, consider the following list of foods:
mxmxvkd kfcds sqjhc nhms (contains dairy, fish)
trh fvjkl sbzzf mxmxvkd (contains dairy)
sqjhc fvjkl (contains soy)
sqjhc mxmxvkd sbzzf (contains fish)
The first food in the list has four ingredients (written in a language you don't understand): mxmxvkd, kfcds, sqjhc, and nhms. While the food might contain other allergens, a few allergens the food definitely contains are listed afterward: dairy and fish.
The first step is to determine which ingredients can't possibly contain any of the allergens in any food in your list. In the above example, none of the ingredients kfcds, nhms, sbzzf, or trh can contain an allergen. Counting the number of times any of these ingredients appear in any ingredients list produces 5: they all appear once each except sbzzf, which appears twice.
Determine which ingredients cannot possibly contain any of the allergens in your list. How many times do any of those ingredients appear?
Your puzzle answer was 2211.
The first half of this puzzle is complete! It provides one gold star: *
--- Part Two ---
Now that you've isolated the inert ingredients, you should have enough information to figure out which ingredient contains which allergen.
In the above example:
mxmxvkd contains dairy.
sqjhc contains fish.
fvjkl contains soy.
Arrange the ingredients alphabetically by their allergen and separate them by commas to produce your canonical dangerous ingredient list. (There should not be any spaces in your canonical dangerous ingredient list.) In the above example, this would be mxmxvkd,sqjhc,fvjkl.
Time to stock your raft with supplies. What is your canonical dangerous ingredient list?
Answer:
Although it hasn't changed, you can still get your puzzle input.
You can also [Share] this puzzle.

76
2020/day21/README.org Normal file
View File

@@ -0,0 +1,76 @@
** --- Day 21: Allergen Assessment ---
You reach the train's last stop and the closest you can get to your
vacation island without getting wet. There aren't even any boats here,
but nothing can stop you now: you build a raft. You just need a few
days' worth of food for your journey.
You don't speak the local language, so you can't read any ingredients
lists. However, sometimes, allergens are listed in a language you /do/
understand. You should be able to use this information to determine
which ingredient contains which allergen and work out which foods are
safe to take with you on your trip.
You start by compiling a list of foods (your puzzle input), one food per
line. Each line includes that food's /ingredients list/ followed by some
or all of the allergens the food contains.
Each allergen is found in exactly one ingredient. Each ingredient
contains zero or one allergen. /Allergens aren't always marked/; when
they're listed (as in =(contains nuts, shellfish)= after an ingredients
list), the ingredient that contains each listed allergen will be
/somewhere in the corresponding ingredients list/. However, even if an
allergen isn't listed, the ingredient that contains that allergen could
still be present: maybe they forgot to label it, or maybe it was labeled
in a language you don't know.
For example, consider the following list of foods:
#+begin_example
mxmxvkd kfcds sqjhc nhms (contains dairy, fish)
trh fvjkl sbzzf mxmxvkd (contains dairy)
sqjhc fvjkl (contains soy)
sqjhc mxmxvkd sbzzf (contains fish)
#+end_example
The first food in the list has four ingredients (written in a language
you don't understand): =mxmxvkd=, =kfcds=, =sqjhc=, and =nhms=. While
the food might contain other allergens, a few allergens the food
definitely contains are listed afterward: =dairy= and =fish=.
The first step is to determine which ingredients /can't possibly/
contain any of the allergens in any food in your list. In the above
example, none of the ingredients =kfcds=, =nhms=, =sbzzf=, or =trh= can
contain an allergen. Counting the number of times any of these
ingredients appear in any ingredients list produces /=5=/: they all
appear once each except =sbzzf=, which appears twice.
Determine which ingredients cannot possibly contain any of the allergens
in your list. /How many times do any of those ingredients appear?/
Your puzzle answer was =2211=.
** --- Part Two ---
Now that you've isolated the inert ingredients, you should have enough
information to figure out which ingredient contains which allergen.
In the above example:
- =mxmxvkd= contains =dairy=.
- =sqjhc= contains =fish=.
- =fvjkl= contains =soy=.
Arrange the ingredients /alphabetically by their allergen/ and separate
them by commas to produce your /canonical dangerous ingredient list/.
(There should /not be any spaces/ in your canonical dangerous ingredient
list.) In the above example, this would be /=mxmxvkd,sqjhc,fvjkl=/.
Time to stock your raft with supplies. /What is your canonical dangerous
ingredient list?/
Your puzzle answer was
=vv,nlxsmb,rnbhjk,bvnkk,ttxvphb,qmkz,trmzkcfg,jpvz=.
Both parts of this puzzle are complete! They provide two gold stars: **
At this point, all that is left is for you to [[/2020][admire your
Advent calendar]].

View File

@@ -1,30 +1,108 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := INPUT.txt
SHELL := /bin/bash
CFLAGS := -w -g
#CFLAGS := -w -g -pg
#CFLAGS := -w -O3
CC := gcc
BEAR := bear
CCLSFILE:= compile_commands.json
LIB := aoc_$(shell uname -m)
INCDIR := ../include
LIBDIR := ../lib
LDFLAGS := -L$(LIBDIR)
#LDLIB := -l$(LIB) -lm
LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
# CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations
CFLAGS += -Wno-unused-result
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
--sigill-diagnostics=yes --quiet --show-error-list=yes
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH)
.PHONY: clean all compile deploy ex1 ex2
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 ccls bear
all: ex1 ex2
all: README.org ccls ex1 ex2
output:
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
memcheck: memcheck1 memcheck2
compile: ex1-c ex2-c
memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
ex1:
@$(TIME) ex1.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
memcheck2: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
ex2:
@$(TIME) ex2.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1
compile: aoc-c
cpp: aoc-c.i
assembly: aoc-c.s
ex1: aoc-c
@$(TIME) ex1.bash -p 1 < $(INPUT)
@$(TIME) aoc-c -p 1 < $(INPUT)
ex2: aoc-c
@$(TIME) ex2.bash -p 2 < $(INPUT)
@$(TIME) aoc-c -p 2 < $(INPUT)
ccls: $(CCLSFILE)
clean:
@rm -f ex1-c ex2-c core
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
deploy:
@$(MAKE) -C .. deploy
.c:
@echo compiling $<
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
# generate pre-processed file (.i) and assembler (.s)
%.i: %.c
@echo generating $@
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
%.s: %.c
@echo generating $@
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
# generate README.org from README.html (must cleanup !)
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@
# generate compile_commands.json
$(CCLSFILE): aoc-c.c Makefile
$(BEAR) -- make clean compile
bear: clean
@$(BEAR) -- make compile
@touch .ccls-root

View File

@@ -1,8 +0,0 @@
ex1.bash: res=31314
time: 0:00.07 real, 0.06 user, 0.00 sys
context-switch: 2+1, page-faults: 0+168
ex2.bash: res=32760
time: 1:21.92 real, 81.89 user, 0.01 sys
context-switch: 462+1, page-faults: 0+5135

View File

@@ -1,386 +0,0 @@
--- Day 22: Crab Combat ---
It only takes a few hours of sailing the ocean on a raft for boredom to sink in. Fortunately, you brought a small deck of space cards! You'd like to play a game of Combat, and there's even an opponent available: a small crab that climbed aboard your raft before you left.
Fortunately, it doesn't take long to teach the crab the rules.
Before the game starts, split the cards so each player has their own deck (your puzzle input). Then, the game consists of a series of rounds: both players draw their top card, and the player with the higher-valued card wins the round. The winner keeps both cards, placing them on the bottom of their own deck so that the winner's card is above the other card. If this causes a player to have all of the cards, they win, and the game ends.
For example, consider the following starting decks:
Player 1:
9
2
6
3
1
Player 2:
5
8
4
7
10
This arrangement means that player 1's deck contains 5 cards, with 9 on top and 1 on the bottom; player 2's deck also contains 5 cards, with 5 on top and 10 on the bottom.
The first round begins with both players drawing the top card of their decks: 9 and 5. Player 1 has the higher card, so both cards move to the bottom of player 1's deck such that 9 is above 5. In total, it takes 29 rounds before a player has all of the cards:
-- Round 1 --
Player 1's deck: 9, 2, 6, 3, 1
Player 2's deck: 5, 8, 4, 7, 10
Player 1 plays: 9
Player 2 plays: 5
Player 1 wins the round!
-- Round 2 --
Player 1's deck: 2, 6, 3, 1, 9, 5
Player 2's deck: 8, 4, 7, 10
Player 1 plays: 2
Player 2 plays: 8
Player 2 wins the round!
-- Round 3 --
Player 1's deck: 6, 3, 1, 9, 5
Player 2's deck: 4, 7, 10, 8, 2
Player 1 plays: 6
Player 2 plays: 4
Player 1 wins the round!
-- Round 4 --
Player 1's deck: 3, 1, 9, 5, 6, 4
Player 2's deck: 7, 10, 8, 2
Player 1 plays: 3
Player 2 plays: 7
Player 2 wins the round!
-- Round 5 --
Player 1's deck: 1, 9, 5, 6, 4
Player 2's deck: 10, 8, 2, 7, 3
Player 1 plays: 1
Player 2 plays: 10
Player 2 wins the round!
...several more rounds pass...
-- Round 27 --
Player 1's deck: 5, 4, 1
Player 2's deck: 8, 9, 7, 3, 2, 10, 6
Player 1 plays: 5
Player 2 plays: 8
Player 2 wins the round!
-- Round 28 --
Player 1's deck: 4, 1
Player 2's deck: 9, 7, 3, 2, 10, 6, 8, 5
Player 1 plays: 4
Player 2 plays: 9
Player 2 wins the round!
-- Round 29 --
Player 1's deck: 1
Player 2's deck: 7, 3, 2, 10, 6, 8, 5, 9, 4
Player 1 plays: 1
Player 2 plays: 7
Player 2 wins the round!
== Post-game results ==
Player 1's deck:
Player 2's deck: 3, 2, 10, 6, 8, 5, 9, 4, 7, 1
Once the game ends, you can calculate the winning player's score. The bottom card in their deck is worth the value of the card multiplied by 1, the second-from-the-bottom card is worth the value of the card multiplied by 2, and so on. With 10 cards, the top card is worth the value on the card multiplied by 10. In this example, the winning player's score is:
3 * 10
+ 2 * 9
+ 10 * 8
+ 6 * 7
+ 8 * 6
+ 5 * 5
+ 9 * 4
+ 4 * 3
+ 7 * 2
+ 1 * 1
= 306
So, once the game ends, the winning player's score is 306.
Play the small crab in a game of Combat using the two decks you just dealt. What is the winning player's score?
Your puzzle answer was 31314.
The first half of this puzzle is complete! It provides one gold star: *
--- Part Two ---
You lost to the small crab! Fortunately, crabs aren't very good at recursion. To defend your honor as a Raft Captain, you challenge the small crab to a game of Recursive Combat.
Recursive Combat still starts by splitting the cards into two decks (you offer to play with the same starting decks as before - it's only fair). Then, the game consists of a series of rounds with a few changes:
Before either player deals a card, if there was a previous round in this game that had exactly the same cards in the same order in the same players' decks, the game instantly ends in a win for player 1. Previous rounds from other games are not considered. (This prevents infinite games of Recursive Combat, which everyone agrees is a bad idea.)
Otherwise, this round's cards must be in a new configuration; the players begin the round by each drawing the top card of their deck as normal.
If both players have at least as many cards remaining in their deck as the value of the card they just drew, the winner of the round is determined by playing a new game of Recursive Combat (see below).
Otherwise, at least one player must not have enough cards left in their deck to recurse; the winner of the round is the player with the higher-value card.
As in regular Combat, the winner of the round (even if they won the round by winning a sub-game) takes the two cards dealt at the beginning of the round and places them on the bottom of their own deck (again so that the winner's card is above the other card). Note that the winner's card might be the lower-valued of the two cards if they won the round due to winning a sub-game. If collecting cards by winning the round causes a player to have all of the cards, they win, and the game ends.
Here is an example of a small game that would loop forever without the infinite game prevention rule:
Player 1:
43
19
Player 2:
2
29
14
During a round of Recursive Combat, if both players have at least as many cards in their own decks as the number on the card they just dealt, the winner of the round is determined by recursing into a sub-game of Recursive Combat. (For example, if player 1 draws the 3 card, and player 2 draws the 7 card, this would occur if player 1 has at least 3 cards left and player 2 has at least 7 cards left, not counting the 3 and 7 cards that were drawn.)
To play a sub-game of Recursive Combat, each player creates a new deck by making a copy of the next cards in their deck (the quantity of cards copied is equal to the number on the card they drew to trigger the sub-game). During this sub-game, the game that triggered it is on hold and completely unaffected; no cards are removed from players' decks to form the sub-game. (For example, if player 1 drew the 3 card, their deck in the sub-game would be copies of the next three cards in their deck.)
Here is a complete example of gameplay, where Game 1 is the primary game of Recursive Combat:
=== Game 1 ===
-- Round 1 (Game 1) --
Player 1's deck: 9, 2, 6, 3, 1
Player 2's deck: 5, 8, 4, 7, 10
Player 1 plays: 9
Player 2 plays: 5
Player 1 wins round 1 of game 1!
-- Round 2 (Game 1) --
Player 1's deck: 2, 6, 3, 1, 9, 5
Player 2's deck: 8, 4, 7, 10
Player 1 plays: 2
Player 2 plays: 8
Player 2 wins round 2 of game 1!
-- Round 3 (Game 1) --
Player 1's deck: 6, 3, 1, 9, 5
Player 2's deck: 4, 7, 10, 8, 2
Player 1 plays: 6
Player 2 plays: 4
Player 1 wins round 3 of game 1!
-- Round 4 (Game 1) --
Player 1's deck: 3, 1, 9, 5, 6, 4
Player 2's deck: 7, 10, 8, 2
Player 1 plays: 3
Player 2 plays: 7
Player 2 wins round 4 of game 1!
-- Round 5 (Game 1) --
Player 1's deck: 1, 9, 5, 6, 4
Player 2's deck: 10, 8, 2, 7, 3
Player 1 plays: 1
Player 2 plays: 10
Player 2 wins round 5 of game 1!
-- Round 6 (Game 1) --
Player 1's deck: 9, 5, 6, 4
Player 2's deck: 8, 2, 7, 3, 10, 1
Player 1 plays: 9
Player 2 plays: 8
Player 1 wins round 6 of game 1!
-- Round 7 (Game 1) --
Player 1's deck: 5, 6, 4, 9, 8
Player 2's deck: 2, 7, 3, 10, 1
Player 1 plays: 5
Player 2 plays: 2
Player 1 wins round 7 of game 1!
-- Round 8 (Game 1) --
Player 1's deck: 6, 4, 9, 8, 5, 2
Player 2's deck: 7, 3, 10, 1
Player 1 plays: 6
Player 2 plays: 7
Player 2 wins round 8 of game 1!
-- Round 9 (Game 1) --
Player 1's deck: 4, 9, 8, 5, 2
Player 2's deck: 3, 10, 1, 7, 6
Player 1 plays: 4
Player 2 plays: 3
Playing a sub-game to determine the winner...
=== Game 2 ===
-- Round 1 (Game 2) --
Player 1's deck: 9, 8, 5, 2
Player 2's deck: 10, 1, 7
Player 1 plays: 9
Player 2 plays: 10
Player 2 wins round 1 of game 2!
-- Round 2 (Game 2) --
Player 1's deck: 8, 5, 2
Player 2's deck: 1, 7, 10, 9
Player 1 plays: 8
Player 2 plays: 1
Player 1 wins round 2 of game 2!
-- Round 3 (Game 2) --
Player 1's deck: 5, 2, 8, 1
Player 2's deck: 7, 10, 9
Player 1 plays: 5
Player 2 plays: 7
Player 2 wins round 3 of game 2!
-- Round 4 (Game 2) --
Player 1's deck: 2, 8, 1
Player 2's deck: 10, 9, 7, 5
Player 1 plays: 2
Player 2 plays: 10
Player 2 wins round 4 of game 2!
-- Round 5 (Game 2) --
Player 1's deck: 8, 1
Player 2's deck: 9, 7, 5, 10, 2
Player 1 plays: 8
Player 2 plays: 9
Player 2 wins round 5 of game 2!
-- Round 6 (Game 2) --
Player 1's deck: 1
Player 2's deck: 7, 5, 10, 2, 9, 8
Player 1 plays: 1
Player 2 plays: 7
Player 2 wins round 6 of game 2!
The winner of game 2 is player 2!
...anyway, back to game 1.
Player 2 wins round 9 of game 1!
-- Round 10 (Game 1) --
Player 1's deck: 9, 8, 5, 2
Player 2's deck: 10, 1, 7, 6, 3, 4
Player 1 plays: 9
Player 2 plays: 10
Player 2 wins round 10 of game 1!
-- Round 11 (Game 1) --
Player 1's deck: 8, 5, 2
Player 2's deck: 1, 7, 6, 3, 4, 10, 9
Player 1 plays: 8
Player 2 plays: 1
Player 1 wins round 11 of game 1!
-- Round 12 (Game 1) --
Player 1's deck: 5, 2, 8, 1
Player 2's deck: 7, 6, 3, 4, 10, 9
Player 1 plays: 5
Player 2 plays: 7
Player 2 wins round 12 of game 1!
-- Round 13 (Game 1) --
Player 1's deck: 2, 8, 1
Player 2's deck: 6, 3, 4, 10, 9, 7, 5
Player 1 plays: 2
Player 2 plays: 6
Playing a sub-game to determine the winner...
=== Game 3 ===
-- Round 1 (Game 3) --
Player 1's deck: 8, 1
Player 2's deck: 3, 4, 10, 9, 7, 5
Player 1 plays: 8
Player 2 plays: 3
Player 1 wins round 1 of game 3!
-- Round 2 (Game 3) --
Player 1's deck: 1, 8, 3
Player 2's deck: 4, 10, 9, 7, 5
Player 1 plays: 1
Player 2 plays: 4
Playing a sub-game to determine the winner...
=== Game 4 ===
-- Round 1 (Game 4) --
Player 1's deck: 8
Player 2's deck: 10, 9, 7, 5
Player 1 plays: 8
Player 2 plays: 10
Player 2 wins round 1 of game 4!
The winner of game 4 is player 2!
...anyway, back to game 3.
Player 2 wins round 2 of game 3!
-- Round 3 (Game 3) --
Player 1's deck: 8, 3
Player 2's deck: 10, 9, 7, 5, 4, 1
Player 1 plays: 8
Player 2 plays: 10
Player 2 wins round 3 of game 3!
-- Round 4 (Game 3) --
Player 1's deck: 3
Player 2's deck: 9, 7, 5, 4, 1, 10, 8
Player 1 plays: 3
Player 2 plays: 9
Player 2 wins round 4 of game 3!
The winner of game 3 is player 2!
...anyway, back to game 1.
Player 2 wins round 13 of game 1!
-- Round 14 (Game 1) --
Player 1's deck: 8, 1
Player 2's deck: 3, 4, 10, 9, 7, 5, 6, 2
Player 1 plays: 8
Player 2 plays: 3
Player 1 wins round 14 of game 1!
-- Round 15 (Game 1) --
Player 1's deck: 1, 8, 3
Player 2's deck: 4, 10, 9, 7, 5, 6, 2
Player 1 plays: 1
Player 2 plays: 4
Playing a sub-game to determine the winner...
=== Game 5 ===
-- Round 1 (Game 5) --
Player 1's deck: 8
Player 2's deck: 10, 9, 7, 5
Player 1 plays: 8
Player 2 plays: 10
Player 2 wins round 1 of game 5!
The winner of game 5 is player 2!
...anyway, back to game 1.
Player 2 wins round 15 of game 1!
-- Round 16 (Game 1) --
Player 1's deck: 8, 3
Player 2's deck: 10, 9, 7, 5, 6, 2, 4, 1
Player 1 plays: 8
Player 2 plays: 10
Player 2 wins round 16 of game 1!
-- Round 17 (Game 1) --
Player 1's deck: 3
Player 2's deck: 9, 7, 5, 6, 2, 4, 1, 10, 8
Player 1 plays: 3
Player 2 plays: 9
Player 2 wins round 17 of game 1!
The winner of game 1 is player 2!
== Post-game results ==
Player 1's deck:
Player 2's deck: 7, 5, 6, 2, 4, 1, 10, 8, 9, 3
After the game, the winning player's score is calculated from the cards they have in their original deck using the same rules as regular Combat. In the above game, the winning player's score is 291.
Defend your honor as Raft Captain by playing the small crab in a game of Recursive Combat using the same two decks as before. What is the winning player's score?
Answer:
Although it hasn't changed, you can still get your puzzle input.
You can also [Share] this puzzle.

452
2020/day22/README.org Normal file
View File

@@ -0,0 +1,452 @@
** --- Day 22: Crab Combat ---
It only takes a few hours of sailing the ocean on a raft for boredom to
sink in. Fortunately, you brought a small deck of [[/2019/day/22][space
cards]]! You'd like to play a game of /Combat/, and there's even an
opponent available: a small crab that climbed aboard your raft before
you left.
Fortunately, it doesn't take long to teach the crab the rules.
Before the game starts, split the cards so each player has their own
deck (your puzzle input). Then, the game consists of a series of
/rounds/: both players draw their top card, and the player with the
higher-valued card wins the round. The winner keeps both cards, placing
them on the bottom of their own deck so that the winner's card is above
the other card. If this causes a player to have all of the cards, they
win, and the game ends.
For example, consider the following starting decks:
#+BEGIN_EXAMPLE
Player 1:
9
2
6
3
1
Player 2:
5
8
4
7
10
#+END_EXAMPLE
This arrangement means that player 1's deck contains 5 cards, with =9=
on top and =1= on the bottom; player 2's deck also contains 5 cards,
with =5= on top and =10= on the bottom.
The first round begins with both players drawing the top card of their
decks: =9= and =5=. Player 1 has the higher card, so both cards move to
the bottom of player 1's deck such that =9= is above =5=. In total, it
takes 29 rounds before a player has all of the cards:
#+BEGIN_EXAMPLE
-- Round 1 --
Player 1's deck: 9, 2, 6, 3, 1
Player 2's deck: 5, 8, 4, 7, 10
Player 1 plays: 9
Player 2 plays: 5
Player 1 wins the round!
-- Round 2 --
Player 1's deck: 2, 6, 3, 1, 9, 5
Player 2's deck: 8, 4, 7, 10
Player 1 plays: 2
Player 2 plays: 8
Player 2 wins the round!
-- Round 3 --
Player 1's deck: 6, 3, 1, 9, 5
Player 2's deck: 4, 7, 10, 8, 2
Player 1 plays: 6
Player 2 plays: 4
Player 1 wins the round!
-- Round 4 --
Player 1's deck: 3, 1, 9, 5, 6, 4
Player 2's deck: 7, 10, 8, 2
Player 1 plays: 3
Player 2 plays: 7
Player 2 wins the round!
-- Round 5 --
Player 1's deck: 1, 9, 5, 6, 4
Player 2's deck: 10, 8, 2, 7, 3
Player 1 plays: 1
Player 2 plays: 10
Player 2 wins the round!
...several more rounds pass...
-- Round 27 --
Player 1's deck: 5, 4, 1
Player 2's deck: 8, 9, 7, 3, 2, 10, 6
Player 1 plays: 5
Player 2 plays: 8
Player 2 wins the round!
-- Round 28 --
Player 1's deck: 4, 1
Player 2's deck: 9, 7, 3, 2, 10, 6, 8, 5
Player 1 plays: 4
Player 2 plays: 9
Player 2 wins the round!
-- Round 29 --
Player 1's deck: 1
Player 2's deck: 7, 3, 2, 10, 6, 8, 5, 9, 4
Player 1 plays: 1
Player 2 plays: 7
Player 2 wins the round!
== Post-game results ==
Player 1's deck:
Player 2's deck: 3, 2, 10, 6, 8, 5, 9, 4, 7, 1
#+END_EXAMPLE
Once the game ends, you can calculate the winning player's /score/. The
bottom card in their deck is worth the value of the card multiplied by
1, the second-from-the-bottom card is worth the value of the card
multiplied by 2, and so on. With 10 cards, the top card is worth the
value on the card multiplied by 10. In this example, the winning
player's score is:
#+BEGIN_EXAMPLE
3 * 10
+ 2 * 9
+ 10 * 8
+ 6 * 7
+ 8 * 6
+ 5 * 5
+ 9 * 4
+ 4 * 3
+ 7 * 2
+ 1 * 1
= 306
#+END_EXAMPLE
So, once the game ends, the winning player's score is /=306=/.
Play the small crab in a game of Combat using the two decks you just
dealt. /What is the winning player's score?/
Your puzzle answer was =31314=.
** --- Part Two ---
You lost to the small crab! Fortunately, crabs aren't very good at
recursion. To defend your honor as a Raft Captain, you challenge the
small crab to a game of /Recursive Combat/.
Recursive Combat still starts by splitting the cards into two decks (you
offer to play with the same starting decks as before - it's only fair).
Then, the game consists of a series of /rounds/ with a few changes:
- Before either player deals a card, if there was a previous round in
this game that had exactly the same cards in the same order in the
same players' decks, the /game/ instantly ends in a win for player 1.
Previous rounds from other games are not considered. (This prevents
infinite games of Recursive Combat, which everyone agrees is a bad
idea.)
- Otherwise, this round's cards must be in a new configuration; the
players begin the round by each drawing the top card of their deck as
normal.
- If both players have at least as many cards remaining in their deck as
the value of the card they just drew, the winner of the round is
determined by playing a new game of Recursive Combat (see below).
- Otherwise, at least one player must not have enough cards left in
their deck to recurse; the winner of the round is the player with the
higher-value card.
As in regular Combat, the winner of the round (even if they won the
round by winning a sub-game) takes the two cards dealt at the beginning
of the round and places them on the bottom of their own deck (again so
that the winner's card is above the other card). Note that the winner's
card might be /the lower-valued of the two cards/ if they won the round
due to winning a sub-game. If collecting cards by winning the round
causes a player to have all of the cards, they win, and the game ends.
Here is an example of a small game that would loop forever without the
infinite game prevention rule:
#+BEGIN_EXAMPLE
Player 1:
43
19
Player 2:
2
29
14
#+END_EXAMPLE
During a round of Recursive Combat, if both players have at least as
many cards in their own decks as the number on the card they just dealt,
the winner of the round is determined by recursing into a sub-game of
Recursive Combat. (For example, if player 1 draws the =3= card, and
player 2 draws the =7= card, this would occur if player 1 has at least 3
cards left and player 2 has at least 7 cards left, not counting the =3=
and =7= cards that were drawn.)
To play a sub-game of Recursive Combat, each player creates a new deck
by making a /copy/ of the next cards in their deck (the quantity of
cards copied is equal to the number on the card they drew to trigger the
sub-game). During this sub-game, the game that triggered it is on hold
and completely unaffected; no cards are removed from players' decks to
form the sub-game. (For example, if player 1 drew the =3= card, their
deck in the sub-game would be /copies/ of the next three cards in their
deck.)
Here is a complete example of gameplay, where =Game 1= is the primary
game of Recursive Combat:
#+BEGIN_EXAMPLE
=== Game 1 ===
-- Round 1 (Game 1) --
Player 1's deck: 9, 2, 6, 3, 1
Player 2's deck: 5, 8, 4, 7, 10
Player 1 plays: 9
Player 2 plays: 5
Player 1 wins round 1 of game 1!
-- Round 2 (Game 1) --
Player 1's deck: 2, 6, 3, 1, 9, 5
Player 2's deck: 8, 4, 7, 10
Player 1 plays: 2
Player 2 plays: 8
Player 2 wins round 2 of game 1!
-- Round 3 (Game 1) --
Player 1's deck: 6, 3, 1, 9, 5
Player 2's deck: 4, 7, 10, 8, 2
Player 1 plays: 6
Player 2 plays: 4
Player 1 wins round 3 of game 1!
-- Round 4 (Game 1) --
Player 1's deck: 3, 1, 9, 5, 6, 4
Player 2's deck: 7, 10, 8, 2
Player 1 plays: 3
Player 2 plays: 7
Player 2 wins round 4 of game 1!
-- Round 5 (Game 1) --
Player 1's deck: 1, 9, 5, 6, 4
Player 2's deck: 10, 8, 2, 7, 3
Player 1 plays: 1
Player 2 plays: 10
Player 2 wins round 5 of game 1!
-- Round 6 (Game 1) --
Player 1's deck: 9, 5, 6, 4
Player 2's deck: 8, 2, 7, 3, 10, 1
Player 1 plays: 9
Player 2 plays: 8
Player 1 wins round 6 of game 1!
-- Round 7 (Game 1) --
Player 1's deck: 5, 6, 4, 9, 8
Player 2's deck: 2, 7, 3, 10, 1
Player 1 plays: 5
Player 2 plays: 2
Player 1 wins round 7 of game 1!
-- Round 8 (Game 1) --
Player 1's deck: 6, 4, 9, 8, 5, 2
Player 2's deck: 7, 3, 10, 1
Player 1 plays: 6
Player 2 plays: 7
Player 2 wins round 8 of game 1!
-- Round 9 (Game 1) --
Player 1's deck: 4, 9, 8, 5, 2
Player 2's deck: 3, 10, 1, 7, 6
Player 1 plays: 4
Player 2 plays: 3
Playing a sub-game to determine the winner...
=== Game 2 ===
-- Round 1 (Game 2) --
Player 1's deck: 9, 8, 5, 2
Player 2's deck: 10, 1, 7
Player 1 plays: 9
Player 2 plays: 10
Player 2 wins round 1 of game 2!
-- Round 2 (Game 2) --
Player 1's deck: 8, 5, 2
Player 2's deck: 1, 7, 10, 9
Player 1 plays: 8
Player 2 plays: 1
Player 1 wins round 2 of game 2!
-- Round 3 (Game 2) --
Player 1's deck: 5, 2, 8, 1
Player 2's deck: 7, 10, 9
Player 1 plays: 5
Player 2 plays: 7
Player 2 wins round 3 of game 2!
-- Round 4 (Game 2) --
Player 1's deck: 2, 8, 1
Player 2's deck: 10, 9, 7, 5
Player 1 plays: 2
Player 2 plays: 10
Player 2 wins round 4 of game 2!
-- Round 5 (Game 2) --
Player 1's deck: 8, 1
Player 2's deck: 9, 7, 5, 10, 2
Player 1 plays: 8
Player 2 plays: 9
Player 2 wins round 5 of game 2!
-- Round 6 (Game 2) --
Player 1's deck: 1
Player 2's deck: 7, 5, 10, 2, 9, 8
Player 1 plays: 1
Player 2 plays: 7
Player 2 wins round 6 of game 2!
The winner of game 2 is player 2!
...anyway, back to game 1.
Player 2 wins round 9 of game 1!
-- Round 10 (Game 1) --
Player 1's deck: 9, 8, 5, 2
Player 2's deck: 10, 1, 7, 6, 3, 4
Player 1 plays: 9
Player 2 plays: 10
Player 2 wins round 10 of game 1!
-- Round 11 (Game 1) --
Player 1's deck: 8, 5, 2
Player 2's deck: 1, 7, 6, 3, 4, 10, 9
Player 1 plays: 8
Player 2 plays: 1
Player 1 wins round 11 of game 1!
-- Round 12 (Game 1) --
Player 1's deck: 5, 2, 8, 1
Player 2's deck: 7, 6, 3, 4, 10, 9
Player 1 plays: 5
Player 2 plays: 7
Player 2 wins round 12 of game 1!
-- Round 13 (Game 1) --
Player 1's deck: 2, 8, 1
Player 2's deck: 6, 3, 4, 10, 9, 7, 5
Player 1 plays: 2
Player 2 plays: 6
Playing a sub-game to determine the winner...
=== Game 3 ===
-- Round 1 (Game 3) --
Player 1's deck: 8, 1
Player 2's deck: 3, 4, 10, 9, 7, 5
Player 1 plays: 8
Player 2 plays: 3
Player 1 wins round 1 of game 3!
-- Round 2 (Game 3) --
Player 1's deck: 1, 8, 3
Player 2's deck: 4, 10, 9, 7, 5
Player 1 plays: 1
Player 2 plays: 4
Playing a sub-game to determine the winner...
=== Game 4 ===
-- Round 1 (Game 4) --
Player 1's deck: 8
Player 2's deck: 10, 9, 7, 5
Player 1 plays: 8
Player 2 plays: 10
Player 2 wins round 1 of game 4!
The winner of game 4 is player 2!
...anyway, back to game 3.
Player 2 wins round 2 of game 3!
-- Round 3 (Game 3) --
Player 1's deck: 8, 3
Player 2's deck: 10, 9, 7, 5, 4, 1
Player 1 plays: 8
Player 2 plays: 10
Player 2 wins round 3 of game 3!
-- Round 4 (Game 3) --
Player 1's deck: 3
Player 2's deck: 9, 7, 5, 4, 1, 10, 8
Player 1 plays: 3
Player 2 plays: 9
Player 2 wins round 4 of game 3!
The winner of game 3 is player 2!
...anyway, back to game 1.
Player 2 wins round 13 of game 1!
-- Round 14 (Game 1) --
Player 1's deck: 8, 1
Player 2's deck: 3, 4, 10, 9, 7, 5, 6, 2
Player 1 plays: 8
Player 2 plays: 3
Player 1 wins round 14 of game 1!
-- Round 15 (Game 1) --
Player 1's deck: 1, 8, 3
Player 2's deck: 4, 10, 9, 7, 5, 6, 2
Player 1 plays: 1
Player 2 plays: 4
Playing a sub-game to determine the winner...
=== Game 5 ===
-- Round 1 (Game 5) --
Player 1's deck: 8
Player 2's deck: 10, 9, 7, 5
Player 1 plays: 8
Player 2 plays: 10
Player 2 wins round 1 of game 5!
The winner of game 5 is player 2!
...anyway, back to game 1.
Player 2 wins round 15 of game 1!
-- Round 16 (Game 1) --
Player 1's deck: 8, 3
Player 2's deck: 10, 9, 7, 5, 6, 2, 4, 1
Player 1 plays: 8
Player 2 plays: 10
Player 2 wins round 16 of game 1!
-- Round 17 (Game 1) --
Player 1's deck: 3
Player 2's deck: 9, 7, 5, 6, 2, 4, 1, 10, 8
Player 1 plays: 3
Player 2 plays: 9
Player 2 wins round 17 of game 1!
The winner of game 1 is player 2!
== Post-game results ==
Player 1's deck:
Player 2's deck: 7, 5, 6, 2, 4, 1, 10, 8, 9, 3
#+END_EXAMPLE
After the game, the winning player's score is calculated from the cards
they have in their original deck using the same rules as regular Combat.
In the above game, the winning player's score is /=291=/.
Defend your honor as Raft Captain by playing the small crab in a game of
Recursive Combat using the same two decks as before. /What is the
winning player's score?/
Your puzzle answer was =32760=.
Both parts of this puzzle are complete! They provide two gold stars: **

315
2020/day22/aoc-c.c Normal file
View File

@@ -0,0 +1,315 @@
/* aoc-c.c: Advent2020, day 22, parts 1 & 2
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "debug.h"
#include "hashtable.h"
#include "list.h"
#include "pool.h"
typedef struct card {
u8 card; /* card value */
struct list_head list; /* list of cards */
} card_t;
typedef struct player {
int ncards; /* player cards # */
struct list_head head; /* head of cards list */
} player_t;
/* zobrist hash used to find duplicate positions
*/
typedef struct hash {
u32 zobrist;
struct list_head players[2];
struct hlist_node hlist;
} hash_t;
#define HBITS 10 /* 10 bits: hash size is 1024 */
#define CARDS 50
pool_t *pool_cards;
pool_t *pool_hash;
static u32 zobrist_table[2][CARDS][CARDS];
static void zobrist_init()
{
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 50; ++j)
for (int k = 0; k < 50; ++k)
zobrist_table[i][j][k] = rand();
}
static u32 zobrist(player_t *players)
{
u32 zobrist = 0;
card_t *card;
for (int p = 0; p < 2; ++p) {
int pos = 0;
list_for_each_entry(card, &players[p].head, list) {
zobrist ^= zobrist_table[p][pos][card->card - 1];
pos++;
}
}
return zobrist;
}
static __always_inline u32 hash(u32 h)
{
return hash_32(h, HBITS);
}
static int equal_decks(hash_t *hasht, player_t *new)
{
for (int i = 0; i < 2; ++i) {
card_t *c1 = list_first_entry_or_null(&hasht->players[i], card_t, list);
card_t *c2 = list_first_entry_or_null(&new[i].head, card_t, list);
if (!c1 || !c2) /* one list (only) is empty */
return 0;
while (!list_entry_is_head(c1, &hasht->players[i], list) &&
!list_entry_is_head(c2, &new[i].head, list) &&
c1->card == c2->card) {
if (c1->card != c2->card)
return 0;
c1 = list_next_entry(c1, list);
c2 = list_next_entry(c2, list);
}
if (!list_entry_is_head(c1, &hasht->players[i], list) ||
!list_entry_is_head(c2, &new[i].head, list))
return 0;
}
return 1;
}
static hash_t *create_hash(player_t *players, u32 h)
{
struct card *card;
hash_t *hash = pool_get(pool_hash);
INIT_HLIST_NODE(&hash->hlist);
hash->zobrist = h;
for (int i = 0; i < 2; ++i) {
INIT_LIST_HEAD(&hash->players[i]);
list_for_each_entry(card, &players[i].head, list) {
struct card *new = pool_get(pool_cards);
new->card = card->card;
list_add_tail(&new->list, &hash->players[i]);
}
}
return hash;
}
static player_t *create_subgame(player_t *from, player_t *to)
{
struct card *card;
for (int i = 0; i < 2; ++i) {
int n = 0, ncards;
to[i].ncards = from[i].ncards - 1;
INIT_LIST_HEAD(&to[i].head);
list_for_each_entry(card, &from[i].head, list) {
if (!n) {
to[i].ncards = ncards = card->card;
} else {
struct card *new = pool_get(pool_cards);
new->card = card->card;
list_add_tail(&new->list, &to[i].head);
if (!--ncards)
break;
}
n++;
}
}
return to;
}
/**
* find_deck - find deck in an hashtable bucket
*/
static hash_t *find_deck(struct hlist_head *hasht, player_t *players)
{
hash_t *cur;
u32 z = zobrist(players);
u32 h = hash(z);
hlist_for_each_entry(cur, hasht + h, hlist) {
if (cur->zobrist == z && equal_decks(cur, players))
return cur;
}
cur = create_hash(players, z);
hlist_add_head(&cur->hlist, &hasht[h]);
return NULL;
}
static player_t *parse(player_t *players)
{
size_t alloc;
ssize_t len;
char *buf = NULL;
int player = 0;
struct card *card;
INIT_LIST_HEAD(&players[0].head);
INIT_LIST_HEAD(&players[1].head);
players[0].ncards = players[1].ncards = 0;
while ((len = getline(&buf, &alloc, stdin)) > 0) {
buf[--len] = 0;
if (len == 0) {
player++;
continue;
}
if (isdigit(*buf)) { /* card */
card = pool_get(pool_cards);
card->card = atoi(buf);
players[player].ncards++;
list_add_tail(&card->list, &players[player].head);
}
}
free(buf);
return players;
}
static int usage(char *prg)
{
fprintf(stderr, "Usage: %s [-d debug_level] [-p part]\n", prg);
return 1;
}
static void winmove(player_t *winner, player_t *loser)
{
card_t *win, *lose;
win = list_first_entry(&winner->head, struct card, list);
lose = list_first_entry(&loser->head, struct card, list);
list_move_tail(&win->list, &winner->head);
list_move_tail(&lose->list, &winner->head);
loser->ncards--;
winner->ncards++;
}
static long calc_result(player_t *players)
{
/* we don't need to check for winner, as one list is empty */
card_t *card;
long res = 0, mult = 1;
list_for_each_entry_reverse(card, &players[0].head, list)
res += card->card * mult++;
list_for_each_entry_reverse(card, &players[1].head, list)
res += card->card * mult++;
return res;
}
static long part1(player_t *players)
{
int round = 0, winner = 0;
while (players[0].ncards > 0 && players[1].ncards > 0) {
int val[2];
/* we can use list_first_entry() macro, as both lists are not empty */
val[0] = list_first_entry(&players[0].head, struct card, list)->card;
val[1] = list_first_entry(&players[1].head, struct card, list)->card;
winner = val[1] > val[0];
winmove(players + winner, players + 1 - winner);
round++;
}
return calc_result(players);
}
static long part2(player_t *players)
{
int round = 1, winner = 0, game;
long res = 0;
static int maxgame = 0;
DEFINE_HASHTABLE(hasht_deck, HBITS); /* htable for dup decks */
game = ++maxgame;
while (players[0].ncards > 0 && players[1].ncards > 0) {
int val[2];
winner = 0;
if (find_deck(hasht_deck, players)) /* duplicate */
goto end;
/* we can use list_first_entry() macro, as both lists are not empty */
val[0] = list_first_entry(&players[0].head, struct card, list)->card;
val[1] = list_first_entry(&players[1].head, struct card, list)->card;
if (players[0].ncards > val[0] && players[1].ncards > val[1]) {
player_t sub[2];
winner = part2(create_subgame(players, sub));
} else {
winner = val[1] > val[0];
}
winmove(players + winner, players + 1 - winner);
round++;
}
end:
if (game == 1)
res = calc_result(players);
/* cleanup decks */
card_t *card, *tmp1;
for (int i = 0; i < 2; ++i) {
list_for_each_entry_safe(card, tmp1, &players[i].head, list) {
list_del(&card->list);
pool_add(pool_cards, card);
}
}
/* cleanup hashtable */
ulong bkt;
struct hlist_node *tmp2;
hash_t *obj;
hash_for_each_safe(hasht_deck, bkt, tmp2, obj, hlist) {
/* cleanup hash decks */
for (int i = 0; i < 2; ++i) {
list_for_each_entry_safe(card, tmp1, &obj->players[i], list) {
list_del(&card->list);
pool_add(pool_cards, card);
}
}
hlist_del(&obj->hlist);
pool_add(pool_hash, obj);
}
return game == 1? res: winner;
}
int main(int ac, char **av)
{
int opt, part = 1;
while ((opt = getopt(ac, av, "d:p:")) != -1) {
switch (opt) {
case 'd':
debug_level_set(atoi(optarg));
break;
case 'p': /* 1 or 2 */
part = atoi(optarg);
if (part < 1 || part > 2)
default:
return usage(*av);
}
}
pool_cards = pool_create("cards", 4096, sizeof(struct card));
pool_hash = pool_create("hash", 128, sizeof(struct hash));
zobrist_init();
player_t players[2];
parse(players);
long res = part == 1 ? part1(players): part2(players);
printf("%s : res=%ld\n", *av, res);
pool_destroy(pool_hash);
pool_destroy(pool_cards);
exit(0);
}

1
2020/day23/INPUT.txt Normal file
View File

@@ -0,0 +1 @@
974618352

View File

@@ -1,30 +1,108 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := INPUT.txt
SHELL := /bin/bash
CFLAGS := -w -g
#CFLAGS := -w -g -pg
#CFLAGS := -w -O3
CC := gcc
BEAR := bear
CCLSFILE:= compile_commands.json
LIB := aoc_$(shell uname -m)
INCDIR := ../include
LIBDIR := ../lib
LDFLAGS := -L$(LIBDIR)
#LDLIB := -l$(LIB) -lm
LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
# CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations
CFLAGS += -Wno-unused-result
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
--sigill-diagnostics=yes --quiet --show-error-list=yes
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH)
.PHONY: clean all compile deploy ex1 ex2
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 ccls
all: ex1 ex2
all: README.org ccls ex1 ex2
output:
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
memcheck: memcheck1 memcheck2
compile: ex1-c ex2-c
memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
ex1:
@$(TIME) ex1.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
memcheck2: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
ex2:
@$(TIME) ex2.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1
compile: aoc-c
cpp: aoc-c.i
assembly: aoc-c.s
ex1: aoc-c
@$(TIME) ex1.bash -p 1 < $(INPUT)
@$(TIME) aoc-c -p 1 < $(INPUT)
ex2: aoc-c
@$(TIME) ex2.bash -p 2 < $(INPUT)
@$(TIME) aoc-c -p 2 < $(INPUT)
ccls: $(CCLSFILE)
clean:
@rm -f ex1-c ex2-c core
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
deploy:
@$(MAKE) -C .. deploy
.c:
@echo compiling $<
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
# generate pre-processed file (.i) and assembler (.s)
%.i: %.c
@echo generating $@
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
%.s: %.c
@echo generating $@
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
# generate README.org from README.html (must cleanup !)
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@
# generate compile_commands.json
$(CCLSFILE): aoc-c.c Makefile
$(BEAR) -- make clean compile
bear: clean
@$(BEAR) -- make compile
@touch .ccls-root

View File

@@ -1,80 +0,0 @@
--- Day 23: Crab Cups ---
The small crab challenges you to a game! The crab is going to mix up some cups, and you have to predict where they'll end up.
The cups will be arranged in a circle and labeled clockwise (your puzzle input). For example, if your labeling were 32415, there would be five cups in the circle; going clockwise around the circle from the first cup, the cups would be labeled 3, 2, 4, 1, 5, and then back to 3 again.
Before the crab starts, it will designate the first cup in your list as the current cup. The crab is then going to do 100 moves.
Each move, the crab does the following actions:
The crab picks up the three cups that are immediately clockwise of the current cup. They are removed from the circle; cup spacing is adjusted as necessary to maintain the circle.
The crab selects a destination cup: the cup with a label equal to the current cup's label minus one. If this would select one of the cups that was just picked up, the crab will keep subtracting one until it finds a cup that wasn't just picked up. If at any point in this process the value goes below the lowest value on any cup's label, it wraps around to the highest value on any cup's label instead.
The crab places the cups it just picked up so that they are immediately clockwise of the destination cup. They keep the same order as when they were picked up.
The crab selects a new current cup: the cup which is immediately clockwise of the current cup.
For example, suppose your cup labeling were 389125467. If the crab were to do merely 10 moves, the following changes would occur:
-- move 1 --
cups: (3) 8 9 1 2 5 4 6 7
pick up: 8, 9, 1
destination: 2
-- move 2 --
cups: 3 (2) 8 9 1 5 4 6 7
pick up: 8, 9, 1
destination: 7
-- move 3 --
cups: 3 2 (5) 4 6 7 8 9 1
pick up: 4, 6, 7
destination: 3
-- move 4 --
cups: 7 2 5 (8) 9 1 3 4 6
pick up: 9, 1, 3
destination: 7
-- move 5 --
cups: 3 2 5 8 (4) 6 7 9 1
pick up: 6, 7, 9
destination: 3
-- move 6 --
cups: 9 2 5 8 4 (1) 3 6 7
pick up: 3, 6, 7
destination: 9
-- move 7 --
cups: 7 2 5 8 4 1 (9) 3 6
pick up: 3, 6, 7
destination: 8
-- move 8 --
cups: 8 3 6 7 4 1 9 (2) 5
pick up: 5, 8, 3
destination: 1
-- move 9 --
cups: 7 4 1 5 8 3 9 2 (6)
pick up: 7, 4, 1
destination: 5
-- move 10 --
cups: (5) 7 4 1 8 3 9 2 6
pick up: 7, 4, 1
destination: 3
-- final --
cups: 5 (8) 3 7 4 1 9 2 6
In the above example, the cups' values are the labels as they appear moving clockwise around the circle; the current cup is marked with ( ).
After the crab is done, what order will the cups be in? Starting after the cup labeled 1, collect the other cups' labels clockwise into a single string with no extra characters; each number except 1 should appear exactly once. In the above example, after 10 moves, the cups clockwise from 1 are labeled 9, 2, 6, 5, and so on, producing 92658374. If the crab were to complete all 100 moves, the order after cup 1 would be 67384529.
Using your labeling, simulate 100 moves. What are the labels on the cups after cup 1?
Your puzzle input is 974618352.
Answer:
You can also [Share] this puzzle.

137
2020/day23/README.org Normal file
View File

@@ -0,0 +1,137 @@
** --- Day 23: Crab Cups ---
The small crab challenges /you/ to a game! The crab is going to mix up
some cups, and you have to predict where they'll end up.
The cups will be arranged in a circle and labeled /clockwise/ (your
puzzle input). For example, if your labeling were =32415=, there would
be five cups in the circle; going clockwise around the circle from the
first cup, the cups would be labeled =3=, =2=, =4=, =1=, =5=, and then
back to =3= again.
Before the crab starts, it will designate the first cup in your list as
the /current cup/. The crab is then going to do /100 moves/.
Each /move/, the crab does the following actions:
- The crab picks up the /three cups/ that are immediately /clockwise/ of
the /current cup/. They are removed from the circle; cup spacing is
adjusted as necessary to maintain the circle.
- The crab selects a /destination cup/: the cup with a /label/ equal to
the /current cup's/ label minus one. If this would select one of the
cups that was just picked up, the crab will keep subtracting one until
it finds a cup that wasn't just picked up. If at any point in this
process the value goes below the lowest value on any cup's label, it
/wraps around/ to the highest value on any cup's label instead.
- The crab places the cups it just picked up so that they are
/immediately clockwise/ of the destination cup. They keep the same
order as when they were picked up.
- The crab selects a new /current cup/: the cup which is immediately
clockwise of the current cup.
For example, suppose your cup labeling were =389125467=. If the crab
were to do merely 10 moves, the following changes would occur:
#+BEGIN_EXAMPLE
-- move 1 --
cups: (3) 8 9 1 2 5 4 6 7
pick up: 8, 9, 1
destination: 2
-- move 2 --
cups: 3 (2) 8 9 1 5 4 6 7
pick up: 8, 9, 1
destination: 7
-- move 3 --
cups: 3 2 (5) 4 6 7 8 9 1
pick up: 4, 6, 7
destination: 3
-- move 4 --
cups: 7 2 5 (8) 9 1 3 4 6
pick up: 9, 1, 3
destination: 7
-- move 5 --
cups: 3 2 5 8 (4) 6 7 9 1
pick up: 6, 7, 9
destination: 3
-- move 6 --
cups: 9 2 5 8 4 (1) 3 6 7
pick up: 3, 6, 7
destination: 9
-- move 7 --
cups: 7 2 5 8 4 1 (9) 3 6
pick up: 3, 6, 7
destination: 8
-- move 8 --
cups: 8 3 6 7 4 1 9 (2) 5
pick up: 5, 8, 3
destination: 1
-- move 9 --
cups: 7 4 1 5 8 3 9 2 (6)
pick up: 7, 4, 1
destination: 5
-- move 10 --
cups: (5) 7 4 1 8 3 9 2 6
pick up: 7, 4, 1
destination: 3
-- final --
cups: 5 (8) 3 7 4 1 9 2 6
#+END_EXAMPLE
In the above example, the cups' values are the labels as they appear
moving clockwise around the circle; the /current cup/ is marked with
=( )=.
After the crab is done, what order will the cups be in? Starting /after
the cup labeled =1=/, collect the other cups' labels clockwise into a
single string with no extra characters; each number except =1= should
appear exactly once. In the above example, after 10 moves, the cups
clockwise from =1= are labeled =9=, =2=, =6=, =5=, and so on, producing
/=92658374=/. If the crab were to complete all 100 moves, the order
after cup =1= would be /=67384529=/.
Using your labeling, simulate 100 moves. /What are the labels on the
cups after cup =1=?/
Your puzzle answer was =75893264=.
** --- Part Two ---
Due to what you can only assume is a mistranslation (you're not exactly
fluent in Crab), you are quite surprised when the crab starts arranging
/many/ cups in a circle on your raft - /one million/ (=1000000=) in
total.
Your labeling is still correct for the first few cups; after that, the
remaining cups are just numbered in an increasing fashion starting from
the number after the highest number in your list and proceeding one by
one until one million is reached. (For example, if your labeling were
=54321=, the cups would be numbered =5=, =4=, =3=, =2=, =1=, and then
start counting up from =6= until one million is reached.) In this way,
every number from one through one million is used exactly once.
After discovering where you made the mistake in translating Crab
Numbers, you realize the small crab isn't going to do merely 100 moves;
the crab is going to do /ten million/ (=10000000=) moves!
The crab is going to hide your /stars/ - one each - under the /two cups
that will end up immediately clockwise of cup =1=/. You can have them if
you predict what the labels on those cups will be when the crab is
finished.
In the above example (=389125467=), this would be =934001= and then
=159792=; multiplying these together produces /=149245887792=/.
Determine which two cups will end up immediately clockwise of cup =1=.
/What do you get if you multiply their labels together?/
Your puzzle answer was =38162588308=.
Both parts of this puzzle are complete! They provide two gold stars: **

1
2020/day23/TEST.txt Normal file
View File

@@ -0,0 +1 @@
389125467

115
2020/day23/aoc-c.c Normal file
View File

@@ -0,0 +1,115 @@
/* aoc-c.c: Advent2020, day 23, part 1
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include "list.h"
#include "debug.h"
/* Here we will simply use an array for the numbers (as key is the number
* itself). All elements make a next/prev ring.
* Note: we will ignore array[0] to avoid millions of useless "position -1"
* calculations
*/
struct list_head *curcup; /* current cup */
struct list_head *cups; /* the cups cups */
int lastnum; /* last cup number */
#define CUR_CUP (&*curcup)
#define NUM(pcup) ((pcup) - cups)
static __always_inline void step()
{
struct list_head *first, *last, *dest = CUR_CUP;
int num[3] = { 0 };
first = CUR_CUP->next;
last = first->next->next;
num[0] = NUM(first);
num[1] = NUM(first->next);
num[2] = NUM(last);
do {
if (NUM(--dest) <= 0)
dest = &cups[lastnum];
} while (NUM(dest) == num[0] || NUM(dest) == num[1] || NUM(dest) == num[2]);
list_bulk_move(dest, first, last);
curcup = CUR_CUP->next;
}
/**
* parse - initialize cups list.
*/
static void parse(int last)
{
int count = 0, c;
cups = malloc(sizeof(struct list_head) * (last + 1));
if (cups) {
for (c = getchar(); isdigit(c); c = getchar(), ++count) {
struct list_head *next = &cups[c - '0'];
if (!count) /* first cup */
INIT_LIST_HEAD(curcup = next);
else
list_add_tail(&cups[c - '0'], CUR_CUP);
}
for (++count; count <= last; ++count) /* add remaining cups */
list_add_tail(&cups[count], CUR_CUP);
}
}
static long part1()
{
struct list_head *cur;
int res = 0;
list_for_each(cur, &cups[1]) {
res = res * 10 + NUM(cur);
}
return res;
}
static long part2()
{
return NUM((&cups[1])->next) * NUM((&cups[1])->next->next);
}
static int usage(char *prg)
{
fprintf(stderr, "Usage: %s [-d debug_level] [-p part]\n", prg);
return 1;
}
int main(ac, av)
int ac;
char **av;
{
int opt, part = 1;
while ((opt = getopt(ac, av, "d:p:")) != -1) {
switch (opt) {
case 'd':
debug_level_set(atoi(optarg));
break;
case 'p': /* 1 or 2 */
part = atoi(optarg);
if (part < 1 || part > 2)
default:
return usage(*av);
}
}
lastnum = part == 1? 9: 1000000;
int loops = part == 1? 100: 10000000;
parse(lastnum);
for (int i = 0; i < loops; ++i)
step();
printf("%s : res=%ld\n", *av, part == 1? part1(): part2());
free(cups);
exit (0);
}

53
2020/day23/ex1.bash Executable file
View File

@@ -0,0 +1,53 @@
#!/bin/bash
#
# ex1.bash: Advent2020 game, day 23/game 1.
CMD=${0##*/}
shopt -s extglob
set -o noglob
declare -A next # next[i] is cup right to i (ring)
declare -i end runs cup _cup
read -r str
tmp="${str//?()/x}"
tmp=${tmp#x}
IFS=x read -ra array <<< "$tmp"
cup=${array[0]}
end=${#array[@]}
runs=100
_cup=$cup
# initialize the next array with input cups
for _next in "${array[@]:1}"; do
next[$_cup]=$_next
_cup=$_next
done
next[$_cup]=$cup # close the ring
_cup=$cup
declare -i _1st _2nd _3rd dest
# make the moves: a simple sub linked list operation.
for ((i = 1; i <= runs; ++i)); do
_1st="${next[$cup]}"
_2nd="${next[$_1st]}"
_3rd="${next[$_2nd]}"
dest=$cup
while
(( --dest > 0 )) || dest=$end
(( dest == _1st || dest == _2nd || dest == _3rd ))
do :; done
(( tmp=next[$dest], next[$dest]=_1st, next[$cup]=next[$_3rd], next[$_3rd]=tmp ))
(( cup=next[$cup] ))
done
res=""
_cup=1
while
(( _cup = next[$_cup] ))
res+="$_cup"
(( next[$_cup] != 1 ))
do :; done
printf "%s: res=%s\n" "$CMD" "$res"
exit 0

51
2020/day23/ex2.bash Executable file
View File

@@ -0,0 +1,51 @@
#!/bin/bash
#
# ex2.bash: Advent2020 game, day 23/game 2.
CMD=${0##*/}
shopt -s extglob
set -o noglob
declare -A next # next[i] is cup right to i (ring)
declare -i end runs cup _cup
read -r str
tmp="${str//?()/x}"
tmp=${tmp#x}
IFS=x read -ra array <<< "$tmp"
cup=${array[0]}
end=1000000
runs=10000000
_cup=$cup
# initialize the next array with input cups
for _next in "${array[@]:1}"; do
next[$_cup]=$_next
_cup=$_next
done
# initialize the next array (up to end)
for ((_next = 10; _next <= end; ++_next)); do
next[$_cup]=$_next
_cup=$_next
done
next[$_cup]=$cup # close the ring
_cup=$cup
declare -i _1st _2nd _3rd dest
# make the moves: a simple sub linked list operation.
for ((i = 1; i <= runs; ++i)); do
_1st="${next[$cup]}"
_2nd="${next[$_1st]}"
_3rd="${next[$_2nd]}"
dest=$cup
while
(( --dest > 0 )) || dest=$end
(( dest == _1st || dest == _2nd || dest == _3rd ))
do :; done
(( tmp=next[$dest], next[$dest]=_1st, next[$cup]=next[$_3rd], next[$_3rd]=tmp ))
(( cup=next[$cup] ))
done
printf "%s: res=%d\n" "$CMD" $(( next[1] * next[${next[1]}] ))
exit 0

496
2020/day24/INPUT.txt Normal file
View File

@@ -0,0 +1,496 @@
enesenwwwsenewswsewenwwnwwnwnwswse
swneswseesweswneswwwwseewnewswsw
neneenenenenwneseneesenewenenwnenenesw
weeswnenenwneneeesweneswenwneene
nwnwnenwnwwnwnwnwnwwsewnwswnwwnwnwnw
nwwwnwnwnenenwewnwseewnwswnwwnww
senwweneewewswweswsenwnesenwwnwswnw
nwnwnenenenenwnesenenenwneswnwnweeswwsene
wswnwswneneswswswswswnesweseswwswnwswsw
neeeeeweseesesweeneweneesw
wwenewwwwwwnwnwwwwwwwwse
swneswswseseswswswsw
seswswsewseesesese
nenwneneneewseneneneenenenenenesenenew
swswwwnewwsewwwswwwswswwnesew
wwswwwwwwwwwwwswewwwwe
senewnwwnwswnwswnwewnenwenwewsenwnwse
wnwnwenwwnwnwwnewnwswsenwnwnwnwwne
nenwneswnwnwswnwnwesewwnwnwnwsenwnene
wsewneeseneseseseswnesesenwswenwswnwe
nesewnwwwswnweneenwswwesenesw
swsesenwswsesesewswswneseseeswnesesesewsw
neneswswwswswwswseswswewwswswswsew
eeeneeneneneneesweenewneneeee
seeenesesweseeeewwneeseeseee
nweeweeneeswenewe
seswwnwseeswseseswswe
wneneeswnesenwseneeneneneenwneneneenwne
newnenesenenenenenewneswnenenenenenenenese
wswswswswwswwwwweswnwswsewswswsw
eeeeeenesenwewseeneeneneweee
sewnwwnwnwwwnwnwnwnwswwwewnwww
sewesenwswwneswnwnwnwsweseseeswwse
nwwewnwweswswwwwewnwnwnwwnwwswe
swwwswnwswswenwneswswseswsweswseswsene
eneeenwswseseeeeeesenwenwwsweee
swseenwseesewnwnewnwneeeswswesenee
swwsesenwnwnwwwwnewenwnwewwwwsw
seeeeeeeeswnweeenwnwnewswesw
seenwswnenenwnewnwnwnwnwe
esenenweeswseeeseeweseseeeee
swswswswseswswswswnenw
neneseswsenenewneenenewwnenenenenenenene
wnewwenweswswwwswseswswwwnesene
seneneneweenwnwseeeweeseseeeene
neenwsweneneeeswwnwwneeenewnene
seseneswwneswseswwsesenwseseseswsesese
wweeeeeeswsenweeneeee
newnenenwneseneneeneeneneseneneeneene
wewnwnwwwwwwsenewnwwnwnwwwse
weseeseseswnwsewseneneeeesewwe
swswswswswswswswswswswwneswswwwswswe
swsenwneeseswseswswswswseseneseswswswsw
seswnenwwswswswneswsewwnewseswswwwsw
swswswneswswseswnwswseswseswswseneseswsw
wwwwnewesesewswwwnewwwne
enweeneseneeeeswnwesw
eesesenwseseeseseesesese
nwswseenesewwseesenee
wwswswswwswswwneesw
newwseswwnewswwwwswnwewnewwsww
nesenenenewenesenenenenwnwswnenwnwnenene
swnwswswneswswneswswswswseswswseswsweswwsw
swswswswswswneseswswseswnwswswswsweswsw
nwwwwswwwsewwwwewnwewswwww
neneeneeewneeneeeneenene
swnwnwnwneswwwseeenewnewswsenwwnww
nenenenwnenwneswnenwnenenenenene
nwweenwesweeeeeeseeeeewnenese
weeeneeseeeseeeseeeewe
wwwwwnwesewwwswewwwwenww
seneseseseseseneswsesesesewsewsesesese
eenwneneseeeeeesweenweeeenee
neseneseseseseseeseswseeeeseewee
nwswnweeeeseeseneeneneswswneneee
sesesewseseswesesesewseeneeseesese
seswnewwswewnwswneneswwnwnwnew
wneseneeeewsesewneneneenenwswnwne
wnwnenwnwnwnwsenenwnesenwnwnwnwnwnwnwnwwnw
wwnewnwwswweswewswseeewenwsw
eneeneseeneneneewneweeeneeeneew
nwwnwnwwnwnwenenwnwnwenwnenwnenwnenw
nwsenwnwenwnwswsenwsenwnwnwnwnwnwswenwnw
eeseseeeeeseseeeneesenwseeswe
ewenewneeneswewneseneswsewswwese
nwwwwswwswswwse
newnwnwnwwwwnwnwswsewewnwwwwnwnw
seswswnwwseseseswseesw
sewseweswwwwwswwwwwswwwwnwne
senenenenwnwnwnwnwnwnwnwnw
swswswwwwswswwnwwwswwesewwww
seeneseseneseesesesewsesesesesenwseswsw
wnenwnwsewwwnwnwwwwwsewwnwnew
swswswswswneswseswswswseseseswswnwsesese
neneneneneeneenenesenenwnenewnesenenee
wseseswseneeseswneseswseswswwwseswne
nenenenenenenwnenenenesenesewswneneenwe
seeseseseeseneesesenweeewseewsese
neeewneneneneseneenenenenenenesenwne
nenewnweneweseenwnwsesewnwswnwnwnw
sewnwnesenenwneswwnenwnwnwsenweneswe
senwnwnenwswnwnwnwnenwenenwnwnenenesenw
wnwwwwwsewnwwwewwwweseww
swnwnewnwnwsenwsenwnwnwnenwneswwwnwenenw
wnwseswnewwweewneneeseseesenww
wseseseseeseseseseseesesesenwswswswnw
neneneneneneneseneswnenenwneneneneneenewne
neswswswswswswsesesesesewsewneswsenesw
nenwneswnwweseeenwnesweneeneeese
seesesesesesweeseseseesweenweseenwse
seeswseseseswseseseswswswnenwswswseswsw
swneswswseswswswwswswnwswseswswswswseneswsw
nwseseesesewneeseseeeeeseewenesese
nenenenewneneswneswneneswswneneneneene
nwswnwnenwnwnwnwswnewnwnwnwenwnwnwnww
nwwnwnwnwnenwnwnenwsenenwnenwnwnwnwnw
senenenwnwewwwneeneewnenwsew
nenenenwneneneneswneneneeswenenenwnenw
wwneweewseswseseneneeseeeseese
neneneeswnenenewneneneneneneswenenene
eeeeewseeeneneneeeeeweenwsw
nwenenwnwswwsenwnwswneswnwnwnenwenenwne
eswwswneswswswswswnwewswswwswswwswswsw
enwwwwnwnwnwwewwnwnwnwnwseeww
seseseneeseseseseneseseewwseesesesese
nenenweneswnewenw
nenenenwneneneseswnwnwsenwenwewnenenwnw
nenenenwnwnwenwnwswnwnwwnwnwnwnwnwsenw
neeneneneeneneneneneneenesw
neeeneeeswnwnenwsewswswnenwsenwnee
wenwwwswenewwwsewswswnewswwew
seseeneeseseseneseseesesewsesewsesesese
swewnwwsenwnwwseewwnwwwnewwnw
wesesweeneeenewnwsweenenwneeesw
nwnwswnwnwnwnwnwenenwnwswnwnwnwnwnwenenw
nwsenwwswnenwneeesenewenwwwnw
ewseeeeenweseseseeeewseeseese
wnwnwsewwnwneswwnwwnwnwwnwwwnwnenw
swswsenwwswwenenenewseswswewswnesw
wnwswsesesesweeswseswswswswswseswswsw
eneeswnwwnwnwsweenwenwnwnewnwswswnwne
seseswswseseswseswsenesesewsenenwsesww
eeeneswnwnwnwneneseneseneenewnenwsee
enweseesweswneeweseenwneeew
newneneneneeneneswsenenewnenenene
eneswwneneenwnenesenewwnenenesenene
swswswswswsesenwswswswswsw
eeeneewewneeeee
swswsesenwswsenwswseswsweswseswnwseswswenw
sweneseswswesenenenwnwwnwnwneswe
wnwnwnwwwwsweneswnwnwnwewwnwww
seseswswswsesenwwseeseswswswswweese
seseeseseseseesesesenwnenwsenwsesesesew
wnwnwswnwwwwwwsewwwnenwwwwe
wnwwsenwneewswnwsenwnenwwnwesenwnewsw
swnenwnenenwnwwnwnesenenwnwnenwnenenenwnw
wwewwwwnwswwwnewwwswwwwnw
neneeeweesesenweneneswneeeewne
swswswseneneswwseseseneseseseswswswswswsw
nwnwnenwswwnwwwwnwwwwsew
swswswswseswsesesenwswsewseseswswesesw
nenwswnwnenwswnenwnwnenwnwnwsenwnwneenw
wseseswswswneseswseseswswsenwswswne
swnesesewseneseswswnwswswswswnwswseswswswsw
wnwnwnwnenwsenwneenwswnwnwnwenwsenwswnw
enenenewnenenwnenenenwnenenenenw
enenwnenwsewwwsweenenewnwnenwene
swwswsewnewswneswswwwswswwswwswwsw
neneswseeneeswewenwwswswweesese
swnwseswsenwsenweewenwsweeneeese
nwenwnwnwnwswnwnenwnwnwnwnwnwnwnwwsenw
seseseseeseseseeeeewesenesesewe
eswsenwnwneswwswwswnwwwwseeswsenwe
enenewnesenewnwnwnwswnwnwnenesenenwnenw
wneneneeneeeeweenewnenesweesene
enewnweneneeneeeswneneeeeenene
nwswsesenwnenwnwwnwnweswswnwnwneeew
eseeewneeneeeeeneeeeeseewene
sewnewwwwwwwsewwwwwwwnwwe
newnenesenweneneneweneenene
swseswswswswswswswswewswswswswswnwneswswsw
eseneneseseeseseeeeseeeeeswsewse
enwneenenewneeneneneswnenenenenenene
nenenwnenenwseneneenwnwnenwnweswnwnww
nwnwenwnwsenwnwnwnwnwwwse
nweswswwswenenweeeseseseeeeeee
nwnenwswnwwnwenwsewwnwneswnwnwnwnwsee
seeseeseseneewswweseseswswwwswswsw
nwnwnesenwenwnwnwnwnwnwwnwneswnwswwnwnw
seseseseswseswesesesesesesenesewswsenw
swswwswseseseseswsewseseneseseswneswswsw
nwnwnwnenwswnwnwnenesenenwnwnenwnwnwnenw
swnewwnwneenwnwenwsenwnwnwsewnwenw
eeenwwweeeewseneeswesenese
swenewneseneswneenwnesenenenwnenewene
nwnenwwwwwnewwwwwwwsesenwwww
seseswneseseseeenewwsese
enwneeeswenewneeeeneeseneeee
seseeseneseeeeeeswwnenwseswsesese
nwnesesenenenwnwnenwnwnenenwnewnwnwnenw
wwswnwnwewewswneseeswswswseneswsw
nwsenwneneneneneneeseewnenenenenesenwse
nesewswswneneswneswseswswnewswswsenese
swswwsesweswnwseseswseseswseseseseswsw
senenwswenwnwnwwnenwsenwnwnwnenwewnwwnw
nenenenwnwneswswneswnenenenenenenenenene
enweneswneneneeswneneeewneenenee
nwnwswnwwnwseesenenwwswwnewwsenwnwnw
neswseseswneeswneneswswneswenwwswwwe
swwneeneeneswwewnwneseeenwnenwnewne
wswwwseenwnewneswwnwwwnwseew
seewwnenenwneswwnenwneseneenenenene
swwsenwswsweseesenwwwswswwnewnesenew
neswswswnenesenenenw
nwwsewwwnwwnewnwwnenwwseswnenwswwnw
nenwneseeewneeeeseneesweneenwsee
seswseswseswnwnwswswseswsweseswswswswse
swwswneswswswswswswneswsweswswswswwswsesw
senesewseseseeewseweseseseeseesese
swnesenenenwneneneswnwnwne
wsesewwenenwsesewneneseseseswsesese
newseswwwswwwnwswweswwewswwww
nweneeneneeswnwwenenesweneseneene
esweneenweeeeseweeeneeewew
neswnweswswnenweseswswnesewswsenwsese
nwnwnwnwnwwenwwwnwnw
swswseseswswswswswswswswswsweswneswswnwsw
neneswnenwnenenenenenwnenwne
seeseseneseseswseseseseswsesesenwsesesese
nwnenwnwseenwnewewswsewnwwswswnew
wseesesweseseeneeenwseeeeeenee
swwwsewesewnewnweenwswswwwwwsw
eeneseseeseseseseswseewse
eeeneseeeeeeswseeenewseeee
swseswswsewenenwnwwnweswne
ewwnenwswnwnenwnwnwnenenwnwenenenwnw
neswswswswswnwswwswsewsw
seseeseswswewsewsenwseseneewsewneee
seswseswenwwnwswwswewnweseswnwnw
sesesenesesesewswseseswneseswsesesesesese
neneneneneseenenewneeneneswwnesenenew
nweeewneenwswneneswnewne
nwwewwswwwseswwswwne
nwnenwnwnwnwsewnwnwwnwewnwnwnwnwwnwnw
seneneneneenenwnewneneneswneenenwswnenese
swseswnwseswswseseseswnwnewseswswswswswsesw
nwnenenwnwnenwnenwnwseswneneenwnesenwne
nenenesweeenenenenewne
eewneeeweeeeseeeneneewene
swsweswswswswswswswswneswnwseswnwwseswsw
wwswwwnwnwewseweswnwnesenwwwew
seeneenenenesenenesweweenenenenwnene
newewseewnwwnwwwsewsenewswswe
sweeseweseseeeseeenesesesenwese
neswewwwseswwwswsww
wewnwnwnwnwnwwwnwwswesenwnwenwsee
seswsewsewseswswenenewseenwnwnwswse
swswseswseswseswswswnwswswnwsenesesw
nwnwsenenenwsewnenenenwsenwnesesenwnwnwnw
swnenwwwwwseswwneewswswwwnesene
seseseswswsesenesesesesesw
eneenwneenenenewswneswnesweee
nwnwneswnenenwsenenenenenenenwnenewnene
seswnewswswswnwswsenwwsweswswnwswesee
swswswswswwswswswewswneswswseswswswneswnw
swswswswswseseswsenwseneesesesesewwsese
seneeesweeeeeeweeeee
senweseeeenweeeenwenwsweeswese
swswneswseewswswnwswswwsenweswswswesw
ewneeeeeneweeeeeeweseesesese
nwseswseneeseeseesweeweseesesee
neeneswnenenewnwnenwnenenenwswneenewne
eswwswswnwnwseeenwweswnwnenwswswse
wwswnewwswnwwwswwneneeswwseswne
neneneneseneneswneneeneeewne
wwwnwwnewsenweseewwwewwnew
neswwsweewneswsenewsesewwsenwsesese
seswwsweenwweseneseneseneeenwwe
senwsesweseseswnwseeseswsenesesenenewsw
swseswswswswnenwswswwswswswswswwswenesw
nesenwnwnwnenwnwnwnenwnewnwnwnwnwnesenw
seswswswwswswwswswswswneswswenewnwswsw
nwnwwnwnwnwnenwenwwwenwswwswnwnwnwnww
neseenesenwnwsenwwneesewnewwswenwnenw
wnenwnwnenenenwnenesenwnenenwnenwnenwe
nwnwnwnwnenwnwnesenwnenwnwnenewnwnenwswe
enwswseeseseseewseeswnweeseeeee
eeeeeesenwseseeee
swsesweweswwswswswswnwnwwswswsw
neseneneeeenwweneenenenene
swwsenwnenenwnesesewneeswwswseswnwswswse
seeenweesesweseeeweeeseeswnw
sewsesesesesenesweesenwswsesw
nwnenwwnwnwswnwnenwnwwnwnenwnwnwnwsenwe
neenenwneeneswnenwneswneeneeneeneene
seseeeweseseeeeseese
nenwnenwnenenenenwswneneneenwnenenenw
wwwwswswwsweswnewwnewsewwwne
wwnenwnwsewnwnenwsenwnwnwnwnwwwnwnwsw
seseseswswsesenwwsenesesesesesesene
nwseswsesenwwswnenesenenwsw
swswsweswswswseweswnwswswneseswswswnwsw
enweesweneeneeneneeeeeneeewe
seswseseseseswsesewseseseswswsenwesese
seswsesesesenwnewsesesesesesesesesesenwsese
swswswnwswswswseswnweswswswsw
newnwwswwneeneneseeneswnenenenwnenwnw
swwswnwwswswnwswwewnwsweswswswseesw
sweswnwswenwwswswwwwsweswswswswswsw
nenenwnwsenesenenwnwnwnenenenenenwnwswnwne
wnwseswwewwnewwswnwnwwswewsesww
seseneseseswsesewswsesesesene
wwnwwwewwwewwwnwwwwwnwsww
wneeneesenwseeeeeweeesweswene
senesenwsweseeseesewseseenesewwsee
nwnwnwsenwnwswesenwenwnwnwnwnwnwnwswnwnwnw
eeweeeeeesweneeeseeneeneee
wwsenweswsewswneswswnweneswneenww
eeneneneeneeeeenewswneneeseenee
swwseseneswseseweseseswneesenesesese
eeeeneneneneneweeee
swsenesewseswsenwnenwsesweswsenwswswswnw
nwnwswsweswnenwnwnwnenenwnwnwnwnwsenenw
swsesweseseseweseeseswnwsesesenwseswsesw
eneeseneswswsweeweewnewne
neneeseenenenewenenenewnenenwswesw
sweeswwewsweewnwenwnwnesesenwesw
swswswswswswneswswswsw
eseseeneeeseewenwweeeeswsesese
swswwnwswnwwwswewweswwwwswswwe
wwewswwnwwwwwswwwwwweww
enenwnwwnwwwwsesese
wwwwnwswwwswswwwewwwew
wnenwneeswneneneseneewsw
sweswnenenwewsesenwsenw
wsewwenwnwnwwwnwwwnwnwwwnwww
eseeeeeeseeeseneeneeewwwee
nwwnwewsewnenenwwnwswwnwwwswnwse
wwswwwwweswwswwswswewwwneww
swnewnwnwnewseswewnesweswswesesw
nwnwnwswnwnenwnwnwnwnwnwewnwenwnwnwnw
swseweswnesewneesenwnesenwwseesew
wenweseesenwseswsesweswnenwneenwse
seeneneneeeenweneene
nwnwnenwneenwneswnenwnwnwnwswnwnwnwnwnw
esesesweswneneneswnwnwnenwneneseww
nwnwwenwnwnenwnenweswwenwnwnwnwnenesw
senewsewswswseseneswseseseseswsesesese
nwnwnwsesenenwneneswnwnwewnesewnenese
neesesewseseneseseseeseeseseesewsese
swnewneswwswswwwnewsesesenwswswnwsew
neseseswswwseseeswsesesesesesewseswse
swsweswseswswneseeswswswnwnwswwwswneswnw
seeeeseswsesesesesenwsesesee
nenenwnwnwnwnwswsenwnwnwne
eswsweswswsweswseswswwnewswwswswswsw
seneswneswswseswswseswswseswswsenenwswswsw
eswswseswnwnwsesewseseswseneeswswnesww
seseseesesenwsesesenesewseseseseseesesew
swswswswnweswswnewswswswswswwneswwswsw
neeswnenenesweeneneeneneeneenenewne
neswwswnwnwnwwseseneneewwsesewsew
eseseswwwseenesenesesenenwwnwseseswee
swswswseseseseswwswneeswswweswnwsesene
neneneneenesenwwweneswnwswwnwswnenwne
neeeneeeseeneswnenenenenwewnee
nwwnwewsenwnwnwenwesenwneewwnwsw
seswewnwwnwwswnwsenwnwswseenesweene
seswseneseswswseseseweesewwswwnesw
neseeneneneswneeneenenenewneneneenw
nwnwsewnwsenesenwwnewenw
senwneneswewnenenesenenenwewwnene
nenwenwwswwwwwwwwwewwwwse
sesenwsesesenwseesesenwnwswswsenewese
eeenenenwnwsweeeeeeeeeeneneswe
swwwseswwseswswwswwneswswwwnwsww
nwnwwnwwnwnesewnenwnwwwwnenwwwesese
seswswnwswseseseswseswneseseseewswsese
seswswneewneneeswswnwswwwswswnweswse
nwnwnwnwwnwsenwnewnwnwnwneenenenwnwnesw
nenwnwnwnwwnwesenwnwnwnwnwsewwnw
neswwnesenwneswwenwnwsenwnweeswsese
wwnwnwsewnenwwswwnwwwnwwnwnwwew
sewswseseneswseseswswneswseneseseswsesw
swwwnwwwswwswwwwwsewwwnwesww
seneswswwswwnwenwnwwswseeswwwwwwsw
neneswneneswnenesenenenewnenwneneneenw
nwswseseneseseswswswnewswseseseweswnesenw
nenenenenwneseneeneneneneneeswnenenwnee
swseneeeeeeeweneswneweeswwnw
nenenwneeneswneseenewnwswwnwenenenw
senenwnwwnwsewsewnesenenwwnewsewww
swweeenenenenewseeeeewsenwnee
nwneeseseseseseseseseseswse
eeeeweeeeweeneeesweneee
swswseseesesesesesewseseseseneswsewnesesw
eeenwseeeswnweeeeeeeeeeeesw
swswswswsweewswswswwsweswseswswnwnww
sesewsenwseeseeseeeenwnweswnesesesw
seseesesesesewseseeswseeseneesesenw
neeenwnenwsweneneseeenee
seenewesenwseseeseseseseee
nwswswsweswswwwwwswswswwswsw
wwwwnewwswnewwwnewwseswseww
eeseseseseseseseseesesesesenwenw
wwewwwwwwwnwwwww
swswswwswnewswneswswseswwswswwwswsw
wswneswswswwwwneswwseswswwswwswswsesw
nwnenwnenwnenenenewneneneseenwsenwswnwne
wnweswenwneeswswweseneseneeeenw
wnwneneneenenwnenenenene
newswwswweeswseseswswwseneswwnew
wsweneeseseseseseseseeseeseseeswene
sesenwseswseseseswseewnwseseswsese
seswnwnwneesenwseneewswnenwee
nwnwnwnwsenwnwnesewwnenenenenenwnenwnwnenw
senewesweeneswewsenwe
sewewswswwwwswnwwwnewwwwwswsww
eeneeeeeneeseneeeneneneeswnwnw
swseswwsewswseseswswseneswswswseseswneswsw
nenenenwneneseneneneneneneeeeneneswnwne
wnwsenwnwnwwsewnwnwnwnwnwewswnenenw
nweeeeeneesweneeeeneeneeswesw
sesewwnewwwwwnwwwnewwseeww
nwswswnwswneswwwnwswswsweeswnweeneee
wwwwwwwwswwwwwsewwnenewww
nenwsenwseeswneswseseswswenwswswseswsww
swswwswnwswwswswwswswwswwwewwnwew
wnwnwnwnewseswwewnwwwnwnwwnwsew
weseeseseseenenewseesewswsesesese
nenenenwnwneswnwneneseneneenwnenwnenew
nwseeeeswnewsewseeeeesesewesee
wwnwwewwwwnwenwnwwwwswnwwww
nwnwnwswnwnwnwenwnwnwnwnwnwnenwnwnwnw
wseswweseseneswnwneseswsewswswseese
neewseeesweeneenee
enwseswswswseseswswswswwswswsenwnwe
sewwnwwewwsewwwwwenwsewwwne
wewswswwnwnenwswneeswnwnesesenwesw
swswnenwneswswswswswswswswwswseneswswswse
wswwswswwswneweswewnwswswwsewwe
wnwwnwwsewswwwwwsenwwwswnenwswnee
seseeswenenesesewsewswneneseseesenwse
sesesesesesesenweneseseseseneswsewswsese
wnwnenenesweneeweneseeeseeene
sewnwwnwnwwnwwwwnwnwwsenwneww
wwswswwnewneseswnewwsenewswwwsew
nenesewneswnwenwwnesw
nweeeeeeseeesenwneswneeweene
nwnwwnwnwnwwnwnwwnwnwwwwew
seseseseseseseseswsenwseswsesesenesesese
seeswnwswnwnwseswsenesesweswse
seseeseseseseeseseenwsewseseswnenesewse
wweswnwwwnwsewwnwnwwnewnwwnwnwenw
neneswswswswswswwswneeswwswseseswswswse
sewnwseseswnwswseswsesenwseswseneseseswe
seseseseseeneseewseswneseeseseseseese
ewswseswnewswwwswwwswewwnew
swwewwswnesenesenwwnewnw
seseneseswsesenwseseswwnesesesewse
newswwswwswswswwswwnewswswswwsesw
wseneeeeswnwneenweneneweeeeeee
wswsewswswneswsewneneneswwwwswwsw
swwneeneswswwwswwwsenwswwneswnene
seeeeneeeeeswenweeeseseswsese
sesweeenwnewnwnwneeenwswsewsenwsw
seswnwseeseewnwswneenwnwseswneesee
neswnwwnwnwswnwnwnwnwnwnwenwnwnwnwnwnw
swseswswswseswswneswsw
neeswneneeswsewnwnwneswewnenwenee
swswseswswseswseswnwseswswweswswswneswswse
seseewseeseeeswseseseneseeewee
eeeeeseeweswwseene
swswswswswswswswswswseewneswswswswswsw
senwwwnewseesesenwnwenwwswnwnenwnwnw
eeeseswneesweeeeenweeeenee
newswnesweneneweneneneene
nesenwnenenwnwswseswenwwwwsww
senewswswwseswswnwwsw
newwwwsewswwwwswnwsewswsw
nwnwwnwnwsenwnwwnwnwnwnwnenwnwwwenw
swsenwnesesesewswswswswswswswswseswswsw
seneseseswwesewseseneseseeese
wwwsewwwwnwnwswwwwwwwewwsw
neewneeswenenenenenenenenenenewnenew
nwnenwenwnwnwnwwnwnwnwnenewnwneenene
enwwwwwwwwwsenwnwwewww
senwnwnwnwnwenenwwswneenesweewswswne
nesesesesewsewnesenwseswseswsenwsesesw
seseswswswseseenwseseneswnwnw
seseseseseseeeseeweeseseswnwsenesenw
nenewwswseseswseenwenesenwwwesenwswse
nwnwnwnwswwnweswenwnwnwnwnwnwnwenwswnw
wwwenwsesewnwnwnenwsenewsenwenwwse
swsewswnwwwswewnw
enwnwsenwnwenwnenwnwnwnwnwwswnwnwwew

108
2020/day24/Makefile Normal file
View File

@@ -0,0 +1,108 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := INPUT.txt
SHELL := /bin/bash
CC := gcc
BEAR := bear
CCLSFILE:= compile_commands.json
LIB := aoc_$(shell uname -m)
INCDIR := ../include
LIBDIR := ../lib
LDFLAGS := -L$(LIBDIR)
#LDLIB := -l$(LIB) -lm
LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
# CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations
CFLAGS += -Wno-unused-result
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
--sigill-diagnostics=yes --quiet --show-error-list=yes
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH)
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 ccls
all: README.org ccls ex1 ex2
memcheck: memcheck1 memcheck2
memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
memcheck2: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
compile: aoc-c
cpp: aoc-c.i
assembly: aoc-c.s
ex1: aoc-c
@$(TIME) ex1.bash -p 1 < $(INPUT)
@$(TIME) aoc-c -p 1 < $(INPUT)
ex2: aoc-c
@$(TIME) ex2.bash -p 2 < $(INPUT)
@$(TIME) aoc-c -p 2 < $(INPUT)
ccls: $(CCLSFILE)
clean:
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
.c:
@echo compiling $<
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
# generate pre-processed file (.i) and assembler (.s)
%.i: %.c
@echo generating $@
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
%.s: %.c
@echo generating $@
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
# generate README.org from README.html (must cleanup !)
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@
# generate compile_commands.json
$(CCLSFILE): aoc-c.c Makefile
$(BEAR) -- make clean compile
bear: clean
@$(BEAR) -- make compile
@touch .ccls-root

131
2020/day24/README.org Normal file
View File

@@ -0,0 +1,131 @@
** --- Day 24: Lobby Layout ---
Your raft makes it to the tropical island; it turns out that the small
crab was an excellent navigator. You make your way to the resort.
As you enter the lobby, you discover a small problem: the floor is being
renovated. You can't even reach the check-in desk until they've finished
installing the /new tile floor/.
The tiles are all /hexagonal/; they need to be arranged in a
[[https://en.wikipedia.org/wiki/Hexagonal_tiling][hex grid]] with a very
specific color pattern. Not in the mood to wait, you offer to help
figure out the pattern.
The tiles are all /white/ on one side and /black/ on the other. They
start with the white side facing up. The lobby is large enough to fit
whatever pattern might need to appear there.
A member of the renovation crew gives you a /list of the tiles that need
to be flipped over/ (your puzzle input). Each line in the list
identifies a single tile that needs to be flipped by giving a series of
steps starting from a /reference tile/ in the very center of the room.
(Every line starts from the same reference tile.)
Because the tiles are hexagonal, every tile has /six neighbors/: east,
southeast, southwest, west, northwest, and northeast. These directions
are given in your list, respectively, as =e=, =se=, =sw=, =w=, =nw=, and
=ne=. A tile is identified by a series of these directions with /no
delimiters/; for example, =esenee= identifies the tile you land on if
you start at the reference tile and then move one tile east, one tile
southeast, one tile northeast, and one tile east.
Each time a tile is identified, it flips from white to black or from
black to white. Tiles might be flipped more than once. For example, a
line like =esew= flips a tile immediately adjacent to the reference
tile, and a line like =nwwswee= flips the reference tile itself.
Here is a larger example:
#+BEGIN_EXAMPLE
sesenwnenenewseeswwswswwnenewsewsw
neeenesenwnwwswnenewnwwsewnenwseswesw
seswneswswsenwwnwse
nwnwneseeswswnenewneswwnewseswneseene
swweswneswnenwsewnwneneseenw
eesenwseswswnenwswnwnwsewwnwsene
sewnenenenesenwsewnenwwwse
wenwwweseeeweswwwnwwe
wsweesenenewnwwnwsenewsenwwsesesenwne
neeswseenwwswnwswswnw
nenwswwsewswnenenewsenwsenwnesesenew
enewnwewneswsewnwswenweswnenwsenwsw
sweneswneswneneenwnewenewwneswswnese
swwesenesewenwneswnwwneseswwne
enesenwswwswneneswsenwnewswseenwsese
wnwnesenesenenwwnenwsewesewsesesew
nenewswnwewswnenesenwnesewesw
eneswnwswnwsenenwnwnwwseeswneewsenese
neswnwewnwnwseenwseesewsenwsweewe
wseweeenwnesenwwwswnew
#+END_EXAMPLE
In the above example, 10 tiles are flipped once (to black), and 5 more
are flipped twice (to black, then back to white). After all of these
instructions have been followed, a total of /=10=/ tiles are /black/.
Go through the renovation crew's list and determine which tiles they
need to flip. After all of the instructions have been followed, /how
many tiles are left with the black side up?/
Your puzzle answer was =450=.
** --- Part Two ---
The tile floor in the lobby is meant to be a living art exhibit. Every
day, the tiles are all flipped according to the following rules:
- Any /black/ tile with /zero/ or /more than 2/ black tiles immediately
adjacent to it is flipped to /white/.
- Any /white/ tile with /exactly 2/ black tiles immediately adjacent to
it is flipped to /black/.
Here, /tiles immediately adjacent/ means the six tiles directly touching
the tile in question.
The rules are applied /simultaneously/ to every tile; put another way,
it is first determined which tiles need to be flipped, then they are all
flipped at the same time.
In the above example, the number of black tiles that are facing up after
the given number of days has passed is as follows:
#+BEGIN_EXAMPLE
Day 1: 15
Day 2: 12
Day 3: 25
Day 4: 14
Day 5: 23
Day 6: 28
Day 7: 41
Day 8: 37
Day 9: 49
Day 10: 37
Day 20: 132
Day 30: 259
Day 40: 406
Day 50: 566
Day 60: 788
Day 70: 1106
Day 80: 1373
Day 90: 1844
Day 100: 2208
#+END_EXAMPLE
After executing this process a total of 100 times, there would be
/=2208=/ black tiles facing up.
/How many tiles will be black after 100 days?/
Your puzzle answer was =4059=.
Both parts of this puzzle are complete! They provide two gold stars: **
At this point, all that is left is for you to [[/2020][admire your
Advent calendar]].
If you still want to see it, you can [[file:24/input][get your puzzle
input]].
You can also [Shareon
[[https://twitter.com/intent/tweet?text=I%27ve+completed+%22Lobby+Layout%22+%2D+Day+24+%2D+Advent+of+Code+2020&url=https%3A%2F%2Fadventofcode%2Ecom%2F2020%2Fday%2F24&related=ericwastl&hashtags=AdventOfCode][Twitter]]
[[javascript:void(0);][Mastodon]]] this puzzle.

20
2020/day24/TEST.txt Normal file
View File

@@ -0,0 +1,20 @@
sesenwnenenewseeswwswswwnenewsewsw
neeenesenwnwwswnenewnwwsewnenwseswesw
seswneswswsenwwnwse
nwnwneseeswswnenewneswwnewseswneseene
swweswneswnenwsewnwneneseenw
eesenwseswswnenwswnwnwsewwnwsene
sewnenenenesenwsewnenwwwse
wenwwweseeeweswwwnwwe
wsweesenenewnwwnwsenewsenwwsesesenwne
neeswseenwwswnwswswnw
nenwswwsewswnenenewsenwsenwnesesenew
enewnwewneswsewnwswenweswnenwsenwsw
sweneswneswneneenwnewenewwneswswnese
swwesenesewenwneswnwwneseswwne
enesenwswwswneneswsenwnewswseenwsese
wnwnesenesenenwwnenwsewesewsesesew
nenewswnwewswnenesenwnesewesw
eneswnwswnwsenenwnwnwwseeswneewsenese
neswnwewnwnwseenwseesewsenwsweewe
wseweeenwnesenwwwswnew

230
2020/day24/aoc-c.c Normal file
View File

@@ -0,0 +1,230 @@
/* aoc-c.c: Advent2020, day 24, parts 1 and 2
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "bits.h"
#include "pool.h"
#include "debug.h"
#include "hashtable.h"
#include "debug.h"
/* In day 24 tasks, we do not care the order of tiles, as we regenerate
* a new list after each process.
* So we will rely on a hashtable, which will allow to quickly find a
* given point.
* We use here two hash-tables: One to keep the current black tiles, and
* one for the neighbours count.
* My first try with the Linux kernel hashtables implementation.
*/
typedef union coord {
u32 val; /* used for hash */
struct {
s16 x, y;
};
} coord_t;
typedef struct point {
coord_t pos;
int count;
struct hlist_node hlist; /* entry in hash table */
} point_t;
#define HBITS 11 /* 11 bits: size is 2048 */
DEFINE_HASHTABLE(hasht_black, HBITS); /* current black tiles */
DEFINE_HASHTABLE(hasht_count, HBITS); /* count of neighbours */
pool_t *pt_pool;
static __always_inline u32 hash(coord_t p)
{
return hash_32(p.val, HASH_BITS(hasht_black));
}
/**
* find_point - find entry in an hashtable bucket
*/
static point_t *find_point(struct hlist_head *head, coord_t p)
{
point_t *point;
hlist_for_each_entry(point, head, hlist) {
if (point->pos.val == p.val)
return point;
}
return NULL;
}
/**
* add_neighbour - add point in hasht_count hashtable (used to count neighbours)
*/
static point_t *add_neighbour(coord_t pos)
{
point_t *new;
u32 h;
h = hash(pos);
if (!(new = find_point(&hasht_count[h], pos))) {
new = pool_get(pt_pool);
new->pos.val = pos.val;
new->count = 0;
hlist_add_head(&new->hlist, &hasht_count[h]);
}
new->count++;
return new;
}
/**
* init_point - add point in hasht_black hashtable, remove if it exists (init)
*/
static point_t *init_point(coord_t pos)
{
point_t *new;
u32 h;
h = hash(pos);
if ((new = find_point(&hasht_black[h], pos))) {
hlist_del(&new->hlist);
pool_add(pt_pool, new);
new = NULL;
} else {
new = pool_get(pt_pool);
new->pos.val = pos.val;
new->count = 0;
hlist_add_head(&new->hlist, &hasht_black[h]);
}
return new;
}
/**
* count_black - count elements in hasht_black
*/
static int count_black()
{
point_t *cur;
int res = 0;
ulong bucket;
hash_for_each(hasht_black, bucket, cur, hlist)
res++;
return res;
}
static const coord_t neighbours [] = {
{ .x = 2, .y = 0 }, { .x = -2, .y = 0 }, /* east and west */
{ .x = 1, .y = -1 }, { .x = 1, .y = 1 }, /* SE and NE */
{ .x = -1, .y = -1 }, { .x = -1, .y = 1 } /* SW and NW */
};
/**
* life - do one day.
*/
static void life()
{
point_t *pt_cur, *pt_count;
u32 bucket;
struct hlist_node *tmp;
/* fill hasht_count hashtable with neighbours */
hash_for_each(hasht_black, bucket, pt_cur, hlist) {
s16 x = pt_cur->pos.x, y = pt_cur->pos.y;
for (int i = 0; i < (int) ARRAY_SIZE(neighbours); ++i) {
coord_t neigh = {
.x = x + neighbours[i].x,
.y = y + neighbours[i].y,
};
add_neighbour(neigh);
}
}
/* check hasht_black tiles (currently black) */
hash_for_each_safe(hasht_black, bucket, tmp, pt_cur, hlist) {
int h = hash(pt_cur->pos);
point_t *pt_count = find_point(&hasht_count[h], pt_cur->pos);
if (!pt_count || pt_count->count > 2) {
hash_del(&pt_cur->hlist); /* black tile becomes white */
pool_add(pt_pool, pt_cur);
}
/* we do not want to re-consider this point in next loop */
if (pt_count) {
hash_del(&pt_count->hlist);
pool_add(pt_pool, pt_count);
}
}
/* check remaining points in hasht_count (not in hasht_black => white) */
hash_for_each_safe(hasht_count, bucket, tmp, pt_count, hlist) {
hash_del(&pt_count->hlist);
if (pt_count->count == 2)
hash_add(hasht_black, &pt_count->hlist, hash(pt_count->pos));
else
pool_add(pt_pool, pt_count);
}
}
static void parse()
{
size_t alloc;
ssize_t len;
char *buf = NULL;
while ((len = getline(&buf, &alloc, stdin)) > 0) {
buf[len - 1] = 0;
coord_t p = { .val = 0 };
char *c = buf;
while (*c) {
switch (*c) {
case 'e': ++p.x; break;
case 'w': --p.x; break;
case 's': --p.y; ++c; break;
case 'n': ++p.y; ++c;
}
if (*c == 'e')
++p.x;
else if (*c == 'w')
--p.x;
c++;
}
init_point(p);
}
free(buf);
}
static int usage(char *prg)
{
fprintf(stderr, "Usage: %s [-d debug_level] [-p part]\n", prg);
return 1;
}
int main(ac, av)
int ac;
char **av;
{
int opt, part = 1;
while ((opt = getopt(ac, av, "d:p:")) != -1) {
switch (opt) {
case 'd':
debug_level_set(atoi(optarg));
break;
case 'p': /* 1 or 2 */
part = atoi(optarg);
if (part < 1 || part > 2)
default:
return usage(*av);
}
}
pt_pool = pool_create("pool_points", 2048, sizeof(point_t));
parse();
if (part == 2) {
for (int i = 0; i < 100; ++i)
life();
}
printf("%s : res=%d\n", *av, count_black());
pool_destroy(pt_pool);
exit (0);
}

46
2020/day24/ex1.bash Executable file
View File

@@ -0,0 +1,46 @@
#!/bin/bash
#
# ex1.bash: Advent2020 game, day 24/game 1.
# See https://www.redblobgames.com/grids/hexagons/ for hexagon possible
# representations.
# I use the "doubled-coordinate" system here :
# https://www.redblobgames.com/grids/hexagons/#coordinates-doubled
CMD=${0##*/}
shopt -s extglob
set -o noglob
declare -A plan
declare -i x y
while read -r line; do
x=0
y=0
for ((i=0; i<${#line}; ++i)); do
c=${line:i:1}
case "$c" in
e) ((++x))
;;
w) ((--x))
;;
s) ((--y, ++i))
c=${line:i:1}
;;
n) ((++y, ++i))
c=${line:i:1}
;;
esac
if [[ "$c" = e ]]; then
((++x))
elif [[ "$c" = w ]]; then
((--x))
else
printf "error c=%s\n" "$c"
exit 1
fi
done
[[ -v plan[$x,$y] ]] && unset "plan[$x,$y]" || plan[$x,$y]=1
done
res=${#plan[@]}
printf "%s: res=%s\n" "$CMD" "$res"
exit 0

71
2020/day24/ex2.bash Executable file
View File

@@ -0,0 +1,71 @@
#!/bin/bash
#
# ex1.bash: Advent2020 game, day 24/game 2.
# See https://www.redblobgames.com/grids/hexagons/ for hexagon possible
# representations.
# I use the "doubled-coordinate" system here :
# https://www.redblobgames.com/grids/hexagons/#coordinates-doubled
CMD=${0##*/}
shopt -s extglob
set -o noglob
declare -A plan=() count=()
declare -i x y loops=100
while read -r line; do
x=0
y=0
for ((i=0; i<${#line}; ++i)); do
c=${line:i:1}
case "$c" in
e) ((++x))
;;
w) ((--x))
;;
s) ((--y, ++i))
c=${line:i:1}
;;
n) ((++y, ++i))
c=${line:i:1}
;;
esac
if [[ "$c" = e ]]; then
((++x))
elif [[ "$c" = w ]]; then
((--x))
else
printf "error c=%s\n" "$c"
exit 1
fi
done
[[ -v plan[$x,$y] ]] && unset "plan[$x,$y]" || plan[$x,$y]=1
done
# adjacent cells (x1 y1 x2 y2 etc...)
declare -a directions=(
2 0 -2 0 # east and west
1 -1 1 1 # SE and NE
-1 -1 -1 1 # SW and NW
)
for ((_c = 0; _c < loops; ++_c)) do
count=()
for cell in "${!plan[@]}"; do # count adjacent tiles
x=${cell%,*}
y=${cell#*,}
for ((i = 0; i < ${#directions[@]}; i += 2)); do
(( ++count[$((x + directions[$i])),$((y + directions[$((i+1))]))] ))
done
done
for cell in "${!plan[@]}"; do # check black tiles
(( count[$cell] == 0 || count[$cell] > 2)) && unset "plan[$cell]"
unset "count[$cell]"
done
for cell in "${!count[@]}"; do # remaining ones are white
((count[$cell] == 2)) && plan[$cell]=1
done
done
printf "%s: res=%d\n" "$CMD" "${#plan[@]}"
exit 0

2
2020/day25/INPUT.txt Normal file
View File

@@ -0,0 +1,2 @@
3418282
8719412

Some files were not shown because too many files have changed in this diff Show More