diff --git a/2024/day-16/solution-1.sh b/2024/day-16/solution-1.sh index c67ebd6..d79345d 100644 --- a/2024/day-16/solution-1.sh +++ b/2024/day-16/solution-1.sh @@ -83,28 +83,33 @@ done CHECKPOINT_ARRAY[$END_POSITION]=0 printf "%s " "${!CHECKPOINT_ARRAY[@]}" printf "\n" +CHECKPOINT_ARRAY_LEN=${#CHECKPOINT_ARRAY[@]} # Iterate over checkpoints and print pairings declare -A CHECKPOINT_PAIRS 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 () { local POSITION=$1 local NEXT_POSITION=$2 local DIRECTION=$3 - # For same directions, weight change is 1 - if [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_UP ]] && [[ $(( DIRECTION % 2 )) -eq 0 ]] + # Check if next position is moving in line with the previous direction + if [[ $(( NEXT_POSITION - POSITION )) -eq $DIR_UP ]] && [[ $(( DIRECTION % PREV_UP )) -eq 0 ]] then printf "1" 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 printf "1" 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 printf "1" 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 printf "1" return 0 @@ -113,45 +118,55 @@ get_weight_change () { printf "1000" } recurse_travel () { - local POSITION=$1 - local CHECKPOINT=$2 - local DIRECTION=$3 - local WEIGHT=$4 - local UP=$(( POSITION - MAP_WIDTH )) - local DOWN=$(( POSITION + MAP_WIDTH )) - local LEFT=$(( POSITION - 1 )) - local RIGHT=$(( POSITION + 1 )) + local POSITION=$1 # Current position + local CHECKPOINT=$2 # Previous checkpoint + local DIRECTION=$3 # Allowed adjacent tiles + local WEIGHT=$4 # Weightage so far + # Search adjacent tiles # Recurse if it's movable # 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 - if [[ ${MAP_ARRAY[$UP]} == "." ]] + local UP=$(( POSITION + DIR_UP )) + if [[ $UP -gt 0 ]] then - WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$UP" "$DIRECTION" ) - recurse_travel "$UP" "$CHECKPOINT" "$(( 2 * 5 * 7 ))" "$(( WEIGHT + WEIGHT_CHANGE ))" - elif [[ -v CHECKPOINT_ARRAY[$UP] ]] - then - WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$UP" "$DIRECTION" ) - CHECKPOINT_PAIRS[$UP]=$CHECKPOINT - CHECKPOINT_PAIR_WEIGHTS["$UP-$CHECKPOINT"]=$(( WEIGHT + WEIGHT_CHANGE )) + if [[ ${MAP_ARRAY[$UP]} == "." ]] + then + WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$UP" "$DIRECTION" ) + recurse_travel "$UP" "$CHECKPOINT" "$(( 2 * 5 * 7 ))" "$(( WEIGHT + WEIGHT_CHANGE ))" + elif [[ -v CHECKPOINT_ARRAY[$UP] ]] + then + WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$UP" "$DIRECTION" ) + CHECKPOINT_PAIRS["$CHECKPOINT-$UP"]=0 + CHECKPOINT_PAIR_WEIGHTS["$CHECKPOINT-$UP"]=$(( WEIGHT + WEIGHT_CHANGE )) + fi fi fi if [[ $(( DIRECTION % 3 )) -eq 0 ]] && [[ $DOWN -lt $MAP_LEN ]] then - if [[ ${MAP_ARRAY[$DOWN]} == "." ]] - then - WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$DOWN" "$DIRECTION" ) - recurse_travel "$DOWN" "$CHECKPOINT" "$(( 3 * 5 * 7 ))" "$(( WEIGHT + WEIGHT_CHANGE ))" - elif [[ -v CHECKPOINT_ARRAY[$DOWN] ]] - then - WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$DOWN" "$DIRECTION" ) - CHECKPOINT_PAIRS[$DOWN]=$CHECKPOINT - CHECKPOINT_PAIR_WEIGHTS["$DOWN-$CHECKPOINT"]=$(( WEIGHT + WEIGHT_CHANGE )) + local DOWN=$(( POSITION + DIR_DOWN )) + if [[ $DOWN -lt $MAP_LEN ]] + then + if [[ ${MAP_ARRAY[$DOWN]} == "." ]] + then + WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$DOWN" "$DIRECTION" ) + recurse_travel "$DOWN" "$CHECKPOINT" "$(( 3 * 5 * 7 ))" "$(( WEIGHT + WEIGHT_CHANGE ))" + elif [[ -v CHECKPOINT_ARRAY[$DOWN] ]] + then + WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$DOWN" "$DIRECTION" ) + CHECKPOINT_PAIRS["$CHECKPOINT-$DOWN"]=0 + CHECKPOINT_PAIR_WEIGHTS["$CHECKPOINT-$DOWN"]=$(( WEIGHT + WEIGHT_CHANGE )) + fi fi fi if [[ $(( DIRECTION % 5 )) -eq 0 ]] then + local LEFT=$(( POSITION + DIR_LEFT )) if [[ ${MAP_ARRAY[$LEFT]} == "." ]] then WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$LEFT" "$DIRECTION" ) @@ -159,12 +174,13 @@ recurse_travel () { elif [[ -v CHECKPOINT_ARRAY[$LEFT] ]] then WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$LEFT" "$DIRECTION" ) - CHECKPOINT_PAIRS[$LEFT]=$CHECKPOINT - CHECKPOINT_PAIR_WEIGHTS["$LEFT-$CHECKPOINT"]=$(( WEIGHT + WEIGHT_CHANGE )) + CHECKPOINT_PAIRS["$CHECKPOINT-$LEFT"]=0 + CHECKPOINT_PAIR_WEIGHTS["$CHECKPOINT-$LEFT"]=$(( WEIGHT + WEIGHT_CHANGE )) fi fi if [[ $(( DIRECTION % 7 )) -eq 0 ]] then + local RIGHT=$(( POSITION + DIR_RIGHT )) if [[ ${MAP_ARRAY[$RIGHT]} == "." ]] then WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$RIGHT" "$DIRECTION" ) @@ -172,25 +188,66 @@ recurse_travel () { elif [[ -v CHECKPOINT_ARRAY[$RIGHT] ]] then WEIGHT_CHANGE=$( get_weight_change "$POSITION" "$RIGHT" "$DIRECTION" ) - CHECKPOINT_PAIRS[$RIGHT]=$CHECKPOINT - CHECKPOINT_PAIR_WEIGHTS["$RIGHT-$CHECKPOINT"]=$(( WEIGHT + WEIGHT_CHANGE )) + CHECKPOINT_PAIRS["$CHECKPOINT-$RIGHT"]=0 + CHECKPOINT_PAIR_WEIGHTS["$CHECKPOINT-$RIGHT"]=$(( WEIGHT + WEIGHT_CHANGE )) fi fi } +ITER=99999 for CHECKPOINT in "${!CHECKPOINT_ARRAY[@]}" 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 for CHECKPOINT in "${!CHECKPOINT_PAIRS[@]}" do - printf "DEST %s from checkpoint %s\n" "${CHECKPOINT_PAIRS[$CHECKPOINT]}" "$CHECKPOINT" -done + printf "Dest %s from checkpoint %s\n" "${CHECKPOINT_PAIRS[$CHECKPOINT]}" "$CHECKPOINT" +done | sort for CHECKPOINT in "${!CHECKPOINT_PAIR_WEIGHTS[@]}" do 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&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&2 + printf "Pointer : %s\n" "$POINTER" >&2 + (( ITER-- )) + if [[ $ITER -eq 0 ]] ; then break ;fi +done | paste -s -d "," diff --git a/2024/day-17/solution-2.sh b/2024/day-17/solution-2.sh new file mode 100644 index 0000000..fe2dcbf --- /dev/null +++ b/2024/day-17/solution-2.sh @@ -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&2 + printf "Pointer : %s\n" "$POINTER" >&2 + (( ITER-- )) + if [[ $ITER -eq 0 ]] ; then break ;fi + done | paste -s -d "," + )" +done diff --git a/2024/day-17/test-input-1 b/2024/day-17/test-input-1 new file mode 100644 index 0000000..f09839b --- /dev/null +++ b/2024/day-17/test-input-1 @@ -0,0 +1,5 @@ +Register A: 729 +Register B: 0 +Register C: 0 + +Program: 0,1,5,4,3,0