Compare commits
1 Commits
main
...
8bc0e74e10
| Author | SHA1 | Date | |
|---|---|---|---|
| 8bc0e74e10 |
14
.gitignore
vendored
14
.gitignore
vendored
@@ -1,15 +1,3 @@
|
|||||||
ex*-c
|
ex*-c
|
||||||
aoc-c
|
core
|
||||||
core*
|
|
||||||
.ccls*
|
|
||||||
.projectile
|
|
||||||
.dir-locals.el
|
|
||||||
gmon.out
|
|
||||||
*.o
|
|
||||||
ex*-cob
|
ex*-cob
|
||||||
lib/
|
|
||||||
GPATH
|
|
||||||
GRTAGS
|
|
||||||
GTAGS
|
|
||||||
README.html
|
|
||||||
compile_commands.json
|
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
# AOC Makefile - GNU make only.
|
|
||||||
#
|
|
||||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
|
||||||
# Licensed under the GNU General Public License v3.0 or later.
|
|
||||||
# Some rights reserved. See COPYING.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with this
|
|
||||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
SUBDIRS := $(shell echo day??)
|
|
||||||
|
|
||||||
CC = gcc
|
|
||||||
|
|
||||||
#LIBS = -lreadline -lncurses
|
|
||||||
CFLAGS += -std=gnu11
|
|
||||||
|
|
||||||
CFLAGS += -O2
|
|
||||||
CFLAGS += -g
|
|
||||||
#CFLAGS += -pg
|
|
||||||
CFLAGS += -Wall
|
|
||||||
CFLAGS += -Wextra
|
|
||||||
CFLAGS += -march=native
|
|
||||||
|
|
||||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
|
||||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
|
||||||
|
|
||||||
INCDIR := ./include
|
|
||||||
LIBSRCDIR := ./libsrc
|
|
||||||
LIBDIR := ./lib
|
|
||||||
LIB := libaoc_$(shell uname -m)
|
|
||||||
SLIB := $(LIBDIR)/$(LIB).a
|
|
||||||
DLIB := $(LIBDIR)/$(LIB).so
|
|
||||||
LIBSRC := $(wildcard $(LIBSRCDIR)/*.c)
|
|
||||||
LIBOBJ := $(patsubst %.c,%.o,$(LIBSRC))
|
|
||||||
LDFLAGS := -L$(LIBDIR)
|
|
||||||
LDLIB := -l$(LIB)
|
|
||||||
|
|
||||||
.PHONY: clean cleanlib cleanall all redo output lib $(SUBDIRS)
|
|
||||||
|
|
||||||
all: lib $(SUBDIRS)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@for dir in $(SUBDIRS) ; do \
|
|
||||||
$(MAKE) --no-print-directory -C $$dir clean ; \
|
|
||||||
done
|
|
||||||
|
|
||||||
cleanlib: clean
|
|
||||||
@$(RM) -f $(SLIB) $(DLIB) $(LIBOBJ)
|
|
||||||
|
|
||||||
cleanall: clean cleanlib
|
|
||||||
|
|
||||||
redo: cleanall all
|
|
||||||
|
|
||||||
$(SUBDIRS):
|
|
||||||
@echo "========================================="
|
|
||||||
@echo "================= $@ ================="
|
|
||||||
@echo "========================================="
|
|
||||||
@echo
|
|
||||||
@echo "+++++++++++++++++ part 1"
|
|
||||||
+@$(MAKE) --no-print-directory -C $@ 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 $@ $<
|
|
||||||
132
2019/RESULTS.txt
132
2019/RESULTS.txt
@@ -1,132 +0,0 @@
|
|||||||
=========================================
|
|
||||||
================= day01 =================
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
+++++++++++++++++ part 1
|
|
||||||
aoc-c : res=3318604
|
|
||||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
|
||||||
context-switch: 0+1, page-faults: 0+87
|
|
||||||
|
|
||||||
+++++++++++++++++ part 2
|
|
||||||
aoc-c : res=4975039
|
|
||||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
|
||||||
context-switch: 0+1, page-faults: 0+89
|
|
||||||
|
|
||||||
=========================================
|
|
||||||
================= day02 =================
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
+++++++++++++++++ part 1
|
|
||||||
aoc-c : res=3790689
|
|
||||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
|
||||||
context-switch: 0+1, page-faults: 0+88
|
|
||||||
|
|
||||||
+++++++++++++++++ part 2
|
|
||||||
aoc-c : res=6533
|
|
||||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
|
||||||
context-switch: 0+1, page-faults: 0+88
|
|
||||||
|
|
||||||
=========================================
|
|
||||||
================= day03 =================
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
+++++++++++++++++ part 1
|
|
||||||
aoc-c : res=860
|
|
||||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
|
||||||
context-switch: 0+1, page-faults: 0+99
|
|
||||||
|
|
||||||
+++++++++++++++++ part 2
|
|
||||||
aoc-c : res=9238
|
|
||||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
|
||||||
context-switch: 0+1, page-faults: 0+98
|
|
||||||
|
|
||||||
=========================================
|
|
||||||
================= day04 =================
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
+++++++++++++++++ part 1
|
|
||||||
aoc-c : res=2090
|
|
||||||
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.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,100 +0,0 @@
|
|||||||
123457
|
|
||||||
98952
|
|
||||||
65241
|
|
||||||
62222
|
|
||||||
144922
|
|
||||||
111868
|
|
||||||
71513
|
|
||||||
74124
|
|
||||||
140122
|
|
||||||
133046
|
|
||||||
65283
|
|
||||||
107447
|
|
||||||
144864
|
|
||||||
136738
|
|
||||||
118458
|
|
||||||
91049
|
|
||||||
71486
|
|
||||||
100320
|
|
||||||
143765
|
|
||||||
88677
|
|
||||||
62034
|
|
||||||
139946
|
|
||||||
81017
|
|
||||||
128668
|
|
||||||
126450
|
|
||||||
56551
|
|
||||||
136839
|
|
||||||
64516
|
|
||||||
91821
|
|
||||||
139909
|
|
||||||
52907
|
|
||||||
78846
|
|
||||||
102008
|
|
||||||
58518
|
|
||||||
128627
|
|
||||||
71256
|
|
||||||
133546
|
|
||||||
90986
|
|
||||||
50808
|
|
||||||
139055
|
|
||||||
88769
|
|
||||||
94491
|
|
||||||
128902
|
|
||||||
55976
|
|
||||||
103658
|
|
||||||
123605
|
|
||||||
113468
|
|
||||||
128398
|
|
||||||
61725
|
|
||||||
100388
|
|
||||||
96763
|
|
||||||
101378
|
|
||||||
139952
|
|
||||||
138298
|
|
||||||
87171
|
|
||||||
51840
|
|
||||||
64828
|
|
||||||
58250
|
|
||||||
88273
|
|
||||||
136781
|
|
||||||
120097
|
|
||||||
127291
|
|
||||||
143752
|
|
||||||
117291
|
|
||||||
100023
|
|
||||||
147239
|
|
||||||
71296
|
|
||||||
100907
|
|
||||||
127612
|
|
||||||
122424
|
|
||||||
62942
|
|
||||||
95445
|
|
||||||
74040
|
|
||||||
118994
|
|
||||||
81810
|
|
||||||
146408
|
|
||||||
98939
|
|
||||||
71359
|
|
||||||
112120
|
|
||||||
100630
|
|
||||||
139576
|
|
||||||
98998
|
|
||||||
92481
|
|
||||||
53510
|
|
||||||
76343
|
|
||||||
125428
|
|
||||||
73447
|
|
||||||
62472
|
|
||||||
91370
|
|
||||||
73506
|
|
||||||
126539
|
|
||||||
50739
|
|
||||||
73133
|
|
||||||
81906
|
|
||||||
100856
|
|
||||||
52758
|
|
||||||
142303
|
|
||||||
107605
|
|
||||||
77797
|
|
||||||
124355
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
# 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 $@
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
** --- Day 1: The Tyranny of the Rocket Equation ---
|
|
||||||
Santa has become stranded at the edge of the Solar System while
|
|
||||||
delivering presents to other planets! To accurately calculate his
|
|
||||||
position in space, safely align his warp drive, and return to Earth in
|
|
||||||
time to save Christmas, he needs you to bring him measurements from
|
|
||||||
/fifty stars/.
|
|
||||||
|
|
||||||
Collect stars by solving puzzles. Two puzzles will be made available on
|
|
||||||
each day in the Advent calendar; the second puzzle is unlocked when you
|
|
||||||
complete the first. Each puzzle grants /one star/. Good luck!
|
|
||||||
|
|
||||||
The Elves quickly load you into a spacecraft and prepare to launch.
|
|
||||||
|
|
||||||
At the first Go / No Go poll, every Elf is Go until the Fuel
|
|
||||||
Counter-Upper. They haven't determined the amount of fuel required yet.
|
|
||||||
|
|
||||||
Fuel required to launch a given /module/ is based on its /mass/.
|
|
||||||
Specifically, to find the fuel required for a module, take its mass,
|
|
||||||
divide by three, round down, and subtract 2.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
- For a mass of =12=, divide by 3 and round down to get =4=, then
|
|
||||||
subtract 2 to get =2=.
|
|
||||||
- For a mass of =14=, dividing by 3 and rounding down still yields =4=,
|
|
||||||
so the fuel required is also =2=.
|
|
||||||
- For a mass of =1969=, the fuel required is =654=.
|
|
||||||
- For a mass of =100756=, the fuel required is =33583=.
|
|
||||||
|
|
||||||
The Fuel Counter-Upper needs to know the total fuel requirement. To find
|
|
||||||
it, individually calculate the fuel needed for the mass of each module
|
|
||||||
(your puzzle input), then add together all the fuel values.
|
|
||||||
|
|
||||||
/What is the sum of the fuel requirements/ for all of the modules on
|
|
||||||
your spacecraft?
|
|
||||||
|
|
||||||
Your puzzle answer was =3318604=.
|
|
||||||
|
|
||||||
** --- Part Two ---
|
|
||||||
During the second Go / No Go poll, the Elf in charge of the Rocket
|
|
||||||
Equation Double-Checker stops the launch sequence. Apparently, you
|
|
||||||
forgot to include additional fuel for the fuel you just added.
|
|
||||||
|
|
||||||
Fuel itself requires fuel just like a module - take its mass, divide by
|
|
||||||
three, round down, and subtract 2. However, that fuel /also/ requires
|
|
||||||
fuel, and /that/ fuel requires fuel, and so on. Any mass that would
|
|
||||||
require /negative fuel/ should instead be treated as if it requires
|
|
||||||
/zero fuel/; the remaining mass, if any, is instead handled by /wishing
|
|
||||||
really hard/, which has no mass and is outside the scope of this
|
|
||||||
calculation.
|
|
||||||
|
|
||||||
So, for each module mass, calculate its fuel and add it to the total.
|
|
||||||
Then, treat the fuel amount you just calculated as the input mass and
|
|
||||||
repeat the process, continuing until a fuel requirement is zero or
|
|
||||||
negative. For example:
|
|
||||||
|
|
||||||
- A module of mass =14= requires =2= fuel. This fuel requires no further
|
|
||||||
fuel (2 divided by 3 and rounded down is =0=, which would call for a
|
|
||||||
negative fuel), so the total fuel required is still just =2=.
|
|
||||||
- At first, a module of mass =1969= requires =654= fuel. Then, this fuel
|
|
||||||
requires =216= more fuel (=654 / 3 - 2=). =216= then requires =70=
|
|
||||||
more fuel, which requires =21= fuel, which requires =5= fuel, which
|
|
||||||
requires no further fuel. So, the total fuel required for a module of
|
|
||||||
mass =1969= is =654 + 216 + 70 + 21 + 5 = 966=.
|
|
||||||
- The fuel required by a module of mass =100756= and its fuel is:
|
|
||||||
=33583 + 11192 + 3728 + 1240 + 411 + 135 + 43 + 12 + 2 = 50346=.
|
|
||||||
|
|
||||||
/What is the sum of the fuel requirements/ for all of the modules on
|
|
||||||
your spacecraft when also taking into account the mass of the added
|
|
||||||
fuel? (Calculate the fuel requirements for each module separately, then
|
|
||||||
add them all up at the end.)
|
|
||||||
|
|
||||||
Your puzzle answer was =4975039=.
|
|
||||||
|
|
||||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
/* aoc-c.c: Advent of Code 2019, day 1 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 "debug.h"
|
|
||||||
#include "pool.h"
|
|
||||||
#include "list.h"
|
|
||||||
#include "bits.h"
|
|
||||||
|
|
||||||
static u64 part1()
|
|
||||||
{
|
|
||||||
u64 res = 0;
|
|
||||||
int cur;
|
|
||||||
|
|
||||||
while (scanf("%d", &cur) != EOF)
|
|
||||||
res += cur / 3 - 2;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u64 part2()
|
|
||||||
{
|
|
||||||
u64 res = 0;
|
|
||||||
int cur;
|
|
||||||
|
|
||||||
while (scanf("%d", &cur) != EOF)
|
|
||||||
while ((cur = cur / 3 - 2) > 0)
|
|
||||||
res += cur;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
return usage(*av);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return usage(*av);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (optind < ac)
|
|
||||||
return usage(*av);
|
|
||||||
|
|
||||||
printf("%s : res=%lu\n", *av, part == 1? part1(): part2());
|
|
||||||
|
|
||||||
exit (0);
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
1,9,10,3,2,3,11,0,99,30,40,50
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
1,0,0,0,99
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
2,3,0,3,99
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
2,4,4,5,99,0
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
1,1,1,4,99,5,6,0,99
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
1,0,0,3,1,1,2,3,1,3,4,3,1,5,0,3,2,1,13,19,1,9,19,23,2,13,23,27,2,27,13,31,2,31,10,35,1,6,35,39,1,5,39,43,1,10,43,47,1,5,47,51,1,13,51,55,2,55,9,59,1,6,59,63,1,13,63,67,1,6,67,71,1,71,10,75,2,13,75,79,1,5,79,83,2,83,6,87,1,6,87,91,1,91,13,95,1,95,13,99,2,99,13,103,1,103,5,107,2,107,10,111,1,5,111,115,1,2,115,119,1,119,6,0,99,2,0,14,0
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
# 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 $@
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
** --- Day 2: 1202 Program Alarm ---
|
|
||||||
On the way to your
|
|
||||||
[[https://en.wikipedia.org/wiki/Gravity_assist][gravity assist]] around
|
|
||||||
the Moon, your ship computer beeps angrily about a
|
|
||||||
"[[https://www.hq.nasa.gov/alsj/a11/a11.landing.html#1023832][1202
|
|
||||||
program alarm]]". On the radio, an Elf is already explaining how to
|
|
||||||
handle the situation: "Don't worry, that's perfectly norma--" The ship
|
|
||||||
computer [[https://en.wikipedia.org/wiki/Halt_and_Catch_Fire][bursts
|
|
||||||
into flames]].
|
|
||||||
|
|
||||||
You notify the Elves that the computer's
|
|
||||||
[[https://en.wikipedia.org/wiki/Magic_smoke][magic smoke]] seems to have
|
|
||||||
escaped. "That computer ran /Intcode/ programs like the gravity assist
|
|
||||||
program it was working on; surely there are enough spare parts up there
|
|
||||||
to build a new Intcode computer!"
|
|
||||||
|
|
||||||
An Intcode program is a list of
|
|
||||||
[[https://en.wikipedia.org/wiki/Integer][integers]] separated by commas
|
|
||||||
(like =1,0,0,3,99=). To run one, start by looking at the first integer
|
|
||||||
(called position =0=). Here, you will find an /opcode/ - either =1=,
|
|
||||||
=2=, or =99=. The opcode indicates what to do; for example, =99= means
|
|
||||||
that the program is finished and should immediately halt. Encountering
|
|
||||||
an unknown opcode means something went wrong.
|
|
||||||
|
|
||||||
Opcode =1= /adds/ together numbers read from two positions and stores
|
|
||||||
the result in a third position. The three integers /immediately after/
|
|
||||||
the opcode tell you these three positions - the first two indicate the
|
|
||||||
/positions/ from which you should read the input values, and the third
|
|
||||||
indicates the /position/ at which the output should be stored.
|
|
||||||
|
|
||||||
For example, if your Intcode computer encounters =1,10,20,30=, it should
|
|
||||||
read the values at positions =10= and =20=, add those values, and then
|
|
||||||
overwrite the value at position =30= with their sum.
|
|
||||||
|
|
||||||
Opcode =2= works exactly like opcode =1=, except it /multiplies/ the two
|
|
||||||
inputs instead of adding them. Again, the three integers after the
|
|
||||||
opcode indicate /where/ the inputs and outputs are, not their values.
|
|
||||||
|
|
||||||
Once you're done processing an opcode, /move to the next one/ by
|
|
||||||
stepping forward =4= positions.
|
|
||||||
|
|
||||||
For example, suppose you have the following program:
|
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
|
||||||
1,9,10,3,2,3,11,0,99,30,40,50
|
|
||||||
#+END_EXAMPLE
|
|
||||||
|
|
||||||
For the purposes of illustration, here is the same program split into
|
|
||||||
multiple lines:
|
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
|
||||||
1,9,10,3,
|
|
||||||
2,3,11,0,
|
|
||||||
99,
|
|
||||||
30,40,50
|
|
||||||
#+END_EXAMPLE
|
|
||||||
|
|
||||||
The first four integers, =1,9,10,3=, are at positions =0=, =1=, =2=, and
|
|
||||||
=3=. Together, they represent the first opcode (=1=, addition), the
|
|
||||||
positions of the two inputs (=9= and =10=), and the position of the
|
|
||||||
output (=3=). To handle this opcode, you first need to get the values at
|
|
||||||
the input positions: position =9= contains =30=, and position =10=
|
|
||||||
contains =40=. /Add/ these numbers together to get =70=. Then, store
|
|
||||||
this value at the output position; here, the output position (=3=) is
|
|
||||||
/at/ position =3=, so it overwrites itself. Afterward, the program looks
|
|
||||||
like this:
|
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
|
||||||
1,9,10,70,
|
|
||||||
2,3,11,0,
|
|
||||||
99,
|
|
||||||
30,40,50
|
|
||||||
#+END_EXAMPLE
|
|
||||||
|
|
||||||
Step forward =4= positions to reach the next opcode, =2=. This opcode
|
|
||||||
works just like the previous, but it multiplies instead of adding. The
|
|
||||||
inputs are at positions =3= and =11=; these positions contain =70= and
|
|
||||||
=50= respectively. Multiplying these produces =3500=; this is stored at
|
|
||||||
position =0=:
|
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
|
||||||
3500,9,10,70,
|
|
||||||
2,3,11,0,
|
|
||||||
99,
|
|
||||||
30,40,50
|
|
||||||
#+END_EXAMPLE
|
|
||||||
|
|
||||||
Stepping forward =4= more positions arrives at opcode =99=, halting the
|
|
||||||
program.
|
|
||||||
|
|
||||||
Here are the initial and final states of a few more small programs:
|
|
||||||
|
|
||||||
- =1,0,0,0,99= becomes =2,0,0,0,99= (=1 + 1 = 2=).
|
|
||||||
- =2,3,0,3,99= becomes =2,3,0,6,99= (=3 * 2 = 6=).
|
|
||||||
- =2,4,4,5,99,0= becomes =2,4,4,5,99,9801= (=99 * 99 = 9801=).
|
|
||||||
- =1,1,1,4,99,5,6,0,99= becomes =30,1,1,4,2,5,6,0,99=.
|
|
||||||
|
|
||||||
Once you have a working computer, the first step is to restore the
|
|
||||||
gravity assist program (your puzzle input) to the "1202 program alarm"
|
|
||||||
state it had just before the last computer caught fire. To do this,
|
|
||||||
/before running the program/, replace position =1= with the value =12=
|
|
||||||
and replace position =2= with the value =2=. /What value is left at
|
|
||||||
position =0=/ after the program halts?
|
|
||||||
|
|
||||||
Your puzzle answer was =3790689=.
|
|
||||||
|
|
||||||
** --- Part Two ---
|
|
||||||
"Good, the new computer seems to be working correctly! /Keep it nearby/
|
|
||||||
during this mission - you'll probably use it again. Real Intcode
|
|
||||||
computers support many more features than your new one, but we'll let
|
|
||||||
you know what they are as you need them."
|
|
||||||
|
|
||||||
"However, your current priority should be to complete your gravity
|
|
||||||
assist around the Moon. For this mission to succeed, we should settle on
|
|
||||||
some terminology for the parts you've already built."
|
|
||||||
|
|
||||||
Intcode programs are given as a list of integers; these values are used
|
|
||||||
as the initial state for the computer's /memory/. When you run an
|
|
||||||
Intcode program, make sure to start by initializing memory to the
|
|
||||||
program's values. A position in memory is called an /address/ (for
|
|
||||||
example, the first value in memory is at "address 0").
|
|
||||||
|
|
||||||
Opcodes (like =1=, =2=, or =99=) mark the beginning of an /instruction/.
|
|
||||||
The values used immediately after an opcode, if any, are called the
|
|
||||||
instruction's /parameters/. For example, in the instruction =1,2,3,4=,
|
|
||||||
=1= is the opcode; =2=, =3=, and =4= are the parameters. The instruction
|
|
||||||
=99= contains only an opcode and has no parameters.
|
|
||||||
|
|
||||||
The address of the current instruction is called the /instruction
|
|
||||||
pointer/; it starts at =0=. After an instruction finishes, the
|
|
||||||
instruction pointer increases by /the number of values in the
|
|
||||||
instruction/; until you add more instructions to the computer, this is
|
|
||||||
always =4= (=1= opcode + =3= parameters) for the add and multiply
|
|
||||||
instructions. (The halt instruction would increase the instruction
|
|
||||||
pointer by =1=, but it halts the program instead.)
|
|
||||||
|
|
||||||
"With terminology out of the way, we're ready to proceed. To complete
|
|
||||||
the gravity assist, you need to /determine what pair of inputs produces
|
|
||||||
the output =19690720=/."
|
|
||||||
|
|
||||||
The inputs should still be provided to the program by replacing the
|
|
||||||
values at addresses =1= and =2=, just like before. In this program, the
|
|
||||||
value placed in address =1= is called the /noun/, and the value placed
|
|
||||||
in address =2= is called the /verb/. Each of the two input values will
|
|
||||||
be between =0= and =99=, inclusive.
|
|
||||||
|
|
||||||
Once the program has halted, its output is available at address =0=,
|
|
||||||
also just like before. Each time you try a pair of inputs, make sure you
|
|
||||||
first /reset the computer's memory to the values in the program/ (your
|
|
||||||
puzzle input) - in other words, don't reuse memory from a previous
|
|
||||||
attempt.
|
|
||||||
|
|
||||||
Find the input /noun/ and /verb/ that cause the program to produce the
|
|
||||||
output =19690720=. /What is =100 * noun + verb=?/ (For example, if
|
|
||||||
=noun=12= and =verb=2=, the answer would be =1202=.)
|
|
||||||
|
|
||||||
Your puzzle answer was =6533=.
|
|
||||||
|
|
||||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
/* aoc-c.c: Advent of Code 2019, day 2 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 "debug.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ADD = 1,
|
|
||||||
MUL = 2,
|
|
||||||
RET = 99
|
|
||||||
} opcode_t;
|
|
||||||
|
|
||||||
#define MAXOPS 1024
|
|
||||||
struct program {
|
|
||||||
int length; /* total program length */
|
|
||||||
int cur; /* current position */
|
|
||||||
int ops[MAXOPS]; /* should really be dynamic */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define OP(p) ((p)->ops + (p)->cur)
|
|
||||||
|
|
||||||
#define A1(p) ((p)->ops + *((p)->ops + (p)->cur + 1))
|
|
||||||
#define A2(p) ((p)->ops + *((p)->ops + (p)->cur + 2))
|
|
||||||
#define A3(p) ((p)->ops + *((p)->ops + (p)->cur + 3))
|
|
||||||
|
|
||||||
static int run(struct program *prog)
|
|
||||||
{
|
|
||||||
while (1) {
|
|
||||||
opcode_t opcode = *OP(prog);
|
|
||||||
switch (opcode) {
|
|
||||||
case ADD:
|
|
||||||
*A3(prog) = *A1(prog) + *A2(prog);
|
|
||||||
break;
|
|
||||||
case MUL:
|
|
||||||
*A3(prog) = *A1(prog) * *A2(prog);
|
|
||||||
break;
|
|
||||||
case RET:
|
|
||||||
return prog->ops[0];
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "wrong opcode %d at %d.\n", opcode, prog->cur);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
prog->cur += 4;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct program *parse()
|
|
||||||
{
|
|
||||||
size_t alloc = 0;
|
|
||||||
ssize_t buflen;
|
|
||||||
char *buf = NULL, *token;
|
|
||||||
int input;
|
|
||||||
struct program *prog = NULL;
|
|
||||||
|
|
||||||
if ((buflen = getline(&buf, &alloc, stdin)) <= 0) {
|
|
||||||
fprintf(stderr, "error reading file.\n");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(prog = calloc(1, sizeof(struct program)))) {
|
|
||||||
fprintf(stderr, "cannot allocate program.\n");
|
|
||||||
goto freebuf;
|
|
||||||
}
|
|
||||||
for (token = strtok(buf, ","); token; token = strtok(NULL, ",")) {
|
|
||||||
if (prog->length >= MAXOPS - 1) {
|
|
||||||
fprintf(stderr, "overflow !\n");
|
|
||||||
free(prog);
|
|
||||||
prog = NULL;
|
|
||||||
goto freebuf;
|
|
||||||
}
|
|
||||||
input=atoi(token);
|
|
||||||
prog->ops[prog->length++] = input;
|
|
||||||
}
|
|
||||||
freebuf:
|
|
||||||
free(buf);
|
|
||||||
end:
|
|
||||||
return prog;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int part1(struct program *p)
|
|
||||||
{
|
|
||||||
p->ops[1] = 12;
|
|
||||||
p->ops[2] = 2;
|
|
||||||
|
|
||||||
return run(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int part2(struct program *p)
|
|
||||||
{
|
|
||||||
struct program work;
|
|
||||||
|
|
||||||
for (int noun = 0; noun < 100; ++noun) {
|
|
||||||
for (int verb = 0; verb < 100; ++verb) {
|
|
||||||
work = *p;
|
|
||||||
work.ops[1] = noun;
|
|
||||||
work.ops[2] = verb;
|
|
||||||
if (run(&work) == 19690720)
|
|
||||||
return noun * 100 + verb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
struct program *p;
|
|
||||||
|
|
||||||
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);
|
|
||||||
p = parse();
|
|
||||||
printf("%s : res=%d\n", *av, part == 1? part1(p): part2(p));
|
|
||||||
free(p);
|
|
||||||
exit (0);
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
R8,U5,L5,D3
|
|
||||||
U7,R6,D4,L4
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
R75,D30,R83,U83,L12,D49,R71,U7,L72
|
|
||||||
U62,R66,U55,R34,D71,R55,D58,R83
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51
|
|
||||||
U98,R91,D20,R16,D67,R40,U7,R15,U6,R7
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
R1000,D722,L887,D371,R430,D952,R168,D541,L972,D594,R377,U890,R544,U505,L629,U839,L680,D863,L315,D10,L482,U874,L291,U100,R770,D717,L749,U776,L869,D155,R250,U672,L195,D991,L556,D925,R358,U296,R647,D652,L790,D780,L865,U405,L400,D160,L460,U50,R515,D666,R306,U746,R754,U854,L332,U254,R673,U795,R560,U69,L507,U332,L328,U547,L717,U291,R626,U868,L583,D256,R371,U462,R793,U559,L571,U270,R738,U425,L231,U549,L465,U21,L647,U43,R847,U104,L699,U378,L549,D975,R13,D306,R532,D730,L566,U846,L903,D224,R448,D424,L727,D199,L626,D872,L541,D786,L304,U462,R347,U379,R29,D556,L775,D768,L284,D480,R654,D659,R818,D57,L77,U140,R619,D148,R686,D461,L910,U244,R115,D769,R968,U802,L737,U868,R399,D150,L791,U579,L856,D11,R115,U522,L443,D575,L133,U750,R437,U718,L79,D119,L97,U471,R817,U438,R157,U105,L219,U777,L965,U687,L906,D744,L983,D350,R664,D917,R431,D721,L153,U757,L665,U526,L49,U166,L59,D293,R962,D764,R538,U519,L24,U91,R11,U574,L647,U891,R44,D897,L715,U498,L624,D573,R287,U762,L613,D79,R122,U148,L849,D385,R792,D20,L512,D431,R818,U428,L10,D800,R773,D936,L594,D38,R824,D216,L220,U358,L463,U550,R968,D346,L658,U113,R813,U411,L730,D84,R479,U877,L730,D961,L839,D792,R424,U321,L105,D862,L815,D243,L521,D913,L1,D513,L269,U495,L27,U16,R904,D926,R640,U948,R346,D240,L273,U131,L296,U556,R347,D640,L261,D43,R136,U824,R126,U583,R736,U530,L734,U717,L256,U362,L86,U48,R851,U519,L610,D134,L554,D766,L179,U637,R71,D895,L21,D908,R486,D863,R31,U85,R420,D718,R466,D861,R655,D304,L701,D403,L860,D208,L595,U64,R999
|
|
||||||
L992,D463,R10,D791,R312,D146,R865,D244,L364,D189,R35,U328,R857,D683,L660,D707,L908,D277,R356,U369,R197,D35,R625,D862,L769,U705,L728,U999,R938,U233,L595,U266,L697,U966,L536,D543,L669,D829,R910,U693,R753,D389,L647,U603,L660,D787,L138,D119,L131,D266,R268,D917,R776,U290,R920,U904,L46,D139,L341,D19,R982,U790,L981,U791,L147,U30,L246,U677,R343,D492,R398,D234,R76,D423,L709,D392,R741,U408,R878,U29,R446,U36,R806,U78,L76,D813,R584,U682,L187,U666,L340,D301,L694,U15,R800,U276,L755,U558,R366,D309,R571,U976,L286,D833,R318,U365,L864,U408,L352,D61,R284,D272,R240,D845,L206,U721,R367,D541,R628,U581,L750,D680,R695,D30,R849,U743,L214,U605,R533,U493,R803,D783,R168,U877,L61,D726,L794,D116,R717,U44,R964,U674,L291,D372,L381,D523,L644,U438,R983,D390,R520,D471,R556,D693,L919,D863,R84,D629,L264,D429,R82,U64,R835,D801,R93,U770,R441,D152,L718,D788,L797,U699,L82,U206,L40,U952,R902,U570,L759,D655,L131,D901,L470,D804,L407,U458,L922,D21,L171,U841,L237,D301,R192,D293,R984,U243,R846,U139,L413,U162,R925,D235,L115,U443,L884,D910,R335,U274,L338,U160,R125,D775,R824,D821,R531,D761,L189,U822,L602,D732,R473,U149,L128,U30,R77,D957,R811,D154,L988,D237,R425,D855,R482,D571,R134,D731,L905,U869,R916,D689,L17,U24,R353,D996,R832,U855,L76,U659,R581,D483,R821,D145,R199,D344,R487,D436,L92,U491,R365,D909,L17,D148,R307,U57,R666,U660,R195,D767,R612,D902,L594,D299,R670,D881,L583,D793,R58,U89,L99,D355,R394,D350,R920,U544,R887,U564,L238,U979,L565,D914,L95,U150,R292,U495,R506,U475,R813,D308,L797,D484,R9
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
# 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 $@
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
** --- Day 3: Crossed Wires ---
|
|
||||||
The gravity assist was successful, and you're well on your way to the
|
|
||||||
Venus refuelling station. During the rush back on Earth, the fuel
|
|
||||||
management system wasn't completely installed, so that's next on the
|
|
||||||
priority list.
|
|
||||||
|
|
||||||
Opening the front panel reveals a jumble of wires. Specifically, /two
|
|
||||||
wires/ are connected to a central port and extend outward on a grid. You
|
|
||||||
trace the path each wire takes as it leaves the central port, one wire
|
|
||||||
per line of text (your puzzle input).
|
|
||||||
|
|
||||||
The wires twist and turn, but the two wires occasionally cross paths. To
|
|
||||||
fix the circuit, you need to /find the intersection point closest to the
|
|
||||||
central port/. Because the wires are on a grid, use the
|
|
||||||
[[https://en.wikipedia.org/wiki/Taxicab_geometry][Manhattan distance]]
|
|
||||||
for this measurement. While the wires do technically cross right at the
|
|
||||||
central port where they both start, this point does not count, nor does
|
|
||||||
a wire count as crossing with itself.
|
|
||||||
|
|
||||||
For example, if the first wire's path is =R8,U5,L5,D3=, then starting
|
|
||||||
from the central port (=o=), it goes right =8=, up =5=, left =5=, and
|
|
||||||
finally down =3=:
|
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
|
||||||
...........
|
|
||||||
...........
|
|
||||||
...........
|
|
||||||
....+----+.
|
|
||||||
....|....|.
|
|
||||||
....|....|.
|
|
||||||
....|....|.
|
|
||||||
.........|.
|
|
||||||
.o-------+.
|
|
||||||
...........
|
|
||||||
#+END_EXAMPLE
|
|
||||||
|
|
||||||
Then, if the second wire's path is =U7,R6,D4,L4=, it goes up =7=, right
|
|
||||||
=6=, down =4=, and left =4=:
|
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
|
||||||
...........
|
|
||||||
.+-----+...
|
|
||||||
.|.....|...
|
|
||||||
.|..+--X-+.
|
|
||||||
.|..|..|.|.
|
|
||||||
.|.-X--+.|.
|
|
||||||
.|..|....|.
|
|
||||||
.|.......|.
|
|
||||||
.o-------+.
|
|
||||||
...........
|
|
||||||
#+END_EXAMPLE
|
|
||||||
|
|
||||||
These wires cross at two locations (marked =X=), but the lower-left one
|
|
||||||
is closer to the central port: its distance is =3 + 3 = 6=.
|
|
||||||
|
|
||||||
Here are a few more examples:
|
|
||||||
|
|
||||||
- =R75,D30,R83,U83,L12,D49,R71,U7,L72= \\
|
|
||||||
=U62,R66,U55,R34,D71,R55,D58,R83=
|
|
||||||
= distance =159=
|
|
||||||
- =R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51= \\
|
|
||||||
=U98,R91,D20,R16,D67,R40,U7,R15,U6,R7=
|
|
||||||
= distance =135=
|
|
||||||
|
|
||||||
/What is the Manhattan distance/ from the central port to the closest
|
|
||||||
intersection?
|
|
||||||
|
|
||||||
Your puzzle answer was =860=.
|
|
||||||
|
|
||||||
** --- Part Two ---
|
|
||||||
It turns out that this circuit is very timing-sensitive; you actually
|
|
||||||
need to /minimize the signal delay/.
|
|
||||||
|
|
||||||
To do this, calculate the /number of steps/ each wire takes to reach
|
|
||||||
each intersection; choose the intersection where the /sum of both wires'
|
|
||||||
steps/ is lowest. If a wire visits a position on the grid multiple
|
|
||||||
times, use the steps value from the /first/ time it visits that position
|
|
||||||
when calculating the total value of a specific intersection.
|
|
||||||
|
|
||||||
The number of steps a wire takes is the total number of grid squares the
|
|
||||||
wire has entered to get to that location, including the intersection
|
|
||||||
being considered. Again consider the example from above:
|
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
|
||||||
...........
|
|
||||||
.+-----+...
|
|
||||||
.|.....|...
|
|
||||||
.|..+--X-+.
|
|
||||||
.|..|..|.|.
|
|
||||||
.|.-X--+.|.
|
|
||||||
.|..|....|.
|
|
||||||
.|.......|.
|
|
||||||
.o-------+.
|
|
||||||
...........
|
|
||||||
#+END_EXAMPLE
|
|
||||||
|
|
||||||
In the above example, the intersection closest to the central port is
|
|
||||||
reached after =8+5+5+2 = 20= steps by the first wire and =7+6+4+3 = 20=
|
|
||||||
steps by the second wire for a total of =20+20 = 40= steps.
|
|
||||||
|
|
||||||
However, the top-right intersection is better: the first wire takes only
|
|
||||||
=8+5+2 = 15= and the second wire takes only =7+6+2 = 15=, a total of
|
|
||||||
=15+15 = 30= steps.
|
|
||||||
|
|
||||||
Here are the best steps for the extra examples from above:
|
|
||||||
|
|
||||||
- =R75,D30,R83,U83,L12,D49,R71,U7,L72= \\
|
|
||||||
=U62,R66,U55,R34,D71,R55,D58,R83=
|
|
||||||
= =610= steps
|
|
||||||
- =R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51= \\
|
|
||||||
=U98,R91,D20,R16,D67,R40,U7,R15,U6,R7=
|
|
||||||
= =410= steps
|
|
||||||
|
|
||||||
/What is the fewest combined steps the wires must take to reach an
|
|
||||||
intersection?/
|
|
||||||
|
|
||||||
Your puzzle answer was =9238=.
|
|
||||||
|
|
||||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
/* aoc-c.c: Advent of Code 2019, day 3 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 <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "br.h"
|
|
||||||
#include "bits.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "list.h"
|
|
||||||
#include "pool.h"
|
|
||||||
|
|
||||||
typedef enum { DOWN = 'D', LEFT = 'L', RIGHT = 'R', UP = 'U' } dir_t;
|
|
||||||
|
|
||||||
struct point {
|
|
||||||
int x, y;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct wire - one segment on wire.
|
|
||||||
* @dist: total distance from start before the current segment
|
|
||||||
* @dir: indicates which of ends[0] and ends[1] was the original line end point
|
|
||||||
* @ends: segment ends, ordered (ends[0].x <= ends[1].x and ends[0].y <= ends[1].y)
|
|
||||||
* @list: segments list
|
|
||||||
*/
|
|
||||||
struct wire {
|
|
||||||
int dist;
|
|
||||||
int dir;
|
|
||||||
struct point ends[2];
|
|
||||||
struct list_head list;
|
|
||||||
};
|
|
||||||
|
|
||||||
static pool_t *wire_pool;
|
|
||||||
|
|
||||||
static struct list_head *parse(struct list_head *wires)
|
|
||||||
{
|
|
||||||
size_t alloc = 0;
|
|
||||||
ssize_t buflen;
|
|
||||||
char *buf = NULL, *token;
|
|
||||||
|
|
||||||
for (int line = 0; line < 2; ++line) {
|
|
||||||
struct point p0 = {0, 0}, p1 = {0, 0};
|
|
||||||
int totdist = 0;
|
|
||||||
|
|
||||||
if ((buflen = getline(&buf, &alloc, stdin)) <= 0) {
|
|
||||||
fprintf(stderr, "error %d reading input.\n", errno);
|
|
||||||
wires = NULL;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (token = strtok(buf, ","); token; token = strtok(NULL, ",")) {
|
|
||||||
dir_t dir = *token;
|
|
||||||
int dist = atoi(token + 1);
|
|
||||||
struct wire *new = pool_get(wire_pool);
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&new->list);
|
|
||||||
new->dist = totdist;
|
|
||||||
totdist += abs(dist);
|
|
||||||
new->dir = !!(dir == DOWN || dir == LEFT);
|
|
||||||
if (dir == DOWN || dir == UP) /* vertical segment */
|
|
||||||
p1.y = p0.y + (1 - (new->dir * 2)) * dist;
|
|
||||||
else /* horizontal segment */
|
|
||||||
p1.x = p0.x + (1 - (new->dir * 2)) * dist;
|
|
||||||
new->ends[0].x = min(p0.x, p1.x); /* order ends (p0.? <= p1.?) */
|
|
||||||
new->ends[0].y = min(p0.y, p1.y);
|
|
||||||
new->ends[1].x = max(p0.x, p1.x);
|
|
||||||
new->ends[1].y = max(p0.y, p1.y);
|
|
||||||
list_add_tail(&new->list, &wires[line]);
|
|
||||||
p0 = p1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end:
|
|
||||||
free(buf);
|
|
||||||
return wires;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct point *intersect(struct wire *w0, struct wire *w1, struct point *ret)
|
|
||||||
{
|
|
||||||
if (w0->ends[0].x == w0->ends[1].x) { /* w0 vertical */
|
|
||||||
/* BUG: overlapping wires is not handled */
|
|
||||||
if (w0->ends[0].x >= w1->ends[0].x && w0->ends[1].x <= w1->ends[1].x &&
|
|
||||||
w0->ends[0].y <= w1->ends[0].y && w0->ends[1].y >= w1->ends[1].y) {
|
|
||||||
ret->x = w0->ends[0].x;
|
|
||||||
ret->y = w1->ends[0].y;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
} else { /* w0 horizontal */
|
|
||||||
if (w0->ends[0].x <= w1->ends[0].x && w0->ends[1].x >= w1->ends[1].x &&
|
|
||||||
w0->ends[0].y <= w1->ends[1].y && w0->ends[1].y >= w1->ends[0].y) {
|
|
||||||
ret->x = w1->ends[0].x;
|
|
||||||
ret->y = w0->ends[0].y;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* part 1 */
|
|
||||||
#define manhattan(point) (abs(point.x) + abs(point.y))
|
|
||||||
/* part 2 */
|
|
||||||
#define signal(point, w0, w1) \
|
|
||||||
(w0->dist + w1->dist + \
|
|
||||||
abs(cross.x - w0->ends[w0->dir].x) + abs(cross.y - w0->ends[w0->dir].y) + \
|
|
||||||
abs(cross.x - w1->ends[w1->dir].x) + abs(cross.y - w1->ends[w1->dir].y))
|
|
||||||
|
|
||||||
static int doit(struct list_head *w, int part)
|
|
||||||
{
|
|
||||||
struct wire *w0, *w1;
|
|
||||||
struct point cross;
|
|
||||||
s32 res = INT32_MAX;
|
|
||||||
|
|
||||||
list_for_each_entry(w0, &w[0], list)
|
|
||||||
list_for_each_entry(w1, &w[1], list)
|
|
||||||
if (intersect(w0, w1, &cross))
|
|
||||||
res = min_not_zero(res, part == 1 ?
|
|
||||||
manhattan(cross) :
|
|
||||||
signal(cross, w0, w1));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
struct list_head wires[2] = { LIST_HEAD_INIT(wires[0]), LIST_HEAD_INIT(wires[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);
|
|
||||||
wire_pool = pool_create("wire", 256, sizeof(struct wire));
|
|
||||||
|
|
||||||
if (parse(wires)) {
|
|
||||||
printf("%s : res=%d\n", *av, doit(wires, part));
|
|
||||||
pool_destroy(wire_pool);
|
|
||||||
}
|
|
||||||
exit (0);
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
130254-678275
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
# 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 $@
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
** --- Day 4: Secure Container ---
|
|
||||||
You arrive at the Venus fuel depot only to discover it's protected by a
|
|
||||||
password. The Elves had written the password on a sticky note, but
|
|
||||||
someone threw it out.
|
|
||||||
|
|
||||||
However, they do remember a few key facts about the password:
|
|
||||||
|
|
||||||
- It is a six-digit number.
|
|
||||||
- The value is within the range given in your puzzle input.
|
|
||||||
- Two adjacent digits are the same (like =22= in =122345=).
|
|
||||||
- Going from left to right, the digits /never decrease/; they only ever
|
|
||||||
increase or stay the same (like =111123= or =135679=).
|
|
||||||
|
|
||||||
Other than the range rule, the following are true:
|
|
||||||
|
|
||||||
- =111111= meets these criteria (double =11=, never decreases).
|
|
||||||
- =223450= does not meet these criteria (decreasing pair of digits
|
|
||||||
=50=).
|
|
||||||
- =123789= does not meet these criteria (no double).
|
|
||||||
|
|
||||||
/How many different passwords/ within the range given in your puzzle
|
|
||||||
input meet these criteria?
|
|
||||||
|
|
||||||
Your puzzle answer was =2090=.
|
|
||||||
|
|
||||||
** --- Part Two ---
|
|
||||||
An Elf just remembered one more important detail: the two adjacent
|
|
||||||
matching digits /are not part of a larger group of matching digits/.
|
|
||||||
|
|
||||||
Given this additional criterion, but still ignoring the range rule, the
|
|
||||||
following are now true:
|
|
||||||
|
|
||||||
- =112233= meets these criteria because the digits never decrease and
|
|
||||||
all repeated digits are exactly two digits long.
|
|
||||||
- =123444= no longer meets the criteria (the repeated =44= is part of a
|
|
||||||
larger group of =444=).
|
|
||||||
- =111122= meets the criteria (even though =1= is repeated more than
|
|
||||||
twice, it still contains a double =22=).
|
|
||||||
|
|
||||||
/How many different passwords/ within the range given in your puzzle
|
|
||||||
input meet all of the criteria?
|
|
||||||
|
|
||||||
Your puzzle answer was =1419=.
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
/* aoc-c.c: Advent of Code 2019, day 4 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 <malloc.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#include "likely.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 next = number - number % (faulty * 10);
|
|
||||||
|
|
||||||
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) {
|
|
||||||
*next = next_number(work, faulty, dec);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (dec == digit) {
|
|
||||||
valid = 1;
|
|
||||||
dups[digit] += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!valid || part == 1)
|
|
||||||
return valid;
|
|
||||||
for (int i = 0; i < 10; ++i)
|
|
||||||
if (dups[i] == 2)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int doit(int *nums, int part)
|
|
||||||
{
|
|
||||||
int res = 0, next = 0;
|
|
||||||
|
|
||||||
for (int i = nums[0]; i < nums[1]; i = next) {
|
|
||||||
if (unlikely(is_valid(i, part, &next)))
|
|
||||||
res++;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int *parse(int *res)
|
|
||||||
{
|
|
||||||
size_t alloc = 0;
|
|
||||||
char *buf = NULL;
|
|
||||||
|
|
||||||
getline(&buf, &alloc, stdin);
|
|
||||||
*res = atoi(strtok(buf, "-"));
|
|
||||||
*(res+1) = atoi(strtok(NULL, "-"));
|
|
||||||
free(buf);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
int nums[2];
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
parse(nums);
|
|
||||||
printf("%s : res=%d\n", *av, doit(nums, part));
|
|
||||||
|
|
||||||
exit (0);
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
3,0,4,0,99
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
1002,4,3,4,33
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
3,9,8,9,10,9,4,9,99,-1,8
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
3,9,7,9,10,9,4,9,99,-1,8
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
3,3,1108,-1,8,3,4,3,99
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
3,3,1107,-1,8,3,4,3,99
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
3,3,1105,-1,9,1101,0,0,12,4,12,99,1
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
# 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 $@
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
** --- 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: **
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
/* 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);
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#!/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
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
COM)B
|
|
||||||
B)C
|
|
||||||
C)D
|
|
||||||
D)E
|
|
||||||
E)F
|
|
||||||
B)G
|
|
||||||
G)H
|
|
||||||
D)I
|
|
||||||
E)J
|
|
||||||
J)K
|
|
||||||
K)L
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
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
2306
2019/day06/INPUT.txt
File diff suppressed because it is too large
Load Diff
@@ -1,93 +0,0 @@
|
|||||||
# 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 $@
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
** --- 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: **
|
|
||||||
@@ -1,270 +0,0 @@
|
|||||||
/* 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 +0,0 @@
|
|||||||
3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
# 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 $@
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
** --- 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: **
|
|
||||||
@@ -1,257 +0,0 @@
|
|||||||
/* 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 +0,0 @@
|
|||||||
0222112222120000
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,93 +0,0 @@
|
|||||||
# 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 $@
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
** --- 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: **
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
/* 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 +0,0 @@
|
|||||||
109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
1102,34915192,34915192,7,4,7,99,0
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
104,1125899906842624,99
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
# 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 $@
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
** --- 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: **
|
|
||||||
@@ -1,258 +0,0 @@
|
|||||||
/* 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);
|
|
||||||
}
|
|
||||||
@@ -1,521 +0,0 @@
|
|||||||
/* bits.h - bits functions.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021-2022 Bruno Raoult ("br")
|
|
||||||
* Licensed under the GNU General Public License v3.0 or later.
|
|
||||||
* Some rights reserved. See COPYING.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
|
||||||
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef BITS_H
|
|
||||||
#define BITS_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
/* next include will define __WORDSIZE: 32 or 64
|
|
||||||
*/
|
|
||||||
#include <bits/wordsize.h>
|
|
||||||
|
|
||||||
#ifndef __has_builtin
|
|
||||||
#define __has_builtin(x) 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* no plan to support 32bits for now...
|
|
||||||
*/
|
|
||||||
#if __WORDSIZE != 64
|
|
||||||
#error "Only 64 bits word size supported."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* fixed-size types
|
|
||||||
*/
|
|
||||||
typedef int64_t s64;
|
|
||||||
typedef int32_t s32;
|
|
||||||
typedef int16_t s16;
|
|
||||||
typedef int8_t s8;
|
|
||||||
|
|
||||||
typedef uint64_t u64;
|
|
||||||
typedef uint32_t u32;
|
|
||||||
typedef uint16_t u16;
|
|
||||||
typedef uint8_t u8;
|
|
||||||
|
|
||||||
/* convenience types
|
|
||||||
*/
|
|
||||||
typedef unsigned long int ulong;
|
|
||||||
typedef unsigned int uint;
|
|
||||||
typedef unsigned short ushort;
|
|
||||||
typedef unsigned char uchar;
|
|
||||||
|
|
||||||
/* char is a special case, as it can be signed or unsigned
|
|
||||||
*/
|
|
||||||
typedef signed char schar;
|
|
||||||
|
|
||||||
/* count trailing zeroes : 00101000 -> 3
|
|
||||||
* ^^^
|
|
||||||
*/
|
|
||||||
static __always_inline int ctz64(u64 n)
|
|
||||||
{
|
|
||||||
# if __has_builtin(__builtin_ctzl)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin ctzl.\n");
|
|
||||||
# endif
|
|
||||||
return __builtin_ctzl(n);
|
|
||||||
|
|
||||||
# elif __has_builtin(__builtin_clzl)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin clzl.\n");
|
|
||||||
# endif
|
|
||||||
return __WORDSIZE - (__builtin_clzl(n & -n) + 1);
|
|
||||||
|
|
||||||
# else
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "emulated.\n");
|
|
||||||
# endif
|
|
||||||
return popcount64((n & −n) − 1);
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static __always_inline int ctz32(u32 n)
|
|
||||||
{
|
|
||||||
# if __has_builtin(__builtin_ctz)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin ctz.\n");
|
|
||||||
# endif
|
|
||||||
return __builtin_ctzl(n);
|
|
||||||
|
|
||||||
# elif __has_builtin(__builtin_clz)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin clz.\n");
|
|
||||||
# endif
|
|
||||||
return __WORDSIZE - (__builtin_clz(n & -n) + 1);
|
|
||||||
|
|
||||||
# else
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "emulated.\n");
|
|
||||||
# endif
|
|
||||||
return popcount32((n & −n) − 1);
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clz - count leading zeroes : 00101000 -> 2
|
|
||||||
* ^^
|
|
||||||
*/
|
|
||||||
static __always_inline int clz64(u64 n)
|
|
||||||
{
|
|
||||||
# if __has_builtin(__builtin_clzl)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin.\n");
|
|
||||||
# endif
|
|
||||||
return __builtin_clzl(n);
|
|
||||||
|
|
||||||
# else
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "emulated.\n");
|
|
||||||
# endif
|
|
||||||
u64 r, q;
|
|
||||||
|
|
||||||
r = (n > 0xFFFFFFFF) << 5; n >>= r;
|
|
||||||
q = (n > 0xFFFF) << 4; n >>= q; r |= q;
|
|
||||||
q = (n > 0xFF ) << 3; n >>= q; r |= q;
|
|
||||||
q = (n > 0xF ) << 2; n >>= q; r |= q;
|
|
||||||
q = (n > 0x3 ) << 1; n >>= q; r |= q;
|
|
||||||
r |= (n >> 1);
|
|
||||||
return 64 - r - 1;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static __always_inline int clz32(u32 n)
|
|
||||||
{
|
|
||||||
# if __has_builtin(__builtin_clz)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin.\n");
|
|
||||||
# endif
|
|
||||||
return __builtin_clz(n);
|
|
||||||
|
|
||||||
# else
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "emulated.\n");
|
|
||||||
# endif
|
|
||||||
u32 r, q;
|
|
||||||
|
|
||||||
r = (n > 0xFFFF) << 4; n >>= r;
|
|
||||||
q = (n > 0xFF ) << 3; n >>= q; r |= q;
|
|
||||||
q = (n > 0xF ) << 2; n >>= q; r |= q;
|
|
||||||
q = (n > 0x3 ) << 1; n >>= q; r |= q;
|
|
||||||
r |= (n >> 1);
|
|
||||||
return 32 - r - 1;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fls - find last set : 00101000 -> 6
|
|
||||||
* ^
|
|
||||||
*/
|
|
||||||
static __always_inline int fls64(u64 n)
|
|
||||||
{
|
|
||||||
if (!n)
|
|
||||||
return 0;
|
|
||||||
return 64 - clz64(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __always_inline int fls32(u32 n)
|
|
||||||
{
|
|
||||||
if (!n)
|
|
||||||
return 0;
|
|
||||||
return 32 - clz32(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find first set : 00101000 -> 4
|
|
||||||
* ^
|
|
||||||
*/
|
|
||||||
static __always_inline uint ffs64(u64 n)
|
|
||||||
{
|
|
||||||
# if __has_builtin(__builtin_ffsl)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin ffsl.\n");
|
|
||||||
# endif
|
|
||||||
return __builtin_ffsl(n);
|
|
||||||
|
|
||||||
# elif __has_builtin(__builtin_ctzl)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin ctzl.\n");
|
|
||||||
# endif
|
|
||||||
if (n == 0)
|
|
||||||
return (0);
|
|
||||||
return __builtin_ctzl(n) + 1;
|
|
||||||
|
|
||||||
# else
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "emulated.\n");
|
|
||||||
# endif
|
|
||||||
return popcount64(n ^ ~-n);
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static __always_inline uint ffs32(u32 n)
|
|
||||||
{
|
|
||||||
# if __has_builtin(__builtin_ffs)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin ffs.\n");
|
|
||||||
# endif
|
|
||||||
return __builtin_ffs(n);
|
|
||||||
|
|
||||||
# elif __has_builtin(__builtin_ctz)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin ctz.\n");
|
|
||||||
# endif
|
|
||||||
if (n == 0)
|
|
||||||
return (0);
|
|
||||||
return __builtin_ctz(n) + 1;
|
|
||||||
|
|
||||||
# else
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "emulated.\n");
|
|
||||||
# endif
|
|
||||||
return popcount32(n ^ ~-n);
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* count set bits: 10101000 -> 3
|
|
||||||
* ^ ^ ^
|
|
||||||
*/
|
|
||||||
static __always_inline int popcount64(u64 n)
|
|
||||||
{
|
|
||||||
# if __has_builtin(__builtin_popcountl)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin.\n");
|
|
||||||
# endif
|
|
||||||
return __builtin_popcountl(n);
|
|
||||||
|
|
||||||
# else
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "emulated.\n");
|
|
||||||
# endif
|
|
||||||
int count = 0;
|
|
||||||
while (n) {
|
|
||||||
count++;
|
|
||||||
n &= (n - 1);
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static __always_inline int popcount32(u32 n)
|
|
||||||
{
|
|
||||||
# if __has_builtin(__builtin_popcount)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin.\n");
|
|
||||||
# endif
|
|
||||||
return __builtin_popcount(n);
|
|
||||||
|
|
||||||
# else
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "emulated.\n");
|
|
||||||
# endif
|
|
||||||
int count = 0;
|
|
||||||
while (n) {
|
|
||||||
count++;
|
|
||||||
n &= (n - 1);
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* rolXX are taken from kernel's <linux/bitops.h> are are:
|
|
||||||
* SPDX-License-Identifier: GPL-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* rol64 - rotate a 64-bit value left
|
|
||||||
* @word: value to rotate
|
|
||||||
* @shift: bits to roll
|
|
||||||
*/
|
|
||||||
static inline u64 rol64(u64 word, unsigned int shift)
|
|
||||||
{
|
|
||||||
return (word << (shift & 63)) | (word >> ((-shift) & 63));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ror64 - rotate a 64-bit value right
|
|
||||||
* @word: value to rotate
|
|
||||||
* @shift: bits to roll
|
|
||||||
*/
|
|
||||||
static inline u64 ror64(u64 word, unsigned int shift)
|
|
||||||
{
|
|
||||||
return (word >> (shift & 63)) | (word << ((-shift) & 63));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* rol32 - rotate a 32-bit value left
|
|
||||||
* @word: value to rotate
|
|
||||||
* @shift: bits to roll
|
|
||||||
*/
|
|
||||||
static inline u32 rol32(u32 word, unsigned int shift)
|
|
||||||
{
|
|
||||||
return (word << (shift & 31)) | (word >> ((-shift) & 31));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ror32 - rotate a 32-bit value right
|
|
||||||
* @word: value to rotate
|
|
||||||
* @shift: bits to roll
|
|
||||||
*/
|
|
||||||
static inline u32 ror32(u32 word, unsigned int shift)
|
|
||||||
{
|
|
||||||
return (word >> (shift & 31)) | (word << ((-shift) & 31));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* rol16 - rotate a 16-bit value left
|
|
||||||
* @word: value to rotate
|
|
||||||
* @shift: bits to roll
|
|
||||||
*/
|
|
||||||
static inline u16 rol16(u16 word, unsigned int shift)
|
|
||||||
{
|
|
||||||
return (word << (shift & 15)) | (word >> ((-shift) & 15));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ror16 - rotate a 16-bit value right
|
|
||||||
* @word: value to rotate
|
|
||||||
* @shift: bits to roll
|
|
||||||
*/
|
|
||||||
static inline u16 ror16(u16 word, unsigned int shift)
|
|
||||||
{
|
|
||||||
return (word >> (shift & 15)) | (word << ((-shift) & 15));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* rol8 - rotate an 8-bit value left
|
|
||||||
* @word: value to rotate
|
|
||||||
* @shift: bits to roll
|
|
||||||
*/
|
|
||||||
static inline u8 rol8(u8 word, unsigned int shift)
|
|
||||||
{
|
|
||||||
return (word << (shift & 7)) | (word >> ((-shift) & 7));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ror8 - rotate an 8-bit value right
|
|
||||||
* @word: value to rotate
|
|
||||||
* @shift: bits to roll
|
|
||||||
*/
|
|
||||||
static inline u8 ror8(u8 word, unsigned int shift)
|
|
||||||
{
|
|
||||||
return (word >> (shift & 7)) | (word << ((-shift) & 7));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ilog2 -
|
|
||||||
*/
|
|
||||||
static __always_inline __attribute__((const))
|
|
||||||
int __ilog2_u32(u32 n)
|
|
||||||
{
|
|
||||||
return fls32(n) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __always_inline __attribute__((const))
|
|
||||||
int __ilog2_u64(u64 n)
|
|
||||||
{
|
|
||||||
return fls64(n) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* is_power_of_2() - check if a value is a power of two
|
|
||||||
* @n: the value to check
|
|
||||||
*
|
|
||||||
* Determine whether some value is a power of two, where zero is
|
|
||||||
* *not* considered a power of two.
|
|
||||||
* Return: true if @n is a power of 2, otherwise false.
|
|
||||||
*/
|
|
||||||
static inline __attribute__((const))
|
|
||||||
bool is_power_of_2(unsigned long n)
|
|
||||||
{
|
|
||||||
return (n != 0 && ((n & (n - 1)) == 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ilog2 - log base 2 of 32-bit or a 64-bit unsigned value
|
|
||||||
* @n: parameter
|
|
||||||
*
|
|
||||||
* constant-capable log of base 2 calculation
|
|
||||||
* - this can be used to initialise global variables from constant data, hence
|
|
||||||
* the massive ternary operator construction
|
|
||||||
*
|
|
||||||
* selects the appropriately-sized optimised version depending on sizeof(n)
|
|
||||||
*/
|
|
||||||
#define ilog2(n) \
|
|
||||||
( \
|
|
||||||
__builtin_constant_p(n) ? \
|
|
||||||
((n) < 2 ? 0 : \
|
|
||||||
63 - __builtin_clzll(n)) : \
|
|
||||||
(sizeof(n) <= 4) ? \
|
|
||||||
__ilog2_u32(n) : \
|
|
||||||
__ilog2_u64(n) \
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* roundup_pow_of_two - round the given value up to nearest power of two
|
|
||||||
* @n: parameter
|
|
||||||
*
|
|
||||||
* round the given value up to the nearest power of two
|
|
||||||
* - the result is undefined when n == 0
|
|
||||||
* - this can be used to initialise global variables from constant data
|
|
||||||
*/
|
|
||||||
#define roundup_pow_of_two(n) \
|
|
||||||
( \
|
|
||||||
__builtin_constant_p(n) ? ( \
|
|
||||||
((n) == 1) ? 1 : \
|
|
||||||
(1UL << (ilog2((n) - 1) + 1)) \
|
|
||||||
) : \
|
|
||||||
__roundup_pow_of_two(n) \
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* rounddown_pow_of_two - round the given value down to nearest power of two
|
|
||||||
* @n: parameter
|
|
||||||
*
|
|
||||||
* round the given value down to the nearest power of two
|
|
||||||
* - the result is undefined when n == 0
|
|
||||||
* - this can be used to initialise global variables from constant data
|
|
||||||
*/
|
|
||||||
#define rounddown_pow_of_two(n) \
|
|
||||||
( \
|
|
||||||
__builtin_constant_p(n) ? ( \
|
|
||||||
(1UL << ilog2(n))) : \
|
|
||||||
__rounddown_pow_of_two(n) \
|
|
||||||
)
|
|
||||||
|
|
||||||
static inline __attribute_const__
|
|
||||||
int __order_base_2(unsigned long n)
|
|
||||||
{
|
|
||||||
return n > 1 ? ilog2(n - 1) + 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* order_base_2 - calculate the (rounded up) base 2 order of the argument
|
|
||||||
* @n: parameter
|
|
||||||
*
|
|
||||||
* The first few values calculated by this routine:
|
|
||||||
* ob2(0) = 0
|
|
||||||
* ob2(1) = 0
|
|
||||||
* ob2(2) = 1
|
|
||||||
* ob2(3) = 2
|
|
||||||
* ob2(4) = 2
|
|
||||||
* ob2(5) = 3
|
|
||||||
* ... and so on.
|
|
||||||
*/
|
|
||||||
#define order_base_2(n) \
|
|
||||||
( \
|
|
||||||
__builtin_constant_p(n) ? ( \
|
|
||||||
((n) == 0 || (n) == 1) ? 0 : \
|
|
||||||
ilog2((n) - 1) + 1) : \
|
|
||||||
__order_base_2(n) \
|
|
||||||
)
|
|
||||||
|
|
||||||
static inline __attribute__((const))
|
|
||||||
int __bits_per(unsigned long n)
|
|
||||||
{
|
|
||||||
if (n < 2)
|
|
||||||
return 1;
|
|
||||||
if (is_power_of_2(n))
|
|
||||||
return order_base_2(n) + 1;
|
|
||||||
return order_base_2(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bits_per - calculate the number of bits required for the argument
|
|
||||||
* @n: parameter
|
|
||||||
*
|
|
||||||
* This is constant-capable and can be used for compile time
|
|
||||||
* initializations, e.g bitfields.
|
|
||||||
*
|
|
||||||
* The first few values calculated by this routine:
|
|
||||||
* bf(0) = 1
|
|
||||||
* bf(1) = 1
|
|
||||||
* bf(2) = 2
|
|
||||||
* bf(3) = 2
|
|
||||||
* bf(4) = 3
|
|
||||||
* ... and so on.
|
|
||||||
*/
|
|
||||||
#define bits_per(n) \
|
|
||||||
( \
|
|
||||||
__builtin_constant_p(n) ? ( \
|
|
||||||
((n) == 0 || (n) == 1) \
|
|
||||||
? 1 : ilog2(n) + 1 \
|
|
||||||
) : \
|
|
||||||
__bits_per(n) \
|
|
||||||
)
|
|
||||||
|
|
||||||
/** bit_for_each - iterate over an u64/u32 bits
|
|
||||||
* @pos: an int used as current bit
|
|
||||||
* @tmp: a temp u64/u32 used as temporary storage
|
|
||||||
* @ul: the u64/u32 to loop over
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
* u64 u=139, _t; // u=b10001011
|
|
||||||
* int cur;
|
|
||||||
* bit_for_each64(cur, _t, u) {
|
|
||||||
* printf("%d\n", cur);
|
|
||||||
* }
|
|
||||||
* This will display the position of each bit set in ul: 1, 2, 4, 8
|
|
||||||
*
|
|
||||||
* I should probably re-think the implementation...
|
|
||||||
*/
|
|
||||||
#define bit_for_each64(pos, tmp, ul) \
|
|
||||||
for (tmp = ul, pos = ffs64(tmp); tmp; tmp &= (tmp - 1), pos = ffs64(tmp))
|
|
||||||
|
|
||||||
#define bit_for_each32(pos, tmp, ul) \
|
|
||||||
for (tmp = ul, pos = ffs32(tmp); tmp; tmp &= (tmp - 1), pos = ffs32(tmp))
|
|
||||||
|
|
||||||
/** or would it be more useful (counting bits from zero instead of 1) ?
|
|
||||||
*/
|
|
||||||
#define bit_for_each64_2(pos, tmp, ul) \
|
|
||||||
for (tmp = ul, pos = ctz64(tmp); tmp; tmp ^= 1UL << pos, pos = ctz64(tmp))
|
|
||||||
|
|
||||||
#define bit_for_each32_2(pos, tmp, ul) \
|
|
||||||
for (tmp = ul, pos = ctz32(tmp); tmp; tmp ^= 1U << pos, pos = ctz32(tmp))
|
|
||||||
|
|
||||||
#endif /* BITS_H */
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
/* bits.h - bits functions.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021-2022 Bruno Raoult ("br")
|
|
||||||
* Licensed under the GNU General Public License v3.0 or later.
|
|
||||||
* Some rights reserved. See COPYING.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
|
||||||
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
*
|
|
||||||
* Some parts are taken from Linux's kernel <linux/kernel.h> and others, and are :
|
|
||||||
* SPDX-License-Identifier: GPL-2.0
|
|
||||||
*
|
|
||||||
* This header contains generic stuff.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _BR_H
|
|
||||||
#define _BR_H
|
|
||||||
|
|
||||||
/* Indirect stringification. Doing two levels allows the parameter to be a
|
|
||||||
* macro itself. For example, compile with -DFOO=bar, __stringify(FOO)
|
|
||||||
* converts to "bar".
|
|
||||||
*/
|
|
||||||
#define __stringify_1(x...) #x
|
|
||||||
#define __stringify(x...) __stringify_1(x)
|
|
||||||
|
|
||||||
/* generate a (maybe) unique id.
|
|
||||||
*/
|
|
||||||
#define ___PASTE(x, y) x##y
|
|
||||||
#define __PASTE(x, y) ___PASTE(x, y)
|
|
||||||
#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
|
|
||||||
|
|
||||||
/* see https://lkml.org/lkml/2018/3/20/845 for explanation of this monster
|
|
||||||
*/
|
|
||||||
#define __is_constexpr(x) \
|
|
||||||
(sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* min()/max()/clamp() macros must accomplish three things:
|
|
||||||
*
|
|
||||||
* - avoid multiple evaluations of the arguments (so side-effects like
|
|
||||||
* "x++" happen only once) when non-constant.
|
|
||||||
* - perform strict type-checking (to generate warnings instead of
|
|
||||||
* nasty runtime surprises). See the "unnecessary" pointer comparison
|
|
||||||
* in __typecheck().
|
|
||||||
* - retain result as a constant expressions when called with only
|
|
||||||
* constant expressions (to avoid tripping VLA warnings in stack
|
|
||||||
* allocation usage).
|
|
||||||
*/
|
|
||||||
#define __typecheck(x, y) \
|
|
||||||
(!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))
|
|
||||||
|
|
||||||
#define __no_side_effects(x, y) \
|
|
||||||
(__is_constexpr(x) && __is_constexpr(y))
|
|
||||||
|
|
||||||
#define __safe_cmp(x, y) \
|
|
||||||
(__typecheck(x, y) && __no_side_effects(x, y))
|
|
||||||
|
|
||||||
#define __cmp(x, y, op) ((x) op (y) ? (x) : (y))
|
|
||||||
|
|
||||||
#define __cmp_once(x, y, unique_x, unique_y, op) ({ \
|
|
||||||
typeof(x) unique_x = (x); \
|
|
||||||
typeof(y) unique_y = (y); \
|
|
||||||
__cmp(unique_x, unique_y, op); })
|
|
||||||
|
|
||||||
#define __careful_cmp(x, y, op) \
|
|
||||||
__builtin_choose_expr(__safe_cmp(x, y), \
|
|
||||||
__cmp(x, y, op), \
|
|
||||||
__cmp_once(x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y), op))
|
|
||||||
|
|
||||||
#define __pure __attribute__((__pure__))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* min - return minimum of two values of the same or compatible types
|
|
||||||
* @x: first value
|
|
||||||
* @y: second value
|
|
||||||
*/
|
|
||||||
#define min(x, y) __careful_cmp(x, y, <)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* max - return maximum of two values of the same or compatible types
|
|
||||||
* @x: first value
|
|
||||||
* @y: second value
|
|
||||||
*/
|
|
||||||
#define max(x, y) __careful_cmp(x, y, >)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* min3 - return minimum of three values
|
|
||||||
* @x: first value
|
|
||||||
* @y: second value
|
|
||||||
* @z: third value
|
|
||||||
*/
|
|
||||||
#define min3(x, y, z) min((typeof(x))min(x, y), z)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* max3 - return maximum of three values
|
|
||||||
* @x: first value
|
|
||||||
* @y: second value
|
|
||||||
* @z: third value
|
|
||||||
*/
|
|
||||||
#define max3(x, y, z) max((typeof(x))max(x, y), z)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* min_not_zero - return the minimum that is _not_ zero, unless both are zero
|
|
||||||
* @x: value1
|
|
||||||
* @y: value2
|
|
||||||
*/
|
|
||||||
#define min_not_zero(x, y) ({ \
|
|
||||||
typeof(x) __x = (x); \
|
|
||||||
typeof(y) __y = (y); \
|
|
||||||
__x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); })
|
|
||||||
|
|
||||||
/**
|
|
||||||
* clamp - return a value clamped to a given range with strict typechecking
|
|
||||||
* @val: current value
|
|
||||||
* @lo: lowest allowable value
|
|
||||||
* @hi: highest allowable value
|
|
||||||
*
|
|
||||||
* This macro does strict typechecking of @lo/@hi to make sure they are of the
|
|
||||||
* same type as @val. See the unnecessary pointer comparisons.
|
|
||||||
*/
|
|
||||||
#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ..and if you can't take the strict
|
|
||||||
* types, you can specify one yourself.
|
|
||||||
*
|
|
||||||
* Or not use min/max/clamp at all, of course.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* min_t - return minimum of two values, using the specified type
|
|
||||||
* @type: data type to use
|
|
||||||
* @x: first value
|
|
||||||
* @y: second value
|
|
||||||
*/
|
|
||||||
#define min_t(type, x, y) __careful_cmp((type)(x), (type)(y), <)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* max_t - return maximum of two values, using the specified type
|
|
||||||
* @type: data type to use
|
|
||||||
* @x: first value
|
|
||||||
* @y: second value
|
|
||||||
*/
|
|
||||||
#define max_t(type, x, y) __careful_cmp((type)(x), (type)(y), >)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* clamp_t - return a value clamped to a given range using a given type
|
|
||||||
* @type: the type of variable to use
|
|
||||||
* @val: current value
|
|
||||||
* @lo: minimum allowable value
|
|
||||||
* @hi: maximum allowable value
|
|
||||||
*
|
|
||||||
* This macro does no typechecking and uses temporary variables of type
|
|
||||||
* @type to make all the comparisons.
|
|
||||||
*/
|
|
||||||
#define clamp_t(type, val, lo, hi) min_t(type, max_t(type, val, lo), hi)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* clamp_val - return a value clamped to a given range using val's type
|
|
||||||
* @val: current value
|
|
||||||
* @lo: minimum allowable value
|
|
||||||
* @hi: maximum allowable value
|
|
||||||
*
|
|
||||||
* This macro does no typechecking and uses temporary variables of whatever
|
|
||||||
* type the input argument @val is. This is useful when @val is an unsigned
|
|
||||||
* type and @lo and @hi are literals that will otherwise be assigned a signed
|
|
||||||
* integer type.
|
|
||||||
*/
|
|
||||||
#define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* swap - swap values of @a and @b
|
|
||||||
* @a: first value
|
|
||||||
* @b: second value
|
|
||||||
*/
|
|
||||||
#define swap(a, b) \
|
|
||||||
do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ARRAY_SIZE - get the number of elements in array @arr
|
|
||||||
* @arr: array to be sized
|
|
||||||
*/
|
|
||||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* abs - return absolute value of an argument
|
|
||||||
* @x: the value. If it is unsigned type, it is converted to signed type first.
|
|
||||||
* char is treated as if it was signed (regardless of whether it really is)
|
|
||||||
* but the macro's return type is preserved as char.
|
|
||||||
*
|
|
||||||
* Return: an absolute value of x.
|
|
||||||
*/
|
|
||||||
#define abs(x) __abs_choose_expr(x, long long, \
|
|
||||||
__abs_choose_expr(x, long, \
|
|
||||||
__abs_choose_expr(x, int, \
|
|
||||||
__abs_choose_expr(x, short, \
|
|
||||||
__abs_choose_expr(x, char, \
|
|
||||||
__builtin_choose_expr( \
|
|
||||||
__builtin_types_compatible_p(typeof(x), char), \
|
|
||||||
(char)({ signed char __x = (x); __x<0?-__x:__x; }), \
|
|
||||||
((void)0)))))))
|
|
||||||
|
|
||||||
#define __abs_choose_expr(x, type, other) __builtin_choose_expr( \
|
|
||||||
__builtin_types_compatible_p(typeof(x), signed type) || \
|
|
||||||
__builtin_types_compatible_p(typeof(x), unsigned type), \
|
|
||||||
({ signed type __x = (x); __x < 0 ? -__x : __x; }), other)
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _BR_H */
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
#ifndef _BR_BUG_H
|
|
||||||
#define _BR_BUG_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "likely.h"
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
/* BUG functions inspired by Linux kernel's <asm/bug.h>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define panic() exit(0xff)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Don't use BUG() or BUG_ON() unless there's really no way out; one
|
|
||||||
* example might be detecting data structure corruption in the middle
|
|
||||||
* of an operation that can't be backed out of. If the (sub)system
|
|
||||||
* can somehow continue operating, perhaps with reduced functionality,
|
|
||||||
* it's probably not BUG-worthy.
|
|
||||||
*
|
|
||||||
* If you're tempted to BUG(), think again: is completely giving up
|
|
||||||
* really the *only* solution? There are usually better options, where
|
|
||||||
* users don't need to reboot ASAP and can mostly shut down cleanly.
|
|
||||||
*/
|
|
||||||
#define BUG() do { \
|
|
||||||
fprintf(stderr, "BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
|
|
||||||
panic(); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* WARN(), WARN_ON(), WARN_ON_ONCE, and so on can be used to report
|
|
||||||
* significant kernel issues that need prompt attention if they should ever
|
|
||||||
* appear at runtime.
|
|
||||||
*
|
|
||||||
* Do not use these macros when checking for invalid external inputs
|
|
||||||
* (e.g. invalid system call arguments, or invalid data coming from
|
|
||||||
* network/devices), and on transient conditions like ENOMEM or EAGAIN.
|
|
||||||
* These macros should be used for recoverable kernel issues only.
|
|
||||||
* For invalid external inputs, transient conditions, etc use
|
|
||||||
* pr_err[_once/_ratelimited]() followed by dump_stack(), if necessary.
|
|
||||||
* Do not include "BUG"/"WARNING" in format strings manually to make these
|
|
||||||
* conditions distinguishable from kernel issues.
|
|
||||||
*
|
|
||||||
* Use the versions with printk format strings to provide better diagnostics.
|
|
||||||
*/
|
|
||||||
#define __WARN() do { \
|
|
||||||
fprintf(stderr, "WARNING: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
|
|
||||||
} while (0)
|
|
||||||
#define __WARN_printf(arg...) do { \
|
|
||||||
vfprintf(stderr, arg); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define WARN_ON(condition) ({ \
|
|
||||||
int __ret_warn_on = !!(condition); \
|
|
||||||
if (unlikely(__ret_warn_on)) \
|
|
||||||
__WARN(); \
|
|
||||||
unlikely(__ret_warn_on); \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define WARN(condition, format...) ({ \
|
|
||||||
int __ret_warn_on = !!(condition); \
|
|
||||||
if (unlikely(__ret_warn_on)) \
|
|
||||||
__WARN_printf(format); \
|
|
||||||
unlikely(__ret_warn_on); \
|
|
||||||
})
|
|
||||||
|
|
||||||
#endif /* _BR_BUG_H */
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
|
|
||||||
/* adaptation of Linux kernel's <linux/container_of.h>
|
|
||||||
*/
|
|
||||||
#ifndef _BR_CONTAINER_OF_H
|
|
||||||
#define _BR_CONTAINER_OF_H
|
|
||||||
|
|
||||||
/* Are two types/vars the same type (ignoring qualifiers)? */
|
|
||||||
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* typeof_member -
|
|
||||||
*/
|
|
||||||
#define typeof_member(T, m) typeof(((T*)0)->m)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* container_of - cast a member of a structure out to the containing structure
|
|
||||||
* @ptr: the pointer to the member.
|
|
||||||
* @type: the type of the container struct this is embedded in.
|
|
||||||
* @member: the name of the member within the struct.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#define container_of(ptr, type, member) ({ \
|
|
||||||
void *__mptr = (void *)(ptr); \
|
|
||||||
_Static_assert(__same_type(*(ptr), ((type *)0)->member) || \
|
|
||||||
__same_type(*(ptr), void), \
|
|
||||||
"pointer type mismatch in container_of()"); \
|
|
||||||
((type *)(__mptr - offsetof(type, member))); })
|
|
||||||
|
|
||||||
#endif /* BR_CONTAINER_OF_H */
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
/* debug.h - debug/log management.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021-2022 Bruno Raoult ("br")
|
|
||||||
* Licensed under the GNU General Public License v3.0 or later.
|
|
||||||
* Some rights reserved. See COPYING.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
|
||||||
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DEBUG_H
|
|
||||||
#define DEBUG_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "bits.h"
|
|
||||||
|
|
||||||
#define _unused __attribute__((__unused__))
|
|
||||||
#define _printf __attribute__ ((format (printf, 6, 7)))
|
|
||||||
|
|
||||||
#ifdef DEBUG_DEBUG
|
|
||||||
void debug_init(u32 level);
|
|
||||||
void debug_level_set(u32 level);
|
|
||||||
void _printf debug(u32 level, bool timestamp,
|
|
||||||
u32 indent, const char *src,
|
|
||||||
u32 line, const char *, ...);
|
|
||||||
#else /* DEBUG_DEBUG */
|
|
||||||
static inline void debug_init(_unused u32 level) {}
|
|
||||||
static inline void debug_level_set(_unused u32 level) {}
|
|
||||||
static inline void _printf debug(_unused u32 level, _unused bool timestamp,
|
|
||||||
_unused u32 indent, _unused const char *src,
|
|
||||||
_unused u32 line, const char *, ...) {}
|
|
||||||
#endif /* DEBUG_DEBUG */
|
|
||||||
#undef _unused
|
|
||||||
#undef _printf
|
|
||||||
|
|
||||||
/**
|
|
||||||
* log - simple log (no function name, no indent, no timestamp)
|
|
||||||
* @level: log level
|
|
||||||
* @fmt: printf format string
|
|
||||||
* @args: subsequent arguments to printf
|
|
||||||
*/
|
|
||||||
#define log(level, fmt, args...) \
|
|
||||||
debug((level), false, 0, NULL, 0, fmt, ##args)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* log_i - log with indent (no function name, no timestamp)
|
|
||||||
* @level: log level
|
|
||||||
* @fmt: printf format string
|
|
||||||
* @args: subsequent arguments to printf
|
|
||||||
*
|
|
||||||
* Output example:
|
|
||||||
* >>>>val=2
|
|
||||||
*/
|
|
||||||
#define log_i(level, fmt, args...) \
|
|
||||||
debug((level), false, (level), NULL, 0, fmt, ##args)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* log_f - log with function name (no indent name, no timestamp)
|
|
||||||
* @level: log level
|
|
||||||
* @fmt: printf format string
|
|
||||||
* @args: subsequent arguments to printf
|
|
||||||
*
|
|
||||||
* Output example:
|
|
||||||
* [function] val=2
|
|
||||||
*/
|
|
||||||
#define log_f(level, fmt, args...) \
|
|
||||||
debug((level), false, 0, __func__, 0, fmt, ##args)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* log_if - log with function name and line number (no indent name, no timestamp)
|
|
||||||
* @level: log level
|
|
||||||
* @fmt: printf format string
|
|
||||||
* @args: subsequent arguments to printf
|
|
||||||
*
|
|
||||||
* Output example:
|
|
||||||
* >>>> [function:15] val=2
|
|
||||||
*/
|
|
||||||
#define log_if(level, fmt, args...) \
|
|
||||||
debug((level), false, (level), __func__, __LINE__, fmt, ##args)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* log_it - log with function name, line number, indent, and timestamp
|
|
||||||
* @level: log level
|
|
||||||
* @fmt: printf format string
|
|
||||||
* @args: subsequent arguments to printf
|
|
||||||
*
|
|
||||||
* Output example:
|
|
||||||
* >>>> [function:15] val=2
|
|
||||||
*/
|
|
||||||
#define log_it(level, fmt, args...) \
|
|
||||||
debug((level), true, (level), __func__, __LINE__, fmt, ##args)
|
|
||||||
|
|
||||||
#endif /* DEBUG_H */
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
|
|
||||||
#ifndef _BR_HASH_H
|
|
||||||
#define _BR_HASH_H
|
|
||||||
/* adaptation of Linux kernel's <linux/hash.h> and <linux/stringhash.h>
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Fast hashing routine for ints, longs and pointers.
|
|
||||||
(C) 2002 Nadia Yvette Chambers, IBM */
|
|
||||||
|
|
||||||
#include <asm/types.h>
|
|
||||||
#include <asm/bitsperlong.h>
|
|
||||||
#include "bits.h"
|
|
||||||
#include "br.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The "GOLDEN_RATIO_PRIME" is used in ifs/btrfs/brtfs_inode.h and
|
|
||||||
* fs/inode.c. It's not actually prime any more (the previous primes
|
|
||||||
* were actively bad for hashing), but the name remains.
|
|
||||||
*/
|
|
||||||
#if __BITS_PER_LONG == 32
|
|
||||||
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_32
|
|
||||||
#define hash_long(val, bits) hash_32(val, bits)
|
|
||||||
#elif __BITS_PER_LONG == 64
|
|
||||||
#define hash_long(val, bits) hash_64(val, bits)
|
|
||||||
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_64
|
|
||||||
#else
|
|
||||||
#error Wordsize not 32 or 64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This hash multiplies the input by a large odd number and takes the
|
|
||||||
* high bits. Since multiplication propagates changes to the most
|
|
||||||
* significant end only, it is essential that the high bits of the
|
|
||||||
* product be used for the hash value.
|
|
||||||
*
|
|
||||||
* Chuck Lever verified the effectiveness of this technique:
|
|
||||||
* http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf
|
|
||||||
*
|
|
||||||
* Although a random odd number will do, it turns out that the golden
|
|
||||||
* ratio phi = (sqrt(5)-1)/2, or its negative, has particularly nice
|
|
||||||
* properties. (See Knuth vol 3, section 6.4, exercise 9.)
|
|
||||||
*
|
|
||||||
* These are the negative, (1 - phi) = phi**2 = (3 - sqrt(5))/2,
|
|
||||||
* which is very slightly easier to multiply by and makes no
|
|
||||||
* difference to the hash distribution.
|
|
||||||
*/
|
|
||||||
#define GOLDEN_RATIO_32 0x61C88647
|
|
||||||
#define GOLDEN_RATIO_64 0x61C8864680B583EBull
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The _generic versions exist only so lib/test_hash.c can compare
|
|
||||||
* the arch-optimized versions with the generic.
|
|
||||||
*
|
|
||||||
* Note that if you change these, any <asm/hash.h> that aren't updated
|
|
||||||
* to match need to have their HAVE_ARCH_* define values updated so the
|
|
||||||
* self-test will not false-positive.
|
|
||||||
*/
|
|
||||||
#ifndef HAVE_ARCH__HASH_32
|
|
||||||
#define __hash_32 __hash_32_generic
|
|
||||||
#endif
|
|
||||||
static inline u32 __hash_32_generic(u32 val)
|
|
||||||
{
|
|
||||||
return val * GOLDEN_RATIO_32;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u32 hash_32(u32 val, unsigned int bits)
|
|
||||||
{
|
|
||||||
/* High bits are more random, so use them. */
|
|
||||||
return __hash_32(val) >> (32 - bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef HAVE_ARCH_HASH_64
|
|
||||||
#define hash_64 hash_64_generic
|
|
||||||
#endif
|
|
||||||
static __always_inline u32 hash_64_generic(u64 val, unsigned int bits)
|
|
||||||
{
|
|
||||||
#if __BITS_PER_LONG == 64
|
|
||||||
/* 64x64-bit multiply is efficient on all 64-bit processors */
|
|
||||||
return val * GOLDEN_RATIO_64 >> (64 - bits);
|
|
||||||
#else
|
|
||||||
/* Hash 64 bits using only 32x32-bit multiply. */
|
|
||||||
return hash_32((u32)val ^ __hash_32(val >> 32), bits);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u32 hash_ptr(const void *ptr, unsigned int bits)
|
|
||||||
{
|
|
||||||
return hash_long((unsigned long)ptr, bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This really should be called fold32_ptr; it does no hashing to speak of. */
|
|
||||||
static inline u32 hash32_ptr(const void *ptr)
|
|
||||||
{
|
|
||||||
unsigned long val = (unsigned long)ptr;
|
|
||||||
|
|
||||||
#if __BITS_PER_LONG == 64
|
|
||||||
val ^= (val >> 32);
|
|
||||||
#endif
|
|
||||||
return (u32)val;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Routines for hashing strings of bytes to a 32-bit hash value.
|
|
||||||
*
|
|
||||||
* These hash functions are NOT GUARANTEED STABLE between kernel
|
|
||||||
* versions, architectures, or even repeated boots of the same kernel.
|
|
||||||
* (E.g. they may depend on boot-time hardware detection or be
|
|
||||||
* deliberately randomized.)
|
|
||||||
*
|
|
||||||
* They are also not intended to be secure against collisions caused by
|
|
||||||
* malicious inputs; much slower hash functions are required for that.
|
|
||||||
*
|
|
||||||
* They are optimized for pathname components, meaning short strings.
|
|
||||||
* Even if a majority of files have longer names, the dynamic profile of
|
|
||||||
* pathname components skews short due to short directory names.
|
|
||||||
* (E.g. /usr/lib/libsesquipedalianism.so.3.141.)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Version 1: one byte at a time. Example of use:
|
|
||||||
*
|
|
||||||
* unsigned long hash = init_name_hash;
|
|
||||||
* while (*p)
|
|
||||||
* hash = partial_name_hash(tolower(*p++), hash);
|
|
||||||
* hash = end_name_hash(hash);
|
|
||||||
*
|
|
||||||
* Although this is designed for bytes, fs/hfsplus/unicode.c
|
|
||||||
* abuses it to hash 16-bit values.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
|
|
||||||
#define init_name_hash(salt) (unsigned long)(salt)
|
|
||||||
|
|
||||||
/* partial hash update function. Assume roughly 4 bits per character */
|
|
||||||
static inline unsigned long
|
|
||||||
partial_name_hash(unsigned long c, unsigned long prevhash)
|
|
||||||
{
|
|
||||||
return (prevhash + (c << 4) + (c >> 4)) * 11;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Finally: cut down the number of bits to a int value (and try to avoid
|
|
||||||
* losing bits). This also has the property (wanted by the dcache)
|
|
||||||
* that the msbits make a good hash table index.
|
|
||||||
*/
|
|
||||||
static inline unsigned int end_name_hash(unsigned long hash)
|
|
||||||
{
|
|
||||||
return hash_long(hash, 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Version 2: One word (32 or 64 bits) at a time.
|
|
||||||
* If CONFIG_DCACHE_WORD_ACCESS is defined (meaning <asm/word-at-a-time.h>
|
|
||||||
* exists, which describes major Linux platforms like x86 and ARM), then
|
|
||||||
* this computes a different hash function much faster.
|
|
||||||
*
|
|
||||||
* If not set, this falls back to a wrapper around the preceding.
|
|
||||||
*/
|
|
||||||
extern unsigned int __pure hash_string(const void *salt, const char *, unsigned int);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A hash_len is a u64 with the hash of a string in the low
|
|
||||||
* half and the length in the high half.
|
|
||||||
*/
|
|
||||||
#define hashlen_hash(hashlen) ((u32)(hashlen))
|
|
||||||
#define hashlen_len(hashlen) ((u32)((hashlen) >> 32))
|
|
||||||
#define hashlen_create(hash, len) ((u64)(len)<<32 | (u32)(hash))
|
|
||||||
|
|
||||||
/* Return the "hash_len" (hash and length) of a null-terminated string */
|
|
||||||
extern u64 __pure hashlen_string(const void *salt, const char *name);
|
|
||||||
|
|
||||||
#endif /* _BR_HASH_H */
|
|
||||||
@@ -1,204 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
/* adaptation of Linux kernel's <linux/hashtable.h>
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Statically sized hash table implementation
|
|
||||||
* (C) 2012 Sasha Levin <levinsasha928@gmail.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _LINUX_HASHTABLE_H
|
|
||||||
#define _LINUX_HASHTABLE_H
|
|
||||||
|
|
||||||
#include "list.h"
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include "hash.h"
|
|
||||||
//#include <linux/rculist.h>
|
|
||||||
|
|
||||||
#define DEFINE_HASHTABLE(name, bits) \
|
|
||||||
struct hlist_head name[1 << (bits)] = \
|
|
||||||
{ [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
|
|
||||||
|
|
||||||
#define DEFINE_READ_MOSTLY_HASHTABLE(name, bits) \
|
|
||||||
struct hlist_head name[1 << (bits)] __read_mostly = \
|
|
||||||
{ [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
|
|
||||||
|
|
||||||
#define DECLARE_HASHTABLE(name, bits) \
|
|
||||||
struct hlist_head name[1 << (bits)]
|
|
||||||
|
|
||||||
#define HASH_SIZE(name) (ARRAY_SIZE(name))
|
|
||||||
#define HASH_BITS(name) ilog2(HASH_SIZE(name))
|
|
||||||
|
|
||||||
/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */
|
|
||||||
#define hash_min(val, bits) \
|
|
||||||
(sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits))
|
|
||||||
|
|
||||||
static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < sz; i++)
|
|
||||||
INIT_HLIST_HEAD(&ht[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_init - initialize a hash table
|
|
||||||
* @hashtable: hashtable to be initialized
|
|
||||||
*
|
|
||||||
* Calculates the size of the hashtable from the given parameter, otherwise
|
|
||||||
* same as hash_init_size.
|
|
||||||
*
|
|
||||||
* This has to be a macro since HASH_BITS() will not work on pointers since
|
|
||||||
* it calculates the size during preprocessing.
|
|
||||||
*/
|
|
||||||
#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_add - add an object to a hashtable
|
|
||||||
* @hashtable: hashtable to add to
|
|
||||||
* @node: the &struct hlist_node of the object to be added
|
|
||||||
* @key: the key of the object to be added
|
|
||||||
*/
|
|
||||||
#define hash_add(hashtable, node, key) \
|
|
||||||
hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_add_rcu - add an object to a rcu enabled hashtable
|
|
||||||
* @hashtable: hashtable to add to
|
|
||||||
* @node: the &struct hlist_node of the object to be added
|
|
||||||
* @key: the key of the object to be added
|
|
||||||
*/
|
|
||||||
#define hash_add_rcu(hashtable, node, key) \
|
|
||||||
hlist_add_head_rcu(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_hashed - check whether an object is in any hashtable
|
|
||||||
* @node: the &struct hlist_node of the object to be checked
|
|
||||||
*/
|
|
||||||
static inline bool hash_hashed(struct hlist_node *node)
|
|
||||||
{
|
|
||||||
return !hlist_unhashed(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < sz; i++)
|
|
||||||
if (!hlist_empty(&ht[i]))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_empty - check whether a hashtable is empty
|
|
||||||
* @hashtable: hashtable to check
|
|
||||||
*
|
|
||||||
* This has to be a macro since HASH_BITS() will not work on pointers since
|
|
||||||
* it calculates the size during preprocessing.
|
|
||||||
*/
|
|
||||||
#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_del - remove an object from a hashtable
|
|
||||||
* @node: &struct hlist_node of the object to remove
|
|
||||||
*/
|
|
||||||
static inline void hash_del(struct hlist_node *node)
|
|
||||||
{
|
|
||||||
hlist_del_init(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each - iterate over a hashtable
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @bkt: integer to use as bucket loop cursor
|
|
||||||
* @obj: the type * to use as a loop cursor for each entry
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
*/
|
|
||||||
#define hash_for_each(name, bkt, obj, member) \
|
|
||||||
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
|
|
||||||
(bkt)++)\
|
|
||||||
hlist_for_each_entry(obj, &name[bkt], member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each_rcu - iterate over a rcu enabled hashtable
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @bkt: integer to use as bucket loop cursor
|
|
||||||
* @obj: the type * to use as a loop cursor for each entry
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
*/
|
|
||||||
#define hash_for_each_rcu(name, bkt, obj, member) \
|
|
||||||
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
|
|
||||||
(bkt)++)\
|
|
||||||
hlist_for_each_entry_rcu(obj, &name[bkt], member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each_safe - iterate over a hashtable safe against removal of
|
|
||||||
* hash entry
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @bkt: integer to use as bucket loop cursor
|
|
||||||
* @tmp: a &struct hlist_node used for temporary storage
|
|
||||||
* @obj: the type * to use as a loop cursor for each entry
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
*/
|
|
||||||
#define hash_for_each_safe(name, bkt, tmp, obj, member) \
|
|
||||||
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
|
|
||||||
(bkt)++)\
|
|
||||||
hlist_for_each_entry_safe(obj, tmp, &name[bkt], member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each_possible - iterate over all possible objects hashing to the
|
|
||||||
* same bucket
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @obj: the type * to use as a loop cursor for each entry
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
* @key: the key of the objects to iterate over
|
|
||||||
*/
|
|
||||||
#define hash_for_each_possible(name, obj, member, key) \
|
|
||||||
hlist_for_each_entry(obj, &name[hash_min(key, HASH_BITS(name))], member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each_possible_rcu - iterate over all possible objects hashing to the
|
|
||||||
* same bucket in an rcu enabled hashtable
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @obj: the type * to use as a loop cursor for each entry
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
* @key: the key of the objects to iterate over
|
|
||||||
*/
|
|
||||||
#define hash_for_each_possible_rcu(name, obj, member, key, cond...) \
|
|
||||||
hlist_for_each_entry_rcu(obj, &name[hash_min(key, HASH_BITS(name))],\
|
|
||||||
member, ## cond)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each_possible_rcu_notrace - iterate over all possible objects hashing
|
|
||||||
* to the same bucket in an rcu enabled hashtable in a rcu enabled hashtable
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @obj: the type * to use as a loop cursor for each entry
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
* @key: the key of the objects to iterate over
|
|
||||||
*
|
|
||||||
* This is the same as hash_for_each_possible_rcu() except that it does
|
|
||||||
* not do any RCU debugging or tracing.
|
|
||||||
*/
|
|
||||||
#define hash_for_each_possible_rcu_notrace(name, obj, member, key) \
|
|
||||||
hlist_for_each_entry_rcu_notrace(obj, \
|
|
||||||
&name[hash_min(key, HASH_BITS(name))], member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash_for_each_possible_safe - iterate over all possible objects hashing to the
|
|
||||||
* same bucket safe against removals
|
|
||||||
* @name: hashtable to iterate
|
|
||||||
* @obj: the type * to use as a loop cursor for each entry
|
|
||||||
* @tmp: a &struct hlist_node used for temporary storage
|
|
||||||
* @member: the name of the hlist_node within the struct
|
|
||||||
* @key: the key of the objects to iterate over
|
|
||||||
*/
|
|
||||||
#define hash_for_each_possible_safe(name, obj, tmp, member, key) \
|
|
||||||
hlist_for_each_entry_safe(obj, tmp,\
|
|
||||||
&name[hash_min(key, HASH_BITS(name))], member)
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
|
|
||||||
/* taken from Kernel's <linux/compiler.h
|
|
||||||
*/
|
|
||||||
#ifndef __LIKELY_H
|
|
||||||
#define __LIKELY_H
|
|
||||||
|
|
||||||
/* See https://kernelnewbies.org/FAQ/LikelyUnlikely
|
|
||||||
*
|
|
||||||
* In 2 words:
|
|
||||||
* "You should use it [likely() and unlikely()] only in cases when the likeliest
|
|
||||||
* branch is very very very likely, or when the unlikeliest branch is very very
|
|
||||||
* very unlikely."
|
|
||||||
*/
|
|
||||||
# define likely(x) __builtin_expect(!!(x), 1)
|
|
||||||
# define unlikely(x) __builtin_expect(!!(x), 0)
|
|
||||||
|
|
||||||
#endif /* __LIKELY_H */
|
|
||||||
@@ -1,992 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
|
|
||||||
/* adaptation of kernel's <linux/list.h>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __BR_LIST_H
|
|
||||||
#define __BR_LIST_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "rwonce.h"
|
|
||||||
#include "container-of.h"
|
|
||||||
|
|
||||||
/************ originally in <include/linux/types.h> */
|
|
||||||
struct list_head {
|
|
||||||
struct list_head *next, *prev;
|
|
||||||
};
|
|
||||||
struct hlist_head {
|
|
||||||
struct hlist_node *first;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct hlist_node {
|
|
||||||
struct hlist_node *next, **pprev;
|
|
||||||
};
|
|
||||||
|
|
||||||
/************ originally in <include/linux/poison.h> */
|
|
||||||
# define POISON_POINTER_DELTA 0
|
|
||||||
/* These are non-NULL pointers that will result in page faults
|
|
||||||
* under normal circumstances, used to verify that nobody uses
|
|
||||||
* non-initialized list entries.
|
|
||||||
*/
|
|
||||||
#define LIST_POISON1 ((void *) 0x100 + POISON_POINTER_DELTA)
|
|
||||||
#define LIST_POISON2 ((void *) 0x200 + POISON_POINTER_DELTA)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Circular doubly linked list implementation.
|
|
||||||
*
|
|
||||||
* Some of the internal functions ("__xxx") are useful when
|
|
||||||
* manipulating whole lists rather than single entries, as
|
|
||||||
* sometimes we already know the next/prev entries and we can
|
|
||||||
* generate better code by using them directly rather than
|
|
||||||
* using the generic single-entry routines.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
|
||||||
|
|
||||||
#define LIST_HEAD(name) \
|
|
||||||
struct list_head name = LIST_HEAD_INIT(name)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* INIT_LIST_HEAD - Initialize a list_head structure
|
|
||||||
* @list: list_head structure to be initialized.
|
|
||||||
*
|
|
||||||
* Initializes the list_head to point to itself. If it is a list header,
|
|
||||||
* the result is an empty list.
|
|
||||||
*/
|
|
||||||
static inline void INIT_LIST_HEAD(struct list_head *list)
|
|
||||||
{
|
|
||||||
WRITE_ONCE(list->next, list);
|
|
||||||
list->prev = list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Insert a new entry between two known consecutive entries.
|
|
||||||
*
|
|
||||||
* This is only for internal list manipulation where we know
|
|
||||||
* the prev/next entries already!
|
|
||||||
*/
|
|
||||||
static inline void __list_add(struct list_head *new,
|
|
||||||
struct list_head *prev,
|
|
||||||
struct list_head *next)
|
|
||||||
{
|
|
||||||
next->prev = new;
|
|
||||||
new->next = next;
|
|
||||||
new->prev = prev;
|
|
||||||
WRITE_ONCE(prev->next, new);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_add - add a new entry
|
|
||||||
* @new: new entry to be added
|
|
||||||
* @head: list head to add it after
|
|
||||||
*
|
|
||||||
* Insert a new entry after the specified head.
|
|
||||||
* This is good for implementing stacks.
|
|
||||||
*/
|
|
||||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_add(new, head, head->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_add_tail - add a new entry
|
|
||||||
* @new: new entry to be added
|
|
||||||
* @head: list head to add it before
|
|
||||||
*
|
|
||||||
* Insert a new entry before the specified head.
|
|
||||||
* This is useful for implementing queues.
|
|
||||||
*/
|
|
||||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_add(new, head->prev, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Delete a list entry by making the prev/next entries
|
|
||||||
* point to each other.
|
|
||||||
*
|
|
||||||
* This is only for internal list manipulation where we know
|
|
||||||
* the prev/next entries already!
|
|
||||||
*/
|
|
||||||
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
|
||||||
{
|
|
||||||
next->prev = prev;
|
|
||||||
WRITE_ONCE(prev->next, next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Delete a list entry and clear the 'prev' pointer.
|
|
||||||
*
|
|
||||||
* This is a special-purpose list clearing method used in the networking code
|
|
||||||
* for lists allocated as per-cpu, where we don't want to incur the extra
|
|
||||||
* WRITE_ONCE() overhead of a regular list_del_init(). The code that uses this
|
|
||||||
* needs to check the node 'prev' pointer instead of calling list_empty().
|
|
||||||
*/
|
|
||||||
static inline void __list_del_clearprev(struct list_head *entry)
|
|
||||||
{
|
|
||||||
__list_del(entry->prev, entry->next);
|
|
||||||
entry->prev = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __list_del_entry(struct list_head *entry)
|
|
||||||
{
|
|
||||||
__list_del(entry->prev, entry->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_del - deletes entry from list.
|
|
||||||
* @entry: the element to delete from the list.
|
|
||||||
* Note: list_empty() on entry does not return true after this, the entry is
|
|
||||||
* in an undefined state.
|
|
||||||
*/
|
|
||||||
static inline void list_del(struct list_head *entry)
|
|
||||||
{
|
|
||||||
__list_del_entry(entry);
|
|
||||||
entry->next = LIST_POISON1;
|
|
||||||
entry->prev = LIST_POISON2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_replace - replace old entry by new one
|
|
||||||
* @old : the element to be replaced
|
|
||||||
* @new : the new element to insert
|
|
||||||
*
|
|
||||||
* If @old was empty, it will be overwritten.
|
|
||||||
*/
|
|
||||||
static inline void list_replace(struct list_head *old,
|
|
||||||
struct list_head *new)
|
|
||||||
{
|
|
||||||
new->next = old->next;
|
|
||||||
new->next->prev = new;
|
|
||||||
new->prev = old->prev;
|
|
||||||
new->prev->next = new;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_replace_init - replace old entry by new one and initialize the old one
|
|
||||||
* @old : the element to be replaced
|
|
||||||
* @new : the new element to insert
|
|
||||||
*
|
|
||||||
* If @old was empty, it will be overwritten.
|
|
||||||
*/
|
|
||||||
static inline void list_replace_init(struct list_head *old,
|
|
||||||
struct list_head *new)
|
|
||||||
{
|
|
||||||
list_replace(old, new);
|
|
||||||
INIT_LIST_HEAD(old);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_swap - replace entry1 with entry2 and re-add entry1 at entry2's position
|
|
||||||
* @entry1: the location to place entry2
|
|
||||||
* @entry2: the location to place entry1
|
|
||||||
*/
|
|
||||||
static inline void list_swap(struct list_head *entry1,
|
|
||||||
struct list_head *entry2)
|
|
||||||
{
|
|
||||||
struct list_head *pos = entry2->prev;
|
|
||||||
|
|
||||||
list_del(entry2);
|
|
||||||
list_replace(entry1, entry2);
|
|
||||||
if (pos == entry1)
|
|
||||||
pos = entry2;
|
|
||||||
list_add(entry1, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_del_init - deletes entry from list and reinitialize it.
|
|
||||||
* @entry: the element to delete from the list.
|
|
||||||
*/
|
|
||||||
static inline void list_del_init(struct list_head *entry)
|
|
||||||
{
|
|
||||||
__list_del_entry(entry);
|
|
||||||
INIT_LIST_HEAD(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_move - delete from one list and add as another's head
|
|
||||||
* @list: the entry to move
|
|
||||||
* @head: the head that will precede our entry
|
|
||||||
*/
|
|
||||||
static inline void list_move(struct list_head *list, struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_del_entry(list);
|
|
||||||
list_add(list, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_move_tail - delete from one list and add as another's tail
|
|
||||||
* @list: the entry to move
|
|
||||||
* @head: the head that will follow our entry
|
|
||||||
*/
|
|
||||||
static inline void list_move_tail(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_del_entry(list);
|
|
||||||
list_add_tail(list, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_bulk_move_tail - move a subsection of a list to its tail
|
|
||||||
* @head: the head that will follow our entry
|
|
||||||
* @first: first entry to move
|
|
||||||
* @last: last entry to move, can be the same as first
|
|
||||||
*
|
|
||||||
* Move all entries between @first and including @last before @head.
|
|
||||||
* All three entries must belong to the same linked list.
|
|
||||||
*/
|
|
||||||
static inline void list_bulk_move_tail(struct list_head *head,
|
|
||||||
struct list_head *first,
|
|
||||||
struct list_head *last)
|
|
||||||
{
|
|
||||||
first->prev->next = last->next;
|
|
||||||
last->next->prev = first->prev;
|
|
||||||
|
|
||||||
head->prev->next = first;
|
|
||||||
first->prev = head->prev;
|
|
||||||
|
|
||||||
last->next = head;
|
|
||||||
head->prev = last;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_is_first -- tests whether @list is the first entry in list @head
|
|
||||||
* @list: the entry to test
|
|
||||||
* @head: the head of the list
|
|
||||||
*/
|
|
||||||
static inline int list_is_first(const struct list_head *list,
|
|
||||||
const struct list_head *head)
|
|
||||||
{
|
|
||||||
return list->prev == head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_is_last - tests whether @list is the last entry in list @head
|
|
||||||
* @list: the entry to test
|
|
||||||
* @head: the head of the list
|
|
||||||
*/
|
|
||||||
static inline int list_is_last(const struct list_head *list,
|
|
||||||
const struct list_head *head)
|
|
||||||
{
|
|
||||||
return list->next == head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_empty - tests whether a list is empty
|
|
||||||
* @head: the list to test.
|
|
||||||
*/
|
|
||||||
static inline int list_empty(const struct list_head *head)
|
|
||||||
{
|
|
||||||
return READ_ONCE(head->next) == head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_rotate_left - rotate the list to the left
|
|
||||||
* @head: the head of the list
|
|
||||||
*/
|
|
||||||
static inline void list_rotate_left(struct list_head *head)
|
|
||||||
{
|
|
||||||
struct list_head *first;
|
|
||||||
|
|
||||||
if (!list_empty(head)) {
|
|
||||||
first = head->next;
|
|
||||||
list_move_tail(first, head);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_rotate_to_front() - Rotate list to specific item.
|
|
||||||
* @list: The desired new front of the list.
|
|
||||||
* @head: The head of the list.
|
|
||||||
*
|
|
||||||
* Rotates list so that @list becomes the new front of the list.
|
|
||||||
*/
|
|
||||||
static inline void list_rotate_to_front(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Deletes the list head from the list denoted by @head and
|
|
||||||
* places it as the tail of @list, this effectively rotates the
|
|
||||||
* list so that @list is at the front.
|
|
||||||
*/
|
|
||||||
list_move_tail(head, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_is_singular - tests whether a list has just one entry.
|
|
||||||
* @head: the list to test.
|
|
||||||
*/
|
|
||||||
static inline int list_is_singular(const struct list_head *head)
|
|
||||||
{
|
|
||||||
return !list_empty(head) && (head->next == head->prev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __list_cut_position(struct list_head *list,
|
|
||||||
struct list_head *head, struct list_head *entry)
|
|
||||||
{
|
|
||||||
struct list_head *new_first = entry->next;
|
|
||||||
list->next = head->next;
|
|
||||||
list->next->prev = list;
|
|
||||||
list->prev = entry;
|
|
||||||
entry->next = list;
|
|
||||||
head->next = new_first;
|
|
||||||
new_first->prev = head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_cut_position - cut a list into two
|
|
||||||
* @list: a new list to add all removed entries
|
|
||||||
* @head: a list with entries
|
|
||||||
* @entry: an entry within head, could be the head itself
|
|
||||||
* and if so we won't cut the list
|
|
||||||
*
|
|
||||||
* This helper moves the initial part of @head, up to and
|
|
||||||
* including @entry, from @head to @list. You should
|
|
||||||
* pass on @entry an element you know is on @head. @list
|
|
||||||
* should be an empty list or a list you do not care about
|
|
||||||
* losing its data.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static inline void list_cut_position(struct list_head *list,
|
|
||||||
struct list_head *head, struct list_head *entry)
|
|
||||||
{
|
|
||||||
if (list_empty(head))
|
|
||||||
return;
|
|
||||||
if (list_is_singular(head) &&
|
|
||||||
(head->next != entry && head != entry))
|
|
||||||
return;
|
|
||||||
if (entry == head)
|
|
||||||
INIT_LIST_HEAD(list);
|
|
||||||
else
|
|
||||||
__list_cut_position(list, head, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_cut_before - cut a list into two, before given entry
|
|
||||||
* @list: a new list to add all removed entries
|
|
||||||
* @head: a list with entries
|
|
||||||
* @entry: an entry within head, could be the head itself
|
|
||||||
*
|
|
||||||
* This helper moves the initial part of @head, up to but
|
|
||||||
* excluding @entry, from @head to @list. You should pass
|
|
||||||
* in @entry an element you know is on @head. @list should
|
|
||||||
* be an empty list or a list you do not care about losing
|
|
||||||
* its data.
|
|
||||||
* If @entry == @head, all entries on @head are moved to
|
|
||||||
* @list.
|
|
||||||
*/
|
|
||||||
static inline void list_cut_before(struct list_head *list,
|
|
||||||
struct list_head *head,
|
|
||||||
struct list_head *entry)
|
|
||||||
{
|
|
||||||
if (head->next == entry) {
|
|
||||||
INIT_LIST_HEAD(list);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
list->next = head->next;
|
|
||||||
list->next->prev = list;
|
|
||||||
list->prev = entry->prev;
|
|
||||||
list->prev->next = list;
|
|
||||||
head->next = entry;
|
|
||||||
entry->prev = head;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __list_splice(const struct list_head *list,
|
|
||||||
struct list_head *prev,
|
|
||||||
struct list_head *next)
|
|
||||||
{
|
|
||||||
struct list_head *first = list->next;
|
|
||||||
struct list_head *last = list->prev;
|
|
||||||
|
|
||||||
first->prev = prev;
|
|
||||||
prev->next = first;
|
|
||||||
|
|
||||||
last->next = next;
|
|
||||||
next->prev = last;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_splice - join two lists, this is designed for stacks
|
|
||||||
* @list: the new list to add.
|
|
||||||
* @head: the place to add it in the first list.
|
|
||||||
*/
|
|
||||||
static inline void list_splice(const struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
if (!list_empty(list))
|
|
||||||
__list_splice(list, head, head->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_splice_tail - join two lists, each list being a queue
|
|
||||||
* @list: the new list to add.
|
|
||||||
* @head: the place to add it in the first list.
|
|
||||||
*/
|
|
||||||
static inline void list_splice_tail(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
if (!list_empty(list))
|
|
||||||
__list_splice(list, head->prev, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_splice_init - join two lists and reinitialise the emptied list.
|
|
||||||
* @list: the new list to add.
|
|
||||||
* @head: the place to add it in the first list.
|
|
||||||
*
|
|
||||||
* The list at @list is reinitialised
|
|
||||||
*/
|
|
||||||
static inline void list_splice_init(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
if (!list_empty(list)) {
|
|
||||||
__list_splice(list, head, head->next);
|
|
||||||
INIT_LIST_HEAD(list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_splice_tail_init - join two lists and reinitialise the emptied list
|
|
||||||
* @list: the new list to add.
|
|
||||||
* @head: the place to add it in the first list.
|
|
||||||
*
|
|
||||||
* Each of the lists is a queue.
|
|
||||||
* The list at @list is reinitialised
|
|
||||||
*/
|
|
||||||
static inline void list_splice_tail_init(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
if (!list_empty(list)) {
|
|
||||||
__list_splice(list, head->prev, head);
|
|
||||||
INIT_LIST_HEAD(list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_entry - get the struct for this entry
|
|
||||||
* @ptr: the &struct list_head pointer.
|
|
||||||
* @type: the type of the struct this is embedded in.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_entry(ptr, type, member) \
|
|
||||||
container_of(ptr, type, member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_first_entry - get the first element from a list
|
|
||||||
* @ptr: the list head to take the element from.
|
|
||||||
* @type: the type of the struct this is embedded in.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Note, that list is expected to be not empty.
|
|
||||||
*/
|
|
||||||
#define list_first_entry(ptr, type, member) \
|
|
||||||
list_entry((ptr)->next, type, member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_last_entry - get the last element from a list
|
|
||||||
* @ptr: the list head to take the element from.
|
|
||||||
* @type: the type of the struct this is embedded in.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Note, that list is expected to be not empty.
|
|
||||||
*/
|
|
||||||
#define list_last_entry(ptr, type, member) \
|
|
||||||
list_entry((ptr)->prev, type, member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_first_entry_or_null - get the first element from a list
|
|
||||||
* @ptr: the list head to take the element from.
|
|
||||||
* @type: the type of the struct this is embedded in.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Note that if the list is empty, it returns NULL.
|
|
||||||
*/
|
|
||||||
#define list_first_entry_or_null(ptr, type, member) ({ \
|
|
||||||
struct list_head *head__ = (ptr); \
|
|
||||||
struct list_head *pos__ = READ_ONCE(head__->next); \
|
|
||||||
pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_next_entry - get the next element in list
|
|
||||||
* @pos: the type * to cursor
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_next_entry(pos, member) \
|
|
||||||
list_entry((pos)->member.next, __typeof__(*(pos)), member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_prev_entry - get the prev element in list
|
|
||||||
* @pos: the type * to cursor
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_prev_entry(pos, member) \
|
|
||||||
list_entry((pos)->member.prev, __typeof__(*(pos)), member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each - iterate over a list
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
*/
|
|
||||||
#define list_for_each(pos, head) \
|
|
||||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_continue - continue iteration over a list
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
*
|
|
||||||
* Continue to iterate over a list, continuing after the current position.
|
|
||||||
*/
|
|
||||||
#define list_for_each_continue(pos, head) \
|
|
||||||
for (pos = pos->next; pos != (head); pos = pos->next)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_prev - iterate over a list backwards
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
*/
|
|
||||||
#define list_for_each_prev(pos, head) \
|
|
||||||
for (pos = (head)->prev; pos != (head); pos = pos->prev)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @n: another &struct list_head to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
*/
|
|
||||||
#define list_for_each_safe(pos, n, head) \
|
|
||||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
|
||||||
pos = n, n = pos->next)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @n: another &struct list_head to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
*/
|
|
||||||
#define list_for_each_prev_safe(pos, n, head) \
|
|
||||||
for (pos = (head)->prev, n = pos->prev; \
|
|
||||||
pos != (head); \
|
|
||||||
pos = n, n = pos->prev)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_entry_is_head - test if the entry points to the head of the list
|
|
||||||
* @pos: the type * to cursor
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_entry_is_head(pos, head, member) \
|
|
||||||
(&pos->member == (head))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry - iterate over list of given type
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry(pos, head, member) \
|
|
||||||
for (pos = list_first_entry(head, __typeof__(*pos), member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = list_next_entry(pos, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_reverse - iterate backwards over list of given type.
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_reverse(pos, head, member) \
|
|
||||||
for (pos = list_last_entry(head, __typeof__(*pos), member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = list_prev_entry(pos, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
|
|
||||||
* @pos: the type * to use as a start point
|
|
||||||
* @head: the head of the list
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Prepares a pos entry for use as a start point in list_for_each_entry_continue().
|
|
||||||
*/
|
|
||||||
#define list_prepare_entry(pos, head, member) \
|
|
||||||
((pos) ? : list_entry(head, __typeof__(*pos), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_continue - continue iteration over list of given type
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Continue to iterate over list of given type, continuing after
|
|
||||||
* the current position.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_continue(pos, head, member) \
|
|
||||||
for (pos = list_next_entry(pos, member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = list_next_entry(pos, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_continue_reverse - iterate backwards from the given point
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Start to iterate over list of given type backwards, continuing after
|
|
||||||
* the current position.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_continue_reverse(pos, head, member) \
|
|
||||||
for (pos = list_prev_entry(pos, member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = list_prev_entry(pos, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_from - iterate over list of given type from the current point
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Iterate over list of given type, continuing from current position.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_from(pos, head, member) \
|
|
||||||
for (; !list_entry_is_head(pos, head, member); \
|
|
||||||
pos = list_next_entry(pos, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_from_reverse - iterate backwards over list of given type
|
|
||||||
* from the current point
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Iterate backwards over list of given type, continuing from current position.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_from_reverse(pos, head, member) \
|
|
||||||
for (; !list_entry_is_head(pos, head, member); \
|
|
||||||
pos = list_prev_entry(pos, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
|
||||||
for (pos = list_first_entry(head, __typeof__(*pos), member), \
|
|
||||||
n = list_next_entry(pos, member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = n, n = list_next_entry(n, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_safe_continue - continue list iteration safe against removal
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Iterate over list of given type, continuing after current point,
|
|
||||||
* safe against removal of list entry.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_safe_continue(pos, n, head, member) \
|
|
||||||
for (pos = list_next_entry(pos, member), \
|
|
||||||
n = list_next_entry(pos, member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = n, n = list_next_entry(n, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_safe_from - iterate over list from current point safe against removal
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Iterate over list of given type from current point, safe against
|
|
||||||
* removal of list entry.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_safe_from(pos, n, head, member) \
|
|
||||||
for (n = list_next_entry(pos, member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = n, n = list_next_entry(n, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Iterate backwards over list of given type, safe against removal
|
|
||||||
* of list entry.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
|
|
||||||
for (pos = list_last_entry(head, __typeof__(*pos), member), \
|
|
||||||
n = list_prev_entry(pos, member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = n, n = list_prev_entry(n, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_safe_reset_next - reset a stale list_for_each_entry_safe loop
|
|
||||||
* @pos: the loop cursor used in the list_for_each_entry_safe loop
|
|
||||||
* @n: temporary storage used in list_for_each_entry_safe
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* list_safe_reset_next is not safe to use in general if the list may be
|
|
||||||
* modified concurrently (eg. the lock is dropped in the loop body). An
|
|
||||||
* exception to this is if the cursor element (pos) is pinned in the list,
|
|
||||||
* and list_safe_reset_next is called after re-taking the lock and before
|
|
||||||
* completing the current iteration of the loop body.
|
|
||||||
*/
|
|
||||||
#define list_safe_reset_next(pos, n, member) \
|
|
||||||
n = list_next_entry(pos, member)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Double linked lists with a single pointer list head.
|
|
||||||
* Mostly useful for hash tables where the two pointer list head is
|
|
||||||
* too wasteful.
|
|
||||||
* You lose the ability to access the tail in O(1).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define HLIST_HEAD_INIT { .first = NULL }
|
|
||||||
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
|
|
||||||
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
|
|
||||||
static inline void INIT_HLIST_NODE(struct hlist_node *h)
|
|
||||||
{
|
|
||||||
h->next = NULL;
|
|
||||||
h->pprev = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_unhashed - Has node been removed from list and reinitialized?
|
|
||||||
* @h: Node to be checked
|
|
||||||
*
|
|
||||||
* Not that not all removal functions will leave a node in unhashed
|
|
||||||
* state. For example, hlist_nulls_del_init_rcu() does leave the
|
|
||||||
* node in unhashed state, but hlist_nulls_del() does not.
|
|
||||||
*/
|
|
||||||
static inline int hlist_unhashed(const struct hlist_node *h)
|
|
||||||
{
|
|
||||||
return !h->pprev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_unhashed_lockless - Version of hlist_unhashed for lockless use
|
|
||||||
* @h: Node to be checked
|
|
||||||
*
|
|
||||||
* This variant of hlist_unhashed() must be used in lockless contexts
|
|
||||||
* to avoid potential load-tearing. The READ_ONCE() is paired with the
|
|
||||||
* various WRITE_ONCE() in hlist helpers that are defined below.
|
|
||||||
*/
|
|
||||||
static inline int hlist_unhashed_lockless(const struct hlist_node *h)
|
|
||||||
{
|
|
||||||
return !READ_ONCE(h->pprev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_empty - Is the specified hlist_head structure an empty hlist?
|
|
||||||
* @h: Structure to check.
|
|
||||||
*/
|
|
||||||
static inline int hlist_empty(const struct hlist_head *h)
|
|
||||||
{
|
|
||||||
return !READ_ONCE(h->first);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __hlist_del(struct hlist_node *n)
|
|
||||||
{
|
|
||||||
struct hlist_node *next = n->next;
|
|
||||||
struct hlist_node **pprev = n->pprev;
|
|
||||||
|
|
||||||
WRITE_ONCE(*pprev, next);
|
|
||||||
if (next)
|
|
||||||
WRITE_ONCE(next->pprev, pprev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_del - Delete the specified hlist_node from its list
|
|
||||||
* @n: Node to delete.
|
|
||||||
*
|
|
||||||
* Note that this function leaves the node in hashed state. Use
|
|
||||||
* hlist_del_init() or similar instead to unhash @n.
|
|
||||||
*/
|
|
||||||
static inline void hlist_del(struct hlist_node *n)
|
|
||||||
{
|
|
||||||
__hlist_del(n);
|
|
||||||
n->next = LIST_POISON1;
|
|
||||||
n->pprev = LIST_POISON2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_del_init - Delete the specified hlist_node from its list and initialize
|
|
||||||
* @n: Node to delete.
|
|
||||||
*
|
|
||||||
* Note that this function leaves the node in unhashed state.
|
|
||||||
*/
|
|
||||||
static inline void hlist_del_init(struct hlist_node *n)
|
|
||||||
{
|
|
||||||
if (!hlist_unhashed(n)) {
|
|
||||||
__hlist_del(n);
|
|
||||||
INIT_HLIST_NODE(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_add_head - add a new entry at the beginning of the hlist
|
|
||||||
* @n: new entry to be added
|
|
||||||
* @h: hlist head to add it after
|
|
||||||
*
|
|
||||||
* Insert a new entry after the specified head.
|
|
||||||
* This is good for implementing stacks.
|
|
||||||
*/
|
|
||||||
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
|
|
||||||
{
|
|
||||||
struct hlist_node *first = h->first;
|
|
||||||
WRITE_ONCE(n->next, first);
|
|
||||||
if (first)
|
|
||||||
WRITE_ONCE(first->pprev, &n->next);
|
|
||||||
WRITE_ONCE(h->first, n);
|
|
||||||
WRITE_ONCE(n->pprev, &h->first);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_add_before - add a new entry before the one specified
|
|
||||||
* @n: new entry to be added
|
|
||||||
* @next: hlist node to add it before, which must be non-NULL
|
|
||||||
*/
|
|
||||||
static inline void hlist_add_before(struct hlist_node *n,
|
|
||||||
struct hlist_node *next)
|
|
||||||
{
|
|
||||||
WRITE_ONCE(n->pprev, next->pprev);
|
|
||||||
WRITE_ONCE(n->next, next);
|
|
||||||
WRITE_ONCE(next->pprev, &n->next);
|
|
||||||
WRITE_ONCE(*(n->pprev), n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_add_behind - add a new entry after the one specified
|
|
||||||
* @n: new entry to be added
|
|
||||||
* @prev: hlist node to add it after, which must be non-NULL
|
|
||||||
*/
|
|
||||||
static inline void hlist_add_behind(struct hlist_node *n,
|
|
||||||
struct hlist_node *prev)
|
|
||||||
{
|
|
||||||
WRITE_ONCE(n->next, prev->next);
|
|
||||||
WRITE_ONCE(prev->next, n);
|
|
||||||
WRITE_ONCE(n->pprev, &prev->next);
|
|
||||||
|
|
||||||
if (n->next)
|
|
||||||
WRITE_ONCE(n->next->pprev, &n->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_add_fake - create a fake hlist consisting of a single headless node
|
|
||||||
* @n: Node to make a fake list out of
|
|
||||||
*
|
|
||||||
* This makes @n appear to be its own predecessor on a headless hlist.
|
|
||||||
* The point of this is to allow things like hlist_del() to work correctly
|
|
||||||
* in cases where there is no list.
|
|
||||||
*/
|
|
||||||
static inline void hlist_add_fake(struct hlist_node *n)
|
|
||||||
{
|
|
||||||
n->pprev = &n->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_fake: Is this node a fake hlist?
|
|
||||||
* @h: Node to check for being a self-referential fake hlist.
|
|
||||||
*/
|
|
||||||
static inline bool hlist_fake(struct hlist_node *h)
|
|
||||||
{
|
|
||||||
return h->pprev == &h->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_is_singular_node - is node the only element of the specified hlist?
|
|
||||||
* @n: Node to check for singularity.
|
|
||||||
* @h: Header for potentially singular list.
|
|
||||||
*
|
|
||||||
* Check whether the node is the only node of the head without
|
|
||||||
* accessing head, thus avoiding unnecessary cache misses.
|
|
||||||
*/
|
|
||||||
static inline bool
|
|
||||||
hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h)
|
|
||||||
{
|
|
||||||
return !n->next && n->pprev == &h->first;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_move_list - Move an hlist
|
|
||||||
* @old: hlist_head for old list.
|
|
||||||
* @new: hlist_head for new list.
|
|
||||||
*
|
|
||||||
* Move a list from one list head to another. Fixup the pprev
|
|
||||||
* reference of the first entry if it exists.
|
|
||||||
*/
|
|
||||||
static inline void hlist_move_list(struct hlist_head *old,
|
|
||||||
struct hlist_head *new)
|
|
||||||
{
|
|
||||||
new->first = old->first;
|
|
||||||
if (new->first)
|
|
||||||
new->first->pprev = &new->first;
|
|
||||||
old->first = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
|
|
||||||
|
|
||||||
#define hlist_for_each(pos, head) \
|
|
||||||
for (pos = (head)->first; pos ; pos = pos->next)
|
|
||||||
|
|
||||||
#define hlist_for_each_safe(pos, n, head) \
|
|
||||||
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
|
|
||||||
pos = n)
|
|
||||||
|
|
||||||
#define hlist_entry_safe(ptr, type, member) \
|
|
||||||
({ __typeof__(ptr) ____ptr = (ptr); \
|
|
||||||
____ptr ? hlist_entry(____ptr, type, member) : NULL; \
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_for_each_entry - iterate over list of given type
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the hlist_node within the struct.
|
|
||||||
*/
|
|
||||||
#define hlist_for_each_entry(pos, head, member) \
|
|
||||||
for (pos = hlist_entry_safe((head)->first, __typeof__(*(pos)), member); \
|
|
||||||
pos; \
|
|
||||||
pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_for_each_entry_continue - iterate over a hlist continuing after current point
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @member: the name of the hlist_node within the struct.
|
|
||||||
*/
|
|
||||||
#define hlist_for_each_entry_continue(pos, member) \
|
|
||||||
for (pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member); \
|
|
||||||
pos; \
|
|
||||||
pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_for_each_entry_from - iterate over a hlist continuing from current point
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @member: the name of the hlist_node within the struct.
|
|
||||||
*/
|
|
||||||
#define hlist_for_each_entry_from(pos, member) \
|
|
||||||
for (; pos; \
|
|
||||||
pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: a &struct hlist_node to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the hlist_node within the struct.
|
|
||||||
*/
|
|
||||||
#define hlist_for_each_entry_safe(pos, n, head, member) \
|
|
||||||
for (pos = hlist_entry_safe((head)->first, __typeof__(*pos), member); \
|
|
||||||
pos && ({ n = pos->member.next; 1; }); \
|
|
||||||
pos = hlist_entry_safe(n, __typeof__(*pos), member))
|
|
||||||
|
|
||||||
#endif /* __BR_LIST_H */
|
|
||||||
@@ -1,301 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
/*
|
|
||||||
* Descending-priority-sorted double-linked list
|
|
||||||
*
|
|
||||||
* (C) 2002-2003 Intel Corp
|
|
||||||
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>.
|
|
||||||
*
|
|
||||||
* 2001-2005 (c) MontaVista Software, Inc.
|
|
||||||
* Daniel Walker <dwalker@mvista.com>
|
|
||||||
*
|
|
||||||
* (C) 2005 Thomas Gleixner <tglx@linutronix.de>
|
|
||||||
*
|
|
||||||
* Simplifications of the original code by
|
|
||||||
* Oleg Nesterov <oleg@tv-sign.ru>
|
|
||||||
*
|
|
||||||
* Based on simple lists (include/linux/list.h).
|
|
||||||
*
|
|
||||||
* This is a priority-sorted list of nodes; each node has a
|
|
||||||
* priority from INT_MIN (highest) to INT_MAX (lowest).
|
|
||||||
*
|
|
||||||
* Addition is O(K), removal is O(1), change of priority of a node is
|
|
||||||
* O(K) and K is the number of RT priority levels used in the system.
|
|
||||||
* (1 <= K <= 99)
|
|
||||||
*
|
|
||||||
* This list is really a list of lists:
|
|
||||||
*
|
|
||||||
* - The tier 1 list is the prio_list, different priority nodes.
|
|
||||||
*
|
|
||||||
* - The tier 2 list is the node_list, serialized nodes.
|
|
||||||
*
|
|
||||||
* Simple ASCII art explanation:
|
|
||||||
*
|
|
||||||
* pl:prio_list (only for plist_node)
|
|
||||||
* nl:node_list
|
|
||||||
* HEAD| NODE(S)
|
|
||||||
* |
|
|
||||||
* ||------------------------------------|
|
|
||||||
* ||->|pl|<->|pl|<--------------->|pl|<-|
|
|
||||||
* | |10| |21| |21| |21| |40| (prio)
|
|
||||||
* | | | | | | | | | | |
|
|
||||||
* | | | | | | | | | | |
|
|
||||||
* |->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-|
|
|
||||||
* |-------------------------------------------|
|
|
||||||
*
|
|
||||||
* The nodes on the prio_list list are sorted by priority to simplify
|
|
||||||
* the insertion of new nodes. There are no nodes with duplicate
|
|
||||||
* priorites on the list.
|
|
||||||
*
|
|
||||||
* The nodes on the node_list are ordered by priority and can contain
|
|
||||||
* entries which have the same priority. Those entries are ordered
|
|
||||||
* FIFO
|
|
||||||
*
|
|
||||||
* Addition means: look for the prio_list node in the prio_list
|
|
||||||
* for the priority of the node and insert it before the node_list
|
|
||||||
* entry of the next prio_list node. If it is the first node of
|
|
||||||
* that priority, add it to the prio_list in the right position and
|
|
||||||
* insert it into the serialized node_list list
|
|
||||||
*
|
|
||||||
* Removal means remove it from the node_list and remove it from
|
|
||||||
* the prio_list if the node_list list_head is non empty. In case
|
|
||||||
* of removal from the prio_list it must be checked whether other
|
|
||||||
* entries of the same priority are on the list or not. If there
|
|
||||||
* is another entry of the same priority then this entry has to
|
|
||||||
* replace the removed entry on the prio_list. If the entry which
|
|
||||||
* is removed is the only entry of this priority then a simple
|
|
||||||
* remove from both list is sufficient.
|
|
||||||
*
|
|
||||||
* INT_MIN is the highest priority, 0 is the medium highest, INT_MAX
|
|
||||||
* is lowest priority.
|
|
||||||
*
|
|
||||||
* No locking is done, up to the caller.
|
|
||||||
*/
|
|
||||||
#ifndef _LINUX_PLIST_H_
|
|
||||||
#define _LINUX_PLIST_H_
|
|
||||||
|
|
||||||
#include "container-of.h"
|
|
||||||
#include "list.h"
|
|
||||||
//#include <types.h>
|
|
||||||
|
|
||||||
// #include <asm/bug.h>
|
|
||||||
|
|
||||||
struct plist_head {
|
|
||||||
struct list_head node_list;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct plist_node {
|
|
||||||
int prio;
|
|
||||||
struct list_head prio_list;
|
|
||||||
struct list_head node_list;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PLIST_HEAD_INIT - static struct plist_head initializer
|
|
||||||
* @head: struct plist_head variable name
|
|
||||||
*/
|
|
||||||
#define PLIST_HEAD_INIT(head) \
|
|
||||||
{ \
|
|
||||||
.node_list = LIST_HEAD_INIT((head).node_list) \
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PLIST_HEAD - declare and init plist_head
|
|
||||||
* @head: name for struct plist_head variable
|
|
||||||
*/
|
|
||||||
#define PLIST_HEAD(head) \
|
|
||||||
struct plist_head head = PLIST_HEAD_INIT(head)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PLIST_NODE_INIT - static struct plist_node initializer
|
|
||||||
* @node: struct plist_node variable name
|
|
||||||
* @__prio: initial node priority
|
|
||||||
*/
|
|
||||||
#define PLIST_NODE_INIT(node, __prio) \
|
|
||||||
{ \
|
|
||||||
.prio = (__prio), \
|
|
||||||
.prio_list = LIST_HEAD_INIT((node).prio_list), \
|
|
||||||
.node_list = LIST_HEAD_INIT((node).node_list), \
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_head_init - dynamic struct plist_head initializer
|
|
||||||
* @head: &struct plist_head pointer
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
plist_head_init(struct plist_head *head)
|
|
||||||
{
|
|
||||||
INIT_LIST_HEAD(&head->node_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_node_init - Dynamic struct plist_node initializer
|
|
||||||
* @node: &struct plist_node pointer
|
|
||||||
* @prio: initial node priority
|
|
||||||
*/
|
|
||||||
static inline void plist_node_init(struct plist_node *node, int prio)
|
|
||||||
{
|
|
||||||
node->prio = prio;
|
|
||||||
INIT_LIST_HEAD(&node->prio_list);
|
|
||||||
INIT_LIST_HEAD(&node->node_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void plist_add(struct plist_node *node, struct plist_head *head);
|
|
||||||
extern void plist_del(struct plist_node *node, struct plist_head *head);
|
|
||||||
|
|
||||||
extern void plist_requeue(struct plist_node *node, struct plist_head *head);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_for_each - iterate over the plist
|
|
||||||
* @pos: the type * to use as a loop counter
|
|
||||||
* @head: the head for your list
|
|
||||||
*/
|
|
||||||
#define plist_for_each(pos, head) \
|
|
||||||
list_for_each_entry(pos, &(head)->node_list, node_list)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_for_each_continue - continue iteration over the plist
|
|
||||||
* @pos: the type * to use as a loop cursor
|
|
||||||
* @head: the head for your list
|
|
||||||
*
|
|
||||||
* Continue to iterate over plist, continuing after the current position.
|
|
||||||
*/
|
|
||||||
#define plist_for_each_continue(pos, head) \
|
|
||||||
list_for_each_entry_continue(pos, &(head)->node_list, node_list)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_for_each_safe - iterate safely over a plist of given type
|
|
||||||
* @pos: the type * to use as a loop counter
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list
|
|
||||||
*
|
|
||||||
* Iterate over a plist of given type, safe against removal of list entry.
|
|
||||||
*/
|
|
||||||
#define plist_for_each_safe(pos, n, head) \
|
|
||||||
list_for_each_entry_safe(pos, n, &(head)->node_list, node_list)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_for_each_entry - iterate over list of given type
|
|
||||||
* @pos: the type * to use as a loop counter
|
|
||||||
* @head: the head for your list
|
|
||||||
* @mem: the name of the list_head within the struct
|
|
||||||
*/
|
|
||||||
#define plist_for_each_entry(pos, head, mem) \
|
|
||||||
list_for_each_entry(pos, &(head)->node_list, mem.node_list)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_for_each_entry_continue - continue iteration over list of given type
|
|
||||||
* @pos: the type * to use as a loop cursor
|
|
||||||
* @head: the head for your list
|
|
||||||
* @m: the name of the list_head within the struct
|
|
||||||
*
|
|
||||||
* Continue to iterate over list of given type, continuing after
|
|
||||||
* the current position.
|
|
||||||
*/
|
|
||||||
#define plist_for_each_entry_continue(pos, head, m) \
|
|
||||||
list_for_each_entry_continue(pos, &(head)->node_list, m.node_list)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_for_each_entry_safe - iterate safely over list of given type
|
|
||||||
* @pos: the type * to use as a loop counter
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list
|
|
||||||
* @m: the name of the list_head within the struct
|
|
||||||
*
|
|
||||||
* Iterate over list of given type, safe against removal of list entry.
|
|
||||||
*/
|
|
||||||
#define plist_for_each_entry_safe(pos, n, head, m) \
|
|
||||||
list_for_each_entry_safe(pos, n, &(head)->node_list, m.node_list)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_head_empty - return !0 if a plist_head is empty
|
|
||||||
* @head: &struct plist_head pointer
|
|
||||||
*/
|
|
||||||
static inline int plist_head_empty(const struct plist_head *head)
|
|
||||||
{
|
|
||||||
return list_empty(&head->node_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_node_empty - return !0 if plist_node is not on a list
|
|
||||||
* @node: &struct plist_node pointer
|
|
||||||
*/
|
|
||||||
static inline int plist_node_empty(const struct plist_node *node)
|
|
||||||
{
|
|
||||||
return list_empty(&node->node_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* All functions below assume the plist_head is not empty. */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_first_entry - get the struct for the first entry
|
|
||||||
* @head: the &struct plist_head pointer
|
|
||||||
* @type: the type of the struct this is embedded in
|
|
||||||
* @member: the name of the list_head within the struct
|
|
||||||
*/
|
|
||||||
#ifdef CONFIG_DEBUG_PLIST
|
|
||||||
# define plist_first_entry(head, type, member) \
|
|
||||||
({ \
|
|
||||||
WARN_ON(plist_head_empty(head)); \
|
|
||||||
container_of(plist_first(head), type, member); \
|
|
||||||
})
|
|
||||||
#else
|
|
||||||
# define plist_first_entry(head, type, member) \
|
|
||||||
container_of(plist_first(head), type, member)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_last_entry - get the struct for the last entry
|
|
||||||
* @head: the &struct plist_head pointer
|
|
||||||
* @type: the type of the struct this is embedded in
|
|
||||||
* @member: the name of the list_head within the struct
|
|
||||||
*/
|
|
||||||
#ifdef CONFIG_DEBUG_PLIST
|
|
||||||
# define plist_last_entry(head, type, member) \
|
|
||||||
({ \
|
|
||||||
WARN_ON(plist_head_empty(head)); \
|
|
||||||
container_of(plist_last(head), type, member); \
|
|
||||||
})
|
|
||||||
#else
|
|
||||||
# define plist_last_entry(head, type, member) \
|
|
||||||
container_of(plist_last(head), type, member)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_next - get the next entry in list
|
|
||||||
* @pos: the type * to cursor
|
|
||||||
*/
|
|
||||||
#define plist_next(pos) \
|
|
||||||
list_next_entry(pos, node_list)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_prev - get the prev entry in list
|
|
||||||
* @pos: the type * to cursor
|
|
||||||
*/
|
|
||||||
#define plist_prev(pos) \
|
|
||||||
list_prev_entry(pos, node_list)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_first - return the first node (and thus, highest priority)
|
|
||||||
* @head: the &struct plist_head pointer
|
|
||||||
*
|
|
||||||
* Assumes the plist is _not_ empty.
|
|
||||||
*/
|
|
||||||
static inline struct plist_node *plist_first(const struct plist_head *head)
|
|
||||||
{
|
|
||||||
return list_entry(head->node_list.next,
|
|
||||||
struct plist_node, node_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_last - return the last node (and thus, lowest priority)
|
|
||||||
* @head: the &struct plist_head pointer
|
|
||||||
*
|
|
||||||
* Assumes the plist is _not_ empty.
|
|
||||||
*/
|
|
||||||
static inline struct plist_node *plist_last(const struct plist_head *head)
|
|
||||||
{
|
|
||||||
return list_entry(head->node_list.prev,
|
|
||||||
struct plist_node, node_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
/* pool.h - A simple memory pool manager.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021-2022 Bruno Raoult ("br")
|
|
||||||
* Licensed under the GNU General Public License v3.0 or later.
|
|
||||||
* Some rights reserved. See COPYING.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
|
||||||
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef POOL_H
|
|
||||||
#define POOL_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include "list.h"
|
|
||||||
#include "bits.h"
|
|
||||||
|
|
||||||
#define POOL_NAME_LENGTH (16) /* max name length including trailing \0 */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
struct list_head list_blocks; /* list of allocated blocks in pool */
|
|
||||||
char data[]; /* objects block */
|
|
||||||
} block_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char name[POOL_NAME_LENGTH]; /* pool name */
|
|
||||||
size_t eltsize; /* object size */
|
|
||||||
u32 available; /* current available elements */
|
|
||||||
u32 allocated; /* total objects allocated */
|
|
||||||
u32 growsize; /* number of objects per block allocated */
|
|
||||||
u32 nblocks; /* number of blocks allocated */
|
|
||||||
struct list_head list_available; /* available nodes */
|
|
||||||
struct list_head list_blocks; /* allocated blocks */
|
|
||||||
} pool_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pool_stats - display some pool statistics
|
|
||||||
* @pool: the pool address.
|
|
||||||
*/
|
|
||||||
void pool_stats(pool_t *pool);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pool_create - create a new memory pool
|
|
||||||
* @name: the name to give to the pool.
|
|
||||||
* @grow: the number of elements to add when no more available.
|
|
||||||
* @size: the size of an element in pool.
|
|
||||||
*
|
|
||||||
* The name will be truncated to 16 characters (including the final '\0').
|
|
||||||
*
|
|
||||||
* Return: The address of the created pool, or NULL if error.
|
|
||||||
*/
|
|
||||||
pool_t *pool_create(const char *name, u32 grow, size_t size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pool_get() - Get an element from a pool.
|
|
||||||
* @pool: The pool address.
|
|
||||||
*
|
|
||||||
* Get an object from the pool.
|
|
||||||
*
|
|
||||||
* Return: The address of the object, or NULL if error.
|
|
||||||
*/
|
|
||||||
void *pool_get(pool_t *pool);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pool_add() - Add (free) an element to a pool.
|
|
||||||
* @pool: The pool address.
|
|
||||||
* @elt: The address of the object to add to the pool.
|
|
||||||
*
|
|
||||||
* The object will be available for further pool_get().
|
|
||||||
*
|
|
||||||
* Return: The current number of available elements in pool (including
|
|
||||||
* @elt).
|
|
||||||
*/
|
|
||||||
u32 pool_add(pool_t *pool, void *elt);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pool_destroy() - destroy a pool.
|
|
||||||
* @pool: The pool address.
|
|
||||||
*
|
|
||||||
* Attention: All memory is freed, but no check is done whether all pool
|
|
||||||
* elements have been released. Referencing any pool object after this call
|
|
||||||
* will likely imply some memory corruption.
|
|
||||||
*/
|
|
||||||
void pool_destroy(pool_t *pool);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
|
|
||||||
/* adaptation of kernel's <asm-generic/rwonce.h>
|
|
||||||
* See https://www.kernel.org/doc/Documentation/memory-barriers.txt
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Prevent the compiler from merging or refetching reads or writes. The
|
|
||||||
* compiler is also forbidden from reordering successive instances of
|
|
||||||
* READ_ONCE and WRITE_ONCE, but only when the compiler is aware of some
|
|
||||||
* particular ordering. One way to make the compiler aware of ordering is to
|
|
||||||
* put the two invocations of READ_ONCE or WRITE_ONCE in different C
|
|
||||||
* statements.
|
|
||||||
*
|
|
||||||
* These two macros will also work on aggregate data types like structs or
|
|
||||||
* unions.
|
|
||||||
*
|
|
||||||
* Their two major use cases are: (1) Mediating communication between
|
|
||||||
* process-level code and irq/NMI handlers, all running on the same CPU,
|
|
||||||
* and (2) Ensuring that the compiler does not fold, spindle, or otherwise
|
|
||||||
* mutilate accesses that either do not require ordering or that interact
|
|
||||||
* with an explicit memory barrier or atomic instruction that provides the
|
|
||||||
* required ordering.
|
|
||||||
*/
|
|
||||||
#ifndef __BR_RWONCE_H
|
|
||||||
#define __BR_RWONCE_H
|
|
||||||
|
|
||||||
/************ originally in <include/linux/compiler_attributes.h> */
|
|
||||||
#if __has_attribute(__error__)
|
|
||||||
# define __compiletime_error(msg) __attribute__((__error__(msg)))
|
|
||||||
#else
|
|
||||||
# define __compiletime_error(msg)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/************ originally in <include/linux/compiler_types.h> */
|
|
||||||
/*
|
|
||||||
* __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving
|
|
||||||
* non-scalar types unchanged.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Prefer C11 _Generic for better compile-times and simpler code. Note: 'char'
|
|
||||||
* is not type-compatible with 'signed char', and we define a separate case.
|
|
||||||
*/
|
|
||||||
#define __scalar_type_to_expr_cases(type) \
|
|
||||||
unsigned type: (unsigned type)0, \
|
|
||||||
signed type: (signed type)0
|
|
||||||
|
|
||||||
#define __unqual_scalar_typeof(x) \
|
|
||||||
typeof(_Generic((x), \
|
|
||||||
char: (char)0, \
|
|
||||||
__scalar_type_to_expr_cases(char), \
|
|
||||||
__scalar_type_to_expr_cases(short), \
|
|
||||||
__scalar_type_to_expr_cases(int), \
|
|
||||||
__scalar_type_to_expr_cases(long), \
|
|
||||||
__scalar_type_to_expr_cases(long long), \
|
|
||||||
default: (x)))
|
|
||||||
|
|
||||||
/* Is this type a native word size -- useful for atomic operations */
|
|
||||||
#define __native_word(t) \
|
|
||||||
(sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || \
|
|
||||||
sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))
|
|
||||||
|
|
||||||
#ifdef __OPTIMIZE__
|
|
||||||
# define __compiletime_assert(condition, msg, prefix, suffix) \
|
|
||||||
do { \
|
|
||||||
extern void prefix ## suffix(void) __compiletime_error(msg); \
|
|
||||||
if (!(condition)) \
|
|
||||||
prefix ## suffix(); \
|
|
||||||
} while (0)
|
|
||||||
#else
|
|
||||||
# define __compiletime_assert(condition, msg, prefix, suffix) do { } while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define _compiletime_assert(condition, msg, prefix, suffix) \
|
|
||||||
__compiletime_assert(condition, msg, prefix, suffix)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* compiletime_assert - break build and emit msg if condition is false
|
|
||||||
* @condition: a compile-time constant condition to check
|
|
||||||
* @msg: a message to emit if condition is false
|
|
||||||
*
|
|
||||||
* In tradition of POSIX assert, this macro will break the build if the
|
|
||||||
* supplied condition is *false*, emitting the supplied error message if the
|
|
||||||
* compiler has support to do so.
|
|
||||||
*/
|
|
||||||
#define compiletime_assert(condition, msg) \
|
|
||||||
_compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
|
|
||||||
|
|
||||||
#define compiletime_assert_atomic_type(t) \
|
|
||||||
compiletime_assert(__native_word(t), \
|
|
||||||
"Need native word sized stores/loads for atomicity.")
|
|
||||||
|
|
||||||
/************ originally in <asm-generic/rwonce.h> */
|
|
||||||
/*
|
|
||||||
* Yes, this permits 64-bit accesses on 32-bit architectures. These will
|
|
||||||
* actually be atomic in some cases (namely Armv7 + LPAE), but for others we
|
|
||||||
* rely on the access being split into 2x32-bit accesses for a 32-bit quantity
|
|
||||||
* (e.g. a virtual address) and a strong prevailing wind.
|
|
||||||
*/
|
|
||||||
#define compiletime_assert_rwonce_type(t) \
|
|
||||||
compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
|
|
||||||
"Unsupported access size for {READ,WRITE}_ONCE().")
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use __READ_ONCE() instead of READ_ONCE() if you do not require any
|
|
||||||
* atomicity. Note that this may result in tears!
|
|
||||||
*/
|
|
||||||
#ifndef __READ_ONCE
|
|
||||||
#define __READ_ONCE(x) (*(const volatile __unqual_scalar_typeof(x) *)&(x))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define READ_ONCE(x) \
|
|
||||||
({ \
|
|
||||||
compiletime_assert_rwonce_type(x); \
|
|
||||||
__READ_ONCE(x); \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define __WRITE_ONCE(x, val) \
|
|
||||||
do { \
|
|
||||||
*(volatile typeof(x) *)&(x) = (val); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define WRITE_ONCE(x, val) \
|
|
||||||
do { \
|
|
||||||
compiletime_assert_rwonce_type(x); \
|
|
||||||
__WRITE_ONCE(x, val); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#endif /* __BR_RWONCE_H */
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
/* debug.c - debug/log management
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021-2022 Bruno Raoult ("br")
|
|
||||||
* Licensed under the GNU General Public License v3.0 or later.
|
|
||||||
* Some rights reserved. See COPYING.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
|
||||||
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#ifndef DEBUG_DEBUG
|
|
||||||
#define DEBUG_DEBUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
#define NANOSEC 1000000000 /* nano sec in sec */
|
|
||||||
#define MILLISEC 1000000 /* milli sec in sec */
|
|
||||||
|
|
||||||
static s64 timer_start; /* in nanosecond */
|
|
||||||
static u32 debug_level=0;
|
|
||||||
|
|
||||||
void debug_level_set(u32 level)
|
|
||||||
{
|
|
||||||
debug_level = level;
|
|
||||||
|
|
||||||
log(1, "debug level set to %u\n", level);
|
|
||||||
}
|
|
||||||
|
|
||||||
void debug_init(u32 level)
|
|
||||||
{
|
|
||||||
struct timespec timer;
|
|
||||||
|
|
||||||
debug_level_set(level);
|
|
||||||
if (!clock_gettime(CLOCK_MONOTONIC, &timer)) {
|
|
||||||
timer_start = timer.tv_sec * NANOSEC + timer.tv_nsec;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
timer_start = 0;
|
|
||||||
}
|
|
||||||
log(0, "timer started.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static s64 timer_elapsed()
|
|
||||||
{
|
|
||||||
struct timespec timer;
|
|
||||||
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &timer);
|
|
||||||
return (timer.tv_sec * NANOSEC + timer.tv_nsec) - timer_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* void debug - log function
|
|
||||||
* @timestamp : boolean
|
|
||||||
* @indent : indent level (2 spaces each)
|
|
||||||
* @src : source file/func name (or NULL)
|
|
||||||
* @line : line number
|
|
||||||
*/
|
|
||||||
void debug(u32 level, bool timestamp, u32 indent, const char *src,
|
|
||||||
u32 line, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
if (level > debug_level)
|
|
||||||
return;
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
if (indent)
|
|
||||||
printf("%*s", 2*(indent-1), "");
|
|
||||||
|
|
||||||
if (timestamp) {
|
|
||||||
s64 diff = timer_elapsed();
|
|
||||||
printf("%ld.%03ld ", diff/NANOSEC, (diff/1000000)%1000);
|
|
||||||
printf("%010ld ", diff);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (src) {
|
|
||||||
if (line)
|
|
||||||
printf("[%s:%u] ", src, line);
|
|
||||||
else
|
|
||||||
printf("[%s] ", src);
|
|
||||||
}
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vprintf(fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BIN_debug
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
int foo=1;
|
|
||||||
debug_init(5);
|
|
||||||
|
|
||||||
log(0, "log0=%d\n", foo++);
|
|
||||||
log(1, "log1=%d\n", foo++);
|
|
||||||
log(2, "log2=%d\n", foo++);
|
|
||||||
log_i(2, "log_i 2=%d\n", foo++);
|
|
||||||
log_i(5, "log_i 5=%d\n", foo++);
|
|
||||||
log_i(6, "log_i 6=%d\n", foo++);
|
|
||||||
log_it(4, "log_it 4=%d\n", foo++);
|
|
||||||
log_f(1, "log_f 5=%d\n", foo++);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
/*
|
|
||||||
* adapted from Linux kernel lib/plist.c
|
|
||||||
*
|
|
||||||
* Descending-priority-sorted double-linked list
|
|
||||||
*
|
|
||||||
* (C) 2002-2003 Intel Corp
|
|
||||||
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>.
|
|
||||||
*
|
|
||||||
* 2001-2005 (c) MontaVista Software, Inc.
|
|
||||||
* Daniel Walker <dwalker@mvista.com>
|
|
||||||
*
|
|
||||||
* (C) 2005 Thomas Gleixner <tglx@linutronix.de>
|
|
||||||
*
|
|
||||||
* Simplifications of the original code by
|
|
||||||
* Oleg Nesterov <oleg@tv-sign.ru>
|
|
||||||
*
|
|
||||||
* Based on simple lists (include/linux/list.h).
|
|
||||||
*
|
|
||||||
* This file contains the add / del functions which are considered to
|
|
||||||
* be too large to inline. See include/linux/plist.h for further
|
|
||||||
* information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "plist.h"
|
|
||||||
#include "bug.h"
|
|
||||||
|
|
||||||
#ifdef DEBUG_PLIST
|
|
||||||
|
|
||||||
static struct plist_head test_head;
|
|
||||||
|
|
||||||
static void plist_check_prev_next(struct list_head *t, struct list_head *p,
|
|
||||||
struct list_head *n)
|
|
||||||
{
|
|
||||||
WARN(n->prev != p || p->next != n,
|
|
||||||
"top: %p, n: %p, p: %p\n"
|
|
||||||
"prev: %p, n: %p, p: %p\n"
|
|
||||||
"next: %p, n: %p, p: %p\n",
|
|
||||||
t, t->next, t->prev,
|
|
||||||
p, p->next, p->prev,
|
|
||||||
n, n->next, n->prev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void plist_check_list(struct list_head *top)
|
|
||||||
{
|
|
||||||
struct list_head *prev = top, *next = top->next;
|
|
||||||
|
|
||||||
plist_check_prev_next(top, prev, next);
|
|
||||||
while (next != top) {
|
|
||||||
prev = next;
|
|
||||||
next = prev->next;
|
|
||||||
plist_check_prev_next(top, prev, next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void plist_check_head(struct plist_head *head)
|
|
||||||
{
|
|
||||||
if (!plist_head_empty(head))
|
|
||||||
plist_check_list(&plist_first(head)->prio_list);
|
|
||||||
plist_check_list(&head->node_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
# define plist_check_head(h) do { } while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_add - add @node to @head
|
|
||||||
*
|
|
||||||
* @node: &struct plist_node pointer
|
|
||||||
* @head: &struct plist_head pointer
|
|
||||||
*/
|
|
||||||
void plist_add(struct plist_node *node, struct plist_head *head)
|
|
||||||
{
|
|
||||||
struct plist_node *first, *iter, *prev = NULL;
|
|
||||||
struct list_head *node_next = &head->node_list;
|
|
||||||
|
|
||||||
plist_check_head(head);
|
|
||||||
WARN_ON(!plist_node_empty(node));
|
|
||||||
WARN_ON(!list_empty(&node->prio_list));
|
|
||||||
|
|
||||||
if (plist_head_empty(head))
|
|
||||||
goto ins_node;
|
|
||||||
|
|
||||||
first = iter = plist_first(head);
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (node->prio < iter->prio) {
|
|
||||||
node_next = &iter->node_list;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
prev = iter;
|
|
||||||
iter = list_entry(iter->prio_list.next,
|
|
||||||
struct plist_node, prio_list);
|
|
||||||
} while (iter != first);
|
|
||||||
|
|
||||||
if (!prev || prev->prio != node->prio)
|
|
||||||
list_add_tail(&node->prio_list, &iter->prio_list);
|
|
||||||
ins_node:
|
|
||||||
list_add_tail(&node->node_list, node_next);
|
|
||||||
|
|
||||||
plist_check_head(head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_del - Remove a @node from plist.
|
|
||||||
*
|
|
||||||
* @node: &struct plist_node pointer - entry to be removed
|
|
||||||
* @head: &struct plist_head pointer - list head
|
|
||||||
*/
|
|
||||||
void plist_del(struct plist_node *node, struct plist_head *head)
|
|
||||||
{
|
|
||||||
plist_check_head(head);
|
|
||||||
|
|
||||||
if (!list_empty(&node->prio_list)) {
|
|
||||||
if (node->node_list.next != &head->node_list) {
|
|
||||||
struct plist_node *next;
|
|
||||||
|
|
||||||
next = list_entry(node->node_list.next,
|
|
||||||
struct plist_node, node_list);
|
|
||||||
|
|
||||||
/* add the next plist_node into prio_list */
|
|
||||||
if (list_empty(&next->prio_list))
|
|
||||||
list_add(&next->prio_list, &node->prio_list);
|
|
||||||
}
|
|
||||||
list_del_init(&node->prio_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
list_del_init(&node->node_list);
|
|
||||||
|
|
||||||
plist_check_head(head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plist_requeue - Requeue @node at end of same-prio entries.
|
|
||||||
*
|
|
||||||
* This is essentially an optimized plist_del() followed by
|
|
||||||
* plist_add(). It moves an entry already in the plist to
|
|
||||||
* after any other same-priority entries.
|
|
||||||
*
|
|
||||||
* @node: &struct plist_node pointer - entry to be moved
|
|
||||||
* @head: &struct plist_head pointer - list head
|
|
||||||
*/
|
|
||||||
void plist_requeue(struct plist_node *node, struct plist_head *head)
|
|
||||||
{
|
|
||||||
struct plist_node *iter;
|
|
||||||
struct list_head *node_next = &head->node_list;
|
|
||||||
|
|
||||||
plist_check_head(head);
|
|
||||||
BUG_ON(plist_head_empty(head));
|
|
||||||
BUG_ON(plist_node_empty(node));
|
|
||||||
|
|
||||||
if (node == plist_last(head))
|
|
||||||
return;
|
|
||||||
|
|
||||||
iter = plist_next(node);
|
|
||||||
|
|
||||||
if (node->prio != iter->prio)
|
|
||||||
return;
|
|
||||||
|
|
||||||
plist_del(node, head);
|
|
||||||
|
|
||||||
plist_for_each_continue(iter, head) {
|
|
||||||
if (node->prio != iter->prio) {
|
|
||||||
node_next = &iter->node_list;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list_add_tail(&node->node_list, node_next);
|
|
||||||
|
|
||||||
plist_check_head(head);
|
|
||||||
}
|
|
||||||
@@ -1,222 +0,0 @@
|
|||||||
/* pool.c - A simple pool manager.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021-2022 Bruno Raoult ("br")
|
|
||||||
* Licensed under the GNU General Public License v3.0 or later.
|
|
||||||
* Some rights reserved. See COPYING.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
|
||||||
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "list.h"
|
|
||||||
#include "pool.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "bits.h"
|
|
||||||
|
|
||||||
void pool_stats(pool_t *pool)
|
|
||||||
{
|
|
||||||
if (pool) {
|
|
||||||
block_t *block;
|
|
||||||
|
|
||||||
log_f(1, "[%s] pool [%p]: blocks:%u avail:%u alloc:%u grow:%u eltsize:%lu\n",
|
|
||||||
pool->name, (void *)pool, pool->nblocks, pool->available, pool->allocated,
|
|
||||||
pool->growsize, pool->eltsize);
|
|
||||||
log(5, "\tblocks: ");
|
|
||||||
list_for_each_entry(block, &pool->list_blocks, list_blocks) {
|
|
||||||
log(5, "%p ", block);
|
|
||||||
}
|
|
||||||
log(5, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pool_t *pool_create(const char *name, u32 growsize, size_t eltsize)
|
|
||||||
{
|
|
||||||
pool_t *pool;
|
|
||||||
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(1, "name=[%s] growsize=%u eltsize=%lu\n",
|
|
||||||
name, growsize, eltsize);
|
|
||||||
# endif
|
|
||||||
/* we need at least sizeof(struct list_head) space in pool elements
|
|
||||||
*/
|
|
||||||
if (eltsize < sizeof (struct list_head)) {
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(1, "[%s]: structure size too small (%lu < %lu), adjusting to %lu.\n",
|
|
||||||
name, eltsize, sizeof(struct list_head), sizeof(struct list_head));
|
|
||||||
# endif
|
|
||||||
eltsize = sizeof(struct list_head);
|
|
||||||
}
|
|
||||||
if ((pool = malloc(sizeof (*pool)))) {
|
|
||||||
strncpy(pool->name, name, POOL_NAME_LENGTH - 1);
|
|
||||||
pool->name[POOL_NAME_LENGTH - 1] = 0;
|
|
||||||
pool->growsize = growsize;
|
|
||||||
pool->eltsize = eltsize;
|
|
||||||
pool->available = 0;
|
|
||||||
pool->allocated = 0;
|
|
||||||
pool->nblocks = 0;
|
|
||||||
INIT_LIST_HEAD(&pool->list_available);
|
|
||||||
INIT_LIST_HEAD(&pool->list_blocks);
|
|
||||||
} else {
|
|
||||||
errno = ENOMEM;
|
|
||||||
}
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 _pool_add(pool_t *pool, struct list_head *elt)
|
|
||||||
{
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(6, "pool=%p &head=%p elt=%p off1=%lu off2=%lu\n",
|
|
||||||
(void *)pool,
|
|
||||||
(void *)&pool->list_available,
|
|
||||||
(void *)elt,
|
|
||||||
(void *)&pool->list_available-(void *)pool,
|
|
||||||
offsetof(pool_t, list_available));
|
|
||||||
# endif
|
|
||||||
|
|
||||||
list_add(elt, &pool->list_available);
|
|
||||||
return ++pool->available;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 pool_add(pool_t *pool, void *elt)
|
|
||||||
{
|
|
||||||
return _pool_add(pool, elt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct list_head *_pool_get(pool_t *pool)
|
|
||||||
{
|
|
||||||
struct list_head *res = pool->list_available.next;
|
|
||||||
pool->available--;
|
|
||||||
list_del(res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *pool_get(pool_t *pool)
|
|
||||||
{
|
|
||||||
if (!pool)
|
|
||||||
return NULL;
|
|
||||||
if (!pool->available) {
|
|
||||||
block_t *block = malloc(sizeof(block_t) + pool->eltsize * pool->growsize);
|
|
||||||
if (!block) {
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(1, "[%s]: failed block allocation\n", pool->name);
|
|
||||||
# endif
|
|
||||||
errno = ENOMEM;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* maintain list of allocated blocks
|
|
||||||
*/
|
|
||||||
list_add(&block->list_blocks, &pool->list_blocks);
|
|
||||||
pool->nblocks++;
|
|
||||||
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(1, "[%s]: growing pool from %u to %u elements. block=%p nblocks=%u\n",
|
|
||||||
pool->name,
|
|
||||||
pool->allocated,
|
|
||||||
pool->allocated + pool->growsize,
|
|
||||||
block,
|
|
||||||
pool->nblocks);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
pool->allocated += pool->growsize;
|
|
||||||
for (u32 i = 0; i < pool->growsize; ++i) {
|
|
||||||
void *cur = block->data + i * pool->eltsize;
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(7, "alloc=%p cur=%p\n", block, cur);
|
|
||||||
# endif
|
|
||||||
_pool_add(pool, (struct list_head *)cur);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* this is the effective address of the object (and also the
|
|
||||||
* pool list_head address)
|
|
||||||
*/
|
|
||||||
return _pool_get(pool);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pool_destroy(pool_t *pool)
|
|
||||||
{
|
|
||||||
block_t *block, *tmp;
|
|
||||||
if (!pool)
|
|
||||||
return;
|
|
||||||
/* release memory blocks */
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(1, "[%s]: releasing %d blocks and main structure\n", pool->name, pool->nblocks);
|
|
||||||
log(5, "blocks:");
|
|
||||||
# endif
|
|
||||||
list_for_each_entry_safe(block, tmp, &pool->list_blocks, list_blocks) {
|
|
||||||
list_del(&block->list_blocks);
|
|
||||||
free(block);
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log(5, " %p", block);
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log(5, "\n");
|
|
||||||
# endif
|
|
||||||
free(pool);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BIN_pool
|
|
||||||
struct d {
|
|
||||||
u16 data1;
|
|
||||||
char c;
|
|
||||||
struct list_head list;
|
|
||||||
};
|
|
||||||
|
|
||||||
static LIST_HEAD (head);
|
|
||||||
|
|
||||||
int main(int ac, char**av)
|
|
||||||
{
|
|
||||||
pool_t *pool;
|
|
||||||
int total;
|
|
||||||
int action=0;
|
|
||||||
u16 icur=0;
|
|
||||||
char ccur='z';
|
|
||||||
struct d *elt;
|
|
||||||
|
|
||||||
debug_init(3);
|
|
||||||
log_f(1, "%s: sizeof(d)=%lu sizeof(*d)=%lu off=%lu\n", *av, sizeof(elt),
|
|
||||||
sizeof(*elt), offsetof(struct d, list));
|
|
||||||
|
|
||||||
if ((pool = pool_create("dummy", 3, sizeof(*elt)))) {
|
|
||||||
pool_stats(pool);
|
|
||||||
for (int cur=1; cur<ac; ++cur) {
|
|
||||||
total = atoi(av[cur]);
|
|
||||||
if (action == 0) { /* add elt to list */
|
|
||||||
log_f(2, "adding %d elements\n", total);
|
|
||||||
for (int i = 0; i < total; ++i) {
|
|
||||||
elt = pool_get(pool);
|
|
||||||
elt->data1 = icur++;
|
|
||||||
elt->c = ccur--;
|
|
||||||
list_add(&elt->list, &head);
|
|
||||||
}
|
|
||||||
pool_stats(pool);
|
|
||||||
action = 1;
|
|
||||||
} else { /* remove one elt from list */
|
|
||||||
log_f(2, "deleting %d elements\n", total);
|
|
||||||
for (int i = 0; i < total; ++i) {
|
|
||||||
if (!list_empty(&head)) {
|
|
||||||
elt = list_last_entry(&head, struct d, list);
|
|
||||||
printf("elt=[%d, %c]\n", elt->data1, elt->c);
|
|
||||||
list_del(&elt->list);
|
|
||||||
pool_add(pool, elt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pool_stats(pool);
|
|
||||||
action = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pool_stats(pool);
|
|
||||||
pool_destroy(pool);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
# AOC Makefile - GNU make only.
|
|
||||||
#
|
|
||||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
|
||||||
# Licensed under the GNU General Public License v3.0 or later.
|
|
||||||
# Some rights reserved. See COPYING.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with this
|
|
||||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
SUBDIRS := $(shell echo day??)
|
|
||||||
|
|
||||||
CC = gcc
|
|
||||||
|
|
||||||
#LIBS = -lreadline -lncurses
|
|
||||||
CFLAGS += -std=gnu11
|
|
||||||
|
|
||||||
CFLAGS += -O2
|
|
||||||
CFLAGS += -g
|
|
||||||
#CFLAGS += -pg
|
|
||||||
CFLAGS += -Wall
|
|
||||||
CFLAGS += -Wextra
|
|
||||||
CFLAGS += -march=native
|
|
||||||
|
|
||||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
|
||||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
|
||||||
|
|
||||||
INCDIR := ./include
|
|
||||||
LIBSRCDIR := ./libsrc
|
|
||||||
LIBDIR := ./lib
|
|
||||||
LIB := libaoc_$(shell uname -m)
|
|
||||||
SLIB := $(LIBDIR)/$(LIB).a
|
|
||||||
DLIB := $(LIBDIR)/$(LIB).so
|
|
||||||
LIBSRC := $(wildcard $(LIBSRCDIR)/*.c)
|
|
||||||
LIBOBJ := $(patsubst %.c,%.o,$(LIBSRC))
|
|
||||||
LDFLAGS := -L$(LIBDIR)
|
|
||||||
LDLIB := -l$(LIB)
|
|
||||||
|
|
||||||
.PHONY: clean cleanlib cleanall all redo output lib $(SUBDIRS)
|
|
||||||
|
|
||||||
all: lib $(SUBDIRS)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@for dir in $(SUBDIRS) ; do \
|
|
||||||
$(MAKE) --no-print-directory -C $$dir clean ; \
|
|
||||||
done
|
|
||||||
|
|
||||||
cleanlib: clean
|
|
||||||
@$(RM) -f $(SLIB) $(DLIB) $(LIBOBJ)
|
|
||||||
|
|
||||||
cleanall: clean cleanlib
|
|
||||||
|
|
||||||
redo: cleanall all
|
|
||||||
|
|
||||||
$(SUBDIRS):
|
|
||||||
@echo "========================================="
|
|
||||||
@echo "================= $@ ================="
|
|
||||||
@echo "========================================="
|
|
||||||
@echo
|
|
||||||
@echo "+++++++++++++++++ part 1"
|
|
||||||
+@$(MAKE) --no-print-directory -C $@ 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 $@ $<
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
1-3 a: abcde
|
|
||||||
1-3 b: cdefg
|
|
||||||
2-9 c: ccccccccc
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# ex1.bash: Advent2020 game, day 10/game 1.
|
|
||||||
|
|
||||||
CMD=${0##*/}
|
|
||||||
shopt -s extglob
|
|
||||||
|
|
||||||
# quicksort implementation (ascending)
|
|
||||||
qsort() {
|
|
||||||
local pivot i smaller=() larger=()
|
|
||||||
qsort_ret=()
|
|
||||||
(($#==0)) && return 0
|
|
||||||
pivot=$1
|
|
||||||
shift
|
|
||||||
for i; do
|
|
||||||
if (( i < pivot )); then
|
|
||||||
smaller+=( "$i" )
|
|
||||||
else
|
|
||||||
larger+=( "$i" )
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
qsort "${smaller[@]}"
|
|
||||||
smaller=( "${qsort_ret[@]}" )
|
|
||||||
qsort "${larger[@]}"
|
|
||||||
larger=( "${qsort_ret[@]}" )
|
|
||||||
qsort_ret=( "${smaller[@]}" "$pivot" "${larger[@]}" )
|
|
||||||
}
|
|
||||||
|
|
||||||
declare -a numbers
|
|
||||||
readarray -t numbers
|
|
||||||
qsort "${numbers[@]}"
|
|
||||||
numbers=(0 ${qsort_ret[@]})
|
|
||||||
size=${#numbers[@]}
|
|
||||||
((last=${numbers[size-1]}+3))
|
|
||||||
numbers+=("$last")
|
|
||||||
((size++))
|
|
||||||
#echo S="$size" $last "[${numbers[@]}]"
|
|
||||||
|
|
||||||
# last
|
|
||||||
declare -a res=(0 0 0 0)
|
|
||||||
|
|
||||||
for ((i=1; i<size; ++i)); do
|
|
||||||
prev=${numbers[$i-1]}
|
|
||||||
cur=${numbers[$i]}
|
|
||||||
diff=$((cur-prev))
|
|
||||||
((res[diff]++))
|
|
||||||
done
|
|
||||||
res1="${res[1]}"
|
|
||||||
res3="${res[3]}"
|
|
||||||
|
|
||||||
printf "%s : diff1=%d diff2=%d res=%d\n" "$CMD" "$res1" "$res3" $((res1*res3))
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
# AOC daily Makefile - GNU make only.
|
|
||||||
#
|
|
||||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
|
||||||
# Licensed under the GNU General Public License v3.0 or later.
|
|
||||||
# Some rights reserved. See COPYING.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with this
|
|
||||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
#
|
|
||||||
|
|
||||||
INPUT := INPUT.txt
|
|
||||||
SHELL := /bin/bash
|
|
||||||
|
|
||||||
CC := gcc
|
|
||||||
BEAR := bear
|
|
||||||
CCLSFILE:= compile_commands.json
|
|
||||||
|
|
||||||
LIB := aoc_$(shell uname -m)
|
|
||||||
INCDIR := ../include
|
|
||||||
LIBDIR := ../lib
|
|
||||||
LDFLAGS := -L$(LIBDIR)
|
|
||||||
#LDLIB := -l$(LIB) -lm
|
|
||||||
LDLIB := -l$(LIB)
|
|
||||||
|
|
||||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
|
||||||
|
|
||||||
CFLAGS += -std=gnu11
|
|
||||||
CFLAGS += -O2
|
|
||||||
CFLAGS += -g
|
|
||||||
# for gprof
|
|
||||||
# CFLAGS += -pg
|
|
||||||
CFLAGS += -Wall
|
|
||||||
CFLAGS += -Wextra
|
|
||||||
CFLAGS += -march=native
|
|
||||||
# Next one may be useful for valgrind (some invalid instructions)
|
|
||||||
# CFLAGS += -mno-tbm
|
|
||||||
CFLAGS += -Wmissing-declarations
|
|
||||||
CFLAGS += -Wno-unused-result
|
|
||||||
|
|
||||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
|
||||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
|
||||||
|
|
||||||
VALGRIND := valgrind
|
|
||||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
|
||||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
|
||||||
|
|
||||||
|
|
||||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
|
||||||
export PATH := .:$(PATH)
|
|
||||||
|
|
||||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 ccls
|
|
||||||
|
|
||||||
all: README.org ccls ex1 ex2
|
|
||||||
|
|
||||||
memcheck: memcheck1 memcheck2
|
|
||||||
|
|
||||||
memcheck1: aoc-c
|
|
||||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
|
||||||
|
|
||||||
memcheck2: aoc-c
|
|
||||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
|
||||||
|
|
||||||
compile: aoc-c
|
|
||||||
|
|
||||||
cpp: aoc-c.i
|
|
||||||
|
|
||||||
assembly: aoc-c.s
|
|
||||||
|
|
||||||
ex1: aoc-c
|
|
||||||
@$(TIME) ex1.bash -p 1 < $(INPUT)
|
|
||||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
|
||||||
|
|
||||||
ex2: aoc-c
|
|
||||||
@$(TIME) ex2.bash -p 2 < $(INPUT)
|
|
||||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
|
||||||
|
|
||||||
ccls: $(CCLSFILE)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
|
|
||||||
|
|
||||||
.c:
|
|
||||||
@echo compiling $<
|
|
||||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
|
||||||
|
|
||||||
# generate pre-processed file (.i) and assembler (.s)
|
|
||||||
%.i: %.c
|
|
||||||
@echo generating $@
|
|
||||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
|
||||||
|
|
||||||
%.s: %.c
|
|
||||||
@echo generating $@
|
|
||||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
|
||||||
|
|
||||||
# generate README.org from README.html (must cleanup !)
|
|
||||||
%.org: %.html
|
|
||||||
@echo generating $@. Cleanup before commit !
|
|
||||||
@pandoc $< -o $@
|
|
||||||
|
|
||||||
# generate compile_commands.json
|
|
||||||
$(CCLSFILE): aoc-c.c Makefile
|
|
||||||
$(BEAR) -- make clean compile
|
|
||||||
|
|
||||||
bear: clean
|
|
||||||
@$(BEAR) -- make compile
|
|
||||||
@touch .ccls-root
|
|
||||||
@@ -1,200 +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:
|
|
||||||
|
|
||||||
#+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: **
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
/* 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);
|
|
||||||
}
|
|
||||||
1727
2020/day20/INPUT.txt
1727
2020/day20/INPUT.txt
File diff suppressed because it is too large
Load Diff
@@ -1,274 +0,0 @@
|
|||||||
--- Day 20: Jurassic Jigsaw ---
|
|
||||||
|
|
||||||
The high-speed train leaves the forest and quickly carries you south. You can even see a desert in the distance! Since you have some spare time, you might as well see if there was anything interesting in the image the Mythical Information Bureau satellite captured.
|
|
||||||
|
|
||||||
After decoding the satellite messages, you discover that the data actually contains many small images created by the satellite's camera array. The camera array consists of many cameras; rather than produce a single square image, they produce many smaller square image tiles that need to be reassembled back into a single image.
|
|
||||||
|
|
||||||
Each camera in the camera array returns a single monochrome image tile with a random unique ID number. The tiles (your puzzle input) arrived in a random order.
|
|
||||||
|
|
||||||
Worse yet, the camera array appears to be malfunctioning: each image tile has been rotated and flipped to a random orientation. Your first task is to reassemble the original image by orienting the tiles so they fit together.
|
|
||||||
|
|
||||||
To show how the tiles should be reassembled, each tile's image data includes a border that should line up exactly with its adjacent tiles. All tiles have this border, and the border lines up exactly when the tiles are both oriented correctly. Tiles at the edge of the image also have this border, but the outermost edges won't line up with any other tiles.
|
|
||||||
|
|
||||||
For example, suppose you have the following nine tiles:
|
|
||||||
|
|
||||||
Tile 2311:
|
|
||||||
..##.#..#.
|
|
||||||
##..#.....
|
|
||||||
#...##..#.
|
|
||||||
####.#...#
|
|
||||||
##.##.###.
|
|
||||||
##...#.###
|
|
||||||
.#.#.#..##
|
|
||||||
..#....#..
|
|
||||||
###...#.#.
|
|
||||||
..###..###
|
|
||||||
|
|
||||||
Tile 1951:
|
|
||||||
#.##...##.
|
|
||||||
#.####...#
|
|
||||||
.....#..##
|
|
||||||
#...######
|
|
||||||
.##.#....#
|
|
||||||
.###.#####
|
|
||||||
###.##.##.
|
|
||||||
.###....#.
|
|
||||||
..#.#..#.#
|
|
||||||
#...##.#..
|
|
||||||
|
|
||||||
Tile 1171:
|
|
||||||
####...##.
|
|
||||||
#..##.#..#
|
|
||||||
##.#..#.#.
|
|
||||||
.###.####.
|
|
||||||
..###.####
|
|
||||||
.##....##.
|
|
||||||
.#...####.
|
|
||||||
#.##.####.
|
|
||||||
####..#...
|
|
||||||
.....##...
|
|
||||||
|
|
||||||
Tile 1427:
|
|
||||||
###.##.#..
|
|
||||||
.#..#.##..
|
|
||||||
.#.##.#..#
|
|
||||||
#.#.#.##.#
|
|
||||||
....#...##
|
|
||||||
...##..##.
|
|
||||||
...#.#####
|
|
||||||
.#.####.#.
|
|
||||||
..#..###.#
|
|
||||||
..##.#..#.
|
|
||||||
|
|
||||||
Tile 1489:
|
|
||||||
##.#.#....
|
|
||||||
..##...#..
|
|
||||||
.##..##...
|
|
||||||
..#...#...
|
|
||||||
#####...#.
|
|
||||||
#..#.#.#.#
|
|
||||||
...#.#.#..
|
|
||||||
##.#...##.
|
|
||||||
..##.##.##
|
|
||||||
###.##.#..
|
|
||||||
|
|
||||||
Tile 2473:
|
|
||||||
#....####.
|
|
||||||
#..#.##...
|
|
||||||
#.##..#...
|
|
||||||
######.#.#
|
|
||||||
.#...#.#.#
|
|
||||||
.#########
|
|
||||||
.###.#..#.
|
|
||||||
########.#
|
|
||||||
##...##.#.
|
|
||||||
..###.#.#.
|
|
||||||
|
|
||||||
Tile 2971:
|
|
||||||
..#.#....#
|
|
||||||
#...###...
|
|
||||||
#.#.###...
|
|
||||||
##.##..#..
|
|
||||||
.#####..##
|
|
||||||
.#..####.#
|
|
||||||
#..#.#..#.
|
|
||||||
..####.###
|
|
||||||
..#.#.###.
|
|
||||||
...#.#.#.#
|
|
||||||
|
|
||||||
Tile 2729:
|
|
||||||
...#.#.#.#
|
|
||||||
####.#....
|
|
||||||
..#.#.....
|
|
||||||
....#..#.#
|
|
||||||
.##..##.#.
|
|
||||||
.#.####...
|
|
||||||
####.#.#..
|
|
||||||
##.####...
|
|
||||||
##..#.##..
|
|
||||||
#.##...##.
|
|
||||||
|
|
||||||
Tile 3079:
|
|
||||||
#.#.#####.
|
|
||||||
.#..######
|
|
||||||
..#.......
|
|
||||||
######....
|
|
||||||
####.#..#.
|
|
||||||
.#...#.##.
|
|
||||||
#.#####.##
|
|
||||||
..#.###...
|
|
||||||
..#.......
|
|
||||||
..#.###...
|
|
||||||
|
|
||||||
By rotating, flipping, and rearranging them, you can find a square arrangement that causes all adjacent borders to line up:
|
|
||||||
|
|
||||||
#...##.#.. ..###..### #.#.#####.
|
|
||||||
..#.#..#.# ###...#.#. .#..######
|
|
||||||
.###....#. ..#....#.. ..#.......
|
|
||||||
###.##.##. .#.#.#..## ######....
|
|
||||||
.###.##### ##...#.### ####.#..#.
|
|
||||||
.##.#....# ##.##.###. .#...#.##.
|
|
||||||
#...###### ####.#...# #.#####.##
|
|
||||||
.....#..## #...##..#. ..#.###...
|
|
||||||
#.####...# ##..#..... ..#.......
|
|
||||||
#.##...##. ..##.#..#. ..#.###...
|
|
||||||
|
|
||||||
#.##...##. ..##.#..#. ..#.###...
|
|
||||||
##..#.##.. ..#..###.# ##.##....#
|
|
||||||
##.####... .#.####.#. ..#.###..#
|
|
||||||
####.#.#.. ...#.##### ###.#..###
|
|
||||||
.#.####... ...##..##. .######.##
|
|
||||||
.##..##.#. ....#...## #.#.#.#...
|
|
||||||
....#..#.# #.#.#.##.# #.###.###.
|
|
||||||
..#.#..... .#.##.#..# #.###.##..
|
|
||||||
####.#.... .#..#.##.. .######...
|
|
||||||
...#.#.#.# ###.##.#.. .##...####
|
|
||||||
|
|
||||||
...#.#.#.# ###.##.#.. .##...####
|
|
||||||
..#.#.###. ..##.##.## #..#.##..#
|
|
||||||
..####.### ##.#...##. .#.#..#.##
|
|
||||||
#..#.#..#. ...#.#.#.. .####.###.
|
|
||||||
.#..####.# #..#.#.#.# ####.###..
|
|
||||||
.#####..## #####...#. .##....##.
|
|
||||||
##.##..#.. ..#...#... .####...#.
|
|
||||||
#.#.###... .##..##... .####.##.#
|
|
||||||
#...###... ..##...#.. ...#..####
|
|
||||||
..#.#....# ##.#.#.... ...##.....
|
|
||||||
|
|
||||||
For reference, the IDs of the above tiles are:
|
|
||||||
|
|
||||||
1951 2311 3079
|
|
||||||
2729 1427 2473
|
|
||||||
2971 1489 1171
|
|
||||||
|
|
||||||
To check that you've assembled the image correctly, multiply the IDs of the four corner tiles together. If you do this with the assembled tiles from the example above, you get 1951 * 3079 * 2971 * 1171 = 20899048083289.
|
|
||||||
|
|
||||||
Assemble the tiles into an image. What do you get if you multiply together the IDs of the four corner tiles?
|
|
||||||
|
|
||||||
Your puzzle answer was 5966506063747.
|
|
||||||
|
|
||||||
The first half of this puzzle is complete! It provides one gold star: *
|
|
||||||
--- Part Two ---
|
|
||||||
|
|
||||||
Now, you're ready to check the image for sea monsters.
|
|
||||||
|
|
||||||
The borders of each tile are not part of the actual image; start by removing them.
|
|
||||||
|
|
||||||
In the example above, the tiles become:
|
|
||||||
|
|
||||||
.#.#..#. ##...#.# #..#####
|
|
||||||
###....# .#....#. .#......
|
|
||||||
##.##.## #.#.#..# #####...
|
|
||||||
###.#### #...#.## ###.#..#
|
|
||||||
##.#.... #.##.### #...#.##
|
|
||||||
...##### ###.#... .#####.#
|
|
||||||
....#..# ...##..# .#.###..
|
|
||||||
.####... #..#.... .#......
|
|
||||||
|
|
||||||
#..#.##. .#..###. #.##....
|
|
||||||
#.####.. #.####.# .#.###..
|
|
||||||
###.#.#. ..#.#### ##.#..##
|
|
||||||
#.####.. ..##..## ######.#
|
|
||||||
##..##.# ...#...# .#.#.#..
|
|
||||||
...#..#. .#.#.##. .###.###
|
|
||||||
.#.#.... #.##.#.. .###.##.
|
|
||||||
###.#... #..#.##. ######..
|
|
||||||
|
|
||||||
.#.#.### .##.##.# ..#.##..
|
|
||||||
.####.## #.#...## #.#..#.#
|
|
||||||
..#.#..# ..#.#.#. ####.###
|
|
||||||
#..####. ..#.#.#. ###.###.
|
|
||||||
#####..# ####...# ##....##
|
|
||||||
#.##..#. .#...#.. ####...#
|
|
||||||
.#.###.. ##..##.. ####.##.
|
|
||||||
...###.. .##...#. ..#..###
|
|
||||||
|
|
||||||
Remove the gaps to form the actual image:
|
|
||||||
|
|
||||||
.#.#..#.##...#.##..#####
|
|
||||||
###....#.#....#..#......
|
|
||||||
##.##.###.#.#..######...
|
|
||||||
###.#####...#.#####.#..#
|
|
||||||
##.#....#.##.####...#.##
|
|
||||||
...########.#....#####.#
|
|
||||||
....#..#...##..#.#.###..
|
|
||||||
.####...#..#.....#......
|
|
||||||
#..#.##..#..###.#.##....
|
|
||||||
#.####..#.####.#.#.###..
|
|
||||||
###.#.#...#.######.#..##
|
|
||||||
#.####....##..########.#
|
|
||||||
##..##.#...#...#.#.#.#..
|
|
||||||
...#..#..#.#.##..###.###
|
|
||||||
.#.#....#.##.#...###.##.
|
|
||||||
###.#...#..#.##.######..
|
|
||||||
.#.#.###.##.##.#..#.##..
|
|
||||||
.####.###.#...###.#..#.#
|
|
||||||
..#.#..#..#.#.#.####.###
|
|
||||||
#..####...#.#.#.###.###.
|
|
||||||
#####..#####...###....##
|
|
||||||
#.##..#..#...#..####...#
|
|
||||||
.#.###..##..##..####.##.
|
|
||||||
...###...##...#...#..###
|
|
||||||
|
|
||||||
Now, you're ready to search for sea monsters! Because your image is monochrome, a sea monster will look like this:
|
|
||||||
|
|
||||||
#
|
|
||||||
# ## ## ###
|
|
||||||
# # # # # #
|
|
||||||
|
|
||||||
When looking for this pattern in the image, the spaces can be anything; only the # need to match. Also, you might need to rotate or flip your image before it's oriented correctly to find sea monsters. In the above image, after flipping and rotating it to the appropriate orientation, there are two sea monsters (marked with O):
|
|
||||||
|
|
||||||
.####...#####..#...###..
|
|
||||||
#####..#..#.#.####..#.#.
|
|
||||||
.#.#...#.###...#.##.O#..
|
|
||||||
#.O.##.OO#.#.OO.##.OOO##
|
|
||||||
..#O.#O#.O##O..O.#O##.##
|
|
||||||
...#.#..##.##...#..#..##
|
|
||||||
#.##.#..#.#..#..##.#.#..
|
|
||||||
.###.##.....#...###.#...
|
|
||||||
#.####.#.#....##.#..#.#.
|
|
||||||
##...#..#....#..#...####
|
|
||||||
..#.##...###..#.#####..#
|
|
||||||
....#.##.#.#####....#...
|
|
||||||
..##.##.###.....#.##..#.
|
|
||||||
#...#...###..####....##.
|
|
||||||
.#.##...#.##.#.#.###...#
|
|
||||||
#.###.#..####...##..#...
|
|
||||||
#.###...#.##...#.##O###.
|
|
||||||
.O##.#OO.###OO##..OOO##.
|
|
||||||
..O#.O..O..O.#O##O##.###
|
|
||||||
#.#..##.########..#..##.
|
|
||||||
#.#####..#.#...##..#....
|
|
||||||
#....##..#.#########..##
|
|
||||||
#...#.....#..##...###.##
|
|
||||||
#..###....##.#...##.##.#
|
|
||||||
|
|
||||||
Determine how rough the waters are in the sea monsters' habitat by counting the number of # that are not part of a sea monster. In the above example, the habitat's water roughness is 273.
|
|
||||||
|
|
||||||
How many # are not part of a sea monster?
|
|
||||||
|
|
||||||
Answer:
|
|
||||||
|
|
||||||
Although it hasn't changed, you can still get your puzzle input.
|
|
||||||
|
|
||||||
You can also [Share] this puzzle.
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
Tile 2311:
|
|
||||||
..##.#..#.
|
|
||||||
##..#.....
|
|
||||||
#...##..#.
|
|
||||||
####.#...#
|
|
||||||
##.##.###.
|
|
||||||
##...#.###
|
|
||||||
.#.#.#..##
|
|
||||||
..#....#..
|
|
||||||
###...#.#.
|
|
||||||
..###..###
|
|
||||||
|
|
||||||
Tile 1951:
|
|
||||||
#.##...##.
|
|
||||||
#.####...#
|
|
||||||
.....#..##
|
|
||||||
#...######
|
|
||||||
.##.#....#
|
|
||||||
.###.#####
|
|
||||||
###.##.##.
|
|
||||||
.###....#.
|
|
||||||
..#.#..#.#
|
|
||||||
#...##.#..
|
|
||||||
|
|
||||||
Tile 1171:
|
|
||||||
####...##.
|
|
||||||
#..##.#..#
|
|
||||||
##.#..#.#.
|
|
||||||
.###.####.
|
|
||||||
..###.####
|
|
||||||
.##....##.
|
|
||||||
.#...####.
|
|
||||||
#.##.####.
|
|
||||||
####..#...
|
|
||||||
.....##...
|
|
||||||
|
|
||||||
Tile 1427:
|
|
||||||
###.##.#..
|
|
||||||
.#..#.##..
|
|
||||||
.#.##.#..#
|
|
||||||
#.#.#.##.#
|
|
||||||
....#...##
|
|
||||||
...##..##.
|
|
||||||
...#.#####
|
|
||||||
.#.####.#.
|
|
||||||
..#..###.#
|
|
||||||
..##.#..#.
|
|
||||||
|
|
||||||
Tile 1489:
|
|
||||||
##.#.#....
|
|
||||||
..##...#..
|
|
||||||
.##..##...
|
|
||||||
..#...#...
|
|
||||||
#####...#.
|
|
||||||
#..#.#.#.#
|
|
||||||
...#.#.#..
|
|
||||||
##.#...##.
|
|
||||||
..##.##.##
|
|
||||||
###.##.#..
|
|
||||||
|
|
||||||
Tile 2473:
|
|
||||||
#....####.
|
|
||||||
#..#.##...
|
|
||||||
#.##..#...
|
|
||||||
######.#.#
|
|
||||||
.#...#.#.#
|
|
||||||
.#########
|
|
||||||
.###.#..#.
|
|
||||||
########.#
|
|
||||||
##...##.#.
|
|
||||||
..###.#.#.
|
|
||||||
|
|
||||||
Tile 2971:
|
|
||||||
..#.#....#
|
|
||||||
#...###...
|
|
||||||
#.#.###...
|
|
||||||
##.##..#..
|
|
||||||
.#####..##
|
|
||||||
.#..####.#
|
|
||||||
#..#.#..#.
|
|
||||||
..####.###
|
|
||||||
..#.#.###.
|
|
||||||
...#.#.#.#
|
|
||||||
|
|
||||||
Tile 2729:
|
|
||||||
...#.#.#.#
|
|
||||||
####.#....
|
|
||||||
..#.#.....
|
|
||||||
....#..#.#
|
|
||||||
.##..##.#.
|
|
||||||
.#.####...
|
|
||||||
####.#.#..
|
|
||||||
##.####...
|
|
||||||
##..#.##..
|
|
||||||
#.##...##.
|
|
||||||
|
|
||||||
Tile 3079:
|
|
||||||
#.#.#####.
|
|
||||||
.#..######
|
|
||||||
..#.......
|
|
||||||
######....
|
|
||||||
####.#..#.
|
|
||||||
.#...#.##.
|
|
||||||
#.#####.##
|
|
||||||
..#.###...
|
|
||||||
..#.......
|
|
||||||
..#.###...
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# ex1.bash: Advent2020 game, day 20/game 1.
|
|
||||||
|
|
||||||
CMD=${0##*/}
|
|
||||||
set -o noglob
|
|
||||||
shopt -s extglob
|
|
||||||
|
|
||||||
declare -a strings T R B L RT RR RB RL nums
|
|
||||||
declare -i res=1 count=-1
|
|
||||||
|
|
||||||
while read -r line; do
|
|
||||||
case ${line:0:1} in
|
|
||||||
T*)
|
|
||||||
((count++))
|
|
||||||
num=${line##* }
|
|
||||||
num=${num%%:}
|
|
||||||
nums+=("$num")
|
|
||||||
;;
|
|
||||||
\#|.)
|
|
||||||
strings[$count]="${strings[$count]} $line"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
((count--))
|
|
||||||
|
|
||||||
for key in "${!nums[@]}"; do
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
str=(${strings[$key]})
|
|
||||||
top="${str[0]}"
|
|
||||||
bottom="${str[9]}"
|
|
||||||
T+=("$top")
|
|
||||||
B+=("$bottom")
|
|
||||||
# find out right and bottom
|
|
||||||
unset left right
|
|
||||||
for ((i=0; i<10; ++i)); do
|
|
||||||
left+=${str[$i]:0:1}
|
|
||||||
right+=${str[$i]: -1:1}
|
|
||||||
done
|
|
||||||
R+=("$right")
|
|
||||||
L+=("$left")
|
|
||||||
unset fliptop flipbottom flipleft flipright
|
|
||||||
for ((i=9; i>=0; --i)); do
|
|
||||||
fliptop+=${top:$i:1}
|
|
||||||
flipbottom+=${bottom:$i:1}
|
|
||||||
flipleft+=${left:$i:1}
|
|
||||||
flipright+=${right:$i:1}
|
|
||||||
done
|
|
||||||
RT+=("$fliptop")
|
|
||||||
RR+=("$flipright")
|
|
||||||
RB+=("$flipbottom")
|
|
||||||
RL+=("$flipleft")
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
ALL="${T[*]} ${R[*]} ${B[*]} ${L[*]} ${RT[*]} ${RR[*]} ${RB[*]} ${RL[*]}"
|
|
||||||
ALLSIZE=${#ALL}
|
|
||||||
|
|
||||||
for ((i=0; i<${#nums[@]}; ++i)); do
|
|
||||||
count=0
|
|
||||||
|
|
||||||
for t in ${T[$i]} ${R[$i]} ${B[$i]} ${L[$i]}; do
|
|
||||||
# https://stackoverflow.com/questions/26212889/bash-counting-substrings-in-a-string/50601141#50601141
|
|
||||||
S=${ALL//$t}
|
|
||||||
# 10 is line size
|
|
||||||
((count += (ALLSIZE-${#S})/10))
|
|
||||||
done
|
|
||||||
# 6 is 4 for itself, + 2 for other matching
|
|
||||||
((count == 6)) && ((res*=${nums[$i]}))
|
|
||||||
done
|
|
||||||
|
|
||||||
printf "%s : res=%d\n" "$CMD" "$res"
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
@@ -1,300 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# ex1.bash: Advent2020 game, day 20/game 2.
|
|
||||||
|
|
||||||
CMD=${0##*/}
|
|
||||||
set -o noglob
|
|
||||||
shopt -s extglob
|
|
||||||
|
|
||||||
source tile.bash
|
|
||||||
|
|
||||||
declare -a strings T R B L RT RR RB RL nums
|
|
||||||
declare -a final
|
|
||||||
declare -A FINAL
|
|
||||||
declare -a CORNER EDGE CENTRAL
|
|
||||||
declare -i count=-1 SQUARE
|
|
||||||
|
|
||||||
while read -r line; do
|
|
||||||
case ${line:0:1} in
|
|
||||||
T*)
|
|
||||||
((count++))
|
|
||||||
num=${line##* }
|
|
||||||
num=${num%%:}
|
|
||||||
nums+=("$num")
|
|
||||||
;;
|
|
||||||
\#|.)
|
|
||||||
strings[$count]="${strings[$count]} $line"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
((count++))
|
|
||||||
case "$count" in
|
|
||||||
9)
|
|
||||||
SQUARE=3
|
|
||||||
;;
|
|
||||||
144)
|
|
||||||
SQUARE=12
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
printf "Fatal: unknown square size."
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
declare top bottom left right
|
|
||||||
declare fliptop flipbottom flipleft flipright
|
|
||||||
|
|
||||||
for key in "${!nums[@]}"; do
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
str=(${strings[$key]})
|
|
||||||
top top "${str[@]}"
|
|
||||||
right right "${str[@]}"
|
|
||||||
bottom bottom "${str[@]}"
|
|
||||||
left left "${str[@]}"
|
|
||||||
flip fliptop "$top"
|
|
||||||
flip flipright "$right"
|
|
||||||
flip flipbottom "$bottom"
|
|
||||||
flip flipleft "$left"
|
|
||||||
|
|
||||||
T+=("$top")
|
|
||||||
B+=("$bottom")
|
|
||||||
R+=("$right")
|
|
||||||
L+=("$left")
|
|
||||||
RT+=("$fliptop")
|
|
||||||
RR+=("$flipright")
|
|
||||||
RB+=("$flipbottom")
|
|
||||||
RL+=("$flipleft")
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
ALL="${T[*]} ${R[*]} ${B[*]} ${L[*]} ${RT[*]} ${RR[*]} ${RB[*]} ${RL[*]} "
|
|
||||||
ALLSIZE=${#ALL}
|
|
||||||
|
|
||||||
for ((i=0; i<${#nums[@]}; ++i)); do
|
|
||||||
c=0
|
|
||||||
|
|
||||||
for t in ${T[$i]} ${R[$i]} ${B[$i]} ${L[$i]}; do
|
|
||||||
S=${ALL//$t}
|
|
||||||
# 10 is line size
|
|
||||||
((c += (ALLSIZE-${#S})/10))
|
|
||||||
done
|
|
||||||
# 6 is 4 for itself, + 2 for other matching
|
|
||||||
case "$c" in
|
|
||||||
6)
|
|
||||||
CORNER+=("$i")
|
|
||||||
;;
|
|
||||||
7)
|
|
||||||
EDGE+=("$i")
|
|
||||||
;;
|
|
||||||
8)
|
|
||||||
CENTRAL+=("$i")
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
for ((row=0; row<SQUARE; ++row)); do
|
|
||||||
for ((col=0; col<SQUARE; ++col)); do
|
|
||||||
found=0
|
|
||||||
################################## 1st tile (top left)
|
|
||||||
if ((row==0 && col==0)); then
|
|
||||||
# Choose one corner for top-left, find the correct orientation
|
|
||||||
i=${CORNER[0]}
|
|
||||||
unset "CORNER[0]"
|
|
||||||
CORNER=("${CORNER[@]}")
|
|
||||||
|
|
||||||
t=${B[$i]}
|
|
||||||
S=${ALL//$t}
|
|
||||||
# flip vertical if bottom is a corner side
|
|
||||||
if (( ALLSIZE-${#S} == 10 )); then
|
|
||||||
flip_v "$i"
|
|
||||||
fi
|
|
||||||
t=${R[$i]}
|
|
||||||
S=${ALL//$t}
|
|
||||||
# flip horizontal if right is a corner side
|
|
||||||
if (( ALLSIZE-${#S} == 10 )); then
|
|
||||||
flip_h "$i"
|
|
||||||
fi
|
|
||||||
FINAL[0,0]="$i"
|
|
||||||
final_add "$row" "$i"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
################################## rest of 1st line
|
|
||||||
if ((row==0)); then
|
|
||||||
if ((col < SQUARE-1)); then
|
|
||||||
list=("${EDGE[@]}")
|
|
||||||
else
|
|
||||||
list=("${CORNER[@]}")
|
|
||||||
fi
|
|
||||||
l=${FINAL[0,$((col-1))]}
|
|
||||||
right right "${strings[$l]}"
|
|
||||||
index=0
|
|
||||||
for j in "${list[@]}"; do
|
|
||||||
SIDES="${T[$j]} ${R[$j]} ${B[$j]} ${L[$j]} ${RT[$j]} ${RR[$j]} ${RB[$j]} ${RL[$j]}"
|
|
||||||
LENGTH=${#SIDES}
|
|
||||||
S=${SIDES//$right}
|
|
||||||
# 10 is line size
|
|
||||||
((c = (LENGTH-${#S})/10))
|
|
||||||
if ((c > 0)); then
|
|
||||||
FINAL[$row,$col]="$j"
|
|
||||||
attach_left "$right" "$j"
|
|
||||||
final_add "$row" "$j"
|
|
||||||
if ((col < SQUARE-1)); then
|
|
||||||
unset "EDGE[$index]"
|
|
||||||
EDGE=("${EDGE[@]}")
|
|
||||||
else
|
|
||||||
unset "CORNER[$index]"
|
|
||||||
CORNER=("${CORNER[@]}")
|
|
||||||
fi
|
|
||||||
found=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
((index++))
|
|
||||||
done
|
|
||||||
if ((found==0)); then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
################################## 1st and last col
|
|
||||||
if ((col==0 || col==SQUARE-1)); then
|
|
||||||
if ((row > 0 && row < SQUARE-1)); then
|
|
||||||
list=("${EDGE[@]}")
|
|
||||||
else
|
|
||||||
list=("${CORNER[@]}")
|
|
||||||
fi
|
|
||||||
l=${FINAL[$((row-1)),$col]}
|
|
||||||
bottom bottom "${strings[$l]}"
|
|
||||||
index=0
|
|
||||||
for j in "${list[@]}"; do
|
|
||||||
SIDES="${T[$j]} ${R[$j]} ${B[$j]} ${L[$j]} ${RT[$j]} ${RR[$j]} ${RB[$j]} ${RL[$j]}"
|
|
||||||
LENGTH=${#SIDES}
|
|
||||||
S=${SIDES//$bottom}
|
|
||||||
# 10 is line size
|
|
||||||
((c = (LENGTH-${#S})/10))
|
|
||||||
if ((c > 0)); then
|
|
||||||
FINAL[$row,$col]="$j"
|
|
||||||
attach_top "$bottom" "$j"
|
|
||||||
final_add "$row" "$j"
|
|
||||||
if ((row < SQUARE-1)); then
|
|
||||||
unset "EDGE[$index]"
|
|
||||||
EDGE=("${EDGE[@]}")
|
|
||||||
else
|
|
||||||
unset "CORNER[$index]"
|
|
||||||
CORNER=("${CORNER[@]}")
|
|
||||||
fi
|
|
||||||
found=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
((index++))
|
|
||||||
done
|
|
||||||
if ((found==0)); then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
################################## rest of last row
|
|
||||||
if ((row == SQUARE-1)); then
|
|
||||||
l=${FINAL[$((row-1)),$col]}
|
|
||||||
bottom bottom "${strings[$l]}"
|
|
||||||
index=0
|
|
||||||
for j in "${EDGE[@]}"; do
|
|
||||||
SIDES="${T[$j]} ${R[$j]} ${B[$j]} ${L[$j]} ${RT[$j]} ${RR[$j]} ${RB[$j]} ${RL[$j]}"
|
|
||||||
LENGTH=${#SIDES}
|
|
||||||
S=${SIDES//$bottom}
|
|
||||||
# 10 is line size
|
|
||||||
((c = (LENGTH-${#S})/10))
|
|
||||||
if ((c > 0)); then
|
|
||||||
FINAL[$row,$col]="$j"
|
|
||||||
attach_top "$bottom" "$j"
|
|
||||||
final_add "$row" "$j"
|
|
||||||
unset "EDGE[$index]"
|
|
||||||
EDGE=("${EDGE[@]}")
|
|
||||||
found=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
((index++))
|
|
||||||
done
|
|
||||||
if ((found==0)); then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
################################## central tiles
|
|
||||||
l=${FINAL[$((row-1)),$col]}
|
|
||||||
bottom bottom "${strings[$l]}"
|
|
||||||
index=0
|
|
||||||
for j in "${CENTRAL[@]}"; do
|
|
||||||
SIDES="${T[$j]} ${R[$j]} ${B[$j]} ${L[$j]} ${RT[$j]} ${RR[$j]} ${RB[$j]} ${RL[$j]}"
|
|
||||||
LENGTH=${#SIDES}
|
|
||||||
S=${SIDES//$bottom}
|
|
||||||
# 10 is line size
|
|
||||||
((c = (LENGTH-${#S})/10))
|
|
||||||
if ((c > 0)); then
|
|
||||||
FINAL[$row,$col]="$j"
|
|
||||||
attach_top "$bottom" "$j"
|
|
||||||
final_add "$row" "$j"
|
|
||||||
unset "CENTRAL[$index]"
|
|
||||||
CENTRAL=("${CENTRAL[@]}")
|
|
||||||
found=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
((index++))
|
|
||||||
done
|
|
||||||
if ((found==0)); then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
# dragon:
|
|
||||||
# 01234567890123456789
|
|
||||||
# 0 #
|
|
||||||
# 1 # ## ## ###
|
|
||||||
# 2 # # # # # #
|
|
||||||
find_dragons() {
|
|
||||||
local drag l1 l2 l3
|
|
||||||
local -i found=0 r c len
|
|
||||||
len=${#final[@]}
|
|
||||||
for ((r=0; r<len-2; ++r)); do
|
|
||||||
l1=${final[$r]}
|
|
||||||
l2=${final[$((r+1))]}
|
|
||||||
l3=${final[$((r+2))]}
|
|
||||||
for ((c=0; c<len-20; ++c)); do
|
|
||||||
drag=${l1:$c+18:1}${l2:$c:1}${l2:$c+5:2}${l2:$c+11:2}${l2:$c+17:3}
|
|
||||||
drag+=${l3:$c+1:1}${l3:$c+4:1}${l3:$c+7:1}${l3:$c+10:1}${l3:$c+13:1}${l3:$c+16:1}
|
|
||||||
if [[ "$drag" == '###############' ]]; then
|
|
||||||
((found++))
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
return $found
|
|
||||||
}
|
|
||||||
|
|
||||||
for ((i=0; i<4; ++i)); do
|
|
||||||
find_dragons
|
|
||||||
found=$?
|
|
||||||
((found>0)) && break
|
|
||||||
|
|
||||||
fliph_final
|
|
||||||
find_dragons
|
|
||||||
found=$?
|
|
||||||
((found>0)) && break
|
|
||||||
fliph_final
|
|
||||||
|
|
||||||
flipv_final
|
|
||||||
find_dragons
|
|
||||||
found=$?
|
|
||||||
((found>0)) && break
|
|
||||||
flipv_final
|
|
||||||
|
|
||||||
rotate_final
|
|
||||||
done
|
|
||||||
|
|
||||||
fullstr="${final[*]}"
|
|
||||||
fullstr="${fullstr//[. ]}"
|
|
||||||
sharp=${#fullstr}
|
|
||||||
printf "%s res=%d \n" "$CMD" $((sharp - found*15))
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
@@ -1,253 +0,0 @@
|
|||||||
#!/usr/bin/bash
|
|
||||||
|
|
||||||
rotate_final() {
|
|
||||||
local -i i j len
|
|
||||||
local -a new
|
|
||||||
local line
|
|
||||||
len=${#final[@]}
|
|
||||||
for ((i=len-1; i>=0; --i)); do
|
|
||||||
line=${final[$i]}
|
|
||||||
for ((j=0; j<len; ++j)); do
|
|
||||||
new[$j]+=${line:$j:1}
|
|
||||||
done
|
|
||||||
#dst+=("$str2")
|
|
||||||
done
|
|
||||||
final=("${new[@]}")
|
|
||||||
}
|
|
||||||
|
|
||||||
flipv_final() {
|
|
||||||
local -i i len
|
|
||||||
local -a dst
|
|
||||||
len=${#final[@]}
|
|
||||||
for ((i=0; i<len; ++i)); do
|
|
||||||
dst[$((len-1-i))]=${final[$i]}
|
|
||||||
done
|
|
||||||
final=("${dst[@]}")
|
|
||||||
}
|
|
||||||
|
|
||||||
fliph_final() {
|
|
||||||
local -i i j len
|
|
||||||
local str1 str2
|
|
||||||
local -a dst
|
|
||||||
local str1 str2
|
|
||||||
|
|
||||||
len=${#final[@]}
|
|
||||||
for ((i=0; i<len; ++i)); do
|
|
||||||
str1=${final[$i]}
|
|
||||||
str2=""
|
|
||||||
for ((j=len-1; j>=0; --j)); do
|
|
||||||
str2+=${str1:$j:1}
|
|
||||||
done
|
|
||||||
dst+=("$str2")
|
|
||||||
done
|
|
||||||
final=("${dst[@]}")
|
|
||||||
}
|
|
||||||
|
|
||||||
final_add() {
|
|
||||||
local -i start=$1 r t
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a src=(${strings[$2]})
|
|
||||||
|
|
||||||
for ((r=1, t=$((start*8)); r<9; ++r, t++)); do
|
|
||||||
final[$t]+=${src[$r]:1:8}
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
flip_v() {
|
|
||||||
local -i t=$1 i
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a dst src=(${strings[$t]})
|
|
||||||
for ((i=0; i<10; ++i)); do
|
|
||||||
dst[$((9-i))]=${src[$i]}
|
|
||||||
done
|
|
||||||
strings[$t]="${dst[*]}"
|
|
||||||
}
|
|
||||||
flip_h() {
|
|
||||||
local -i t=$1 i j
|
|
||||||
local str1 str2
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a dst src=(${strings[$t]})
|
|
||||||
local len=${#src[0]}
|
|
||||||
local str1 str2
|
|
||||||
for ((i=0; i<10; ++i)); do
|
|
||||||
str1=${src[$i]}
|
|
||||||
str2=""
|
|
||||||
for ((j=9; j>=0; --j)); do
|
|
||||||
str2+=${str1:$j:1}
|
|
||||||
done
|
|
||||||
dst+=("$str2")
|
|
||||||
done
|
|
||||||
strings[$t]="${dst[*]}"
|
|
||||||
}
|
|
||||||
r90() {
|
|
||||||
local -i t=$1 i j
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a dst src=(${strings[$t]}) str2
|
|
||||||
local str1
|
|
||||||
for ((i=9; i>=0; --i)); do
|
|
||||||
str1=${src[$i]}
|
|
||||||
for ((j=0; j<10; ++j)); do
|
|
||||||
str2[$j]+=${str1:$j:1}
|
|
||||||
done
|
|
||||||
#dst+=("$str2")
|
|
||||||
done
|
|
||||||
strings[$t]="${str2[*]}"
|
|
||||||
}
|
|
||||||
|
|
||||||
r180() {
|
|
||||||
local -i t=$1 i j
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a dst src=(${strings[$t]})
|
|
||||||
local str1 str2
|
|
||||||
for ((i=9; i>=0; --i)); do
|
|
||||||
str1=${src[$i]}
|
|
||||||
str2=""
|
|
||||||
for ((j=9; j>=0; --j)); do
|
|
||||||
str2+=${str1:$j:1}
|
|
||||||
done
|
|
||||||
dst+=("$str2")
|
|
||||||
done
|
|
||||||
strings[$t]="${dst[*]}"
|
|
||||||
}
|
|
||||||
r270() {
|
|
||||||
local -i t=$1 i j
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a dst src=(${strings[$t]}) str2
|
|
||||||
local str1
|
|
||||||
for ((i=0; i<10; ++i)); do
|
|
||||||
str1=${src[$i]}
|
|
||||||
for ((j=0; j<10; ++j)); do
|
|
||||||
str2[$j]+=${str1:9-$j:1}
|
|
||||||
done
|
|
||||||
#dst+=("$str2")
|
|
||||||
done
|
|
||||||
strings[$t]="${str2[*]}"
|
|
||||||
}
|
|
||||||
left() {
|
|
||||||
local -n _r="$1"
|
|
||||||
local -i i
|
|
||||||
shift
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a tile=($*)
|
|
||||||
_r=""
|
|
||||||
for ((i=0; i<10; ++i)); do
|
|
||||||
_r+=${tile[$i]:0:1}
|
|
||||||
done
|
|
||||||
}
|
|
||||||
right() {
|
|
||||||
local -n _r="$1"
|
|
||||||
local -i i
|
|
||||||
shift
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a tile=($*)
|
|
||||||
_r=""
|
|
||||||
for ((i=0; i<10; ++i)); do
|
|
||||||
_r+=${tile[$i]: -1:1}
|
|
||||||
done
|
|
||||||
}
|
|
||||||
top() {
|
|
||||||
local -n _r="$1"
|
|
||||||
shift
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a tile=($*)
|
|
||||||
_r=${tile[0]}
|
|
||||||
}
|
|
||||||
bottom() {
|
|
||||||
local -n _r="$1"
|
|
||||||
shift
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a tile=($*)
|
|
||||||
_r=${tile[9]}
|
|
||||||
}
|
|
||||||
flip() {
|
|
||||||
local -n _r="$1"
|
|
||||||
local str="$2"
|
|
||||||
local -i i
|
|
||||||
_r=""
|
|
||||||
for ((i=9; i>=0; --i)); do
|
|
||||||
_r+=${str:$i:1}
|
|
||||||
done
|
|
||||||
}
|
|
||||||
# transform $2 tile to match $1 on left
|
|
||||||
attach_left() {
|
|
||||||
local _l="$1"
|
|
||||||
local -i t="$2" m=0
|
|
||||||
local s
|
|
||||||
|
|
||||||
for s in ${T[$t]} ${R[$t]} ${B[$t]} ${L[$t]} \
|
|
||||||
${RT[$t]} ${RR[$t]} ${RB[$t]} ${RL[$t]}; do
|
|
||||||
if [[ "$s" == "$_l" ]]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
((m++))
|
|
||||||
done
|
|
||||||
case $m in
|
|
||||||
0) # top
|
|
||||||
r270 "$t"
|
|
||||||
flip_v "$t"
|
|
||||||
;;
|
|
||||||
1) # right
|
|
||||||
flip_h "$t"
|
|
||||||
;;
|
|
||||||
2) # bottom
|
|
||||||
r90 "$t"
|
|
||||||
;;
|
|
||||||
3) # left
|
|
||||||
;;
|
|
||||||
4) # rev top
|
|
||||||
r270 "$t"
|
|
||||||
;;
|
|
||||||
5) # rev right
|
|
||||||
r180 "$t"
|
|
||||||
;;
|
|
||||||
6) # rev bottom
|
|
||||||
r90 "$t"
|
|
||||||
flip_v "$t"
|
|
||||||
;;
|
|
||||||
7) # rev left
|
|
||||||
flip_v "$t"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# transform $2 tile to match $1 on left
|
|
||||||
attach_top() {
|
|
||||||
local _l="$1"
|
|
||||||
local -i t="$2" m=0
|
|
||||||
local s
|
|
||||||
|
|
||||||
for s in ${T[$t]} ${R[$t]} ${B[$t]} ${L[$t]} \
|
|
||||||
${RT[$t]} ${RR[$t]} ${RB[$t]} ${RL[$t]}; do
|
|
||||||
if [[ "$s" == "$_l" ]]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
((m++))
|
|
||||||
done
|
|
||||||
case $m in
|
|
||||||
0) # top
|
|
||||||
;;
|
|
||||||
1) # right
|
|
||||||
r270 "$t"
|
|
||||||
;;
|
|
||||||
2) # bottom
|
|
||||||
flip_v "$t"
|
|
||||||
;;
|
|
||||||
3) # left
|
|
||||||
r90 "$t"
|
|
||||||
flip_h "$t"
|
|
||||||
;;
|
|
||||||
4) # rev top
|
|
||||||
flip_h "$t"
|
|
||||||
;;
|
|
||||||
5) # rev right
|
|
||||||
r270 "$t"
|
|
||||||
flip_h "$t"
|
|
||||||
;;
|
|
||||||
6) # rev bottom
|
|
||||||
r180 "$t"
|
|
||||||
;;
|
|
||||||
7) # rev left
|
|
||||||
r90 "$t"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
xfdrdc jvns jxmvd fgr nfzmfc rqg zkbjn tfrgk vnqndg jbqrf kmx jvsp gvldp xxsg krhbv khcz bsvsgpv ckxhnn kcfj smcfc lmssp sccq czfhj vcdttr ggllbbq knsmcv sklfg nhdcrsm fcgdg vv xddnkh hmbfrf glpp phjf pvczp nhdm nlxsmb zrsx krpd fqgc nlxnmh qnnfsk jchhzn hxbnzg bhzhv vlbpsc mlr rnbhjk gdsqjpb knr qkg ttkp hgfx txfcjmgr qmkz qhrsjg hsqxc gzk bvnkk cvvlpx jpvz xpxpzj txhxn bfs vllzx bl gstcl jxlk hmjtv pxt jbhcfs rqq hktg trmzkcfg jtfxpx zjdhhql blxc dvbhvrc lljjv lslbrf zdprv czqmsht lkcg cvvqm (contains eggs)
|
|
||||||
ftkq qrfvp pqvz dkpgx gstcl zsdjf dhkbkh nlxsmb qjgkx jvns bhtnm rdzzx gvldp vzcnrt lqjkvt ktvngm trmzkcfg ttxvphb czqmsht jbhcfs nbmvrvtz glpp txhxn zpbgmqh vv jrdgbq jxghqb thjln lf fcgdg hmjtv shgm dchqtx hmbfrf vnqndg ngrn rnbhjk zkbjn mlr fqqcnjj fgr qmkz fqgc tgh mbmmhs bvnkk rrhjckjb xrssmn gqk sczgc czgv qvnsd dbgx vbldc sklfg hsqxc nztj dxm xgrvrpk zrls sqhvjzp (contains fish)
|
|
||||||
hmjtv fqqcnjj nlxnmh qhrsjg zkbjn dxznn cvvqm lslbrf nrpfgqg fgr gdsqjpb rxrf vhrngpv sgkbdf jtfxpx zjdhhql shgm blxc zdprv cpjpzs hhsn krpd fcgdg nlxsmb fvrqmm rrhjckjb rhgk czfhj qlk jbqrf pvl jcxr jchhzn jxmvd glpp vv lmssp pxt bvnkk xgrvrpk lf vzcnrt lqnmc gqk czgv bsvsgpv jlvvh xpxpzj ktvngm zpbgmqh qmkz trmzkcfg jvsp jxghqb bhtnm tvxxfrnl krhbv gzk jpvz pvczp lljjv jkjgmfr fdrqq lkcg cmnnlm dxm zrldmc jvns ttxvphb (contains soy)
|
|
||||||
kmx qlk vnqndg bmhr mksnj lqjkvt gdsqjpb khcz nbmvrvtz glpp jpvz dchqtx dbgx bvnkk bl jbqrf ckxhnn nztj cjrnk cpjpzs nlxsmb vv jtfxpx vqvm jchhzn qhhzc txhxn qkg jxghqb jvztb jcxr zrldmc qnnfsk qbnkv jlvvh zrls zdprv nhdm dxznn pvl jbhcfs rnbhjk nhdcrsm qvnsd sgfmv trmzkcfg zsdjf zrsx rttfvfrs xfdrdc cvvqm cvvlpx ttxvphb smcfc ktz (contains fish, eggs)
|
|
||||||
qdlxb czgv ffp fgr pvl rdzzx nhsxfc dxm jxmvd qmkz hzk nlxsmb ttxvphb qlk bvnkk vnqndg bmhr jrdgbq jxlk kmx gstcl jvztb nhdm trmzkcfg zrldmc bhzhv knsmcv vv jchhzn ttkp qnnfsk zrls sgkbdf qkg ktz pxt jpvz cmnnlm fvrqmm xxsg rqq zsdjf vzcnrt sgkp bl (contains nuts, soy, wheat)
|
|
||||||
jvns czqmsht gvldp sgkbdf ffp ttxvphb qmkz sqhvjzp qzfq ngrn csgf hmnqgbn dngmrr dhpm qnnfsk bhzhv rnbhjk nlxsmb fvrqmm xfdrdc svtb phjf gqk qgxftv jchhzn jbhcfs zrldmc dhkbkh jxlk txfcjmgr vlbpsc nbmvrvtz mksnj khcz rdzzx bvnkk vv qbnkv fcgdg hgfx jtfxpx rxrf rqg djtnh vbldc nhdcrsm hxbnzg tcjcn cvvqm lf nkkxt zdprv dxznn fkzfb nhsxfc zrls czfhj qkkb gcrfsb mzmz jpvz blxc (contains wheat, fish, nuts)
|
|
||||||
qlrcp lf nlxsmb cszgr txhxn tfrgk vv ngqf mxrm hhsn xqpsvm kmx bfs csgf sgkbdf jpvz nztj qlk trmzkcfg nnqq ttxvphb jvztb xfdrdc sxd fgr hcxdnj nhdm kgzbpxt gzk zdprv qmkz bvnkk vllzx rqg mbmmhs dhkbkh qhrsjg bmhr hgfx lkcg kgbd ngfhps dqq hzk qvnsd svtb pkjjt ckfhr (contains eggs, nuts, wheat)
|
|
||||||
qhrsjg mzmz ttxvphb dvbhvrc mcbnnp vv vnqndg nnqq fqgc vlbpsc dbgx nlxsmb jtfxpx qkg rhgk pkjjt rqq ftkq zrsx kmlxqx sqhvjzp jmdr smbvks lf hmbfrf bsvsgpv hcxdnj vqvm phjf vcdttr xgvz qrfvp qbnkv jcxr ffp lljjv bvnkk rnbhjk khcz rxrf jpvz dxznn trmzkcfg rttfvfrs hmjtv bmhr ttkp cszgr jxghqb krhbv fgr qkkb nfzmfc ckxhnn zrldmc txfcjmgr cpjpzs zjdhhql ggllbbq cmnnlm zkbjn qnnfsk (contains fish, dairy)
|
|
||||||
jpvz sblll ttxvphb lslbrf qjgkx ckfhr vhmh bmhr mlr ggllbbq fqqcnjj knsmcv qrfvp nhsxfc rxrf dvbhvrc ngrn jxghqb lljjv blxc csgf lqnmc vnqndg mcbnnp svtb sklfg hcxdnj bsvsgpv jrdgbq nnqq rrhjckjb bvnkk qsvkt bl pvl mzmz hmbfrf xfdrdc qmkz ftkq hmjtv czqmsht nfzmfc sccq dxm rdzzx qgxftv rqg jchhzn dxznn cszgr pqvz ngfhps trmzkcfg vv nlxsmb nhdcrsm cvvlpx (contains eggs, nuts)
|
|
||||||
txhxn lrkft jpvz gstcl nhdm gzk nhdcrsm sblll bsvsgpv rnbhjk cjrnk jlvvh zjdhhql smcfc dbgx sm hhsn nkkxt sgkbdf pxt nbmvrvtz ftkq jmdr lmssp fgr mlr csgf qmkz jvztb vllzx jvsp gcrfsb nfzmfc cjhk krhbv ttxvphb cvvqm svtb knsmcv dvbhvrc phjf sgfmv jjzh qnnfsk trmzkcfg qsvkt qlk cszgr xrssmn thjln bvnkk qvnsd dqq cpjpzs kcfj zpbgmqh qhhzc hcxdnj zkbjn xqpsvm pvczp khcz cvvlpx nlxnmh ckfhr lvbbgn txfcjmgr ktvngm dxm rhgk vv tgh fqgc vbldc (contains wheat, shellfish, fish)
|
|
||||||
qhrsjg bfs nkkxt fvrqmm ttxvphb lqjkvt nlxsmb mzmz lmssp lkcg cvvlpx qdlxb blxc gdsqjpb bl trmzkcfg phjf zrls qvnsd dxznn zjdhhql mxrm hcxdnj nlxnmh jmdr gstcl jvns jlvvh sccq vbldc smbvks qhcj nfzmfc dqq qmkz ktvngm rttfvfrs lrkft vv rnbhjk ngqf vzcnrt mbmmhs qgxftv djtnh qhhzc fgr jtfxpx sczgc vhmh cvvqm sgfmv jxmvd cjrnk mksnj kgbd jxlk gvldp kmx nhdcrsm ktz jpvz kcfj xpxpzj dhkbkh nnqq hxbnzg lqnmc sm (contains fish, shellfish)
|
|
||||||
czfhj nrpfgqg gstcl xddnkh jxlk mcbnnp hsqxc vnqndg kgzbpxt jmdr gzk vcdttr zrsx mlr jtfxpx vv ktvngm krpd smbvks sqhvjzp cjrnk gvldp dngmrr trmzkcfg qlk hmjtv qvnsd qhrsjg sccq hktg cvvlpx jvsp bvnkk ttxvphb jxghqb fvrqmm sm qbnkv zdprv tfrgk lmssp djtnh kmx lljjv rdzzx rnbhjk jpvz dvbhvrc fcgdg hzk jcxr mksnj fqqcnjj qhcj tcjcn zrldmc qmkz tvxxfrnl dxm hmbfrf bhtnm zsdjf vhmh khcz xqpsvm ffp fqgc rxrf xpxpzj krhbv sklfg (contains fish, shellfish)
|
|
||||||
qbnkv fgr rnbhjk csgf xrssmn ttkp trmzkcfg vv vhrngpv vqvm zrls xfdrdc fcgdg tfrgk lljjv kgzbpxt svtb pkjjt fdrqq nztj jchhzn cjhk djtnh kcfj vcdttr jmdr qlk bl hhsn cpjpzs hmjtv pvl nkkxt tgh jxmvd jvns jcxr dhpm nhsxfc sxd smbvks ckxhnn glpp bmhr dxm mlr jlvvh czqmsht txfcjmgr sczgc cvvqm nhdm gvldp sklfg sgkp nfzmfc gzk lf bvnkk nlxsmb qhrsjg ftkq gqk bsvsgpv dhkbkh jpvz nlxnmh mcbnnp qrfvp mxrm bhzhv ngfhps krpd kmx tcjcn jkjgmfr ttxvphb cjrnk zpbgmqh hsqxc (contains fish)
|
|
||||||
nztj jtfxpx zrls krhbv fqqcnjj bfs rqg kmlxqx xddnkh mlr gzk czfhj zsdjf qvnsd ckfhr czqmsht ngrn trmzkcfg dxm fdrqq jkjgmfr hcxdnj bl cjrnk xqpsvm xpxpzj tfrgk hmbfrf pkjjt lvbbgn nlxsmb lmssp bhzhv tvxxfrnl fgr sqhvjzp qzfq smcfc mksnj qjgkx vv lqnmc lkcg bvnkk gvldp qmkz shgm jpvz jxlk czgv pxt ffdc ttxvphb (contains nuts, peanuts, eggs)
|
|
||||||
mlr lqjkvt nrpfgqg djtnh nhdcrsm vv ktz gvldp zjdhhql gstcl qvnsd czgv xgvz csgf fqgc jxlk rdzzx nbfkp gdsqjpb fvrqmm hhsn lljjv dxznn zrldmc lvbbgn vhrngpv dhpm nkkxt hmbfrf hsqxc sm ttxvphb qrfvp bl xddnkh jvns rrhjckjb cjrnk lslbrf jmdr sczgc jvsp gzk rxrf qnnfsk zpbgmqh kmx qlk ktvngm trmzkcfg vzcnrt bmhr hcxdnj nlxsmb jpvz rnbhjk xxsg tcjcn qhhzc knsmcv qmkz rqq mzmz fgr ngqf gqk czfhj (contains shellfish, dairy, soy)
|
|
||||||
dkpgx qmkz sccq rnbhjk xgrvrpk vv gzk gcrfsb trmzkcfg dhkbkh zkbjn svtb fgr xpxpzj qkg ckxhnn zsdjf jcxr hgfx sqhvjzp djtnh vllzx rdzzx nlxsmb hmjtv nrpfgqg lslbrf ktz bvnkk ngfhps nbmvrvtz phjf zjdhhql lf pkjjt sxd ttxvphb dhpm nnqq kcfj zrldmc qjgkx jxghqb xddnkh vhrngpv nbfkp ftkq (contains peanuts, fish)
|
|
||||||
jvztb nhdm vcdttr cjhk qrfvp dbgx svtb jkjgmfr fgr tcjcn pvl bvnkk txhxn nztj sgkp fcgdg jtfxpx tgh jpvz lljjv zsdjf fqgc vv nfzmfc qkg knr gcrfsb trmzkcfg qzfq jxmvd rrhjckjb ftkq ttkp czgv qmkz sqhvjzp rnbhjk bhtnm hmjtv vhmh xddnkh mzmz jxghqb jchhzn ktvngm jvsp cjrnk bmhr rqg dhpm sm smcfc ttxvphb tfrgk vzcnrt qhcj fqqcnjj tvxxfrnl jjzh dxznn sblll rxrf dngmrr djtnh kgzbpxt nlxnmh lvbbgn qhrsjg rttfvfrs vnqndg cmnnlm sxd (contains fish, wheat)
|
|
||||||
ckfhr vzcnrt ngfhps ggllbbq sgkbdf cszgr qgxftv qdlxb bvnkk xqpsvm vv smbvks nbfkp lf bsvsgpv sblll qmkz trmzkcfg rnbhjk gdsqjpb jpvz gvldp qkg nbmvrvtz jmdr czqmsht fqgc dhpm qhcj sczgc vllzx tgh hsqxc qzfq blxc qrfvp krpd ttxvphb qjgkx tvxxfrnl khcz qhrsjg kmlxqx nztj dhkbkh gqk nkkxt rdzzx zpbgmqh tfrgk thjln rqg sgkp lkcg hzk ktvngm phjf (contains shellfish, dairy, soy)
|
|
||||||
qhhzc mbmmhs trmzkcfg smcfc rrhjckjb vlbpsc xgrvrpk zkbjn zrls lrkft qdlxb qmkz nbmvrvtz qjgkx qrfvp vv jjzh zsdjf qbnkv txhxn ttxvphb ckxhnn tvxxfrnl txfcjmgr sgkp qgxftv qlrcp qsvkt zrsx bhtnm qkg xddnkh krhbv hxbnzg phjf ttkp qlk cszgr sm jpvz kcfj bvnkk sklfg hmnqgbn pvl jbqrf cmnnlm dvbhvrc dqq mcbnnp kmx rqq rnbhjk zrldmc xqpsvm nnqq sqhvjzp ktz ffp vllzx hzk cvvlpx fqqcnjj vhrngpv nhdm vcdttr jxmvd (contains dairy, nuts)
|
|
||||||
gqk fvrqmm qmkz vqvm vcdttr rnbhjk hxbnzg kgbd vhrngpv fgr qkkb bvnkk zjdhhql cvvqm bfs mlr nrpfgqg tfrgk rqq dxznn vv nhsxfc nbfkp gdsqjpb vzcnrt dqq jvsp ttxvphb nlxnmh kmlxqx nhdm xgrvrpk kmx zrls sczgc sxd hmbfrf fcgdg xgvz ktz jbqrf dkpgx sqhvjzp mzmz bsvsgpv shgm dchqtx glpp qzfq vnqndg nbmvrvtz rdzzx bmhr trmzkcfg nlxsmb bhtnm hktg lslbrf pxt dhkbkh zsdjf mbmmhs sccq ttkp xpxpzj rttfvfrs dhpm (contains dairy, fish)
|
|
||||||
rnbhjk fcgdg rqq khcz lslbrf bfs vqvm nlxsmb rqg dvbhvrc mbmmhs kgzbpxt vlbpsc qmkz sgkbdf fdrqq sxd cpjpzs lqjkvt gcrfsb sqhvjzp pxt czgv jcxr vv jrdgbq vzcnrt cmnnlm jbhcfs qjgkx ngrn nhdcrsm dkpgx xrssmn gqk hmnqgbn ngfhps jmdr dxznn thjln xgrvrpk bvnkk dchqtx qnnfsk pqvz jpvz hzk gvldp djtnh csgf qgxftv hmbfrf smcfc lf sm svtb vhmh mlr ttkp ttxvphb dbgx tcjcn qlrcp zpbgmqh lrkft sblll lmssp qhrsjg phjf (contains eggs)
|
|
||||||
zjdhhql ftkq zrldmc vzcnrt dbgx bhzhv nlxnmh shgm nlxsmb qsvkt vlbpsc qvnsd nhdcrsm cjhk sklfg djtnh hmbfrf nhdm dhpm qkkb bvnkk smbvks vv pxt fcgdg lkcg blxc jpvz rxrf cszgr kmlxqx rnbhjk fvrqmm rqq ttxvphb cvvlpx rdzzx cjrnk qlrcp dxm bl nztj vhrngpv zkbjn qrfvp xpxpzj zrsx mlr qmkz qhhzc (contains peanuts)
|
|
||||||
zkbjn qrfvp vlbpsc sczgc jlvvh knsmcv ngfhps rnbhjk vv hktg cszgr ttkp jvztb dngmrr trmzkcfg cvvlpx djtnh tcjcn lmssp nlxsmb jbhcfs qvnsd qkkb sccq mzmz jtfxpx fcgdg lvbbgn cjhk pvczp qmkz sxd jcxr dqq bvnkk sgfmv hmbfrf cjrnk jkjgmfr xpxpzj rxrf rhgk jvsp blxc vllzx jpvz xgrvrpk ffp qlrcp hmnqgbn zsdjf nkkxt zrsx qgxftv czfhj vqvm lrkft kgzbpxt ngqf kgbd xfdrdc (contains soy)
|
|
||||||
dxm ftkq sccq ktvngm zrls lvbbgn gcrfsb cszgr vv xrssmn vzcnrt jchhzn rttfvfrs qmkz mbmmhs hmjtv qnnfsk nhdm qsvkt xxsg gvldp trmzkcfg svtb txfcjmgr jrdgbq bmhr sgkp cpjpzs bsvsgpv hmnqgbn glpp dxznn blxc nlxsmb fgr jtfxpx jpvz qhrsjg bvnkk fkzfb cvvqm qvnsd bl kmlxqx ngrn lqnmc lslbrf thjln kmx smcfc lrkft nfzmfc ttxvphb cjhk rrhjckjb dhpm (contains shellfish, eggs, nuts)
|
|
||||||
qmkz rxrf ngqf ttxvphb qrfvp qjgkx bfs hzk kgbd pvczp tfrgk jbqrf xgvz jxmvd nnqq qhhzc zrsx bl cmnnlm nbmvrvtz fvrqmm zpbgmqh fqgc hmnqgbn ttkp nhdm sgfmv jvns sccq hktg hmjtv ngfhps vqvm qlk qgxftv dchqtx sm rrhjckjb ffdc bvnkk dvbhvrc vhrngpv ktz smcfc jpvz trmzkcfg kmx mlr hcxdnj nkkxt nlxnmh czfhj smbvks jcxr rhgk rnbhjk ngrn krhbv txhxn sklfg shgm sxd krpd gvldp pxt dxznn thjln dkpgx jbhcfs hmbfrf pvl qzfq xfdrdc mcbnnp vv sgkp zdprv (contains wheat)
|
|
||||||
xgrvrpk zrsx ckfhr jtfxpx ckxhnn trmzkcfg qrfvp lslbrf smcfc bhtnm pxt rhgk jxmvd dngmrr jmdr czfhj djtnh cjrnk hgfx ktz qgxftv fqqcnjj hmjtv rrhjckjb mxrm zrldmc rttfvfrs tvxxfrnl qkkb ttxvphb dvbhvrc pvczp vhrngpv bl sblll jpvz jchhzn tcjcn qjgkx xxsg vv czgv dxm kmlxqx zpbgmqh hcxdnj lf jcxr zdprv nhsxfc smbvks vnqndg rdzzx nnqq sxd ffp nrpfgqg bvnkk sgkp qzfq gcrfsb ftkq nlxsmb rnbhjk rqq dbgx nkkxt pkjjt dhkbkh qlrcp fcgdg knr xgvz xrssmn (contains fish, soy)
|
|
||||||
pvczp bsvsgpv nfzmfc zpbgmqh qsvkt pkjjt jxghqb hgfx dxm xgrvrpk smbvks txhxn sgkp xfdrdc rttfvfrs tgh jpvz tcjcn bmhr cvvqm sccq rhgk nztj gzk vhrngpv ttkp nkkxt zrldmc ggllbbq xpxpzj qmkz ktvngm krhbv zrsx jchhzn mbmmhs gstcl hzk kgzbpxt dhpm fgr jbqrf sklfg ffp ttxvphb bvnkk jbhcfs dqq rqq mxrm rqg vhmh jkjgmfr hhsn qhrsjg jxmvd fdrqq rrhjckjb nlxsmb kmlxqx cszgr qrfvp nhdcrsm lljjv kmx tfrgk glpp cjrnk fvrqmm qnnfsk blxc nbfkp qzfq jvztb cjhk ngqf qgxftv zjdhhql zkbjn sqhvjzp czqmsht thjln djtnh rnbhjk gqk zsdjf shgm gcrfsb vv dkpgx (contains dairy, eggs)
|
|
||||||
cmnnlm sgkp qlk jvns sqhvjzp fvrqmm jpvz rhgk jbqrf rqq qzfq rnbhjk gvldp vv fkzfb ktz mzmz jtfxpx bhzhv txfcjmgr nlxsmb smbvks rdzzx jvztb jrdgbq ftkq qvnsd mlr gcrfsb mcbnnp fdrqq zsdjf trmzkcfg dvbhvrc ttxvphb hmjtv qhhzc fcgdg dkpgx rrhjckjb lmssp sccq qmkz pvczp krpd ckfhr svtb mxrm (contains wheat, soy, peanuts)
|
|
||||||
jxmvd mlr jkjgmfr hhsn rxrf qvnsd phjf vhmh lmssp ttxvphb lljjv qlrcp bsvsgpv qsvkt trmzkcfg kmx hxbnzg rnbhjk qmkz thjln fvrqmm hzk jbqrf nlxsmb lqjkvt hktg kgzbpxt fqgc qrfvp gcrfsb bvnkk txhxn qlk smcfc kmlxqx jpvz pqvz krpd gstcl fqqcnjj gzk nnqq lrkft tfrgk (contains fish, wheat, peanuts)
|
|
||||||
xxsg lqnmc jxlk phjf lljjv lqjkvt rdzzx kcfj nkkxt zjdhhql rnbhjk nbfkp nlxnmh hhsn jtfxpx nztj qrfvp xgrvrpk jpvz krpd jlvvh pxt lrkft qgxftv qjgkx trmzkcfg lmssp hmjtv ttxvphb xddnkh qsvkt rxrf vhrngpv hzk qmkz jcxr vv mxrm hmnqgbn smbvks vllzx gcrfsb bhzhv qlrcp qdlxb nlxsmb fqqcnjj ngqf txhxn jvztb knsmcv ktvngm (contains peanuts, dairy)
|
|
||||||
jbqrf tvxxfrnl mlr cvvqm zpbgmqh vlbpsc knsmcv xrssmn cjhk qkkb cpjpzs qnnfsk hmnqgbn hzk fdrqq vcdttr qmkz jcxr qrfvp vhrngpv pvczp fgr gstcl vnqndg tgh mbmmhs ktz rnbhjk lmssp qdlxb fqqcnjj xxsg nlxsmb trmzkcfg hktg qhhzc xddnkh pkjjt ngfhps ttxvphb xfdrdc rqg tcjcn zrsx smbvks dxm jtfxpx xpxpzj lf nztj vllzx qbnkv jchhzn nlxnmh jjzh sqhvjzp dbgx sczgc qhrsjg bvnkk xgrvrpk jpvz hmjtv dvbhvrc knr czgv hxbnzg (contains eggs, shellfish)
|
|
||||||
rnbhjk qvnsd nlxsmb krpd qbnkv kgzbpxt mzmz qzfq lqjkvt ngrn qhrsjg qhcj bhtnm trmzkcfg sqhvjzp blxc txfcjmgr ggllbbq jxmvd jrdgbq gvldp cmnnlm nhdm zsdjf sm vllzx hmbfrf dvbhvrc pqvz rdzzx jvns kgbd lljjv cvvqm lkcg knsmcv djtnh rqg rrhjckjb jkjgmfr vlbpsc tcjcn nbmvrvtz fqgc gqk hcxdnj vcdttr jtfxpx xrssmn lrkft pvl nkkxt ttxvphb csgf sxd bsvsgpv vv bvnkk qmkz (contains fish, soy)
|
|
||||||
tfrgk dxznn nfzmfc qmkz ngqf nkkxt sm hzk kmlxqx fgr jvsp gzk jkjgmfr hmbfrf dngmrr hgfx vcdttr ggllbbq rnbhjk ffp lqnmc zkbjn xxsg hktg qlk lqjkvt glpp vlbpsc rhgk pxt cjhk jxlk pvl lf hhsn dbgx jchhzn sxd sccq cszgr phjf qgxftv lmssp qkkb vhmh bfs bhtnm trmzkcfg dhpm smbvks nhsxfc fcgdg sgkp mlr smcfc xddnkh lrkft sgfmv mxrm lslbrf jtfxpx nlxnmh sgkbdf kgbd vv qdlxb ttxvphb bl xfdrdc ngfhps jpvz nhdm fqqcnjj thjln knr dchqtx knsmcv xpxpzj nlxsmb ngrn hcxdnj ttkp zsdjf jbhcfs blxc xrssmn ckfhr jvns qlrcp hmnqgbn ckxhnn svtb zpbgmqh ffdc gstcl jvztb shgm (contains shellfish, eggs)
|
|
||||||
gqk dbgx gstcl mxrm qjgkx qhrsjg jpvz bvnkk kmx fkzfb lrkft qzfq ttxvphb rxrf tgh bl vlbpsc fcgdg pvczp zrldmc kmlxqx dvbhvrc rnbhjk qgxftv vqvm thjln xqpsvm trmzkcfg bmhr nlxnmh qmkz pvl dngmrr khcz bsvsgpv phjf hcxdnj djtnh jkjgmfr jtfxpx ttkp nbmvrvtz czqmsht cvvlpx rqq xgrvrpk qlrcp hzk jchhzn jcxr vcdttr cjrnk sccq jlvvh vv (contains shellfish)
|
|
||||||
hhsn jxghqb fqgc sccq jrdgbq qnnfsk djtnh nkkxt nlxsmb xrssmn bhtnm krhbv sgfmv cvvlpx jcxr xgrvrpk jmdr bsvsgpv hktg qhcj vbldc cpjpzs lqjkvt hzk sgkbdf vnqndg ttxvphb lqnmc rrhjckjb kcfj lf rnbhjk blxc bvnkk hmbfrf nbfkp pvczp zkbjn fcgdg qmkz sczgc ggllbbq phjf trmzkcfg svtb dhpm jpvz (contains fish)
|
|
||||||
hmjtv qbnkv qhhzc mzmz rhgk ktvngm jvns hmnqgbn gqk zrldmc khcz sgfmv nfzmfc knr nhdcrsm jlvvh bfs jpvz ttxvphb rxrf ggllbbq nlxsmb sccq mcbnnp sgkbdf cszgr sqhvjzp pqvz trmzkcfg nnqq qhrsjg jxlk fqqcnjj fvrqmm rnbhjk vnqndg jbqrf mbmmhs czgv pvl sm nztj dbgx bvnkk hsqxc jjzh vv nhsxfc vlbpsc dchqtx jtfxpx xgvz hhsn bmhr jvztb qrfvp rqg zpbgmqh sxd jcxr jrdgbq thjln zrsx lkcg fqgc dhkbkh fdrqq cjhk (contains wheat, peanuts)
|
|
||||||
vv bvnkk rttfvfrs nnqq smbvks vzcnrt nbmvrvtz khcz hmjtv fgr zrls qmkz hmbfrf nhdm tfrgk ttxvphb lkcg dvbhvrc qkg mlr sccq jxghqb lrkft csgf sgkp zkbjn kgzbpxt jbqrf jpvz pxt krhbv rqg knr sm qjgkx nhdcrsm jmdr cszgr zrsx gvldp gzk zsdjf trmzkcfg pvl xddnkh ffp gdsqjpb pqvz vqvm dhkbkh sxd bmhr ffdc xpxpzj bhzhv nfzmfc rnbhjk lslbrf (contains shellfish)
|
|
||||||
bfs ftkq sqhvjzp ffp nlxsmb hgfx cvvlpx rdzzx kgzbpxt mbmmhs bvnkk jjzh xddnkh krpd dxm jchhzn qrfvp nbmvrvtz zrldmc ktz gvldp svtb zdprv vqvm mxrm zrsx nbfkp tgh rrhjckjb tvxxfrnl jtfxpx sm rqq dqq pkjjt nkkxt qdlxb jvztb vv fgr txhxn fdrqq gqk cjhk xgrvrpk rhgk lmssp fkzfb zrls ttxvphb smbvks jvns trmzkcfg hhsn jxghqb fqqcnjj vhmh dngmrr qsvkt gzk jlvvh tcjcn rqg ngqf dkpgx xpxpzj sgfmv tfrgk qmkz rnbhjk jxlk jcxr lslbrf pqvz fcgdg bhtnm zjdhhql jbqrf ngfhps bmhr (contains peanuts, soy, eggs)
|
|
||||||
zrsx dxznn lvbbgn hmbfrf rnbhjk nhdcrsm bhtnm xgrvrpk cvvlpx knsmcv bvnkk pxt qkkb qzfq vv zkbjn thjln qlrcp jrdgbq hhsn nztj mbmmhs khcz lqnmc vlbpsc rrhjckjb hmnqgbn hsqxc xfdrdc tfrgk czfhj zrls jpvz dhkbkh vllzx trmzkcfg zpbgmqh nfzmfc gstcl sgkbdf hxbnzg vcdttr nhdm tvxxfrnl lf pvczp vhrngpv nlxsmb ttxvphb nrpfgqg rdzzx jxghqb sccq xrssmn cmnnlm sblll sxd sqhvjzp qhhzc kmlxqx kcfj jlvvh gdsqjpb jmdr (contains soy)
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
# AOC daily Makefile - GNU make only.
|
|
||||||
#
|
|
||||||
# Copyright (C) 2021-2022 Bruno Raoult ("br")
|
|
||||||
# Licensed under the GNU General Public License v3.0 or later.
|
|
||||||
# Some rights reserved. See COPYING.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with this
|
|
||||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
#
|
|
||||||
|
|
||||||
INPUT := INPUT.txt
|
|
||||||
SHELL := /bin/bash
|
|
||||||
|
|
||||||
CC := gcc
|
|
||||||
BEAR := bear
|
|
||||||
CCLSFILE:= compile_commands.json
|
|
||||||
|
|
||||||
LIB := aoc_$(shell uname -m)
|
|
||||||
INCDIR := ../include
|
|
||||||
LIBDIR := ../lib
|
|
||||||
LDFLAGS := -L$(LIBDIR)
|
|
||||||
#LDLIB := -l$(LIB) -lm
|
|
||||||
LDLIB := -l$(LIB)
|
|
||||||
|
|
||||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
|
||||||
|
|
||||||
CFLAGS += -std=gnu11
|
|
||||||
CFLAGS += -O2
|
|
||||||
CFLAGS += -g
|
|
||||||
# for gprof
|
|
||||||
# CFLAGS += -pg
|
|
||||||
CFLAGS += -Wall
|
|
||||||
CFLAGS += -Wextra
|
|
||||||
CFLAGS += -march=native
|
|
||||||
# Next one may be useful for valgrind (some invalid instructions)
|
|
||||||
# CFLAGS += -mno-tbm
|
|
||||||
CFLAGS += -Wmissing-declarations
|
|
||||||
CFLAGS += -Wno-unused-result
|
|
||||||
|
|
||||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
|
||||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
|
||||||
|
|
||||||
VALGRIND := valgrind
|
|
||||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
|
||||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
|
||||||
|
|
||||||
|
|
||||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
|
||||||
export PATH := .:$(PATH)
|
|
||||||
|
|
||||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 ccls
|
|
||||||
|
|
||||||
all: README.org ccls ex1 ex2
|
|
||||||
|
|
||||||
memcheck: memcheck1 memcheck2
|
|
||||||
|
|
||||||
memcheck1: aoc-c
|
|
||||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
|
||||||
|
|
||||||
memcheck2: aoc-c
|
|
||||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
|
||||||
|
|
||||||
compile: aoc-c
|
|
||||||
|
|
||||||
cpp: aoc-c.i
|
|
||||||
|
|
||||||
assembly: aoc-c.s
|
|
||||||
|
|
||||||
ex1: aoc-c
|
|
||||||
@$(TIME) ex1.bash -p 1 < $(INPUT)
|
|
||||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
|
||||||
|
|
||||||
ex2: aoc-c
|
|
||||||
@$(TIME) ex2.bash -p 2 < $(INPUT)
|
|
||||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
|
||||||
|
|
||||||
ccls: $(CCLSFILE)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json
|
|
||||||
|
|
||||||
.c:
|
|
||||||
@echo compiling $<
|
|
||||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
|
||||||
|
|
||||||
# generate pre-processed file (.i) and assembler (.s)
|
|
||||||
%.i: %.c
|
|
||||||
@echo generating $@
|
|
||||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
|
||||||
|
|
||||||
%.s: %.c
|
|
||||||
@echo generating $@
|
|
||||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
|
||||||
|
|
||||||
# generate README.org from README.html (must cleanup !)
|
|
||||||
%.org: %.html
|
|
||||||
@echo generating $@. Cleanup before commit !
|
|
||||||
@pandoc $< -o $@
|
|
||||||
|
|
||||||
# generate compile_commands.json
|
|
||||||
$(CCLSFILE): aoc-c.c Makefile
|
|
||||||
$(BEAR) -- make clean compile
|
|
||||||
|
|
||||||
bear: clean
|
|
||||||
@$(BEAR) -- make compile
|
|
||||||
@touch .ccls-root
|
|
||||||
@@ -1,76 +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:
|
|
||||||
|
|
||||||
#+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,4 +0,0 @@
|
|||||||
mxmxvkd kfcds sqjhc nhms (contains dairy, fish)
|
|
||||||
trh fvjkl sbzzf mxmxvkd (contains dairy)
|
|
||||||
sqjhc fvjkl (contains soy)
|
|
||||||
sqjhc mxmxvkd sbzzf (contains fish)
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# ex1.bash: Advent2020 game, day 21/game 1.
|
|
||||||
|
|
||||||
CMD=${0##*/}
|
|
||||||
shopt -s extglob
|
|
||||||
set -o noglob
|
|
||||||
|
|
||||||
declare -A CANBE=() A_RULES=() FOUND=() ALL_I=() ALL_A=() I_COUNT=()
|
|
||||||
declare -a R
|
|
||||||
declare -i count=0
|
|
||||||
|
|
||||||
# intersect the words of 2 strings into $1
|
|
||||||
intersect() {
|
|
||||||
local -n _res="$1"
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a _str1=($2) _str2=($3)
|
|
||||||
local _i _j
|
|
||||||
_res=""
|
|
||||||
for _i in "${_str1[@]}"; do
|
|
||||||
for _j in "${_str2[@]}"; do
|
|
||||||
[[ "$_i" == "$_j" ]] && _res+=" $_i"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
_res="${_res##*( )}"
|
|
||||||
}
|
|
||||||
# count words in a string and put result in $1
|
|
||||||
count() {
|
|
||||||
local -n _res="$1"
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a _str=($2)
|
|
||||||
_res=${#_str[@]}
|
|
||||||
}
|
|
||||||
# remove a word from a string and put result in $1
|
|
||||||
delw() {
|
|
||||||
local -n _res="$1"
|
|
||||||
local _w=$2
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a _str=($3)
|
|
||||||
local _i
|
|
||||||
_res=""
|
|
||||||
for _i in "${_str[@]}"; do
|
|
||||||
[[ $_i != "$_w" ]] && _res+=" $_i"
|
|
||||||
done
|
|
||||||
_res="${_res##*( )}"
|
|
||||||
_res="${_res%%*( )}"
|
|
||||||
}
|
|
||||||
|
|
||||||
REGEX="(.*) \(contains(.*)\)"
|
|
||||||
while read -r line; do
|
|
||||||
[[ "$line" =~ $REGEX ]]
|
|
||||||
ingr="${BASH_REMATCH[1]}"
|
|
||||||
allg="${BASH_REMATCH[2]}"
|
|
||||||
allg=${allg//,}
|
|
||||||
|
|
||||||
R[$count]="$ingr"
|
|
||||||
for ka in $allg; do
|
|
||||||
A_RULES[$ka]+=" $count"
|
|
||||||
ALL_A[$ka]=""
|
|
||||||
for ki in $ingr; do
|
|
||||||
ALL_I[$ki]=""
|
|
||||||
done
|
|
||||||
done
|
|
||||||
for ki in $ingr; do
|
|
||||||
(( I_COUNT[$ki]++ ))
|
|
||||||
done
|
|
||||||
((count++))
|
|
||||||
done
|
|
||||||
all_i="${!ALL_I[*]}"
|
|
||||||
for k in "${!ALL_A[@]}"; do
|
|
||||||
CANBE[$k]="$all_i"
|
|
||||||
done
|
|
||||||
|
|
||||||
solved=0
|
|
||||||
while ((solved==0)); do
|
|
||||||
solved=1
|
|
||||||
for allerg in "${!CANBE[@]}"; do
|
|
||||||
str="${CANBE[$allerg]}"
|
|
||||||
|
|
||||||
if [[ -v FOUND["$allerg"] ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
for rule in ${A_RULES[$allerg]}; do
|
|
||||||
intersect str "${R[$rule]}" "$str"
|
|
||||||
done
|
|
||||||
CANBE[$allerg]="$str"
|
|
||||||
|
|
||||||
count count "$str"
|
|
||||||
((count > 1)) && solved=0
|
|
||||||
if ((count==1)); then
|
|
||||||
word=$str #{CANBE[$allerg]}
|
|
||||||
# shellcheck disable=SC2034
|
|
||||||
FOUND[$allerg]="${CANBE[$allerg]}"
|
|
||||||
unset ALL_I["${CANBE[$allerg]}"]
|
|
||||||
for allerg1 in "${!CANBE[@]}"; do
|
|
||||||
if [[ "$allerg" != "$allerg1" ]]; then
|
|
||||||
delw CANBE["$allerg1"] "$word" "${CANBE[$allerg1]}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
for rule in "${!R[@]}"; do
|
|
||||||
delw R[$rule] "$word" "${R[$rule]}"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
res=0
|
|
||||||
for i in "${!ALL_I[@]}"; do
|
|
||||||
((res+=${I_COUNT[$i]}))
|
|
||||||
done
|
|
||||||
|
|
||||||
printf "%s: res=%d\n" "$CMD" "$res"
|
|
||||||
exit 0
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# ex2.bash: Advent2020 game, day 21/game 2.
|
|
||||||
|
|
||||||
CMD=${0##*/}
|
|
||||||
shopt -s extglob
|
|
||||||
set -o noglob
|
|
||||||
|
|
||||||
declare -A CANBE=() A_RULES=() FOUND=() ALL_I=() ALL_A=() I_COUNT=()
|
|
||||||
declare -a R
|
|
||||||
declare -i count=0
|
|
||||||
|
|
||||||
# intersect the words of 2 strings into $1
|
|
||||||
intersect() {
|
|
||||||
local -n _res="$1"
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a _str1=($2) _str2=($3)
|
|
||||||
local _i _j
|
|
||||||
_res=""
|
|
||||||
for _i in "${_str1[@]}"; do
|
|
||||||
for _j in "${_str2[@]}"; do
|
|
||||||
[[ "$_i" == "$_j" ]] && _res+=" $_i"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
_res="${_res##*( )}"
|
|
||||||
}
|
|
||||||
# count words in a string and put result in $1
|
|
||||||
count() {
|
|
||||||
local -n _res="$1"
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a _str=($2)
|
|
||||||
_res=${#_str[@]}
|
|
||||||
}
|
|
||||||
# remove a word from a string and put result in $1
|
|
||||||
delw() {
|
|
||||||
local -n _res="$1"
|
|
||||||
local _w=$2
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
local -a _str=($3)
|
|
||||||
local _i
|
|
||||||
_res=""
|
|
||||||
for _i in "${_str[@]}"; do
|
|
||||||
[[ $_i != "$_w" ]] && _res+=" $_i"
|
|
||||||
done
|
|
||||||
_res="${_res##*( )}"
|
|
||||||
_res="${_res%%*( )}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# simple bubble sort for alphanumeric array (ascending)
|
|
||||||
# args: 1: the array
|
|
||||||
# todo: add a parameter for asc/desc order.
|
|
||||||
sort_a() {
|
|
||||||
local -a array=( "$@" )
|
|
||||||
local -i i max=$(( ${#array[@]} - 1 ))
|
|
||||||
local val1 val2 tmp
|
|
||||||
|
|
||||||
for (( max= $(( ${#array[@]} - 1 )); max > 0; max-- )); do
|
|
||||||
for (( i=0; i<max; i++ )); do
|
|
||||||
val1=${array[$i]}
|
|
||||||
val2=${array[$((i + 1))]}
|
|
||||||
|
|
||||||
# switch if necessary
|
|
||||||
if [[ $val1 > $val2 ]]; then
|
|
||||||
tmp=$val1
|
|
||||||
array[$i]=$val2
|
|
||||||
array[$((i + 1))]=$tmp
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
echo "${array[@]}"
|
|
||||||
}
|
|
||||||
|
|
||||||
REGEX="(.*) \(contains(.*)\)"
|
|
||||||
while read -r line; do
|
|
||||||
[[ "$line" =~ $REGEX ]]
|
|
||||||
ingr="${BASH_REMATCH[1]}"
|
|
||||||
allg="${BASH_REMATCH[2]}"
|
|
||||||
allg=${allg//,}
|
|
||||||
|
|
||||||
R[$count]="$ingr"
|
|
||||||
for ka in $allg; do
|
|
||||||
A_RULES[$ka]+=" $count"
|
|
||||||
ALL_A[$ka]=""
|
|
||||||
for ki in $ingr; do
|
|
||||||
ALL_I[$ki]=""
|
|
||||||
done
|
|
||||||
done
|
|
||||||
for ki in $ingr; do
|
|
||||||
(( I_COUNT[$ki]++ ))
|
|
||||||
done
|
|
||||||
((count++))
|
|
||||||
done
|
|
||||||
all_i="${!ALL_I[*]}"
|
|
||||||
for k in "${!ALL_A[@]}"; do
|
|
||||||
CANBE[$k]="$all_i"
|
|
||||||
done
|
|
||||||
|
|
||||||
solved=0
|
|
||||||
while ((solved==0)); do
|
|
||||||
solved=1
|
|
||||||
for allerg in "${!CANBE[@]}"; do
|
|
||||||
str="${CANBE[$allerg]}"
|
|
||||||
|
|
||||||
if [[ -v FOUND["$allerg"] ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
for rule in ${A_RULES[$allerg]}; do
|
|
||||||
intersect str "${R[$rule]}" "$str"
|
|
||||||
done
|
|
||||||
CANBE[$allerg]="$str"
|
|
||||||
|
|
||||||
count count "$str"
|
|
||||||
((count > 1)) && solved=0
|
|
||||||
if ((count==1)); then
|
|
||||||
word=$str #{CANBE[$allerg]}
|
|
||||||
# shellcheck disable=SC2034
|
|
||||||
FOUND[$allerg]="${CANBE[$allerg]}"
|
|
||||||
unset ALL_I["${CANBE[$allerg]}"]
|
|
||||||
for allerg1 in "${!CANBE[@]}"; do
|
|
||||||
if [[ "$allerg" != "$allerg1" ]]; then
|
|
||||||
delw CANBE["$allerg1"] "$word" "${CANBE[$allerg1]}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
for rule in "${!R[@]}"; do
|
|
||||||
delw R[$rule] "$word" "${R[$rule]}"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
sorted=$(sort_a "${!CANBE[@]}")
|
|
||||||
res=""
|
|
||||||
for k in $sorted; do
|
|
||||||
res+=",${CANBE[$k]}"
|
|
||||||
done
|
|
||||||
|
|
||||||
printf "%s: res=%s\n" "$CMD" "${res##,}"
|
|
||||||
exit 0
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
Player 1:
|
|
||||||
1
|
|
||||||
10
|
|
||||||
28
|
|
||||||
29
|
|
||||||
13
|
|
||||||
11
|
|
||||||
35
|
|
||||||
7
|
|
||||||
43
|
|
||||||
8
|
|
||||||
30
|
|
||||||
25
|
|
||||||
4
|
|
||||||
5
|
|
||||||
17
|
|
||||||
32
|
|
||||||
22
|
|
||||||
39
|
|
||||||
50
|
|
||||||
46
|
|
||||||
16
|
|
||||||
26
|
|
||||||
45
|
|
||||||
38
|
|
||||||
21
|
|
||||||
|
|
||||||
Player 2:
|
|
||||||
19
|
|
||||||
40
|
|
||||||
2
|
|
||||||
12
|
|
||||||
49
|
|
||||||
23
|
|
||||||
34
|
|
||||||
47
|
|
||||||
9
|
|
||||||
14
|
|
||||||
20
|
|
||||||
24
|
|
||||||
42
|
|
||||||
37
|
|
||||||
48
|
|
||||||
44
|
|
||||||
27
|
|
||||||
6
|
|
||||||
33
|
|
||||||
18
|
|
||||||
15
|
|
||||||
3
|
|
||||||
36
|
|
||||||
41
|
|
||||||
31
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user