-
-
Save tb3088/3d297d2327400c2915e55be2d6280a7a to your computer and use it in GitHub Desktop.
#!/bin/bash -e | |
set -o pipefail; LC_COLATE=C | |
: "${LETTERS:=5}" | |
: "${ROUNDS:=7}" | |
: "${DICTIONARY:=/usr/share/dict/words}" | |
#https://www.shellhacks.com/bash-colors/ | |
hit='\e[30;102m'; match='\e[30;103m'; miss='\e[30;107m'; reset='\e[0m' | |
pool=`printf '%s' {a..z}` | |
readlink -e "$DICTIONARY" >/dev/null | |
# pick first letter because uneven frequency distribution | |
first=${pool:(( RANDOM % ${#pool} )):1} | |
mapfile -t words < <( | |
( zcat "$DICTIONARY" 2>/dev/null || cat "$DICTIONARY" ) | | |
grep -xiE "^${first:?}[a-z]{$(( LETTERS - 1 ))}" | |
) | |
declare -i wc=${#words[@]} | |
declare -i line=$(( RANDOM % wc )) | |
declare -l guess='' secret=${words[$line]} | |
${DEBUG:+ echo $secret: $line/$wc} | |
function score { | |
local -a pad=() matched=(); color=$reset | |
# pre-mark hits with '=', then later '.' for match | |
for (( i=0; i < LETTERS; i++ )); do | |
c=${guess:$i:1}; k=${secret:$i:1} | |
[[ "$k" == "$c" ]] && pad[$i]='=' || pad[$i]=$k | |
done | |
for (( i=0; i < LETTERS; i++ )); do | |
c=${guess:$i:1} | |
if [[ ${pad[$i]} == '=' ]]; then | |
color=$hit; matched+=( "$c" ) | |
elif [[ "$c" == " " ]]; then | |
# _hint | |
color=$reset; c='_' | |
elif [[ "${pad[@]}" =~ ${c:-\000} ]]; then | |
# mark with '.' | |
color=$match; pad=( "${pad[@]//$c/.}" ); matched+=( "$c" ) | |
else | |
color=$miss | |
[[ "${matched[@]}" =~ $c ]] || pool=${pool/$c/ } | |
fi | |
pool=${pool/$c/${c^^}} | |
echo -en "$color ${c^^} " | |
done | |
echo -e "${reset}\t\t${pool}\n" | |
} | |
#--- MAIN --- | |
echo "Guess the secret word ($LETTERS letters) in $ROUNDS attempts. (Type '_hint' for an assist)" | |
echo | |
for (( j=1; j <= ROUNDS; j++ )); do | |
read -ep "$j/$ROUNDS: " guess | |
if [[ "$guess" =~ _hint ]]; then | |
offset=$(( RANDOM % LETTERS )) | |
guess=`printf '%*s%*s' $((offset + 1)) "${secret:$offset:1}" $((LETTERS - offset - 1)) ' '` | |
elif (( ${#guess} != LETTERS )) || ! [[ "$guess" =~ [a-z]{$LETTERS} ]]; then | |
echo -e " WARN\timproper guess"; continue | |
fi | |
score | |
[[ "$guess" == "$secret" ]] && { echo "Congratulations!"; exit; } | |
done | |
echo "The word was '$secret'. Better luck next time!" | |
# dictionaries | |
# [esl]='https://eslforums.com/5-letter-words/' | |
# [github]='https://gist.githubusercontent.com/prichey/95db6bdef37482ba3f6eb7b4dec99101/raw/' | |
# [popular]='https://raw.githubusercontent.com/dolph/dictionary/master/popular.txt' | |
# http://www.yougowords.com/5-letters | |
# http://www.newgeneralservicelist.org/ | |
# [system]=/usr/share/dict/words | |
#[ -s "$DICTIONARY" ] || { | |
# command -v curl &>/dev/null || exit 1 | |
# #pic a dict, fetch and process | |
#} |
github doesn't publish emails and actively squashes them in comments/posts like this. There are excellent books out there on Bash scripting. Seems you could benefit from getting one.
https://www.oreilly.com/library/view/bash-cookbook-2nd/9781491975329/
so you want to type in the guess as lowercase and for it to echo to the screen as uppercase? what on earth for? users have capslock key for a reason. but yes you can do this, you just need to turn off echo during a tight loop read() and then echo out. But if you want to upper-case immediately whatever the user typed in, just declare -u
the variable. First rule of programming is don't fk with what the user is typing in.
just because you 'score' the user's entry as all caps is distinct and separate from overriding the keystrokes they are entering during read(). NEVER lie to the user by changing his input as he's typing it. If you want to 'score' the guess as lowercase if he used lower, and score it as upper if he used upper, then don't use declare -u
or declare -l
for guess.
sorry man but you're wasting time on a broken UI paradigm. The correct answer is to not do that.
Hey @CqN let's chat over here. 'declare -l' or '-u' forces lower or upper case when values are assigned.