94 lines
4.0 KiB
Sed
94 lines
4.0 KiB
Sed
|
# Render next frame of falling balls with rockets and stuff
|
||
|
#
|
||
|
# Copyright (C) 2018 Mike Gerwitz
|
||
|
#
|
||
|
# This program is free software: you can redistribute it and/or modify
|
||
|
# it under the terms of the GNU General Public License as published by
|
||
|
# the Free Software Foundation, either version 3 of the License, or
|
||
|
# (at your option) any later version.
|
||
|
#
|
||
|
# This program is distributed in the hope that it will be useful,
|
||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
# GNU General Public License for more details.
|
||
|
#
|
||
|
# You should have received a copy of the GNU General Public License
|
||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
#
|
||
|
# A remarkably interactive environment can be created using only regular
|
||
|
# expressions and treating the input frame as a character matrix. By
|
||
|
# encoding all rules and state into the characters themselves, we can create
|
||
|
# a dynamic world using only a series of deterministic finite automata
|
||
|
# (DFAs).
|
||
|
#
|
||
|
# The core concept here is that, if we load the entire frame into the
|
||
|
# pattern space so that we can match on newlines, and we know the width of
|
||
|
# the frame (every line must be 40 characters), then we can easily match on
|
||
|
# the lines above and below by matching 40 characters, +/- some number.
|
||
|
#
|
||
|
# There is one caveat here that I haven't bothered addressing: if some
|
||
|
# movable object is caught up in the pattern of another object (e.g. is on
|
||
|
# the same line), then it will not be processed until the following
|
||
|
# frame. This could be mitigated by looping using `t', but it's not quite
|
||
|
# that simple: can you think of what's needed?
|
||
|
#
|
||
|
# This script only renders one frame. To use it for an animation, run it
|
||
|
# in a loop, or use the provided helper script `animate'.
|
||
|
##
|
||
|
|
||
|
# Accumulate all text (including newlines) into pattern space so that
|
||
|
# regular expressions can span lines.
|
||
|
:a; N; $!ba
|
||
|
|
||
|
|
||
|
# A ball is represented by `o' and is moved left or right depending on
|
||
|
# what object is underneath it (`<' for left and `>' for right), provided
|
||
|
# that there is space to move into.
|
||
|
s#o \(.\{40\}>\)# o\1#g
|
||
|
s# o\(.\{41\}<\)#o \1#g
|
||
|
|
||
|
# Angled walls are represented by `\' and `/' and cause movement at an
|
||
|
# angle, again provided that space is available.
|
||
|
s#o\(.\{41\}\\\) # \1o#g
|
||
|
s#o\(.\{40\}\) /# \1o/#g
|
||
|
|
||
|
# Plungers look like `=|' or `|=' when retracted and will push to the
|
||
|
# right or left (respectively) when a ball appears next to it. Expanded
|
||
|
# plungers will retract if no ball is next to it. The effect is that one
|
||
|
# frame will push the ball and then it will retract the next frame.
|
||
|
s#=~|#=| #g; s#=|o #=~|o#g
|
||
|
s#|~=# |=#g; s# o|=#o|~=#g
|
||
|
|
||
|
# A rocket (`^') will explode if there is no room left to push a
|
||
|
# ball. Explosions will destroy the character above the ball, the ball
|
||
|
# itself, and the rocket. The character above the ball and the ball will
|
||
|
# be replaced with smoke (`#'), which will disappear the following frame.
|
||
|
s|#| |g
|
||
|
s|[^ ]\(.\{41\}\)o\(.\{41\}\)\^|#\1#\2 |g
|
||
|
|
||
|
# Rockets leave a trail `:', which needs to be cleaned up in the event of
|
||
|
# an explosion if no rocket is above it.
|
||
|
s#\([^^:].\{41\}\):#\1 #g
|
||
|
|
||
|
# Rockets (^) rise when they have a ball on top of them, but fall
|
||
|
# otherwise. They leave behind a trail (`:'), which is used as a guide
|
||
|
# for falling back into its original position.
|
||
|
s# \(.\{41\}\)o\(.\{41\}\)\^#o\1^\2:#g
|
||
|
s#\([^o].\{41\}\)\^\(.\{41\}\):#\1 \2^#g
|
||
|
|
||
|
# Finally, balls will fall if there is nothing beneath them. We do this
|
||
|
# last so that ball aren't found floating in a frame (e.g. if they fall
|
||
|
# off of an edge, they do so immediately, not float over the edge until
|
||
|
# the next frame).
|
||
|
s#o\(.\{41\}\) # \1o#g
|
||
|
|
||
|
# If no substitutions were made, exit with a non-zero status so that the
|
||
|
# animation script will stop animating.
|
||
|
t
|
||
|
q1
|
||
|
|
||
|
# All of the above makes for a pretty interesting animation, but doesn't
|
||
|
# allow for a whole lot of creativity with regards to world manipulation;
|
||
|
# it lacks useful primitives. That's the topic of future hacks. Have
|
||
|
# fun, and happy hacking!
|