Compare commits
183 Commits
0ce9f9aafa
...
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 | |||
| 563798871a | |||
| cced357154 | |||
| 4653101623 | |||
| 0fb3d8832f | |||
| c30ca858e4 | |||
| cd41685cb5 | |||
| d2d66dc763 | |||
| 284eeb3dea | |||
| f74a1ffb8a | |||
| b001690c95 | |||
| 0fe04e43dc | |||
| bd851b6524 | |||
|
|
1cfd1c81f0 | ||
|
|
130f2a4d54 | ||
| 625966f5b8 | |||
| 521e6e1bca | |||
| bacbc6eded | |||
| 5694883ef5 | |||
| 6a43725e30 | |||
| 4d938b6cd7 | |||
| 0c9b93b42a | |||
| 04fcca5829 | |||
| ddfa8cf05b | |||
| 5008963937 | |||
| 155e066ed2 | |||
| 626bd1df41 | |||
| 8ed39e52b7 | |||
| e83b690822 | |||
| 0004b2091e | |||
| a201283599 | |||
| d5c37f5d48 | |||
| 1c10926cf9 | |||
| 94c6b2eec5 | |||
| b50f3a7098 | |||
| 8783eca22c | |||
| 3d18e36ff4 | |||
| b6af1f3edb | |||
|
|
68d81fd1da | ||
|
|
b206ee5b87 | ||
|
|
13c977957f | ||
|
|
d0adb2378a | ||
| d1221ab086 | |||
| f2b32f236d | |||
| 696273367a | |||
| f7336d6814 | |||
| a461bf2842 |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -2,6 +2,8 @@ ex*-c
|
||||
aoc-c
|
||||
core*
|
||||
.ccls*
|
||||
.projectile
|
||||
.dir-locals.el
|
||||
gmon.out
|
||||
*.o
|
||||
ex*-cob
|
||||
@@ -9,8 +11,5 @@ lib/
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
2020/day23/
|
||||
FOO*
|
||||
BAR*
|
||||
QUAX*
|
||||
TOTO*
|
||||
README.html
|
||||
compile_commands.json
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
((nil . ((eval . (let ((root (expand-file-name (projectile-project-root))))
|
||||
(setq-local
|
||||
flycheck-gcc-include-path (list (concat root "include"))
|
||||
compile-command (concat "make -C " root " all")))))))
|
||||
@@ -1,6 +1,6 @@
|
||||
# AOC Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021 Bruno Raoult ("br")
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
|
||||
@@ -46,10 +46,87 @@ aoc-c : res=9238
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c : res=2090
|
||||
time: 0:00.01 real, 0.01 user, 0.00 sys
|
||||
context-switch: 2+1, page-faults: 0+88
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+90
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
aoc-c : res=1419
|
||||
time: 0:00.01 real, 0.00 user, 0.00 sys
|
||||
context-switch: 3+1, page-faults: 0+91
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+89
|
||||
|
||||
=========================================
|
||||
================= day05 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c : res=10987514
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+87
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
aoc-c : res=14195011
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+87
|
||||
|
||||
=========================================
|
||||
================= day06 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
compiling aoc-c.c
|
||||
aoc-c : res=453028
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+417
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
aoc-c : res=562
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+417
|
||||
|
||||
=========================================
|
||||
================= day07 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c : res=65464
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+94
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
aoc-c : res=1518124
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+94
|
||||
|
||||
=========================================
|
||||
================= day08 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c : res=2250
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+93
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
#### # # ## # # #
|
||||
# # # # # # #
|
||||
### #### # # # #
|
||||
# # # # # # #
|
||||
# # # # # # # #
|
||||
# # # ## ## ####
|
||||
aoc-c : res=0
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+90
|
||||
|
||||
=========================================
|
||||
================= day09 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c : res=2682107844
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+92
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
aoc-c : res=34738
|
||||
time: 0:00.01 real, 0.01 user, 0.00 sys
|
||||
context-switch: 1+1, page-faults: 0+95
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021 Bruno Raoult ("br")
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
@@ -24,7 +24,7 @@ LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu99
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
@@ -41,7 +41,8 @@ CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := -q -s --leak-check=full --show-leak-kinds=all --track-origins=yes
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 1 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 2021 Bruno Raoult ("br")
|
||||
* Copyright (C) 2022 Bruno Raoult ("br")
|
||||
* Licensed under the GNU General Public License v3.0 or later.
|
||||
* Some rights reserved. See COPYING.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021 Bruno Raoult ("br")
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
@@ -24,7 +24,7 @@ LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu99
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
@@ -41,7 +41,8 @@ CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := -q -s --leak-check=full --show-leak-kinds=all --track-origins=yes
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 2 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 2021 Bruno Raoult ("br")
|
||||
* Copyright (C) 2022 Bruno Raoult ("br")
|
||||
* Licensed under the GNU General Public License v3.0 or later.
|
||||
* Some rights reserved. See COPYING.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021 Bruno Raoult ("br")
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
@@ -24,7 +24,7 @@ LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu99
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
@@ -41,7 +41,8 @@ CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := -q -s --leak-check=full --show-leak-kinds=all --track-origins=yes
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 3 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 2021 Bruno Raoult ("br")
|
||||
* Copyright (C) 2022 Bruno Raoult ("br")
|
||||
* Licensed under the GNU General Public License v3.0 or later.
|
||||
* Some rights reserved. See COPYING.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021 Bruno Raoult ("br")
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
@@ -24,7 +24,7 @@ LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu99
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 3 parts 1 & 2
|
||||
/* aoc-c.c: Advent of Code 2019, day 4 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 2021 Bruno Raoult ("br")
|
||||
* Copyright (C) 2022 Bruno Raoult ("br")
|
||||
* Licensed under the GNU General Public License v3.0 or later.
|
||||
* Some rights reserved. See COPYING.
|
||||
*
|
||||
@@ -18,17 +18,45 @@
|
||||
#include <getopt.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "likely.h"
|
||||
|
||||
static int is_valid(int number, int part)
|
||||
/**
|
||||
* next_number() - finds next suitable number after a faulty right digit
|
||||
* @number: the number
|
||||
* @faulty: the faulty digit position (1, 10, 100, etc...)
|
||||
* @left: the left digit of faulty one
|
||||
*
|
||||
* This function is called when rule 4 is violated:
|
||||
* "Going from left to right, the digits never decrease."
|
||||
* Example: 453456
|
||||
* ^
|
||||
* Here we will replace the faulty digit and next ones with its left digit
|
||||
* value (5 here). Returned number will be 455555.
|
||||
* This function allowed to save 546,495/548,022 calls to is_valid(), which
|
||||
* is 99.7%.
|
||||
*/
|
||||
static int next_number(int number, int faulty, int left)
|
||||
{
|
||||
int valid = 0, dups[10] = { 0 };
|
||||
int digit, dec;
|
||||
int next = number - number % (faulty * 10);
|
||||
|
||||
for (digit = number % 10; number > 10; digit = dec) {
|
||||
for (; faulty; faulty /= 10)
|
||||
next += left * faulty;
|
||||
return next;
|
||||
}
|
||||
|
||||
static int is_valid(int number, int part, int *next)
|
||||
{
|
||||
int valid = 0, dups[10] = { 0 }, work = number;
|
||||
int digit, dec = number + 1, faulty = 1;
|
||||
*next = number + 1;
|
||||
|
||||
for (digit = number % 10; number > 10; digit = dec, faulty *= 10) {
|
||||
number /= 10;
|
||||
dec = number % 10;
|
||||
if (dec > digit)
|
||||
if (dec > digit) {
|
||||
*next = next_number(work, faulty, dec);
|
||||
return 0;
|
||||
}
|
||||
if (dec == digit) {
|
||||
valid = 1;
|
||||
dups[digit] += 2;
|
||||
@@ -44,13 +72,12 @@ static int is_valid(int number, int part)
|
||||
|
||||
static int doit(int *nums, int part)
|
||||
{
|
||||
int res = 0;
|
||||
int res = 0, next = 0;
|
||||
|
||||
/* There is surely a way to avoid 99% of useless calls to is_valid.
|
||||
*/
|
||||
for (int i = nums[0]; i < nums[1]; ++i)
|
||||
if (is_valid(i, part))
|
||||
for (int i = nums[0]; i < nums[1]; i = next) {
|
||||
if (unlikely(is_valid(i, part, &next)))
|
||||
res++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
1
2019/day05/EXAMPLE.txt
Normal file
1
2019/day05/EXAMPLE.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,0,4,0,99
|
||||
1
2019/day05/EXAMPLE1.txt
Normal file
1
2019/day05/EXAMPLE1.txt
Normal file
@@ -0,0 +1 @@
|
||||
1002,4,3,4,33
|
||||
1
2019/day05/EXAMPLE2.txt
Normal file
1
2019/day05/EXAMPLE2.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,9,8,9,10,9,4,9,99,-1,8
|
||||
1
2019/day05/EXAMPLE3.txt
Normal file
1
2019/day05/EXAMPLE3.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,9,7,9,10,9,4,9,99,-1,8
|
||||
1
2019/day05/EXAMPLE4.txt
Normal file
1
2019/day05/EXAMPLE4.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,3,1108,-1,8,3,4,3,99
|
||||
1
2019/day05/EXAMPLE5.txt
Normal file
1
2019/day05/EXAMPLE5.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,3,1107,-1,8,3,4,3,99
|
||||
1
2019/day05/EXAMPLE6.txt
Normal file
1
2019/day05/EXAMPLE6.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9
|
||||
1
2019/day05/EXAMPLE7.txt
Normal file
1
2019/day05/EXAMPLE7.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,3,1105,-1,9,1101,0,0,12,4,12,99,1
|
||||
1
2019/day05/EXAMPLE8.txt
Normal file
1
2019/day05/EXAMPLE8.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99
|
||||
1
2019/day05/INPUT.txt
Normal file
1
2019/day05/INPUT.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,225,1,225,6,6,1100,1,238,225,104,0,1101,86,8,225,1101,82,69,225,101,36,65,224,1001,224,-106,224,4,224,1002,223,8,223,1001,224,5,224,1,223,224,223,102,52,148,224,101,-1144,224,224,4,224,1002,223,8,223,101,1,224,224,1,224,223,223,1102,70,45,225,1002,143,48,224,1001,224,-1344,224,4,224,102,8,223,223,101,7,224,224,1,223,224,223,1101,69,75,225,1001,18,85,224,1001,224,-154,224,4,224,102,8,223,223,101,2,224,224,1,224,223,223,1101,15,59,225,1102,67,42,224,101,-2814,224,224,4,224,1002,223,8,223,101,3,224,224,1,223,224,223,1101,28,63,225,1101,45,22,225,1101,90,16,225,2,152,92,224,1001,224,-1200,224,4,224,102,8,223,223,101,7,224,224,1,223,224,223,1101,45,28,224,1001,224,-73,224,4,224,1002,223,8,223,101,7,224,224,1,224,223,223,1,14,118,224,101,-67,224,224,4,224,1002,223,8,223,1001,224,2,224,1,223,224,223,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,7,677,677,224,102,2,223,223,1005,224,329,1001,223,1,223,1008,226,226,224,1002,223,2,223,1005,224,344,1001,223,1,223,1107,677,226,224,1002,223,2,223,1006,224,359,1001,223,1,223,107,677,677,224,102,2,223,223,1005,224,374,101,1,223,223,1108,677,226,224,102,2,223,223,1005,224,389,1001,223,1,223,1007,677,677,224,1002,223,2,223,1005,224,404,101,1,223,223,1008,677,226,224,102,2,223,223,1005,224,419,101,1,223,223,1108,226,677,224,102,2,223,223,1006,224,434,1001,223,1,223,8,677,226,224,1002,223,2,223,1005,224,449,101,1,223,223,1008,677,677,224,1002,223,2,223,1006,224,464,1001,223,1,223,1108,226,226,224,1002,223,2,223,1005,224,479,1001,223,1,223,1007,226,677,224,102,2,223,223,1005,224,494,1001,223,1,223,1007,226,226,224,102,2,223,223,1005,224,509,101,1,223,223,107,677,226,224,1002,223,2,223,1006,224,524,1001,223,1,223,108,677,677,224,102,2,223,223,1006,224,539,101,1,223,223,7,677,226,224,102,2,223,223,1006,224,554,1001,223,1,223,1107,226,677,224,102,2,223,223,1005,224,569,101,1,223,223,108,677,226,224,1002,223,2,223,1006,224,584,101,1,223,223,108,226,226,224,102,2,223,223,1006,224,599,1001,223,1,223,1107,226,226,224,102,2,223,223,1006,224,614,1001,223,1,223,8,226,677,224,102,2,223,223,1006,224,629,1001,223,1,223,107,226,226,224,102,2,223,223,1005,224,644,101,1,223,223,8,226,226,224,102,2,223,223,1006,224,659,101,1,223,223,7,226,677,224,102,2,223,223,1005,224,674,101,1,223,223,4,223,99,226
|
||||
93
2019/day05/Makefile
Normal file
93
2019/day05/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with this
|
||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
||||
184
2019/day05/README.org
Normal file
184
2019/day05/README.org
Normal file
@@ -0,0 +1,184 @@
|
||||
** --- Day 5: Sunny with a Chance of Asteroids ---
|
||||
You're starting to sweat as the ship makes its way toward Mercury. The
|
||||
Elves suggest that you get the air conditioner working by upgrading your
|
||||
ship computer to support the Thermal Environment Supervision Terminal.
|
||||
|
||||
The Thermal Environment Supervision Terminal (TEST) starts by running a
|
||||
/diagnostic program/ (your puzzle input). The TEST diagnostic program
|
||||
will run on [[file:~/dev/advent-of-code/2019/day02][your existing Intcode computer]] after a few
|
||||
modifications:
|
||||
|
||||
/First/, you'll need to add /two new instructions/:
|
||||
|
||||
- Opcode =3= takes a single integer as /input/ and saves it to the
|
||||
position given by its only parameter. For example, the instruction
|
||||
=3,50= would take an input value and store it at address =50=.
|
||||
- Opcode =4= /outputs/ the value of its only parameter. For example, the
|
||||
instruction =4,50= would output the value at address =50=.
|
||||
|
||||
Programs that use these instructions will come with documentation that
|
||||
explains what should be connected to the input and output. The program
|
||||
=3,0,4,0,99= outputs whatever it gets as input, then halts.
|
||||
|
||||
/Second/, you'll need to add support for /parameter modes/:
|
||||
|
||||
Each parameter of an instruction is handled based on its parameter mode.
|
||||
Right now, your ship computer already understands parameter mode =0=,
|
||||
/position mode/, which causes the parameter to be interpreted as a
|
||||
/position/ - if the parameter is =50=, its value is /the value stored at
|
||||
address =50= in memory/. Until now, all parameters have been in position
|
||||
mode.
|
||||
|
||||
Now, your ship computer will also need to handle parameters in mode =1=,
|
||||
/immediate mode/. In immediate mode, a parameter is interpreted as a
|
||||
/value/ - if the parameter is =50=, its value is simply /=50=/.
|
||||
|
||||
Parameter modes are stored in the same value as the instruction's
|
||||
opcode. The opcode is a two-digit number based only on the ones and tens
|
||||
digit of the value, that is, the opcode is the rightmost two digits of
|
||||
the first value in an instruction. Parameter modes are single digits,
|
||||
one per parameter, read right-to-left from the opcode: the first
|
||||
parameter's mode is in the hundreds digit, the second parameter's mode
|
||||
is in the thousands digit, the third parameter's mode is in the
|
||||
ten-thousands digit, and so on. Any missing modes are =0=.
|
||||
|
||||
For example, consider the program =1002,4,3,4,33=.
|
||||
|
||||
The first instruction, =1002,4,3,4=, is a /multiply/ instruction - the
|
||||
rightmost two digits of the first value, =02=, indicate opcode =2=,
|
||||
multiplication. Then, going right to left, the parameter modes are =0=
|
||||
(hundreds digit), =1= (thousands digit), and =0= (ten-thousands digit,
|
||||
not present and therefore zero):
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
ABCDE
|
||||
1002
|
||||
|
||||
DE - two-digit opcode, 02 == opcode 2
|
||||
C - mode of 1st parameter, 0 == position mode
|
||||
B - mode of 2nd parameter, 1 == immediate mode
|
||||
A - mode of 3rd parameter, 0 == position mode,
|
||||
omitted due to being a leading zero
|
||||
#+END_EXAMPLE
|
||||
|
||||
This instruction multiplies its first two parameters. The first
|
||||
parameter, =4= in position mode, works like it did before - its value is
|
||||
the value stored at address =4= (=33=). The second parameter, =3= in
|
||||
immediate mode, simply has value =3=. The result of this operation,
|
||||
=33 * 3 = 99=, is written according to the third parameter, =4= in
|
||||
position mode, which also works like it did before - =99= is written to
|
||||
address =4=.
|
||||
|
||||
Parameters that an instruction writes to will /never be in immediate
|
||||
mode/.
|
||||
|
||||
/Finally/, some notes:
|
||||
|
||||
- It is important to remember that the instruction pointer should
|
||||
increase by /the number of values in the instruction/ after the
|
||||
instruction finishes. Because of the new instructions, this amount is
|
||||
no longer always =4=.
|
||||
- Integers can be negative: =1101,100,-1,4,0= is a valid program (find
|
||||
=100 + -1=, store the result in position =4=).
|
||||
|
||||
The TEST diagnostic program will start by requesting from the user the
|
||||
ID of the system to test by running an /input/ instruction - provide it
|
||||
=1=, the ID for the ship's air conditioner unit.
|
||||
|
||||
It will then perform a series of diagnostic tests confirming that
|
||||
various parts of the Intcode computer, like parameter modes, function
|
||||
correctly. For each test, it will run an /output/ instruction indicating
|
||||
how far the result of the test was from the expected value, where =0=
|
||||
means the test was successful. Non-zero outputs mean that a function is
|
||||
not working correctly; check the instructions that were run before the
|
||||
output instruction to see which one failed.
|
||||
|
||||
Finally, the program will output a /diagnostic code/ and immediately
|
||||
halt. This final output isn't an error; an output followed immediately
|
||||
by a halt means the program finished. If all outputs were zero except
|
||||
the diagnostic code, the diagnostic program ran successfully.
|
||||
|
||||
After providing =1= to the only input instruction and passing all the
|
||||
tests, /what diagnostic code does the program produce?/
|
||||
|
||||
Your puzzle answer was =10987514=.
|
||||
|
||||
** --- Part Two ---
|
||||
The air conditioner comes online! Its cold air feels good for a while,
|
||||
but then the TEST alarms start to go off. Since the air conditioner
|
||||
can't vent its heat anywhere but back into the spacecraft, it's actually
|
||||
making the air inside the ship /warmer/.
|
||||
|
||||
Instead, you'll need to use the TEST to extend the
|
||||
[[https://en.wikipedia.org/wiki/Spacecraft_thermal_control][thermal
|
||||
radiators]]. Fortunately, the diagnostic program (your puzzle input) is
|
||||
already equipped for this. Unfortunately, your Intcode computer is not.
|
||||
|
||||
Your computer is only missing a few opcodes:
|
||||
|
||||
- Opcode =5= is /jump-if-true/: if the first parameter is /non-zero/, it
|
||||
sets the instruction pointer to the value from the second parameter.
|
||||
Otherwise, it does nothing.
|
||||
- Opcode =6= is /jump-if-false/: if the first parameter /is zero/, it
|
||||
sets the instruction pointer to the value from the second parameter.
|
||||
Otherwise, it does nothing.
|
||||
- Opcode =7= is /less than/: if the first parameter is /less than/ the
|
||||
second parameter, it stores =1= in the position given by the third
|
||||
parameter. Otherwise, it stores =0=.
|
||||
- Opcode =8= is /equals/: if the first parameter is /equal to/ the
|
||||
second parameter, it stores =1= in the position given by the third
|
||||
parameter. Otherwise, it stores =0=.
|
||||
|
||||
Like all instructions, these instructions need to support /parameter
|
||||
modes/ as described above.
|
||||
|
||||
Normally, after an instruction is finished, the instruction pointer
|
||||
increases by the number of values in that instruction. /However/, if the
|
||||
instruction modifies the instruction pointer, that value is used and the
|
||||
instruction pointer is /not automatically increased/.
|
||||
|
||||
For example, here are several programs that take one input, compare it
|
||||
to the value =8=, and then produce one output:
|
||||
|
||||
- =3,9,8,9,10,9,4,9,99,-1,8= - Using /position mode/, consider whether
|
||||
the input is /equal to/ =8=; output =1= (if it is) or =0= (if it is
|
||||
not).
|
||||
- =3,9,7,9,10,9,4,9,99,-1,8= - Using /position mode/, consider whether
|
||||
the input is /less than/ =8=; output =1= (if it is) or =0= (if it is
|
||||
not).
|
||||
- =3,3,1108,-1,8,3,4,3,99= - Using /immediate mode/, consider whether
|
||||
the input is /equal to/ =8=; output =1= (if it is) or =0= (if it is
|
||||
not).
|
||||
- =3,3,1107,-1,8,3,4,3,99= - Using /immediate mode/, consider whether
|
||||
the input is /less than/ =8=; output =1= (if it is) or =0= (if it is
|
||||
not).
|
||||
|
||||
Here are some jump tests that take an input, then output =0= if the
|
||||
input was zero or =1= if the input was non-zero:
|
||||
|
||||
- =3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9= (using /position mode/)
|
||||
- =3,3,1105,-1,9,1101,0,0,12,4,12,99,1= (using /immediate mode/)
|
||||
|
||||
Here's a larger example:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,
|
||||
1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,
|
||||
999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99
|
||||
#+END_EXAMPLE
|
||||
|
||||
The above example program uses an input instruction to ask for a single
|
||||
number. The program will then output =999= if the input value is below
|
||||
=8=, output =1000= if the input value is equal to =8=, or output =1001=
|
||||
if the input value is greater than =8=.
|
||||
|
||||
This time, when the TEST diagnostic program runs its input instruction
|
||||
to get the ID of the system to test, /provide it =5=/, the ID for the
|
||||
ship's thermal radiator controller. This diagnostic test suite only
|
||||
outputs one number, the /diagnostic code/.
|
||||
|
||||
/What is the diagnostic code for system ID =5=?/
|
||||
|
||||
Your puzzle answer was =14195011=.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
||||
162
2019/day05/aoc-c.c
Normal file
162
2019/day05/aoc-c.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 5 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 2022 Bruno Raoult ("br")
|
||||
* Licensed under the GNU General Public License v3.0 or later.
|
||||
* Some rights reserved. See COPYING.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this
|
||||
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "br.h"
|
||||
#include "bits.h"
|
||||
#include "debug.h"
|
||||
|
||||
typedef enum {
|
||||
ADD = 1, MUL = 2,
|
||||
INP = 3, OUT = 4,
|
||||
JMP_T = 5, JMP_F = 6,
|
||||
SET_LT = 7, SET_EQ = 8,
|
||||
HLT = 99
|
||||
} opcode_t;
|
||||
|
||||
/**
|
||||
* ops - array of op-codes, mnemo, and number of parameters
|
||||
* @op: An integer, the opcode
|
||||
* @nargs: Opcode number of parameters (unused)
|
||||
* @jump: Next instruction (usually @nargs + 1)
|
||||
* @mnemo: Opcode mnemo (unused, for debug)
|
||||
*/
|
||||
typedef struct {
|
||||
int op;
|
||||
u8 nargs;
|
||||
u8 jump;
|
||||
char *mnemo;
|
||||
} ops_t;
|
||||
|
||||
#define MAXOPS 1024
|
||||
typedef struct {
|
||||
int length; /* total program length */
|
||||
int cur; /* current position */
|
||||
int mem [MAXOPS]; /* should really be dynamic */
|
||||
} program_t;
|
||||
|
||||
static ops_t ops[] = {
|
||||
[ADD] = { ADD, 3, 4, __stringify(ADD) },
|
||||
[MUL] = { MUL, 3, 4, __stringify(MUL) },
|
||||
[INP] = { INP, 1, 2, __stringify(INP) },
|
||||
[OUT] = { OUT, 1, 2, __stringify(OUT) },
|
||||
[JMP_T] = { JMP_T, 2, 3, __stringify(JMP_T) },
|
||||
[JMP_F] = { JMP_F, 2, 3, __stringify(JMP_F) },
|
||||
[SET_LT] = { SET_LT, 3, 4, __stringify({SET_LT) },
|
||||
[SET_EQ] = { SET_EQ, 3, 4, __stringify(SET_EQ) },
|
||||
[HLT] = { HLT, 0, 1, __stringify(HLT) }
|
||||
};
|
||||
|
||||
|
||||
static int _flag_pow10[] = {1, 100, 1000, 10000};
|
||||
#define OP(p, n) ((p->mem[n]) % 100)
|
||||
#define ISDIRECT(p, n, i) ((((p->mem[n]) / _flag_pow10[i]) % 10))
|
||||
#define DIRECT(p, i) ((p)->mem[i])
|
||||
#define INDIRECT(p, i) (DIRECT(p, DIRECT(p, i)))
|
||||
|
||||
#define peek(p, n, i) (ISDIRECT(p, n, i)? DIRECT(p, n + i): INDIRECT(p, n + i))
|
||||
#define poke(p, n, i, val) do { \
|
||||
INDIRECT(p, n + i) = val; } \
|
||||
while (0)
|
||||
|
||||
static int run(program_t *p, int in)
|
||||
{
|
||||
int out = -1;
|
||||
while (1) {
|
||||
int op = OP(p, p->cur), cur = p->cur;
|
||||
|
||||
if (!(ops[op].op)) {
|
||||
fprintf(stderr, "PANIC: illegal instruction %d at %d.\n", op, p->cur);
|
||||
return -1;
|
||||
}
|
||||
switch (op) {
|
||||
case ADD:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) + peek(p, p->cur, 2));
|
||||
break;
|
||||
case MUL:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) * peek(p, p->cur, 2));
|
||||
break;
|
||||
case INP:
|
||||
poke(p, p->cur, 1, in);
|
||||
break;
|
||||
case OUT:
|
||||
out = peek(p, p->cur, 1);
|
||||
break;
|
||||
case JMP_T:
|
||||
if (peek(p, p->cur, 1))
|
||||
p->cur = peek(p, p->cur, 2);
|
||||
break;
|
||||
case JMP_F:
|
||||
if (!peek(p, p->cur, 1))
|
||||
p->cur = peek(p, p->cur, 2);
|
||||
break;
|
||||
case SET_LT:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) < peek(p, p->cur, 2) ? 1: 0);
|
||||
break;
|
||||
case SET_EQ:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) == peek(p, p->cur, 2) ? 1: 0);
|
||||
break;
|
||||
case HLT:
|
||||
return out;
|
||||
}
|
||||
if (p->cur == cur)
|
||||
p->cur += ops[op].jump;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse(program_t *prog)
|
||||
{
|
||||
while (scanf("%d%*c", &prog->mem[prog->length++]) > 0)
|
||||
;
|
||||
}
|
||||
|
||||
static int usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int opt, part = 1, in = -1;
|
||||
program_t p = { 0 };
|
||||
|
||||
while ((opt = getopt(ac, av, "d:p:i:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
debug_level_set(atoi(optarg));
|
||||
break;
|
||||
case 'i':
|
||||
in = atoi(optarg);
|
||||
break;
|
||||
case 'p': /* 1 or 2 */
|
||||
part = atoi(optarg);
|
||||
if (part < 1 || part > 2)
|
||||
return usage(*av);
|
||||
break;
|
||||
default:
|
||||
return usage(*av);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < ac)
|
||||
return usage(*av);
|
||||
if (in == -1)
|
||||
in = part == 1? 1: 5;
|
||||
parse(&p);
|
||||
printf("%s : res=%d\n", *av, run(&p, in));
|
||||
exit (0);
|
||||
}
|
||||
53
2019/day05/run-examples.sh
Executable file
53
2019/day05/run-examples.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
make compile
|
||||
|
||||
printf "***** EXAMPLE.txt: input value, then output it\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 1 < EXAMPLE.txt
|
||||
printf "Expected: 5\t"
|
||||
./aoc-c -i 5 < EXAMPLE.txt
|
||||
|
||||
printf "\n***** EXAMPLE2.txt: equal test, position mode\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 8 < EXAMPLE2.txt
|
||||
printf "Expected: 0\t"
|
||||
./aoc-c -i 0 < EXAMPLE.txt
|
||||
|
||||
printf "\n***** EXAMPLE3.txt: less than test, position mode\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 7 < EXAMPLE3.txt
|
||||
printf "Expected: 0\t"
|
||||
./aoc-c -i 8 < EXAMPLE3.txt
|
||||
|
||||
printf "\n***** EXAMPLE4.txt: equal test, immediate mode\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 8 < EXAMPLE4.txt
|
||||
printf "Expected: 0\t"
|
||||
./aoc-c -i 0 < EXAMPLE4.txt
|
||||
|
||||
printf "\n***** EXAMPLE5.txt: less than test, immediate mode\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 7 < EXAMPLE5.txt
|
||||
printf "Expected: 0\t"
|
||||
./aoc-c -i 8 < EXAMPLE5.txt
|
||||
|
||||
printf "\n***** EXAMPLE6.txt: equal/jump test, position mode\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 8 < EXAMPLE6.txt
|
||||
printf "Expected: 0\t"
|
||||
./aoc-c -i 0 < EXAMPLE6.txt
|
||||
|
||||
printf "\n***** EXAMPLE7.txt: equal/jump test, immediate mode\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 8 < EXAMPLE7.txt
|
||||
printf "Expected: 0\t"
|
||||
./aoc-c -i 0 < EXAMPLE7.txt
|
||||
|
||||
printf "\n***** EXAMPLE8.txt: equal/less/jump test, mixed mode\n"
|
||||
printf "Expected:999\t"
|
||||
./aoc-c -i 7 < EXAMPLE8.txt
|
||||
printf "Expected: 1000\t"
|
||||
./aoc-c -i 8 < EXAMPLE8.txt
|
||||
printf "Expected: 1001\t"
|
||||
./aoc-c -i 9 < EXAMPLE8.txt
|
||||
11
2019/day06/EXAMPLE.txt
Normal file
11
2019/day06/EXAMPLE.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
COM)B
|
||||
B)C
|
||||
C)D
|
||||
D)E
|
||||
E)F
|
||||
B)G
|
||||
G)H
|
||||
D)I
|
||||
E)J
|
||||
J)K
|
||||
K)L
|
||||
13
2019/day06/EXAMPLE2.txt
Normal file
13
2019/day06/EXAMPLE2.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
COM)B
|
||||
B)C
|
||||
C)D
|
||||
D)E
|
||||
E)F
|
||||
B)G
|
||||
G)H
|
||||
D)I
|
||||
E)J
|
||||
J)K
|
||||
K)L
|
||||
K)YOU
|
||||
I)SAN
|
||||
2306
2019/day06/INPUT.txt
Normal file
2306
2019/day06/INPUT.txt
Normal file
File diff suppressed because it is too large
Load Diff
93
2019/day06/Makefile
Normal file
93
2019/day06/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with this
|
||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
||||
147
2019/day06/README.org
Normal file
147
2019/day06/README.org
Normal file
@@ -0,0 +1,147 @@
|
||||
** --- Day 6: Universal Orbit Map ---
|
||||
You've landed at the Universal Orbit Map facility on Mercury. Because
|
||||
navigation in space often involves transferring between orbits, the
|
||||
orbit maps here are useful for finding efficient routes between, for
|
||||
example, you and Santa. You download a map of the local orbits (your
|
||||
puzzle input).
|
||||
|
||||
Except for the universal Center of Mass (=COM=), every object in space
|
||||
is in orbit around exactly one other object. An
|
||||
[[https://en.wikipedia.org/wiki/Orbit][orbit]] looks roughly like this:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
\
|
||||
\
|
||||
|
|
||||
|
|
||||
AAA--> o o <--BBB
|
||||
|
|
||||
|
|
||||
/
|
||||
/
|
||||
#+END_EXAMPLE
|
||||
|
||||
In this diagram, the object =BBB= is in orbit around =AAA=. The path
|
||||
that =BBB= takes around =AAA= (drawn with lines) is only partly shown.
|
||||
In the map data, this orbital relationship is written =AAA)BBB=, which
|
||||
means "=BBB= is in orbit around =AAA=".
|
||||
|
||||
Before you use your map data to plot a course, you need to make sure it
|
||||
wasn't corrupted during the download. To verify maps, the Universal
|
||||
Orbit Map facility uses /orbit count checksums/ - the total number of
|
||||
/direct orbits/ (like the one shown above) and /indirect orbits/.
|
||||
|
||||
Whenever =A= orbits =B= and =B= orbits =C=, then =A= /indirectly orbits/
|
||||
=C=. This chain can be any number of objects long: if =A= orbits =B=,
|
||||
=B= orbits =C=, and =C= orbits =D=, then =A= indirectly orbits =D=.
|
||||
|
||||
For example, suppose you have the following map:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
COM)B
|
||||
B)C
|
||||
C)D
|
||||
D)E
|
||||
E)F
|
||||
B)G
|
||||
G)H
|
||||
D)I
|
||||
E)J
|
||||
J)K
|
||||
K)L
|
||||
#+END_EXAMPLE
|
||||
|
||||
Visually, the above map of orbits looks like this:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
G - H J - K - L
|
||||
/ /
|
||||
COM - B - C - D - E - F
|
||||
\
|
||||
I
|
||||
#+END_EXAMPLE
|
||||
|
||||
In this visual representation, when two objects are connected by a line,
|
||||
the one on the right directly orbits the one on the left.
|
||||
|
||||
Here, we can count the total number of orbits as follows:
|
||||
|
||||
- =D= directly orbits =C= and indirectly orbits =B= and =COM=, a total
|
||||
of =3= orbits.
|
||||
- =L= directly orbits =K= and indirectly orbits =J=, =E=, =D=, =C=, =B=,
|
||||
and =COM=, a total of =7= orbits.
|
||||
- =COM= orbits nothing.
|
||||
|
||||
The total number of direct and indirect orbits in this example is =42=.
|
||||
|
||||
/What is the total number of direct and indirect orbits/ in your map
|
||||
data?
|
||||
|
||||
Your puzzle answer was =453028=.
|
||||
|
||||
** --- Part Two ---
|
||||
Now, you just need to figure out how many /orbital transfers/ you
|
||||
(=YOU=) need to take to get to Santa (=SAN=).
|
||||
|
||||
You start at the object =YOU= are orbiting; your destination is the
|
||||
object =SAN= is orbiting. An orbital transfer lets you move from any
|
||||
object to an object orbiting or orbited by that object.
|
||||
|
||||
For example, suppose you have the following map:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
COM)B
|
||||
B)C
|
||||
C)D
|
||||
D)E
|
||||
E)F
|
||||
B)G
|
||||
G)H
|
||||
D)I
|
||||
E)J
|
||||
J)K
|
||||
K)L
|
||||
K)YOU
|
||||
I)SAN
|
||||
#+END_EXAMPLE
|
||||
|
||||
Visually, the above map of orbits looks like this:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
YOU
|
||||
/
|
||||
G - H J - K - L
|
||||
/ /
|
||||
COM - B - C - D - E - F
|
||||
\
|
||||
I - SAN
|
||||
#+END_EXAMPLE
|
||||
|
||||
In this example, =YOU= are in orbit around =K=, and =SAN= is in orbit
|
||||
around =I=. To move from =K= to =I=, a minimum of =4= orbital transfers
|
||||
are required:
|
||||
|
||||
- =K= to =J=
|
||||
- =J= to =E=
|
||||
- =E= to =D=
|
||||
- =D= to =I=
|
||||
|
||||
Afterward, the map of orbits looks like this:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
G - H J - K - L
|
||||
/ /
|
||||
COM - B - C - D - E - F
|
||||
\
|
||||
I - SAN
|
||||
\
|
||||
YOU
|
||||
#+END_EXAMPLE
|
||||
|
||||
/What is the minimum number of orbital transfers required/ to move from
|
||||
the object =YOU= are orbiting to the object =SAN= is orbiting? (Between
|
||||
the objects they are orbiting - /not/ between =YOU= and =SAN=.)
|
||||
|
||||
Your puzzle answer was =562=.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
||||
270
2019/day06/aoc-c.c
Normal file
270
2019/day06/aoc-c.c
Normal file
@@ -0,0 +1,270 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 6 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 2022 Bruno Raoult ("br")
|
||||
* Licensed under the GNU General Public License v3.0 or later.
|
||||
* Some rights reserved. See COPYING.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this
|
||||
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "br.h"
|
||||
#include "debug.h"
|
||||
#include "pool.h"
|
||||
|
||||
/**
|
||||
* As the character set is [1-9A-Z], the trie arrays size will be 26 + 9 = 35,
|
||||
* organized as:
|
||||
* char: 1 2 ... 8 9 A B ... Y Z
|
||||
* index: 0 1 ... 7 8 9 10 ... 33 34
|
||||
*/
|
||||
#define TRIESIZE ('Z' - 'A' + 1 + '9' - '1' + 1)
|
||||
#define c2index(c) ((c) >= 'A'? (c) - 'A' + 9: (c) - '1')
|
||||
#define index2c(c) ((c) >= 9? (c) + 'A' - 9: (c) + '1')
|
||||
|
||||
/**
|
||||
* object_t - object representation
|
||||
* @parent: a pointer to the object we orbit around
|
||||
* @sibling: a list of objects orbiting around @parent
|
||||
* @child: a list of object orbiting around this object
|
||||
* @name: the object name
|
||||
*
|
||||
* Example: if N1 and N2 orbit around O and S orbits around N1, we will
|
||||
* have :
|
||||
* +---------+
|
||||
* +---->| 0 |<---------+
|
||||
* | |---------| |
|
||||
* | | parent |--->NIL |
|
||||
* | |---------| |
|
||||
* +-------------------+---->| child |<---------+-----------------+
|
||||
* | | |---------| | |
|
||||
* | | +-->| sibling |<--+ | |
|
||||
* | | | +---------+ | | |
|
||||
* | | | | | |
|
||||
* | +---------+ | +-----------------+ | +---------+ |
|
||||
* | | N1 |<---+-----+ | | N2 | |
|
||||
* | |---------| | | | |---------| |
|
||||
* | | parent |----+ | +--| parent | |
|
||||
* | |---------| | |---------| |
|
||||
* | +->| child |<---------+----+ NIL<---| child | |
|
||||
* | | |---------| | | |---------| |
|
||||
* +-+->| sibling |<---------+----+----------------->| sibling |<---+
|
||||
* | +---------+ | | +---------+
|
||||
* | | |
|
||||
* | +---------+ | |
|
||||
* | | S | | |
|
||||
* | |---------| | |
|
||||
* | | parent |----------+ |
|
||||
* | |---------| |
|
||||
* | | child |--->NIL |
|
||||
* | |---------| |
|
||||
* +->| sibling |<--------------+
|
||||
* +---------+
|
||||
*
|
||||
*/
|
||||
typedef struct object {
|
||||
struct object *parent;
|
||||
struct list_head sibling, child;
|
||||
char name[8];
|
||||
} object_t;
|
||||
|
||||
/**
|
||||
* trie_t - trie node
|
||||
* @child: array of pointers to trie_t children of current node
|
||||
* @object: pointer to object data (NULL if node only)
|
||||
*
|
||||
* For example, if objects N1, N2, and S exist, the structure will be:
|
||||
*
|
||||
* Root trie
|
||||
* +--------+-------------------------------------+
|
||||
* | object | 0 | 1 | ... | N | ... | S | ... | Z |
|
||||
* +--------+---------------+---------------------+
|
||||
* | | | | |
|
||||
* v v | | v
|
||||
* NIL NIL | | NIL
|
||||
* +----------------------------+ +-----+
|
||||
* | "N" trie | "S" trie
|
||||
* | +--------+-------------+ | +--------------------------+
|
||||
* +-->| object | 0 | ... | Z | +->| object | 0 | 1 | 2 | ... |
|
||||
* +--------+-------------+ +--------------------------+
|
||||
* | | | | | | |
|
||||
* | v v v v | |
|
||||
* | NIL NIL NIL NIL | |
|
||||
* | +---------------------------------+ |
|
||||
* | | +-----------+
|
||||
* | | "S1" trie | "S2" trie
|
||||
* | | +------------------+ | +------------------+
|
||||
* | +-->| object | 0 | ... | +-->| object | 0 | ... |
|
||||
* | +------------------+ +------------------+
|
||||
* | | | | |
|
||||
* | | v | v
|
||||
* v v NIL v NIL
|
||||
* +-----------+ +-----------+ +-----------+
|
||||
* | Object N | | Object S1 | | Object S2 |
|
||||
* +-----------+ +-----------+ +-----------+
|
||||
*/
|
||||
typedef struct trie {
|
||||
struct trie *child[TRIESIZE];
|
||||
object_t *object;
|
||||
} trie_t;
|
||||
|
||||
static pool_t *pool_tries, *pool_objects;
|
||||
|
||||
static trie_t *trie_get(trie_t *parent, char *name, int pos)
|
||||
{
|
||||
trie_t *trie;
|
||||
|
||||
if ((trie = pool_get(pool_tries))) {
|
||||
for (int i = 0; i < TRIESIZE; ++i)
|
||||
trie->child[i] = NULL;
|
||||
trie->object = NULL;
|
||||
if (parent)
|
||||
parent->child[c2index(name[pos])] = trie;
|
||||
}
|
||||
return trie;
|
||||
}
|
||||
|
||||
static trie_t *trie_find(trie_t *root, char *name)
|
||||
{
|
||||
int len = strlen(name);
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
int ind = c2index(name[i]);
|
||||
root = root->child[ind] ? root->child[ind]: trie_get(root, name, i);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
static object_t *object_find(trie_t *root, char *name)
|
||||
{
|
||||
trie_t *trie = trie_find(root, name);
|
||||
|
||||
if (!trie->object) {
|
||||
trie->object = pool_get(pool_objects);
|
||||
trie->object->parent = NULL;
|
||||
strcpy(trie->object->name, name);
|
||||
INIT_LIST_HEAD(&trie->object->child);
|
||||
INIT_LIST_HEAD(&trie->object->sibling);
|
||||
}
|
||||
return trie->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_orbits - get all orbits (direct and indirect) around an object
|
||||
* @object: object address
|
||||
* @depth: depth of current object
|
||||
*/
|
||||
static int get_orbits(object_t *object, int depth)
|
||||
{
|
||||
int ret = depth;
|
||||
object_t *cur;
|
||||
|
||||
if (!list_empty(&object->child))
|
||||
list_for_each_entry(cur, &object->child, sibling)
|
||||
ret += get_orbits(cur, depth + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int part1(trie_t *root, char *name)
|
||||
{
|
||||
object_t *object = object_find(root, name);
|
||||
return get_orbits(object, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_depth - get depth of an object in a tree
|
||||
* @object: object address
|
||||
* Return: object depth
|
||||
*/
|
||||
static int get_depth(object_t *obj)
|
||||
{
|
||||
int res = 0;
|
||||
for (; obj; obj = obj->parent)
|
||||
res++;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int part2(trie_t *root, char *name1, char *name2)
|
||||
{
|
||||
object_t *obj1 = object_find(root, name1), *obj2 = object_find(root, name2);
|
||||
int count = 0, depth1, depth2;
|
||||
|
||||
depth1 = get_depth(obj1);
|
||||
depth2 = get_depth(obj2);
|
||||
/* ensure highest depth is obj1
|
||||
*/
|
||||
if (depth1 < depth2) {
|
||||
swap(obj1, obj2);
|
||||
swap(depth1, depth2);
|
||||
}
|
||||
/* make the 2 depths equal
|
||||
*/
|
||||
for (; depth1 > depth2; count++, depth1--)
|
||||
obj1 = obj1->parent;
|
||||
/* find common parent
|
||||
*/
|
||||
for (; obj1 != obj2; count += 2) {
|
||||
obj1 = obj1->parent;
|
||||
obj2 = obj2->parent;
|
||||
}
|
||||
return count - 2; /* coz' we want parents objects */
|
||||
}
|
||||
|
||||
static void parse(trie_t *root)
|
||||
{
|
||||
char str1[8], str2[8];
|
||||
|
||||
while (scanf(" %7[^)])%s", str1, str2) == 2) {
|
||||
object_t *star = object_find(root, str1);
|
||||
object_t *planet = object_find(root, str2);
|
||||
/* link planet to star, add planet to star's planets list
|
||||
*/
|
||||
planet->parent = star;
|
||||
list_add(&planet->sibling, &star->child);
|
||||
}
|
||||
}
|
||||
|
||||
static int usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-d debug_level] [-p part]\n", prg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int opt, part = 1;
|
||||
|
||||
while ((opt = getopt(ac, av, "d:p:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
debug_level_set(atoi(optarg));
|
||||
break;
|
||||
case 'p': /* 1 or 2 */
|
||||
part = atoi(optarg);
|
||||
if (part < 1 || part > 2)
|
||||
default:
|
||||
return usage(*av);
|
||||
}
|
||||
}
|
||||
if (optind < ac)
|
||||
return usage(*av);
|
||||
|
||||
pool_tries = pool_create("tries", 1024, sizeof(trie_t));
|
||||
pool_objects = pool_create("objects", 1024, sizeof(object_t));
|
||||
trie_t *root = trie_get(NULL, NULL, 0);
|
||||
parse(root);
|
||||
printf("%s : res=%d\n", *av,
|
||||
part == 1 ? part1(root, "COM") : part2(root, "YOU", "SAN"));
|
||||
pool_destroy(pool_tries);
|
||||
pool_destroy(pool_objects);
|
||||
exit (0);
|
||||
}
|
||||
1
2019/day07/EXAMPLE.txt
Normal file
1
2019/day07/EXAMPLE.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0
|
||||
1
2019/day07/EXAMPLE1.txt
Normal file
1
2019/day07/EXAMPLE1.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,0,0
|
||||
1
2019/day07/EXAMPLE2.txt
Normal file
1
2019/day07/EXAMPLE2.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0
|
||||
1
2019/day07/INPUT.txt
Normal file
1
2019/day07/INPUT.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,8,1001,8,10,8,105,1,0,0,21,30,39,64,81,102,183,264,345,426,99999,3,9,1001,9,2,9,4,9,99,3,9,1002,9,4,9,4,9,99,3,9,1002,9,5,9,101,2,9,9,102,3,9,9,1001,9,2,9,1002,9,2,9,4,9,99,3,9,1002,9,3,9,1001,9,5,9,1002,9,3,9,4,9,99,3,9,102,4,9,9,1001,9,3,9,102,4,9,9,1001,9,5,9,4,9,99,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,99,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,99,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,101,1,9,9,4,9,99
|
||||
93
2019/day07/Makefile
Normal file
93
2019/day07/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with this
|
||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
||||
167
2019/day07/README.org
Normal file
167
2019/day07/README.org
Normal file
@@ -0,0 +1,167 @@
|
||||
** --- Day 7: Amplification Circuit ---
|
||||
Based on the navigational maps, you're going to need to send more power
|
||||
to your ship's thrusters to reach Santa in time. To do this, you'll need
|
||||
to configure a series of
|
||||
[[https://en.wikipedia.org/wiki/Amplifier][amplifiers]] already
|
||||
installed on the ship.
|
||||
|
||||
There are five amplifiers connected in series; each one receives an
|
||||
input signal and produces an output signal. They are connected such that
|
||||
the first amplifier's output leads to the second amplifier's input, the
|
||||
second amplifier's output leads to the third amplifier's input, and so
|
||||
on. The first amplifier's input value is =0=, and the last amplifier's
|
||||
output leads to your ship's thrusters.
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
O-------O O-------O O-------O O-------O O-------O
|
||||
0 ->| Amp A |->| Amp B |->| Amp C |->| Amp D |->| Amp E |-> (to thrusters)
|
||||
O-------O O-------O O-------O O-------O O-------O
|
||||
#+END_EXAMPLE
|
||||
|
||||
The Elves have sent you some /Amplifier Controller Software/ (your
|
||||
puzzle input), a program that should run on your [[file:5][existing
|
||||
Intcode computer]]. Each amplifier will need to run a copy of the
|
||||
program.
|
||||
|
||||
When a copy of the program starts running on an amplifier, it will first
|
||||
use an input instruction to ask the amplifier for its current /phase
|
||||
setting/ (an integer from =0= to =4=). Each phase setting is used
|
||||
/exactly once/, but the Elves can't remember which amplifier needs which
|
||||
phase setting.
|
||||
|
||||
The program will then call another input instruction to get the
|
||||
amplifier's input signal, compute the correct output signal, and supply
|
||||
it back to the amplifier with an output instruction. (If the amplifier
|
||||
has not yet received an input signal, it waits until one arrives.)
|
||||
|
||||
Your job is to /find the largest output signal that can be sent to the
|
||||
thrusters/ by trying every possible combination of phase settings on the
|
||||
amplifiers. Make sure that memory is not shared or reused between copies
|
||||
of the program.
|
||||
|
||||
For example, suppose you want to try the phase setting sequence
|
||||
=3,1,2,4,0=, which would mean setting amplifier =A= to phase setting
|
||||
=3=, amplifier =B= to setting =1=, =C= to =2=, =D= to =4=, and =E= to
|
||||
=0=. Then, you could determine the output signal that gets sent from
|
||||
amplifier =E= to the thrusters with the following steps:
|
||||
|
||||
- Start the copy of the amplifier controller software that will run on
|
||||
amplifier =A=. At its first input instruction, provide it the
|
||||
amplifier's phase setting, =3=. At its second input instruction,
|
||||
provide it the input signal, =0=. After some calculations, it will use
|
||||
an output instruction to indicate the amplifier's output signal.
|
||||
- Start the software for amplifier =B=. Provide it the phase setting
|
||||
(=1=) and then whatever output signal was produced from amplifier =A=.
|
||||
It will then produce a new output signal destined for amplifier =C=.
|
||||
- Start the software for amplifier =C=, provide the phase setting (=2=)
|
||||
and the value from amplifier =B=, then collect its output signal.
|
||||
- Run amplifier =D='s software, provide the phase setting (=4=) and
|
||||
input value, and collect its output signal.
|
||||
- Run amplifier =E='s software, provide the phase setting (=0=) and
|
||||
input value, and collect its output signal.
|
||||
|
||||
The final output signal from amplifier =E= would be sent to the
|
||||
thrusters. However, this phase setting sequence may not have been the
|
||||
best one; another sequence might have sent a higher signal to the
|
||||
thrusters.
|
||||
|
||||
Here are some example programs:
|
||||
|
||||
- Max thruster signal /=43210=/ (from phase setting sequence
|
||||
=4,3,2,1,0=):
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0
|
||||
#+END_EXAMPLE
|
||||
|
||||
- Max thruster signal /=54321=/ (from phase setting sequence
|
||||
=0,1,2,3,4=):
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
3,23,3,24,1002,24,10,24,1002,23,-1,23,
|
||||
101,5,23,23,1,24,23,23,4,23,99,0,0
|
||||
#+END_EXAMPLE
|
||||
|
||||
- Max thruster signal /=65210=/ (from phase setting sequence
|
||||
=1,0,4,3,2=):
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,
|
||||
1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0
|
||||
#+END_EXAMPLE
|
||||
|
||||
Try every combination of phase settings on the amplifiers. /What is the
|
||||
highest signal that can be sent to the thrusters?/
|
||||
|
||||
Your puzzle answer was =65464=.
|
||||
|
||||
** --- Part Two ---
|
||||
It's no good - in this configuration, the amplifiers can't generate a
|
||||
large enough output signal to produce the thrust you'll need. The Elves
|
||||
quickly talk you through rewiring the amplifiers into a /feedback loop/:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
O-------O O-------O O-------O O-------O O-------O
|
||||
0 -+->| Amp A |->| Amp B |->| Amp C |->| Amp D |->| Amp E |-.
|
||||
| O-------O O-------O O-------O O-------O O-------O |
|
||||
| |
|
||||
'--------------------------------------------------------+
|
||||
|
|
||||
v
|
||||
(to thrusters)
|
||||
#+END_EXAMPLE
|
||||
|
||||
Most of the amplifiers are connected as they were before; amplifier
|
||||
=A='s output is connected to amplifier =B='s input, and so on.
|
||||
/However,/ the output from amplifier =E= is now connected into amplifier
|
||||
=A='s input. This creates the feedback loop: the signal will be sent
|
||||
through the amplifiers /many times/.
|
||||
|
||||
In feedback loop mode, the amplifiers need /totally different phase
|
||||
settings/: integers from =5= to =9=, again each used exactly once. These
|
||||
settings will cause the Amplifier Controller Software to repeatedly take
|
||||
input and produce output many times before halting. Provide each
|
||||
amplifier its phase setting at its first input instruction; all further
|
||||
input/output instructions are for signals.
|
||||
|
||||
Don't restart the Amplifier Controller Software on any amplifier during
|
||||
this process. Each one should continue receiving and sending signals
|
||||
until it halts.
|
||||
|
||||
All signals sent or received in this process will be between pairs of
|
||||
amplifiers except the very first signal and the very last signal. To
|
||||
start the process, a =0= signal is sent to amplifier =A='s input
|
||||
/exactly once/.
|
||||
|
||||
Eventually, the software on the amplifiers will halt after they have
|
||||
processed the final loop. When this happens, the last output signal from
|
||||
amplifier =E= is sent to the thrusters. Your job is to /find the largest
|
||||
output signal that can be sent to the thrusters/ using the new phase
|
||||
settings and feedback loop arrangement.
|
||||
|
||||
Here are some example programs:
|
||||
|
||||
- Max thruster signal /=139629729=/ (from phase setting sequence
|
||||
=9,8,7,6,5=):
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,
|
||||
27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5
|
||||
#+END_EXAMPLE
|
||||
|
||||
- Max thruster signal /=18216=/ (from phase setting sequence
|
||||
=9,7,8,5,6=):
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54,
|
||||
-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4,
|
||||
53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10
|
||||
#+END_EXAMPLE
|
||||
|
||||
Try every combination of the new phase settings on the amplifier
|
||||
feedback loop. /What is the highest signal that can be sent to the
|
||||
thrusters?/
|
||||
|
||||
Your puzzle answer was =1518124=.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
||||
257
2019/day07/aoc-c.c
Normal file
257
2019/day07/aoc-c.c
Normal file
@@ -0,0 +1,257 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 7 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 2022 Bruno Raoult ("br")
|
||||
* Licensed under the GNU General Public License v3.0 or later.
|
||||
* Some rights reserved. See COPYING.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this
|
||||
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "br.h"
|
||||
#include "bits.h"
|
||||
#include "debug.h"
|
||||
#include "list.h"
|
||||
#include "pool.h"
|
||||
|
||||
/* operators codes
|
||||
*/
|
||||
typedef enum {
|
||||
ADD = 1, MUL = 2, /* CALC: add and mult */
|
||||
INP = 3, OUT = 4, /* I/O: input and output value */
|
||||
JMP_T = 5, JMP_F = 6, /* JUMPS: jump if true / if false */
|
||||
SET_LT = 7, SET_EQ = 8, /* COND SETS: set if true/false */
|
||||
HLT = 99 /* HALT */
|
||||
} opcode_t;
|
||||
|
||||
/**
|
||||
* ops - array of op-codes, mnemo, and number of parameters
|
||||
* @op: An integer, the opcode
|
||||
* @length: Next instruction offset
|
||||
*/
|
||||
typedef struct {
|
||||
int op;
|
||||
u8 length;
|
||||
} ops_t;
|
||||
|
||||
typedef struct input {
|
||||
int val;
|
||||
struct list_head list;
|
||||
} input_t;
|
||||
|
||||
#define MAXOPS 1024
|
||||
typedef struct {
|
||||
int length; /* total program length */
|
||||
int cur; /* current position */
|
||||
struct list_head input; /* process input queue */
|
||||
int mem [MAXOPS]; /* should really be dynamic */
|
||||
} program_t;
|
||||
|
||||
static ops_t ops[] = {
|
||||
[ADD] = { ADD, 4 }, [MUL] = { MUL, 4 },
|
||||
[INP] = { INP, 2 }, [OUT] = { OUT, 2 },
|
||||
[JMP_T] = { JMP_T, 3 }, [JMP_F] = { JMP_F, 3 },
|
||||
[SET_LT] = { SET_LT, 4 }, [SET_EQ] = { SET_EQ, 4 },
|
||||
[HLT] = { HLT, 1 }
|
||||
};
|
||||
|
||||
|
||||
static int _flag_pow10[] = {1, 100, 1000, 10000};
|
||||
#define OP(p, n) ((p->mem[n]) % 100)
|
||||
#define ISDIRECT(p, n, i) ((((p->mem[n]) / _flag_pow10[i]) % 10))
|
||||
#define DIRECT(p, i) ((p)->mem[i])
|
||||
#define INDIRECT(p, i) (DIRECT(p, DIRECT(p, i)))
|
||||
|
||||
#define peek(p, n, i) (ISDIRECT(p, n, i)? DIRECT(p, n + i): INDIRECT(p, n + i))
|
||||
#define poke(p, n, i, val) do { \
|
||||
INDIRECT(p, n + i) = val; } \
|
||||
while (0)
|
||||
|
||||
|
||||
static pool_t *pool_input;
|
||||
static __always_inline int prg_add_input(program_t *prg, int in)
|
||||
{
|
||||
input_t *input = pool_get(pool_input);
|
||||
input->val = in;
|
||||
list_add_tail(&input->list, &prg->input);
|
||||
return in;
|
||||
}
|
||||
|
||||
static __always_inline int prg_get_input(program_t *prg, int *out)
|
||||
{
|
||||
input_t *input = list_first_entry_or_null(&prg->input, input_t, list);
|
||||
if (!input)
|
||||
return 0;
|
||||
*out = input->val;
|
||||
list_del(&input->list);
|
||||
pool_add(pool_input, input);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* permute - get next permutation of an array of integers
|
||||
* @len: length of array
|
||||
* @array: address of array
|
||||
*
|
||||
* Algorithm: lexicographic permutations
|
||||
* https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
|
||||
* Before the initial call, the array must be sorted (e.g. 0 2 3 5)
|
||||
*
|
||||
* Return: 1 if next permutation was found, 0 if no more permutation.
|
||||
*
|
||||
*/
|
||||
static int permute_next(int len, int *array)
|
||||
{
|
||||
int k, l;
|
||||
|
||||
/* 1. Find the largest index k such that a[k] < a[k + 1] */
|
||||
for (k = len - 2; k >= 0 && array[k] >= array[k + 1]; k--)
|
||||
;
|
||||
/* No more permutations */
|
||||
if (k < 0)
|
||||
return 0;
|
||||
/* 2. Find the largest index l greater than k such that a[k] < a[l] */
|
||||
for (l = len - 1; array[l] <= array[k]; l--)
|
||||
;
|
||||
/* 3. Swap the value of a[k] with that of a[l] */
|
||||
swap(array[k], array[l]);
|
||||
/* 4. Reverse sequence from a[k + 1] up to the final element */
|
||||
for (l = len - 1, k++; k < l; k++, l--)
|
||||
swap(array[k], array[l]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int run(program_t *p, int *end)
|
||||
{
|
||||
int out = -1;
|
||||
while (1) {
|
||||
int op = OP(p, p->cur), cur = p->cur, input;
|
||||
|
||||
if (!(ops[op].op)) {
|
||||
fprintf(stderr, "PANIC: illegal instruction %d at %d.\n", op, p->cur);
|
||||
return -1;
|
||||
}
|
||||
switch (op) {
|
||||
case ADD:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) + peek(p, p->cur, 2));
|
||||
break;
|
||||
case MUL:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) * peek(p, p->cur, 2));
|
||||
break;
|
||||
case INP:
|
||||
if (prg_get_input(p, &input))
|
||||
poke(p, p->cur, 1, input);
|
||||
else
|
||||
/* we need an input which is not yet avalaible, so we need
|
||||
* to put the program in "waiting mode": We stop it (and
|
||||
* return output value) without setting end flag.
|
||||
*/
|
||||
goto sleep;
|
||||
break;
|
||||
case OUT:
|
||||
out = peek(p, p->cur, 1);
|
||||
break;
|
||||
case JMP_T:
|
||||
if (peek(p, p->cur, 1))
|
||||
p->cur = peek(p, p->cur, 2);
|
||||
break;
|
||||
case JMP_F:
|
||||
if (!peek(p, p->cur, 1))
|
||||
p->cur = peek(p, p->cur, 2);
|
||||
break;
|
||||
case SET_LT:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) < peek(p, p->cur, 2) ? 1: 0);
|
||||
break;
|
||||
case SET_EQ:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) == peek(p, p->cur, 2) ? 1: 0);
|
||||
break;
|
||||
case HLT:
|
||||
*end = 1;
|
||||
sleep:
|
||||
return out;
|
||||
}
|
||||
if (p->cur == cur)
|
||||
p->cur += ops[op].length;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse(program_t *prog)
|
||||
{
|
||||
while (scanf("%d%*c", &prog->mem[prog->length++]) > 0)
|
||||
;
|
||||
}
|
||||
|
||||
static int usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int phase1[] = {0, 1, 2, 3, 4}, phase2[] = {5, 6, 7, 8, 9}, *phase;
|
||||
int opt, max = 0, part = 1;
|
||||
program_t p = { 0 }, prg[5];
|
||||
|
||||
while ((opt = getopt(ac, av, "d:p:o:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
debug_level_set(atoi(optarg));
|
||||
break;
|
||||
case 'o':
|
||||
for (ulong i = 0; i < strlen(optarg); ++i)
|
||||
phase1[i] = optarg[i] - '0';
|
||||
break;
|
||||
case 'p': /* 1 or 2 */
|
||||
part = atoi(optarg);
|
||||
if (part < 1 || part > 2)
|
||||
return usage(*av);
|
||||
break;
|
||||
default:
|
||||
return usage(*av);
|
||||
}
|
||||
}
|
||||
|
||||
pool_input = pool_create("input", 128, sizeof(input_t));
|
||||
|
||||
if (optind < ac)
|
||||
return usage(*av);
|
||||
|
||||
phase = part == 1? phase1: phase2;
|
||||
parse(&p);
|
||||
|
||||
do {
|
||||
int out = 0, end = 0;
|
||||
/* reset programs initial state, and add phase to their input
|
||||
*/
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(prg); ++i) {
|
||||
prg[i] = p;
|
||||
INIT_LIST_HEAD(&prg[i].input);
|
||||
prg_add_input(&prg[i], phase[i]);
|
||||
}
|
||||
|
||||
/* run the 5 processes in order (0, 1, 2, 3, 4, 0, 1, etc...),
|
||||
* until end flag is set by the process 4 (HLT instruction)
|
||||
*/
|
||||
while (!end) {
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
/* add last process output in current process input queue
|
||||
*/
|
||||
prg_add_input(&prg[i], out);
|
||||
out = run(&prg[i], &end);
|
||||
}
|
||||
}
|
||||
max = max(max, out);
|
||||
} while (permute_next(5, phase));
|
||||
|
||||
printf("%s : res=%d\n", *av, max);
|
||||
pool_destroy(pool_input);
|
||||
exit(0);
|
||||
}
|
||||
1
2019/day08/EXAMPLE.txt
Normal file
1
2019/day08/EXAMPLE.txt
Normal file
@@ -0,0 +1 @@
|
||||
0222112222120000
|
||||
1
2019/day08/INPUT.txt
Normal file
1
2019/day08/INPUT.txt
Normal file
File diff suppressed because one or more lines are too long
93
2019/day08/Makefile
Normal file
93
2019/day08/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with this
|
||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
||||
99
2019/day08/README.org
Normal file
99
2019/day08/README.org
Normal file
@@ -0,0 +1,99 @@
|
||||
** --- Day 8: Space Image Format ---
|
||||
The Elves' spirits are lifted when they realize you have an opportunity
|
||||
to reboot one of their Mars rovers, and so they are curious if you would
|
||||
spend a brief sojourn on Mars. You land your ship near the rover.
|
||||
|
||||
When you reach the rover, you discover that it's already in the process
|
||||
of rebooting! It's just waiting for someone to enter a
|
||||
[[https://en.wikipedia.org/wiki/BIOS][BIOS]] password. The Elf
|
||||
responsible for the rover takes a picture of the password (your puzzle
|
||||
input) and sends it to you via the Digital Sending Network.
|
||||
|
||||
Unfortunately, images sent via the Digital Sending Network aren't
|
||||
encoded with any normal encoding; instead, they're encoded in a special
|
||||
Space Image Format. None of the Elves seem to remember why this is the
|
||||
case. They send you the instructions to decode it.
|
||||
|
||||
Images are sent as a series of digits that each represent the color of a
|
||||
single pixel. The digits fill each row of the image left-to-right, then
|
||||
move downward to the next row, filling rows top-to-bottom until every
|
||||
pixel of the image is filled.
|
||||
|
||||
Each image actually consists of a series of identically-sized /layers/
|
||||
that are filled in this way. So, the first digit corresponds to the
|
||||
top-left pixel of the first layer, the second digit corresponds to the
|
||||
pixel to the right of that on the same layer, and so on until the last
|
||||
digit, which corresponds to the bottom-right pixel of the last layer.
|
||||
|
||||
For example, given an image =3= pixels wide and =2= pixels tall, the
|
||||
image data =123456789012= corresponds to the following image layers:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
Layer 1: 123
|
||||
456
|
||||
|
||||
Layer 2: 789
|
||||
012
|
||||
#+END_EXAMPLE
|
||||
|
||||
The image you received is /=25= pixels wide and =6= pixels tall/.
|
||||
|
||||
To make sure the image wasn't corrupted during transmission, the Elves
|
||||
would like you to find the layer that contains the /fewest =0= digits/.
|
||||
On that layer, what is /the number of =1= digits multiplied by the
|
||||
number of =2= digits?/
|
||||
|
||||
Your puzzle answer was =2250=.
|
||||
|
||||
** --- Part Two ---
|
||||
Now you're ready to decode the image. The image is rendered by stacking
|
||||
the layers and aligning the pixels with the same positions in each
|
||||
layer. The digits indicate the color of the corresponding pixel: =0= is
|
||||
black, =1= is white, and =2= is transparent.
|
||||
|
||||
The layers are rendered with the first layer in front and the last layer
|
||||
in back. So, if a given position has a transparent pixel in the first
|
||||
and second layers, a black pixel in the third layer, and a white pixel
|
||||
in the fourth layer, the final image would have a /black/ pixel at that
|
||||
position.
|
||||
|
||||
For example, given an image =2= pixels wide and =2= pixels tall, the
|
||||
image data =0222112222120000= corresponds to the following image layers:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
Layer 1: 02
|
||||
22
|
||||
|
||||
Layer 2: 11
|
||||
22
|
||||
|
||||
Layer 3: 22
|
||||
12
|
||||
|
||||
Layer 4: 00
|
||||
00
|
||||
#+END_EXAMPLE
|
||||
|
||||
Then, the full image can be found by determining the top visible pixel
|
||||
in each position:
|
||||
|
||||
- The top-left pixel is /black/ because the top layer is =0=.
|
||||
- The top-right pixel is /white/ because the top layer is =2=
|
||||
(transparent), but the second layer is =1=.
|
||||
- The bottom-left pixel is /white/ because the top two layers are =2=,
|
||||
but the third layer is =1=.
|
||||
- The bottom-right pixel is /black/ because the only visible pixel in
|
||||
that position is =0= (from layer 4).
|
||||
|
||||
So, the final image looks like this:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
01
|
||||
10
|
||||
#+END_EXAMPLE
|
||||
|
||||
/What message is produced after decoding your image?/
|
||||
|
||||
Your puzzle answer was =FHJUL=.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
||||
120
2019/day08/aoc-c.c
Normal file
120
2019/day08/aoc-c.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 8 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 2022 Bruno Raoult ("br")
|
||||
* Licensed under the GNU General Public License v3.0 or later.
|
||||
* Some rights reserved. See COPYING.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this
|
||||
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "br.h"
|
||||
#include "bits.h"
|
||||
#include "debug.h"
|
||||
#include "list.h"
|
||||
#include "pool.h"
|
||||
|
||||
struct input {
|
||||
int len;
|
||||
char *buf;
|
||||
|
||||
};
|
||||
|
||||
static int part1(struct input *input, int width, int height)
|
||||
{
|
||||
int depth = input->len / width / height;
|
||||
int minzero = input->len, n1n2;
|
||||
|
||||
for (int i = 0; i < depth; ++i) {
|
||||
char *layer = input->buf + i * (width * height);
|
||||
int tmp[10] = {0};
|
||||
for (int j = 0; j < width*height; ++j) {
|
||||
tmp[layer[j] - '0'] ++;
|
||||
}
|
||||
if (tmp[0] < minzero) {
|
||||
minzero = tmp[0];
|
||||
n1n2 = tmp[1] * tmp[2];
|
||||
}
|
||||
}
|
||||
return n1n2;
|
||||
}
|
||||
|
||||
static int part2(struct input *input, int width, int height)
|
||||
{
|
||||
for (int line = 0; line < height; line++) {
|
||||
for (int pixel = 0; pixel < width; ++pixel) {
|
||||
char *pos = input->buf + line * width + pixel;
|
||||
while (pos < input->buf + input->len && *pos == '2')
|
||||
pos += width * height;
|
||||
putchar(*pos == '0'? ' ': '#');
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse(struct input *input)
|
||||
{
|
||||
size_t alloc = 0;
|
||||
ssize_t buflen;
|
||||
char *buf = NULL;
|
||||
|
||||
if ((buflen = getline(&buf, &alloc, stdin)) <= 0) {
|
||||
fprintf(stderr, "error reading file.\n");
|
||||
return 0;
|
||||
}
|
||||
buf[buflen--] = 0;
|
||||
input->buf = buf;
|
||||
input->len = buflen;
|
||||
return buflen;
|
||||
}
|
||||
|
||||
static int usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int opt, part = 1, width = 25, height = 6;
|
||||
struct input input = { 0 };
|
||||
|
||||
while ((opt = getopt(ac, av, "d:p:w:h:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
debug_level_set(atoi(optarg));
|
||||
break;
|
||||
case 'w':
|
||||
width = atoi(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
height = atoi(optarg);
|
||||
break;
|
||||
case 'p': /* 1 or 2 */
|
||||
part = atoi(optarg);
|
||||
if (part < 1 || part > 2)
|
||||
return usage(*av);
|
||||
break;
|
||||
default:
|
||||
return usage(*av);
|
||||
}
|
||||
}
|
||||
if (optind < ac)
|
||||
return usage(*av);
|
||||
|
||||
parse(&input);
|
||||
printf("%s : res=%d\n", *av,
|
||||
part == 1?
|
||||
part1(&input, width, height) :
|
||||
part2(&input, width, height));
|
||||
free(input.buf);
|
||||
exit(0);
|
||||
}
|
||||
1
2019/day09/EXAMPLE.txt
Normal file
1
2019/day09/EXAMPLE.txt
Normal file
@@ -0,0 +1 @@
|
||||
109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99
|
||||
1
2019/day09/EXAMPLE2.txt
Normal file
1
2019/day09/EXAMPLE2.txt
Normal file
@@ -0,0 +1 @@
|
||||
1102,34915192,34915192,7,4,7,99,0
|
||||
1
2019/day09/EXAMPLE3.txt
Normal file
1
2019/day09/EXAMPLE3.txt
Normal file
@@ -0,0 +1 @@
|
||||
104,1125899906842624,99
|
||||
1
2019/day09/INPUT.txt
Normal file
1
2019/day09/INPUT.txt
Normal file
@@ -0,0 +1 @@
|
||||
1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1102,3,1,1000,109,988,209,12,9,1000,209,6,209,3,203,0,1008,1000,1,63,1005,63,65,1008,1000,2,63,1005,63,904,1008,1000,0,63,1005,63,58,4,25,104,0,99,4,0,104,0,99,4,17,104,0,99,0,0,1101,20,0,1007,1101,0,197,1022,1102,475,1,1028,1102,30,1,1008,1101,25,0,1010,1102,1,23,1009,1101,0,22,1013,1101,470,0,1029,1102,24,1,1014,1102,1,39,1005,1101,31,0,1003,1101,807,0,1026,1101,0,26,1018,1102,1,804,1027,1101,0,0,1020,1102,1,38,1017,1101,0,27,1016,1102,443,1,1024,1101,0,36,1006,1102,21,1,1015,1101,28,0,1001,1102,33,1,1019,1102,1,37,1011,1102,1,190,1023,1101,0,434,1025,1101,34,0,1004,1102,1,1,1021,1101,0,29,1012,1102,1,32,1002,1101,35,0,1000,109,30,2105,1,-7,1001,64,1,64,1105,1,199,4,187,1002,64,2,64,109,-23,2101,0,-5,63,1008,63,32,63,1005,63,225,4,205,1001,64,1,64,1105,1,225,1002,64,2,64,109,7,2102,1,-5,63,1008,63,23,63,1005,63,251,4,231,1001,64,1,64,1106,0,251,1002,64,2,64,109,-16,2101,0,2,63,1008,63,33,63,1005,63,275,1001,64,1,64,1106,0,277,4,257,1002,64,2,64,109,10,21102,40,1,4,1008,1012,40,63,1005,63,299,4,283,1106,0,303,1001,64,1,64,1002,64,2,64,109,7,2102,1,-9,63,1008,63,33,63,1005,63,327,1001,64,1,64,1105,1,329,4,309,1002,64,2,64,109,-17,2107,34,2,63,1005,63,347,4,335,1105,1,351,1001,64,1,64,1002,64,2,64,109,1,1201,8,0,63,1008,63,23,63,1005,63,375,1001,64,1,64,1106,0,377,4,357,1002,64,2,64,109,-4,2108,31,8,63,1005,63,395,4,383,1105,1,399,1001,64,1,64,1002,64,2,64,109,3,1201,8,0,63,1008,63,36,63,1005,63,421,4,405,1105,1,425,1001,64,1,64,1002,64,2,64,109,25,2105,1,1,4,431,1001,64,1,64,1105,1,443,1002,64,2,64,109,-3,1205,0,459,1001,64,1,64,1106,0,461,4,449,1002,64,2,64,109,-2,2106,0,10,4,467,1106,0,479,1001,64,1,64,1002,64,2,64,109,12,1206,-9,495,1001,64,1,64,1106,0,497,4,485,1002,64,2,64,109,-39,1207,9,36,63,1005,63,519,4,503,1001,64,1,64,1105,1,519,1002,64,2,64,109,11,1202,-1,1,63,1008,63,28,63,1005,63,541,4,525,1105,1,545,1001,64,1,64,1002,64,2,64,109,6,2107,24,1,63,1005,63,565,1001,64,1,64,1106,0,567,4,551,1002,64,2,64,109,1,1207,-3,35,63,1005,63,583,1106,0,589,4,573,1001,64,1,64,1002,64,2,64,109,1,21102,41,1,5,1008,1015,40,63,1005,63,613,1001,64,1,64,1105,1,615,4,595,1002,64,2,64,109,-2,2108,22,1,63,1005,63,635,1001,64,1,64,1105,1,637,4,621,1002,64,2,64,109,-10,1208,4,33,63,1005,63,653,1106,0,659,4,643,1001,64,1,64,1002,64,2,64,109,16,1206,6,673,4,665,1106,0,677,1001,64,1,64,1002,64,2,64,109,-4,1202,-8,1,63,1008,63,35,63,1005,63,701,1001,64,1,64,1105,1,703,4,683,1002,64,2,64,109,13,21108,42,42,-8,1005,1015,721,4,709,1105,1,725,1001,64,1,64,1002,64,2,64,109,-18,21107,43,44,5,1005,1010,743,4,731,1106,0,747,1001,64,1,64,1002,64,2,64,109,-11,1208,8,32,63,1005,63,765,4,753,1106,0,769,1001,64,1,64,1002,64,2,64,109,15,21101,44,0,5,1008,1014,47,63,1005,63,789,1105,1,795,4,775,1001,64,1,64,1002,64,2,64,109,13,2106,0,5,1106,0,813,4,801,1001,64,1,64,1002,64,2,64,109,-12,21108,45,43,0,1005,1010,829,1106,0,835,4,819,1001,64,1,64,1002,64,2,64,109,-4,21107,46,45,10,1005,1016,855,1001,64,1,64,1106,0,857,4,841,1002,64,2,64,109,3,21101,47,0,5,1008,1014,47,63,1005,63,883,4,863,1001,64,1,64,1106,0,883,1002,64,2,64,109,10,1205,2,901,4,889,1001,64,1,64,1105,1,901,4,64,99,21102,27,1,1,21102,915,1,0,1106,0,922,21201,1,13433,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21101,0,942,0,1106,0,922,22102,1,1,-1,21201,-2,-3,1,21102,1,957,0,1105,1,922,22201,1,-1,-2,1106,0,968,21202,-2,1,-2,109,-3,2106,0,0
|
||||
93
2019/day09/Makefile
Normal file
93
2019/day09/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with this
|
||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
||||
94
2019/day09/README.org
Normal file
94
2019/day09/README.org
Normal file
@@ -0,0 +1,94 @@
|
||||
** --- Day 9: Sensor Boost ---
|
||||
You've just said goodbye to the rebooted rover and left Mars when you
|
||||
receive a faint distress signal coming from the asteroid belt. It must
|
||||
be the Ceres monitoring station!
|
||||
|
||||
In order to lock on to the signal, you'll need to boost your sensors.
|
||||
The Elves send up the latest /BOOST/ program - Basic Operation Of System
|
||||
Test.
|
||||
|
||||
While BOOST (your puzzle input) is capable of boosting your sensors, for
|
||||
tenuous safety reasons, it refuses to do so until the computer it runs
|
||||
on passes some checks to demonstrate it is a /complete Intcode
|
||||
computer/.
|
||||
|
||||
[[file:5][Your existing Intcode computer]] is missing one key feature:
|
||||
it needs support for parameters in /relative mode/.
|
||||
|
||||
Parameters in mode =2=, /relative mode/, behave very similarly to
|
||||
parameters in /position mode/: the parameter is interpreted as a
|
||||
position. Like position mode, parameters in relative mode can be read
|
||||
from or written to.
|
||||
|
||||
The important difference is that relative mode parameters don't count
|
||||
from address =0=. Instead, they count from a value called the /relative
|
||||
base/. The /relative base/ starts at =0=.
|
||||
|
||||
The address a relative mode parameter refers to is itself /plus/ the
|
||||
current /relative base/. When the relative base is =0=, relative mode
|
||||
parameters and position mode parameters with the same value refer to the
|
||||
same address.
|
||||
|
||||
For example, given a relative base of =50=, a relative mode parameter of
|
||||
=-7= refers to memory address =50 + -7 = 43=.
|
||||
|
||||
The relative base is modified with the /relative base offset/
|
||||
instruction:
|
||||
|
||||
- Opcode =9= /adjusts the relative base/ by the value of its only
|
||||
parameter. The relative base increases (or decreases, if the value is
|
||||
negative) by the value of the parameter.
|
||||
|
||||
For example, if the relative base is =2000=, then after the instruction
|
||||
=109,19=, the relative base would be =2019=. If the next instruction
|
||||
were =204,-34=, then the value at address =1985= would be output.
|
||||
|
||||
Your Intcode computer will also need a few other capabilities:
|
||||
|
||||
- The computer's available memory should be much larger than the initial
|
||||
program. Memory beyond the initial program starts with the value =0=
|
||||
and can be read or written like any other memory. (It is invalid to
|
||||
try to access memory at a negative address, though.)
|
||||
- The computer should have support for large numbers. Some instructions
|
||||
near the beginning of the BOOST program will verify this capability.
|
||||
|
||||
Here are some example programs that use these features:
|
||||
|
||||
- =109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99= takes no
|
||||
input and produces a
|
||||
[[https://en.wikipedia.org/wiki/Quine_(computing)][copy of itself]] as
|
||||
output.
|
||||
- =1102,34915192,34915192,7,4,7,99,0= should output a 16-digit number.
|
||||
- =104,1125899906842624,99= should output the large number in the
|
||||
middle.
|
||||
|
||||
The BOOST program will ask for a single input; run it in test mode by
|
||||
providing it the value =1=. It will perform a series of checks on each
|
||||
opcode, output any opcodes (and the associated parameter modes) that
|
||||
seem to be functioning incorrectly, and finally output a BOOST keycode.
|
||||
|
||||
Once your Intcode computer is fully functional, the BOOST program should
|
||||
report no malfunctioning opcodes when run in test mode; it should only
|
||||
output a single value, the BOOST keycode. /What BOOST keycode does it
|
||||
produce?/
|
||||
|
||||
Your puzzle answer was =2682107844=.
|
||||
|
||||
** --- Part Two ---
|
||||
/You now have a complete Intcode computer./
|
||||
|
||||
Finally, you can lock on to the Ceres distress signal! You just need to
|
||||
boost your sensors using the BOOST program.
|
||||
|
||||
The program runs in sensor boost mode by providing the input instruction
|
||||
the value =2=. Once run, it will boost the sensors automatically, but it
|
||||
might take a few seconds to complete the operation on slower hardware.
|
||||
In sensor boost mode, the program will output a single value: /the
|
||||
coordinates of the distress signal/.
|
||||
|
||||
Run the BOOST program in sensor boost mode. /What are the coordinates of
|
||||
the distress signal?/
|
||||
|
||||
Your puzzle answer was =34738=.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
||||
258
2019/day09/aoc-c.c
Normal file
258
2019/day09/aoc-c.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 9 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 2022 Bruno Raoult ("br")
|
||||
* Licensed under the GNU General Public License v3.0 or later.
|
||||
* Some rights reserved. See COPYING.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this
|
||||
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "br.h"
|
||||
#include "bits.h"
|
||||
#include "debug.h"
|
||||
#include "list.h"
|
||||
#include "pool.h"
|
||||
|
||||
#define _unused __attribute__((unused))
|
||||
|
||||
/* operators codes
|
||||
*/
|
||||
typedef enum {
|
||||
ADD = 1, MUL = 2, /* CALC: add and mult */
|
||||
INP = 3, OUT = 4, /* I/O: input and output value */
|
||||
JMP_T = 5, JMP_F = 6, /* JUMPS: jump if true / if false */
|
||||
SET_LT = 7, SET_EQ = 8, /* COND SETS: set if true/false */
|
||||
ADJ_RL = 9, /* ADDRESSING: adjust relative addr */
|
||||
HLT = 99 /* HALT */
|
||||
} opcode_t;
|
||||
|
||||
/**
|
||||
* ops - array of op-codes, mnemo, and number of parameters
|
||||
* @op: An integer, the opcode
|
||||
* @length: Next instruction offset
|
||||
*/
|
||||
typedef struct {
|
||||
int op;
|
||||
u8 length;
|
||||
} ops_t;
|
||||
|
||||
typedef struct io {
|
||||
s64 val;
|
||||
struct list_head list;
|
||||
} io_t;
|
||||
|
||||
#define MAXOPS 2048
|
||||
typedef struct {
|
||||
s64 length; /* total program length */
|
||||
s64 cur; /* current instruction */
|
||||
s64 rel; /* current relative memory */
|
||||
struct list_head input; /* process input queue */
|
||||
struct list_head output; /* process output queue */
|
||||
s64 mem [MAXOPS]; /* should really be dynamic */
|
||||
} program_t;
|
||||
|
||||
static ops_t ops[] = {
|
||||
[ADD] = { ADD, 4 }, [MUL] = { MUL, 4 },
|
||||
[INP] = { INP, 2 }, [OUT] = { OUT, 2 },
|
||||
[JMP_T] = { JMP_T, 3 }, [JMP_F] = { JMP_F, 3 },
|
||||
[SET_LT] = { SET_LT, 4 }, [SET_EQ] = { SET_EQ, 4 },
|
||||
[ADJ_RL] = { ADJ_RL, 2 },
|
||||
[HLT] = { HLT, 1 }
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
IND = 0,
|
||||
DIR = 1,
|
||||
REL = 2
|
||||
} param_t;
|
||||
|
||||
static __always_inline int getop(program_t *prg, int addr)
|
||||
{
|
||||
return prg->mem[addr] % 100;
|
||||
}
|
||||
|
||||
static __always_inline param_t paramtype(program_t *prg, int addr, int param)
|
||||
{
|
||||
static int _flag_pow10[] = {1, 100, 1000, 10000};
|
||||
return prg->mem[addr] / _flag_pow10[param] % 10;
|
||||
}
|
||||
|
||||
#define DIRECT(p, i) ((p)->mem[i])
|
||||
#define INDIRECT(p, i) (DIRECT(p, DIRECT(p, i)))
|
||||
#define RELATIVE(p, i) (DIRECT(p, DIRECT(p, i) + p->rel))
|
||||
|
||||
static __always_inline s64 peek(program_t *prg, s64 cur, s64 param)
|
||||
{
|
||||
switch(paramtype(prg, cur, param)) {
|
||||
case IND:
|
||||
return INDIRECT(prg, cur + param);
|
||||
case REL:
|
||||
return RELATIVE(prg, cur + param);
|
||||
case DIR:
|
||||
return DIRECT(prg, cur + param);
|
||||
}
|
||||
return 0; /* not reached */
|
||||
}
|
||||
|
||||
static __always_inline void poke(program_t *prg, int cur, int param, s64 val)
|
||||
{
|
||||
if (paramtype(prg, cur, param) == REL)
|
||||
RELATIVE(prg, cur + param) = val;
|
||||
else
|
||||
INDIRECT(prg, cur + param) = val;
|
||||
}
|
||||
|
||||
static pool_t *pool_io;
|
||||
|
||||
static inline int prg_add_input(program_t *prg, s64 in)
|
||||
{
|
||||
io_t *input = pool_get(pool_io);
|
||||
input->val = in;
|
||||
list_add_tail(&input->list, &prg->input);
|
||||
return in;
|
||||
}
|
||||
|
||||
static inline s64 prg_add_output(program_t *prg, s64 out)
|
||||
{
|
||||
io_t *output = pool_get(pool_io);
|
||||
output->val = out;
|
||||
list_add_tail(&output->list, &prg->output);
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline int prg_get_input(program_t *prg, s64 *in)
|
||||
{
|
||||
io_t *input = list_first_entry_or_null(&prg->input, io_t, list);
|
||||
if (!input)
|
||||
return 0;
|
||||
*in = input->val;
|
||||
list_del(&input->list);
|
||||
pool_add(pool_io, input);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline _unused int prg_get_output(program_t *prg, s64 *out)
|
||||
{
|
||||
io_t *output = list_first_entry_or_null(&prg->output, io_t, list);
|
||||
if (!output)
|
||||
return 0;
|
||||
*out = output->val;
|
||||
list_del(&output->list);
|
||||
pool_add(pool_io, output);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static s64 run(program_t *p, int *end)
|
||||
{
|
||||
s64 out = -1, input;
|
||||
|
||||
while (1) {
|
||||
int cur = p->cur;
|
||||
opcode_t op = getop(p, p->cur);
|
||||
|
||||
if (!(ops[op].op)) {
|
||||
fprintf(stderr, "PANIC: illegal instruction %d at %ld.\n", op, p->cur);
|
||||
return -1;
|
||||
}
|
||||
switch (op) {
|
||||
case ADD:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) + peek(p, p->cur, 2));
|
||||
break;
|
||||
case MUL:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) * peek(p, p->cur, 2));
|
||||
break;
|
||||
case INP:
|
||||
if (prg_get_input(p, &input))
|
||||
poke(p, p->cur, 1, input);
|
||||
else
|
||||
/* we need an input which is not yet avalaible, so we need
|
||||
* to put the program in "waiting mode": We stop it (and
|
||||
* return output value) without setting end flag.
|
||||
*/
|
||||
goto sleep;
|
||||
break;
|
||||
case OUT:
|
||||
prg_add_output(p, out = peek(p, p->cur, 1));
|
||||
break;
|
||||
case JMP_T:
|
||||
if (peek(p, p->cur, 1))
|
||||
p->cur = peek(p, p->cur, 2);
|
||||
break;
|
||||
case JMP_F:
|
||||
if (!peek(p, p->cur, 1))
|
||||
p->cur = peek(p, p->cur, 2);
|
||||
break;
|
||||
case SET_LT:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) < peek(p, p->cur, 2) ? 1: 0);
|
||||
break;
|
||||
case SET_EQ:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) == peek(p, p->cur, 2) ? 1: 0);
|
||||
break;
|
||||
case ADJ_RL:
|
||||
p->rel += peek(p, p->cur, 1);
|
||||
break;
|
||||
case HLT:
|
||||
*end = 1;
|
||||
sleep:
|
||||
return out;
|
||||
}
|
||||
if (p->cur == cur)
|
||||
p->cur += ops[op].length;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse(program_t *prog)
|
||||
{
|
||||
while (scanf("%ld%*c", &prog->mem[prog->length++]) > 0)
|
||||
;
|
||||
}
|
||||
|
||||
static int usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int opt, part = 1;
|
||||
|
||||
while ((opt = getopt(ac, av, "d:p:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
debug_level_set(atoi(optarg));
|
||||
break;
|
||||
case 'p': /* 1 or 2 */
|
||||
part = atoi(optarg);
|
||||
if (part < 1 || part > 2)
|
||||
return usage(*av);
|
||||
break;
|
||||
default:
|
||||
return usage(*av);
|
||||
}
|
||||
}
|
||||
if (optind < ac)
|
||||
return usage(*av);
|
||||
|
||||
int end = 0;
|
||||
program_t p = { 0 };
|
||||
|
||||
pool_io = pool_create("i/o", 128, sizeof(io_t));
|
||||
|
||||
INIT_LIST_HEAD(&p.input);
|
||||
INIT_LIST_HEAD(&p.output);
|
||||
prg_add_input(&p, part);
|
||||
parse(&p);
|
||||
|
||||
printf("%s : res=%ld\n", *av, run(&p, &end));
|
||||
pool_destroy(pool_io);
|
||||
exit(0);
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
#define BITS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* next include will define __WORDSIZE: 32 or 64
|
||||
*/
|
||||
@@ -262,7 +263,231 @@ static __always_inline int popcount32(u32 n)
|
||||
# endif
|
||||
}
|
||||
|
||||
/* rolXX are taken from kernel's <linux/bitops.h> are are:
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* rol64 - rotate a 64-bit value left
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u64 rol64(u64 word, unsigned int shift)
|
||||
{
|
||||
return (word << (shift & 63)) | (word >> ((-shift) & 63));
|
||||
}
|
||||
|
||||
/**
|
||||
* ror64 - rotate a 64-bit value right
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u64 ror64(u64 word, unsigned int shift)
|
||||
{
|
||||
return (word >> (shift & 63)) | (word << ((-shift) & 63));
|
||||
}
|
||||
|
||||
/**
|
||||
* rol32 - rotate a 32-bit value left
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u32 rol32(u32 word, unsigned int shift)
|
||||
{
|
||||
return (word << (shift & 31)) | (word >> ((-shift) & 31));
|
||||
}
|
||||
|
||||
/**
|
||||
* ror32 - rotate a 32-bit value right
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u32 ror32(u32 word, unsigned int shift)
|
||||
{
|
||||
return (word >> (shift & 31)) | (word << ((-shift) & 31));
|
||||
}
|
||||
|
||||
/**
|
||||
* rol16 - rotate a 16-bit value left
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u16 rol16(u16 word, unsigned int shift)
|
||||
{
|
||||
return (word << (shift & 15)) | (word >> ((-shift) & 15));
|
||||
}
|
||||
|
||||
/**
|
||||
* ror16 - rotate a 16-bit value right
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u16 ror16(u16 word, unsigned int shift)
|
||||
{
|
||||
return (word >> (shift & 15)) | (word << ((-shift) & 15));
|
||||
}
|
||||
|
||||
/**
|
||||
* rol8 - rotate an 8-bit value left
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u8 rol8(u8 word, unsigned int shift)
|
||||
{
|
||||
return (word << (shift & 7)) | (word >> ((-shift) & 7));
|
||||
}
|
||||
|
||||
/**
|
||||
* ror8 - rotate an 8-bit value right
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u8 ror8(u8 word, unsigned int shift)
|
||||
{
|
||||
return (word >> (shift & 7)) | (word << ((-shift) & 7));
|
||||
}
|
||||
|
||||
/**
|
||||
* ilog2 -
|
||||
*/
|
||||
static __always_inline __attribute__((const))
|
||||
int __ilog2_u32(u32 n)
|
||||
{
|
||||
return fls32(n) - 1;
|
||||
}
|
||||
|
||||
static __always_inline __attribute__((const))
|
||||
int __ilog2_u64(u64 n)
|
||||
{
|
||||
return fls64(n) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_power_of_2() - check if a value is a power of two
|
||||
* @n: the value to check
|
||||
*
|
||||
* Determine whether some value is a power of two, where zero is
|
||||
* *not* considered a power of two.
|
||||
* Return: true if @n is a power of 2, otherwise false.
|
||||
*/
|
||||
static inline __attribute__((const))
|
||||
bool is_power_of_2(unsigned long n)
|
||||
{
|
||||
return (n != 0 && ((n & (n - 1)) == 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* ilog2 - log base 2 of 32-bit or a 64-bit unsigned value
|
||||
* @n: parameter
|
||||
*
|
||||
* constant-capable log of base 2 calculation
|
||||
* - this can be used to initialise global variables from constant data, hence
|
||||
* the massive ternary operator construction
|
||||
*
|
||||
* selects the appropriately-sized optimised version depending on sizeof(n)
|
||||
*/
|
||||
#define ilog2(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? \
|
||||
((n) < 2 ? 0 : \
|
||||
63 - __builtin_clzll(n)) : \
|
||||
(sizeof(n) <= 4) ? \
|
||||
__ilog2_u32(n) : \
|
||||
__ilog2_u64(n) \
|
||||
)
|
||||
|
||||
/**
|
||||
* roundup_pow_of_two - round the given value up to nearest power of two
|
||||
* @n: parameter
|
||||
*
|
||||
* round the given value up to the nearest power of two
|
||||
* - the result is undefined when n == 0
|
||||
* - this can be used to initialise global variables from constant data
|
||||
*/
|
||||
#define roundup_pow_of_two(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? ( \
|
||||
((n) == 1) ? 1 : \
|
||||
(1UL << (ilog2((n) - 1) + 1)) \
|
||||
) : \
|
||||
__roundup_pow_of_two(n) \
|
||||
)
|
||||
|
||||
/**
|
||||
* rounddown_pow_of_two - round the given value down to nearest power of two
|
||||
* @n: parameter
|
||||
*
|
||||
* round the given value down to the nearest power of two
|
||||
* - the result is undefined when n == 0
|
||||
* - this can be used to initialise global variables from constant data
|
||||
*/
|
||||
#define rounddown_pow_of_two(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? ( \
|
||||
(1UL << ilog2(n))) : \
|
||||
__rounddown_pow_of_two(n) \
|
||||
)
|
||||
|
||||
static inline __attribute_const__
|
||||
int __order_base_2(unsigned long n)
|
||||
{
|
||||
return n > 1 ? ilog2(n - 1) + 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* order_base_2 - calculate the (rounded up) base 2 order of the argument
|
||||
* @n: parameter
|
||||
*
|
||||
* The first few values calculated by this routine:
|
||||
* ob2(0) = 0
|
||||
* ob2(1) = 0
|
||||
* ob2(2) = 1
|
||||
* ob2(3) = 2
|
||||
* ob2(4) = 2
|
||||
* ob2(5) = 3
|
||||
* ... and so on.
|
||||
*/
|
||||
#define order_base_2(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? ( \
|
||||
((n) == 0 || (n) == 1) ? 0 : \
|
||||
ilog2((n) - 1) + 1) : \
|
||||
__order_base_2(n) \
|
||||
)
|
||||
|
||||
static inline __attribute__((const))
|
||||
int __bits_per(unsigned long n)
|
||||
{
|
||||
if (n < 2)
|
||||
return 1;
|
||||
if (is_power_of_2(n))
|
||||
return order_base_2(n) + 1;
|
||||
return order_base_2(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* bits_per - calculate the number of bits required for the argument
|
||||
* @n: parameter
|
||||
*
|
||||
* This is constant-capable and can be used for compile time
|
||||
* initializations, e.g bitfields.
|
||||
*
|
||||
* The first few values calculated by this routine:
|
||||
* bf(0) = 1
|
||||
* bf(1) = 1
|
||||
* bf(2) = 2
|
||||
* bf(3) = 2
|
||||
* bf(4) = 3
|
||||
* ... and so on.
|
||||
*/
|
||||
#define bits_per(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? ( \
|
||||
((n) == 0 || (n) == 1) \
|
||||
? 1 : ilog2(n) + 1 \
|
||||
) : \
|
||||
__bits_per(n) \
|
||||
)
|
||||
|
||||
/** bit_for_each - iterate over an u64/u32 bits
|
||||
* @pos: an int used as current bit
|
||||
|
||||
@@ -18,12 +18,18 @@
|
||||
#ifndef _BR_H
|
||||
#define _BR_H
|
||||
|
||||
/* Indirect stringification. Doing two levels allows the parameter to be a
|
||||
* macro itself. For example, compile with -DFOO=bar, __stringify(FOO)
|
||||
* converts to "bar".
|
||||
*/
|
||||
#define __stringify_1(x...) #x
|
||||
#define __stringify(x...) __stringify_1(x)
|
||||
|
||||
/* generate a (maybe) unique id.
|
||||
*/
|
||||
#define ___PASTE(x, y) x##y
|
||||
#define __PASTE(x, y) ___PASTE(x, y)
|
||||
#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
|
||||
//__##prefix##__COUNTER__
|
||||
|
||||
/* see https://lkml.org/lkml/2018/3/20/845 for explanation of this monster
|
||||
*/
|
||||
@@ -63,6 +69,8 @@
|
||||
__cmp(x, y, op), \
|
||||
__cmp_once(x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y), op))
|
||||
|
||||
#define __pure __attribute__((__pure__))
|
||||
|
||||
/**
|
||||
* min - return minimum of two values of the same or compatible types
|
||||
* @x: first value
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
#include "likely.h"
|
||||
#include "debug.h"
|
||||
|
||||
/* inspired by Linux kernel's <asm/bug.h> */
|
||||
/* BUG functions inspired by Linux kernel's <asm/bug.h>
|
||||
*/
|
||||
|
||||
#define panic() exit(0xff)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#ifndef _BR_HASH_H
|
||||
#define _BR_HASH_H
|
||||
/* adaptation of Linux kernel's <linux/hash.h>
|
||||
/* adaptation of Linux kernel's <linux/hash.h> and <linux/stringhash.h>
|
||||
*/
|
||||
|
||||
/* Fast hashing routine for ints, longs and pointers.
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <asm/types.h>
|
||||
#include <asm/bitsperlong.h>
|
||||
#include "bits.h"
|
||||
#include "br.h"
|
||||
|
||||
/*
|
||||
* The "GOLDEN_RATIO_PRIME" is used in ifs/btrfs/brtfs_inode.h and
|
||||
* fs/inode.c. It's not actually prime any more (the previous primes
|
||||
@@ -98,4 +100,74 @@ static inline u32 hash32_ptr(const void *ptr)
|
||||
return (u32)val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines for hashing strings of bytes to a 32-bit hash value.
|
||||
*
|
||||
* These hash functions are NOT GUARANTEED STABLE between kernel
|
||||
* versions, architectures, or even repeated boots of the same kernel.
|
||||
* (E.g. they may depend on boot-time hardware detection or be
|
||||
* deliberately randomized.)
|
||||
*
|
||||
* They are also not intended to be secure against collisions caused by
|
||||
* malicious inputs; much slower hash functions are required for that.
|
||||
*
|
||||
* They are optimized for pathname components, meaning short strings.
|
||||
* Even if a majority of files have longer names, the dynamic profile of
|
||||
* pathname components skews short due to short directory names.
|
||||
* (E.g. /usr/lib/libsesquipedalianism.so.3.141.)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Version 1: one byte at a time. Example of use:
|
||||
*
|
||||
* unsigned long hash = init_name_hash;
|
||||
* while (*p)
|
||||
* hash = partial_name_hash(tolower(*p++), hash);
|
||||
* hash = end_name_hash(hash);
|
||||
*
|
||||
* Although this is designed for bytes, fs/hfsplus/unicode.c
|
||||
* abuses it to hash 16-bit values.
|
||||
*/
|
||||
|
||||
/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
|
||||
#define init_name_hash(salt) (unsigned long)(salt)
|
||||
|
||||
/* partial hash update function. Assume roughly 4 bits per character */
|
||||
static inline unsigned long
|
||||
partial_name_hash(unsigned long c, unsigned long prevhash)
|
||||
{
|
||||
return (prevhash + (c << 4) + (c >> 4)) * 11;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally: cut down the number of bits to a int value (and try to avoid
|
||||
* losing bits). This also has the property (wanted by the dcache)
|
||||
* that the msbits make a good hash table index.
|
||||
*/
|
||||
static inline unsigned int end_name_hash(unsigned long hash)
|
||||
{
|
||||
return hash_long(hash, 32);
|
||||
}
|
||||
|
||||
/*
|
||||
* Version 2: One word (32 or 64 bits) at a time.
|
||||
* If CONFIG_DCACHE_WORD_ACCESS is defined (meaning <asm/word-at-a-time.h>
|
||||
* exists, which describes major Linux platforms like x86 and ARM), then
|
||||
* this computes a different hash function much faster.
|
||||
*
|
||||
* If not set, this falls back to a wrapper around the preceding.
|
||||
*/
|
||||
extern unsigned int __pure hash_string(const void *salt, const char *, unsigned int);
|
||||
|
||||
/*
|
||||
* A hash_len is a u64 with the hash of a string in the low
|
||||
* half and the length in the high half.
|
||||
*/
|
||||
#define hashlen_hash(hashlen) ((u32)(hashlen))
|
||||
#define hashlen_len(hashlen) ((u32)((hashlen) >> 32))
|
||||
#define hashlen_create(hash, len) ((u64)(len)<<32 | (u32)(hash))
|
||||
|
||||
/* Return the "hash_len" (hash and length) of a null-terminated string */
|
||||
extern u64 __pure hashlen_string(const void *salt, const char *name);
|
||||
|
||||
#endif /* _BR_HASH_H */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* pool.h - A simple memory pool manager.
|
||||
*
|
||||
* Copyright (C) 2021 Bruno Raoult ("br")
|
||||
* Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
* Licensed under the GNU General Public License v3.0 or later.
|
||||
* Some rights reserved. See COPYING.
|
||||
*
|
||||
|
||||
@@ -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,7 +490,72 @@ ex1.bash: res=31314
|
||||
time: 0:00.07 real, 0.06 user, 0.00 sys
|
||||
context-switch: 2+1, page-faults: 0+168
|
||||
|
||||
aoc-c : res=31314
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+89
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash: res=32760
|
||||
time: 1:21.92 real, 81.89 user, 0.01 sys
|
||||
context-switch: 462+1, page-faults: 0+5135
|
||||
|
||||
aoc-c : res=32760
|
||||
time: 0:01.11 real, 1.09 user, 0.01 sys
|
||||
context-switch: 70+1, page-faults: 0+1933
|
||||
|
||||
=========================================
|
||||
================= day23 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash: res=75893264
|
||||
time: 0:00.01 real, 0.01 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+166
|
||||
|
||||
aoc-c : res=75893264
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+83
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash: res=38162588308
|
||||
time: 6:52.50 real, 412.30 user, 0.14 sys
|
||||
context-switch: 2219+1, page-faults: 0+30233
|
||||
|
||||
aoc-c : res=38162588308
|
||||
time: 0:01.33 real, 1.32 user, 0.01 sys
|
||||
context-switch: 3+1, page-faults: 0+3992
|
||||
|
||||
=========================================
|
||||
================= day24 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash: res=450
|
||||
time: 0:00.17 real, 0.16 user, 0.00 sys
|
||||
context-switch: 1+1, page-faults: 0+177
|
||||
|
||||
aoc-c : res=450
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+100
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash: res=4059
|
||||
time: 0:22.35 real, 22.22 user, 0.07 sys
|
||||
context-switch: 1102+1, page-faults: 0+858
|
||||
|
||||
aoc-c : res=4059
|
||||
time: 0:00.04 real, 0.04 user, 0.00 sys
|
||||
context-switch: 16+1, page-faults: 0+215
|
||||
|
||||
=========================================
|
||||
================= day25 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash: res=9620012
|
||||
time: 2:42.30 real, 162.05 user, 0.08 sys
|
||||
context-switch: 3634+1, page-faults: 0+163
|
||||
|
||||
ex1-c : res=9620012
|
||||
time: 0:00.08 real, 0.08 user, 0.00 sys
|
||||
context-switch: 2+1, page-faults: 0+79
|
||||
|
||||
@@ -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,8 +0,0 @@
|
||||
ex1.bash: res=2211
|
||||
time: 0:01.72 real, 1.71 user, 0.00 sys
|
||||
context-switch: 9+1, page-faults: 0+1090
|
||||
|
||||
ex2.bash: res=vv,nlxsmb,rnbhjk,bvnkk,ttxvphb,qmkz,trmzkcfg,jpvz
|
||||
time: 0:01.75 real, 1.74 user, 0.00 sys
|
||||
context-switch: 36+4, page-faults: 0+1388
|
||||
|
||||
@@ -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.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user