Working day 17 part 1
This commit is contained in:
@ -83,28 +83,33 @@ done
|
|||||||
CHECKPOINT_ARRAY[$END_POSITION]=0
|
CHECKPOINT_ARRAY[$END_POSITION]=0
|
||||||
printf "%s " "${!CHECKPOINT_ARRAY[@]}"
|
printf "%s " "${!CHECKPOINT_ARRAY[@]}"
|
||||||
printf "\n"
|
printf "\n"
|
||||||
|
CHECKPOINT_ARRAY_LEN=${#CHECKPOINT_ARRAY[@]}
|
||||||
|
|
||||||
# Iterate over checkpoints and print pairings
|
# Iterate over checkpoints and print pairings
|
||||||
declare -A CHECKPOINT_PAIRS
|
declare -A CHECKPOINT_PAIRS
|
||||||
declare -A CHECKPOINT_PAIR_WEIGHTS
|
declare -A CHECKPOINT_PAIR_WEIGHTS
|
||||||
|
PREV_UP=$(( 2 * 5 * 7 ))
|
||||||
|
PREV_DOWN=$(( 3 * 5 * 7 ))
|
||||||
|
PREV_LEFT=$(( 2 * 3 * 5 ))
|
||||||
|
PREV_RIGHT=$(( 2 * 3 * 7 ))
|
||||||
get_weight_change () {
|
get_weight_change () {
|
||||||
local POSITION=$1
|
local POSITION=$1
|
||||||
local NEXT_POSITION=$2
|
local NEXT_POSITION=$2
|
||||||
local DIRECTION=$3
|
local DIRECTION=$3
|
||||||
# For same directions, weight change is 1
|
# Check if next position is moving in line with the previous direction
|
||||||
if [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_UP ]] && [[ $(( DIRECTION % 2 )) -eq 0 ]]
|
if [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_UP ]] && [[ $(( DIRECTION % PREV_UP )) -eq 0 ]]
|
||||||
then
|
then
|
||||||
printf "1"
|
printf "1"
|
||||||
return 0
|
return 0
|
||||||
elif [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_DOWN ]] && [[ $(( DIRECTION % 3 )) -eq 0 ]]
|
elif [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_DOWN ]] && [[ $(( DIRECTION % PREV_DOWN )) -eq 0 ]]
|
||||||
then
|
then
|
||||||
printf "1"
|
printf "1"
|
||||||
return 0
|
return 0
|
||||||
elif [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_LEFT ]] && [[ $(( DIRECTION % 5 )) -eq 0 ]]
|
elif [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_LEFT ]] && [[ $(( DIRECTION % PREV_LEFT )) -eq 0 ]]
|
||||||
then
|
then
|
||||||
printf "1"
|
printf "1"
|
||||||
return 0
|
return 0
|
||||||
elif [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_RIGHT ]] && [[ $(( DIRECTION % 7 )) -eq 0 ]]
|
elif [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_RIGHT ]] && [[ $(( DIRECTION % PREV_RIGHT )) -eq 0 ]]
|
||||||
then
|
then
|
||||||
printf "1"
|
printf "1"
|
||||||
return 0
|
return 0
|
||||||
@ -113,18 +118,22 @@ get_weight_change () {
|
|||||||
printf "1000"
|
printf "1000"
|
||||||
}
|
}
|
||||||
recurse_travel () {
|
recurse_travel () {
|
||||||
local POSITION=$1
|
local POSITION=$1 # Current position
|
||||||
local CHECKPOINT=$2
|
local CHECKPOINT=$2 # Previous checkpoint
|
||||||
local DIRECTION=$3
|
local DIRECTION=$3 # Allowed adjacent tiles
|
||||||
local WEIGHT=$4
|
local WEIGHT=$4 # Weightage so far
|
||||||
local UP=$(( POSITION - MAP_WIDTH ))
|
|
||||||
local DOWN=$(( POSITION + MAP_WIDTH ))
|
|
||||||
local LEFT=$(( POSITION - 1 ))
|
|
||||||
local RIGHT=$(( POSITION + 1 ))
|
|
||||||
# Search adjacent tiles
|
# Search adjacent tiles
|
||||||
# Recurse if it's movable
|
# Recurse if it's movable
|
||||||
# Add a checkpoint pair and weights if checkpoint found
|
# Add a checkpoint pair and weights if checkpoint found
|
||||||
if [[ $(( DIRECTION % 2 )) -eq 0 ]] && [[ $UP -gt 0 ]]
|
# 2 : Up
|
||||||
|
# 3 : Down
|
||||||
|
# 5 : Left
|
||||||
|
# 7 : Right
|
||||||
|
if [[ $(( DIRECTION % 2 )) -eq 0 ]]
|
||||||
|
then
|
||||||
|
local UP=$(( POSITION + DIR_UP ))
|
||||||
|
if [[ $UP -gt 0 ]]
|
||||||
then
|
then
|
||||||
if [[ ${MAP_ARRAY[$UP]} == "." ]]
|
if [[ ${MAP_ARRAY[$UP]} == "." ]]
|
||||||
then
|
then
|
||||||
@ -133,11 +142,15 @@ recurse_travel () {
|
|||||||
elif [[ -v CHECKPOINT_ARRAY[$UP] ]]
|
elif [[ -v CHECKPOINT_ARRAY[$UP] ]]
|
||||||
then
|
then
|
||||||
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$UP" "$DIRECTION" )
|
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$UP" "$DIRECTION" )
|
||||||
CHECKPOINT_PAIRS[$UP]=$CHECKPOINT
|
CHECKPOINT_PAIRS["$CHECKPOINT-$UP"]=0
|
||||||
CHECKPOINT_PAIR_WEIGHTS["$UP-$CHECKPOINT"]=$(( WEIGHT + WEIGHT_CHANGE ))
|
CHECKPOINT_PAIR_WEIGHTS["$CHECKPOINT-$UP"]=$(( WEIGHT + WEIGHT_CHANGE ))
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if [[ $(( DIRECTION % 3 )) -eq 0 ]] && [[ $DOWN -lt $MAP_LEN ]]
|
if [[ $(( DIRECTION % 3 )) -eq 0 ]] && [[ $DOWN -lt $MAP_LEN ]]
|
||||||
|
then
|
||||||
|
local DOWN=$(( POSITION + DIR_DOWN ))
|
||||||
|
if [[ $DOWN -lt $MAP_LEN ]]
|
||||||
then
|
then
|
||||||
if [[ ${MAP_ARRAY[$DOWN]} == "." ]]
|
if [[ ${MAP_ARRAY[$DOWN]} == "." ]]
|
||||||
then
|
then
|
||||||
@ -146,12 +159,14 @@ recurse_travel () {
|
|||||||
elif [[ -v CHECKPOINT_ARRAY[$DOWN] ]]
|
elif [[ -v CHECKPOINT_ARRAY[$DOWN] ]]
|
||||||
then
|
then
|
||||||
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$DOWN" "$DIRECTION" )
|
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$DOWN" "$DIRECTION" )
|
||||||
CHECKPOINT_PAIRS[$DOWN]=$CHECKPOINT
|
CHECKPOINT_PAIRS["$CHECKPOINT-$DOWN"]=0
|
||||||
CHECKPOINT_PAIR_WEIGHTS["$DOWN-$CHECKPOINT"]=$(( WEIGHT + WEIGHT_CHANGE ))
|
CHECKPOINT_PAIR_WEIGHTS["$CHECKPOINT-$DOWN"]=$(( WEIGHT + WEIGHT_CHANGE ))
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if [[ $(( DIRECTION % 5 )) -eq 0 ]]
|
if [[ $(( DIRECTION % 5 )) -eq 0 ]]
|
||||||
then
|
then
|
||||||
|
local LEFT=$(( POSITION + DIR_LEFT ))
|
||||||
if [[ ${MAP_ARRAY[$LEFT]} == "." ]]
|
if [[ ${MAP_ARRAY[$LEFT]} == "." ]]
|
||||||
then
|
then
|
||||||
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$LEFT" "$DIRECTION" )
|
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$LEFT" "$DIRECTION" )
|
||||||
@ -159,12 +174,13 @@ recurse_travel () {
|
|||||||
elif [[ -v CHECKPOINT_ARRAY[$LEFT] ]]
|
elif [[ -v CHECKPOINT_ARRAY[$LEFT] ]]
|
||||||
then
|
then
|
||||||
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$LEFT" "$DIRECTION" )
|
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$LEFT" "$DIRECTION" )
|
||||||
CHECKPOINT_PAIRS[$LEFT]=$CHECKPOINT
|
CHECKPOINT_PAIRS["$CHECKPOINT-$LEFT"]=0
|
||||||
CHECKPOINT_PAIR_WEIGHTS["$LEFT-$CHECKPOINT"]=$(( WEIGHT + WEIGHT_CHANGE ))
|
CHECKPOINT_PAIR_WEIGHTS["$CHECKPOINT-$LEFT"]=$(( WEIGHT + WEIGHT_CHANGE ))
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if [[ $(( DIRECTION % 7 )) -eq 0 ]]
|
if [[ $(( DIRECTION % 7 )) -eq 0 ]]
|
||||||
then
|
then
|
||||||
|
local RIGHT=$(( POSITION + DIR_RIGHT ))
|
||||||
if [[ ${MAP_ARRAY[$RIGHT]} == "." ]]
|
if [[ ${MAP_ARRAY[$RIGHT]} == "." ]]
|
||||||
then
|
then
|
||||||
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$RIGHT" "$DIRECTION" )
|
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$RIGHT" "$DIRECTION" )
|
||||||
@ -172,25 +188,66 @@ recurse_travel () {
|
|||||||
elif [[ -v CHECKPOINT_ARRAY[$RIGHT] ]]
|
elif [[ -v CHECKPOINT_ARRAY[$RIGHT] ]]
|
||||||
then
|
then
|
||||||
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$RIGHT" "$DIRECTION" )
|
WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$RIGHT" "$DIRECTION" )
|
||||||
CHECKPOINT_PAIRS[$RIGHT]=$CHECKPOINT
|
CHECKPOINT_PAIRS["$CHECKPOINT-$RIGHT"]=0
|
||||||
CHECKPOINT_PAIR_WEIGHTS["$RIGHT-$CHECKPOINT"]=$(( WEIGHT + WEIGHT_CHANGE ))
|
CHECKPOINT_PAIR_WEIGHTS["$CHECKPOINT-$RIGHT"]=$(( WEIGHT + WEIGHT_CHANGE ))
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
ITER=99999
|
||||||
for CHECKPOINT in "${!CHECKPOINT_ARRAY[@]}"
|
for CHECKPOINT in "${!CHECKPOINT_ARRAY[@]}"
|
||||||
do
|
do
|
||||||
recurse_travel "$CHECKPOINT" "$CHECKPOINT" "$CHECKPOINT" "$(( 2 * 3 * 5 * 7 ))" "0"
|
recurse_travel "$CHECKPOINT" "$CHECKPOINT" "$(( 2 * 3 * 5 * 7 ))" "0"
|
||||||
|
(( ITER-- ))
|
||||||
|
if [[ $ITER -eq 0 ]] ; then break ;fi
|
||||||
done
|
done
|
||||||
for CHECKPOINT in "${!CHECKPOINT_PAIRS[@]}"
|
for CHECKPOINT in "${!CHECKPOINT_PAIRS[@]}"
|
||||||
do
|
do
|
||||||
printf "DEST %s from checkpoint %s\n" "${CHECKPOINT_PAIRS[$CHECKPOINT]}" "$CHECKPOINT"
|
printf "Dest %s from checkpoint %s\n" "${CHECKPOINT_PAIRS[$CHECKPOINT]}" "$CHECKPOINT"
|
||||||
done
|
done | sort
|
||||||
for CHECKPOINT in "${!CHECKPOINT_PAIR_WEIGHTS[@]}"
|
for CHECKPOINT in "${!CHECKPOINT_PAIR_WEIGHTS[@]}"
|
||||||
do
|
do
|
||||||
printf "Weight %s for checkpoint pair %s\n" "${CHECKPOINT_PAIR_WEIGHTS[$CHECKPOINT]}" "$CHECKPOINT"
|
printf "Weight %s for checkpoint pair %s\n" "${CHECKPOINT_PAIR_WEIGHTS[$CHECKPOINT]}" "$CHECKPOINT"
|
||||||
|
done | sort
|
||||||
|
|
||||||
|
if [[ ${#CHECKPOINT_PAIRS[@]} -ne ${#CHECKPOINT_PAIR_WEIGHTS[@]} ]]
|
||||||
|
then
|
||||||
|
printf "Checkpoint count with weight counts do not match.\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Map out full paths for calculate final results for it
|
||||||
|
# Quite akin to BFS
|
||||||
|
declare -A FINAL_PATH
|
||||||
|
FINAL_PATH[$START_POSITION]=0
|
||||||
|
for (( i=0 ; i<CHECKPOINT_ARRAY_LEN ; i+= 1 )) # Start to end should only have these many iterations
|
||||||
|
do
|
||||||
|
for PATH in "${!FINAL_PATH[@]}"
|
||||||
|
do
|
||||||
|
CHECKPOINT=${PATH##*-}
|
||||||
|
PATH_SCORE=${FINAL_PATH[$PATH]}
|
||||||
|
if [[ $CHECKPOINT -eq $END_POSITION ]] # This path has completed
|
||||||
|
then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
for NEXT_CHECKPOINT in "${!CHECKPOINT_ARRAY[@]}" # Check if there is a next mapping
|
||||||
|
do
|
||||||
|
if [[ $PATH =~ -$NEXT_CHECKPOINT- ]]; then continue; fi # Prevent loops
|
||||||
|
PAIR="$CHECKPOINT-$NEXT_CHECKPOINT"
|
||||||
|
if [[ -v CHECKPOINT_PAIRS[$PAIR] ]]
|
||||||
|
then
|
||||||
|
FINAL_PATH["$PATH-$NEXT_CHECKPOINT"]=$(( PATH_SCORE + ${CHECKPOINT_PAIR_WEIGHTS[$PAIR]} ))
|
||||||
|
unset "FINAL_PATH[$PATH]"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
# Score the path
|
for PATH in "${!FINAL_PATH[@]}"
|
||||||
#
|
do
|
||||||
|
END=${PATH##*-}
|
||||||
|
if [[ $END == "$END_POSITION" ]]
|
||||||
|
then
|
||||||
|
printf "Path: %s weight: %s \n" "$PATH" "${FINAL_PATH[$PATH]}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
print_map
|
#print_map
|
||||||
|
5
2024/day-17/input
Normal file
5
2024/day-17/input
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Register A: 64196994
|
||||||
|
Register B: 0
|
||||||
|
Register C: 0
|
||||||
|
|
||||||
|
Program: 2,4,1,1,7,5,1,5,4,0,0,3,5,5,3,0
|
145
2024/day-17/solution-1.sh
Normal file
145
2024/day-17/solution-1.sh
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
FILE=$1
|
||||||
|
ITER=99
|
||||||
|
|
||||||
|
REG_A=$(grep 'Register A:' "$FILE" | cut -f2 -d: )
|
||||||
|
REG_B=$(grep 'Register B:' "$FILE" | cut -f2 -d: )
|
||||||
|
REG_C=$(grep 'Register C:' "$FILE" | cut -f2 -d: )
|
||||||
|
read -r -a INPUT <<< "$(grep 'Program:' "$FILE" | cut -f2 -d: | tr ',' ' ' )"
|
||||||
|
INPUT_LEN=${#INPUT[@]}
|
||||||
|
|
||||||
|
printf "Registers A: %s B: %s C: %s\n" "$REG_A" "$REG_B" "$REG_C" >&2
|
||||||
|
printf "Input : " >&2
|
||||||
|
printf "%s " "${INPUT[@]}" >&2
|
||||||
|
printf "\n" >&2
|
||||||
|
|
||||||
|
adv () { # OPCODE 0
|
||||||
|
printf "OPCODE : 0 OP: adv OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$( get_combo "$1" )
|
||||||
|
REG_A=$(( REG_A / (2 ** OPERAND) ))
|
||||||
|
}
|
||||||
|
bxl () { # OPCODE 1
|
||||||
|
printf "OPCODE : 1 OP: bxl OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$1
|
||||||
|
REG_B=$(( REG_B ^ OPERAND ))
|
||||||
|
}
|
||||||
|
bst () { # OPCODE 2
|
||||||
|
printf "OPCODE : 2 OP: bst OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$( get_combo "$1" )
|
||||||
|
REG_B=$(( OPERAND % 8 ))
|
||||||
|
}
|
||||||
|
jnz () { # OPCODE 3
|
||||||
|
printf "OPCODE : 3 OP: jnz OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$1
|
||||||
|
if [[ $REG_A -eq 0 ]]
|
||||||
|
then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
POINTER=$OPERAND
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
bxc () { # OPCODE 4
|
||||||
|
printf "OPCODE : 4 OP: bxc OPERAND: %s\n" "$1" >&2
|
||||||
|
# OPERAND=$1 # Deprecated for legacy reasons
|
||||||
|
REG_B=$(( REG_B ^ REG_C ))
|
||||||
|
}
|
||||||
|
out () { # OPCODE 5
|
||||||
|
printf "OPCODE : 5 OP: out OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$( get_combo "$1" )
|
||||||
|
printf "%s\n" "$(( OPERAND % 8 ))"
|
||||||
|
}
|
||||||
|
bdv () { # OPCODE 6
|
||||||
|
printf "OPCODE : 6 OP: bdv OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$( get_combo "$1" )
|
||||||
|
REG_B=$(( REG_A / (2 ** OPERAND) ))
|
||||||
|
}
|
||||||
|
cdv () { # OPCODE 7
|
||||||
|
printf "OPCODE : 7 OP: cdv OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$( get_combo "$1" )
|
||||||
|
REG_C=$(( REG_A / (2 ** OPERAND) ))
|
||||||
|
}
|
||||||
|
|
||||||
|
get_combo () {
|
||||||
|
# Interpret operand value
|
||||||
|
if [[ $OPERAND -eq 0 ]]
|
||||||
|
then
|
||||||
|
printf "$1"
|
||||||
|
elif [[ $OPERAND -eq 1 ]]
|
||||||
|
then
|
||||||
|
printf "$1"
|
||||||
|
elif [[ $OPERAND -eq 2 ]]
|
||||||
|
then
|
||||||
|
printf "$1"
|
||||||
|
elif [[ $OPERAND -eq 3 ]]
|
||||||
|
then
|
||||||
|
printf "$1"
|
||||||
|
elif [[ $OPERAND -eq 4 ]]
|
||||||
|
then
|
||||||
|
printf "%s" "$REG_A"
|
||||||
|
elif [[ $OPERAND -eq 5 ]]
|
||||||
|
then
|
||||||
|
printf "%s" "$REG_B"
|
||||||
|
elif [[ $OPERAND -eq 6 ]]
|
||||||
|
then
|
||||||
|
printf "%s" "$REG_C"
|
||||||
|
elif [[ $OPERAND -eq 7 ]]
|
||||||
|
then
|
||||||
|
printf "Reserved operand. Exiting.\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_quine () {
|
||||||
|
for (( i=0; i<INPUT_LEN; i++ ))
|
||||||
|
do
|
||||||
|
if [[ ${INPUT[$i]} != "${OUTPUT[$i]}" ]]
|
||||||
|
then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
POINTER=0
|
||||||
|
while [[ $POINTER -lt $INPUT_LEN ]]
|
||||||
|
do
|
||||||
|
OPCODE=${INPUT[$POINTER]}
|
||||||
|
OPERAND=${INPUT[$POINTER+1]}
|
||||||
|
if [[ $OPCODE -eq 0 ]]
|
||||||
|
then
|
||||||
|
adv "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
elif [[ $OPCODE -eq 1 ]]
|
||||||
|
then
|
||||||
|
bxl "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
elif [[ $OPCODE -eq 2 ]]
|
||||||
|
then
|
||||||
|
bst "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
elif [[ $OPCODE -eq 3 ]]
|
||||||
|
then
|
||||||
|
# jnz itself moves the pointer
|
||||||
|
jnz "$OPERAND"
|
||||||
|
elif [[ $OPCODE -eq 4 ]]
|
||||||
|
then
|
||||||
|
bxc "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
elif [[ $OPCODE -eq 5 ]]
|
||||||
|
then
|
||||||
|
out "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
elif [[ $OPCODE -eq 6 ]]
|
||||||
|
then
|
||||||
|
bdv "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
elif [[ $OPCODE -eq 7 ]]
|
||||||
|
then
|
||||||
|
cdv "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
fi
|
||||||
|
printf "Registers A : %s B: %s C : %s\n" "$REG_A" "$REG_B" "$REG_C" >&2
|
||||||
|
printf "Pointer : %s\n" "$POINTER" >&2
|
||||||
|
(( ITER-- ))
|
||||||
|
if [[ $ITER -eq 0 ]] ; then break ;fi
|
||||||
|
done | paste -s -d ","
|
150
2024/day-17/solution-2.sh
Normal file
150
2024/day-17/solution-2.sh
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
FILE=$1
|
||||||
|
ITER=99
|
||||||
|
|
||||||
|
REG_A=$(grep 'Register A:' "$FILE" | cut -f2 -d: )
|
||||||
|
REG_B=$(grep 'Register B:' "$FILE" | cut -f2 -d: )
|
||||||
|
REG_C=$(grep 'Register C:' "$FILE" | cut -f2 -d: )
|
||||||
|
read -r -a INPUT <<< "$(grep 'Program:' "$FILE" | cut -f2 -d: | tr ',' ' ' )"
|
||||||
|
INPUT_LEN=${#INPUT[@]}
|
||||||
|
|
||||||
|
printf "Registers A: %s B: %s C: %s\n" "$REG_A" "$REG_B" "$REG_C" >&2
|
||||||
|
printf "Input : " >&2
|
||||||
|
printf "%s " "${INPUT[@]}" >&2
|
||||||
|
printf "\n" >&2
|
||||||
|
|
||||||
|
adv () { # OPCODE 0
|
||||||
|
printf "OPCODE : 0 OP: adv OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$( get_combo "$1" )
|
||||||
|
REG_A=$(( REG_A / (2 ** OPERAND) ))
|
||||||
|
}
|
||||||
|
bxl () { # OPCODE 1
|
||||||
|
printf "OPCODE : 1 OP: bxl OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$1
|
||||||
|
REG_B=$(( REG_B ^ OPERAND ))
|
||||||
|
}
|
||||||
|
bst () { # OPCODE 2
|
||||||
|
printf "OPCODE : 2 OP: bst OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$( get_combo "$1" )
|
||||||
|
REG_B=$(( OPERAND % 8 ))
|
||||||
|
}
|
||||||
|
jnz () { # OPCODE 3
|
||||||
|
printf "OPCODE : 3 OP: jnz OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$1
|
||||||
|
if [[ $REG_A -eq 0 ]]
|
||||||
|
then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
POINTER=$OPERAND
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
bxc () { # OPCODE 4
|
||||||
|
printf "OPCODE : 4 OP: bxc OPERAND: %s\n" "$1" >&2
|
||||||
|
# OPERAND=$1 # Deprecated for legacy reasons
|
||||||
|
REG_B=$(( REG_B ^ REG_C ))
|
||||||
|
}
|
||||||
|
out () { # OPCODE 5
|
||||||
|
printf "OPCODE : 5 OP: out OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$( get_combo "$1" )
|
||||||
|
printf "%s\n" "$(( OPERAND % 8 ))"
|
||||||
|
}
|
||||||
|
bdv () { # OPCODE 6
|
||||||
|
printf "OPCODE : 6 OP: bdv OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$( get_combo "$1" )
|
||||||
|
REG_B=$(( REG_A / (2 ** OPERAND) ))
|
||||||
|
}
|
||||||
|
cdv () { # OPCODE 7
|
||||||
|
printf "OPCODE : 7 OP: cdv OPERAND: %s\n" "$1" >&2
|
||||||
|
OPERAND=$( get_combo "$1" )
|
||||||
|
REG_C=$(( REG_A / (2 ** OPERAND) ))
|
||||||
|
}
|
||||||
|
|
||||||
|
get_combo () {
|
||||||
|
# Interpret operand value
|
||||||
|
if [[ $OPERAND -eq 0 ]]
|
||||||
|
then
|
||||||
|
printf "$1"
|
||||||
|
elif [[ $OPERAND -eq 1 ]]
|
||||||
|
then
|
||||||
|
printf "$1"
|
||||||
|
elif [[ $OPERAND -eq 2 ]]
|
||||||
|
then
|
||||||
|
printf "$1"
|
||||||
|
elif [[ $OPERAND -eq 3 ]]
|
||||||
|
then
|
||||||
|
printf "$1"
|
||||||
|
elif [[ $OPERAND -eq 4 ]]
|
||||||
|
then
|
||||||
|
printf "%s" "$REG_A"
|
||||||
|
elif [[ $OPERAND -eq 5 ]]
|
||||||
|
then
|
||||||
|
printf "%s" "$REG_B"
|
||||||
|
elif [[ $OPERAND -eq 6 ]]
|
||||||
|
then
|
||||||
|
printf "%s" "$REG_C"
|
||||||
|
elif [[ $OPERAND -eq 7 ]]
|
||||||
|
then
|
||||||
|
printf "Reserved operand. Exiting.\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_quine () {
|
||||||
|
for (( i=0; i<INPUT_LEN; i++ ))
|
||||||
|
do
|
||||||
|
if [[ ${INPUT[$i]} != "${OUTPUT[$i]}" ]]
|
||||||
|
then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
while ! check_quine
|
||||||
|
do
|
||||||
|
read -r -a OUTPUT <<<"$(
|
||||||
|
POINTER=0
|
||||||
|
while [[ $POINTER -lt $INPUT_LEN ]]
|
||||||
|
do
|
||||||
|
OPCODE=${INPUT[$POINTER]}
|
||||||
|
OPERAND=${INPUT[$POINTER+1]}
|
||||||
|
if [[ $OPCODE -eq 0 ]]
|
||||||
|
then
|
||||||
|
adv "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
elif [[ $OPCODE -eq 1 ]]
|
||||||
|
then
|
||||||
|
bxl "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
elif [[ $OPCODE -eq 2 ]]
|
||||||
|
then
|
||||||
|
bst "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
elif [[ $OPCODE -eq 3 ]]
|
||||||
|
then
|
||||||
|
# jnz itself moves the pointer
|
||||||
|
jnz "$OPERAND"
|
||||||
|
elif [[ $OPCODE -eq 4 ]]
|
||||||
|
then
|
||||||
|
bxc "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
elif [[ $OPCODE -eq 5 ]]
|
||||||
|
then
|
||||||
|
out "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
elif [[ $OPCODE -eq 6 ]]
|
||||||
|
then
|
||||||
|
bdv "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
elif [[ $OPCODE -eq 7 ]]
|
||||||
|
then
|
||||||
|
cdv "$OPERAND"
|
||||||
|
(( POINTER+=2 ))
|
||||||
|
fi
|
||||||
|
printf "Registers A : %s B: %s C : %s\n" "$REG_A" "$REG_B" "$REG_C" >&2
|
||||||
|
printf "Pointer : %s\n" "$POINTER" >&2
|
||||||
|
(( ITER-- ))
|
||||||
|
if [[ $ITER -eq 0 ]] ; then break ;fi
|
||||||
|
done | paste -s -d ","
|
||||||
|
)"
|
||||||
|
done
|
5
2024/day-17/test-input-1
Normal file
5
2024/day-17/test-input-1
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Register A: 729
|
||||||
|
Register B: 0
|
||||||
|
Register C: 0
|
||||||
|
|
||||||
|
Program: 0,1,5,4,3,0
|
Reference in New Issue
Block a user