Compare commits

..

136 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
252 changed files with 32079 additions and 1450 deletions

5
.gitignore vendored
View File

@@ -11,8 +11,5 @@ lib/
GPATH GPATH
GRTAGS GRTAGS
GTAGS GTAGS
FOO*
BAR*
QUAX*
TOTO*
README.html README.html
compile_commands.json

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??) 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: clean:
for dir in $(SUBDIRS) ; do \ @for dir in $(SUBDIRS) ; do \
make -C $$dir clean ; \ $(MAKE) --no-print-directory -C $$dir clean ; \
done done
all: $(SUBDIRS) cleanlib: clean
@$(RM) -f $(SLIB) $(DLIB) $(LIBOBJ)
cleanall: clean cleanlib
redo: cleanall all
$(SUBDIRS): $(SUBDIRS):
@echo "=========================================" @echo "========================================="
@echo "================= $@ =================" @echo "================= $@ ================="
@echo "=========================================" @echo "========================================="
@echo @echo
@echo "+++++++++++++++++ ex1" @echo "+++++++++++++++++ part 1"
@$(MAKE) --no-print-directory -C $@ ex1 2>&1 +@$(MAKE) --no-print-directory -C $@ ex1 2>&1
@echo "+++++++++++++++++ ex2" @echo "+++++++++++++++++ part 2"
@$(MAKE) --no-print-directory -C $@ ex2 2>&1 +@$(MAKE) --no-print-directory -C $@ ex2 2>&1
output: output:
@$(MAKE) --no-print-directory all >OUTPUT 2>&1 @$(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 time: 0:00.56 real, 0.55 user, 0.00 sys
context-switch: 12+1, page-faults: 0+5967 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
ex2.bash : res=412 ex2.bash : res=412
time: 0:03.37 real, 3.34 user, 0.03 sys time: 0:03.37 real, 3.34 user, 0.03 sys
context-switch: 19+1, page-faults: 0+11909 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 ================= ================= day20 =================
========================================= =========================================
@@ -481,31 +490,72 @@ ex1.bash: res=31314
time: 0:00.07 real, 0.06 user, 0.00 sys time: 0:00.07 real, 0.06 user, 0.00 sys
context-switch: 2+1, page-faults: 0+168 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
ex2.bash: res=32760 ex2.bash: res=32760
time: 1:21.92 real, 81.89 user, 0.01 sys time: 1:21.92 real, 81.89 user, 0.01 sys
context-switch: 462+1, page-faults: 0+5135 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 ================= ================= day23 =================
========================================= =========================================
+++++++++++++++++ ex1
ex1.bash: res=75893264 ex1.bash: res=75893264
time: 0:00.01 real, 0.01 user, 0.00 sys time: 0:00.01 real, 0.01 user, 0.00 sys
context-switch: 0+1, page-faults: 0+166 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 ex2.bash: res=38162588308
time: 6:52.50 real, 412.30 user, 0.14 sys time: 6:52.50 real, 412.30 user, 0.14 sys
context-switch: 2219+1, page-faults: 0+30233 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 ================= ================= day24 =================
========================================= =========================================
+++++++++++++++++ ex1
ex1.bash: res=450 ex1.bash: res=450
time: 0:00.17 real, 0.17 user, 0.00 sys time: 0:00.17 real, 0.16 user, 0.00 sys
context-switch: 5+1, page-faults: 0+177 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 ex2.bash: res=4059
time: 0:22.35 real, 22.22 user, 0.07 sys time: 0:22.35 real, 22.22 user, 0.07 sys
context-switch: 1471+1, page-faults: 0+858 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) @$(TIME) ex2-c < $(INPUT)
clean: clean:
@rm -f ex1-c ex2-c core ex2-galoisgirl-cob ex2-cob @rm -f ex1-c ex2-c core ex*-cob
output: output:
$(MAKE) --no-print-directory all >OUTPUT 2>&1 $(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; char **av;
{ {
int line=1, linelen=0, mod=0, i; int line=1, linelen=0, mod=0, i;
unsigned long res=1; unsigned long long res=1;
char str[80]; char str[80];
scanf("%s", str); /* ignore 1st line */ scanf("%s", str); /* ignore 1st line */
@@ -51,6 +51,6 @@ int main(ac, av)
} }
for (i=0; set[i].dx != -1; ++i) for (i=0; set[i].dx != -1; ++i)
res*=set[i].count; 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); 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; struct list *list;
unsigned long long val; unsigned long long val;
{ {
//int val;
unsigned cur, size; unsigned cur, size;
unsigned long long *ptr; unsigned long long *ptr;
@@ -80,7 +79,6 @@ struct list *add_val(list, val)
size+=BLOCKSIZE; size+=BLOCKSIZE;
list->size=size; list->size=size;
list->list=realloc(list->list, sizeof(unsigned long long)*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; ptr=list->list+cur;
@@ -91,10 +89,10 @@ struct list *add_val(list, val)
return list; return list;
} }
unsigned *calc(list) unsigned long long *calc(list)
struct list *list; struct list *list;
{ {
static unsigned res[4]; static unsigned long long res[4];
unsigned long long *ptr=list->list; unsigned long long *ptr=list->list;
unsigned last=list->last, i; unsigned last=list->last, i;
@@ -113,10 +111,9 @@ int main(ac, av)
{ {
char line[80]; char line[80];
struct list *list=NULL; struct list *list=NULL;
unsigned long long res, last; unsigned long long res, last, *result;
unsigned *result;
list=add_val(list, 0); list=add_val(list, 0llu);
while (fgets(line, sizeof line, stdin)) { while (fgets(line, sizeof line, stdin)) {
sscanf(line, "%llu", &res); sscanf(line, "%llu", &res);
list=add_val(list, res); list=add_val(list, res);
@@ -126,7 +123,7 @@ int main(ac, av)
list=add_val(list, last+3); list=add_val(list, last+3);
//print_list(list); //print_list(list);
result=calc(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]); result[1]*result[3]);
exit (0); exit (0);
} }

View File

@@ -131,7 +131,7 @@ int main(ac, av)
struct list *list=NULL; struct list *list=NULL;
unsigned long long res, last; unsigned long long res, last;
list=add_val(list, 0); list=add_val(list, 0ll);
while (fgets(line, sizeof line, stdin)) { while (fgets(line, sizeof line, stdin)) {
sscanf(line, "%llu", &res); sscanf(line, "%llu", &res);
list=add_val(list, 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() { function adj() {
local -i r="$1" n="$2" c="$3" count=0 local -i r="$1" n="$2" c="$3" count=0
local -a prow=(${rows[r-1]}) local -a prow=("${rows[r-1]}")
local -a row=(${rows[r]}) local -a row=("${rows[r]}")
local -a nrow=(${rows[r+1]}) local -a nrow=("${rows[r+1]}")
#echo #echo
#echo p="${prow[*]}" #echo p="${prow[*]}"
#echo r="${row[*]}" #echo r="${row[*]}"
@@ -51,7 +51,7 @@ function run() {
changed=0 changed=0
seated=0 seated=0
for ((r=1; r<=NROWS; ++r)); do for ((r=1; r<=NROWS; ++r)); do
row=(${rows[r]}) row=("${rows[r]}")
newrow=(0) newrow=(0)
for ((c=1; c<=RLENGTH; ++c)); do for ((c=1; c<=RLENGTH; ++c)); do
newrow+=("${row[c]}") newrow+=("${row[c]}")
@@ -61,13 +61,13 @@ function run() {
case ${row[c]} in case ${row[c]} in
0) continue 0) continue
;; ;;
1) if (( $(adj $r $c 2) == 0 )); then 1) if (( $(adj "$r" "$c" 2) == 0 )); then
((++changed)) ((++changed))
newrow[c]=2 newrow[c]=2
fi fi
#printf "[%d][%d]: %s %s %d\n" $r $c "${row[c]}" "${newrow[c]}" $(adj $r $c 2) #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)) ((++changed))
newrow[c]=1 newrow[c]=1
fi 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 @$(TIME) ex12-c 2 < $(INPUT) 2>&1
clean: clean:
@rm -f ex1-c ex2-c core @rm -f ex12-c core
deploy: deploy:
@$(MAKE) -C .. deploy @$(MAKE) -C .. deploy

View File

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

View File

@@ -1,30 +1,108 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := INPUT.txt INPUT := INPUT.txt
SHELL := /bin/bash SHELL := /bin/bash
CFLAGS := -w -g
#CFLAGS := -w -g -pg CC := gcc
#CFLAGS := -w -O3 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" TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH) 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: memcheck: memcheck1 memcheck2
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
compile: ex1-c ex2-c memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
ex1: memcheck2: aoc-c
@$(TIME) ex1.bash < $(INPUT) 2>&1 @$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
ex2: compile: aoc-c
@$(TIME) ex2.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1 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: 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: .c:
@$(MAKE) -C .. deploy @echo compiling $<
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
# generate pre-processed file (.i) and assembler (.s)
%.i: %.c
@echo generating $@
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
%.s: %.c
@echo generating $@
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
# generate README.org from README.html (must cleanup !)
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@
# generate compile_commands.json
$(CCLSFILE): aoc-c.c Makefile
$(BEAR) -- make clean compile
bear: clean
@$(BEAR) -- make compile
@touch .ccls-root

View File

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

View File

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

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

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

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

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

View File

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

View File

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

View File

@@ -1,30 +1,108 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := INPUT.txt INPUT := INPUT.txt
SHELL := /bin/bash SHELL := /bin/bash
CFLAGS := -w -g
#CFLAGS := -w -g -pg CC := gcc
#CFLAGS := -w -O3 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" TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH) 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: memcheck: memcheck1 memcheck2
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
compile: ex1-c ex2-c memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
ex1: memcheck2: aoc-c
@$(TIME) ex1.bash < $(INPUT) 2>&1 @$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
ex2: compile: aoc-c
@$(TIME) ex2.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1 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: 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: .c:
@$(MAKE) -C .. deploy @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,45 +0,0 @@
--- Day 21: Allergen Assessment ---
You reach the train's last stop and the closest you can get to your vacation island without getting wet. There aren't even any boats here, but nothing can stop you now: you build a raft. You just need a few days' worth of food for your journey.
You don't speak the local language, so you can't read any ingredients lists. However, sometimes, allergens are listed in a language you do understand. You should be able to use this information to determine which ingredient contains which allergen and work out which foods are safe to take with you on your trip.
You start by compiling a list of foods (your puzzle input), one food per line. Each line includes that food's ingredients list followed by some or all of the allergens the food contains.
Each allergen is found in exactly one ingredient. Each ingredient contains zero or one allergen. Allergens aren't always marked; when they're listed (as in (contains nuts, shellfish) after an ingredients list), the ingredient that contains each listed allergen will be somewhere in the corresponding ingredients list. However, even if an allergen isn't listed, the ingredient that contains that allergen could still be present: maybe they forgot to label it, or maybe it was labeled in a language you don't know.
For example, consider the following list of foods:
mxmxvkd kfcds sqjhc nhms (contains dairy, fish)
trh fvjkl sbzzf mxmxvkd (contains dairy)
sqjhc fvjkl (contains soy)
sqjhc mxmxvkd sbzzf (contains fish)
The first food in the list has four ingredients (written in a language you don't understand): mxmxvkd, kfcds, sqjhc, and nhms. While the food might contain other allergens, a few allergens the food definitely contains are listed afterward: dairy and fish.
The first step is to determine which ingredients can't possibly contain any of the allergens in any food in your list. In the above example, none of the ingredients kfcds, nhms, sbzzf, or trh can contain an allergen. Counting the number of times any of these ingredients appear in any ingredients list produces 5: they all appear once each except sbzzf, which appears twice.
Determine which ingredients cannot possibly contain any of the allergens in your list. How many times do any of those ingredients appear?
Your puzzle answer was 2211.
The first half of this puzzle is complete! It provides one gold star: *
--- Part Two ---
Now that you've isolated the inert ingredients, you should have enough information to figure out which ingredient contains which allergen.
In the above example:
mxmxvkd contains dairy.
sqjhc contains fish.
fvjkl contains soy.
Arrange the ingredients alphabetically by their allergen and separate them by commas to produce your canonical dangerous ingredient list. (There should not be any spaces in your canonical dangerous ingredient list.) In the above example, this would be mxmxvkd,sqjhc,fvjkl.
Time to stock your raft with supplies. What is your canonical dangerous ingredient list?
Answer:
Although it hasn't changed, you can still get your puzzle input.
You can also [Share] this puzzle.

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

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

View File

@@ -1,30 +1,108 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := INPUT.txt INPUT := INPUT.txt
SHELL := /bin/bash SHELL := /bin/bash
CFLAGS := -w -g
#CFLAGS := -w -g -pg CC := gcc
#CFLAGS := -w -O3 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" TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH) 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: memcheck: memcheck1 memcheck2
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
compile: ex1-c ex2-c memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
ex1: memcheck2: aoc-c
@$(TIME) ex1.bash < $(INPUT) 2>&1 @$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
ex2: compile: aoc-c
@$(TIME) ex2.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1 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: 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: .c:
@$(MAKE) -C .. deploy @echo compiling $<
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
# generate pre-processed file (.i) and assembler (.s)
%.i: %.c
@echo generating $@
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
%.s: %.c
@echo generating $@
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
# generate README.org from README.html (must cleanup !)
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@
# generate compile_commands.json
$(CCLSFILE): aoc-c.c Makefile
$(BEAR) -- make clean compile
bear: clean
@$(BEAR) -- make compile
@touch .ccls-root

View File

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

View File

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

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

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

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

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

View File

@@ -1,30 +1,108 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := INPUT.txt INPUT := INPUT.txt
SHELL := /bin/bash SHELL := /bin/bash
CFLAGS := -w -g
#CFLAGS := -w -g -pg CC := gcc
#CFLAGS := -w -O3 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" TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH) 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: memcheck: memcheck1 memcheck2
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
compile: ex1-c ex2-c memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
ex1: memcheck2: aoc-c
@$(TIME) ex1.bash < $(INPUT) 2>&1 @$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
ex2: compile: aoc-c
@$(TIME) ex2.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1 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: 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: .c:
@$(MAKE) -C .. deploy @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,94 +0,0 @@
--- Day 23: Crab Cups ---
The small crab challenges you to a game! The crab is going to mix up some cups, and you have to predict where they'll end up.
The cups will be arranged in a circle and labeled clockwise (your puzzle input). For example, if your labeling were 32415, there would be five cups in the circle; going clockwise around the circle from the first cup, the cups would be labeled 3, 2, 4, 1, 5, and then back to 3 again.
Before the crab starts, it will designate the first cup in your list as the current cup. The crab is then going to do 100 moves.
Each move, the crab does the following actions:
The crab picks up the three cups that are immediately clockwise of the current cup. They are removed from the circle; cup spacing is adjusted as necessary to maintain the circle.
The crab selects a destination cup: the cup with a label equal to the current cup's label minus one. If this would select one of the cups that was just picked up, the crab will keep subtracting one until it finds a cup that wasn't just picked up. If at any point in this process the value goes below the lowest value on any cup's label, it wraps around to the highest value on any cup's label instead.
The crab places the cups it just picked up so that they are immediately clockwise of the destination cup. They keep the same order as when they were picked up.
The crab selects a new current cup: the cup which is immediately clockwise of the current cup.
For example, suppose your cup labeling were 389125467. If the crab were to do merely 10 moves, the following changes would occur:
-- move 1 --
cups: (3) 8 9 1 2 5 4 6 7
pick up: 8, 9, 1
destination: 2
-- move 2 --
cups: 3 (2) 8 9 1 5 4 6 7
pick up: 8, 9, 1
destination: 7
-- move 3 --
cups: 3 2 (5) 4 6 7 8 9 1
pick up: 4, 6, 7
destination: 3
-- move 4 --
cups: 7 2 5 (8) 9 1 3 4 6
pick up: 9, 1, 3
destination: 7
-- move 5 --
cups: 3 2 5 8 (4) 6 7 9 1
pick up: 6, 7, 9
destination: 3
-- move 6 --
cups: 9 2 5 8 4 (1) 3 6 7
pick up: 3, 6, 7
destination: 9
-- move 7 --
cups: 7 2 5 8 4 1 (9) 3 6
pick up: 3, 6, 7
destination: 8
-- move 8 --
cups: 8 3 6 7 4 1 9 (2) 5
pick up: 5, 8, 3
destination: 1
-- move 9 --
cups: 7 4 1 5 8 3 9 2 (6)
pick up: 7, 4, 1
destination: 5
-- move 10 --
cups: (5) 7 4 1 8 3 9 2 6
pick up: 7, 4, 1
destination: 3
-- final --
cups: 5 (8) 3 7 4 1 9 2 6
In the above example, the cups' values are the labels as they appear moving clockwise around the circle; the current cup is marked with ( ).
After the crab is done, what order will the cups be in? Starting after the cup labeled 1, collect the other cups' labels clockwise into a single string with no extra characters; each number except 1 should appear exactly once. In the above example, after 10 moves, the cups clockwise from 1 are labeled 9, 2, 6, 5, and so on, producing 92658374. If the crab were to complete all 100 moves, the order after cup 1 would be 67384529.
Using your labeling, simulate 100 moves. What are the labels on the cups after cup 1?
Your puzzle answer was 75893264.
--- Part Two ---
Due to what you can only assume is a mistranslation (you're not exactly fluent in Crab), you are quite surprised when the crab starts arranging many cups in a circle on your raft - one million (1000000) in total.
Your labeling is still correct for the first few cups; after that, the remaining cups are just numbered in an increasing fashion starting from the number after the highest number in your list and proceeding one by one until one million is reached. (For example, if your labeling were 54321, the cups would be numbered 5, 4, 3, 2, 1, and then start counting up from 6 until one million is reached.) In this way, every number from one through one million is used exactly once.
After discovering where you made the mistake in translating Crab Numbers, you realize the small crab isn't going to do merely 100 moves; the crab is going to do ten million (10000000) moves!
The crab is going to hide your stars - one each - under the two cups that will end up immediately clockwise of cup 1. You can have them if you predict what the labels on those cups will be when the crab is finished.
In the above example (389125467), this would be 934001 and then 159792; multiplying these together produces 149245887792.
Determine which two cups will end up immediately clockwise of cup 1. What do you get if you multiply their labels together?
Your puzzle answer was 38162588308.
Both parts of this puzzle are complete! They provide two gold stars: **

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

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

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

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

View File

@@ -6,7 +6,7 @@ CMD=${0##*/}
shopt -s extglob shopt -s extglob
set -o noglob set -o noglob
declare -A next # next[i] is cup right to i declare -A next # next[i] is cup right to i (ring)
declare -i end runs cup _cup declare -i end runs cup _cup
read -r str read -r str
@@ -27,9 +27,8 @@ done
next[$_cup]=$cup # close the ring next[$_cup]=$cup # close the ring
_cup=$cup _cup=$cup
declare -i _1st _2nd _3rd dest declare -i _1st _2nd _3rd dest
# make the moves: a simple sub-linked list operation. # make the moves: a simple sub linked list operation.
for ((i = 1; i <= runs; ++i)); do for ((i = 1; i <= runs; ++i)); do
_1st="${next[$cup]}" _1st="${next[$cup]}"
_2nd="${next[$_1st]}" _2nd="${next[$_1st]}"

View File

@@ -33,6 +33,7 @@ next[$_cup]=$cup # close the ring
_cup=$cup _cup=$cup
declare -i _1st _2nd _3rd dest declare -i _1st _2nd _3rd dest
# make the moves: a simple sub linked list operation.
for ((i = 1; i <= runs; ++i)); do for ((i = 1; i <= runs; ++i)); do
_1st="${next[$cup]}" _1st="${next[$cup]}"
_2nd="${next[$_1st]}" _2nd="${next[$_1st]}"

View File

@@ -1,30 +1,108 @@
# AOC daily Makefile - GNU make only.
#
# Copyright (C) 2021-2022 Bruno Raoult ("br")
# Licensed under the GNU General Public License v3.0 or later.
# Some rights reserved. See COPYING.
#
# You should have received a copy of the GNU General Public License along with this
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
INPUT := INPUT.txt INPUT := INPUT.txt
SHELL := /bin/bash SHELL := /bin/bash
CFLAGS := -w -g
#CFLAGS := -w -g -pg CC := gcc
#CFLAGS := -w -O3 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" TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH) 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: memcheck: memcheck1 memcheck2
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
compile: ex1-c ex2-c memcheck1: aoc-c
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
ex1: memcheck2: aoc-c
@$(TIME) ex1.bash < $(INPUT) 2>&1 @$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
ex2: compile: aoc-c
@$(TIME) ex2.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1 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: 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: .c:
@$(MAKE) -C .. deploy @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,85 +0,0 @@
--- Day 24: Lobby Layout ---
Your raft makes it to the tropical island; it turns out that the small crab was an excellent navigator. You make your way to the resort.
As you enter the lobby, you discover a small problem: the floor is being renovated. You can't even reach the check-in desk until they've finished installing the new tile floor.
The tiles are all hexagonal; they need to be arranged in a hex grid with a very specific color pattern. Not in the mood to wait, you offer to help figure out the pattern.
The tiles are all white on one side and black on the other. They start with the white side facing up. The lobby is large enough to fit whatever pattern might need to appear there.
A member of the renovation crew gives you a list of the tiles that need to be flipped over (your puzzle input). Each line in the list identifies a single tile that needs to be flipped by giving a series of steps starting from a reference tile in the very center of the room. (Every line starts from the same reference tile.)
Because the tiles are hexagonal, every tile has six neighbors: east, southeast, southwest, west, northwest, and northeast. These directions are given in your list, respectively, as e, se, sw, w, nw, and ne. A tile is identified by a series of these directions with no delimiters; for example, esenee identifies the tile you land on if you start at the reference tile and then move one tile east, one tile southeast, one tile northeast, and one tile east.
Each time a tile is identified, it flips from white to black or from black to white. Tiles might be flipped more than once. For example, a line like esew flips a tile immediately adjacent to the reference tile, and a line like nwwswee flips the reference tile itself.
Here is a larger example:
sesenwnenenewseeswwswswwnenewsewsw
neeenesenwnwwswnenewnwwsewnenwseswesw
seswneswswsenwwnwse
nwnwneseeswswnenewneswwnewseswneseene
swweswneswnenwsewnwneneseenw
eesenwseswswnenwswnwnwsewwnwsene
sewnenenenesenwsewnenwwwse
wenwwweseeeweswwwnwwe
wsweesenenewnwwnwsenewsenwwsesesenwne
neeswseenwwswnwswswnw
nenwswwsewswnenenewsenwsenwnesesenew
enewnwewneswsewnwswenweswnenwsenwsw
sweneswneswneneenwnewenewwneswswnese
swwesenesewenwneswnwwneseswwne
enesenwswwswneneswsenwnewswseenwsese
wnwnesenesenenwwnenwsewesewsesesew
nenewswnwewswnenesenwnesewesw
eneswnwswnwsenenwnwnwwseeswneewsenese
neswnwewnwnwseenwseesewsenwsweewe
wseweeenwnesenwwwswnew
In the above example, 10 tiles are flipped once (to black), and 5 more are flipped twice (to black, then back to white). After all of these instructions have been followed, a total of 10 tiles are black.
Go through the renovation crew's list and determine which tiles they need to flip. After all of the instructions have been followed, how many tiles are left with the black side up?
Your puzzle answer was 450.
--- Part Two ---
The tile floor in the lobby is meant to be a living art exhibit. Every day, the tiles are all flipped according to the following rules:
Any black tile with zero or more than 2 black tiles immediately adjacent to it is flipped to white.
Any white tile with exactly 2 black tiles immediately adjacent to it is flipped to black.
Here, tiles immediately adjacent means the six tiles directly touching the tile in question.
The rules are applied simultaneously to every tile; put another way, it is first determined which tiles need to be flipped, then they are all flipped at the same time.
In the above example, the number of black tiles that are facing up after the given number of days has passed is as follows:
Day 1: 15
Day 2: 12
Day 3: 25
Day 4: 14
Day 5: 23
Day 6: 28
Day 7: 41
Day 8: 37
Day 9: 49
Day 10: 37
Day 20: 132
Day 30: 259
Day 40: 406
Day 50: 566
Day 60: 788
Day 70: 1106
Day 80: 1373
Day 90: 1844
Day 100: 2208
After executing this process a total of 100 times, there would be 2208 black tiles facing up.
How many tiles will be black after 100 days?
Your puzzle answer was 4059.
Both parts of this puzzle are complete! They provide two gold stars: **

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

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

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

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

View File

@@ -2,6 +2,10 @@
# #
# ex1.bash: Advent2020 game, day 24/game 1. # ex1.bash: Advent2020 game, day 24/game 1.
# See https://www.redblobgames.com/grids/hexagons/ for hexagon possible
# representations.
# I use the "doubled-coordinate" system here :
# https://www.redblobgames.com/grids/hexagons/#coordinates-doubled
CMD=${0##*/} CMD=${0##*/}
shopt -s extglob shopt -s extglob
set -o noglob set -o noglob

View File

@@ -2,6 +2,10 @@
# #
# ex1.bash: Advent2020 game, day 24/game 2. # ex1.bash: Advent2020 game, day 24/game 2.
# See https://www.redblobgames.com/grids/hexagons/ for hexagon possible
# representations.
# I use the "doubled-coordinate" system here :
# https://www.redblobgames.com/grids/hexagons/#coordinates-doubled
CMD=${0##*/} CMD=${0##*/}
shopt -s extglob shopt -s extglob
set -o noglob set -o noglob

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

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

30
2020/day25/Makefile Normal file
View File

@@ -0,0 +1,30 @@
INPUT := INPUT.txt
SHELL := /bin/bash
CFLAGS := -w -g -O3
#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"
export PATH := .:$(PATH)
.PHONY: clean all compile deploy ex1 ex2
all: ex1
output:
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
compile: ex1-c
ex1: ex1-c
@$(TIME) ex1.bash < $(INPUT) 2>&1
@$(TIME) ex1-c < $(INPUT) 2>&1
ex2:
@#$(TIME) ex2.bash < $(INPUT) 2>&1
@#$(TIME) ex1-c < $(INPUT) 2>&1
clean:
@rm -f ex1-c ex2-c core
deploy:
@$(MAKE) -C .. deploy

57
2020/day25/README Normal file
View File

@@ -0,0 +1,57 @@
--- Day 25: Combo Breaker ---
You finally reach the check-in desk. Unfortunately, their registration systems are currently offline, and they cannot check you in. Noticing the look on your face, they quickly add that tech support is already on the way! They even created all the room keys this morning; you can take yours now and give them your room deposit once the registration system comes back online.
The room key is a small RFID card. Your room is on the 25th floor and the elevators are also temporarily out of service, so it takes what little energy you have left to even climb the stairs and navigate the halls. You finally reach the door to your room, swipe your card, and - beep - the light turns red.
Examining the card more closely, you discover a phone number for tech support.
"Hello! How can we help you today?" You explain the situation.
"Well, it sounds like the card isn't sending the right command to unlock the door. If you go back to the check-in desk, surely someone there can reset it for you." Still catching your breath, you describe the status of the elevator and the exact number of stairs you just had to climb.
"I see! Well, your only other option would be to reverse-engineer the cryptographic handshake the card does with the door and then inject your own commands into the data stream, but that's definitely impossible." You thank them for their time.
Unfortunately for the door, you know a thing or two about cryptographic handshakes.
The handshake used by the card and the door involves an operation that transforms a subject number. To transform a subject number, start with the value 1. Then, a number of times called the loop size, perform the following steps:
Set the value to itself multiplied by the subject number.
Set the value to the remainder after dividing the value by 20201227.
The card always uses a specific, secret loop size when it transforms a subject number. The door always uses a different, secret loop size.
The cryptographic handshake works like this:
The card transforms the subject number of 7 according to the card's secret loop size. The result is called the card's public key.
The door transforms the subject number of 7 according to the door's secret loop size. The result is called the door's public key.
The card and door use the wireless RFID signal to transmit the two public keys (your puzzle input) to the other device. Now, the card has the door's public key, and the door has the card's public key. Because you can eavesdrop on the signal, you have both public keys, but neither device's loop size.
The card transforms the subject number of the door's public key according to the card's loop size. The result is the encryption key.
The door transforms the subject number of the card's public key according to the door's loop size. The result is the same encryption key as the card calculated.
If you can use the two public keys to determine each device's loop size, you will have enough information to calculate the secret encryption key that the card and door use to communicate; this would let you send the unlock command directly to the door!
For example, suppose you know that the card's public key is 5764801. With a little trial and error, you can work out that the card's loop size must be 8, because transforming the initial subject number of 7 with a loop size of 8 produces 5764801.
Then, suppose you know that the door's public key is 17807724. By the same process, you can determine that the door's loop size is 11, because transforming the initial subject number of 7 with a loop size of 11 produces 17807724.
At this point, you can use either device's loop size with the other device's public key to calculate the encryption key. Transforming the subject number of 17807724 (the door's public key) with a loop size of 8 (the card's loop size) produces the encryption key, 14897079. (Transforming the subject number of 5764801 (the card's public key) with a loop size of 11 (the door's loop size) produces the same encryption key: 14897079.)
What encryption key is the handshake trying to establish?
Your puzzle answer was 9620012.
The first half of this puzzle is complete! It provides one gold star: *
--- Part Two ---
The light turns green and the door unlocks. As you collapse onto the bed in your room, your pager goes off!
"It's an emergency!" the Elf calling you explains. "The soft serve machine in the cafeteria on sub-basement 7 just failed and you're the only one that knows how to fix it! We've already dispatched a reindeer to your location to pick you up."
You hear the sound of hooves landing on your balcony.
The reindeer carefully explores the contents of your room while you figure out how you're going to pay the 50 stars you owe the resort before you leave. Noticing that you look concerned, the reindeer wanders over to you; you see that it's carrying a small pouch.
"Sorry for the trouble," a note in the pouch reads. Sitting at the bottom of the pouch is a gold coin with a little picture of a starfish on it.
Looks like you only needed 49 stars after all.

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

@@ -0,0 +1,2 @@
5764801
17807724

31
2020/day25/ex1-c.c Normal file
View File

@@ -0,0 +1,31 @@
/* ex1-c: Advent2020, day 25/part 1
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(ac, av)
int ac;
char **av;
{
ulong pub[] = {1, 1}, enc[] = {1, 1}, key[2], res;
scanf("%lu", key);
scanf("%lu", key+1);
while (1) {
pub[0] = pub[0] * 7 % 20201227;
pub[1] = pub[1] * 7 % 20201227;
enc[0] = enc[0] * key[0] %20201227;
enc[1] = enc[1] * key[1] %20201227;
if (pub[0] == key[0]) {
res=enc[1];
break;
} else if (pub[1] == key[1]) {
res=enc[0];
break;
}
}
printf("%s : res=%lu\n", *av, res);
exit (0);
}

22
2020/day25/ex1.bash Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/bash
#
# ex1.bash: Advent2020 game, day 25/game 1.
CMD=${0##*/}
shopt -s extglob
set -o noglob
declare -a pub=(1 1) enc=(1 1) key
read -r "key[0]"
read -r "key[1]"
while true; do
((pub[0] = (pub[0] * 7) % 20201227,
pub[1] = (pub[1] * 7) % 20201227,
enc[0] = (enc[0] * key[0]) % 20201227,
enc[1] = (enc[1] * key[1]) % 20201227))
((pub[0] == key[0])) && res=${enc[1]} && break
((pub[1] == key[1])) && res=${enc[0]} && break
done
printf "%s: res=%s\n" "$CMD" "$res"
exit 0

523
2020/include/bits.h Normal file
View File

@@ -0,0 +1,523 @@
/* bits.h - bits functions.
*
* 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>
*
*/
#ifndef _BITS_H
#define _BITS_H
#include <stdint.h>
#include <stdbool.h>
/* next include will define __WORDSIZE: 32 or 64
*/
#include <bits/wordsize.h>
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
/* no plan to support 32bits for now...
*/
/*
#if __WORDSIZE != 64
#error "Only 64 bits word size supported."
#endif
*/
/* fixed-size types
*/
typedef int64_t s64;
typedef int32_t s32;
typedef int16_t s16;
typedef int8_t s8;
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
/* convenience types
*/
typedef unsigned long int ulong;
typedef unsigned int uint;
typedef unsigned short ushort;
typedef unsigned char uchar;
/* count set bits: 10101000 -> 3
* ^ ^ ^
*/
static __always_inline int popcount64(u64 n)
{
# if __has_builtin(__builtin_popcountl)
# ifdef DEBUG_BITS
log_f(1, "builtin.\n");
# endif
return __builtin_popcountl(n);
# else
# ifdef DEBUG_BITS
log_f(1, "emulated.\n");
# endif
int count = 0;
while (n) {
count++;
n &= (n - 1);
}
return count;
# endif
}
static __always_inline int popcount32(u32 n)
{
# if __has_builtin(__builtin_popcount)
# ifdef DEBUG_BITS
log_f(1, "builtin.\n");
# endif
return __builtin_popcount(n);
# else
# ifdef DEBUG_BITS
log_f(1, "emulated.\n");
# endif
int count = 0;
while (n) {
count++;
n &= (n - 1);
}
return count;
# endif
}
/* char is a special case, as it can be signed or unsigned
*/
typedef signed char schar;
/* count trailing zeroes : 00101000 -> 3
* ^^^
*/
static __always_inline int ctz64(u64 n)
{
# if __has_builtin(__builtin_ctzl)
# ifdef DEBUG_BITS
log_f(1, "builtin ctzl.\n");
# endif
return __builtin_ctzl(n);
# elif __has_builtin(__builtin_clzl)
# ifdef DEBUG_BITS
log_f(1, "builtin clzl.\n");
# endif
return __WORDSIZE - (__builtin_clzl(n & -n) + 1);
# else
# ifdef DEBUG_BITS
log_f(1, "emulated.\n");
# endif
return popcount64((n & -n) - 1);
# endif
}
static __always_inline int ctz32(u32 n)
{
# if __has_builtin(__builtin_ctz)
# ifdef DEBUG_BITS
log_f(1, "builtin ctz.\n");
# endif
return __builtin_ctzl(n);
# elif __has_builtin(__builtin_clz)
# ifdef DEBUG_BITS
log_f(1, "builtin clz.\n");
# endif
return __WORDSIZE - (__builtin_clz(n & -n) + 1);
# else
# ifdef DEBUG_BITS
log_f(1, "emulated.\n");
# endif
return popcount32((n & -n) - 1);
# endif
}
/* clz - count leading zeroes : 00101000 -> 2
* ^^
*/
static __always_inline int clz64(u64 n)
{
# if __has_builtin(__builtin_clzl)
# ifdef DEBUG_BITS
log_f(1, "builtin.\n");
# endif
return __builtin_clzl(n);
# else
# ifdef DEBUG_BITS
log_f(1, "emulated.\n");
# endif
u64 r, q;
r = (n > 0xFFFFFFFF) << 5; n >>= r;
q = (n > 0xFFFF) << 4; n >>= q; r |= q;
q = (n > 0xFF ) << 3; n >>= q; r |= q;
q = (n > 0xF ) << 2; n >>= q; r |= q;
q = (n > 0x3 ) << 1; n >>= q; r |= q;
r |= (n >> 1);
return 64 - r - 1;
# endif
}
static __always_inline int clz32(u32 n)
{
# if __has_builtin(__builtin_clz)
# ifdef DEBUG_BITS
log_f(1, "builtin.\n");
# endif
return __builtin_clz(n);
# else
# ifdef DEBUG_BITS
log_f(1, "emulated.\n");
# endif
u32 r, q;
r = (n > 0xFFFF) << 4; n >>= r;
q = (n > 0xFF ) << 3; n >>= q; r |= q;
q = (n > 0xF ) << 2; n >>= q; r |= q;
q = (n > 0x3 ) << 1; n >>= q; r |= q;
r |= (n >> 1);
return 32 - r - 1;
# endif
}
/* fls - find last set : 00101000 -> 6
* ^
*/
static __always_inline int fls64(u64 n)
{
if (!n)
return 0;
return 64 - clz64(n);
}
static __always_inline int fls32(u32 n)
{
if (!n)
return 0;
return 32 - clz32(n);
}
/* find first set : 00101000 -> 4
* ^
*/
static __always_inline uint ffs64(u64 n)
{
# if __has_builtin(__builtin_ffsl)
# ifdef DEBUG_BITS
log_f(1, "builtin ffsl.\n");
# endif
return __builtin_ffsl(n);
# elif __has_builtin(__builtin_ctzl)
# ifdef DEBUG_BITS
log_f(1, "builtin ctzl.\n");
# endif
if (n == 0)
return (0);
return __builtin_ctzl(n) + 1;
# else
# ifdef DEBUG_BITS
log_f(1, "emulated.\n");
# endif
return popcount64(n ^ ~-n);
# endif
}
static __always_inline uint ffs32(u32 n)
{
# if __has_builtin(__builtin_ffs)
# ifdef DEBUG_BITS
log_f(1, "builtin ffs.\n");
# endif
return __builtin_ffs(n);
# elif __has_builtin(__builtin_ctz)
# ifdef DEBUG_BITS
log_f(1, "builtin ctz.\n");
# endif
if (n == 0)
return (0);
return __builtin_ctz(n) + 1;
# else
# ifdef DEBUG_BITS
log_f(1, "emulated.\n");
# endif
return popcount32(n ^ ~-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
* @tmp: a temp u64/u32 used as temporary storage
* @ul: the u64/u32 to loop over
*
* Usage:
* u64 u=139, _t; // u=b10001011
* int cur;
* bit_for_each64(cur, _t, u) {
* printf("%d\n", cur);
* }
* This will display the position of each bit set in ul: 1, 2, 4, 8
*
* I should probably re-think the implementation...
*/
#define bit_for_each64(pos, tmp, ul) \
for (tmp = ul, pos = ffs64(tmp); tmp; tmp &= (tmp - 1), pos = ffs64(tmp))
#define bit_for_each32(pos, tmp, ul) \
for (tmp = ul, pos = ffs32(tmp); tmp; tmp &= (tmp - 1), pos = ffs32(tmp))
/** or would it be more useful (counting bits from zero instead of 1) ?
*/
#define bit_for_each64_2(pos, tmp, ul) \
for (tmp = ul, pos = ctz64(tmp); tmp; tmp ^= 1UL << pos, pos = ctz64(tmp))
#define bit_for_each32_2(pos, tmp, ul) \
for (tmp = ul, pos = ctz32(tmp); tmp; tmp ^= 1U << pos, pos = ctz32(tmp))
#endif /* _BITS_H */

211
2020/include/br.h Normal file
View File

@@ -0,0 +1,211 @@
/* br.h - misc macros.
*
* 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>
*
* Some parts are taken from Linux's kernel <linux/kernel.h> and others, and are :
* SPDX-License-Identifier: GPL-2.0
*
* This header contains generic stuff.
*/
#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__)
/* see https://lkml.org/lkml/2018/3/20/845 for explanation of this monster
*/
#define __is_constexpr(x) \
(sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))
/*
* min()/max()/clamp() macros must accomplish three things:
*
* - avoid multiple evaluations of the arguments (so side-effects like
* "x++" happen only once) when non-constant.
* - perform strict type-checking (to generate warnings instead of
* nasty runtime surprises). See the "unnecessary" pointer comparison
* in __typecheck().
* - retain result as a constant expressions when called with only
* constant expressions (to avoid tripping VLA warnings in stack
* allocation usage).
*/
#define __typecheck(x, y) \
(!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))
#define __no_side_effects(x, y) \
(__is_constexpr(x) && __is_constexpr(y))
#define __safe_cmp(x, y) \
(__typecheck(x, y) && __no_side_effects(x, y))
#define __cmp(x, y, op) ((x) op (y) ? (x) : (y))
#define __cmp_once(x, y, unique_x, unique_y, op) ({ \
typeof(x) unique_x = (x); \
typeof(y) unique_y = (y); \
__cmp(unique_x, unique_y, op); })
#define __careful_cmp(x, y, op) \
__builtin_choose_expr(__safe_cmp(x, y), \
__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
* @y: second value
*/
#define min(x, y) __careful_cmp(x, y, <)
/**
* max - return maximum of two values of the same or compatible types
* @x: first value
* @y: second value
*/
#define max(x, y) __careful_cmp(x, y, >)
/**
* min3 - return minimum of three values
* @x: first value
* @y: second value
* @z: third value
*/
#define min3(x, y, z) min((typeof(x))min(x, y), z)
/**
* max3 - return maximum of three values
* @x: first value
* @y: second value
* @z: third value
*/
#define max3(x, y, z) max((typeof(x))max(x, y), z)
/**
* min_not_zero - return the minimum that is _not_ zero, unless both are zero
* @x: value1
* @y: value2
*/
#define min_not_zero(x, y) ({ \
typeof(x) __x = (x); \
typeof(y) __y = (y); \
__x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); })
/**
* clamp - return a value clamped to a given range with strict typechecking
* @val: current value
* @lo: lowest allowable value
* @hi: highest allowable value
*
* This macro does strict typechecking of @lo/@hi to make sure they are of the
* same type as @val. See the unnecessary pointer comparisons.
*/
#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi)
/*
* ..and if you can't take the strict
* types, you can specify one yourself.
*
* Or not use min/max/clamp at all, of course.
*/
/**
* min_t - return minimum of two values, using the specified type
* @type: data type to use
* @x: first value
* @y: second value
*/
#define min_t(type, x, y) __careful_cmp((type)(x), (type)(y), <)
/**
* max_t - return maximum of two values, using the specified type
* @type: data type to use
* @x: first value
* @y: second value
*/
#define max_t(type, x, y) __careful_cmp((type)(x), (type)(y), >)
/**
* clamp_t - return a value clamped to a given range using a given type
* @type: the type of variable to use
* @val: current value
* @lo: minimum allowable value
* @hi: maximum allowable value
*
* This macro does no typechecking and uses temporary variables of type
* @type to make all the comparisons.
*/
#define clamp_t(type, val, lo, hi) min_t(type, max_t(type, val, lo), hi)
/**
* clamp_val - return a value clamped to a given range using val's type
* @val: current value
* @lo: minimum allowable value
* @hi: maximum allowable value
*
* This macro does no typechecking and uses temporary variables of whatever
* type the input argument @val is. This is useful when @val is an unsigned
* type and @lo and @hi are literals that will otherwise be assigned a signed
* integer type.
*/
#define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi)
/**
* swap - swap values of @a and @b
* @a: first value
* @b: second value
*/
#define swap(a, b) \
do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
/**
* ARRAY_SIZE - get the number of elements in array @arr
* @arr: array to be sized
*/
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
/**
* abs - return absolute value of an argument
* @x: the value. If it is unsigned type, it is converted to signed type first.
* char is treated as if it was signed (regardless of whether it really is)
* but the macro's return type is preserved as char.
*
* Return: an absolute value of x.
*/
#define abs(x) __abs_choose_expr(x, long long, \
__abs_choose_expr(x, long, \
__abs_choose_expr(x, int, \
__abs_choose_expr(x, short, \
__abs_choose_expr(x, char, \
__builtin_choose_expr( \
__builtin_types_compatible_p(typeof(x), char), \
(char)({ signed char __x = (x); __x<0?-__x:__x; }), \
((void)0)))))))
#define __abs_choose_expr(x, type, other) __builtin_choose_expr( \
__builtin_types_compatible_p(typeof(x), signed type) || \
__builtin_types_compatible_p(typeof(x), unsigned type), \
({ signed type __x = (x); __x < 0 ? -__x : __x; }), other)
#endif /* _BR_H */

71
2020/include/bug.h Normal file
View File

@@ -0,0 +1,71 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _BR_BUG_H
#define _BR_BUG_H
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "likely.h"
#include "debug.h"
/* BUG functions inspired by Linux kernel's <asm/bug.h>
*/
#define panic() exit(0xff)
/*
* Don't use BUG() or BUG_ON() unless there's really no way out; one
* example might be detecting data structure corruption in the middle
* of an operation that can't be backed out of. If the (sub)system
* can somehow continue operating, perhaps with reduced functionality,
* it's probably not BUG-worthy.
*
* If you're tempted to BUG(), think again: is completely giving up
* really the *only* solution? There are usually better options, where
* users don't need to reboot ASAP and can mostly shut down cleanly.
*/
#define BUG() do { \
fprintf(stderr, "BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
panic(); \
} while (0)
#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0)
/*
* WARN(), WARN_ON(), WARN_ON_ONCE, and so on can be used to report
* significant kernel issues that need prompt attention if they should ever
* appear at runtime.
*
* Do not use these macros when checking for invalid external inputs
* (e.g. invalid system call arguments, or invalid data coming from
* network/devices), and on transient conditions like ENOMEM or EAGAIN.
* These macros should be used for recoverable kernel issues only.
* For invalid external inputs, transient conditions, etc use
* pr_err[_once/_ratelimited]() followed by dump_stack(), if necessary.
* Do not include "BUG"/"WARNING" in format strings manually to make these
* conditions distinguishable from kernel issues.
*
* Use the versions with printk format strings to provide better diagnostics.
*/
#define __WARN() do { \
fprintf(stderr, "WARNING: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
} while (0)
#define __WARN_printf(arg...) do { \
vfprintf(stderr, arg); \
} while (0)
#define WARN_ON(condition) ({ \
int __ret_warn_on = !!(condition); \
if (unlikely(__ret_warn_on)) \
__WARN(); \
unlikely(__ret_warn_on); \
})
#define WARN(condition, format...) ({ \
int __ret_warn_on = !!(condition); \
if (unlikely(__ret_warn_on)) \
__WARN_printf(format); \
unlikely(__ret_warn_on); \
})
#endif /* _BR_BUG_H */

View File

@@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* adaptation of Linux kernel's <linux/container_of.h>
*/
#ifndef _BR_CONTAINER_OF_H
#define _BR_CONTAINER_OF_H
/* Are two types/vars the same type (ignoring qualifiers)? */
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
/**
* typeof_member -
*/
#define typeof_member(T, m) typeof(((T*)0)->m)
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
void *__mptr = (void *)(ptr); \
_Static_assert(__same_type(*(ptr), ((type *)0)->member) || \
__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })
#endif /* BR_CONTAINER_OF_H */

98
2020/include/debug.h Normal file
View File

@@ -0,0 +1,98 @@
/* debug.h - debug/log management.
*
* 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>
*
*/
#ifndef DEBUG_H
#define DEBUG_H
#include <stdbool.h>
#include <stdint.h>
#include "bits.h"
#define _unused __attribute__((__unused__))
#define _printf __attribute__ ((format (printf, 6, 7)))
#ifdef DEBUG_DEBUG
void debug_init(u32 level);
void debug_level_set(u32 level);
void _printf debug(u32 level, bool timestamp,
u32 indent, const char *src,
u32 line, const char *, ...);
#else /* DEBUG_DEBUG */
static inline void debug_init(_unused u32 level) {}
static inline void debug_level_set(_unused u32 level) {}
static inline void _printf debug(_unused u32 level, _unused bool timestamp,
_unused u32 indent, _unused const char *src,
_unused u32 line, const char *, ...) {}
#endif /* DEBUG_DEBUG */
#undef _unused
#undef _printf
/**
* log - simple log (no function name, no indent, no timestamp)
* @level: log level
* @fmt: printf format string
* @args: subsequent arguments to printf
*/
#define log(level, fmt, args...) \
debug((level), false, 0, NULL, 0, fmt, ##args)
/**
* log_i - log with indent (no function name, no timestamp)
* @level: log level
* @fmt: printf format string
* @args: subsequent arguments to printf
*
* Output example:
* >>>>val=2
*/
#define log_i(level, fmt, args...) \
debug((level), false, (level), NULL, 0, fmt, ##args)
/**
* log_f - log with function name (no indent name, no timestamp)
* @level: log level
* @fmt: printf format string
* @args: subsequent arguments to printf
*
* Output example:
* [function] val=2
*/
#define log_f(level, fmt, args...) \
debug((level), false, 0, __func__, 0, fmt, ##args)
/**
* log_if - log with function name and line number (no indent name, no timestamp)
* @level: log level
* @fmt: printf format string
* @args: subsequent arguments to printf
*
* Output example:
* >>>> [function:15] val=2
*/
#define log_if(level, fmt, args...) \
debug((level), false, (level), __func__, __LINE__, fmt, ##args)
/**
* log_it - log with function name, line number, indent, and timestamp
* @level: log level
* @fmt: printf format string
* @args: subsequent arguments to printf
*
* Output example:
* >>>> [function:15] val=2
*/
#define log_it(level, fmt, args...) \
debug((level), true, (level), __func__, __LINE__, fmt, ##args)
#endif /* DEBUG_H */

173
2020/include/hash.h Normal file
View File

@@ -0,0 +1,173 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _BR_HASH_H
#define _BR_HASH_H
/* adaptation of Linux kernel's <linux/hash.h> and <linux/stringhash.h>
*/
/* Fast hashing routine for ints, longs and pointers.
(C) 2002 Nadia Yvette Chambers, IBM */
//#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
* were actively bad for hashing), but the name remains.
*/
#if __BITS_PER_LONG == 32
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_32
#define hash_long(val, bits) hash_32(val, bits)
#elif __BITS_PER_LONG == 64
#define hash_long(val, bits) hash_64(val, bits)
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_64
#else
#error Wordsize not 32 or 64
#endif
/*
* This hash multiplies the input by a large odd number and takes the
* high bits. Since multiplication propagates changes to the most
* significant end only, it is essential that the high bits of the
* product be used for the hash value.
*
* Chuck Lever verified the effectiveness of this technique:
* http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf
*
* Although a random odd number will do, it turns out that the golden
* ratio phi = (sqrt(5)-1)/2, or its negative, has particularly nice
* properties. (See Knuth vol 3, section 6.4, exercise 9.)
*
* These are the negative, (1 - phi) = phi**2 = (3 - sqrt(5))/2,
* which is very slightly easier to multiply by and makes no
* difference to the hash distribution.
*/
#define GOLDEN_RATIO_32 0x61C88647
#define GOLDEN_RATIO_64 0x61C8864680B583EBull
/*
* The _generic versions exist only so lib/test_hash.c can compare
* the arch-optimized versions with the generic.
*
* Note that if you change these, any <asm/hash.h> that aren't updated
* to match need to have their HAVE_ARCH_* define values updated so the
* self-test will not false-positive.
*/
#ifndef HAVE_ARCH__HASH_32
#define __hash_32 __hash_32_generic
#endif
static inline u32 __hash_32_generic(u32 val)
{
return val * GOLDEN_RATIO_32;
}
static inline u32 hash_32(u32 val, unsigned int bits)
{
/* High bits are more random, so use them. */
return __hash_32(val) >> (32 - bits);
}
#ifndef HAVE_ARCH_HASH_64
#define hash_64 hash_64_generic
#endif
static __always_inline u32 hash_64_generic(u64 val, unsigned int bits)
{
#if __BITS_PER_LONG == 64
/* 64x64-bit multiply is efficient on all 64-bit processors */
return val * GOLDEN_RATIO_64 >> (64 - bits);
#else
/* Hash 64 bits using only 32x32-bit multiply. */
return hash_32((u32)val ^ __hash_32(val >> 32), bits);
#endif
}
static inline u32 hash_ptr(const void *ptr, unsigned int bits)
{
return hash_long((unsigned long)ptr, bits);
}
/* This really should be called fold32_ptr; it does no hashing to speak of. */
static inline u32 hash32_ptr(const void *ptr)
{
unsigned long val = (unsigned long)ptr;
#if __BITS_PER_LONG == 64
val ^= (val >> 32);
#endif
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 */

203
2020/include/hashtable.h Normal file
View File

@@ -0,0 +1,203 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* adaptation of Linux kernel's <linux/hashtable.h>
*/
/*
* Statically sized hash table implementation
* (C) 2012 Sasha Levin <levinsasha928@gmail.com>
*/
#ifndef _LINUX_HASHTABLE_H
#define _LINUX_HASHTABLE_H
#include "list.h"
#include <linux/kernel.h>
#include "hash.h"
//#include <linux/rculist.h>
#define DEFINE_HASHTABLE(name, bits) \
struct hlist_head name[1 << (bits)] = \
{ [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
#define DEFINE_READ_MOSTLY_HASHTABLE(name, bits) \
struct hlist_head name[1 << (bits)] __read_mostly = \
{ [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
#define DECLARE_HASHTABLE(name, bits) \
struct hlist_head name[1 << (bits)]
#define HASH_SIZE(name) (ARRAY_SIZE(name))
#define HASH_BITS(name) ilog2(HASH_SIZE(name))
/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */
#define hash_min(val, bits) \
(sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits))
static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
{
unsigned int i;
for (i = 0; i < sz; i++)
INIT_HLIST_HEAD(&ht[i]);
}
/**
* hash_init - initialize a hash table
* @hashtable: hashtable to be initialized
*
* Calculates the size of the hashtable from the given parameter, otherwise
* same as hash_init_size.
*
* This has to be a macro since HASH_BITS() will not work on pointers since
* it calculates the size during preprocessing.
*/
#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable))
/**
* hash_add - add an object to a hashtable
* @hashtable: hashtable to add to
* @node: the &struct hlist_node of the object to be added
* @key: the key of the object to be added
*/
#define hash_add(hashtable, node, key) \
hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
/**
* hash_add_rcu - add an object to a rcu enabled hashtable
* @hashtable: hashtable to add to
* @node: the &struct hlist_node of the object to be added
* @key: the key of the object to be added
*/
#define hash_add_rcu(hashtable, node, key) \
hlist_add_head_rcu(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
/**
* hash_hashed - check whether an object is in any hashtable
* @node: the &struct hlist_node of the object to be checked
*/
static inline bool hash_hashed(struct hlist_node *node)
{
return !hlist_unhashed(node);
}
static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz)
{
unsigned int i;
for (i = 0; i < sz; i++)
if (!hlist_empty(&ht[i]))
return false;
return true;
}
/**
* hash_empty - check whether a hashtable is empty
* @hashtable: hashtable to check
*
* This has to be a macro since HASH_BITS() will not work on pointers since
* it calculates the size during preprocessing.
*/
#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable))
/**
* hash_del - remove an object from a hashtable
* @node: &struct hlist_node of the object to remove
*/
static inline void hash_del(struct hlist_node *node)
{
hlist_del_init(node);
}
/**
* hash_for_each - iterate over a hashtable
* @name: hashtable to iterate
* @bkt: integer to use as bucket loop cursor
* @obj: the type * to use as a loop cursor for each entry
* @member: the name of the hlist_node within the struct
*/
#define hash_for_each(name, bkt, obj, member) \
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
(bkt)++)\
hlist_for_each_entry(obj, &name[bkt], member)
/**
* hash_for_each_rcu - iterate over a rcu enabled hashtable
* @name: hashtable to iterate
* @bkt: integer to use as bucket loop cursor
* @obj: the type * to use as a loop cursor for each entry
* @member: the name of the hlist_node within the struct
*/
#define hash_for_each_rcu(name, bkt, obj, member) \
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
(bkt)++)\
hlist_for_each_entry_rcu(obj, &name[bkt], member)
/**
* hash_for_each_safe - iterate over a hashtable safe against removal of
* hash entry
* @name: hashtable to iterate
* @bkt: integer to use as bucket loop cursor
* @tmp: a &struct hlist_node used for temporary storage
* @obj: the type * to use as a loop cursor for each entry
* @member: the name of the hlist_node within the struct
*/
#define hash_for_each_safe(name, bkt, tmp, obj, member) \
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
(bkt)++)\
hlist_for_each_entry_safe(obj, tmp, &name[bkt], member)
/**
* hash_for_each_possible - iterate over all possible objects hashing to the
* same bucket
* @name: hashtable to iterate
* @obj: the type * to use as a loop cursor for each entry
* @member: the name of the hlist_node within the struct
* @key: the key of the objects to iterate over
*/
#define hash_for_each_possible(name, obj, member, key) \
hlist_for_each_entry(obj, &name[hash_min(key, HASH_BITS(name))], member)
/**
* hash_for_each_possible_rcu - iterate over all possible objects hashing to the
* same bucket in an rcu enabled hashtable
* @name: hashtable to iterate
* @obj: the type * to use as a loop cursor for each entry
* @member: the name of the hlist_node within the struct
* @key: the key of the objects to iterate over
*/
#define hash_for_each_possible_rcu(name, obj, member, key, cond...) \
hlist_for_each_entry_rcu(obj, &name[hash_min(key, HASH_BITS(name))],\
member, ## cond)
/**
* hash_for_each_possible_rcu_notrace - iterate over all possible objects hashing
* to the same bucket in an rcu enabled hashtable in a rcu enabled hashtable
* @name: hashtable to iterate
* @obj: the type * to use as a loop cursor for each entry
* @member: the name of the hlist_node within the struct
* @key: the key of the objects to iterate over
*
* This is the same as hash_for_each_possible_rcu() except that it does
* not do any RCU debugging or tracing.
*/
#define hash_for_each_possible_rcu_notrace(name, obj, member, key) \
hlist_for_each_entry_rcu_notrace(obj, \
&name[hash_min(key, HASH_BITS(name))], member)
/**
* hash_for_each_possible_safe - iterate over all possible objects hashing to the
* same bucket safe against removals
* @name: hashtable to iterate
* @obj: the type * to use as a loop cursor for each entry
* @tmp: a &struct hlist_node used for temporary storage
* @member: the name of the hlist_node within the struct
* @key: the key of the objects to iterate over
*/
#define hash_for_each_possible_safe(name, obj, tmp, member, key) \
hlist_for_each_entry_safe(obj, tmp,\
&name[hash_min(key, HASH_BITS(name))], member)
#endif

18
2020/include/likely.h Normal file
View File

@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* taken from Kernel's <linux/compiler.h
*/
#ifndef __LIKELY_H
#define __LIKELY_H
/* See https://kernelnewbies.org/FAQ/LikelyUnlikely
*
* In 2 words:
* "You should use it [likely() and unlikely()] only in cases when the likeliest
* branch is very very very likely, or when the unlikeliest branch is very very
* very unlikely."
*/
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
#endif /* __LIKELY_H */

1015
2020/include/list.h Normal file

File diff suppressed because it is too large Load Diff

90
2020/include/pool.h Normal file
View File

@@ -0,0 +1,90 @@
/* pool.h - A simple memory pool manager.
*
* Copyright (C) 2021 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>
*
*/
#ifndef POOL_H
#define POOL_H
#include <stdint.h>
#include <stddef.h>
#include "list.h"
#include "bits.h"
#define POOL_NAME_LENGTH (16) /* max name length including trailing \0 */
typedef struct {
struct list_head list_blocks; /* list of allocated blocks in pool */
char data[]; /* objects block */
} block_t;
typedef struct {
char name[POOL_NAME_LENGTH]; /* pool name */
size_t eltsize; /* object size */
u32 available; /* current available elements */
u32 allocated; /* total objects allocated */
u32 growsize; /* number of objects per block allocated */
u32 nblocks; /* number of blocks allocated */
struct list_head list_available; /* available nodes */
struct list_head list_blocks; /* allocated blocks */
} pool_t;
/**
* pool_stats - display some pool statistics
* @pool: the pool address.
*/
void pool_stats(pool_t *pool);
/**
* pool_create - create a new memory pool
* @name: the name to give to the pool.
* @grow: the number of elements to add when no more available.
* @size: the size of an element in pool.
*
* The name will be truncated to 16 characters (including the final '\0').
*
* Return: The address of the created pool, or NULL if error.
*/
pool_t *pool_create(const char *name, u32 grow, size_t size);
/**
* pool_get() - Get an element from a pool.
* @pool: The pool address.
*
* Get an object from the pool.
*
* Return: The address of the object, or NULL if error.
*/
void *pool_get(pool_t *pool);
/**
* pool_add() - Add (free) an element to a pool.
* @pool: The pool address.
* @elt: The address of the object to add to the pool.
*
* The object will be available for further pool_get().
*
* Return: The current number of available elements in pool (including
* @elt).
*/
u32 pool_add(pool_t *pool, void *elt);
/**
* pool_destroy() - destroy a pool.
* @pool: The pool address.
*
* Attention: All memory is freed, but no check is done whether all pool
* elements have been released. Referencing any pool object after this call
* will likely imply some memory corruption.
*/
void pool_destroy(pool_t *pool);
#endif

128
2020/include/rwonce.h Normal file
View File

@@ -0,0 +1,128 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* adaptation of kernel's <asm-generic/rwonce.h>
* See https://www.kernel.org/doc/Documentation/memory-barriers.txt
*/
/*
* Prevent the compiler from merging or refetching reads or writes. The
* compiler is also forbidden from reordering successive instances of
* READ_ONCE and WRITE_ONCE, but only when the compiler is aware of some
* particular ordering. One way to make the compiler aware of ordering is to
* put the two invocations of READ_ONCE or WRITE_ONCE in different C
* statements.
*
* These two macros will also work on aggregate data types like structs or
* unions.
*
* Their two major use cases are: (1) Mediating communication between
* process-level code and irq/NMI handlers, all running on the same CPU,
* and (2) Ensuring that the compiler does not fold, spindle, or otherwise
* mutilate accesses that either do not require ordering or that interact
* with an explicit memory barrier or atomic instruction that provides the
* required ordering.
*/
#ifndef __BR_RWONCE_H
#define __BR_RWONCE_H
/************ originally in <include/linux/compiler_attributes.h> */
#if __has_attribute(__error__)
# define __compiletime_error(msg) __attribute__((__error__(msg)))
#else
# define __compiletime_error(msg)
#endif
/************ originally in <include/linux/compiler_types.h> */
/*
* __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving
* non-scalar types unchanged.
*/
/*
* Prefer C11 _Generic for better compile-times and simpler code. Note: 'char'
* is not type-compatible with 'signed char', and we define a separate case.
*/
#define __scalar_type_to_expr_cases(type) \
unsigned type: (unsigned type)0, \
signed type: (signed type)0
#define __unqual_scalar_typeof(x) \
typeof(_Generic((x), \
char: (char)0, \
__scalar_type_to_expr_cases(char), \
__scalar_type_to_expr_cases(short), \
__scalar_type_to_expr_cases(int), \
__scalar_type_to_expr_cases(long), \
__scalar_type_to_expr_cases(long long), \
default: (x)))
/* Is this type a native word size -- useful for atomic operations */
#define __native_word(t) \
(sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || \
sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))
#ifdef __OPTIMIZE__
# define __compiletime_assert(condition, msg, prefix, suffix) \
do { \
extern void prefix ## suffix(void) __compiletime_error(msg); \
if (!(condition)) \
prefix ## suffix(); \
} while (0)
#else
# define __compiletime_assert(condition, msg, prefix, suffix) do { } while (0)
#endif
#define _compiletime_assert(condition, msg, prefix, suffix) \
__compiletime_assert(condition, msg, prefix, suffix)
/**
* compiletime_assert - break build and emit msg if condition is false
* @condition: a compile-time constant condition to check
* @msg: a message to emit if condition is false
*
* In tradition of POSIX assert, this macro will break the build if the
* supplied condition is *false*, emitting the supplied error message if the
* compiler has support to do so.
*/
#define compiletime_assert(condition, msg) \
_compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
#define compiletime_assert_atomic_type(t) \
compiletime_assert(__native_word(t), \
"Need native word sized stores/loads for atomicity.")
/************ originally in <asm-generic/rwonce.h> */
/*
* Yes, this permits 64-bit accesses on 32-bit architectures. These will
* actually be atomic in some cases (namely Armv7 + LPAE), but for others we
* rely on the access being split into 2x32-bit accesses for a 32-bit quantity
* (e.g. a virtual address) and a strong prevailing wind.
*/
#define compiletime_assert_rwonce_type(t) \
compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
"Unsupported access size for {READ,WRITE}_ONCE().")
/*
* Use __READ_ONCE() instead of READ_ONCE() if you do not require any
* atomicity. Note that this may result in tears!
*/
#ifndef __READ_ONCE
#define __READ_ONCE(x) (*(const volatile __unqual_scalar_typeof(x) *)&(x))
#endif
#define READ_ONCE(x) \
({ \
compiletime_assert_rwonce_type(x); \
__READ_ONCE(x); \
})
#define __WRITE_ONCE(x, val) \
do { \
*(volatile typeof(x) *)&(x) = (val); \
} while (0)
#define WRITE_ONCE(x, val) \
do { \
compiletime_assert_rwonce_type(x); \
__WRITE_ONCE(x, val); \
} while (0)
#endif /* __BR_RWONCE_H */

112
2020/libsrc/debug.c Normal file
View File

@@ -0,0 +1,112 @@
/* debug.c - debug/log management
*
* 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>
*
*/
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#ifndef DEBUG_DEBUG
#define DEBUG_DEBUG
#endif
#include "bits.h"
#include "debug.h"
#define NS_SEC 1000000000 /* nano sec in sec */
#define MS_SEC 1000000 /* microsec in sec */
#define NS_MS 1000 /* nano in micro */
static long long timer_start; /* in nanosecond */
static u32 debug_level=0;
void debug_level_set(u32 level)
{
debug_level = level;
log(1, "debug level set to %u\n", level);
}
void debug_init(u32 level)
{
struct timespec timer;
debug_level_set(level);
if (!clock_gettime(CLOCK_MONOTONIC, &timer)) {
timer_start = timer.tv_sec * NS_SEC + timer.tv_nsec;
}
else {
timer_start = 0;
}
log(0, "timer started.\n");
}
inline static long long timer_elapsed()
{
struct timespec timer;
clock_gettime(CLOCK_MONOTONIC, &timer);
return (timer.tv_sec * NS_SEC + timer.tv_nsec) - timer_start;
}
/* void debug - log function
* @timestamp : boolean
* @indent : indent level (2 spaces each)
* @src : source file/func name (or NULL)
* @line : line number
*/
void debug(u32 level, bool timestamp, u32 indent, const char *src,
u32 line, const char *fmt, ...)
{
if (level > debug_level)
return;
va_list ap;
if (indent)
printf("%*s", 2*(indent-1), "");
if (timestamp) {
long long diff = timer_elapsed();
printf("%lld.%03lld ", diff / NS_SEC, (diff % NS_SEC) / NS_MS);
printf("%010lldμs ", diff / NS_MS);
}
if (src) {
if (line)
printf("[%s:%u] ", src, line);
else
printf("[%s] ", src);
}
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
#ifdef BIN_debug
#include <unistd.h>
int main()
{
int foo=1;
debug_init(5);
log(0, "log0=%d\n", foo++);
log(1, "log1=%d\n", foo++);
log(2, "log2=%d\n", foo++);
log_i(2, "log_i 2=%d\n", foo++);
log_i(5, "log_i 5=%d\n", foo++);
log_i(6, "log_i 6=%d\n", foo++);
log_it(4, "log_it 4=%d\n", foo++);
log_f(1, "log_f 5=%d\n", foo++);
}
#endif

219
2020/libsrc/pool.c Normal file
View File

@@ -0,0 +1,219 @@
/* pool.c - A simple pool manager.
*
* 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>
*
*/
#include <stddef.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "list.h"
#include "pool.h"
#include "debug.h"
#include "bits.h"
void pool_stats(pool_t *pool)
{
if (pool) {
block_t *block;
log_f(1, "[%s] pool [%p]: blocks:%u avail:%u alloc:%u grow:%u eltsize:%zu\n",
pool->name, (void *)pool, pool->nblocks, pool->available,
pool->allocated, pool->growsize, pool->eltsize);
log(5, "\tblocks: ");
list_for_each_entry(block, &pool->list_blocks, list_blocks) {
log(5, "%p ", block);
}
log(5, "\n");
}
}
pool_t *pool_create(const char *name, u32 growsize, size_t eltsize)
{
pool_t *pool;
# ifdef DEBUG_POOL
log_f(1, "name=[%s] growsize=%u eltsize=%zu\n", name, growsize, eltsize);
# endif
/* we need at least sizeof(struct list_head) space in pool elements
*/
if (eltsize < sizeof (struct list_head)) {
# ifdef DEBUG_POOL
log_f(1, "[%s]: structure size too small (%zu < %zu), adjusting to %zu.\n",
name, eltsize, sizeof(struct list_head), sizeof(struct list_head));
# endif
eltsize = sizeof(struct list_head);
}
if ((pool = malloc(sizeof (*pool)))) {
strncpy(pool->name, name, POOL_NAME_LENGTH - 1);
pool->name[POOL_NAME_LENGTH - 1] = 0;
pool->growsize = growsize;
pool->eltsize = eltsize;
pool->available = 0;
pool->allocated = 0;
pool->nblocks = 0;
INIT_LIST_HEAD(&pool->list_available);
INIT_LIST_HEAD(&pool->list_blocks);
} else {
errno = ENOMEM;
}
return pool;
}
static u32 _pool_add(pool_t *pool, struct list_head *elt)
{
# ifdef DEBUG_POOL
log_f(6, "pool=%p &head=%p elt=%p off1=%zu off2=%zu\n",
(void *)pool, (void *)&pool->list_available, (void *)elt,
(void *)&pool->list_available - (void *)pool,
offsetof(pool_t, list_available));
# endif
list_add(elt, &pool->list_available);
return ++pool->available;
}
u32 pool_add(pool_t *pool, void *elt)
{
return _pool_add(pool, elt);
}
static struct list_head *_pool_get(pool_t *pool)
{
struct list_head *res = pool->list_available.next;
pool->available--;
list_del(res);
return res;
}
void *pool_get(pool_t *pool)
{
if (!pool)
return NULL;
if (!pool->available) {
block_t *block = malloc(sizeof(block_t) + pool->eltsize * pool->growsize);
if (!block) {
# ifdef DEBUG_POOL
log_f(1, "[%s]: failed block allocation\n", pool->name);
# endif
errno = ENOMEM;
return NULL;
}
/* maintain list of allocated blocks
*/
list_add(&block->list_blocks, &pool->list_blocks);
pool->nblocks++;
# ifdef DEBUG_POOL
log_f(1, "[%s]: growing pool from %u to %u elements. block=%p nblocks=%u\n",
pool->name,
pool->allocated,
pool->allocated + pool->growsize,
block,
pool->nblocks);
# endif
pool->allocated += pool->growsize;
for (u32 i = 0; i < pool->growsize; ++i) {
void *cur = block->data + i * pool->eltsize;
# ifdef DEBUG_POOL
log_f(7, "alloc=%p cur=%p\n", block, cur);
# endif
_pool_add(pool, (struct list_head *)cur);
}
}
/* this is the effective address of the object (and also the
* pool list_head address)
*/
return _pool_get(pool);
}
void pool_destroy(pool_t *pool)
{
block_t *block, *tmp;
if (!pool)
return;
/* release memory blocks */
# ifdef DEBUG_POOL
log_f(1, "[%s]: releasing %d blocks and main structure\n", pool->name, pool->nblocks);
log(5, "blocks:");
# endif
list_for_each_entry_safe(block, tmp, &pool->list_blocks, list_blocks) {
# ifdef DEBUG_POOL
log(5, " %p", block);
# endif
list_del(&block->list_blocks);
free(block);
}
# ifdef DEBUG_POOL
log(5, "\n");
# endif
free(pool);
}
#ifdef BIN_pool
struct d {
u16 data1;
char c;
struct list_head list;
};
static LIST_HEAD (head);
int main(int ac, char**av)
{
pool_t *pool;
int total;
int action=0;
u16 icur=0;
char ccur='z';
struct d *elt;
debug_init(3);
log_f(1, "%s: sizeof(d)=%lu sizeof(*d)=%lu off=%lu\n", *av, sizeof(elt),
sizeof(*elt), offsetof(struct d, list));
if ((pool = pool_create("dummy", 3, sizeof(*elt)))) {
pool_stats(pool);
for (int cur=1; cur<ac; ++cur) {
total = atoi(av[cur]);
if (action == 0) { /* add elt to list */
log_f(2, "adding %d elements\n", total);
for (int i = 0; i < total; ++i) {
elt = pool_get(pool);
elt->data1 = icur++;
elt->c = ccur--;
list_add(&elt->list, &head);
}
pool_stats(pool);
action = 1;
} else { /* remove one elt from list */
log_f(2, "deleting %d elements\n", total);
for (int i = 0; i < total; ++i) {
if (!list_empty(&head)) {
elt = list_last_entry(&head, struct d, list);
printf("elt=[%d, %c]\n", elt->data1, elt->c);
list_del(&elt->list);
pool_add(pool, elt);
}
}
pool_stats(pool);
action = 0;
}
}
}
pool_stats(pool);
pool_destroy(pool);
}
#endif

87
2022/Makefile Normal file
View File

@@ -0,0 +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??)
CC = gcc
#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) --no-print-directory -C $$dir clean ; \
done
cleanlib: clean
@$(RM) -f $(SLIB) $(DLIB) $(LIBOBJ)
cleanall: clean cleanlib
redo: cleanall all
$(SUBDIRS):
@echo "========================================="
@echo "================= $@ ================="
@echo "========================================="
@echo
@echo "+++++++++++++++++ part 1"
+@$(MAKE) --no-print-directory -C $@ part1 2>&1
@echo "+++++++++++++++++ part 2"
+@$(MAKE) --no-print-directory -C $@ part2 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 $@ $<

317
2022/RESULTS.txt Normal file
View File

@@ -0,0 +1,317 @@
=========================================
================= day01 =================
=========================================
+++++++++++++++++ part 1
aoc.bash: res=66719
time: 0:00.03 real, 0.02 user, 0.00 sys
context-switch: 0+1, page-faults: 0+257
aoc-c: res=66719
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+88
+++++++++++++++++ part 2
aoc.bash: res=198551
time: 0:00.03 real, 0.03 user, 0.00 sys
context-switch: 2+1, page-faults: 0+259
aoc-c: res=198551
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+87
=========================================
================= day02 =================
=========================================
+++++++++++++++++ part 1
aoc.bash: res=11841
time: 0:00.05 real, 0.05 user, 0.00 sys
context-switch: 7+1, page-faults: 0+273
aoc-c: res=11841
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+87
+++++++++++++++++ part 2
aoc.bash: res=13022
time: 0:00.05 real, 0.03 user, 0.01 sys
context-switch: 9+1, page-faults: 0+272
aoc-c: res=13022
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+87
=========================================
================= day03 =================
=========================================
+++++++++++++++++ part 1
aoc.bash: res=7878
time: 0:00.02 real, 0.01 user, 0.00 sys
context-switch: 2+1, page-faults: 0+301
aoc-c: res=7878
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+87
+++++++++++++++++ part 2
aoc.bash: res=2760
time: 0:00.01 real, 0.01 user, 0.00 sys
context-switch: 1+1, page-faults: 0+282
aoc-c: res=2760
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+88
=========================================
================= day04 =================
=========================================
+++++++++++++++++ part 1
aoc.bash: res=444
time: 0:00.02 real, 0.01 user, 0.00 sys
context-switch: 0+1, page-faults: 0+258
aoc-c: res=444
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+87
+++++++++++++++++ part 2
aoc.bash: res=801
time: 0:00.02 real, 0.01 user, 0.00 sys
context-switch: 1+1, page-faults: 0+261
aoc-c: res=801
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+87
=========================================
================= day05 =================
=========================================
+++++++++++++++++ part 1
aoc.bash: res=VQZNJMWTR
time: 0:00.08 real, 0.06 user, 0.01 sys
context-switch: 3+1, page-faults: 0+274
aoc-c: res=VQZNJMWTR
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+87
+++++++++++++++++ part 2
aoc.bash: res=NLCDCLVMQ
time: 0:00.04 real, 0.02 user, 0.01 sys
context-switch: 20+1, page-faults: 0+274
aoc-c: res=NLCDCLVMQ
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+86
=========================================
================= day06 =================
=========================================
+++++++++++++++++ part 1
aoc.bash: res=1658
time: 0:00.06 real, 0.06 user, 0.00 sys
context-switch: 1+1, page-faults: 0+266
aoc-c: res=1658
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+87
+++++++++++++++++ part 2
aoc.bash: res=2260
time: 0:00.09 real, 0.09 user, 0.00 sys
context-switch: 1+1, page-faults: 0+265
aoc-c: res=2260
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+87
=========================================
================= day07 =================
=========================================
+++++++++++++++++ part 1
aoc.bash: res=1390824
time: 0:00.05 real, 0.03 user, 0.01 sys
context-switch: 7+1, page-faults: 0+307
aoc-c: res=1390824
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+98
+++++++++++++++++ part 2
aoc.bash: res=7490863
time: 0:00.05 real, 0.05 user, 0.00 sys
context-switch: 9+1, page-faults: 0+308
aoc-c: res=7490863
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+98
=========================================
================= day08 =================
=========================================
+++++++++++++++++ part 1
aoc.bash: res=1698
time: 0:01.10 real, 1.10 user, 0.00 sys
context-switch: 5+1, page-faults: 0+319
aoc-c: res=1698
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+92
+++++++++++++++++ part 2
aoc.bash: res=672280
time: 0:03.54 real, 3.53 user, 0.00 sys
context-switch: 48+1, page-faults: 0+284
aoc-c: res=672280
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+91
=========================================
================= day09 =================
=========================================
+++++++++++++++++ part 1
aoc.bash: res=5619
time: 0:00.69 real, 0.69 user, 0.00 sys
context-switch: 38+1, page-faults: 0+430
aoc-c: res=5619
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+158
+++++++++++++++++ part 2
aoc.bash: res=2376
time: 0:03.25 real, 3.24 user, 0.00 sys
context-switch: 46+1, page-faults: 0+340
aoc-c: res=2376
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+131
=========================================
================= day10 =================
=========================================
+++++++++++++++++ part 1
aoc.bash: res=13220
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+260
aoc-c: res=13220
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+88
+++++++++++++++++ part 2
aoc.bash: res=
###..#..#..##..#..#.#..#.###..####.#..##
#..#.#..#.#..#.#.#..#..#.#..#.#....#.#..
#..#.#..#.#..#.##...####.###..###..##..#
###..#..#.####.#.#..#..#.#..#.#....#.#.#
#.#..#..#.#..#.#.#..#..#.#..#.#....#.#..
#..#..##..#..#.#..#.#..#.###..####.#..#.
time: 0:00.01 real, 0.00 user, 0.00 sys
context-switch: 3+1, page-faults: 0+262
###..#..#..##..#..#.#..#.###..####.#..##
#..#.#..#.#..#.#.#..#..#.#..#.#....#.#..
#..#.#..#.#..#.##...####.###..###..##..#
###..#..#.####.#.#..#..#.#..#.#....#.#.#
#.#..#..#.#..#.#.#..#..#.#..#.#....#.#..
#..#..##..#..#.#..#.#..#.###..####.#..#.
aoc-c: res=0
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+88
=========================================
================= day11 =================
=========================================
+++++++++++++++++ part 1
aoc.bash: res=54253
time: 0:00.05 real, 0.04 user, 0.00 sys
context-switch: 1+1, page-faults: 0+268
aoc-c: res=54253
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+87
+++++++++++++++++ part 2
aoc.bash: res=13119526120
time: 0:16.49 real, 16.48 user, 0.00 sys
context-switch: 106+1, page-faults: 0+270
aoc-c: res=13119526120
time: 0:00.01 real, 0.01 user, 0.00 sys
context-switch: 13+1, page-faults: 0+87
=========================================
================= day12 =================
=========================================
+++++++++++++++++ part 1
aoc.bash: res=408
time: 0:00.81 real, 0.80 user, 0.00 sys
context-switch: 223+1, page-faults: 0+486
aoc-c: res=408
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+170
+++++++++++++++++ part 2
aoc.bash: res=399
time: 0:00.55 real, 0.54 user, 0.01 sys
context-switch: 25+1, page-faults: 0+460
aoc-c: res=399
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+171
=========================================
================= day13 =================
=========================================
+++++++++++++++++ part 1
aoc-c: res=5843
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+192
+++++++++++++++++ part 2
aoc-c: res=26289
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 1+1, page-faults: 0+190
=========================================
================= day14 =================
=========================================
+++++++++++++++++ part 1
aoc-c: res=665
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+109
+++++++++++++++++ part 2
aoc-c: res=25434
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+121
=========================================
================= day15 =================
=========================================
+++++++++++++++++ part 1
aoc-c: res=5176944
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+152
+++++++++++++++++ part 2
aoc-c: res=13350458933732
time: 0:00.00 real, 0.00 user, 0.00 sys
context-switch: 0+1, page-faults: 0+88

111
2022/day01/Makefile Normal file
View File

@@ -0,0 +1,111 @@
# 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/input.txt
SHELL := /bin/bash
CC := gcc
BEAR := bear
CCLSFILE:= compile_commands.json
LIB := aoc_$(shell uname -m)
INCDIR := ../include
LIBDIR := ../lib
LDFLAGS := -L$(LIBDIR)
#LDLIB := -l$(LIB) -lm
LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
# CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations
CFLAGS += -Wno-unused-result
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
--sigill-diagnostics=yes --quiet --show-error-list=yes
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH)
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 part1 part2 ccls bear org
all: README.org ccls part1 part2
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
cpp: aoc-c.i
assembly: aoc-c.s
part1: aoc-c
@$(TIME) aoc.bash -p 1 < $(INPUT) 2>&1
@$(TIME) aoc-c -p 1 < $(INPUT)
part2: aoc-c
@$(TIME) aoc.bash -p 2 < $(INPUT) 2>&1
@$(TIME) aoc-c -p 2 < $(INPUT)
ccls: $(CCLSFILE)
clean:
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
aoc-c: aoc-c.c common.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: README.org
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@
# generate compile_commands.json
$(CCLSFILE): aoc-c.c Makefile
$(BEAR) -- make clean compile
bear: clean
@touch .ccls-root
@$(BEAR) -- make compile

89
2022/day01/README.org Normal file
View File

@@ -0,0 +1,89 @@
** --- Day 1: Calorie Counting ---
Santa's reindeer typically eat regular reindeer food, but they need a
lot of [[/2018/day/25][magical energy]] to deliver presents on
Christmas. For that, their favorite snack is a special type of /star/
fruit that only grows deep in the jungle. The Elves have brought you on
their annual expedition to the grove where the fruit grows.
To supply enough magical energy, the expedition needs to retrieve a
minimum of /fifty stars/ by December 25th. Although the Elves assure you
that the grove has plenty of fruit, you decide to grab any fruit you see
along the way, just in case.
Collect stars by solving puzzles. Two puzzles will be made available on
each day in the Advent calendar; the second puzzle is unlocked when you
complete the first. Each puzzle grants /one star/. Good luck!
The jungle must be too overgrown and difficult to navigate in vehicles
or access from the air; the Elves' expedition traditionally goes on
foot. As your boats approach land, the Elves begin taking inventory of
their supplies. One important consideration is food - in particular, the
number of /Calories/ each Elf is carrying (your puzzle input).
The Elves take turns writing down the number of Calories contained by
the various meals, snacks, rations, etc. that they've brought with them,
one item per line. Each Elf separates their own inventory from the
previous Elf's inventory (if any) by a blank line.
For example, suppose the Elves finish writing their items' Calories and
end up with the following list:
#+begin_example
1000
2000
3000
4000
5000
6000
7000
8000
9000
10000
#+end_example
This list represents the Calories of the food carried by five Elves:
- The first Elf is carrying food with =1000=, =2000=, and =3000=
Calories, a total of =6000= Calories.
- The second Elf is carrying one food item with =4000= Calories.
- The third Elf is carrying food with =5000= and =6000= Calories, a
total of =11000= Calories.
- The fourth Elf is carrying food with =7000=, =8000=, and =9000=
Calories, a total of =24000= Calories.
- The fifth Elf is carrying one food item with =10000= Calories.
In case the Elves get hungry and need extra snacks, they need to know
which Elf to ask: they'd like to know how many Calories are being
carried by the Elf carrying the /most/ Calories. In the example above,
this is /=24000=/ (carried by the fourth Elf).
Find the Elf carrying the most Calories. /How many total Calories is
that Elf carrying?/
Your puzzle answer was =66719=.
** --- Part Two ---
By the time you calculate the answer to the Elves' question, they've
already realized that the Elf carrying the most Calories of food might
eventually /run out of snacks/.
To avoid this unacceptable situation, the Elves would instead like to
know the total Calories carried by the /top three/ Elves carrying the
most Calories. That way, even if one of those Elves runs out of snacks,
they still have two backups.
In the example above, the top three Elves are the fourth Elf (with
=24000= Calories), then the third Elf (with =11000= Calories), then the
fifth Elf (with =10000= Calories). The sum of the Calories carried by
these three elves is =45000=.
Find the top three Elves carrying the most Calories. /How many Calories
are those Elves carrying in total?/
Your puzzle answer was =198551=.
Both parts of this puzzle are complete! They provide two gold stars: **

77
2022/day01/aoc-c.c Normal file
View File

@@ -0,0 +1,77 @@
/* aoc-c.c: Advent of Code 2022, day 1
*
* 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 "plist.h"
#include "debug.h"
#include "pool.h"
#include "aoc.h"
PLIST_HEAD(plist);
static int calc_top_plist(int n)
{
int res = 0;
struct plist_node *node;
plist_for_each_reverse(node, &plist) {
res += node->prio;
if (!--n)
break;
}
return res;
}
static void parse(pool_t *pool)
{
size_t alloc = 0;
char *buf = NULL;
ssize_t buflen;
int total = 0;
struct plist_node *node;
while (1) {
buflen = getline(&buf, &alloc, stdin);
switch (buflen) {
case 1:
case -1: /* EOF */
node = pool_get(pool);
plist_node_init(node, total);
plist_add(node, &plist);
total = 0;
if (buflen == -1)
goto end;
break;
default:
total += atoi(buf);
}
}
end:
free(buf);
return;
}
int main(int ac, char **av)
{
int part = parseargs(ac, av);
pool_t *pool_tot = pool_create("total", 128, sizeof(struct plist_node));
parse(pool_tot);
printf("%s: res=%d\n", *av, calc_top_plist(part == 1? 1: 3));
pool_destroy(pool_tot);
exit(0);
}

56
2022/day01/aoc.bash Executable file
View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bash
#
# aoc.bash: Advent of Code 2022, day 1
#
# 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>
. common.bash
declare -a elf
declare -i maxwanted=3
parse() {
local -i tot=0 i res
while true; do
read -r line
res=$?
# number found: sum & continue
[[ -n $line ]] && (( tot += line)) && continue
# first elf: we set it and continue
(( !${#elf[@]} )) && (( elf[0] = tot )) && continue
# find a place to (maybe) insert new high (keep array sorted)
for (( i = 0; i < ${#elf[@]}; ++i )); do
if (( tot > elf[i] )); then # normal insert (tot > old value)
elf=( "${elf[@]:0:i}" "$tot" "${elf[@]:i}" )
break
elif (( i == ${#elf[@]}-1 )); then # insert at end
elf+=( "$tot" )
break
fi
done
# keep array size <= maxwanted
elf=( "${elf[@]:0:maxwanted}" )
(( tot = 0 ))
((res > 0)) && break # EOF
done
}
solve() {
local -i part="$1"
if ((part == 1)); then
(( res = elf[0] ))
else
(( res = elf[0] + elf[1] + elf[2] ))
fi
}
main "$@"
exit 0

17
2022/day01/aoc.h Normal file
View File

@@ -0,0 +1,17 @@
/* aoc.c: Advent of Code 2022
*
* 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>
*/
#ifndef _AOC_H_
#define _AOC_H_
extern int parseargs(int ac, char**av);
#endif /* _AOC_H_ */

68
2022/day01/common.bash Executable file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/env bash
#
# common.bash: Advent of Code 2022, common bash functions
#
# 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>
# shellcheck disable=2034
export cmdname=${0##*/}
export debug=0
export res
export LANG=C
shopt -s extglob
set -o noglob
usage() {
printf "usage: %s [-d DEBUG] [-p PART]\n" "$cmdname"
exit 1
}
checkargs() {
local part=1
while getopts p:d: todo; do
case "$todo" in
d)
if [[ "$OPTARG" =~ ^[[:digit:]+]$ ]]; then
debug="$OPTARG"
else
printf "%s: illegal [%s] debug level.\n" "$CMD" "$OPTARG"
exit 1
fi
;;
p)
if [[ "$OPTARG" =~ ^[12]$ ]]; then
part="$OPTARG"
else
printf "%s: illegal [%s] part.\n" "$CMD" "$OPTARG"
exit 1
fi
;;
*)
usage
;;
esac
done
# Now check remaining argument (backup directory)
shift $((OPTIND - 1))
(( $# > 1 )) && usage
return "$part"
}
main() {
local -i part
checkargs "$@"
part=$?
parse "$part"
solve "$part"
printf "%s: res=%s\n" "$cmdname" "$res"
}

49
2022/day01/common.c Normal file
View File

@@ -0,0 +1,49 @@
/* common.c: Advent of Code 2022, common functions
*
* 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 "aoc.h"
#include "debug.h"
static int usage(char *prg)
{
fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg);
return 1;
}
int parseargs(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;
case 'i':
default:
return usage(*av);
}
}
if (optind < ac)
return usage(*av);
return part;
}

View File

@@ -0,0 +1,14 @@
1000
2000
3000
4000
5000
6000
7000
8000
9000
10000

2255
2022/day01/input/input.txt Normal file

File diff suppressed because it is too large Load Diff

111
2022/day02/Makefile Normal file
View File

@@ -0,0 +1,111 @@
# 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/input.txt
SHELL := /bin/bash
CC := gcc
BEAR := bear
CCLSFILE:= compile_commands.json
LIB := aoc_$(shell uname -m)
INCDIR := ../include
LIBDIR := ../lib
LDFLAGS := -L$(LIBDIR)
#LDLIB := -l$(LIB) -lm
LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
# CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations
CFLAGS += -Wno-unused-result
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
--sigill-diagnostics=yes --quiet --show-error-list=yes
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH)
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 part1 part2 ccls bear org
all: README.org ccls part1 part2
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
cpp: aoc-c.i
assembly: aoc-c.s
part1: aoc-c
@$(TIME) aoc.bash -p 1 < $(INPUT) 2>&1
@$(TIME) aoc-c -p 1 < $(INPUT)
part2: aoc-c
@$(TIME) aoc.bash -p 2 < $(INPUT) 2>&1
@$(TIME) aoc-c -p 2 < $(INPUT)
ccls: $(CCLSFILE)
clean:
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
aoc-c: aoc-c.c common.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: README.org
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@
# generate compile_commands.json
$(CCLSFILE): aoc-c.c Makefile
$(BEAR) -- make clean compile
bear: clean
@touch .ccls-root
@$(BEAR) -- make compile

89
2022/day02/README.org Normal file
View File

@@ -0,0 +1,89 @@
** --- Day 2: Rock Paper Scissors ---
The Elves begin to set up camp on the beach. To decide whose tent gets
to be closest to the snack storage, a giant
[[https://en.wikipedia.org/wiki/Rock_paper_scissors][Rock Paper
Scissors]] tournament is already in progress.
Rock Paper Scissors is a game between two players. Each game contains
many rounds; in each round, the players each simultaneously choose one
of Rock, Paper, or Scissors using a hand shape. Then, a winner for that
round is selected: Rock defeats Scissors, Scissors defeats Paper, and
Paper defeats Rock. If both players choose the same shape, the round
instead ends in a draw.
Appreciative of your help yesterday, one Elf gives you an /encrypted
strategy guide/ (your puzzle input) that they say will be sure to help
you win. "The first column is what your opponent is going to play: =A=
for Rock, =B= for Paper, and =C= for Scissors. The second column--"
Suddenly, the Elf is called away to help with someone's tent.
The second column, you reason, must be what you should play in response:
=X= for Rock, =Y= for Paper, and =Z= for Scissors. Winning every time
would be suspicious, so the responses must have been carefully chosen.
The winner of the whole tournament is the player with the highest score.
Your /total score/ is the sum of your scores for each round. The score
for a single round is the score for the /shape you selected/ (1 for
Rock, 2 for Paper, and 3 for Scissors) plus the score for the /outcome
of the round/ (0 if you lost, 3 if the round was a draw, and 6 if you
won).
Since you can't be sure if the Elf is trying to help you or trick you,
you should calculate the score you would get if you were to follow the
strategy guide.
For example, suppose you were given the following strategy guide:
#+begin_example
A Y
B X
C Z
#+end_example
This strategy guide predicts and recommends the following:
- In the first round, your opponent will choose Rock (=A=), and you
should choose Paper (=Y=). This ends in a win for you with a score of
/8/ (2 because you chose Paper + 6 because you won).
- In the second round, your opponent will choose Paper (=B=), and you
should choose Rock (=X=). This ends in a loss for you with a score of
/1/ (1 + 0).
- The third round is a draw with both players choosing Scissors, giving
you a score of 3 + 3 = /6/.
In this example, if you were to follow the strategy guide, you would get
a total score of =15= (8 + 1 + 6).
/What would your total score be if everything goes exactly according to
your strategy guide?/
Your puzzle answer was =11841=.
** --- Part Two ---
The Elf finishes helping with the tent and sneaks back over to you.
"Anyway, the second column says how the round needs to end: =X= means
you need to lose, =Y= means you need to end the round in a draw, and =Z=
means you need to win. Good luck!"
The total score is still calculated in the same way, but now you need to
figure out what shape to choose so the round ends as indicated. The
example above now goes like this:
- In the first round, your opponent will choose Rock (=A=), and you need
the round to end in a draw (=Y=), so you also choose Rock. This gives
you a score of 1 + 3 = /4/.
- In the second round, your opponent will choose Paper (=B=), and you
choose Rock so you lose (=X=) with a score of 1 + 0 = /1/.
- In the third round, you will defeat your opponent's Scissors with Rock
for a score of 1 + 6 = /7/.
Now that you're correctly decrypting the ultra top secret strategy
guide, you would get a total score of =12=.
Following the Elf's instructions for the second column, /what would your
total score be if everything goes exactly according to your strategy
guide?/
Your puzzle answer was =13022=.
Both parts of this puzzle are complete! They provide two gold stars: **

64
2022/day02/aoc-c.c Normal file
View File

@@ -0,0 +1,64 @@
/* aoc-c.c: Advent of Code 2022, day 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 "plist.h"
#include "debug.h"
#include "pool.h"
#include "aoc.h"
/* we will use the following convention, for input line "a x":
* position in array=(a-'A' * 3) + x - 'X'
*/
enum {
A = 0, B, C,
X = 0, Y, Z
};
#define pos(x, y) ((x) * 3 + (y))
int outcome[2][9] = { /* shape is known */
{
[pos(A, X)] = 3 + 1, [pos(A, Y)] = 6 + 2, [pos(A, Z)] = 0 + 3,
[pos(B, X)] = 0 + 1, [pos(B, Y)] = 3 + 2, [pos(B, Z)] = 6 + 3,
[pos(C, X)] = 6 + 1, [pos(C, Y)] = 0 + 2, [pos(C, Z)] = 3 + 3
},
{ /* result is known */
[pos(A, X)] = 0 + 3, [pos(A, Y)] = 3 + 1, [pos(A, Z)] = 6 + 2,
[pos(B, X)] = 0 + 1, [pos(B, Y)] = 3 + 2, [pos(B, Z)] = 6 + 3,
[pos(C, X)] = 0 + 2, [pos(C, Y)] = 3 + 3, [pos(C, Z)] = 6 + 1
}
};
static int *parse(int *res)
{
size_t alloc = 0;
char *buf = NULL;
ssize_t buflen;
while ((buflen = getline(&buf, &alloc, stdin)) > 0) {
for (int i = 0; i < 2; ++i)
res[i] += outcome[i][pos(buf[0] - 'A', buf[2] - 'X')];
}
free(buf);
return res;
}
int main(int ac, char **av)
{
int res[2] = { 0, 0 };
printf("%s: res=%d\n", *av, parse(res)[parseargs(ac, av) - 1]);
exit(0);
}

42
2022/day02/aoc.bash Executable file
View File

@@ -0,0 +1,42 @@
#!/usr/bin/env bash
#
# aoc.bash: Advent of Code 2022, day 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>
. common.bash
declare -A outcome=( # shape is known
[A X]=$((3+1)) [A Y]=$((6+2)) [A Z]=$((0+3))
[B X]=$((0+1)) [B Y]=$((3+2)) [B Z]=$((6+3))
[C X]=$((6+1)) [C Y]=$((0+2)) [C Z]=$((3+3))
)
declare -A outcome2=( # result is known
[A X]=$((0+3)) [A Y]=$((3+1)) [A Z]=$((6+2))
[B X]=$((0+1)) [B Y]=$((3+2)) [B Z]=$((6+3))
[C X]=$((0+2)) [C Y]=$((3+3)) [C Z]=$((6+1))
)
declare -a tot
parse() {
local input
while read -r input; do
(( tot[1] += outcome[$input] ))
(( tot[2] += outcome2[$input] ))
done
}
solve() {
res="${tot[$1]}"
}
main "$@"
exit 0

17
2022/day02/aoc.h Normal file
View File

@@ -0,0 +1,17 @@
/* aoc.c: Advent of Code 2022
*
* 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>
*/
#ifndef _AOC_H_
#define _AOC_H_
extern int parseargs(int ac, char**av);
#endif /* _AOC_H_ */

68
2022/day02/common.bash Executable file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/env bash
#
# common.bash: Advent of Code 2022, common bash functions
#
# 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>
# shellcheck disable=2034
export cmdname=${0##*/}
export debug=0
export res
export LANG=C
shopt -s extglob
set -o noglob
usage() {
printf "usage: %s [-d DEBUG] [-p PART]\n" "$cmdname"
exit 1
}
checkargs() {
local part=1
while getopts p:d: todo; do
case "$todo" in
d)
if [[ "$OPTARG" =~ ^[[:digit:]+]$ ]]; then
debug="$OPTARG"
else
printf "%s: illegal [%s] debug level.\n" "$CMD" "$OPTARG"
exit 1
fi
;;
p)
if [[ "$OPTARG" =~ ^[12]$ ]]; then
part="$OPTARG"
else
printf "%s: illegal [%s] part.\n" "$CMD" "$OPTARG"
exit 1
fi
;;
*)
usage
;;
esac
done
# Now check remaining argument (backup directory)
shift $((OPTIND - 1))
(( $# > 1 )) && usage
return "$part"
}
main() {
local -i part
checkargs "$@"
part=$?
parse "$part"
solve "$part"
printf "%s: res=%s\n" "$cmdname" "$res"
}

49
2022/day02/common.c Normal file
View File

@@ -0,0 +1,49 @@
/* common.c: Advent of Code 2022, common functions
*
* 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 "aoc.h"
#include "debug.h"
static int usage(char *prg)
{
fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg);
return 1;
}
int parseargs(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;
case 'i':
default:
return usage(*av);
}
}
if (optind < ac)
return usage(*av);
return part;
}

View File

@@ -0,0 +1,3 @@
A Y
B X
C Z

2500
2022/day02/input/input.txt Normal file

File diff suppressed because it is too large Load Diff

111
2022/day03/Makefile Normal file
View File

@@ -0,0 +1,111 @@
# 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/input.txt
SHELL := /bin/bash
CC := gcc
BEAR := bear
CCLSFILE:= compile_commands.json
LIB := aoc_$(shell uname -m)
INCDIR := ../include
LIBDIR := ../lib
LDFLAGS := -L$(LIBDIR)
#LDLIB := -l$(LIB) -lm
LDLIB := -l$(LIB)
export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu11
CFLAGS += -O2
CFLAGS += -g
# for gprof
# CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations
CFLAGS += -Wno-unused-result
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
CFLAGS += -DDEBUG_POOL # memory pools management
VALGRIND := valgrind
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
--sigill-diagnostics=yes --quiet --show-error-list=yes
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH)
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 part1 part2 ccls bear org
all: README.org ccls part1 part2
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
cpp: aoc-c.i
assembly: aoc-c.s
part1: aoc-c
@$(TIME) aoc.bash -p 1 < $(INPUT) 2>&1
@$(TIME) aoc-c -p 1 < $(INPUT)
part2: aoc-c
@$(TIME) aoc.bash -p 2 < $(INPUT) 2>&1
@$(TIME) aoc-c -p 2 < $(INPUT)
ccls: $(CCLSFILE)
clean:
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
aoc-c: aoc-c.c common.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: README.org
%.org: %.html
@echo generating $@. Cleanup before commit !
@pandoc $< -o $@
# generate compile_commands.json
$(CCLSFILE): aoc-c.c Makefile
$(BEAR) -- make clean compile
bear: clean
@touch .ccls-root
@$(BEAR) -- make compile

114
2022/day03/README.org Normal file
View File

@@ -0,0 +1,114 @@
** --- Day 3: Rucksack Reorganization ---
One Elf has the important job of loading all of the
[[https://en.wikipedia.org/wiki/Rucksack][rucksacks]] with supplies for
the jungle journey. Unfortunately, that Elf didn't quite follow the
packing instructions, and so a few items now need to be rearranged.
Each rucksack has two large /compartments/. All items of a given type
are meant to go into exactly one of the two compartments. The Elf that
did the packing failed to follow this rule for exactly one item type per
rucksack.
The Elves have made a list of all of the items currently in each
rucksack (your puzzle input), but they need your help finding the
errors. Every item type is identified by a single lowercase or uppercase
letter (that is, =a= and =A= refer to different types of items).
The list of items for each rucksack is given as characters all on a
single line. A given rucksack always has the same number of items in
each of its two compartments, so the first half of the characters
represent items in the first compartment, while the second half of the
characters represent items in the second compartment.
For example, suppose you have the following list of contents from six
rucksacks:
#+begin_example
vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw
#+end_example
- The first rucksack contains the items =vJrwpWtwJgWrhcsFMMfFFhFp=,
which means its first compartment contains the items =vJrwpWtwJgWr=,
while the second compartment contains the items =hcsFMMfFFhFp=. The
only item type that appears in both compartments is lowercase =p=.
- The second rucksack's compartments contain =jqHRNqRjqzjGDLGL= and
=rsFMfFZSrLrFZsSL=. The only item type that appears in both
compartments is uppercase =L=.
- The third rucksack's compartments contain =PmmdzqPrV= and =vPwwTWBwg=;
the only common item type is uppercase =P=.
- The fourth rucksack's compartments only share item type =v=.
- The fifth rucksack's compartments only share item type =t=.
- The sixth rucksack's compartments only share item type =s=.
To help prioritize item rearrangement, every item type can be converted
to a /priority/:
- Lowercase item types =a= through =z= have priorities 1 through 26.
- Uppercase item types =A= through =Z= have priorities 27 through 52.
In the above example, the priority of the item type that appears in both
compartments of each rucksack is 16 (=p=), 38 (=L=), 42 (=P=), 22 (=v=),
20 (=t=), and 19 (=s=); the sum of these is =157=.
Find the item type that appears in both compartments of each rucksack.
/What is the sum of the priorities of those item types?/
Your puzzle answer was =7878=.
** --- Part Two ---
As you finish identifying the misplaced items, the Elves come to you
with another issue.
For safety, the Elves are divided into groups of three. Every Elf
carries a badge that identifies their group. For efficiency, within each
group of three Elves, the badge is the /only item type carried by all
three Elves/. That is, if a group's badge is item type =B=, then all
three Elves will have item type =B= somewhere in their rucksack, and at
most two of the Elves will be carrying any other item type.
The problem is that someone forgot to put this year's updated
authenticity sticker on the badges. All of the badges need to be pulled
out of the rucksacks so the new authenticity stickers can be attached.
Additionally, nobody wrote down which item type corresponds to each
group's badges. The only way to tell which item type is the right one is
by finding the one item type that is /common between all three Elves/ in
each group.
Every set of three lines in your list corresponds to a single group, but
each group can have a different badge item type. So, in the above
example, the first group's rucksacks are the first three lines:
#+begin_example
vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
#+end_example
And the second group's rucksacks are the next three lines:
#+begin_example
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw
#+end_example
In the first group, the only item type that appears in all three
rucksacks is lowercase =r=; this must be their badges. In the second
group, their badge item type must be =Z=.
Priorities for these items must still be found to organize the sticker
attachment efforts: here, they are 18 (=r=) for the first group and 52
(=Z=) for the second group. The sum of these is =70=.
Find the item type that corresponds to the badges of each three-Elf
group. /What is the sum of the priorities of those item types?/
Your puzzle answer was =2760=.
Both parts of this puzzle are complete! They provide two gold stars: **

97
2022/day03/aoc-c.c Normal file
View File

@@ -0,0 +1,97 @@
/* aoc-c.c: Advent of Code 2022, day 3
*
* 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 <string.h>
#include "aoc.h"
#define NCHARS ('Z' - 'A' + 1 + 'z' - 'a' + 1)
/* convert item to map position, and vice versa */
#define CHAR2POS(c) ((c) > 'Z'? (c) - 'a': (c) - 'A' + 26)
#define POS2CHAR(p) ((p) < 26? (p) + 'a': (p) - 26 + 'A')
/* set a map from char */
#define SET_MAP(ex, c) ((ex)[CHAR2POS(c)] = 1)
static void map_init(char *p)
{
memset(p, 0, NCHARS);
}
static void map_populate(char *ex, char *p, int len)
{
map_init(ex);
for (; len; --len)
SET_MAP(ex, p[len - 1]);
}
/* match map with items list. If dest is NULL, return first match,
* otherwise populate dest with matching chars.
*/
static int map_match(char *dest, char *map, char *items, int ilen)
{
if (dest)
map_init(dest);
for (int i = 0; i < ilen; ++i) {
int pos = CHAR2POS(items[i]);
if (map[pos]) { /* already exists */
if (dest)
dest[pos] = 1; /* fill dest array */
else
return pos + 1; /* one match only: return prio */
}
}
return -1; /* unused if dest != NULL */
}
static int parse(int part)
{
size_t alloc = 0;
char *buf = NULL;
ssize_t buflen;
int line = 0, res = 0;
char map[2][NCHARS];
while ((buflen = getline(&buf, &alloc, stdin)) > 0) {
buf[--buflen] = 0;
if (part == 1) {
int half = buflen / 2;
map_populate(*map, buf, half); /* populate and calculate */
res += map_match(NULL, *map, buf + half, half);
continue;
}
/* Part 2 here */
switch (++line % 3) { /* group lines by 3 */
case 1: /* line 1: populate *map */
map_populate(*map, buf, buflen);
break;
case 2: /* line 2: merge #1 into map[1] */
map_match(*(map + 1), *map, buf, buflen);
break;
case 0: /* line 3: final merge & calc */
res += map_match(NULL, *(map + 1), buf, buflen);
break;
}
}
free(buf);
return res;
}
int main(int ac, char **av)
{
printf("%s: res=%d\n", *av, parse(parseargs(ac, av)));
exit(0);
}

86
2022/day03/aoc.bash Executable file
View File

@@ -0,0 +1,86 @@
#!/usr/bin/env bash
#
# aoc.bash: Advent of Code 2022, day 3
#
# 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>
. common.bash
declare -a input
# prio - get priority value for an item
# $1: reference of variable for result
# $2: string
prio() {
local -n _val="$1"
local _char="${2:0:1}"
printf -v _val "%d" "'$_char"
if [[ $_char > "Z" ]]; then # a-z
((_val += (1 - 97) ))
else # A-Z
((_val += (27 - 65) ))
fi
}
# common=chars - get common characters in two strings
# $1: reference of variable for result
# $2, $3: The two strings
common_chars() {
local -n _res="$1"
_res="${2//[^$3]}"
}
parse() {
readarray -t input
}
part1() {
local line half1 half2 common
local -i half i prio
declare -ig res=0
for line in "${input[@]}"; do
(( half = ${#line} / 2 ))
half1="${line:0:half}"
half2="${line:half}"
common="${half1//[^${half2}]}"
prio prio "${common}"
(( res += prio ))
done
}
part2() {
local one two three common
local -i i prio
declare -ig res=0
for (( i = ${#input[@]} - 1; i > 1; i -= 3)); do
three=${input[i]}
two=${input[i - 1]}
one=${input[i - 2]}
common_chars common "$three" "$two"
common_chars common "$common" "$one"
prio prio "${common}"
(( res += prio ))
done
}
solve() {
if (($1 == 1)); then
part1
else
part2
fi
}
main "$@"
exit 0

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