2019 day 5 init (with day 2 code)
This commit is contained in:
1
2019/day05/EXAMPLE.txt
Normal file
1
2019/day05/EXAMPLE.txt
Normal file
@@ -0,0 +1 @@
|
||||
1002,4,3,4
|
1
2019/day05/EXAMPLE2.txt
Normal file
1
2019/day05/EXAMPLE2.txt
Normal file
@@ -0,0 +1 @@
|
||||
1101,100,-1,4,0
|
1
2019/day05/INPUT.txt
Normal file
1
2019/day05/INPUT.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,225,1,225,6,6,1100,1,238,225,104,0,1101,86,8,225,1101,82,69,225,101,36,65,224,1001,224,-106,224,4,224,1002,223,8,223,1001,224,5,224,1,223,224,223,102,52,148,224,101,-1144,224,224,4,224,1002,223,8,223,101,1,224,224,1,224,223,223,1102,70,45,225,1002,143,48,224,1001,224,-1344,224,4,224,102,8,223,223,101,7,224,224,1,223,224,223,1101,69,75,225,1001,18,85,224,1001,224,-154,224,4,224,102,8,223,223,101,2,224,224,1,224,223,223,1101,15,59,225,1102,67,42,224,101,-2814,224,224,4,224,1002,223,8,223,101,3,224,224,1,223,224,223,1101,28,63,225,1101,45,22,225,1101,90,16,225,2,152,92,224,1001,224,-1200,224,4,224,102,8,223,223,101,7,224,224,1,223,224,223,1101,45,28,224,1001,224,-73,224,4,224,1002,223,8,223,101,7,224,224,1,224,223,223,1,14,118,224,101,-67,224,224,4,224,1002,223,8,223,1001,224,2,224,1,223,224,223,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,7,677,677,224,102,2,223,223,1005,224,329,1001,223,1,223,1008,226,226,224,1002,223,2,223,1005,224,344,1001,223,1,223,1107,677,226,224,1002,223,2,223,1006,224,359,1001,223,1,223,107,677,677,224,102,2,223,223,1005,224,374,101,1,223,223,1108,677,226,224,102,2,223,223,1005,224,389,1001,223,1,223,1007,677,677,224,1002,223,2,223,1005,224,404,101,1,223,223,1008,677,226,224,102,2,223,223,1005,224,419,101,1,223,223,1108,226,677,224,102,2,223,223,1006,224,434,1001,223,1,223,8,677,226,224,1002,223,2,223,1005,224,449,101,1,223,223,1008,677,677,224,1002,223,2,223,1006,224,464,1001,223,1,223,1108,226,226,224,1002,223,2,223,1005,224,479,1001,223,1,223,1007,226,677,224,102,2,223,223,1005,224,494,1001,223,1,223,1007,226,226,224,102,2,223,223,1005,224,509,101,1,223,223,107,677,226,224,1002,223,2,223,1006,224,524,1001,223,1,223,108,677,677,224,102,2,223,223,1006,224,539,101,1,223,223,7,677,226,224,102,2,223,223,1006,224,554,1001,223,1,223,1107,226,677,224,102,2,223,223,1005,224,569,101,1,223,223,108,677,226,224,1002,223,2,223,1006,224,584,101,1,223,223,108,226,226,224,102,2,223,223,1006,224,599,1001,223,1,223,1107,226,226,224,102,2,223,223,1006,224,614,1001,223,1,223,8,226,677,224,102,2,223,223,1006,224,629,1001,223,1,223,107,226,226,224,102,2,223,223,1005,224,644,101,1,223,223,8,226,226,224,102,2,223,223,1006,224,659,101,1,223,223,7,226,677,224,102,2,223,223,1005,224,674,101,1,223,223,4,223,99,226
|
93
2019/day05/Makefile
Normal file
93
2019/day05/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# Copyright (C) 2021 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
|
||||
|
||||
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 $@
|
104
2019/day05/README.org
Normal file
104
2019/day05/README.org
Normal file
@@ -0,0 +1,104 @@
|
||||
** --- 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:2][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?/
|
||||
|
||||
To begin, [[file:5/input][get your puzzle input]].
|
150
2019/day05/aoc-c.c
Normal file
150
2019/day05/aoc-c.c
Normal file
@@ -0,0 +1,150 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 5 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));
|
||||
free(p);
|
||||
exit (0);
|
||||
}
|
Reference in New Issue
Block a user