Compare commits

..

183 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
d5c37f5d48 cosmetic changes 2022-09-28 15:24:18 +02:00
1c10926cf9 bits.h: add rolXX(), rorXX(), ilog2(), bits_per(), etc... 2022-09-28 15:22:25 +02:00
94c6b2eec5 add attribute(__pure__) 2022-09-28 15:21:11 +02:00
b50f3a7098 switch from gnu99 to gnu11 2022-09-28 15:16:41 +02:00
8783eca22c 2019 day 6 init 2022-09-25 12:28:40 +02:00
3d18e36ff4 2019 day 5: fix wrong link in README, replace struct with typedefs 2022-09-25 12:26:07 +02:00
b6af1f3edb 2019 day 5: Update results & README 2022-09-24 18:48:20 +02:00
Bruno
68d81fd1da 2019 day5: cleaner (final ?) version 2022-09-24 12:13:14 +02:00
Bruno
b206ee5b87 2019 day5: fix run-example.sh reversed results 2022-09-24 12:12:12 +02:00
Bruno
13c977957f 2019 day 5: working version before cleanup 2022-09-24 08:01:57 +02:00
Bruno
d0adb2378a 2019 day 5: set all examples + test script 2022-09-24 07:55:47 +02:00
d1221ab086 2019 day 5: add examples from day 2, add _stringify in br.h 2022-09-22 10:11:24 +02:00
f2b32f236d 2019 day 5 init (with day 2 code) 2022-09-21 09:43:50 +02:00
696273367a 2019: update Makefile from day 4 2022-09-21 09:27:33 +02:00
f7336d6814 when rule 4 is violated, skip to next possible number 2022-09-20 22:01:43 +02:00
a461bf2842 typo 2022-09-20 20:02:23 +02:00
314 changed files with 37923 additions and 1382 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

@@ -46,10 +46,87 @@ aoc-c : res=9238
+++++++++++++++++ part 1
aoc-c : res=2090
time: 0:00.01 real, 0.01 user, 0.00 sys
context-switch: 2+1, page-faults: 0+88
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+90
+++++++++++++++++ part 2
aoc-c : res=1419
time: 0:00.01 real, 0.00 user, 0.00 sys
context-switch: 3+1, page-faults: 0+91
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+89
=========================================
================= day05 =================
=========================================
+++++++++++++++++ part 1
aoc-c : res=10987514
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+87
+++++++++++++++++ part 2
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.
#
@@ -24,7 +24,7 @@ LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu99
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
@@ -41,7 +41,8 @@ CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := -q -s --leak-check=full --show-leak-kinds=all --track-origins=yes
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"

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.
#
@@ -24,7 +24,7 @@ LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu99
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
@@ -41,7 +41,8 @@ CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := -q -s --leak-check=full --show-leak-kinds=all --track-origins=yes
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"

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.
#
@@ -24,7 +24,7 @@ LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu99
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
@@ -41,7 +41,8 @@ CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := -q -s --leak-check=full --show-leak-kinds=all --track-origins=yes
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"

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.
#
@@ -24,7 +24,7 @@ LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu99
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof

View File

@@ -1,6 +1,6 @@
/* aoc-c.c: Advent of Code 2019, day 3 parts 1 & 2
/* 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.
*
@@ -18,17 +18,45 @@
#include <getopt.h>
#include "debug.h"
#include "likely.h"
static int is_valid(int number, int part)
/**
* next_number() - finds next suitable number after a faulty right digit
* @number: the number
* @faulty: the faulty digit position (1, 10, 100, etc...)
* @left: the left digit of faulty one
*
* This function is called when rule 4 is violated:
* "Going from left to right, the digits never decrease."
* Example: 453456
* ^
* Here we will replace the faulty digit and next ones with its left digit
* value (5 here). Returned number will be 455555.
* This function allowed to save 546,495/548,022 calls to is_valid(), which
* is 99.7%.
*/
static int next_number(int number, int faulty, int left)
{
int valid = 0, dups[10] = { 0 };
int digit, dec;
int next = number - number % (faulty * 10);
for (digit = number % 10; number > 10; digit = dec) {
for (; faulty; faulty /= 10)
next += left * faulty;
return next;
}
static int is_valid(int number, int part, int *next)
{
int valid = 0, dups[10] = { 0 }, work = number;
int digit, dec = number + 1, faulty = 1;
*next = number + 1;
for (digit = number % 10; number > 10; digit = dec, faulty *= 10) {
number /= 10;
dec = number % 10;
if (dec > digit)
if (dec > digit) {
*next = next_number(work, faulty, dec);
return 0;
}
if (dec == digit) {
valid = 1;
dups[digit] += 2;
@@ -44,13 +72,12 @@ static int is_valid(int number, int part)
static int doit(int *nums, int part)
{
int res = 0;
int res = 0, next = 0;
/* There is surely a way to avoid 99% of useless calls to is_valid.
*/
for (int i = nums[0]; i < nums[1]; ++i)
if (is_valid(i, part))
for (int i = nums[0]; i < nums[1]; i = next) {
if (unlikely(is_valid(i, part, &next)))
res++;
}
return res;
}

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

@@ -0,0 +1 @@
3,0,4,0,99

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

@@ -0,0 +1 @@
1002,4,3,4,33

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

@@ -0,0 +1 @@
3,9,8,9,10,9,4,9,99,-1,8

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

@@ -0,0 +1 @@
3,9,7,9,10,9,4,9,99,-1,8

1
2019/day05/EXAMPLE4.txt Normal file
View File

@@ -0,0 +1 @@
3,3,1108,-1,8,3,4,3,99

1
2019/day05/EXAMPLE5.txt Normal file
View File

@@ -0,0 +1 @@
3,3,1107,-1,8,3,4,3,99

1
2019/day05/EXAMPLE6.txt Normal file
View File

@@ -0,0 +1 @@
3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9

1
2019/day05/EXAMPLE7.txt Normal file
View File

@@ -0,0 +1 @@
3,3,1105,-1,9,1101,0,0,12,4,12,99,1

1
2019/day05/EXAMPLE8.txt Normal file
View File

@@ -0,0 +1 @@
3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99

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

@@ -0,0 +1 @@
3,225,1,225,6,6,1100,1,238,225,104,0,1101,86,8,225,1101,82,69,225,101,36,65,224,1001,224,-106,224,4,224,1002,223,8,223,1001,224,5,224,1,223,224,223,102,52,148,224,101,-1144,224,224,4,224,1002,223,8,223,101,1,224,224,1,224,223,223,1102,70,45,225,1002,143,48,224,1001,224,-1344,224,4,224,102,8,223,223,101,7,224,224,1,223,224,223,1101,69,75,225,1001,18,85,224,1001,224,-154,224,4,224,102,8,223,223,101,2,224,224,1,224,223,223,1101,15,59,225,1102,67,42,224,101,-2814,224,224,4,224,1002,223,8,223,101,3,224,224,1,223,224,223,1101,28,63,225,1101,45,22,225,1101,90,16,225,2,152,92,224,1001,224,-1200,224,4,224,102,8,223,223,101,7,224,224,1,223,224,223,1101,45,28,224,1001,224,-73,224,4,224,1002,223,8,223,101,7,224,224,1,224,223,223,1,14,118,224,101,-67,224,224,4,224,1002,223,8,223,1001,224,2,224,1,223,224,223,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,7,677,677,224,102,2,223,223,1005,224,329,1001,223,1,223,1008,226,226,224,1002,223,2,223,1005,224,344,1001,223,1,223,1107,677,226,224,1002,223,2,223,1006,224,359,1001,223,1,223,107,677,677,224,102,2,223,223,1005,224,374,101,1,223,223,1108,677,226,224,102,2,223,223,1005,224,389,1001,223,1,223,1007,677,677,224,1002,223,2,223,1005,224,404,101,1,223,223,1008,677,226,224,102,2,223,223,1005,224,419,101,1,223,223,1108,226,677,224,102,2,223,223,1006,224,434,1001,223,1,223,8,677,226,224,1002,223,2,223,1005,224,449,101,1,223,223,1008,677,677,224,1002,223,2,223,1006,224,464,1001,223,1,223,1108,226,226,224,1002,223,2,223,1005,224,479,1001,223,1,223,1007,226,677,224,102,2,223,223,1005,224,494,1001,223,1,223,1007,226,226,224,102,2,223,223,1005,224,509,101,1,223,223,107,677,226,224,1002,223,2,223,1006,224,524,1001,223,1,223,108,677,677,224,102,2,223,223,1006,224,539,101,1,223,223,7,677,226,224,102,2,223,223,1006,224,554,1001,223,1,223,1107,226,677,224,102,2,223,223,1005,224,569,101,1,223,223,108,677,226,224,1002,223,2,223,1006,224,584,101,1,223,223,108,226,226,224,102,2,223,223,1006,224,599,1001,223,1,223,1107,226,226,224,102,2,223,223,1006,224,614,1001,223,1,223,8,226,677,224,102,2,223,223,1006,224,629,1001,223,1,223,107,226,226,224,102,2,223,223,1005,224,644,101,1,223,223,8,226,226,224,102,2,223,223,1006,224,659,101,1,223,223,7,226,677,224,102,2,223,223,1005,224,674,101,1,223,223,4,223,99,226

93
2019/day05/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 $@

184
2019/day05/README.org Normal file
View File

@@ -0,0 +1,184 @@
** --- Day 5: Sunny with a Chance of Asteroids ---
You're starting to sweat as the ship makes its way toward Mercury. The
Elves suggest that you get the air conditioner working by upgrading your
ship computer to support the Thermal Environment Supervision Terminal.
The Thermal Environment Supervision Terminal (TEST) starts by running a
/diagnostic program/ (your puzzle input). The TEST diagnostic program
will run on [[file:~/dev/advent-of-code/2019/day02][your existing Intcode computer]] after a few
modifications:
/First/, you'll need to add /two new instructions/:
- Opcode =3= takes a single integer as /input/ and saves it to the
position given by its only parameter. For example, the instruction
=3,50= would take an input value and store it at address =50=.
- Opcode =4= /outputs/ the value of its only parameter. For example, the
instruction =4,50= would output the value at address =50=.
Programs that use these instructions will come with documentation that
explains what should be connected to the input and output. The program
=3,0,4,0,99= outputs whatever it gets as input, then halts.
/Second/, you'll need to add support for /parameter modes/:
Each parameter of an instruction is handled based on its parameter mode.
Right now, your ship computer already understands parameter mode =0=,
/position mode/, which causes the parameter to be interpreted as a
/position/ - if the parameter is =50=, its value is /the value stored at
address =50= in memory/. Until now, all parameters have been in position
mode.
Now, your ship computer will also need to handle parameters in mode =1=,
/immediate mode/. In immediate mode, a parameter is interpreted as a
/value/ - if the parameter is =50=, its value is simply /=50=/.
Parameter modes are stored in the same value as the instruction's
opcode. The opcode is a two-digit number based only on the ones and tens
digit of the value, that is, the opcode is the rightmost two digits of
the first value in an instruction. Parameter modes are single digits,
one per parameter, read right-to-left from the opcode: the first
parameter's mode is in the hundreds digit, the second parameter's mode
is in the thousands digit, the third parameter's mode is in the
ten-thousands digit, and so on. Any missing modes are =0=.
For example, consider the program =1002,4,3,4,33=.
The first instruction, =1002,4,3,4=, is a /multiply/ instruction - the
rightmost two digits of the first value, =02=, indicate opcode =2=,
multiplication. Then, going right to left, the parameter modes are =0=
(hundreds digit), =1= (thousands digit), and =0= (ten-thousands digit,
not present and therefore zero):
#+BEGIN_EXAMPLE
ABCDE
1002
DE - two-digit opcode, 02 == opcode 2
C - mode of 1st parameter, 0 == position mode
B - mode of 2nd parameter, 1 == immediate mode
A - mode of 3rd parameter, 0 == position mode,
omitted due to being a leading zero
#+END_EXAMPLE
This instruction multiplies its first two parameters. The first
parameter, =4= in position mode, works like it did before - its value is
the value stored at address =4= (=33=). The second parameter, =3= in
immediate mode, simply has value =3=. The result of this operation,
=33 * 3 = 99=, is written according to the third parameter, =4= in
position mode, which also works like it did before - =99= is written to
address =4=.
Parameters that an instruction writes to will /never be in immediate
mode/.
/Finally/, some notes:
- It is important to remember that the instruction pointer should
increase by /the number of values in the instruction/ after the
instruction finishes. Because of the new instructions, this amount is
no longer always =4=.
- Integers can be negative: =1101,100,-1,4,0= is a valid program (find
=100 + -1=, store the result in position =4=).
The TEST diagnostic program will start by requesting from the user the
ID of the system to test by running an /input/ instruction - provide it
=1=, the ID for the ship's air conditioner unit.
It will then perform a series of diagnostic tests confirming that
various parts of the Intcode computer, like parameter modes, function
correctly. For each test, it will run an /output/ instruction indicating
how far the result of the test was from the expected value, where =0=
means the test was successful. Non-zero outputs mean that a function is
not working correctly; check the instructions that were run before the
output instruction to see which one failed.
Finally, the program will output a /diagnostic code/ and immediately
halt. This final output isn't an error; an output followed immediately
by a halt means the program finished. If all outputs were zero except
the diagnostic code, the diagnostic program ran successfully.
After providing =1= to the only input instruction and passing all the
tests, /what diagnostic code does the program produce?/
Your puzzle answer was =10987514=.
** --- Part Two ---
The air conditioner comes online! Its cold air feels good for a while,
but then the TEST alarms start to go off. Since the air conditioner
can't vent its heat anywhere but back into the spacecraft, it's actually
making the air inside the ship /warmer/.
Instead, you'll need to use the TEST to extend the
[[https://en.wikipedia.org/wiki/Spacecraft_thermal_control][thermal
radiators]]. Fortunately, the diagnostic program (your puzzle input) is
already equipped for this. Unfortunately, your Intcode computer is not.
Your computer is only missing a few opcodes:
- Opcode =5= is /jump-if-true/: if the first parameter is /non-zero/, it
sets the instruction pointer to the value from the second parameter.
Otherwise, it does nothing.
- Opcode =6= is /jump-if-false/: if the first parameter /is zero/, it
sets the instruction pointer to the value from the second parameter.
Otherwise, it does nothing.
- Opcode =7= is /less than/: if the first parameter is /less than/ the
second parameter, it stores =1= in the position given by the third
parameter. Otherwise, it stores =0=.
- Opcode =8= is /equals/: if the first parameter is /equal to/ the
second parameter, it stores =1= in the position given by the third
parameter. Otherwise, it stores =0=.
Like all instructions, these instructions need to support /parameter
modes/ as described above.
Normally, after an instruction is finished, the instruction pointer
increases by the number of values in that instruction. /However/, if the
instruction modifies the instruction pointer, that value is used and the
instruction pointer is /not automatically increased/.
For example, here are several programs that take one input, compare it
to the value =8=, and then produce one output:
- =3,9,8,9,10,9,4,9,99,-1,8= - Using /position mode/, consider whether
the input is /equal to/ =8=; output =1= (if it is) or =0= (if it is
not).
- =3,9,7,9,10,9,4,9,99,-1,8= - Using /position mode/, consider whether
the input is /less than/ =8=; output =1= (if it is) or =0= (if it is
not).
- =3,3,1108,-1,8,3,4,3,99= - Using /immediate mode/, consider whether
the input is /equal to/ =8=; output =1= (if it is) or =0= (if it is
not).
- =3,3,1107,-1,8,3,4,3,99= - Using /immediate mode/, consider whether
the input is /less than/ =8=; output =1= (if it is) or =0= (if it is
not).
Here are some jump tests that take an input, then output =0= if the
input was zero or =1= if the input was non-zero:
- =3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9= (using /position mode/)
- =3,3,1105,-1,9,1101,0,0,12,4,12,99,1= (using /immediate mode/)
Here's a larger example:
#+BEGIN_EXAMPLE
3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,
1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,
999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99
#+END_EXAMPLE
The above example program uses an input instruction to ask for a single
number. The program will then output =999= if the input value is below
=8=, output =1000= if the input value is equal to =8=, or output =1001=
if the input value is greater than =8=.
This time, when the TEST diagnostic program runs its input instruction
to get the ID of the system to test, /provide it =5=/, the ID for the
ship's thermal radiator controller. This diagnostic test suite only
outputs one number, the /diagnostic code/.
/What is the diagnostic code for system ID =5=?/
Your puzzle answer was =14195011=.
Both parts of this puzzle are complete! They provide two gold stars: **

162
2019/day05/aoc-c.c Normal file
View File

@@ -0,0 +1,162 @@
/* aoc-c.c: Advent of Code 2019, day 5 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"
typedef enum {
ADD = 1, MUL = 2,
INP = 3, OUT = 4,
JMP_T = 5, JMP_F = 6,
SET_LT = 7, SET_EQ = 8,
HLT = 99
} opcode_t;
/**
* ops - array of op-codes, mnemo, and number of parameters
* @op: An integer, the opcode
* @nargs: Opcode number of parameters (unused)
* @jump: Next instruction (usually @nargs + 1)
* @mnemo: Opcode mnemo (unused, for debug)
*/
typedef struct {
int op;
u8 nargs;
u8 jump;
char *mnemo;
} ops_t;
#define MAXOPS 1024
typedef struct {
int length; /* total program length */
int cur; /* current position */
int mem [MAXOPS]; /* should really be dynamic */
} program_t;
static ops_t ops[] = {
[ADD] = { ADD, 3, 4, __stringify(ADD) },
[MUL] = { MUL, 3, 4, __stringify(MUL) },
[INP] = { INP, 1, 2, __stringify(INP) },
[OUT] = { OUT, 1, 2, __stringify(OUT) },
[JMP_T] = { JMP_T, 2, 3, __stringify(JMP_T) },
[JMP_F] = { JMP_F, 2, 3, __stringify(JMP_F) },
[SET_LT] = { SET_LT, 3, 4, __stringify({SET_LT) },
[SET_EQ] = { SET_EQ, 3, 4, __stringify(SET_EQ) },
[HLT] = { HLT, 0, 1, __stringify(HLT) }
};
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 int run(program_t *p, int in)
{
int out = -1;
while (1) {
int op = OP(p, p->cur), cur = p->cur;
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:
poke(p, p->cur, 1, in);
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:
return out;
}
if (p->cur == cur)
p->cur += ops[op].jump;
}
}
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 opt, part = 1, in = -1;
program_t p = { 0 };
while ((opt = getopt(ac, av, "d:p:i:")) != -1) {
switch (opt) {
case 'd':
debug_level_set(atoi(optarg));
break;
case 'i':
in = 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);
if (in == -1)
in = part == 1? 1: 5;
parse(&p);
printf("%s : res=%d\n", *av, run(&p, in));
exit (0);
}

53
2019/day05/run-examples.sh Executable file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env bash
make compile
printf "***** EXAMPLE.txt: input value, then output it\n"
printf "Expected: 1\t"
./aoc-c -i 1 < EXAMPLE.txt
printf "Expected: 5\t"
./aoc-c -i 5 < EXAMPLE.txt
printf "\n***** EXAMPLE2.txt: equal test, position mode\n"
printf "Expected: 1\t"
./aoc-c -i 8 < EXAMPLE2.txt
printf "Expected: 0\t"
./aoc-c -i 0 < EXAMPLE.txt
printf "\n***** EXAMPLE3.txt: less than test, position mode\n"
printf "Expected: 1\t"
./aoc-c -i 7 < EXAMPLE3.txt
printf "Expected: 0\t"
./aoc-c -i 8 < EXAMPLE3.txt
printf "\n***** EXAMPLE4.txt: equal test, immediate mode\n"
printf "Expected: 1\t"
./aoc-c -i 8 < EXAMPLE4.txt
printf "Expected: 0\t"
./aoc-c -i 0 < EXAMPLE4.txt
printf "\n***** EXAMPLE5.txt: less than test, immediate mode\n"
printf "Expected: 1\t"
./aoc-c -i 7 < EXAMPLE5.txt
printf "Expected: 0\t"
./aoc-c -i 8 < EXAMPLE5.txt
printf "\n***** EXAMPLE6.txt: equal/jump test, position mode\n"
printf "Expected: 1\t"
./aoc-c -i 8 < EXAMPLE6.txt
printf "Expected: 0\t"
./aoc-c -i 0 < EXAMPLE6.txt
printf "\n***** EXAMPLE7.txt: equal/jump test, immediate mode\n"
printf "Expected: 1\t"
./aoc-c -i 8 < EXAMPLE7.txt
printf "Expected: 0\t"
./aoc-c -i 0 < EXAMPLE7.txt
printf "\n***** EXAMPLE8.txt: equal/less/jump test, mixed mode\n"
printf "Expected:999\t"
./aoc-c -i 7 < EXAMPLE8.txt
printf "Expected: 1000\t"
./aoc-c -i 8 < EXAMPLE8.txt
printf "Expected: 1001\t"
./aoc-c -i 9 < EXAMPLE8.txt

11
2019/day06/EXAMPLE.txt Normal file
View File

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

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

2306
2019/day06/INPUT.txt Normal file

File diff suppressed because it is too large Load Diff

93
2019/day06/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 $@

147
2019/day06/README.org Normal file
View File

@@ -0,0 +1,147 @@
** --- Day 6: Universal Orbit Map ---
You've landed at the Universal Orbit Map facility on Mercury. Because
navigation in space often involves transferring between orbits, the
orbit maps here are useful for finding efficient routes between, for
example, you and Santa. You download a map of the local orbits (your
puzzle input).
Except for the universal Center of Mass (=COM=), every object in space
is in orbit around exactly one other object. An
[[https://en.wikipedia.org/wiki/Orbit][orbit]] looks roughly like this:
#+BEGIN_EXAMPLE
\
\
|
|
AAA--> o o <--BBB
|
|
/
/
#+END_EXAMPLE
In this diagram, the object =BBB= is in orbit around =AAA=. The path
that =BBB= takes around =AAA= (drawn with lines) is only partly shown.
In the map data, this orbital relationship is written =AAA)BBB=, which
means "=BBB= is in orbit around =AAA=".
Before you use your map data to plot a course, you need to make sure it
wasn't corrupted during the download. To verify maps, the Universal
Orbit Map facility uses /orbit count checksums/ - the total number of
/direct orbits/ (like the one shown above) and /indirect orbits/.
Whenever =A= orbits =B= and =B= orbits =C=, then =A= /indirectly orbits/
=C=. This chain can be any number of objects long: if =A= orbits =B=,
=B= orbits =C=, and =C= orbits =D=, then =A= indirectly orbits =D=.
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
#+END_EXAMPLE
Visually, the above map of orbits looks like this:
#+BEGIN_EXAMPLE
G - H J - K - L
/ /
COM - B - C - D - E - F
\
I
#+END_EXAMPLE
In this visual representation, when two objects are connected by a line,
the one on the right directly orbits the one on the left.
Here, we can count the total number of orbits as follows:
- =D= directly orbits =C= and indirectly orbits =B= and =COM=, a total
of =3= orbits.
- =L= directly orbits =K= and indirectly orbits =J=, =E=, =D=, =C=, =B=,
and =COM=, a total of =7= orbits.
- =COM= orbits nothing.
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

@@ -14,6 +14,7 @@
#define BITS_H
#include <stdint.h>
#include <stdbool.h>
/* next include will define __WORDSIZE: 32 or 64
*/
@@ -262,7 +263,231 @@ static __always_inline int popcount32(u32 n)
# endif
}
/* rolXX are taken from kernel's <linux/bitops.h> are are:
* SPDX-License-Identifier: GPL-2.0
*/
/**
* rol64 - rotate a 64-bit value left
* @word: value to rotate
* @shift: bits to roll
*/
static inline u64 rol64(u64 word, unsigned int shift)
{
return (word << (shift & 63)) | (word >> ((-shift) & 63));
}
/**
* ror64 - rotate a 64-bit value right
* @word: value to rotate
* @shift: bits to roll
*/
static inline u64 ror64(u64 word, unsigned int shift)
{
return (word >> (shift & 63)) | (word << ((-shift) & 63));
}
/**
* rol32 - rotate a 32-bit value left
* @word: value to rotate
* @shift: bits to roll
*/
static inline u32 rol32(u32 word, unsigned int shift)
{
return (word << (shift & 31)) | (word >> ((-shift) & 31));
}
/**
* ror32 - rotate a 32-bit value right
* @word: value to rotate
* @shift: bits to roll
*/
static inline u32 ror32(u32 word, unsigned int shift)
{
return (word >> (shift & 31)) | (word << ((-shift) & 31));
}
/**
* rol16 - rotate a 16-bit value left
* @word: value to rotate
* @shift: bits to roll
*/
static inline u16 rol16(u16 word, unsigned int shift)
{
return (word << (shift & 15)) | (word >> ((-shift) & 15));
}
/**
* ror16 - rotate a 16-bit value right
* @word: value to rotate
* @shift: bits to roll
*/
static inline u16 ror16(u16 word, unsigned int shift)
{
return (word >> (shift & 15)) | (word << ((-shift) & 15));
}
/**
* rol8 - rotate an 8-bit value left
* @word: value to rotate
* @shift: bits to roll
*/
static inline u8 rol8(u8 word, unsigned int shift)
{
return (word << (shift & 7)) | (word >> ((-shift) & 7));
}
/**
* ror8 - rotate an 8-bit value right
* @word: value to rotate
* @shift: bits to roll
*/
static inline u8 ror8(u8 word, unsigned int shift)
{
return (word >> (shift & 7)) | (word << ((-shift) & 7));
}
/**
* ilog2 -
*/
static __always_inline __attribute__((const))
int __ilog2_u32(u32 n)
{
return fls32(n) - 1;
}
static __always_inline __attribute__((const))
int __ilog2_u64(u64 n)
{
return fls64(n) - 1;
}
/**
* is_power_of_2() - check if a value is a power of two
* @n: the value to check
*
* Determine whether some value is a power of two, where zero is
* *not* considered a power of two.
* Return: true if @n is a power of 2, otherwise false.
*/
static inline __attribute__((const))
bool is_power_of_2(unsigned long n)
{
return (n != 0 && ((n & (n - 1)) == 0));
}
/**
* ilog2 - log base 2 of 32-bit or a 64-bit unsigned value
* @n: parameter
*
* constant-capable log of base 2 calculation
* - this can be used to initialise global variables from constant data, hence
* the massive ternary operator construction
*
* selects the appropriately-sized optimised version depending on sizeof(n)
*/
#define ilog2(n) \
( \
__builtin_constant_p(n) ? \
((n) < 2 ? 0 : \
63 - __builtin_clzll(n)) : \
(sizeof(n) <= 4) ? \
__ilog2_u32(n) : \
__ilog2_u64(n) \
)
/**
* roundup_pow_of_two - round the given value up to nearest power of two
* @n: parameter
*
* round the given value up to the nearest power of two
* - the result is undefined when n == 0
* - this can be used to initialise global variables from constant data
*/
#define roundup_pow_of_two(n) \
( \
__builtin_constant_p(n) ? ( \
((n) == 1) ? 1 : \
(1UL << (ilog2((n) - 1) + 1)) \
) : \
__roundup_pow_of_two(n) \
)
/**
* rounddown_pow_of_two - round the given value down to nearest power of two
* @n: parameter
*
* round the given value down to the nearest power of two
* - the result is undefined when n == 0
* - this can be used to initialise global variables from constant data
*/
#define rounddown_pow_of_two(n) \
( \
__builtin_constant_p(n) ? ( \
(1UL << ilog2(n))) : \
__rounddown_pow_of_two(n) \
)
static inline __attribute_const__
int __order_base_2(unsigned long n)
{
return n > 1 ? ilog2(n - 1) + 1 : 0;
}
/**
* order_base_2 - calculate the (rounded up) base 2 order of the argument
* @n: parameter
*
* The first few values calculated by this routine:
* ob2(0) = 0
* ob2(1) = 0
* ob2(2) = 1
* ob2(3) = 2
* ob2(4) = 2
* ob2(5) = 3
* ... and so on.
*/
#define order_base_2(n) \
( \
__builtin_constant_p(n) ? ( \
((n) == 0 || (n) == 1) ? 0 : \
ilog2((n) - 1) + 1) : \
__order_base_2(n) \
)
static inline __attribute__((const))
int __bits_per(unsigned long n)
{
if (n < 2)
return 1;
if (is_power_of_2(n))
return order_base_2(n) + 1;
return order_base_2(n);
}
/**
* bits_per - calculate the number of bits required for the argument
* @n: parameter
*
* This is constant-capable and can be used for compile time
* initializations, e.g bitfields.
*
* The first few values calculated by this routine:
* bf(0) = 1
* bf(1) = 1
* bf(2) = 2
* bf(3) = 2
* bf(4) = 3
* ... and so on.
*/
#define bits_per(n) \
( \
__builtin_constant_p(n) ? ( \
((n) == 0 || (n) == 1) \
? 1 : ilog2(n) + 1 \
) : \
__bits_per(n) \
)
/** bit_for_each - iterate over an u64/u32 bits
* @pos: an int used as current bit

View File

@@ -18,12 +18,18 @@
#ifndef _BR_H
#define _BR_H
/* Indirect stringification. Doing two levels allows the parameter to be a
* macro itself. For example, compile with -DFOO=bar, __stringify(FOO)
* converts to "bar".
*/
#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)
/* generate a (maybe) unique id.
*/
#define ___PASTE(x, y) x##y
#define __PASTE(x, y) ___PASTE(x, y)
#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
//__##prefix##__COUNTER__
/* see https://lkml.org/lkml/2018/3/20/845 for explanation of this monster
*/
@@ -63,6 +69,8 @@
__cmp(x, y, op), \
__cmp_once(x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y), op))
#define __pure __attribute__((__pure__))
/**
* min - return minimum of two values of the same or compatible types
* @x: first value

View File

@@ -8,7 +8,8 @@
#include "likely.h"
#include "debug.h"
/* inspired by Linux kernel's <asm/bug.h> */
/* BUG functions inspired by Linux kernel's <asm/bug.h>
*/
#define panic() exit(0xff)

View File

@@ -2,7 +2,7 @@
#ifndef _BR_HASH_H
#define _BR_HASH_H
/* adaptation of Linux kernel's <linux/hash.h>
/* adaptation of Linux kernel's <linux/hash.h> and <linux/stringhash.h>
*/
/* Fast hashing routine for ints, longs and pointers.
@@ -11,6 +11,8 @@
#include <asm/types.h>
#include <asm/bitsperlong.h>
#include "bits.h"
#include "br.h"
/*
* The "GOLDEN_RATIO_PRIME" is used in ifs/btrfs/brtfs_inode.h and
* fs/inode.c. It's not actually prime any more (the previous primes
@@ -98,4 +100,74 @@ static inline u32 hash32_ptr(const void *ptr)
return (u32)val;
}
/*
* Routines for hashing strings of bytes to a 32-bit hash value.
*
* These hash functions are NOT GUARANTEED STABLE between kernel
* versions, architectures, or even repeated boots of the same kernel.
* (E.g. they may depend on boot-time hardware detection or be
* deliberately randomized.)
*
* They are also not intended to be secure against collisions caused by
* malicious inputs; much slower hash functions are required for that.
*
* They are optimized for pathname components, meaning short strings.
* Even if a majority of files have longer names, the dynamic profile of
* pathname components skews short due to short directory names.
* (E.g. /usr/lib/libsesquipedalianism.so.3.141.)
*/
/*
* Version 1: one byte at a time. Example of use:
*
* unsigned long hash = init_name_hash;
* while (*p)
* hash = partial_name_hash(tolower(*p++), hash);
* hash = end_name_hash(hash);
*
* Although this is designed for bytes, fs/hfsplus/unicode.c
* abuses it to hash 16-bit values.
*/
/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
#define init_name_hash(salt) (unsigned long)(salt)
/* partial hash update function. Assume roughly 4 bits per character */
static inline unsigned long
partial_name_hash(unsigned long c, unsigned long prevhash)
{
return (prevhash + (c << 4) + (c >> 4)) * 11;
}
/*
* Finally: cut down the number of bits to a int value (and try to avoid
* losing bits). This also has the property (wanted by the dcache)
* that the msbits make a good hash table index.
*/
static inline unsigned int end_name_hash(unsigned long hash)
{
return hash_long(hash, 32);
}
/*
* Version 2: One word (32 or 64 bits) at a time.
* If CONFIG_DCACHE_WORD_ACCESS is defined (meaning <asm/word-at-a-time.h>
* exists, which describes major Linux platforms like x86 and ARM), then
* this computes a different hash function much faster.
*
* If not set, this falls back to a wrapper around the preceding.
*/
extern unsigned int __pure hash_string(const void *salt, const char *, unsigned int);
/*
* A hash_len is a u64 with the hash of a string in the low
* half and the length in the high half.
*/
#define hashlen_hash(hashlen) ((u32)(hashlen))
#define hashlen_len(hashlen) ((u32)((hashlen) >> 32))
#define hashlen_create(hash, len) ((u64)(len)<<32 | (u32)(hash))
/* Return the "hash_len" (hash and length) of a null-terminated string */
extern u64 __pure hashlen_string(const void *salt, const char *name);
#endif /* _BR_HASH_H */

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 @@
INPUT := INPUT.txt
SHELL := /bin/bash
CFLAGS := -w -g
#CFLAGS := -w -g -pg
#CFLAGS := -w -O3
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
# 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 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 @@
INPUT := INPUT.txt
SHELL := /bin/bash
CFLAGS := -w -g
#CFLAGS := -w -g -pg
#CFLAGS := -w -O3
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
# 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 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 @@
INPUT := INPUT.txt
SHELL := /bin/bash
CFLAGS := -w -g
#CFLAGS := -w -g -pg
#CFLAGS := -w -O3
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
# 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 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.

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