Compare commits
137 Commits
563798871a
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| ad6a39e82a | |||
| 3a857e4d53 | |||
| f80a051177 | |||
| 129fa07787 | |||
| 1472082c86 | |||
| e8bed49e13 | |||
| 83d70dcc7a | |||
| 56d2e63fac | |||
| 5c91de5d40 | |||
| 40a9c7b12e | |||
| 34b6cd7b57 | |||
| 5ad5c87fd8 | |||
| 11e7b45676 | |||
| 3f2a5648df | |||
| 0a3b404c4c | |||
| a214d2b70d | |||
| f490c2353e | |||
| 2ed6284bcd | |||
| 5fc204744a | |||
| d1cf8d96b8 | |||
| b285f74997 | |||
| c949c64da2 | |||
| 357e8ce087 | |||
| 5cde9051ec | |||
| 111fde4fbd | |||
| f54479189b | |||
| 8e00fec33c | |||
| d0376f21c3 | |||
| 04a856dc47 | |||
| 0658ffdd7d | |||
| efe0dec8f0 | |||
| 6d4a8dd85b | |||
| 11cb3c5c64 | |||
| 7e0a21704e | |||
| 008599e79c | |||
| fe381ae7f0 | |||
| 4a0749999e | |||
| 18720b9e09 | |||
| 17e140f235 | |||
| a1e436babc | |||
| 02a1dda786 | |||
| ef29ca28a1 | |||
| c1b3e83c68 | |||
| bd2548fca9 | |||
| 3f5b282883 | |||
| 38ef781f0a | |||
| 13d183de79 | |||
| dfe2207e8e | |||
| 31a255a9ac | |||
| 25d25b399e | |||
| f5ebb5c5cc | |||
| c608f6dcde | |||
| 9e3a875e37 | |||
| 4c0f6e3025 | |||
| 68f200ff65 | |||
| 8aff410ff4 | |||
| 16da47600c | |||
| 8b68bf4449 | |||
| c86517897e | |||
| 9c999e9717 | |||
| 05643127c2 | |||
| 6a5a0da435 | |||
| 3dd072c53e | |||
| 8f09fcf13f | |||
| 8f444d7341 | |||
| d7fa1c4fb5 | |||
| 0c787d9a51 | |||
| 64ad068ec8 | |||
| ab73311d6b | |||
| d116b98ae9 | |||
| 325c8254b8 | |||
| 76ab3d0c5b | |||
| bc2b2ac726 | |||
| b7c0b1fa01 | |||
| 487766c0a2 | |||
| a0fddb5f44 | |||
| f68d5b319e | |||
| 9455b99342 | |||
| ea4967bfcd | |||
| d1026e8f59 | |||
| 01cdce6608 | |||
| b8f6763a3b | |||
| 81a58c6266 | |||
| ca06a4a355 | |||
| 9d375aecfc | |||
| d412824317 | |||
| d8e05b0fca | |||
| a49a2ed073 | |||
| 2c14abff21 | |||
| 50919df627 | |||
| 73c9fa8150 | |||
| b949e11314 | |||
| f003511e10 | |||
| 36f763830f | |||
| c7553e7849 | |||
|
|
6012d4d375 | ||
| ce446be296 | |||
| a8cab0c7c3 | |||
| dbff06e5da | |||
| 0fb4219c92 | |||
| 58ba8b4ab8 | |||
| cca3d6fbe5 | |||
| cfba08b197 | |||
| ca8de49d5e | |||
| ea9c144127 | |||
| d4d5af0cb6 | |||
| 5ee230df69 | |||
| 9fe7b64263 | |||
| 8df13f9713 | |||
| 74ab0ba990 | |||
| 46dee29af6 | |||
| ad7c6f3042 | |||
| d485983efc | |||
| 23c33894a5 | |||
| 9bd03e0650 | |||
| 6de646f0d1 | |||
| a525ab6338 | |||
| 2de0c3c9c8 | |||
| 6e4c64db39 | |||
| b73db03da9 | |||
| f6d1fe7b9d | |||
| 30cdb5e1a4 | |||
| b4a2603c7b | |||
| abcc4af572 | |||
| 94f0d95544 | |||
| 452a912fe5 | |||
| 46d6b77596 | |||
| 65c03075f1 | |||
| 4a565af1c2 | |||
| 0a03bc557b | |||
| 282d55c3cd | |||
| 920f830fac | |||
| e3d6b622dc | |||
| 5795d24ab4 | |||
| 86a62f0b2d | |||
| f3ae028751 | |||
| d2b5a9dc34 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -11,8 +11,5 @@ lib/
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
FOO*
|
||||
BAR*
|
||||
QUAX*
|
||||
TOTO*
|
||||
README.html
|
||||
compile_commands.json
|
||||
|
||||
@@ -1,25 +1,87 @@
|
||||
# AOC Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with this
|
||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
#
|
||||
|
||||
|
||||
SUBDIRS := $(shell echo day??)
|
||||
|
||||
EXCLUDE := --exclude 'cob-01/'
|
||||
CC = gcc
|
||||
|
||||
.PHONY: clean $(SUBDIRS)
|
||||
#LIBS = -lreadline -lncurses
|
||||
CFLAGS += -std=gnu11
|
||||
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
INCDIR := ./include
|
||||
LIBSRCDIR := ./libsrc
|
||||
LIBDIR := ./lib
|
||||
LIB := libaoc_$(shell uname -m)
|
||||
SLIB := $(LIBDIR)/$(LIB).a
|
||||
DLIB := $(LIBDIR)/$(LIB).so
|
||||
LIBSRC := $(wildcard $(LIBSRCDIR)/*.c)
|
||||
LIBOBJ := $(patsubst %.c,%.o,$(LIBSRC))
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
.PHONY: clean cleanlib cleanall all redo output lib $(SUBDIRS)
|
||||
|
||||
all: lib $(SUBDIRS)
|
||||
|
||||
clean:
|
||||
for dir in $(SUBDIRS) ; do \
|
||||
make -C $$dir clean ; \
|
||||
@for dir in $(SUBDIRS) ; do \
|
||||
$(MAKE) --no-print-directory -C $$dir clean ; \
|
||||
done
|
||||
|
||||
all: $(SUBDIRS)
|
||||
cleanlib: clean
|
||||
@$(RM) -f $(SLIB) $(DLIB) $(LIBOBJ)
|
||||
|
||||
cleanall: clean cleanlib
|
||||
|
||||
redo: cleanall all
|
||||
|
||||
$(SUBDIRS):
|
||||
@echo "========================================="
|
||||
@echo "================= $@ ================="
|
||||
@echo "========================================="
|
||||
@echo
|
||||
@echo "+++++++++++++++++ ex1"
|
||||
@$(MAKE) --no-print-directory -C $@ ex1 2>&1
|
||||
@echo "+++++++++++++++++ ex2"
|
||||
@$(MAKE) --no-print-directory -C $@ ex2 2>&1
|
||||
@echo "+++++++++++++++++ part 1"
|
||||
+@$(MAKE) --no-print-directory -C $@ ex1 2>&1
|
||||
@echo "+++++++++++++++++ part 2"
|
||||
+@$(MAKE) --no-print-directory -C $@ ex2 2>&1
|
||||
|
||||
output:
|
||||
@$(MAKE) --no-print-directory all >OUTPUT 2>&1
|
||||
|
||||
lib: $(DLIB) $(SLIB)
|
||||
|
||||
$(SLIB): $(LIBOBJ)
|
||||
@echo building $@ static library.
|
||||
@mkdir -p $(LIBDIR)
|
||||
@$(AR) $(ARFLAGS) -o $@ $^
|
||||
|
||||
$(DLIB): CFLAGS += -fPIC
|
||||
$(DLIB): LDFLAGS += -shared
|
||||
$(DLIB): $(LIBOBJ)
|
||||
@echo building $@ shared library.
|
||||
@mkdir -p $(LIBDIR)
|
||||
@$(CC) $(LDFLAGS) $^ -o $@
|
||||
|
||||
.c.o:
|
||||
@echo compiling $<.
|
||||
@$(CC) -c $(CFLAGS) $(LDFLAGS) -I $(INCDIR) -o $@ $<
|
||||
|
||||
@@ -439,11 +439,20 @@ ex1.bash : res=285
|
||||
time: 0:00.56 real, 0.55 user, 0.00 sys
|
||||
context-switch: 12+1, page-faults: 0+5967
|
||||
|
||||
aoc-c : res=285
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+94
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash : res=412
|
||||
time: 0:03.37 real, 3.34 user, 0.03 sys
|
||||
context-switch: 19+1, page-faults: 0+11909
|
||||
|
||||
|
||||
aoc-c : res=412
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+95
|
||||
|
||||
=========================================
|
||||
================= day20 =================
|
||||
=========================================
|
||||
@@ -481,19 +490,72 @@ ex1.bash: res=31314
|
||||
time: 0:00.07 real, 0.06 user, 0.00 sys
|
||||
context-switch: 2+1, page-faults: 0+168
|
||||
|
||||
aoc-c : res=31314
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+89
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash: res=32760
|
||||
time: 1:21.92 real, 81.89 user, 0.01 sys
|
||||
context-switch: 462+1, page-faults: 0+5135
|
||||
|
||||
aoc-c : res=32760
|
||||
time: 0:01.11 real, 1.09 user, 0.01 sys
|
||||
context-switch: 70+1, page-faults: 0+1933
|
||||
|
||||
=========================================
|
||||
================= day23 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash: res=75893264
|
||||
time: 0:00.01 real, 0.01 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+166
|
||||
|
||||
aoc-c : res=75893264
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+83
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash: res=38162588308
|
||||
time: 6:52.50 real, 412.30 user, 0.14 sys
|
||||
context-switch: 2219+1, page-faults: 0+30233
|
||||
|
||||
aoc-c : res=38162588308
|
||||
time: 0:01.33 real, 1.32 user, 0.01 sys
|
||||
context-switch: 3+1, page-faults: 0+3992
|
||||
|
||||
=========================================
|
||||
================= day24 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash: res=450
|
||||
time: 0:00.17 real, 0.16 user, 0.00 sys
|
||||
context-switch: 1+1, page-faults: 0+177
|
||||
|
||||
aoc-c : res=450
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+100
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash: res=4059
|
||||
time: 0:22.35 real, 22.22 user, 0.07 sys
|
||||
context-switch: 1102+1, page-faults: 0+858
|
||||
|
||||
aoc-c : res=4059
|
||||
time: 0:00.04 real, 0.04 user, 0.00 sys
|
||||
context-switch: 16+1, page-faults: 0+215
|
||||
|
||||
=========================================
|
||||
================= day25 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash: res=9620012
|
||||
time: 2:42.30 real, 162.05 user, 0.08 sys
|
||||
context-switch: 3634+1, page-faults: 0+163
|
||||
|
||||
ex1-c : res=9620012
|
||||
time: 0:00.08 real, 0.08 user, 0.00 sys
|
||||
context-switch: 2+1, page-faults: 0+79
|
||||
|
||||
@@ -28,7 +28,7 @@ ex2: ex2-c ex2-sort-cob ex2-pure-sort-cob
|
||||
@$(TIME) ex2-c < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f ex1-c ex2-c core ex2-galoisgirl-cob ex2-cob
|
||||
@rm -f ex1-c ex2-c core ex*-cob
|
||||
|
||||
output:
|
||||
$(MAKE) --no-print-directory all >OUTPUT 2>&1
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -32,7 +32,7 @@ int main(ac, av)
|
||||
char **av;
|
||||
{
|
||||
int line=1, linelen=0, mod=0, i;
|
||||
unsigned long res=1;
|
||||
unsigned long long res=1;
|
||||
char str[80];
|
||||
|
||||
scanf("%s", str); /* ignore 1st line */
|
||||
@@ -51,6 +51,6 @@ int main(ac, av)
|
||||
}
|
||||
for (i=0; set[i].dx != -1; ++i)
|
||||
res*=set[i].count;
|
||||
printf ("%s : lines=%d res=%lu\n", *av, line, res);
|
||||
printf ("%s : lines=%d res=%llu\n", *av, line, res);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#! /bin/bash
|
||||
PATH=.:$PATH
|
||||
IN="$1"
|
||||
time { ex1.bash < $IN; ex2.bash < $IN; } 2>&1
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -63,7 +63,6 @@ struct list *add_val(list, val)
|
||||
struct list *list;
|
||||
unsigned long long val;
|
||||
{
|
||||
//int val;
|
||||
unsigned cur, size;
|
||||
unsigned long long *ptr;
|
||||
|
||||
@@ -80,7 +79,6 @@ struct list *add_val(list, val)
|
||||
size+=BLOCKSIZE;
|
||||
list->size=size;
|
||||
list->list=realloc(list->list, sizeof(unsigned long long)*size);
|
||||
fprintf(stderr, "realloc buf: cur=%d size=%d ptr=%p\n", cur, size, list->list);
|
||||
}
|
||||
ptr=list->list+cur;
|
||||
|
||||
@@ -91,10 +89,10 @@ struct list *add_val(list, val)
|
||||
return list;
|
||||
}
|
||||
|
||||
unsigned *calc(list)
|
||||
unsigned long long *calc(list)
|
||||
struct list *list;
|
||||
{
|
||||
static unsigned res[4];
|
||||
static unsigned long long res[4];
|
||||
unsigned long long *ptr=list->list;
|
||||
unsigned last=list->last, i;
|
||||
|
||||
@@ -113,10 +111,9 @@ int main(ac, av)
|
||||
{
|
||||
char line[80];
|
||||
struct list *list=NULL;
|
||||
unsigned long long res, last;
|
||||
unsigned *result;
|
||||
unsigned long long res, last, *result;
|
||||
|
||||
list=add_val(list, 0);
|
||||
list=add_val(list, 0llu);
|
||||
while (fgets(line, sizeof line, stdin)) {
|
||||
sscanf(line, "%llu", &res);
|
||||
list=add_val(list, res);
|
||||
@@ -126,7 +123,7 @@ int main(ac, av)
|
||||
list=add_val(list, last+3);
|
||||
//print_list(list);
|
||||
result=calc(list);
|
||||
printf("%s : diff1=%u diff2=%u res=%u\n", *av, result[1], result[3],
|
||||
printf("%s : diff1=%llu diff2=%llu res=%llu\n", *av, result[1], result[3],
|
||||
result[1]*result[3]);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ int main(ac, av)
|
||||
struct list *list=NULL;
|
||||
unsigned long long res, last;
|
||||
|
||||
list=add_val(list, 0);
|
||||
list=add_val(list, 0ll);
|
||||
while (fgets(line, sizeof line, stdin)) {
|
||||
sscanf(line, "%llu", &res);
|
||||
list=add_val(list, res);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -12,9 +12,9 @@ declare floor
|
||||
|
||||
function adj() {
|
||||
local -i r="$1" n="$2" c="$3" count=0
|
||||
local -a prow=(${rows[r-1]})
|
||||
local -a row=(${rows[r]})
|
||||
local -a nrow=(${rows[r+1]})
|
||||
local -a prow=("${rows[r-1]}")
|
||||
local -a row=("${rows[r]}")
|
||||
local -a nrow=("${rows[r+1]}")
|
||||
#echo
|
||||
#echo p="${prow[*]}"
|
||||
#echo r="${row[*]}"
|
||||
@@ -51,7 +51,7 @@ function run() {
|
||||
changed=0
|
||||
seated=0
|
||||
for ((r=1; r<=NROWS; ++r)); do
|
||||
row=(${rows[r]})
|
||||
row=("${rows[r]}")
|
||||
newrow=(0)
|
||||
for ((c=1; c<=RLENGTH; ++c)); do
|
||||
newrow+=("${row[c]}")
|
||||
@@ -61,13 +61,13 @@ function run() {
|
||||
case ${row[c]} in
|
||||
0) continue
|
||||
;;
|
||||
1) if (( $(adj $r $c 2) == 0 )); then
|
||||
1) if (( $(adj "$r" "$c" 2) == 0 )); then
|
||||
((++changed))
|
||||
newrow[c]=2
|
||||
fi
|
||||
#printf "[%d][%d]: %s %s %d\n" $r $c "${row[c]}" "${newrow[c]}" $(adj $r $c 2)
|
||||
;;
|
||||
2) if (( $(adj $r $c 2) >= 4 )); then
|
||||
2) if (( $(adj "$r" "$c" 2) >= 4 )); then
|
||||
((++changed))
|
||||
newrow[c]=1
|
||||
fi
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,7 +24,7 @@ ex2: ex12-c
|
||||
@$(TIME) ex12-c 2 < $(INPUT) 2>&1
|
||||
|
||||
clean:
|
||||
@rm -f ex1-c ex2-c core
|
||||
@rm -f ex12-c core
|
||||
|
||||
deploy:
|
||||
@$(MAKE) -C .. deploy
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,30 +1,108 @@
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
CFLAGS := -w -g
|
||||
#CFLAGS := -w -g -pg
|
||||
#CFLAGS := -w -O3
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with this
|
||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
BEAR := bear
|
||||
CCLSFILE:= compile_commands.json
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
# CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile deploy ex1 ex2
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 ccls
|
||||
|
||||
all: ex1 ex2
|
||||
all: README.org ccls ex1 ex2
|
||||
|
||||
output:
|
||||
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
compile: ex1-c ex2-c
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex1:
|
||||
@$(TIME) ex1.bash < $(INPUT) 2>&1
|
||||
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
ex2:
|
||||
@$(TIME) ex2.bash < $(INPUT) 2>&1
|
||||
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1
|
||||
compile: aoc-c
|
||||
|
||||
cpp: aoc-c.i
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) ex1.bash -p 1 < $(INPUT)
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) ex2.bash -p 2 < $(INPUT)
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
ccls: $(CCLSFILE)
|
||||
|
||||
clean:
|
||||
@rm -f ex1-c ex2-c core
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
|
||||
|
||||
deploy:
|
||||
@$(MAKE) -C .. deploy
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
||||
|
||||
# generate compile_commands.json
|
||||
$(CCLSFILE): aoc-c.c Makefile
|
||||
$(BEAR) -- make clean compile
|
||||
|
||||
bear: clean
|
||||
@$(BEAR) -- make compile
|
||||
@touch .ccls-root
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
200
2020/day19/README.org
Normal 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
165
2020/day19/aoc-c.c
Normal 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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -1,30 +1,108 @@
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
CFLAGS := -w -g
|
||||
#CFLAGS := -w -g -pg
|
||||
#CFLAGS := -w -O3
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with this
|
||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
BEAR := bear
|
||||
CCLSFILE:= compile_commands.json
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
# CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile deploy ex1 ex2
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 ccls
|
||||
|
||||
all: ex1 ex2
|
||||
all: README.org ccls ex1 ex2
|
||||
|
||||
output:
|
||||
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
compile: ex1-c ex2-c
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex1:
|
||||
@$(TIME) ex1.bash < $(INPUT) 2>&1
|
||||
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
ex2:
|
||||
@$(TIME) ex2.bash < $(INPUT) 2>&1
|
||||
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1
|
||||
compile: aoc-c
|
||||
|
||||
cpp: aoc-c.i
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) ex1.bash -p 1 < $(INPUT)
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) ex2.bash -p 2 < $(INPUT)
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
ccls: $(CCLSFILE)
|
||||
|
||||
clean:
|
||||
@rm -f ex1-c ex2-c core
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
|
||||
|
||||
deploy:
|
||||
@$(MAKE) -C .. deploy
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
||||
|
||||
# generate compile_commands.json
|
||||
$(CCLSFILE): aoc-c.c Makefile
|
||||
$(BEAR) -- make clean compile
|
||||
|
||||
bear: clean
|
||||
@$(BEAR) -- make compile
|
||||
@touch .ccls-root
|
||||
|
||||
@@ -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
76
2020/day21/README.org
Normal 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]].
|
||||
@@ -1,30 +1,108 @@
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
CFLAGS := -w -g
|
||||
#CFLAGS := -w -g -pg
|
||||
#CFLAGS := -w -O3
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with this
|
||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
BEAR := bear
|
||||
CCLSFILE:= compile_commands.json
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
# CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile deploy ex1 ex2
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 ccls bear
|
||||
|
||||
all: ex1 ex2
|
||||
all: README.org ccls ex1 ex2
|
||||
|
||||
output:
|
||||
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
compile: ex1-c ex2-c
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex1:
|
||||
@$(TIME) ex1.bash < $(INPUT) 2>&1
|
||||
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
ex2:
|
||||
@$(TIME) ex2.bash < $(INPUT) 2>&1
|
||||
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1
|
||||
compile: aoc-c
|
||||
|
||||
cpp: aoc-c.i
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) ex1.bash -p 1 < $(INPUT)
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) ex2.bash -p 2 < $(INPUT)
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
ccls: $(CCLSFILE)
|
||||
|
||||
clean:
|
||||
@rm -f ex1-c ex2-c core
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
|
||||
|
||||
deploy:
|
||||
@$(MAKE) -C .. deploy
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
||||
|
||||
# generate compile_commands.json
|
||||
$(CCLSFILE): aoc-c.c Makefile
|
||||
$(BEAR) -- make clean compile
|
||||
|
||||
bear: clean
|
||||
@$(BEAR) -- make compile
|
||||
@touch .ccls-root
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
452
2020/day22/README.org
Normal 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
315
2020/day22/aoc-c.c
Normal file
@@ -0,0 +1,315 @@
|
||||
/* aoc-c.c: Advent2020, day 22, parts 1 & 2
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "hashtable.h"
|
||||
#include "list.h"
|
||||
#include "pool.h"
|
||||
|
||||
typedef struct card {
|
||||
u8 card; /* card value */
|
||||
struct list_head list; /* list of cards */
|
||||
} card_t;
|
||||
|
||||
typedef struct player {
|
||||
int ncards; /* player cards # */
|
||||
struct list_head head; /* head of cards list */
|
||||
} player_t;
|
||||
|
||||
/* zobrist hash used to find duplicate positions
|
||||
*/
|
||||
typedef struct hash {
|
||||
u32 zobrist;
|
||||
struct list_head players[2];
|
||||
struct hlist_node hlist;
|
||||
} hash_t;
|
||||
|
||||
#define HBITS 10 /* 10 bits: hash size is 1024 */
|
||||
#define CARDS 50
|
||||
|
||||
pool_t *pool_cards;
|
||||
pool_t *pool_hash;
|
||||
static u32 zobrist_table[2][CARDS][CARDS];
|
||||
|
||||
static void zobrist_init()
|
||||
{
|
||||
for (int i = 0; i < 2; ++i)
|
||||
for (int j = 0; j < 50; ++j)
|
||||
for (int k = 0; k < 50; ++k)
|
||||
zobrist_table[i][j][k] = rand();
|
||||
}
|
||||
|
||||
static u32 zobrist(player_t *players)
|
||||
{
|
||||
u32 zobrist = 0;
|
||||
card_t *card;
|
||||
|
||||
for (int p = 0; p < 2; ++p) {
|
||||
int pos = 0;
|
||||
list_for_each_entry(card, &players[p].head, list) {
|
||||
zobrist ^= zobrist_table[p][pos][card->card - 1];
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
return zobrist;
|
||||
}
|
||||
|
||||
static __always_inline u32 hash(u32 h)
|
||||
{
|
||||
return hash_32(h, HBITS);
|
||||
}
|
||||
|
||||
static int equal_decks(hash_t *hasht, player_t *new)
|
||||
{
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
card_t *c1 = list_first_entry_or_null(&hasht->players[i], card_t, list);
|
||||
card_t *c2 = list_first_entry_or_null(&new[i].head, card_t, list);
|
||||
|
||||
if (!c1 || !c2) /* one list (only) is empty */
|
||||
return 0;
|
||||
|
||||
while (!list_entry_is_head(c1, &hasht->players[i], list) &&
|
||||
!list_entry_is_head(c2, &new[i].head, list) &&
|
||||
c1->card == c2->card) {
|
||||
if (c1->card != c2->card)
|
||||
return 0;
|
||||
c1 = list_next_entry(c1, list);
|
||||
c2 = list_next_entry(c2, list);
|
||||
}
|
||||
if (!list_entry_is_head(c1, &hasht->players[i], list) ||
|
||||
!list_entry_is_head(c2, &new[i].head, list))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static hash_t *create_hash(player_t *players, u32 h)
|
||||
{
|
||||
struct card *card;
|
||||
hash_t *hash = pool_get(pool_hash);
|
||||
INIT_HLIST_NODE(&hash->hlist);
|
||||
hash->zobrist = h;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
INIT_LIST_HEAD(&hash->players[i]);
|
||||
list_for_each_entry(card, &players[i].head, list) {
|
||||
struct card *new = pool_get(pool_cards);
|
||||
new->card = card->card;
|
||||
list_add_tail(&new->list, &hash->players[i]);
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
static player_t *create_subgame(player_t *from, player_t *to)
|
||||
{
|
||||
struct card *card;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
int n = 0, ncards;
|
||||
|
||||
to[i].ncards = from[i].ncards - 1;
|
||||
INIT_LIST_HEAD(&to[i].head);
|
||||
list_for_each_entry(card, &from[i].head, list) {
|
||||
if (!n) {
|
||||
to[i].ncards = ncards = card->card;
|
||||
} else {
|
||||
struct card *new = pool_get(pool_cards);
|
||||
new->card = card->card;
|
||||
list_add_tail(&new->list, &to[i].head);
|
||||
if (!--ncards)
|
||||
break;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return to;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_deck - find deck in an hashtable bucket
|
||||
*/
|
||||
static hash_t *find_deck(struct hlist_head *hasht, player_t *players)
|
||||
{
|
||||
hash_t *cur;
|
||||
u32 z = zobrist(players);
|
||||
u32 h = hash(z);
|
||||
hlist_for_each_entry(cur, hasht + h, hlist) {
|
||||
if (cur->zobrist == z && equal_decks(cur, players))
|
||||
return cur;
|
||||
}
|
||||
cur = create_hash(players, z);
|
||||
hlist_add_head(&cur->hlist, &hasht[h]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static player_t *parse(player_t *players)
|
||||
{
|
||||
size_t alloc;
|
||||
ssize_t len;
|
||||
char *buf = NULL;
|
||||
int player = 0;
|
||||
struct card *card;
|
||||
|
||||
INIT_LIST_HEAD(&players[0].head);
|
||||
INIT_LIST_HEAD(&players[1].head);
|
||||
players[0].ncards = players[1].ncards = 0;
|
||||
while ((len = getline(&buf, &alloc, stdin)) > 0) {
|
||||
buf[--len] = 0;
|
||||
if (len == 0) {
|
||||
player++;
|
||||
continue;
|
||||
}
|
||||
if (isdigit(*buf)) { /* card */
|
||||
card = pool_get(pool_cards);
|
||||
card->card = atoi(buf);
|
||||
players[player].ncards++;
|
||||
list_add_tail(&card->list, &players[player].head);
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
return players;
|
||||
}
|
||||
|
||||
static int usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-d debug_level] [-p part]\n", prg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void winmove(player_t *winner, player_t *loser)
|
||||
{
|
||||
card_t *win, *lose;
|
||||
|
||||
win = list_first_entry(&winner->head, struct card, list);
|
||||
lose = list_first_entry(&loser->head, struct card, list);
|
||||
list_move_tail(&win->list, &winner->head);
|
||||
list_move_tail(&lose->list, &winner->head);
|
||||
loser->ncards--;
|
||||
winner->ncards++;
|
||||
}
|
||||
|
||||
static long calc_result(player_t *players)
|
||||
{
|
||||
/* we don't need to check for winner, as one list is empty */
|
||||
card_t *card;
|
||||
long res = 0, mult = 1;
|
||||
list_for_each_entry_reverse(card, &players[0].head, list)
|
||||
res += card->card * mult++;
|
||||
list_for_each_entry_reverse(card, &players[1].head, list)
|
||||
res += card->card * mult++;
|
||||
return res;
|
||||
}
|
||||
|
||||
static long part1(player_t *players)
|
||||
{
|
||||
int round = 0, winner = 0;
|
||||
|
||||
while (players[0].ncards > 0 && players[1].ncards > 0) {
|
||||
int val[2];
|
||||
/* we can use list_first_entry() macro, as both lists are not empty */
|
||||
val[0] = list_first_entry(&players[0].head, struct card, list)->card;
|
||||
val[1] = list_first_entry(&players[1].head, struct card, list)->card;
|
||||
winner = val[1] > val[0];
|
||||
winmove(players + winner, players + 1 - winner);
|
||||
round++;
|
||||
}
|
||||
return calc_result(players);
|
||||
}
|
||||
|
||||
static long part2(player_t *players)
|
||||
{
|
||||
int round = 1, winner = 0, game;
|
||||
long res = 0;
|
||||
static int maxgame = 0;
|
||||
DEFINE_HASHTABLE(hasht_deck, HBITS); /* htable for dup decks */
|
||||
game = ++maxgame;
|
||||
|
||||
while (players[0].ncards > 0 && players[1].ncards > 0) {
|
||||
int val[2];
|
||||
winner = 0;
|
||||
|
||||
if (find_deck(hasht_deck, players)) /* duplicate */
|
||||
goto end;
|
||||
|
||||
/* we can use list_first_entry() macro, as both lists are not empty */
|
||||
val[0] = list_first_entry(&players[0].head, struct card, list)->card;
|
||||
val[1] = list_first_entry(&players[1].head, struct card, list)->card;
|
||||
|
||||
if (players[0].ncards > val[0] && players[1].ncards > val[1]) {
|
||||
player_t sub[2];
|
||||
winner = part2(create_subgame(players, sub));
|
||||
} else {
|
||||
winner = val[1] > val[0];
|
||||
}
|
||||
winmove(players + winner, players + 1 - winner);
|
||||
round++;
|
||||
}
|
||||
end:
|
||||
if (game == 1)
|
||||
res = calc_result(players);
|
||||
|
||||
/* cleanup decks */
|
||||
card_t *card, *tmp1;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
list_for_each_entry_safe(card, tmp1, &players[i].head, list) {
|
||||
list_del(&card->list);
|
||||
pool_add(pool_cards, card);
|
||||
}
|
||||
}
|
||||
|
||||
/* cleanup hashtable */
|
||||
ulong bkt;
|
||||
struct hlist_node *tmp2;
|
||||
hash_t *obj;
|
||||
hash_for_each_safe(hasht_deck, bkt, tmp2, obj, hlist) {
|
||||
/* cleanup hash decks */
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
list_for_each_entry_safe(card, tmp1, &obj->players[i], list) {
|
||||
list_del(&card->list);
|
||||
pool_add(pool_cards, card);
|
||||
}
|
||||
}
|
||||
hlist_del(&obj->hlist);
|
||||
pool_add(pool_hash, obj);
|
||||
}
|
||||
return game == 1? res: winner;
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int opt, part = 1;
|
||||
|
||||
while ((opt = getopt(ac, av, "d:p:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
debug_level_set(atoi(optarg));
|
||||
break;
|
||||
case 'p': /* 1 or 2 */
|
||||
part = atoi(optarg);
|
||||
if (part < 1 || part > 2)
|
||||
default:
|
||||
return usage(*av);
|
||||
}
|
||||
}
|
||||
|
||||
pool_cards = pool_create("cards", 4096, sizeof(struct card));
|
||||
pool_hash = pool_create("hash", 128, sizeof(struct hash));
|
||||
zobrist_init();
|
||||
player_t players[2];
|
||||
parse(players);
|
||||
|
||||
long res = part == 1 ? part1(players): part2(players);
|
||||
|
||||
printf("%s : res=%ld\n", *av, res);
|
||||
pool_destroy(pool_hash);
|
||||
pool_destroy(pool_cards);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,30 +1,108 @@
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
CFLAGS := -w -g
|
||||
#CFLAGS := -w -g -pg
|
||||
#CFLAGS := -w -O3
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with this
|
||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
BEAR := bear
|
||||
CCLSFILE:= compile_commands.json
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
# CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile deploy ex1 ex2
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 ccls
|
||||
|
||||
all: ex1 ex2
|
||||
all: README.org ccls ex1 ex2
|
||||
|
||||
output:
|
||||
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
compile: ex1-c ex2-c
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex1:
|
||||
@$(TIME) ex1.bash < $(INPUT) 2>&1
|
||||
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
ex2:
|
||||
@$(TIME) ex2.bash < $(INPUT) 2>&1
|
||||
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1
|
||||
compile: aoc-c
|
||||
|
||||
cpp: aoc-c.i
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) ex1.bash -p 1 < $(INPUT)
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) ex2.bash -p 2 < $(INPUT)
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
ccls: $(CCLSFILE)
|
||||
|
||||
clean:
|
||||
@rm -f ex1-c ex2-c core
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
|
||||
|
||||
deploy:
|
||||
@$(MAKE) -C .. deploy
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
||||
|
||||
# generate compile_commands.json
|
||||
$(CCLSFILE): aoc-c.c Makefile
|
||||
$(BEAR) -- make clean compile
|
||||
|
||||
bear: clean
|
||||
@$(BEAR) -- make compile
|
||||
@touch .ccls-root
|
||||
|
||||
@@ -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
137
2020/day23/README.org
Normal 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
115
2020/day23/aoc-c.c
Normal 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);
|
||||
}
|
||||
@@ -6,7 +6,7 @@ CMD=${0##*/}
|
||||
shopt -s extglob
|
||||
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
|
||||
|
||||
read -r str
|
||||
@@ -27,9 +27,8 @@ done
|
||||
next[$_cup]=$cup # close the ring
|
||||
|
||||
_cup=$cup
|
||||
|
||||
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
|
||||
_1st="${next[$cup]}"
|
||||
_2nd="${next[$_1st]}"
|
||||
|
||||
@@ -33,6 +33,7 @@ next[$_cup]=$cup # close the ring
|
||||
|
||||
_cup=$cup
|
||||
declare -i _1st _2nd _3rd dest
|
||||
# make the moves: a simple sub linked list operation.
|
||||
for ((i = 1; i <= runs; ++i)); do
|
||||
_1st="${next[$cup]}"
|
||||
_2nd="${next[$_1st]}"
|
||||
|
||||
@@ -1,30 +1,108 @@
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
CFLAGS := -w -g
|
||||
#CFLAGS := -w -g -pg
|
||||
#CFLAGS := -w -O3
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with this
|
||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
BEAR := bear
|
||||
CCLSFILE:= compile_commands.json
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
# CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile deploy ex1 ex2
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 ccls
|
||||
|
||||
all: ex1 ex2
|
||||
all: README.org ccls ex1 ex2
|
||||
|
||||
output:
|
||||
@$(MAKE) --no-print-directory all 2>&1 > OUTPUT
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
compile: ex1-c ex2-c
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex1:
|
||||
@$(TIME) ex1.bash < $(INPUT) 2>&1
|
||||
@#$(TIME) ex1-c 2020 < $(INPUT) 2>&1
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
ex2:
|
||||
@$(TIME) ex2.bash < $(INPUT) 2>&1
|
||||
@#$(TIME) ex1-c 30000000 < $(INPUT) 2>&1
|
||||
compile: aoc-c
|
||||
|
||||
cpp: aoc-c.i
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) ex1.bash -p 1 < $(INPUT)
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) ex2.bash -p 2 < $(INPUT)
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
ccls: $(CCLSFILE)
|
||||
|
||||
clean:
|
||||
@rm -f ex1-c ex2-c core
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
|
||||
|
||||
deploy:
|
||||
@$(MAKE) -C .. deploy
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
||||
|
||||
# generate compile_commands.json
|
||||
$(CCLSFILE): aoc-c.c Makefile
|
||||
$(BEAR) -- make clean compile
|
||||
|
||||
bear: clean
|
||||
@$(BEAR) -- make compile
|
||||
@touch .ccls-root
|
||||
|
||||
@@ -1,83 +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.
|
||||
|
||||
The first half of this puzzle is complete! It provides one gold star: *
|
||||
--- 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?
|
||||
131
2020/day24/README.org
Normal file
131
2020/day24/README.org
Normal 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
230
2020/day24/aoc-c.c
Normal 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);
|
||||
}
|
||||
@@ -2,6 +2,10 @@
|
||||
#
|
||||
# ex1.bash: Advent2020 game, day 24/game 1.
|
||||
|
||||
# See https://www.redblobgames.com/grids/hexagons/ for hexagon possible
|
||||
# representations.
|
||||
# I use the "doubled-coordinate" system here :
|
||||
# https://www.redblobgames.com/grids/hexagons/#coordinates-doubled
|
||||
CMD=${0##*/}
|
||||
shopt -s extglob
|
||||
set -o noglob
|
||||
|
||||
71
2020/day24/ex2.bash
Executable file
71
2020/day24/ex2.bash
Executable file
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# ex1.bash: Advent2020 game, day 24/game 2.
|
||||
|
||||
# See https://www.redblobgames.com/grids/hexagons/ for hexagon possible
|
||||
# representations.
|
||||
# I use the "doubled-coordinate" system here :
|
||||
# https://www.redblobgames.com/grids/hexagons/#coordinates-doubled
|
||||
CMD=${0##*/}
|
||||
shopt -s extglob
|
||||
set -o noglob
|
||||
|
||||
declare -A plan=() count=()
|
||||
declare -i x y loops=100
|
||||
while read -r line; do
|
||||
x=0
|
||||
y=0
|
||||
for ((i=0; i<${#line}; ++i)); do
|
||||
c=${line:i:1}
|
||||
case "$c" in
|
||||
e) ((++x))
|
||||
;;
|
||||
w) ((--x))
|
||||
;;
|
||||
s) ((--y, ++i))
|
||||
c=${line:i:1}
|
||||
;;
|
||||
n) ((++y, ++i))
|
||||
c=${line:i:1}
|
||||
;;
|
||||
esac
|
||||
if [[ "$c" = e ]]; then
|
||||
((++x))
|
||||
elif [[ "$c" = w ]]; then
|
||||
((--x))
|
||||
else
|
||||
printf "error c=%s\n" "$c"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
[[ -v plan[$x,$y] ]] && unset "plan[$x,$y]" || plan[$x,$y]=1
|
||||
done
|
||||
|
||||
# adjacent cells (x1 y1 x2 y2 etc...)
|
||||
declare -a directions=(
|
||||
2 0 -2 0 # east and west
|
||||
1 -1 1 1 # SE and NE
|
||||
-1 -1 -1 1 # SW and NW
|
||||
)
|
||||
|
||||
for ((_c = 0; _c < loops; ++_c)) do
|
||||
count=()
|
||||
for cell in "${!plan[@]}"; do # count adjacent tiles
|
||||
x=${cell%,*}
|
||||
y=${cell#*,}
|
||||
for ((i = 0; i < ${#directions[@]}; i += 2)); do
|
||||
(( ++count[$((x + directions[$i])),$((y + directions[$((i+1))]))] ))
|
||||
done
|
||||
done
|
||||
for cell in "${!plan[@]}"; do # check black tiles
|
||||
(( count[$cell] == 0 || count[$cell] > 2)) && unset "plan[$cell]"
|
||||
unset "count[$cell]"
|
||||
done
|
||||
for cell in "${!count[@]}"; do # remaining ones are white
|
||||
((count[$cell] == 2)) && plan[$cell]=1
|
||||
done
|
||||
done
|
||||
|
||||
printf "%s: res=%d\n" "$CMD" "${#plan[@]}"
|
||||
|
||||
exit 0
|
||||
2
2020/day25/INPUT.txt
Normal file
2
2020/day25/INPUT.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
3418282
|
||||
8719412
|
||||
30
2020/day25/Makefile
Normal file
30
2020/day25/Makefile
Normal 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
57
2020/day25/README
Normal 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
2
2020/day25/TEST.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
5764801
|
||||
17807724
|
||||
31
2020/day25/ex1-c.c
Normal file
31
2020/day25/ex1-c.c
Normal 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
22
2020/day25/ex1.bash
Executable 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
523
2020/include/bits.h
Normal 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
211
2020/include/br.h
Normal 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
71
2020/include/bug.h
Normal 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 */
|
||||
30
2020/include/container-of.h
Normal file
30
2020/include/container-of.h
Normal 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
98
2020/include/debug.h
Normal 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
173
2020/include/hash.h
Normal 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
203
2020/include/hashtable.h
Normal 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
18
2020/include/likely.h
Normal 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
1015
2020/include/list.h
Normal file
File diff suppressed because it is too large
Load Diff
90
2020/include/pool.h
Normal file
90
2020/include/pool.h
Normal 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
128
2020/include/rwonce.h
Normal 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
112
2020/libsrc/debug.c
Normal 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
219
2020/libsrc/pool.c
Normal 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
87
2022/Makefile
Normal 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
317
2022/RESULTS.txt
Normal 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
111
2022/day01/Makefile
Normal 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
89
2022/day01/README.org
Normal 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
77
2022/day01/aoc-c.c
Normal 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
56
2022/day01/aoc.bash
Executable 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
17
2022/day01/aoc.h
Normal 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
68
2022/day01/common.bash
Executable 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
49
2022/day01/common.c
Normal 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;
|
||||
}
|
||||
14
2022/day01/input/example.txt
Normal file
14
2022/day01/input/example.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
1000
|
||||
2000
|
||||
3000
|
||||
|
||||
4000
|
||||
|
||||
5000
|
||||
6000
|
||||
|
||||
7000
|
||||
8000
|
||||
9000
|
||||
|
||||
10000
|
||||
2255
2022/day01/input/input.txt
Normal file
2255
2022/day01/input/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
111
2022/day02/Makefile
Normal file
111
2022/day02/Makefile
Normal 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
89
2022/day02/README.org
Normal 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
64
2022/day02/aoc-c.c
Normal 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
42
2022/day02/aoc.bash
Executable 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
17
2022/day02/aoc.h
Normal 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
68
2022/day02/common.bash
Executable 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
49
2022/day02/common.c
Normal 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;
|
||||
}
|
||||
3
2022/day02/input/example.txt
Normal file
3
2022/day02/input/example.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
A Y
|
||||
B X
|
||||
C Z
|
||||
2500
2022/day02/input/input.txt
Normal file
2500
2022/day02/input/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
111
2022/day03/Makefile
Normal file
111
2022/day03/Makefile
Normal 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
114
2022/day03/README.org
Normal 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
97
2022/day03/aoc-c.c
Normal 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
86
2022/day03/aoc.bash
Executable 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
Reference in New Issue
Block a user