From 130f2a4d543d5671bbd5843b96280fbff0bc3af4 Mon Sep 17 00:00:00 2001
From: Bruno
Date: Tue, 4 Oct 2022 07:34:29 +0200
Subject: [PATCH] 2019 day 9 init from day 7
---
2019/day09/EXAMPLE.txt | 1 +
2019/day09/EXAMPLE2.txt | 1 +
2019/day09/EXAMPLE3.txt | 1 +
2019/day09/INPUT.txt | 1 +
2019/day09/Makefile | 93 +++++++++++++++
2019/day09/README.org | 81 +++++++++++++
2019/day09/aoc-c.c | 258 ++++++++++++++++++++++++++++++++++++++++
7 files changed, 436 insertions(+)
create mode 100644 2019/day09/EXAMPLE.txt
create mode 100644 2019/day09/EXAMPLE2.txt
create mode 100644 2019/day09/EXAMPLE3.txt
create mode 100644 2019/day09/INPUT.txt
create mode 100644 2019/day09/Makefile
create mode 100644 2019/day09/README.org
create mode 100644 2019/day09/aoc-c.c
diff --git a/2019/day09/EXAMPLE.txt b/2019/day09/EXAMPLE.txt
new file mode 100644
index 0000000..2ce40b6
--- /dev/null
+++ b/2019/day09/EXAMPLE.txt
@@ -0,0 +1 @@
+109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99
diff --git a/2019/day09/EXAMPLE2.txt b/2019/day09/EXAMPLE2.txt
new file mode 100644
index 0000000..50a032d
--- /dev/null
+++ b/2019/day09/EXAMPLE2.txt
@@ -0,0 +1 @@
+1102,34915192,34915192,7,4,7,99,0
diff --git a/2019/day09/EXAMPLE3.txt b/2019/day09/EXAMPLE3.txt
new file mode 100644
index 0000000..f0c3e19
--- /dev/null
+++ b/2019/day09/EXAMPLE3.txt
@@ -0,0 +1 @@
+104,1125899906842624,99
diff --git a/2019/day09/INPUT.txt b/2019/day09/INPUT.txt
new file mode 100644
index 0000000..0ad4957
--- /dev/null
+++ b/2019/day09/INPUT.txt
@@ -0,0 +1 @@
+1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1102,3,1,1000,109,988,209,12,9,1000,209,6,209,3,203,0,1008,1000,1,63,1005,63,65,1008,1000,2,63,1005,63,904,1008,1000,0,63,1005,63,58,4,25,104,0,99,4,0,104,0,99,4,17,104,0,99,0,0,1101,20,0,1007,1101,0,197,1022,1102,475,1,1028,1102,30,1,1008,1101,25,0,1010,1102,1,23,1009,1101,0,22,1013,1101,470,0,1029,1102,24,1,1014,1102,1,39,1005,1101,31,0,1003,1101,807,0,1026,1101,0,26,1018,1102,1,804,1027,1101,0,0,1020,1102,1,38,1017,1101,0,27,1016,1102,443,1,1024,1101,0,36,1006,1102,21,1,1015,1101,28,0,1001,1102,33,1,1019,1102,1,37,1011,1102,1,190,1023,1101,0,434,1025,1101,34,0,1004,1102,1,1,1021,1101,0,29,1012,1102,1,32,1002,1101,35,0,1000,109,30,2105,1,-7,1001,64,1,64,1105,1,199,4,187,1002,64,2,64,109,-23,2101,0,-5,63,1008,63,32,63,1005,63,225,4,205,1001,64,1,64,1105,1,225,1002,64,2,64,109,7,2102,1,-5,63,1008,63,23,63,1005,63,251,4,231,1001,64,1,64,1106,0,251,1002,64,2,64,109,-16,2101,0,2,63,1008,63,33,63,1005,63,275,1001,64,1,64,1106,0,277,4,257,1002,64,2,64,109,10,21102,40,1,4,1008,1012,40,63,1005,63,299,4,283,1106,0,303,1001,64,1,64,1002,64,2,64,109,7,2102,1,-9,63,1008,63,33,63,1005,63,327,1001,64,1,64,1105,1,329,4,309,1002,64,2,64,109,-17,2107,34,2,63,1005,63,347,4,335,1105,1,351,1001,64,1,64,1002,64,2,64,109,1,1201,8,0,63,1008,63,23,63,1005,63,375,1001,64,1,64,1106,0,377,4,357,1002,64,2,64,109,-4,2108,31,8,63,1005,63,395,4,383,1105,1,399,1001,64,1,64,1002,64,2,64,109,3,1201,8,0,63,1008,63,36,63,1005,63,421,4,405,1105,1,425,1001,64,1,64,1002,64,2,64,109,25,2105,1,1,4,431,1001,64,1,64,1105,1,443,1002,64,2,64,109,-3,1205,0,459,1001,64,1,64,1106,0,461,4,449,1002,64,2,64,109,-2,2106,0,10,4,467,1106,0,479,1001,64,1,64,1002,64,2,64,109,12,1206,-9,495,1001,64,1,64,1106,0,497,4,485,1002,64,2,64,109,-39,1207,9,36,63,1005,63,519,4,503,1001,64,1,64,1105,1,519,1002,64,2,64,109,11,1202,-1,1,63,1008,63,28,63,1005,63,541,4,525,1105,1,545,1001,64,1,64,1002,64,2,64,109,6,2107,24,1,63,1005,63,565,1001,64,1,64,1106,0,567,4,551,1002,64,2,64,109,1,1207,-3,35,63,1005,63,583,1106,0,589,4,573,1001,64,1,64,1002,64,2,64,109,1,21102,41,1,5,1008,1015,40,63,1005,63,613,1001,64,1,64,1105,1,615,4,595,1002,64,2,64,109,-2,2108,22,1,63,1005,63,635,1001,64,1,64,1105,1,637,4,621,1002,64,2,64,109,-10,1208,4,33,63,1005,63,653,1106,0,659,4,643,1001,64,1,64,1002,64,2,64,109,16,1206,6,673,4,665,1106,0,677,1001,64,1,64,1002,64,2,64,109,-4,1202,-8,1,63,1008,63,35,63,1005,63,701,1001,64,1,64,1105,1,703,4,683,1002,64,2,64,109,13,21108,42,42,-8,1005,1015,721,4,709,1105,1,725,1001,64,1,64,1002,64,2,64,109,-18,21107,43,44,5,1005,1010,743,4,731,1106,0,747,1001,64,1,64,1002,64,2,64,109,-11,1208,8,32,63,1005,63,765,4,753,1106,0,769,1001,64,1,64,1002,64,2,64,109,15,21101,44,0,5,1008,1014,47,63,1005,63,789,1105,1,795,4,775,1001,64,1,64,1002,64,2,64,109,13,2106,0,5,1106,0,813,4,801,1001,64,1,64,1002,64,2,64,109,-12,21108,45,43,0,1005,1010,829,1106,0,835,4,819,1001,64,1,64,1002,64,2,64,109,-4,21107,46,45,10,1005,1016,855,1001,64,1,64,1106,0,857,4,841,1002,64,2,64,109,3,21101,47,0,5,1008,1014,47,63,1005,63,883,4,863,1001,64,1,64,1106,0,883,1002,64,2,64,109,10,1205,2,901,4,889,1001,64,1,64,1105,1,901,4,64,99,21102,27,1,1,21102,915,1,0,1106,0,922,21201,1,13433,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21101,0,942,0,1106,0,922,22102,1,1,-1,21201,-2,-3,1,21102,1,957,0,1105,1,922,22201,1,-1,-2,1106,0,968,21202,-2,1,-2,109,-3,2106,0,0
diff --git a/2019/day09/Makefile b/2019/day09/Makefile
new file mode 100644
index 0000000..7a1c6da
--- /dev/null
+++ b/2019/day09/Makefile
@@ -0,0 +1,93 @@
+# AOC daily Makefile - GNU make only.
+#
+# Copyright (C) 2021-2022 Bruno Raoult ("br")
+# Licensed under the GNU General Public License v3.0 or later.
+# Some rights reserved. See COPYING.
+#
+# You should have received a copy of the GNU General Public License along with this
+# program. If not, see .
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+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 $@
diff --git a/2019/day09/README.org b/2019/day09/README.org
new file mode 100644
index 0000000..1d28a35
--- /dev/null
+++ b/2019/day09/README.org
@@ -0,0 +1,81 @@
+** --- 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?/
+
+To begin, [[file:9/input][get your puzzle input]].
+
+Answer:
+
+You can also [Shareon
+[[https://twitter.com/intent/tweet?text=%22Sensor+Boost%22+%2D+Day+9+%2D+Advent+of+Code+2019&url=https%3A%2F%2Fadventofcode%2Ecom%2F2019%2Fday%2F9&related=ericwastl&hashtags=AdventOfCode][Twitter]]
+[[javascript:void(0);][Mastodon]]] this puzzle.
diff --git a/2019/day09/aoc-c.c b/2019/day09/aoc-c.c
new file mode 100644
index 0000000..25a300f
--- /dev/null
+++ b/2019/day09/aoc-c.c
@@ -0,0 +1,258 @@
+/* aoc-c.c: Advent of Code 2019, day 9 parts 1 & 2
+ *
+ * Copyright (C) 2022 Bruno Raoult ("br")
+ * Licensed under the GNU General Public License v3.0 or later.
+ * Some rights reserved. See COPYING.
+ *
+ * You should have received a copy of the GNU General Public License along with this
+ * program. If not, see .
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include
+#include
+#include
+#include
+
+#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 */
+ 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 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);
+}