Rozszyfruj: Gra słowna
Napisał: Patryk Krawaczyński
18/09/2009 w Hacks & Scripts Brak komentarzy. (artykuł nr 156, ilość słów: 1009)
P
rzedstawiony skrypt jest tłumaczeniem “Unscramble: A Word Game” z książki “Wicked Cool Shell Scripts” autorstwa Dave’a Taylor’a udostępnionym on-line (Skrypt #99) na stronie http://www.intuitive.com/wicked/. Do tłumaczenia zostało dodane także parę informacji od tłumacza.
Jeśli widziałeś grę rozsypankę w twojej lokalnej gazecie lub grałeś w ogóle w gry słowne, jesteś zaznajomiony z podstawowymi zasadami działania tych gier: wybierane jest losowo słowo, które następnie jest kodowane. Twoim zadaniem jest zorientowanie się oraz odgadnięcie jakie oryginalnie słowo kryje się za rozsypanką w minimalnej ilości tur.
Kod:
#!/bin/sh # unscramble - wybiera słowo, koduje je i prosi użytkownika # o odgadnięcie oryginalnego słowa... wordlib="/usr/lib/games/long-words.txt" randomquote="$HOME/bin/randomquote.sh" scrambleword() { # pick a word randomly from the wordlib, and scramble it # Original word is 'match' and scrambled word is 'scrambled' match="$($randomquote $wordlib)" echo "Picked out a word!" len=$(echo $match | wc -c | sed 's/[^[:digit:]]//g') scrambled=""; lastval=1 for (( val=1; $val < $len ; )) do if [ $(perl -e "print int rand(2)") -eq 1 ] ; then scrambled=$scrambled$(echo $match | cut -c$val) else scrambled=$(echo $match | cut -c$val)$scrambled fi val=$(( $val + 1 )) done } if [ ! -r $wordlib ] ; then echo "$0: Missing word library $wordlib" >&2 echo "(online at http://www.intuitive.com/wicked/examples/long-words.txt" >&2 echo "save the file as $wordlib and you're ready to play!)" >&2 exit 1 fi newgame=""; guesses=0; correct=0; total=0 until [ "$guess" = "quit" ] ; do scrambleword echo "" echo "You need to unscramble: $scrambled" guess="??" ; guesses=0 total=$(( $total + 1 )) while [ "$guess" != "$match" -a "$guess" != "quit" -a "$guess" != "next" ] do echo "" echo -n "Your guess (quit|next) : " read guess if [ "$guess" = "$match" ] ; then guesses=$(( $guesses + 1 )) echo "" echo "*** You got it with tries = ${guesses}! Well done!! ***" echo "" correct=$(( $correct + 1 )) elif [ "$guess" = "next" -o "$guess" = "quit" ] ; then echo "The unscrambled word was \"$match\". Your tries: $guesses" else echo "Nope. That's not the unscrambled word. Try again." guesses=$(( $guesses + 1 )) fi done done echo "Done. You correctly figured out $correct out of $total scrambled words." exit 0
Jak to działa:
By losowo wybrać pojedynczą linię z pliku skrypt ten używa skryptu #76, “Wyświetlanie losowego tekstu” – nawet jeśli pierwotne został napisany w celu pracy ze stronami internetowymi. Podobnie jak wiele dobrych narzędzi Uniksa, okazuje się, że jest przydatną formą budowania w innych kontekstach niż ta jedna, do której został przeznaczony:
match="$($randomquote $wordlib)"
Najtrudniejszą częścią tego skryptu było wymyślenie jak ma być kodowane słowo. Nie ma żadnego uniksowego narzędzia, które by mogło w tym pomóc, ale na szczęście okazuje się, że jeśli złożymy zakodowane słowo, przechodząc litera po literze przez prawidłowo napisane słowo, a następnie losowo dodając każdą kolejną literę do zakodowanej sekwencji albo na jej początku, albo na jej końcu, możemy nawet efektywnie zakodować słowo – za każdym razem nieprzewidywalnie oraz w inny sposób:
if [ $(perl -e "print int rand(2)") -eq 1 ] ; then scrambled=$scrambled$(echo $match | cut -c$val) else scrambled=$(echo $match | cut -c$val)$scrambled fi
Należy zwrócić uwagę, gdzie w dwóch liniach znajduje się $scrambled: w pierwszej na początku jest dodawana litera, podczas, gdy w drugiej na końcu.
I innym przypadku główna logika gry powinna być z łatwością zrozumiana: zewnętrzna pętla while pracuje aż do momentu, kiedy użytkownik zamiast odgadywać słowo wpiszę frazę: quit, natomiast wewnętrzna pętla działa, aż użytkownik zgadnie słowo albo wpiszę frazę: next, aby przejść do kolejnego.
Uruchamianie skryptu:
Skrypt ten nie posiada żadnych argumentów czy parametrów, tak więc wystarczy wklepać jego nazwę i jesteś gotowy do gry!
Rezultaty:
$ unscramble Picked out a word! You need to unscramble: ninrenoccg Your guess (quit|next) : concerning *** You got it with tries = 1! Well done!! *** Picked out a word! You need to unscramble: esivrmipod Your guess (quit|next) : quit The unscrambled word was "improvised". Your tries: 0 Done. You correctly figured out 1 out of 2 scrambled words.
Czyste oraz intuicyjne odgadnięcie za pierwszym razem!
Modyfikowanie skryptu:
Być może jakaś metoda podpowiedzi uczyniłaby tę grę bardziej interesującą lub alternatywnie flaga, która by wymagała minimalną długość słowa, które jest akceptowalne. Aby wykonać to pierwsze, można na przykład kosztem wyniku pokazać pierwsze kilka liter niezaszyfrowanego wyrazu. Jeśli chodzi o to drugie, trzeba by mieć rozbudowany słownik wyrazów, ponieważ w tym załączonym do skryptu minimalna długość słowa to dziesięć liter, co z pewnością utrudnia zgadywanie!
Shell Script 076-randomquote.sh: #!/bin/sh # randomquote - given a one-line-per-entry datafile, this # script will randomly pick one and display it. Best used # as an SSI call within a Web page. awkscript="/tmp/randomquote.awk.$$" if [ $# -ne 1 ] ; then echo "Usage: randomquote datafilename" >&2 exit 1 elif [ ! -r "$1" ] ; then echo "Error: quote file $1 is missing or not readable" >&2 exit 1 fi trap "/bin/rm -f $awkscript" 0 cat < < "EOF" > $awkscript BEGIN { srand(); } { s[NR] = $0 } END { print s[randint(NR)] } function randint(n) { return int (n * rand() ) + 1 } EOF awk -f $awkscript < "$1" exit 0
Powyżej został zawarty kod skryptu randomquote.sh niezbędny do działania gry słownej, który należy skopiować do katalogu /bin w swoim domowym katalogu lub jeśli gra ma być dostępna dla ogółu użytkowników w systemie należy sam skrypt jak i dodatek umieścić w głównym katalogu /bin oraz nadać mu odpowiednie prawa wykonywalności. Do prawidłowego działania także wymagane jest umieszczenie słownika słów, które mają być zgadywane w katalogu: /usr/lib/games/ pod nazwą: long-words.txt.
Więcej informacji: Script Shell, man bash
- Brak tematycznie powiązanych artykułów.