2019 day 2

This commit is contained in:
2022-09-18 17:30:46 +02:00
parent d9b0f7b7c4
commit 0d7424d9c6
10 changed files with 405 additions and 0 deletions

View File

@@ -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

1
2019/day02/EXAMPLE.txt Normal file
View File

@@ -0,0 +1 @@
1,9,10,3,2,3,11,0,99,30,40,50

1
2019/day02/EXAMPLE2.txt Normal file
View File

@@ -0,0 +1 @@
1,0,0,0,99

1
2019/day02/EXAMPLE3.txt Normal file
View File

@@ -0,0 +1 @@
2,3,0,3,99

1
2019/day02/EXAMPLE4.txt Normal file
View File

@@ -0,0 +1 @@
2,4,4,5,99,0

1
2019/day02/EXAMPLE5.txt Normal file
View File

@@ -0,0 +1 @@
1,1,1,4,99,5,6,0,99

1
2019/day02/INPUT.txt Normal file
View File

@@ -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

77
2019/day02/Makefile Normal file
View File

@@ -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 <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=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 $@

159
2019/day02/README.org Normal file
View File

@@ -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: **

150
2019/day02/aoc-c.c Normal file
View File

@@ -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 <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));
exit (0);
}