发新话题
打印

shell游戏:扫雷

shell游戏:扫雷

  http://www.chinaunix.net 作者:bitbull  发表于:2005-10-26 11:29:21

【发表回复】【查看论坛原帖】【添加到收藏夹】【关闭】  

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键进行标识,以避免误挖.挖开地图内所有非雷方块则获胜.

代码:
[code:1:24e3d9688d]#!/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

    [/code:1:24e3d9688d]




    --------------------------------------------------------------------------------
    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
    [quote:bcfdafdf5f="bitbull"]烈火兄老给我戴高帽,惭愧...........

    这段上网很不方便,所以很少来,给各位老朋友问安了[/quote:bcfdafdf5f]
    老兄的三个shell game:
    [quote:bcfdafdf5f]
    shell游戏:老虎机  
    shell游戏:贪吃蛇
    shell游戏:扫雷[/quote:bcfdafdf5f]
    堪称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:fc3f81b6c1][yY])   exec "$( realpath "$0" )";;[/color:fc3f81b6c1]
                   [nN])   GameExit;;
                   *)      continue;;
                   esac     
           done     

           return $OK       
    }



    --------------------------------------------------------------------------------
    bitbull 回复于:2005-10-27 08:31:54
    [quote:effa1b1a94="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        
    }[/quote:effa1b1a94]


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

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

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

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

    超经典的游戏呀~~
    WEB : http://www.love-b.cn
    OpenBSD FANS QQ群:27881338

    TOP

    发新话题