mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-10-31 18:10:56 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			243 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			243 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| # 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 "$@"
 |