首页 > 学技术 > 技术网文 > Linux Shell > 正文

[原创] shell游戏:扫雷


来源 chinaunix.net 酷勤网整理

shell游戏:扫雷

期待各位帮忙测试,如有BUG,请及时告知,谢谢
转载请保持版权声明完整,十分感谢

下载代码:
http://bitbull.cn/works/mine.sh

屏幕截图:
*

运行环境:
bash
80x24终端

usage:
$chmod 755 mine.sh
$./mine.sh

按1-3选择对应难度,4退出

方向:
上:w 下:s 左:a 右:d
标识地雷:
FLAG:f
挖:
DIG:j
重玩
NEWGAME:n
退出
EXIT:x 

规则:
玩家可用方向键移动指针,按j挖雷,若挖到地雷,则游戏结束.否则,游戏将在你所挖方块内显示该方块周围8个方块内所有地雷数.若怀疑某方块为地雷,可按f键进行标识,以避免误挖.挖开地图内所有非雷方块则获胜.

代码:
#!/bin/bash

#-------------CopyRight-------------
#   Name:Mine Sweeping
#   Version Number:1.00
#   Type:game
#   Language:bash shell
#   Date:2005-10-26
#   Author:BitBull
#   Email:BitBull.cn(at)gmail.com
#------------Environment------------
#   Terminal: column 80 line 24
#   Linux 2.6.9 i686
#   GNU Bash 3.00.15
#-----------------------------------

#---------------Define--------------
ECHO="echo -ne"
ESC="\033["

OK=0
FALSE=1
#--------------Variable--------------
#ANSI ESC action
FLASH=5
REV=7

#color
NULL=0
BLACK=30
RED=31
GREEN=32
ORANGE=33
BLUE=34
PURPLE=35
SBLUE=36
GREY=37

#back color
BBLACK=40
BRED=41
BGREEN=42
BORANGE=43
BBLUE=44
BPURPLE=45
BSBLUE=46
BGREY=47

MINE='@'
FLAG='F'
NUL=' '
SHADOW='X'

X=0
Y=0
CurX=1 #cur's X
CurY=1 #cur's Y
OCurX=1 #old cur's X
OCurY=1 #old cur's Y
MCount=0 #count mine
FCount=0 #count flag
SCount=0 #count shadow
MXYp=0 #MXY Array's ptr
#---------------Array----------------

#if ${XY[]} == M { mine }
#if ${XY[]} == F { flag }
#if ${XY[]} == N { null }
#if ${XY[]} == S { shadow }
#if ${XY[]} == [1-8] { tip_num }
#${XY[]} init in XYInit(i)

MXY[0]=""

#--------------Function--------------

function SttyInit ()
{
stty_save=$(stty -g) #backup stty

clear
trap "GameExit;" 2 15
stty -echo

$ECHO "${ESC}?25l" #hidden cursor

return $OK
}

function GameExit ()
{
stty $stty_save
stty echo
clear
trap 2 15
$ECHO "${ESC}?25h${ESC}0;0H${ESC}0m"

exit $OK
}

#print help
function Help ()
{
msg="Move:w s a d Dig:j Flag:f NewGame:n Exit:x   --CopyRight-- -2005-10-28 BitBull--"
$ECHO "${ESC}${REV};${RED}m${ESC}24;1H${msg}${ESC}${NULL}m"

return $OK
}

#print dialog window in screen
function PMsg ()
{
local title="$1" content="$2" greeting="$3"

        $ECHO "${ESC}${RED}m"
        $ECHO "${ESC}11;20H ------------------------------------------- "
        $ECHO "${ESC}12;20H|         ======>$title<======           |"
        $ECHO "${ESC}13;20H|         $content          |"
        $ECHO "${ESC}14;20H|         ======>$greeting<======           |"
        $ECHO "${ESC}15;20H ------------------------------------------- "
        $ECHO "${ESC}${NULL}m"

return $OK
}

#print menu and player choose level,then ${X,Y,MCount,FCount,SCount} init
function Menu ()
{
local key

$ECHO "${ESC}6;1H${ESC}${RED}m"
cat<<MENUEND
                       +++++++++++++++++++++++++++++
                       +        (1) Easy           +
                       +        (2) Normal         +
                       +        (3) Hardly         +
                       +        (4) Exit           +
                       +++++++++++++++++++++++++++++
MENUEND
$ECHO "${ESC}${NULL}m"

while read -s -n 1 key
do
case $key in
1) X=10;Y=10;MCount=10;FCount=10;SCount=100;break
;;
2) X=20;Y=14;MCount=28;FCount=28;SCount=280;break
;;
3) X=36;Y=18;MCount=65;FCount=65;SCount=648;break
;;
4) GameExit
;;
esac
done

return $OK
}

#receive CurX CurY,put it into XY[CurX+X*(CurY-1))]
#if $# == 3;write into XY[]
#if $# == 2;read from XY[]
function XYFormat ()
{
local XTmp=$1 YTmp=$2

if [[ $# -eq 3 ]]
then XY[$XTmp+$X*($YTmp-1)]=$3
else echo ${XY[$XTmp+$X*($YTmp-1)]}
fi

return $OK
}

function DrawInit ()
{
local DIline DIline2

DIline=$( for (( i=1; i<$((X*2)); i++ )) do $ECHO '-';done )
DIline2=$( for (( i=0; i<X; i++ )) do $ECHO "|${ESC}${SBLUE}mX${ESC}${NULL}m";done )

clear
Help

$ECHO "${ESC}1;1H+${DIline}+"
for (( i=0; i<Y; i++ ))
do
$ECHO "${ESC}$((i+2));1H${DIline2}|"
done
$ECHO "${ESC}$((Y+2));1H+${DIline}+"

return $OK
}

#${XY[*]}=S
function XYInit ()
{
for (( i=1; i<=$X; i++ ))
do
for (( j=1; j<=$Y; j++ ))
do
XYFormat $i $j S
done
done
return $OK
}

#check X Y
function CheckXY ()
{
local XYTmp="$1 $2"

for(( i=0; i<MXYp; i++ ))
do
if [[ "${MXY}" == "$XYTmp" ]]
then return $FALSE
fi
done

return $OK
}

#RANDOM mine's X Y
function XYRand ()
{
local XTmp YTmp

for(( i=0; i<MCount; i++ ))
do
while : 
do
XTmp=$(( RANDOM % ( X - 1 ) + 1 ))
YTmp=$(( RANDOM % ( Y - 1 ) + 1 ))
CheckXY $XTmp $YTmp

if [[ "$?" == "$OK" ]]
then
XYFormat $XTmp $YTmp M
MXY="$XTmp $YTmp"
(( ++MXYp ))
break
else continue
fi
done
done

return $OK
}

#DEBUG
# print ${XY[*]} into ./mine.tmp
#you can read mine.tmp to know where is mine,xixi~~:)
#M is mine
function DEBUGPXY ()
{
rm mine.tmp>/dev/null 2>&1
for(( i=1; i<=$Y; i++ ))
do
for(( j=1; j<=$X; j++))
do
$ECHO "$(XYFormat $j $i)">>mine.tmp
done
$ECHO "\n">>mine.tmp
done

return $OK
}

#move cur
#usage:CurMov [UP|DOWN|LEFT|RIGHT]
function CurMov ()
{
local direction=$1 Xmin=1 Ymin=1 Xmax=$X Ymax=$Y

OCurX=$CurX
OCurY=$CurY

case $direction in
"UP") if [[ $CurY -gt $Ymin ]];then (( CurY-- ));fi
;;
"DOWN") if [[ $CurY -lt $Ymax ]];then (( CurY++ ));fi
;;
"LEFT") if [[ $CurX -gt $Xmin ]];then (( CurX-- ));fi
;;
"RIGHT")if [[ $CurX -lt $Xmax ]];then (( CurX++ ));fi
;;
esac

if [[ $CurX != $OCurX || $CurY != $OCurY ]]
then DrawPoint $CurX $CurY CUR
fi

return $OK
}

#display point
#include cur,flag,mine,shadow,nul,tip [1-8]
function DrawPoint ()
{
local TCurX=$(( $1 * 2 )) TCurY=$(( $2 + 1 )) Type=$3
local TOCurX=$(( OCurX * 2 )) TOCurY=$(( OCurY + 1 ))
local colr=0 osign=0 sign=0

case $Type in
"CUR")
case $(XYFormat $OCurX $OCurY) in
F) colr=$PURPLE;osign=$FLAG;;
N) colr=$NULL;osign=$NUL;;
[1-8]) colr=$ORANGE;osign=$(XYFormat $OCurX $OCurY);;
[SM]) colr=$SBLUE;osign=$SHADOW;;
esac

case $(XYFormat $CurX $CurY) in
F)      sign=$FLAG;;
N)      sign=$NUL;;
[1-8]) sign=$(XYFormat $CurX $CurY);;
[SM])     sign=$SHADOW;;
esac

$ECHO "${ESC}${colr}m${ESC}${TOCurY};${TOCurX}H${osign}${ESC}${NULL}m"
$ECHO "${ESC}${REV};${FLASH};${ORANGE}m${ESC}${TCurY};${TCurX}H${sign}${ESC}${NULL}m"
;;
"SHADOW")
$ECHO "${ESC}${SBLUE}m${ESC}${TCurY};${TCurX}H${SHADOW}${ESC}${NULL}m"
;;
"MINE") 
$ECHO "${ESC}${REV};${RED}m${ESC}${TCurY};${TCurX}H${MINE}${ESC}${NULL}m"
;;
"FLAG")
$ECHO "${ESC}${TCurY};${TCurX}H${ESC}${PURPLE}m${FLAG}${ESC}${NULL}m"
;;
[1-8])
$ECHO "${ESC}${TCurY};${TCurX}H${ESC}${ORANGE}m${Type}${ESC}${NULL}m"
;;
"NUL")
$ECHO "${ESC}${TCurY};${TCurX}H${NUL}"
esac

return $OK
}

#check xy
function Loop ()
{
local XYTmp="$1 $2"

for (( i=0; i<MXYp; i++ ))
do
if [[ "$XYTmp" == "${MXY}" ]]
then $ECHO 1
fi
done

return $OK
}

#count around mine
#A B C
#D X E
#F G H
#return mine's number
function CountM ()
{
local Xmin=1 Ymin=1 Xmax=$X Ymax=$Y minecount=0 n=0
#A
if [[ ( $CurX -gt $Xmin ) && ( $CurY -gt $Ymin ) ]]
then
n=$( Loop $((CurX-1)) $((CurY-1)) )
(( minecount += n ))
n=0
fi
#B
if [[ $CurY -gt $Ymin ]]
then
n=$( Loop $CurX $((CurY-1)) )
(( minecount += n ))
n=0
fi
#C
if [[ ( $CurX -lt $Xmax ) && ( $CurY -gt $Ymin ) ]]
then
n=$( Loop $((CurX+1)) $((CurY-1)) )
(( minecount += n ))
n=0
fi
#D
if [[ $CurX -gt $Xmin ]]
then
n=$( Loop $((CurX-1)) $CurY )
(( minecount += n ))
n=0
fi
#E
if [[ $CurX -lt $Xmax ]]
then
n=$( Loop $((CurX+1)) $CurY )
(( minecount += n ))
n=0
fi
#F
if [[ ( $CurX -gt $Xmin ) && ( $CurY -lt $Ymax ) ]]
then
n=$( Loop $((CurX-1)) $((CurY+1)) )
(( minecount += n ))
n=0
fi
#G
if [[ $CurY -lt $Ymax ]]
then 
n=$( Loop $CurX $((CurY+1)) )
(( minecount += n ))
n=0
fi
#H
if [[ ( $CurX -lt $Xmax ) && ( $CurY -lt $Ymax ) ]]
then
n=$( Loop $((CurX+1)) $((CurY+1)) )
(( minecount += n ))
n=0
fi

return $minecount
}

#dig
#if mine ,gameover
#else tip around mine's number
function Dig ()
{
local key minenum=0

case $(XYFormat $CurX $CurY) in
M)
DrawPoint $CurX $CurY MINE
read -s -n 1 key
GameOver "Game Over"
;;
S)
CountM
minenum=$?
if [[ $minenum -eq $NULL ]]
then
XYFormat $CurX $CurY N
DrawPoint $CurX $CurY NUL
else
XYFormat $CurX $CurY $minenum
DrawPoint $CurX $CurY $minenum
fi

(( SCount-- ))
if [[ $SCount -eq $MCount ]]
then GameOver "Well Done"
fi
;;
esac
DrawPoint $CurX $CurY CUR

return $OK
}

#draw flag's number
function DrawFCount ()
{
$ECHO "${ESC}22;34H${ESC};${PURPLE}mFLAG=${FCount}  ${ESC}${NULL}m"
}

#sign mine
function Flag ()
{
local XYTmp="$CurX $CurY";stat=$FALSE

case $(XYFormat $CurX $CurY) in
F)
for (( i=1; i<MXYp; i++ ))
do
if [[ "${MXY}" == "$XYTmp" ]]
then XYFormat $CurX $CurY M;stat=$OK;break
fi
done
if [[ $stat == $FALSE ]]
then XYFormat $CurX $CurY S
fi

DrawPoint $CurX $CurY SHADOW
(( FCount++ ))
DrawFCount
;;
[SM])
if [[ $FCount -eq $NULL ]]
then return $FALSE
fi

DrawPoint $CurX $CurY FLAG
XYFormat $CurX $CurY F
(( FCount-- ))
DrawFCount
;;
esac
DrawPoint $CurX $CurY CUR

return $OK
}

function GameOver ()
{
local key msgtitle=$1

PMsg "$msgtitle" "Do you want replay?<y/n>" "Thank You"
while read -s -n 1 key
do
case $key in
[yY]) exec $(dirname $0)/$(basename $0);;
[nN]) GameExit;;
*) continue;;
esac
done

return $OK
}

#main
#drawscreen and control
function Main ()
{
local key

XYInit
XYRand
############################
# if you enable DEBUGPXY,
#you can know where is mine
# DEBUGPXY  #delete this line's #
#then cat ./mine.tmp
############################

DrawPoint $CurX $CurY CUR
DrawFCount

while read -s -n 1 key
do
case $key in
[wW]) CurMov UP;;
[sS]) CurMov DOWN;;
[aA]) CurMov LEFT;;
[dD]) CurMov RIGHT;;
[jJ]) Dig;;
[fF]) Flag;;
[nN]) exec $(dirname $0)/$(basename $0);;
[xX]) GameExit;;
esac
done

return $OK
}
#---------------Main-----------------

SttyInit
Menu #X Y MCount FCount SCount OK!
DrawInit
Main





 bitbull 回复于:2005-10-26 11:34:58

很久没摸SHELL,继续shell游戏系列当练手,感觉技术没什么新颖,就是在程序风格上有点进步.

现在回头看
shell游戏:老虎机
shell游戏:贪吃蛇
都感觉风格写得很糟糕

也许当第4个shell游戏出来后,又会觉得这个很糟糕了,呵呵


 bleem1998 回复于:2005-10-26 11:44:43

强阿
可是怎么不能挖雷呢???
空格都快按爆了


 bitbull 回复于:2005-10-26 14:07:52

j挖雷,哥们没看帮助?


 寂寞烈火 回复于:2005-10-26 14:38:30

MR.bitbull---A shell master !!!


 bitbull 回复于:2005-10-26 14:47:28

烈火兄老给我戴高帽,惭愧...........

这段上网很不方便,所以很少来,给各位老朋友问安了


 寂寞烈火 回复于:2005-10-26 14:55:37

引用:原帖由 "bitbull" 发表:
烈火兄老给我戴高帽,惭愧...........

这段上网很不方便,所以很少来,给各位老朋友问安了


老兄的三个shell game:
引用:
shell游戏:老虎机 
shell游戏:贪吃蛇
shell游戏:扫雷


堪称shell之经典呀~~~  :em06:


 tonyfu 回复于:2005-10-26 14:57:28

把shell玩到这份上,,,,,佩服


 ZealeS 回复于:2005-10-26 16:16:11

老兄的想法,毅力,实力实在是高,把shell写到这程度,作为一个shell的fans,我佩服的一塌糊涂。。。顺手收藏先。。。


 mrlau 回复于:2005-10-26 16:20:53

高人!!!


 anyfox 回复于:2005-10-26 16:30:29

佩服 呵呵


 bitbull 回复于:2005-10-26 22:27:05

还是自觉得比不上飞灰橙兄,他的俄罗斯方块一直是我努力的目标,严谨的程序风格,巧妙的构思
也许追上飞灰兄,就是本人SHELL游戏系列终结的日子,呵呵

再等几个月手又有点生了再写一个吧,谢谢各位支持

waker兄来个精华,起码也来个保留,不然过几个星期贴子就被删了,成不了系列了,55555555~~~~先谢了


 seeLnd 回复于:2005-10-27 00:56:35

佩服, 学习了!!
但是发现一个小bug, 
如果输入sh mine.sh启动游戏, 
踩到雷, 按y进行replay时, 
程序提示: mine.sh: line 510: exec: mine.sh: not found

斗胆修改一下, 在程序510行:

function GameOver ()
{
        local key msgtitle=$1

        PMsg "$msgtitle" "Do you want replay?<y/n>" "Thank You"
        while read -s -n 1 key
        do
                case $key in 
                [color=red][yY])   exec "$( realpath "$0" )";;[/color]
                [nN])   GameExit;;
                *)      continue;;
                esac    
        done    

        return $OK      
}


 bitbull 回复于:2005-10-27 08:31:54

引用:原帖由 "seeLnd" 发表:
佩服, 学习了!! 
但是发现一个小bug, 
如果输入sh mine.sh启动游戏, 
踩到雷, 按y进行replay时, 
程序提示: mine.sh: line 510: exec: mine.sh: not found 

斗胆修改一下, 在程序510行: 

function GameOver () 

       local key msgtitle=$1 

       PMsg "$msgtitle" "Do you want replay?<y/n>" "Thank You" 
       while read -s -n 1 key 
       do 
               case $key in 
               [yY])   exec "$( realpath "$0" )";; 
               [nN])   GameExit;; 
               *)      continue;; 
               esac     
       done     

       return $OK       
}




 :em02:  :em02: 
谢谢.疏忽了.

我的系统上没realpath,用个比较笨的办法修复

exec "$(dirname $0)/$(basename $0)"

稍后对原文做修改,希望有更多BUG被指出,谢谢


 mocou 回复于:2005-10-27 12:15:47

厉害。佩服


 Haskell 回复于:2005-10-27 13:34:24

佩服得六体投地!
不过好像和微软的不一样哦~
就算法上来讲,还需要优化。


 mefit 回复于:2005-10-27 13:35:41

牛人啊


 bitbull 回复于:2005-10-27 15:33:17

引用:原帖由 "Haskell" 发表:
不过好像和微软的不一样哦~
就算法上来讲,还需要优化。





跟windows下带的那个比,少了计时,还有如果碰到周围没地雷时,windows下的扫雷会一直连翻开

对于算法的优化,愿闻其详,谢谢,我拿出代码就是来和大家讨论的


 xchen301 回复于:2005-10-27 15:46:45

牛牛又出精品了!

学习中。。。


 Zelgadiss 回复于:2005-10-27 16:15:47

引用:我的系统上没realpath,用个比较笨的办法修复 

exec "$(dirname $0)/$(basename $0)"



这二个我都不行:(

PS:学习学习再学习


 gorilla 回复于:2005-11-03 11:05:02

这个运行不了!出错提示:
mine.sh: MXY[0]=: not found
mine.sh: syntax error at line 76: `(' unexpected

问一下楼主,是不是sh 的类型不对呀!我用的是SCOUNIX 5.0.5的,怎么看登陆用户用的是什么sh?


 prc 回复于:2005-11-04 11:01:33

强就一个字


 murdoc 回复于:2005-11-04 12:35:29

shell写游戏,高手中的高手,向楼主学习啊


 huxiao45 回复于:2005-11-23 10:04:12

嗯~看不懂


 ha_ 回复于:2005-11-23 11:13:54


#./mine.sh
./mine.sh: line 166: syntax error near unexpected token `XY[$XTmp+$X*($YTmp-1)'
./mine.sh: line 166: `  then XY[$XTmp+$X*($YTmp-1)]=$3'
#sh mine.sh
mine.sh: MXY[0]=: not found
mine.sh: syntax error at line 76: `(' unexpected
#bash mine.sh
mine.sh: line 166: syntax error near unexpected token `XY[$XTmp+$X*($YTmp-1)'
mine.sh: line 166: `    then XY[$XTmp+$X*($YTmp-1)]=$3'


solaris


 purpleme 回复于:2005-11-23 11:14:08

高实在是高,佩服!


 bitbull 回复于:2005-11-24 19:54:44

re ha gorilla :
SORRY,没在solaris调试过

查看当前shell可以
echo $0
echo $SHELL


 寂寞烈火 回复于:2005-11-24 19:56:59

引用:原帖由 bitbull 于 2005-11-24 19:54 发表
re ha gorilla :
SORRY,没在solaris调试过

查看当前shell可以
echo $0
echo $SHELL 


恭喜兄弟上任linuxforum shell版主~~ :em02:


 大蚂蚁 回复于:2005-11-24 21:17:28

引用:原帖由 寂寞烈火 于 2005-11-24 19:56 发表

恭喜兄弟上任linuxforum shell版主~~ :em02: 


:em22::em22::em22:都上任N久了! 我以为又有什么新帖子呢,原来你是来水的:m01::m01::em11:


 James_Guan 回复于:2005-12-06 13:48:46

高手原来是这么玩的!
向高手学习!


 jlbslj 回复于:2005-12-06 15:08:27

各位老手
有能力还是帮帮新手吧


 dbcat 回复于:2005-12-06 15:46:47

学习!:em02::em02:




原文链接:http://bbs.chinaunix.net/viewthread.php?tid=634271
转载请注明作者名及原文出处



收藏本页到: