首页 > 系统相关 >用shell脚本设计的『扫雷』

用shell脚本设计的『扫雷』

时间:2023-08-16 18:36:39浏览次数:35  
标签:脚本 do shell tput 扫雷 result done fi local

不知道为什么,这个脚本和CentOS 7不兼容。

载入脚本后,用WASD键控制光标移动,按空格挖开地块,挖到的数字是地块周围的地雷数量,挖到地雷后游戏失败;
按F标记有地雷的地块,按E表示可能有地雷。已挖开的地块无法被标记。将所有地雷标记完毕后游戏胜利。
按Q键退出游戏。无论如何退出游戏,脚本都会总结扫到雷的数量和本局游戏的时间。

#!/bin/bash
# ========================================
# Author: Kide_Lee
# Date: 2023.8.15
# Blog: https://www.cnblogs.com/-zyyz-/
# ========================================
# 用户设置
# ========================================
width=8      # 界面的宽度
height=8     # 界面的高度
mineCount=10 # 地雷数量
mine="#"     # 地雷样式
title="MineSweeper"

# ========================================
# 方法
# 用一维数组模拟一张二维表;
# 下面提供若干方法,使脚本能够通过查询二维坐标的方式访问数组;
# 其中横纵坐标按书写方向,从零开始计数。
# ========================================
function ReadTable() {
    local x=$2
    local y=$3

    # matrix和field是脚本维护的两张表,
    # 其分别记录了雷区信息和用户界面。
    case "$1" in
    matrix) local info=("${matrix[@]}") ;;
    field) local info=("${field[@]}") ;;
    esac

    # 若读取的坐标越界或无值,则返回0;否则返回坐标对应值。
    local result=${info[$(("$y" * "$width" + "$x"))]}
    if [ -z "$result" ]; then
        return 0
    elif [ "$x" -lt 0 ]; then
        return 0
    elif [ "$y" -lt 0 ]; then
        return 0
    elif [ "$x" -ge $width ]; then
        return 0
    elif [ "$y" -ge $height ]; then
        return 0
    else
        return "$result"
    fi
}
function WriteTable() {
    local x=$2
    local y=$3
    local new=$4

    if [ "$x" -lt 0 ]; then
        return 0
    elif [ "$y" -lt 0 ]; then
        return 0
    elif [ "$x" -ge $width ]; then
        return 0
    elif [ "$y" -ge $height ]; then
        return 0
    fi

    if [ "$1" == "matrix" ]; then
        matrix["$y" * "$width" + "$x"]=$new
    elif [ "$1" == "field" ]; then
        field["$y" * "$width" + "$x"]=$new
    fi
}

# ========================================
# 初始化
# ========================================
# 主函数
function StartGame() {
    X=$(("$width" / 2 - 1))
    Y=$(("$height" / 2 - 1))
    size=$(("$width" * "$height"))
    tput civis
    # 生成雷区
    for ((i = 0; i < "$size"; i++)); do
        matrix+=("0")
    done
    # 生成界面
    for ((i = 0; i < "$size"; i++)); do
        field+=("10")
    done
    DrawField
    while [ -z "$checkFirst" ]; do
        DrawFocus $X $Y
        IFS_back=$IFS
        IFS=""
        read -srn1 input
        IFS=$IFS_back
        case "$input" in
        w | W) MoveUp ;;
        a | A) MoveLeft ;;
        s | S) MoveDown ;;
        d | D) MoveRight ;;
        f | F) MarkMatrix $X $Y 11 ;;
        e | E) MarkMatrix $X $Y 12 ;;
        q | Q) return 1 ;;
        " ")
            CreateMine
            CreateNumber
            startTime=$(date +%s)
            CheckMatrix $X $Y
            local checkFirst="yes"
            ;;
        esac
    done
}
# 绘制界面
function DrawField() {
    # 绘制标题栏
    tput clear
    local fieldWidth=$(("$width" * 3 + 2))
    local titleWidth=${#title}
    if [ "$fieldWidth" -gt "$titleWidth" ]; then
        tput cup 0 $(("$fieldWidth" / 2 - "$titleWidth" / 2))
        echo $title
    else
        tput cup 0 0
        echo $title
    fi
    # 绘制上边框
    echo -n +
    for ((i = 0; i < "$width"; i++)); do
        echo -n "---"
    done
    echo +
    # 绘制游戏区域
    for ((i = 0; i < "$height"; i++)); do
        echo -n "|"
        for ((j = 0; j < "$width"; j++)); do
            echo -n "[ ]"
        done
        echo "|"
    done
    # 绘制下边框
    echo -n +
    for ((i = 0; i < "$width"; i++)); do
        echo -n "---"
    done
    echo +
    # 增加游戏提示
    echo "move: WASD  check: Space"
    echo "mark: F  question: E  quit: Q"
}
# 铺设地雷
function CreateMine() {
    # 定义安全区,保证首次排雷安全
    local safeFieldList=()
    for x in $X-1 $X $X+1; do
        for y in $Y-1 $Y $Y+1; do
            x=$(("$x"))
            y=$(("$y"))
            local safeNum=$(("$y" * "$width" + "$x"))
            if [ $safeNum -ge 0 ] || [ $safeNum -lt "$size" ]; then
                safeFieldList+=("$safeNum")
            fi
        done
    done
    # 定义地雷,本质是一串不重复的随机数
    local mineList=()
    while [ ${#mineList[*]} -lt $mineCount ]; do
        local random=$(("$RANDOM" % "$size"))
        local isRepeat=false
        for i in "${mineList[@]}" "${safeFieldList[@]}"; do
            if [ $random == "$i" ]; then
                isRepeat=true
                break
            fi
        done

        if [ $isRepeat == false ]; then
            mineList+=("$random")
        fi
    done
    # 布置地雷,在雷区中,9代表有地雷
    for i in "${mineList[@]}"; do
        matrix["$i"]=9
    done
}
# 生成数字
function CreateNumber() {
    function PutOne() {
        local x=$1
        local y=$2
        for i in $x-1 $x $x+1; do
            for j in $y-1 $y $y+1; do
                local i=$(("$i"))
                local j=$(("$j"))
                ReadTable matrix $i $j
                tmpNum=$?
                if [ $tmpNum != 9 ]; then
                    WriteTable matrix $i $j $(("$tmpNum" + 1))
                fi
            done
        done
    }
    # 遇到地雷,非地雷邻格数字+1。
    for ((y = 0; y < "$height"; y++)); do
        for ((x = 0; x < "$width"; x++)); do
            ReadTable matrix $x $y
            if [ $? == 9 ]; then
                PutOne $x $y
            fi
        done
    done
}

# ========================================
# 游戏过程
# ========================================
# 主函数
function PlayGame() {
    while true; do
        DrawFocus $X $Y
        IFS_back=$IFS
        IFS=""
        read -srn1 input
        IFS=$IFS_back
        case "$input" in
        w | W) MoveUp ;;
        a | A) MoveLeft ;;
        s | S) MoveDown ;;
        d | D) MoveRight ;;
        f | F) MarkMatrix $X $Y 11 ;;
        e | E) MarkMatrix $X $Y 12 ;;
        q | Q) return 1 ;;
        " ")
            CheckMatrix $X $Y
            if [ $? == 9 ]; then
                tput bel
                return 2
            fi
            ;;
        esac
        Judging
        if [ $? == 2 ]; then
            return 3
        fi
    done
}
# 检查雷区
function CheckCell() {
    local x=$1
    local y=$2
    ReadTable field "$x" "$y"
    local result=$?
    if [ $result -ge 10 ]; then
        ReadTable matrix "$x" "$y"
        local result=$?
        WriteTable field "$x" "$y" "$result"
        Draw "$x" "$y"
    elif [ $result == 0 ]; then
        local result=10
    fi
    return "$result"
}
# 递归检查雷区
function CheckMatrix() {
    local x_1=$1
    local y_1=$2
    local edgeList=("$x_1" "$y_1")
    local edgeLength=2
    while [ "$edgeLength" -gt 0 ]; do
        local x=${edgeList[$edgeLength - 2]}
        local y=${edgeList[$edgeLength - 1]}
        unset "edgeList[$edgeLength-2]"
        unset "edgeList[$edgeLength-1]"
        CheckCell "$x" "$y"
        local result=$?
        if [ $result == 0 ]; then
            for i in $x-1 $x $x+1; do
                for j in $y-1 $y $y+1; do
                    local i=$(("$i"))
                    local j=$(("$j"))
                    edgeList+=("$i" "$j")
                done
            done
        fi
        local edgeLength=${#edgeList[@]}
    done
    # 提供返回值
    ReadTable field "$x_1" "$y_1"
    return $?
}
# 渲染界面
# 本函数同时仅能渲染一个格子。
function Draw() {
    local x=$1
    local y=$2
    ReadTable field "$x" "$y"
    local result=$?
    case "$result" in
    0) display="   " ;;
    9) display="$(tput setaf 1) ${mine} $(tput sgr0)" ;;
    10) display="[ ]" ;;
    11) display="$(tput setaf 2)[F]$(tput sgr0)" ;;
    12) display="$(tput setaf 3)[?]$(tput sgr0)" ;;
    *) display="$(tput setaf $((8 - "$result"))) ${result} $(tput sgr0)" ;;
    esac
    tput cup $(("$y" + 2)) $(("$x" * 3 + 1))
    echo -n "$(tput sgr0)${display}"
}
# 渲染焦点
function DrawFocus() {
    local x=$1
    local y=$2

    if [ "$old_X" ]; then
        Draw "$old_X" "$old_Y"
    fi

    Draw "$x" "$y"
    tput cup $(("$y" + 2)) $(("$x" * 3 + 1))
    echo -n "$(tput rev)${display}"

    old_X=$1
    old_Y=$2
}
# 标记雷区
function MarkMatrix() {
    local x=$1
    local y=$2
    local mark=$3
    ReadTable field "$x" "$y"
    local fieldChar=$?
    if [ $fieldChar == "$mark" ]; then
        WriteTable field "$x" "$y" 10
    elif [ $fieldChar -gt 9 ]; then
        WriteTable field "$x" "$y" "$mark"
    fi
}
# 移动
function MoveUp() {
    Y=$(("$Y" - 1))
    if [ $Y -lt 0 ]; then
        Y=$(("$Y" + "$height"))
    fi
}
function MoveDown() {
    Y=$(("$Y" + 1))
    if [ $Y -ge $height ]; then
        Y=$(("$Y" - "$height"))
    fi
}
function MoveLeft() {
    X=$(("$X" - 1))
    if [ $X -lt 0 ]; then
        X=$(("$X" + "$width"))
    fi
}
function MoveRight() {
    X=$(("$X" + 1))
    if [ $X -ge $width ]; then
        X=$(("$X" - "$width"))
    fi
}
# 判断
function Judging() {
    for i in "${field[@]}"; do
        if [ "$i" == 10 ] || [ "$i" == 12 ]; then
            return 1
        fi
    done
    return 2
}

# ========================================
# 游戏清算
# ========================================
function ClearGame() {
    endTime=$(date +%s)
    Draw $X $Y
    if [ "$startTime" ]; then
        time=$(("$endTime" - "$startTime"))
    else
        time=0
    fi
    mineSweeper=0
    if [ $result == 1 ]; then
        for ((i = 0; i < ${#matrix[@]}; i++)); do
            x=$(("$i" % "$width"))
            y=$(("$i" / "$height"))
            if [ "${matrix[$i]}" == 9 ]; then
                if [ "${field[$i]}" == 11 ]; then
                    mineSweeper=$(("$mineSweeper" + 1))
                    Draw "$x" "$y"
                    tput cup $(("$y" + 2)) $(("$x" * 3 + 1))
                    echo -n "$(tput rev)$(tput setaf 2)[F]$(tput sgr0)"
                else
                    Draw "$x" "$y"
                    tput cup $(("$y" + 2)) $(("$x" * 3 + 1))
                    echo -n "[${mine}]"
                fi
            fi
        done
        clearInfo="Game Exited.\nYou swept $mineSweeper mines in $time seconds."
    elif [ $result == 2 ]; then
        for ((i = 0; i < ${#matrix[@]}; i++)); do
            x=$(("$i" % "$width"))
            y=$(("$i" / "$height"))
            if [ "${matrix[$i]}" == 9 ]; then
                if [ "${field[$i]}" == 11 ]; then
                    mineSweeper=$(("$mineSweeper" + 1))
                    Draw "$x" "$y"
                    tput cup $(("$y" + 2)) $(("$x" * 3 + 1))
                    echo -n "$(tput rev)$(tput setaf 2) ${mine} $(tput sgr0)"
                else
                    Draw "$x" "$y"
                    tput cup $(("$y" + 2)) $(("$x" * 3 + 1))
                    echo -n "$(tput rev)$(tput setaf 1) ${mine} $(tput sgr0)"
                fi
            fi
        done
        clearInfo="$(tput setaf 1)The Game Failed. \nYou swept $mineSweeper mines in $time seconds."
    elif [ $result == 3 ]; then
        clearInfo="$(tput setaf 2)You Win!\nYou swept all mines in $time seconds."
    fi
    tput cnorm
    tput cup $(("$height" + 3)) 0
    tput el
    echo -e "$(tput rev)${clearInfo}$(tput sgr0)"
}

# ========================================
# 游戏运行
# ========================================
StartGame
result=$?
if [ $result == 0 ]; then
    PlayGame
    result=$?
fi
ClearGame

标签:脚本,do,shell,tput,扫雷,result,done,fi,local
From: https://www.cnblogs.com/-zyyz-/p/17635907.html

相关文章

  • HDFS shell 常用命令
    创建多级目录(-p):hadoopfs-mkdir-p/test/a/b 展示目录:hadoopfs-ls/ 递归展示:hadoopfs-ls-R/ 从HDFS上下载文件到本地:hadoopfs-get/test/a/b/h.txthadoopfs-copyToLocal  /test/a/b/h.txt 从本地上传文件到HDFS:hadoopfs-copyFromLocalhello......
  • shell 用户输入值REPLY变量值传递给 read 变量
    shell变量值传递给read变量readselChoices<<<"$REPLY"echo$selChoices"$REPLY"是用户输入的值,它通过here-string(<<<)传递给read命令参考:https://qa.1r1g.com/sf/ask/2128520901/......
  • hook脚本的编写
    1.hook_mapvarTreeMap=Java.use('java.util.TreeMap');varMap=Java.use("java.util.Map");TreeMap.put.implementation=function(key,value){if(key=="data"){console.log(key,value);}......
  • shell基础
    一.shell脚本在/etc/shells中可以找到当前系统支持的shell脚本种类  脚本用途将简单的命令组合完成复杂的工作,自动化执行命令,提高工作效率减少手工命令的重复输入,一定程度上避免人为错误将软件或应用的安装及配置实现标准化用于实现日常性的,重复性的运维工作,如:文......
  • linux ssh 免密脚本
    #!/bin/baship="$1"pawd="123qwe!@#"expect<<EOFsettimeout10spawnssh-copy-id-p60022root@${ip}expect{       "yes/no"{send"yes\n";exp_continue}       "password:"{send"${pawd}\n"......
  • Jmeter 的 BeanShell
    通过BeanShell可以访问ctx、vars、props、prev、sampler、log;1.通过ctx可以访问jmeter运行时状态,比如线程数及线程状态;ctx:获取当前线程上下文数据(可获取所有信息);可以通过获取jmeterContent实例来获取运行时信息;ctx.getVariables(“变量名”):获取变量值(同vars.get())。ct......
  • x64ShellCode-通过PEB获取模块地址.
    以x64dbg.exe调试x64dbg.exe为例.汇编代码为如下.movrax,qwordptrgs:[0x0000000000000060]movrax,qwordptrds:[rax+0x10]二进制硬编码如下"\x65\x48\x8B\x04\x25\x60\x00\x00\x00\x48\x8B\x40\x10\x90\x90"结果如下:......
  • SElinux 导致 Keepalived 检测脚本无法执行
    哈喽大家好,我是咸鱼今天我们来看一个关于Keepalived检测脚本无法执行的问题一位粉丝后台私信我,说他部署的keepalived集群vrrp_script模块中的脚本执行失败了,但是手动执行这个脚本却没有任何问题这个问题也是咸鱼第一次遇到,为了能让更多的小伙伴以后不会踩这个坑,便有了今......
  • 图文结合丨带你轻松玩转MySQL Shell for GreatSQL
    一、引言1.1什么是MySQLShell?MySQLShell是MySQL的一个高级客户端和代码编辑器,是第二代MySQL客户端。第一代MySQL客户端即我们常用的MySQL。除了提供类似于MySQL的SQL功能外,MySQLShell还提供JavaScript和Python脚本功能,并包括与MySQL一起使用的API。......
  • shell命令概述 Shell作用:命令解释器 介于操作系统内核与用户之间,负责解释命令行 获得
    shell命令概述Shell作用:命令解释器介于操作系统内核与用户之间,负责解释命令行获得命令帮助内部命令help命令的“--help”选项使用man命令阅读手册页命令行编辑的几个辅助操作Tab键:自动补齐反斜杠“\”:强制换行快捷键Ctrl+U:清空至行首快捷键Ctrl+K:清空至行尾快捷键Ctr......