Last active
August 29, 2015 14:04
-
-
Save programus/41e774ac052248619b39 to your computer and use it in GitHub Desktop.
mine sweeper shell version
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Just found that gists can be cloned! Thx!