Skip to content

Instantly share code, notes, and snippets.

@programus
Last active August 29, 2015 14:04
Show Gist options
  • Select an option

  • Save programus/41e774ac052248619b39 to your computer and use it in GitHub Desktop.

Select an option

Save programus/41e774ac052248619b39 to your computer and use it in GitHub Desktop.
mine sweeper shell version
#!/bin/bash
MINE="@"
BOOM="X"
BLANK=" "
NEW="."
MARK="M"
OPEN_FLAG=1
MARK_FLAG=2
function printBanner()
{
echo "****************************"
echo "* MINE SWEEPER *"
echo "****************************"
}
function getIndex()
{
if [[ -n $3 ]]
then
local w=$3
else
local w=8
fi
local x=$1
local y=$2
echo $((x+y*w))
}
function generateMines()
{
if [[ -n $* ]]
then
local ex=$(echo $*|tr -d ' ')
else
local ex=xx
fi
local pool=($(seq -w 0 77|sed '/[89]/d'|grep -v $ex))
for i in $(seq 0 9)
do
let local pick=${RANDOM}%${#pool[@]}
local mine[$i]=${pool[$pick]}
pool=(${pool[@]:0:$pick} ${pool[@]:$((pick+1))})
done
echo ${mine[@]}
}
function split2char()
{
echo $*|sed 's/./& /g'
}
function isValidPosition()
{
[[ $# -eq 2 ]] && echo $*|grep '^[0-7] [0-7]$' > /dev/null
}
function readPosition()
{
read -p ':' input
if echo $input|grep ^[^0-9] > /dev/null
then
local cmd=$(echo $input|cut -c1)
local pos=$(split2char ${input:1})
else
local pos=$(split2char $input)
fi
isValidPosition $pos && echo $pos $cmd
}
function generateField()
{
local field=($(yes 00|head -64))
for m in $*
do
local pos=$(split2char $m)
local i=$(getIndex $pos)
local field[$i]=$(echo "${MINE}0")
local x=${m:0:1}
local y=${m:1:2}
for dx in -1 0 1
do
for dy in -1 0 1
do
local xx=$((x+dx))
local yy=$((y+dy))
if isValidPosition $xx $yy
then
local index=$(getIndex $xx $yy)
local n=${field[$index]:0:1}
if [[ $n != $MINE ]]
then
((n++))
fi
field[$index]=$(echo "$n${field[$index]:1:2}")
fi
done
done
done
echo ${field[@]}
}
function markOpen()
{
local field=($3)
local x=$1
local y=$2
local force=$4
local i=$(getIndex $x $y)
local mask=${field[$i]:1:2}
local n=${field[$i]:0:1}
if [[ -n $force ]] || ([[ $mask != ${OPEN_FLAG} ]] && [[ $mask != ${MARK_FLAG} ]])
then
field[$i]=$(echo "$n${OPEN_FLAG}")
if [[ $n = "0" ]] || [[ -n $force ]]
then
for dx in -1 0 1
do
local xx=$((x+dx))
if [[ xx -ge 0 ]] && [[ xx -le 7 ]]
then
for dy in -1 $([[ dx -ne 0 ]] && echo 0) 1
do
local yy=$((y+dy))
if [[ yy -ge 0 ]] && [[ yy -le 7 ]]
then
field=($(markOpen $xx $yy "${field[*]}"))
fi
done
fi
done
fi
fi
if [[ ${field[$i]:0:1} = $MINE ]] && [[ $mask != ${MARK_FLAG} ]]
then
field[$i]=$(echo "$BOOM${field[$i]:1:2}")
echo ${field[@]}|sed 's/\([^ ]\)[^ ]/\11/g'
return 1
else
echo ${field[@]}
fi
}
function markFlag()
{
local field=($3)
local i=$(getIndex $1 $2)
local mask=${field[$i]:1:2}
if [[ $mask -eq ${MARK_FLAG} ]]
then
field[$i]=$(echo "${field[$i]:0:1}0")
elif [[ $mask -ne ${OPEN_FLAG} ]]
then
field[$i]=$(echo "${field[$i]:0:1}${MARK_FLAG}")
fi
echo ${field[@]}
}
function showField()
{
local field=($*)
echo " $(seq 0 7|tr '\n' ' ')"
echo " +$(yes '-'|head -15|tr -d '\n')+"
for y in $(seq 0 7)
do
for x in $(seq 0 7)
do
local i=$(getIndex $x $y)
local mask=${field[$i]:1:2}
local n=${field[$i]:0:1}
if [[ $mask -eq ${OPEN_FLAG} ]]
then
local line[$x]=$(echo $n|tr '0' "$BLANK")
elif [[ $mask -eq ${MARK_FLAG} ]]
then
local line[$x]=$MARK
else
local line[$x]=$NEW
fi
done
local ln=$(echo "${line[*]}"|sed \
-e "s/${BOOM}/\\\e[41;37;1m${BOOM}\\\e[0m/g" \
-e "s/${MARK}/\\\e[43;34;2m${MARK}\\\e[0m/g" \
-e "s/${MINE}/\\\e[43;31;2m${MINE}\\\e[0m/g" \
-e "s/\<1\>/\\\e[34;1m1\\\e[0m/g" \
-e "s/\<2\>/\\\e[32;1m2\\\e[0m/g" \
-e "s/\<3\>/\\\e[31;1m3\\\e[0m/g" \
-e "s/\<4\>/\\\e[34;2m3\\\e[0m/g" \
)
echo -e "$y |$ln|"
done
echo " +$(yes '-'|head -15|tr -d '\n')+"
}
function game()
{
local field=
local step=0
local mine=10
trap 'echo;echo "You lose because you aborted!";exit' INT
echo "There are $mine mines. "
echo "Sweep them all!"
while [[ 1 = 1 ]]
do
((step++))
showField $field
printf "[%2d]" $step
until pos=($(readPosition))
do
echo "Input format wrong!"
echo "Please input a valid position in format x y or m x y for marking."
printf "[%2d]" $step
done
echo $(yes "="|head -23|tr -d '\n')
if [[ ! -n $field ]]
then
field=$(generateField $(generateMines ${pos[@]}))
fi
if [[ ${pos[@]:2:3} = "m" ]]
then
field=$(markFlag ${pos[@]:0:2} "$field")
else
if ! field=$(markOpen ${pos[@]:0:2} "$field" ${pos[@]:2:3}) || echo $field|grep "$BOOM" > /dev/null
then
showField $field
echo "Oops, you exploded a mine!"
echo
break
fi
local remain=$(echo $field|tr ' ' '\n'|sed '/1$/d'|wc -l)
if [[ $remain -eq 10 ]]
then
showField $field
echo "Wow, you sweeped all mine after $step steps!"
echo
break
fi
fi
done
trap - INT
}
printBanner
until [[ $exit ]]
do
game $1
echo "-----"
select sel in "Play again?" "Exit"
do
case $sel in
Exit)
exit=1
break;;
*)
echo "====="
break;;
esac
done
done
@limingjie
Copy link
Copy Markdown

Add color to the board :)

Try this:
$ echo -e '\e[0;31mC\e[0;32mO\e[0;33mL\e[0;34mO\e[0;35mR'

@programus
Copy link
Copy Markdown
Author

Great idea. Added color. :-)

@limingjie
Copy link
Copy Markdown

Just found that gists can be cloned! Thx!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment