X-Git-Url: https://git.sommitrealweird.co.uk/advent-of-code-2021.git/blobdiff_plain/93dfe872eef986673cae31e8e985c547a09209f7..5c0cc1b6ff5f44d4c6083a80b06448958a2d1364:/day04/bingo.sh diff --git a/day04/bingo.sh b/day04/bingo.sh new file mode 100755 index 0000000..4348325 --- /dev/null +++ b/day04/bingo.sh @@ -0,0 +1,169 @@ +#!/bin/bash + +set -e +set -u + +filename=${1:-example.txt} + +bold=$(tput bold) +normal=$(tput sgr0) + +# each board is a 5*5 grid, so that's handy, we'll store all the boards in one +# array, then create a second array that shows which matches we have, we can +# select any given board by limiting to a range of 25 values from the array + +exec 3<"$filename" + +# first line is the draws, so read that in to an array too +OLDIFS="$IFS" +IFS="," +read -u 3 -a draw + +read -u 3 line + +IFS=" " +line_count=0 + +declare -a boards +declare -a checked + +while read -u 3 -a row; do + ((line_count+=1)) + boards+=("${row[@]}") + if [ $line_count -eq 5 ]; then + read -u 3 line || true + line_count=0 + fi +done + +for x in ${boards[@]}; do + checked+=(0) +done + +display_board() { + local board_number=$1 + offset=$((25*$board_number)) + + count=0 + + for val in "${boards[@]:$offset:25}"; do + if [ ${checked[$((offset+$count))]} -eq 1 ]; then + echo -n "${bold}" + fi + ((count+=1)) + printf "%2d " $val + echo -n "${normal}" + if [ $((count%5)) -eq 0 ]; then + echo + fi + done + echo +} + +check_board() { + local board_number=$1 + local drawn_number=$2 + offset=$((25*$board_number)) + + count=0 + for val in "${boards[@]:$offset:25}"; do + if [ $val -eq $drawn_number ]; then + checked[$((offset+$count))]=1 + fi + ((count+=1)) + done + + row=0 + col=0 + declare -a row_matches=(0 0 0 0 0) + declare -a col_matches=(0 0 0 0 0) + + for val in "${checked[@]:$offset:25}"; do + if [ $val -eq 1 ]; then + ((col_matches[$col]+=1)) + ((row_matches[$row]+=1)) + fi + ((col+=1)) + if [ $col -eq 5 ]; then + col=0 + ((row+=1)) + fi + done + + for row in "${row_matches[@]}"; do + if [ $row -eq 5 ]; then + return 0 + fi + done + + for col in "${col_matches[@]}"; do + if [ $col -eq 5 ]; then + return 0 + fi + done + + return 1 +} + +get_unmarked_count() { + local board_number=$1 + local offset=$((board_number*25)) + local count=0 + + for ((i=0; i<25; i++)); do + if [ ${checked[$(($offset+$i))]} -eq 0 ]; then + ((count+=${boards[$(($offset+$i))]})) + fi + done + + echo $count +} + +declare -a completed_boards=() + +in_array() { + local value=$1 + local -n array=$2 + + for val in "${array[@]}"; do + if [ $val -eq $value ]; then + return 0 + fi + done + + return 1 +} + +first_board=-1 +first_board_last_number=-1 +last_board_last_number=-1 + +for number in "${draw[@]}"; do + for (( board=0; board<$((${#boards[@]} / 25)); board++ )); do + if ( ! in_array $board completed_boards ); then + check_board $board $number && { if [ $first_board -eq -1 ]; then first_board=$board; first_board_last_number=$number; fi; completed_boards+=( $board ); } || true + if [ ${#completed_boards[@]} -eq $((${#boards[@]} / 25)) ]; then + last_board_last_number=$number + break 2 + fi + fi + done +done + +echo "Board matched: $first_board" +echo "Last number drawn: $first_board_last_number" +echo +display_board $first_board + +unmarked=$(get_unmarked_count $first_board) + +echo "$unmarked * $first_board_last_number = "$((unmarked*$first_board_last_number)) + +echo "Last board matched: "${completed_boards[-1]} +echo "Last number drawn: $last_board_last_number" +echo +display_board ${completed_boards[-1]} + +unmarked=$(get_unmarked_count ${completed_boards[-1]}) + +echo "$unmarked * $last_board_last_number = "$((unmarked*$last_board_last_number))