Skip to content

Instantly share code, notes, and snippets.

@Hayao0819
Last active May 12, 2022 15:25
Show Gist options
  • Save Hayao0819/caad8ef3952bdfef7287ef8c5d71e03c to your computer and use it in GitHub Desktop.
Save Hayao0819/caad8ef3952bdfef7287ef8c5d71e03c to your computer and use it in GitHub Desktop.
計算をして遊ぶゲーム miniは最小限の実装
#!/usr/bin/env bash
#-- Initilize script --#
set -eu
# shellcheck source=/dev/null
source /dev/stdin < <(curl -sL "https://github.com/Hayao0819/FasBashLib/releases/download/v0.2.1/fasbashlib.sh")
#-- Define --#
AvailableNumbers=()
NumberOfStart=5
TargetNumber=10
#-- Functions --#
HelpMessage(){ echo "There is nothing"; }
GetExprNumbers(){
local _NPrefix="" _Before="" _Chr
while read -r _Chr; do
if grep -qx "^[0-9]\+$" <<< "$_Chr"; then
echo "${_NPrefix-""}${_Chr}"
_NPrefix=""
else
case "$_Chr" in
"-")
if grep -qx "^[0-9]\+$" <<< "$_Before"; then
_NPrefix=""
else
_NPrefix="-"
fi
;;
esac
fi
_Before="$_Chr"
done < <(BreakChar <<< "$*")
}
# RemoveMatchLine <String> < <(PrintArray "${array[@]}")
RemoveMatchLine(){
local i unseted=false
while read -r i; do
if [[ "$i" != "${1}" ]] || [[ "${unseted}" = true ]]; then
echo "$i"
else
unseted=true
fi
done
unset unseted i
}
# Loop [回数] [コマンド]
Loop(){
local _T="$1"
shift 1 || return 1
ForEach "$@" < <(yes "" | head -n "$_T")
}
# ゲームのメイン関数
Game.Main(){
local InputExpr
Game.Start
while true; do
! Game.Ask || break
done
Game.Result
}
Game.Start(){
echo "四則演算をして最終的に\"$TargetNumber\"を作ろう"
# NumberOfStart回、0~9で乱数を取得してAvailableNumbersに追加
# shellcheck disable=SC2016
Loop "$NumberOfStart" eval 'ArrayAppend AvailableNumbers <<< $(( RANDOM % 10 ))'
}
Game.Result(){
echo "最終的に残ったのは${AvailableNumbers[0]}"
if [[ "${AvailableNumbers[0]}" = "${TargetNumber}" ]]; then
echo "クリア!"
else
echo "失敗!"
fi
exit 0
}
Game.Ask(){
local UsedNumber=()
echo "今回使える数字は以下のとおりです"
PrintArray "${AvailableNumbers[@]}" | ForEach echo "・ {}"
echo -n "式を入力してください: "
read -r InputExpr
echo
# 指定された式の数字が使えるかどうかを確認
local Num
while read -r Num; do
if ! PrintArray "${AvailableNumbers[@]}" | grep -qx -- "$Num"; then
echo "${Num}は使えません!"
AvailableNumbers+=("${UsedNumber[@]}")
unset UsedNumber
return 1 # 異常終了して関数を再度呼び出す
else
UsedNumber+=("$Num")
readarray -t AvailableNumbers < <(PrintArray "${AvailableNumbers[@]}" | RemoveMatchLine "$Num")
fi
done < <(GetExprNumbers "$InputExpr")
AvailableNumbers+=("$(( "$InputExpr" ))") 2> /dev/null
# もし数字が1つだけならゲームを終了する
if [[ "${#AvailableNumbers[@]}" = 1 ]]; then
return 0
else
return 2
fi
}
Game.Main
#!/usr/bin/env bash
#-- Initilize script --#
set -eu
# shellcheck source=/dev/null
source /dev/stdin < <(curl -sL "https://github.com/Hayao0819/FasBashLib/releases/download/v0.2.1/fasbashlib.sh")
#-- Define --#
AvailableNumbers=()
NumberOfStart=5
TargetNumber=10
ExprHistory=()
#-- Functions --#
HelpMessage(){ echo "There is nothing"; }
# ShiftArray <Array> <Number>
ShiftArray(){
readarray -t "$1" < <(PrintEvalArray "$1" | sed "1,${2-"1"}d")
}
#ParseExpr(){ sed -E "s|([0-9]+)|\1\n|g" <<< "${*}" | sed -E -e "s|(\+)|\1\n|g" -e "s|(\-)|\1\n|g" -e "s|(\*)|\1\n|g" -e "s|(\/)|\1\n|g" | grep -v "^$"; }
GetExprNumbers(){
local _NPrefix="" _Before="" _Chr
while read -r _Chr; do
if grep -qx "^[0-9]\+$" <<< "$_Chr"; then
echo "${_NPrefix-""}${_Chr}"
_NPrefix=""
else
case "$_Chr" in
"-")
if grep -qx "^[0-9]\+$" <<< "$_Before"; then
_NPrefix=""
else
_NPrefix="-"
fi
;;
esac
fi
_Before="$_Chr"
done < <(BreakChar <<< "$*")
}
# CheckNum <Number>
CheckNum(){
! grep -q -- "\." <<< "$1"
}
# Loop [回数] [コマンド]
Loop(){
local _T="$1"
shift 1 || return 1
ForEach "$@" < <(yes "" | head -n "$_T")
}
# RemoveMatchLine <String> < <(PrintArray "${array[@]}")
RemoveMatchLine(){
local i unseted=false
while read -r i; do
if [[ "$i" != "${1}" ]] || [[ "${unseted}" = true ]]; then
echo "$i"
else
unseted=true
fi
done
unset unseted i
}
# ゲームのメイン関数
Game.Main(){
Game.Start
while true; do
! Game.Ask || break #Game.Askが正常終了した時にループを終了する
done
Game.Result
}
Game.Start(){
echo "四則演算をして最終的に\"$TargetNumber\"を作ろう"
# NumberOfStart回、0~9で乱数を取得してAvailableNumbersに追加
# shellcheck disable=SC2016
if [[ "${#AvailableNumbers[@]}" == 0 ]]; then
Loop "$NumberOfStart" eval 'ArrayAppend AvailableNumbers <<< $(( RANDOM % 10 ))'
fi
echo "今回使える数字は以下のとおりです"
}
Game.Result(){
echo "最終的に残ったのは${AvailableNumbers[0]}"
if [[ "${AvailableNumbers[0]}" = "${TargetNumber}" ]]; then
echo "クリア!"
else
echo "失敗!"
fi
exit 0
}
# Exit Code
# 0: 関数を終了
# 1: 使用できない数字
# 2: まだ俺のバトルフェイズは終了してないぜ!
# 3: 不正な入力
Game.Ask(){
local UsedNumber=()
local InputExpr PreviousExpr
PrintArray "${AvailableNumbers[@]}" | ForEach echo "・ {}"
echo -n "(式)> "
read -r InputExpr
# 空白を削除
InputExpr="$(RemoveBlank <<< "$InputExpr")"
# 通常以外のコマンド?的なもの
PreviousExpr="$(PrintArray "${ExprHistory[@]}" | tail -n 1)" # 履歴から前回の式だけ取り出す
case "$InputExpr" in
"back" | "undo")
[[ "${#ExprHistory[@]}" = 0 ]] && return 2
# 前回の式で使われた数字を元に戻す
ArrayAppend AvailableNumbers < <(GetExprNumbers "$(cut -d "=" -f 1 <<< "${PreviousExpr}")")
# 前回の式で追加された数字を削除する
readarray -t AvailableNumbers < <(PrintArray "${AvailableNumbers[@]}" | RemoveMatchLine "$(cut -d "=" -f 2 <<< "${PreviousExpr}")")
# 履歴から前回の式を削除する
readarray -t ExprHistory < <(PrintArray "${ExprHistory[@]}" | sed -e '$d')
return 2
;;
"help")
HelpMessage
return 2
;;
"history")
PrintArray "${ExprHistory[@]}" | ForEach echo "- {}"
return 2
;;
"clear")
echo -e "\x1b\x5b\x48\x1b\x5b\x32\x4a\c"
return 2
;;
"exit")
return 0
esac
# 入力された文字の確認
# shellcheck disable=SC2143
if [[ -z "${InputExpr}" ]]; then
#echo "式を入力してください。"
return 3
elif [[ -n "$(grep -v -e "[0-9]+" -e "+" -e "-" -e "*" -e "/" <<< "$InputExpr")" ]]; then
echo "式以外が入力されました。"
return 3
fi
# 改行を出力
echo
# 指定された式の数字が使えるかどうかを確認
local Num
while read -r Num; do
if ! PrintArray "${AvailableNumbers[@]}" | grep -qx -- "$Num"; then
echo "${Num}は使えません!"
AvailableNumbers+=("${UsedNumber[@]}")
unset UsedNumber
return 1 # 異常終了して関数を再度呼び出す
else
UsedNumber+=("$Num")
readarray -t AvailableNumbers < <(PrintArray "${AvailableNumbers[@]}" | RemoveMatchLine "$Num")
fi
done < <(GetExprNumbers "$InputExpr")
# 計算結果
local CalculatedValue="$(( "$InputExpr" ))"
AvailableNumbers+=("${CalculatedValue}")
# もし数字が1つだけならゲームを終了する
if [[ "${#AvailableNumbers[@]}" = 1 ]]; then
return 0
else
# 異常終了してこの関数を再度呼び出す
ExprHistory+=("${InputExpr}=${CalculatedValue}")
return 2
fi
}
#-- Parse args --#
ParseArg LONG="help,target:,jamaica,number:" SHORT="ht:jn:" -- "$@" && eval set -- "${OPTRET[*]}"
while true; do
case "$1" in
"--target" | "-t")
CheckNum "$2" || { echo "小数は利用できません。"; exit 1; }
TargetNumber="$2"
shift 2
;;
"--jamaica" | "-j")
TargetNumber="$(( (RANDOM % 6 + 1) * 10 + (RANDOM % 6 + 1)))"
shift 1
;;
"--number" | "-n")
tr "," "\n" <<< "$2" | ForEach CheckNum "{}" || { echo "小数は利用できません。"; exit 1; }
readarray -t AvailableNumbers < <(tr "," "\n" <<< "$2")
shift 2
;;
"--help" | "-h")
HelpMessage
shift 1
;;
"--")
break
shift 1
;;
esac
done
Game.Main
@Hayao0819
Copy link
Author

@Hayao0819
Copy link
Author

@Hayao0819
Copy link
Author

@Hayao0819
Copy link
Author

@Hayao0819
Copy link
Author

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