Files
advent-of-code/day19/ex2.bash

73 lines
1.8 KiB
Bash
Executable File

#!/bin/bash
#
# ex1.bash: Advent2020 game, day 19/game 1.
CMD=${0##*/}
set -o noglob
shopt -s extglob
declare -a RULE=() MATCH=() STRING=()
# shellcheck disable=SC2034
declare var_0
declare -i res=0
# build a regexp use-able by bash =~ operator.
# Recursively replace rules, until we get final text values.
# To avoid running subshell, we must create local variables w/ different
# names at each recursion level (to avoid "circular name reference" error).
function buildtree {
local -i prof="$1" # to allow ≠ local names
local -n upname="$2" # caller variable name
local name="var_$prof" # local var name, w/ depth
eval "local $name" # ... declared here
shift 2
local args=$* res="" arg
for arg in $args; do
if [[ -z "${arg/[|ab]}" ]]; then
res+="$arg"
else
if [[ ! -v MATCH[$arg] ]]; then
buildtree "$((prof+1))" "$name" "${RULE[$arg]}"
MATCH[$arg]="(${!name})"
fi
res+=${MATCH[$arg]}
fi
done
# shellcheck disable=SC2034
upname="$res"
}
while read -r line; do
case ${line:0:1} in
[0-9]*) # rule
rule=${line%:*}
val=${line#*: }
RULE[$rule]="${val//\"}"
;;
[a-z]*) # string
STRING+=("$line")
;;
esac
done
# Old rules:
# 8: 42
# 11: 42 31
# New rules:
# 8: 42 | 42 8
# 11: 42 31 | 42 11 31
buildtree 1 var_0 42
printf "RULE 42 = %s\n" "${MATCH[42]}"
buildtree 1 var_0 31
printf "RULE 31 = %s\n" "${MATCH[11]}"
for str in "${STRING[@]}"; do
[[ "$str" =~ ^${MATCH[0]}$ ]] && ((res++))
done
printf "%s : res=%d\n" "$CMD" "$res"
exit 0