Files
advent-of-code/2020/day21/ex1.bash
2021-07-30 17:44:04 +02:00

114 lines
2.5 KiB
Bash
Executable File

#!/bin/bash
#
# ex1.bash: Advent2020 game, day 21/game 1.
CMD=${0##*/}
shopt -s extglob
set -o noglob
declare -A CANBE=() A_RULES=() FOUND=() ALL_I=() ALL_A=() I_COUNT=()
declare -a R
declare -i count=0
# intersect the words of 2 strings into $1
intersect() {
local -n _res="$1"
# shellcheck disable=SC2206
local -a _str1=($2) _str2=($3)
local _i _j
_res=""
for _i in "${_str1[@]}"; do
for _j in "${_str2[@]}"; do
[[ "$_i" == "$_j" ]] && _res+=" $_i"
done
done
_res="${_res##*( )}"
}
# count words in a string and put result in $1
count() {
local -n _res="$1"
# shellcheck disable=SC2206
local -a _str=($2)
_res=${#_str[@]}
}
# remove a word from a string and put result in $1
delw() {
local -n _res="$1"
local _w=$2
# shellcheck disable=SC2206
local -a _str=($3)
local _i
_res=""
for _i in "${_str[@]}"; do
[[ $_i != "$_w" ]] && _res+=" $_i"
done
_res="${_res##*( )}"
_res="${_res%%*( )}"
}
REGEX="(.*) \(contains(.*)\)"
while read -r line; do
[[ "$line" =~ $REGEX ]]
ingr="${BASH_REMATCH[1]}"
allg="${BASH_REMATCH[2]}"
allg=${allg//,}
R[$count]="$ingr"
for ka in $allg; do
A_RULES[$ka]+=" $count"
ALL_A[$ka]=""
for ki in $ingr; do
ALL_I[$ki]=""
done
done
for ki in $ingr; do
(( I_COUNT[$ki]++ ))
done
((count++))
done
all_i="${!ALL_I[*]}"
for k in "${!ALL_A[@]}"; do
CANBE[$k]="$all_i"
done
solved=0
while ((solved==0)); do
solved=1
for allerg in "${!CANBE[@]}"; do
str="${CANBE[$allerg]}"
if [[ -v FOUND["$allerg"] ]]; then
continue
fi
for rule in ${A_RULES[$allerg]}; do
intersect str "${R[$rule]}" "$str"
done
CANBE[$allerg]="$str"
count count "$str"
((count > 1)) && solved=0
if ((count==1)); then
word=$str #{CANBE[$allerg]}
# shellcheck disable=SC2034
FOUND[$allerg]="${CANBE[$allerg]}"
unset ALL_I["${CANBE[$allerg]}"]
for allerg1 in "${!CANBE[@]}"; do
if [[ "$allerg" != "$allerg1" ]]; then
delw CANBE["$allerg1"] "$word" "${CANBE[$allerg1]}"
fi
done
for rule in "${!R[@]}"; do
delw R[$rule] "$word" "${R[$rule]}"
done
fi
done
done
res=0
for i in "${!ALL_I[@]}"; do
((res+=${I_COUNT[$i]}))
done
printf "%s: res=%d\n" "$CMD" "$res"
exit 0