Mike Gerwitz

Free Software Hacker+Activist

aboutsummaryrefslogtreecommitdiffstats
blob: 70d987a4c7189c5b7b7218717702a53522640423 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# 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!