summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--Doc/Zsh/contrib.yo20
-rw-r--r--Functions/Misc/.distfiles1
-rw-r--r--Functions/Misc/tetris243
4 files changed, 268 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 331551bab..e0412abde 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2001-09-21 Andrew Main (Zefram) <zefram@zsh.org>
+
+ * Doc/Zsh/contrib.yo, Functions/Misc/tetris: Tetris game for ZLE.
+
2001-09-20 Bart Schaefer <schaefer@zsh.org>
* 15847: Src/init.c: Avoid using the word "termcap" in an error
diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
index 4f91c7680..013a37979 100644
--- a/Doc/Zsh/contrib.yo
+++ b/Doc/Zsh/contrib.yo
@@ -791,6 +791,26 @@ See `Accessing On-Line Help'
ifzman(above)\
ifnzman((noderef(Utilities))).
)
+item(tt(tetris))(
+Zsh was once accused of not being as complete as Emacs,
+because it lacked a Tetris game. This function was written to
+refute this vicious slander.
+
+This function must be used as a ZLE widget:
+
+example(autoload -U tetris
+zle -N tetris
+bindkey var(keys) tetris)
+
+To start a game, execute the widget by typing the var(keys). Whatever command
+line you were editing disappears temporarily, and your keymap is also
+temporarily replaced by the Tetris control keys. The previous editor state
+is restored when you quit the game (by pressing `tt(q)') or when you lose.
+
+If you quit in the middle of a game, the next invocation of the tt(tetris)
+widget will continue where you left off. If you lost, it will start a new
+game.
+)
findex(zcalc)
item(tt(zcalc) [ var(expression) ... ])(
A reasonably powerful calculator based on zsh's arithmetic evaluation
diff --git a/Functions/Misc/.distfiles b/Functions/Misc/.distfiles
index 5040576b5..9de53001a 100644
--- a/Functions/Misc/.distfiles
+++ b/Functions/Misc/.distfiles
@@ -4,4 +4,5 @@ allopt harden nslookup zkbd zstyle+
checkmail is-at-least run-help zmv
colors mere zed zrecompile
getjobs promptnl
+tetris
'
diff --git a/Functions/Misc/tetris b/Functions/Misc/tetris
new file mode 100644
index 000000000..a9d367964
--- /dev/null
+++ b/Functions/Misc/tetris
@@ -0,0 +1,243 @@
+# Someone once accused zsh of not being as complete as Emacs, because it
+# lacks Tetris and an adventure game.
+#
+# autoload -U tetris
+# zle -N tetris
+# bindkey '...' tetris
+
+emulate -L zsh
+
+tetris_hsz=11
+tetris_vsz=20
+typeset -ga tetris_shapes
+tetris_shapes=(
+ 0x0f00 0x4444 0x0f00 0x4444
+ 0x4e00 0x4c40 0x0e40 0x4640
+ 0x6600 0x6600 0x6600 0x6600
+ 0x4620 0x6c00 0x4620 0x6c00
+ 0x2640 0x6300 0x2640 0x6300
+ 0x6440 0x8e00 0x44c0 0x0e20
+ 0xc440 0x0e80 0x4460 0x2e00
+)
+typeset -gA tetris_rotations
+tetris_rotations=(
+ 0x0f00 0x4444 0x4444 0x0f00
+ 0x4e00 0x4c40 0x4c40 0x0e40 0x0e40 0x4640 0x4640 0x4e00
+ 0x6600 0x6600
+ 0x4620 0x6c00 0x6c00 0x4620
+ 0x2640 0x6300 0x6300 0x2640
+ 0x6440 0x8e00 0x8e00 0x44c0 0x44c0 0x0e20 0x0e20 0x6440
+ 0xc440 0x0e80 0x0e80 0x4460 0x4460 0x2e00 0x2e00 0xc440
+)
+
+tetris_blankline=
+for ((tetris_i=tetris_hsz; tetris_i--; )); do
+ tetris_blankline="$tetris_blankline "
+done
+tetris_blankboard=
+for ((tetris_i=tetris_vsz; tetris_i--; )); do
+ tetris_blankboard="$tetris_blankboard$tetris_blankline"
+done
+
+bindkey -N tetris
+bindkey -R -M tetris '\000-\377' tetris-timeout
+for ((tetris_i=256; tetris_i--; )); do
+ bindkey -M tetris 'T\'$(([##8]tetris_i)) tetris-timeout
+done
+bindkey -M tetris Ta tetris-left
+bindkey -M tetris Tj tetris-left
+bindkey -M tetris Ts tetris-rotate
+bindkey -M tetris Tk tetris-rotate
+bindkey -M tetris Td tetris-right
+bindkey -M tetris Tl tetris-right
+bindkey -M tetris 'T ' tetris-drop
+bindkey -M tetris Tq tetris-quit
+
+unset tetris_board tetris_score
+
+zle -N tetris
+function tetris {
+ emulate -L zsh
+ if ! zle; then
+ print -u2 "Use M-x tetris RET to play tetris."
+ return 2
+ fi
+ tetris_saved_state="BUFFER=${BUFFER:q};CURSOR=${CURSOR:q};MARK=${MARK:q};zle -K ${KEYMAP:q}"
+ tetris_speed=$((100.0/KEYTIMEOUT))
+ zle -K tetris
+ if [[ ${tetris_board+set} == set ]]; then
+ tetris-timeout
+ else
+ tetris_board=$tetris_blankboard
+ tetris_score=0
+ tetris-new-block
+ fi
+}
+
+function tetris-new-block {
+ emulate -L zsh
+ tetris_block=$tetris_shapes[1+RANDOM%$#tetris_shapes]
+ tetris_block_y=0
+ tetris_block_x=4
+ if ! tetris-block-fits; then
+ tetris-place-block "#"
+ tetris-render-screen
+ unset tetris_board tetris_score
+ tetris-quit
+ return
+ fi
+ tetris-place-block "*"
+ tetris-timed-move
+}
+
+zle -N tetris-left
+function tetris-left {
+ emulate -L zsh
+ tetris-place-block " "
+ (( tetris_block_x-- ))
+ tetris-block-fits || (( tetris_block_x++ ))
+ tetris-place-block "*"
+ tetris-timeout
+}
+
+zle -N tetris-right
+function tetris-right {
+ emulate -L zsh
+ tetris-place-block " "
+ (( tetris_block_x++ ))
+ tetris-block-fits || (( tetris_block_x-- ))
+ tetris-place-block "*"
+ tetris-timeout
+}
+
+zle -N tetris-rotate
+function tetris-rotate {
+ emulate -L zsh
+ tetris-place-block " "
+ local save_block=$tetris_block
+ tetris_block=$tetris_rotations[$tetris_block]
+ tetris-block-fits || tetris_block=$save_block
+ tetris-place-block "*"
+ tetris-timeout
+}
+
+zle -N tetris-drop
+function tetris-drop {
+ emulate -L zsh
+ tetris-place-block " "
+ ((tetris_block_y++))
+ while tetris-block-fits; do
+ ((tetris_block_y++))
+ done
+ ((tetris_block_y--))
+ tetris-block-dropped
+}
+
+zle -N tetris-timeout
+function tetris-timeout {
+ emulate -L zsh
+ tetris-place-block " "
+ ((tetris_block_y++))
+ if tetris-block-fits; then
+ tetris-place-block "*"
+ tetris-timed-move
+ return
+ fi
+ ((tetris_block_y--))
+ tetris-block-dropped
+}
+
+function tetris-block-dropped {
+ emulate -L zsh
+ tetris-place-block "O"
+ local fl=${tetris_blankline// /O} i=$((tetris_block_y*tetris_hsz)) y
+ for ((y=0; y!=4; y++)); do
+ if [[ $tetris_board[i+1,i+tetris_hsz] == $fl ]]; then
+ tetris_board[i+1,i+tetris_hsz]=
+ tetris_board=$tetris_blankline$tetris_board
+ ((tetris_score++))
+ fi
+ ((i += tetris_hsz))
+ done
+ tetris-new-block
+}
+
+function tetris-block-fits {
+ emulate -L zsh
+ local y x i=$((1+tetris_block_y*tetris_hsz+tetris_block_x)) b=0x8000
+ for ((y=0; y!=4; y++)); do
+ for ((x=0; x!=4; x++)); do
+ if ((tetris_block&b)); then
+ ((x+tetris_block_x >= 0)) || return 1
+ ((x+tetris_block_x < tetris_hsz)) || return 1
+ ((y+tetris_block_y >= 0)) || return 1
+ ((y+tetris_block_y < tetris_vsz)) || return 1
+ [[ $tetris_board[i] == " " ]] || return 1
+ fi
+ ((b >>= 1))
+ ((i++))
+ done
+ ((i+=tetris_hsz-4))
+ done
+ return 0
+}
+
+function tetris-place-block {
+ emulate -L zsh
+ local y x i=$((1+tetris_block_y*tetris_hsz+tetris_block_x)) b=0x8000
+ for ((y=0; y!=4; y++)); do
+ for ((x=0; x!=4; x++)); do
+ ((tetris_block&b)) && tetris_board[i]=$1
+ ((b >>= 1))
+ ((i++))
+ done
+ ((i+=tetris_hsz-4))
+ done
+}
+
+function tetris-timed-move {
+ emulate -L zsh
+ tetris-render-screen
+ LBUFFER=
+ RBUFFER=$'\n'$tetris_screen
+ zle -R
+ zle -U T
+}
+
+function tetris-render-screen {
+ emulate -L zsh
+ setopt extendedglob
+ local s i extras
+ extras=(
+ "Score: $tetris_score"
+ ""
+ "Game parameters: ${tetris_hsz}x$tetris_vsz, ${tetris_speed}Hz"
+ ""
+ "Keys: left: a j"
+ " rotate: s k"
+ " right: d l"
+ " drop: space"
+ " quit: q"
+ )
+ for ((i=0; i!=tetris_vsz; i++)); do
+ s="$s|${${${${${tetris_board[1+i*tetris_hsz,(i+1)*tetris_hsz]}//O/()}//\*/**}// / }//\#/##}|"${extras[1]+ $extras[1]}$'\n'
+ extras[1]=()
+ done
+ s="$s+${tetris_blankline// /--}+"
+ tetris_screen=$s
+}
+
+zle -N tetris-quit
+function tetris-quit {
+ emulate -L zsh
+ if [[ ! -o always_last_prompt ]]; then
+ BUFFER=
+ zle -M $tetris_screen
+ fi
+ eval $tetris_saved_state
+ if [[ -o always_last_prompt ]]; then
+ zle -M $tetris_screen
+ fi
+}
+
+tetris "$@"