summary refs log tree commit diff
path: root/Functions/Misc
diff options
context:
space:
mode:
Diffstat (limited to 'Functions/Misc')
-rw-r--r--Functions/Misc/.distfiles1
-rw-r--r--Functions/Misc/tetris243
2 files changed, 244 insertions, 0 deletions
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 "$@"