#!/bin/bash rulesdir=~/.golly/Rules rulename=AoC2018Day17 title='Advent of Code 2018 - Day 17: Reservoir Research' # Build rule definition for Golly mkdir -p "$rulesdir" cat <"$rulesdir/$rulename.rule" @RULE $rulename --- $title --- @TABLE n_states:6 neighborhood:Moore symmetries:none # 0 : dry # 1 : flowing # 2 : found east barrier # 3 : found west barrier # 4 : pooled # 5 : barrier # Don't cares # (multiple vars defined with the same value allows # input states described by those vars not to need to # match each other) var xn={0,1,2,3,4,5} var xne={xn} var xe={xn} var xse={xn} var xs={xn} var xsw={xn} var xw={xn} var xnw={xn} # Pooled water and barriers both block flow var bn={4,5} var bne={bn} var be={bn} var bse={bn} var bs={bn} var bsw={bn} var bw={bn} var bnw={bn} # Dry with flowing n -> flowing 0,1,xne,xe,xse,xs,xsw,xw,xnw,1 # Dry with blocker sw and flowing w -> flowing; # mirror for east side 0,xn,xne,xe,xse,xs,bsw,1,xnw,1 0,xn,xne,1,bse,xs,xsw,xw,xnw,1 # Flowing with blocker s, and barriers or founds e, w -> pooled 1,xn,xne,be,xse,bs,xsw,bw,xnw,4 1,xn,xne,2,xse,bs,xsw,3,xnw,4 # Flowing with blocker s, and barrier or found east e -> found east 1,xn,xne,5,xse,bs,xsw,xw,xnw,2 1,xn,xne,2,xse,bs,xsw,xw,xnw,2 # Flowing with blocker s, and barrier or found west w -> found west 1,xn,xne,xe,xse,bs,xsw,5,xnw,3 1,xn,xne,xe,xse,bs,xsw,3,xnw,3 # Found east with found west or blocker w -> pooled # Found west with found east or blocker e -> pooled 2,xn,xne,xe,xse,xs,xsw,3,xnw,4 2,xn,xne,xe,xse,xs,xsw,bw,xnw,4 3,xn,xne,2,xse,xs,xsw,xw,xnw,4 3,xn,xne,be,xse,xs,xsw,xw,xnw,4 @COLORS 0 51 51 51 dry: dark grey 1 0 102 102 flowing: turquoise 2 51 102 51 found east: greenish 3 102 51 51 found west: purplish 4 0 0 153 pooled: blue 5 102 102 0 barrier: clay colored EOF # Massage input map into a flat list with a single X Y # coordinate pair on each line, with duplicate pairs removed. # Make two versions, one sorted by each coordinate. input=${1:-input.txt} by_x=$(mktemp) by_y=$(mktemp) while IFS='=, ' read c1 val c2 range do case $c1$c2 in xy) eval "for y in {$range};" 'do echo $val $y; done' ;; yx) eval "for x in {$range};" 'do echo $x $val; done' esac done <"$input" | sort -n -k1 -k2 -u | tee $by_x | sort -n -k2 -k1 >$by_y # Find coordinate limits. set -- $(head -n1 $by_y) top=$2 set -- $(tail -n1 $by_y) bottom=$2 set -- $(head -n1 $by_x) left=$1-1 set -- $(tail -n1 $by_x) right=$1+1 # Use Y-sorted coordinates list to build a Golly RLE input file. # After the header, each line represents one row of input cells. # Cell states are . for state 0, A-E for states 1-5, and each # of these can have an optional numeric prefix which is taken # as a repeat count. $ marks the end of an input row. Short rows # get filled to the right with state 0 cells. See Golly help for # full file format details. rle=${input%.txt}.rle rle=/tmp/${rle%%*/} { let width=right-left+1 height=bottom-top+2 echo "# $title" echo "x = $width, y = $height, rule = $rulename:P$width,$height" x=500 # Position of spring let le=x-left && printf $le. printf A let row=top-1 while read x y do while let 'row < y' do echo '$' let row++ col=left done let le=x-col && printf $le. printf E let col=x+1 done <$by_y echo '$' } >"$rle" # Let Golly do what Golly does best. After the population stabilzes, # save the pattern back over the original RLE file for further # processing here. golly "$rle" >/dev/null 2>&1 # Massage the counts in the output RLE file into variable-increment # instructions for bc, then have bc add up the ones we want. sed "$rle" -Ee '1,/^x =/d' | sed -Ee ' 1s/^[^$]+\$// s/[^0-9.A-E]*//g y/.ABCDE/abcdef/ s/([0-9]*)([a-z])/\1\2\n/g ' | sed -Ee ' s/^([^0-9])/1\1/ s/([0-9]+)([a-z])/\2+=\1/ $a\ b+c+d+e\ e ' | bc