From 0d7424d9c6461829b875c517b968715e9aaae14b Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Sun, 18 Sep 2022 17:30:46 +0200 Subject: [PATCH] 2019 day 2 --- 2019/RESULTS.txt | 13 ++++ 2019/day02/EXAMPLE.txt | 1 + 2019/day02/EXAMPLE2.txt | 1 + 2019/day02/EXAMPLE3.txt | 1 + 2019/day02/EXAMPLE4.txt | 1 + 2019/day02/EXAMPLE5.txt | 1 + 2019/day02/INPUT.txt | 1 + 2019/day02/Makefile | 77 +++++++++++++++++++ 2019/day02/README.org | 159 ++++++++++++++++++++++++++++++++++++++++ 2019/day02/aoc-c.c | 150 +++++++++++++++++++++++++++++++++++++ 10 files changed, 405 insertions(+) create mode 100644 2019/day02/EXAMPLE.txt create mode 100644 2019/day02/EXAMPLE2.txt create mode 100644 2019/day02/EXAMPLE3.txt create mode 100644 2019/day02/EXAMPLE4.txt create mode 100644 2019/day02/EXAMPLE5.txt create mode 100644 2019/day02/INPUT.txt create mode 100644 2019/day02/Makefile create mode 100644 2019/day02/README.org create mode 100644 2019/day02/aoc-c.c diff --git a/2019/RESULTS.txt b/2019/RESULTS.txt index 20de860..1a9bc15 100644 --- a/2019/RESULTS.txt +++ b/2019/RESULTS.txt @@ -12,3 +12,16 @@ 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 diff --git a/2019/day02/EXAMPLE.txt b/2019/day02/EXAMPLE.txt new file mode 100644 index 0000000..2912131 --- /dev/null +++ b/2019/day02/EXAMPLE.txt @@ -0,0 +1 @@ +1,9,10,3,2,3,11,0,99,30,40,50 diff --git a/2019/day02/EXAMPLE2.txt b/2019/day02/EXAMPLE2.txt new file mode 100644 index 0000000..a2389ec --- /dev/null +++ b/2019/day02/EXAMPLE2.txt @@ -0,0 +1 @@ +1,0,0,0,99 diff --git a/2019/day02/EXAMPLE3.txt b/2019/day02/EXAMPLE3.txt new file mode 100644 index 0000000..e795b14 --- /dev/null +++ b/2019/day02/EXAMPLE3.txt @@ -0,0 +1 @@ +2,3,0,3,99 diff --git a/2019/day02/EXAMPLE4.txt b/2019/day02/EXAMPLE4.txt new file mode 100644 index 0000000..89e8255 --- /dev/null +++ b/2019/day02/EXAMPLE4.txt @@ -0,0 +1 @@ +2,4,4,5,99,0 diff --git a/2019/day02/EXAMPLE5.txt b/2019/day02/EXAMPLE5.txt new file mode 100644 index 0000000..f4b112c --- /dev/null +++ b/2019/day02/EXAMPLE5.txt @@ -0,0 +1 @@ +1,1,1,4,99,5,6,0,99 diff --git a/2019/day02/INPUT.txt b/2019/day02/INPUT.txt new file mode 100644 index 0000000..04b9352 --- /dev/null +++ b/2019/day02/INPUT.txt @@ -0,0 +1 @@ +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 diff --git a/2019/day02/Makefile b/2019/day02/Makefile new file mode 100644 index 0000000..04f5b05 --- /dev/null +++ b/2019/day02/Makefile @@ -0,0 +1,77 @@ +# AOC daily Makefile - GNU make only. +# +# Copyright (C) 2021 Bruno Raoult ("br") +# Licensed under the GNU General Public License v3.0 or later. +# Some rights reserved. See COPYING. +# +# You should have received a copy of the GNU General Public License along with this +# program. If not, see . +# +# 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=gnu99 +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 + +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: ex1 ex2 + +memcheck: memcheck1 + +memcheck1: + @valgrind -q -s --track-origins=yes aoc-c -p 1 < $(INPUT) + +memcheck2: + @valgrind -q -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 + +.c: + @echo compiling $< + @$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@ + +.c.s: + @echo generating $@ + @$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@ diff --git a/2019/day02/README.org b/2019/day02/README.org new file mode 100644 index 0000000..3277553 --- /dev/null +++ b/2019/day02/README.org @@ -0,0 +1,159 @@ +** --- 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: ** diff --git a/2019/day02/aoc-c.c b/2019/day02/aoc-c.c new file mode 100644 index 0000000..5ed1d5d --- /dev/null +++ b/2019/day02/aoc-c.c @@ -0,0 +1,150 @@ +/* aoc-c.c: Advent of Code 2019, day 2 parts 1 & 2 + * + * Copyright (C) 2021 Bruno Raoult ("br") + * Licensed under the GNU General Public License v3.0 or later. + * Some rights reserved. See COPYING. + * + * You should have received a copy of the GNU General Public License along with this + * program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include +#include +#include +#include + +#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)); + + exit (0); +}