#!/bin/sed -nf # arkanoid.sed - http://aurelio.net/bin/sed/arkanoid/ # by Aurelio Marinho Jargas <verde (a) aurelio net> # # Arkanoid: a paddle that bounces a ball (pong!) to destroy blocks # # ACTORS: # o ball -- paddle # = block ~~ paddle (on hold mode) # * block exploding . life (mini paddle) # [come on, use your imagination :)] # COMMANDS: # z left move c hold mode ON/OFF # x right move q quit # # HOW TO PLAY: # You must press the ENTER key after *every* command. Start the # program with "sed -f arkanoid.sed". Press ENTER. Choose the # level. Press ENTER. Move the paddle with the keyboard arrows # or with the Z and X keys. Press ENTER. Release the ball using # the down arrow ou the C key. Press ENTER. Press ENTER. Press # ENTER. Press ENTER... # # ANTI-FLAME DISCLAIMER: # Well, just as sokoban.sed, this one is cool because it's sed. # It's not funny to play or even exciting, because keep pressing # ENTER to the ball move sucks. But hey, it's cute! &;) # # For the how-many-lines-it-has? fanatics: # prompt$ sed '/^ *#/d' arkanoid.sed | sed '$=;d' # # Tip: Use hold mode and hit the paddle twice on the wall # to escape cyclic ball movement # # TODO Get classic Arkanoid levels (somebody help me!) # # CHANGELOG: # 2002-07-09 v1.0: Debut release # 2005-05-13 v1.1: Now it's a sedcheck compliant script. # It will run on most SED's, including oldies. # 2013-02-12 v1.2: Removed ISO-8859-1 char, now we're plain ASCII. b zero :nocolor ### if you don't want colorful output, just uncomment next line #s/K(\([0-9;]*\))//g b showmap :parsecmd ### arrow keys (1), numeric pad (2), i-case (3), wipe trash(4) // { s/\[A/h/g s/\[B/h/g s/\[C/x/g s/\[D/z/g } y/4560/zhxq/ y/QZXHCc/qzxhhh/ s/[^qzxh#]//g b execcmd :welcome i\ Welcome to the SED Arkanoid\ \ Please select a level to begin [1-2]: d :showhelp ### clear screen, show help i\ [2J[H x s|.*|\ ... Sed Arkanoid\ ... \ ... z,4,<left> left move\ ... x,6,<right> right move\ ... c,5,<down> hold on/off\ ... q,0 quit game\ ... <enter> go!\ \ |p s/.*// x b end :loadmap ### load map on HOLD space /^1$/ { s/.*/\ _____________ \ | |\ | |\ |=============|\ |=============|\ |=============|\ | |\ | |\ | |\ | |\ | o |\ | ~~ |\ |...__________|\ / b endmap } /^2$/ { s/.*/\ _____________ \ |= |\ |=== |\ |===== |\ |======= |\ |========= |\ |=========== |\ |=============|\ | |\ | |\ | o |\ | ~~ |\ |...__________|\ / b endmap } ### test levels # # free X test /^t1$/ { s/.*/\ TEST 1 - f:X\ _____________ \ | = = = |\ | o |\ | = = = |\ | |\ |.____________|\ / b endmap } # free Y test /^t2$/ { s/.*/\ TEST 2 - f:Y\ _____________ \ | |\ | == = |\ | = == |\ | == |\ | =o= |\ | == |\ | |\ |____.________|\ / b endmap } # tri-explosion test /^t3$/ { s/.*/\ TEST 3 - 3\ _____________ \ | == |\ | == |\ | == = |\ | = == |\ | =o |\ | == |\ | |\ |.____________|\ / b endmap } # round explosion test /^t4$/ { s/.*/\ TEST 4 - >, <, b:>, b:<\ _____________ \ | = = |\ | == o == |\ | = = = = |\ | == == |\ | |\ |___________._|\ / b endmap } /~~/ !{ s/.*/there is no '&' level!/p q } :endmap s/^/[H/ s/ $/ru / h b showhelp #-------------------------------------------------------------------- # ### general hints about the code: # # - rlud are movements to perform on this turn # - RLUD are movements already done # - O is a ball already moved on this turn # - @% are temporary ball states to indicate ball over a block # - ! is a temporary explosion state after a free Y move # - -- is plain paddle and ~~ is paddle on hold mode # - ... are your 3 lives (mini-paddles) # - # is the cheat mode identifier (jail!) # - on hold, when releasing the ball, its X-direction will be same of # the paddle side where the ball is # - on hold, forcing paddle on the wall can move ball to the other side # of the paddle # - on hold mode, Y-direction is always down # - explosions are showed, then reconverted to ball on the next move # - ball on vertical and top borders do bounce # - block explosion and paddle (of course) bounces # - bounce: change X or Y direction # - exploding a block may change Y-direction and/or X-direction, depending # if there's another block on the way (see explosion comments) # - diagonal moves are done as X then Y moves (that's why % is needed) # - K() pattern is replaced by color escape chars <esc>[m # - < and > are round explosion direction. stored at the end (.$) of the map # - ball direction (rlud) is stored at the end (.. $) of the map also # - user commands are case insensitive # ballmiss routine: 1. reset direction and explosion status # 2. put ball over paddle , 3. take one life, 4. put paddle on hold mode # :ballmiss s/...$/ru / s/\*/ / s/ \(.\{20\}\)\([-~]\)/o\1\2/ s/\._/__/ s/--/~~/ b end :zero 1 b welcome # first map loading 2 b loadmap b parsecmd :execcmd ### execute user commands ### first, have you missed a ball? x /\*\(.\{20\}\)[_.]/ { /#/ !b ballmiss # cheat mode: never loses y/d*/uo/ b execcmd } x /q/ q # you cheater! (keep holding enter - hyper-speed) /#/ { x /#/ !s/\(.*\)|/\1#/ } # 1. move ball+paddle on hold, and goto end # 2. move just paddle and continue /z/ { x /o.\{20\}~/ { s/ o/o / s/ ~~/~~ / b end } s/ --/-- / s/ ~~/~~ / } /x/ { x /o.\{20\}~/ { s/o / o/ s/~~ / ~~/ b end } s/-- / --/ s/~~ / ~~/ } /h/ { x ### turn OFF hold mode routine /~~/ { # depending which side of paddle, change X-direction /o.\{20\}~~/ y/Rr/LL/ /o.\{20\}~[^~]/ y/Ll/RR/ # change Y-direction /o.\{20\}~/ y/Dd/UU/ } # swap ON/OFF paddle shape y/-~/~-/ } /./ !x # current explosion turns back to ball /o/ s/\*/ /g s/\*/o/ # reset movements y/RLUD/rlud/ # hold ball, no move /o.\{20\}~/ b end ### LET'S MOVE IT! # reached top: do bounce changing Y-direction /_\(.\{20\}\)o/ y/u/d/ ### detect borders, change X-direction /|o/ y/l/r/ /o|/ y/r/l/ # plain right-left ball move /r/ s/o / O/ /l/ s/ o/O / # tricky move over a block - part I /r/ { s/o=/ @/ s/% /=o/ } /l/ { s/=o/@ / s/ %/o=/ } # restore ball and mark X moves as done y/O@rl/o%RL/ b boom ### detect block. if so, explode it! # # 0 1 RIGHT-UP example: # +---+---+ # | = | * | 0. free X-way # |o | o| 1. explode and change Y-direction (right-down) # +-------+ # |== |** | 0. blocked X and Y way (tri-explosion) # |o= |o* | 1. explode all and change X and Y direction (left-down) # +-------+ # | |o | # | = | * | 0. free Y-way # |o= | = | 1. explode and change X-direction (left-up) # +---+---+ # ### RIGHT-UP Smart clockwise full round explosion! # # +---+---+---+---+---+ # | = | * | | | | If two explosions on two turns, # |o =| =| *| |o | we're on a round explosion. # | = | = | = | * | | After the roll, we end as left-up. # +---+---+---+---+---+ # ### explosion functions (wise is clockwise [>] or anti-clockwise [<]) # chkwise: if wise direction is empty, set it! - else dowise # setwise: set wise direction, based on current ball direction # dowise: set the next ball direction, based on wise direction # :chkwise / $/ b setwise b dowise # */! : ball came from X/Y free :setwise /\*/ { /Ld $/ s/ $/>/ /Ru $/ s/ $/>/ /Rd $/ s/ $/</ /Lu $/ s/ $/</ y/ud/du/ } /!/ { /Ld $/ s/ $/</ /Ru $/ s/ $/</ /Rd $/ s/ $/>/ /Lu $/ s/ $/>/ y/RL/LR/ } y/ud/UD/ b end :dowise /Rd<$/ y/d/U/ /Lu<$/ y/u/D/ /Ru<$/ y/R/L/ /Ld<$/ y/L/R/ /Ld>$/ y/d/U/ /Ru>$/ y/u/D/ /Rd>$/ y/R/L/ /Lu>$/ y/L/R/ b end # UP & DOWN explosion code: # 1. free X # 2. blocked XY from left (tri-explosion) # 3. blocked XY from right (tri-explosion) # 4. free Y # :boom /d/ { /o\(.\{20\}\)=/ s// \1*/ /% \(.\{19\}\)==\(.*L\)/ s//*o\1**\2/ / %\(.\{19\}\)==\(.*R\)/ s//o*\1**\2/ /%\(.\{20\}\)=/ s//=\1!/ } /u/ { /=\(.\{20\}\)o/ s//*\1 / /==\(.\{19\}\)% \(.*L\)/ s//**\1*o\2/ /==\(.\{19\}\) %\(.*R\)/ s//**\1o*\2/ /=\(.\{20\}\)%/ s//!\1=/ } # end tri-explosion: invert all directions (keep before "end free X" code) /\*\*/ { y/udRL/DULR/ b end } # end free Y explosion /! .*L/ b chkwise / !.*R/ b chkwise # end free X explosion /\*/ b chkwise # detect paddle bounce, change Y-direction /o\(.\{20\}\)-/ y/d/u/ # plain up-down ball move (no explosion) /u/ s/ \(.\{20\}\)o/o\1 / /d/ s/o\(.\{20\}\) / \1o/ # tricky move over a block - part II /u/ s/ \(.\{20\}\)%/o\1=/ /d/ s/%\(.\{20\}\) /=\1o/ # you missed the ball! /o\(.\{20\}\)[_.]/ y/o/*/ :end # show move over a block explosion right y/!/*/ # reset last explosion reminder for plain moves /\*/ !s/[<>]$/ / ### detect level finished or GAME OVER /=/ !s/\(\([^\n]*\n\)\{5\}[^|]*|\).........../\1K(33;1) VICTORY!!K()/ /\./ !s/\(\([^\n]*\n\)\{5\}[^|]*|\).........../\1K(31;1) GAME OVERK()/ ### save map h ### hide direction (comment for debug) s/...$// ### add colors s/--/K(32;1)&K()/g s/~~/K(32;1)&K()/g s/o/K(33;1)&K()/g s/ \{0,1\}_\{1,\} \{0,1\}/K(42;32)&K()/g s/|/K(42;32)&K()/g s/\./K(42;32;1)&K()/g s/#/K(42;37;1)&K()/g s/\*/K(31;1)&K()/g b nocolor :showmap s/K(\([0-9;]*\))/[\1m/g p /VICT/ q /OVER/ q d ### colorized by sedsed, a debugger and code formatter for sed scripts ### original script: http://aurelio.net/bin/sed/arkanoid/arkanoid.sed