• shell版俄罗斯方块最终源码 分类: shell版俄罗斯方块 2015-07-28 17:06 66人阅读 评论(0) 收藏


    #!/bin/bash
    
    #Pargram  tetris game
    
    #History Walker 2015-07-27 version:first
    
    APP_NAME="${0##*[\/]}"
    APP_VERSION="1.0"
    
    #颜色定义
    iSumColor=7    #颜色总数
    cRed=1        #红色
    cGreen=2
    cYellow=3
    cBlue=4
    cFuchSia=5
    cCyan=6
    cWhite=7
    
    #位置定义
    marginLeft=10
    marginTop=10
    ((mapLeft=marginLeft+2))
    ((mapTop=marginTop+1))
    mapWidth=10
    mapHeight=15
    
    #信号定义
    sigRotate=25
    sigLeft=26
    sigRight=27
    sigDown=28
    sigAllDown=29
    sigExit=30
    
    #颜色设置
    cBorder=$cGreen
    cScore=$cFuchsia
    cScoreValue=$cCyan
    
    #方块类型
    box0_0=(0 0 0 1 1 0 1 1 0 4)
     
    box1_0=(0 1 1 1 2 1 3 1 0 3)
    box1_1=(1 0 1 1 1 2 1 3 -1 3)
     
    box2_0=(0 0 1 0 1 1 2 1 0 4)
    box2_1=(0 1 0 2 1 0 1 1 0 3)
     
    box3_0=(0 1 1 0 1 1 2 0 0 4)
    box3_1=(0 0 0 1 1 1 1 2 0 4)
     
    box4_0=(0 2 1 0 1 1 1 2 0 3)
    box4_1=(0 1 1 1 2 1 2 2 0 3)
    box4_2=(1 0 1 1 1 2 2 0 -1 3)
    box4_3=(0 0 0 1 1 1 2 1 0 4)
     
    box5_0=(0 0 1 0 1 1 1 2 0 3)
    box5_1=(0 1 0 2 1 1 2 1 0 3)
    box5_2=(1 0 1 1 1 2 2 2 -1 3)
    box5_3=(0 1 1 1 2 0 2 1 0 4)
     
    box6_0=(0 1 1 0 1 1 1 2 0 3)
    box6_1=(0 1 1 1 1 2 2 1 0 3)
    box6_2=(1 0 1 1 1 2 2 1 -1 3)
    box6_3=(0 1 1 0 1 1 2 1 0 4)
    
    iSumType=7     #方块总数
    boxStyle=(1 2 2 2 4 4 4) #每种方块对应的变化数
    
    iScoreEachLevel=50
    #运行时数据
    sig=0
    iScore=0
    iLevel=0
    
    boxNext=()  #下一个方块
    iboxNextColor=0
    iboxNextType=0
    iboxNextStyle=0
    
    boxCur=()
    iBoxCurColor=0
    iBoxCurType=0
    iBoxCurStyle=0
    
    #显示进程PID
    pidDisplayer=0
    
    #这两个是相对于边框的坐标
    boxCurX=-1
    boxCurY=-1
    #背景数组,用颜色表示,没有方块则为-1
    map=()
    
    for (( i = 0; i < mapHeight * mapWidth ; i++ ))
    do
    	map[$i]=-1
    done
    
    MyExitNoSub()
    {
    	local y
    	stty $sTTY               #恢复终端
    	((y = marginTop + mapHeight + 10 ))
    
    	echo -e "33[?25h33[${y};0H"
    	exit
    }
    
    MyExit()
    {
    	kill -$sigExit $pidDisplayer                  #关闭显示进程
    	MyExitNoSub
    }
    
     #显示退出
    ShowExit()
    {
        local y
        (( y = marginTop + mapHeight + 3 ))
        echo -e "33[${y};1HGameOver!33[0m"
        exit
    }
    
    
    #绘制方块函数
    DrawCurBox()
    {
    	local i x y bErase sBox
    	bErase=$1
    	if (( ${bErase} == 0 ))                          #根据参数不同,选择擦除方块或绘制方块
    	then
    		sBox="4040"
    	else
    		sBox="[]"
    		echo -ne "33[1m33[3${iBoxCurColor}m33[4${iBoxCurColor}m"
    	fi
    
    	for (( i = 0; i < 8; i += 2))
    	do
    		(( y = mapTop + 1 + ${boxCur[$i]} + boxCurY ))                #方块刚出现时就会全部绘制在棋盘中
    		(( x = mapLeft + 1 + 2 * (boxCurX + ${boxCur[$i+1]}) ))
    		echo -ne "33[${y};${x}H${sBox}"
    	done
    	echo -ne "33[0m"
    }
    
    #接收命令
    RunAsKeyReceiver()
    {
    	local Key aKey sig cESC sTTY
    
    	pidDisplayer=$1
    	aKey=(0 0 0)
    
    	cESC=`echo -ne "33"`
    	cSpace=`echo -ne "40"`
    
    	sTTY=`stty -g`                                   #保存终端
    
    	trap "MyExit;" INT QUIT
    	trap "MyExitNoSub;" $sigExit
    
    	echo -ne "33[?25l"
    
    	while :
    	do                                               #始终在等待信号
    		read -s -n 1 Key
    
    		aKey[0]=${aKey[1]}
    		aKey[1]=${aKey[2]}
    		aKey[2]=$Key
    
    		sig=0
    
    		if [[ $Key == $cESC && {aKey[1]} == $cESC ]]
    		then
    			MyExit
    		elif [[ ${aKey[0]} == $cESC && ${aKey[1]} == "[" ]]
    		then
    			if [[ $Key == "A" ]]; then sig=$sigRotate              #判断上下左右输入
    			elif [[ $Key == "B" ]]; then sig=$sigDown
    			elif [[ $Key == "C" ]]; then sig=$sigRight
    			elif [[ $Key == "D" ]]; then sig=$sigLeft
    			fi
    		elif [[ $Key == "W" || $Key == "w" ]]; then sig=$sigRotate
    		elif [[ $Key == "S" || $Key == "s" ]]; then sig=$sigDown
    		elif [[ $Key == "A" || $Key == "a" ]]; then sig=$sigLeft
    		elif [[ $Key == "D" || $Key == "d" ]]; then sig=$sigRight
    		elif [[ [$Key] == "[]" ]]; then sig=$sigAllDown
    		elif [[ $Key == "Q" || $Key == "q" ]]	
    		then
    			MyExit
    		fi
    
    		if [[ $sig != 0 ]]
    		then
    			kill -$sig $pidDisplayer
    		fi
    	done
    }
    
    #绘制边界
    DrawBorder()
    {
    	clear
    	local i y x1 x2
    
    	echo -ne "33[1m33[3${cBorder}m33[4${cBorder}m"
    
    	((x1 = marginLeft + 1))
    	((x2 = x1 + 2 + mapWidth * 2))
    
    	for (( i = 0; i < mapHeight; i++ ))
    	do
    		((y = i+ marginTop + 2))
    		echo -ne "33[${y};${x1}H||"
    		echo -ne "33[${y};${x2}H||"
    	done
    
    	((x1 = marginTop + mapHeight + 2))
    	((upBorder = marginTop +1))
    	for ((i =0 ;i < mapWidth + 2;i++))
    	do
    		((y = i * 2 + marginLeft + 1))
    		echo -ne "33[${upBorder};${y}H=="
    		echo -ne "33[${x1};${y}H=="
    	done
    	echo -ne "33[0m"
    
    	echo -ne "33[1m"
    	((y = marginLeft + mapWidth *2 + 7))
    	((x1 = marginTop + 10))
    
    	echo -ne "33[3${cScore}m33[${x1};${y}HScore"
    	((x1 = marginTop + 11))
    	echo -ne "33[3${cScoreValue}m33[${x1};${y}H${iScore}"
    	((x1 = marginTop + 13))
    	echo -ne "33[3${cScore}m33[${x1};${y}HLevel"
    	((x1 = marginTop + 14))
    	echo -ne "33[3${cScoreValue}m33[${x1};${y}H${iLevel}"
    	echo -ne "33[0m"
    }
    
    #用于判断是否可以移动
    BoxMove()
    {
    	local i x y xPos yPos
    	yPos=$1
    	xPos=$2
    
    	for (( i = 0 ; i < 8 ; i += 2 ))
    	do
    		(( y = yPos + ${boxCur[$i]} ))
    		(( x = xPos + ${boxCur[$i+1]} ))
    
    		if (( y < 0 || y >= mapHeight || x < 0 || x >= mapWidth ))
    		then
    			return 1
    		fi
    
    		if (( ${map[y * mapWidth + x]} != -1 ))
    		then
    			return 1
    		fi
    	done
    	return 0
    }
    
    #准备下一方块
    PrepareNextBox()
    {
    	local i x y
    	#擦除已有的预显示方块
    	if (( ${#boxNext[@]} != 0 )); then
    		for ((i = 0 ; i < 8 ;i += 2 ))
    		do
    			((y = marginTop +1 + ${boxNext[$i]}))
    			((x = marginLeft + 2 * mapWidth + 7 + 2 * ${boxNext[$i +1]}))
    			echo -ne "33[${y};${x}H4040"
    		done
    	fi
    
       #随机生成下一方块
        (( iBoxNextType = RANDOM % iSumType))
    	(( iBoxNextStyle = RANDOM % ${boxStyle[$iBoxNextType]} ))
    	(( iBoxNextColor = RANDOM % ${iSumColor} + 1 ))
    
    	boxNext=( `eval 'echo ${box'$iBoxNextType'_'$iBoxNextStyle'[@]}'` )
    
    	echo -ne "33[1m33[3${iBoxNextColor}m33[4${iBoxNextColor}m"
    
    #绘制预显示方块
    	for (( i = 0; i < 8 ; i += 2 ))
    	do
    		(( y = marginTop + 1 + ${boxNext[$i]} ))
    		(( x = marginLeft + 2 * mapWidth + 7 + 2 * ${boxNext[$i+1]} ))
    		echo -ne "33[${y};${x}H[]"
    	done
    	echo -ne "33[0m"
    }
    
    #生成方块
    CreateBox()
    {
    	if (( ${#boxCur[@]} == 0 ))
    	then
    		(( iBoxCurType = RANDOM % iSumType))
    		(( iBoxCurStyle = RANDOM % ${boxStyle[$iBoxCurType]} ))
    		(( iBoxCurColor = RANDOM % $iSumColor + 1 ))
    	else
    		iBoxCurType=$iBoxNextType
    		iBoxCurStyle=$iBoxNextStyle
    		iBoxCurColor=$iBoxNextColor
    	fi
    
    	boxCur=( `eval 'echo ${box'$iBoxCurType'_'$iBoxCurStyle'[@]}'` )
    	boxCurY=boxCur[8]
    	boxCurX=boxCur[9]
    
    #创建后开始绘制
    	DrawCurBox 1
    	if ! BoxMove $boxCurY $boxCurX
    	then
    #		kill -$sigExit $PPID
    		MyExit
    #	ShowExit
    	fi
    
    #同时开始准备下一方块
    	PrepareNextBox
    }
    
    #初始化
    InitDraw()
    {
    	clear
    	DrawBorder
    	CreateBox
    }
    
    #将方块写入背景当中
    Box2Map()
    {
    	local i j x y line
    	#填充背景色
    	for ((i = 0 ; i < 8 ; i += 2))
    	do
    		((y = ${boxCur[$i]} + boxCurY ))
    		((x = ${boxCur[$i+1]} + boxCurX ))
    		map[y*mapWidth+x]=$iBoxCurColor
        done
    
    	line=0
    	
        #判断每一行
    	for (( i = 0 ; i < mapHeight ; i++))
    	do
    		for (( j = 0; j < mapWidth; j++ ))
    		do
    			[[ ${map[i * mapWidth + j]} -eq -1 ]] && break
    		done
    
    		[ $j -lt $mapWidth ] && continue
    		(( line++ ))
    
            #删除第i行,并将第0行到i-1行全部下移一行,移动行的下限(0)可以进一步简化
    		for (( j = i * mapWidth - 1; j >= 0; j-- ))
    		do
    			((x = j + mapWidth))
    	    	map[$x]=${map[$j]}
    		done
    	    #将第0行置空
         	for ((i = 0; i<mapWidth;i++))
        	do
    	    	map[$i]=-1
        	done
    	done
    
        #写入背景结束后,开始计算分数    
    	[ $line -eq 0 ] && return
    
    	(( x = marginLeft + mapWidth * 2 + 7))
    	(( y = marginTop + 11 ))
    	(( iScore += line * 2 ))
        #显示新的分数
    	echo -ne "33[1m33[3${cScoreValue}m33[${y};${x}H${iScore}"
        #显示速度等级
    	if ((iScore % iScoreEachLevel < line * 2 - 1))
    	then
    		if ((iLevel < 20))
    		then
    			(( iLevel++ ))
    			(( y = marginTop + 14 ))
    			echo -ne "33[3${cScoreValue}m33[${y};${x}H${iLevel}"
    		fi
    	fi
    	echo -ne "33[0m"
    
        #重新绘制界面
    	for (( i = 0; i < mapHeight ; i++))
    	do
            #棋盘相对于屏幕的坐标
    		((y = i + mapTop + 1))
    		((x = mapLeft + 1))
            #移动光标
    		echo -ne "33[${y};${x}H"
    		
    		for (( j = 0; j < mapWidth ; j++))
    		do
    			((tmp = i * mapWidth + j))
    			if ((${map[$tmp]} == -1))                                     #说明是空格
    			then
    				echo -ne "  "
    			else
    				echo -ne "33[1m33[3${map[$tmp]}m33[4${map[$tmp]}m[]33[0m"
    			fi
    		done
    	done
    }
    
    #直接下落到底
    BoxAllDown()
    {
    	local y iDown
    
    	iDown=0
    
    	(( y = boxCurY + 1 ))
    	while BoxMove $y $boxCurX
    	do
    		(( y++ ))
    		(( iDown++ ))
    	done
    
    	DrawCurBox 0
    	(( boxCurY += iDown ))
    	DrawCurBox 1
    	Box2Map
    	CreateBox
    }
    
    #上方向键,旋转
    BoxRotate()
    {
    	[ ${boxStyle[$iBoxCurType]} -eq 1 ] && return
    	(( rotateStyle = (iBoxCurStyle +1) % ${boxStyle[$iBoxCurType]} ))
    	boxTmp=( `eval 'echo ${boxCur[@]}'` )
    	boxCur=( `eval 'echo ${box'$iBoxCurType'_'$rotateStyle'[@]}'` )
    
    	if BoxMove $boxCurY $boxCurX
    	then
    		boxCur=( `eval 'echo ${boxTmp[@]}'` )
    		DrawCurBox 0
    
    		boxCur=( `eval 'echo ${box'$iBoxCurType'_'$rotateStyle'[@]}'` )
    		DrawCurBox 1
    		iBoxCurStyle=$rotateStyle
    	else
    		boxCur=( `eval 'echo ${boxTmp[@]}'` )
    	fi
    }
    
    
    BoxLeft()
    {
    	local x
    	((x = boxCurX - 1))
    	if BoxMove $boxCurY $x
    	then
    		DrawCurBox 0
    		((boxCurX = x))
    		DrawCurBox 1
    	fi
    }
    
    
    BoxRight()
    {
    	local x
    	((x = boxCurX + 1))
    	if BoxMove $boxCurY $x
    	then
    		DrawCurBox 0
    		((boxCurX = x))
    		DrawCurBox 1
    	fi
    }
    
    BoxDown()
    {
    	local y
    	(( y = boxCurY + 1 ))
    	if BoxMove $y $boxCurX                     #如果可移动则移动,不能则写入背景当中
    	then
    		DrawCurBox 0
    		(( boxCurY = y ))
    		DrawCurBox 1
    	else
    		Box2Map                               #写入背景当中,并创建下一方块
    		CreateBox
    	fi
    }
    
    
    RunAsDisplayer()
    {                                           #显示进程运行这一函数
    	local sigThis
    	InitDraw                                #初始化操作
    
    	trap "sig=$sigRotate;" $sigRotate
    	trap "sig=$sigLeft;" $sigLeft
    	trap "sig=$sigRight;" $sigRight
    	trap "sig=$sigDown;" $sigDown
    	trap "sig=$sigAllDown;" $sigAllDown
    	trap "ShowExit;" $sigExit
    
    	while :                                   #始终在循环等待
    	do
    #本循环用于接收信号,for循环中有个睡眠时间,for循环之后有个BoxDown函数
    #for循环睡眠时间越长,自动下落延迟越长,所以for循环的次数决定了下落速度
    		for ((i = 0; i < 21 - iLevel; i++))
    		do
    			sleep 0.02
    			sigThis=$sig
    			sig=0
    
    			if (( sigThis == sigRotate )); then BoxRotate;
    			elif (( sigThis == sigLeft )); then BoxLeft;
    			elif (( sigThis == sigRight )); then BoxRight;
    			elif (( sigThis == sigDown )); then BoxDown;
    			elif (( sigThis == sigAllDown )); then BoxAllDown;
    			fi
    		done
    		BoxDown
    	done
    }
    
    #help
    usage()
    {
    	echo "tetris.sh [option]"
    	echo "option:"
    	echo "   --version:for version information"
    	echo "   --help:for help information"
    	echo "no option to run game"	
    }
    
    #游戏主程序,以上是函数定义
    if [[ "$1" == "--version" ]]; then
    	echo "$APP_NAME $APP_VERSION"
    elif [[ "$1" == "--help" || "$1" == "--h" ]];then
    	usage
    elif [[ "$1" == "--show" || "$1" == "--v" ]]; then
    	RunAsDisplayer                              #只运行显示进程
    else
    	bash $0 --show&                             #启动显示进程,并放入后台开始执行
    	RunAsKeyReceiver $!                         #获取最后一个后台进程
    fi




  • 相关阅读:
    轻量级的Web服务器Nginx0.9.0 开发版发布 狼人:
    微软发布Silverlight 5 Beta新特性 狼人:
    TechCrunch新闻评论:Flash耗电问题严重 狼人:
    IE9是最佳浏览器? 狼人:
    Silverlight面向客户端,HTML5面向Web 狼人:
    Silverlight 结构分析 狼人:
    HTML5是否已经准备好了?仍在W3C层层审核当中 狼人:
    Adobe驳斥Flash过度耗电论 称HTML5更耗电 狼人:
    Silverlight 5即将来临 狼人:
    运行控制[置顶] 有趣的编程控制自己电脑的CPU
  • 原文地址:https://www.cnblogs.com/zclzqbx/p/4687029.html
Copyright © 2020-2023  润新知