mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-11-19 13:33:52 +01:00
244 lines
5.3 KiB
Plaintext
244 lines
5.3 KiB
Plaintext
# 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 "$@"
|