next up previous contents
Nästa: 12.4 Felhantering Upp: 12. Avancerad Bashprogrammering Förra: 12.2 Funktioner

12.3 Ett spel

I detta avsnitt ska vi ge ett programexempel som är något större än de tidigare. Programmet vi ska skriva är ett spel som går ut på att gissa en hemlig kod som datorn har skapat. Koden består av fem olika bokstäver från A till J. För varje gissning anger datorn hur många rätt man har - dels hur många bokstäver i gissningen som är helt rätt (rätt bokstav på rätt position), dels hur många bokstäver som är delvis rätt (rätt bokstav men fel position). En spelomgång kan se ut så här:$ spel
Ange 5 symboler (bland ABCDEFGHIJ): ABCDE
      0 Guld,   2 Silver
Ange 5 symboler (bland ABCDEFGHIJ): ABFGH
      0 Guld,   3 Silver
Ange 5 symboler (bland ABCDEFGHIJ): ACIGH
      1 Guld,   1 Silver
Ange 5 symboler (bland ABCDEFGHIJ): BDIFG
      2 Guld,   3 Silver
Ange 5 symboler (bland ABCDEFGHIJ): DFIBG
      2 Guld,   3 Silver
Ange 5 symboler (bland ABCDEFGHIJ): GDIBF
      5 Guld,   0 Silver
Rätt svar!
Hejdå, och tack för den här gången!
$
Antalet ''guld'' är antalet av de gissade bokstäverna som är helt rätt, medan antalet ''silver'' är antalet bokstäver som är delvis rätt.

När man ska skriva ett sådant program är det lämpligt att börja med att strukturera det. Detta innebär att man funderar ut vad som behöver göras och delar upp problemet i mindre delproblem som kan lösas separat. Ifall problemet/programmet är mycket stort, så brukar man först dela upp det i stora delproblem; dessa delproblem delas sedan upp i mindre delproblem och så vidare.

Så vad ska vårt spelprogram göra? Jo, först måste det skapa den hemliga koden. Därefter ska användaren få skriva in sin gissning, och programmet ska beräkna och skriva ut antalet poäng. Om gissningen inte var exakt rätt, så ska användaren få göra en ny gissning. De svåraste uppgifterna är förmodligen följande:

För var och en av dessa uppgifter skapar vi en funktion som löser respektive uppgift. Vi behöver alltså en funktion med namnet skapa_hemlig_kod, en med namnet las_in_gissning och en med namnet berakna_poang.

Man kan modifiera spelreglerna och tillåta en kod där bokstäverna inte är olika. Koden behöver inte heller bestå av exakt fem bokstäver, fyra eller sex bokstäver kunde gå lika bra. Och varför ska det vara just tio olika bokstäver att välja mellan? Dessutom skulle man kunna använda andra symboler än bokstäver i koden, till exempel siffror. Vi vill skriva programmet så att det blir lätt att ändra spelreglerna. För att uppnå detta inför vi ett antal variabler vars värden anger spelreglerna. Variabeln KODLANGD ska ange kodens längd, som i vår exempelkörning är 5. Variabeln SYMBOLER ska ange vilka symobler man får välja bland. Variabeln OLIKA_SYMBOLER ska vara ''Ja'' om koden måste bestå av olika symboler, annars ''Nej''. Ett standardtrick är att först definiera JA som 1 och NEJ som 0, och sedan definiera OLIKA_SYMBOLER som antingen JA eller NEJ.

Den hemliga koden lagras i en global variabel med namnet HEMLIG_KOD och vars värde ska vara en textsträng bestående av KODLANGD stycken symboler bland dem som anges av variabeln SYMBOLER. Varje gissning lagras på motsvarande sätt i variabeln GISSNING. Så här ser programmet ut:

#!/bin/bash

declare -i JA=1
declare -i NEJ=0
# Längden av den hemliga koden (antal positioner):
declare -i KODLANGD=5
# Ska symbolerna i den hemliga koden vara olika?
OLIKA_SYMBOLER=$JA
# Vilka symboler som ska användas (OBS! 
# Dessa måste vara olika):
SYMBOLER=ABCDEFGHIJ
# Antal symboler att välja bland:
declare -i ANTAL_SYMBOLER=${#SYMBOLER}
# HEMLIG_KOD ska innehålla den hemliga koden,
# GISSNING ska innehålla den senaste gissningen
# Följade ska ange antalet poäng för den senaste gissningen:
declare -i POANG_GULD=0
declare -i POANG_SILVER=0

function skapa_hemlig_kod()
{
  local N SYMB=$SYMBOLER SLUMPTAL NY
  HEMLIG_KOD=''
  declare -i N=0
  while (( (N+=1)<=KODLANGD )) ; do
    # Välj ny symbol slumpmässigt
    SLUMPTAL=$RANDOM%${#SYMB}
NY=${SYMB: $SLUMPTAL: 1}
    HEMLIG_KOD=$HEMLIG_KOD$NY
    # Om symbolerna i den hemliga koden ska vara olika,
    # så ta bort den valda symbolen från SYMB:
    (( OLIKA_SYMBOLER )) && SYMB=${SYMB/$NY/}
  done
}

function las_in_gissning()
{
  read -p "Ange $KODLANGD symboler (bland $SYMBOLER): " GISSNING
  # Stryk alla icke tillåtna tecken från GISSNING:
  GISSNING=${GISSNING//[^$SYMBOLER]/}
  # Finns det rätt antal tecken kvar i GISSNING?
  if (( ${#GISSNING} != $KODLANGD )) ; then
    echo 'Felaktig gissning, försök igen!'
    las_in_gissning
  fi
}

function berakna_poang()
{
  local N KOD=$HEMLIG_KOD S
  declare -i N=0
  # Beräkna först antalet guld.
  POANG_GULD=0
  # Jämför symbol för symbol mellan
  # GISSNING och KOD
  while (( N<${#KOD} )) ; do
    S=${KOD: $N: 1}
    if [ ${GISSNING: $N: 1} == $S ] ; then
       POANG_GULD=POANG_GULD+1
       # Plocka bort den symbol som gav poäng
       # så att den inte senare ger silver också:
       GISSNING=${GISSNING/$S/}
       KOD=${KOD/$S/}
    else
      N=N+1
    fi
  done
  # Beräkna nu antalet silver.
  # För varje symbol i koden, stryk den första eventuella
  # förekomsten av den från GISSNING.
  while (( (N-=1)>=0 )) ; do
    GISSNING=${GISSNING/${KOD: $N: 1}/}
  done
  # Antal silver = antalet strukna symboler i GISSNING:
  POANG_SILVER=${#KOD}-${#GISSNING}
  echo "      $POANG_GULD Guld,   $POANG_SILVER Silver"
}

skapa_hemlig_kod
while (( POANG_GULD != KODLANGD )) ; do
  las_in_gissning
  berakna_poang
done
echo 'Rätt svar!'
echo 'Hejdå, och tack för den här gången!'


next up previous contents
Nästa: 12.4 Felhantering Upp: 12. Avancerad Bashprogrammering Förra: 12.2 Funktioner
Goran Andersson
1999-03-08