Løbeseddel 4: Web-programmering med tilfældige tal og tilstand

for Databasestøttet Webpublicering

af Martin Elsman og Niels Hallenberg sidst rettet 15. februar, 2002


Opgave A i denne øvelse går ud på at blive fortrolig med at programmere med lister i Tcl. Opgave B og C omhandler hvorledes skjulte (hidden) formvariabler kan bruges til at implementere tilstand i web-programmer. I opgave C benyttes Tcl-kommandoen randomRange til generering af tilfældige tal.

Opgave A (30 procent) - Fra Tcl-lister til HTML-lister

Tcl-koden i denne opgave afvikles i Tcl-fortolkeren - ikke på web-serveren.

Opgaver:

  1. Skriv kode, som tildeler variablen toppings en liste med elementerne Ost, Oliven, Kylling og Skinke.
    set toppings [ ... ]
    Du skal bagefter kunne skrive følgende i fortolkeren:
    % set toppings
    Ost Oliven Kylling Skinke
    
  2. Skriv kode som udskriver, med kommandoen puts, længden af listen toppings på skærmen, dvs. tallet fire.
    % puts [     ...        ]
    4
    
    Du skal anvende kommandoen llength.

  3. Skriv kode, som udskriver (med puts) element nummer 2 i listen toppings på skærmen.
    % puts [       ...          ]
    Kylling
    
    Du skal anvende kommandoen lindex.

  4. Skriv kode, som tilføjer elementet Kødstykker til listen toppings.
    % ... 
    Ost Oliven Kylling Skinke Kødstykker
    
    Du skal anvende kommandoen lappend.

  5. Skriv proceduren mk_ulist, som tager en liste af strenge som argument og returnerer (med return) HTML-kode for en ikke-ordnet liste (HTML tag <ul>). Kroppen af proceduren skal indeholde et kald til kommandoen foreach, som bruges til at gennemløbe en liste. Følgende skabelon kan anvendes:
    proc mk_ulist { xs } {
      set res "<ul>\n";
      foreach ... ... {
        append res ...  ...  ...
      }
      append res "</ul>\n";
      return $res;
    }
    
    Her er et eksempel på kald af proceduren:
    % mk_ulist $toppings
    <ul>
    <li>Ost
    <li>Oliven
    <li>Kylling
    <li>Skinke
    <li>Kødstykker
    </ul>
    
  6. Skriv proceduren mk_mailto, som tager en email som argument og returnerer en <a href="mailto:..." ... > tag. Følgende skabelon kan anvendes:
    proc mk_mailto {email} {
      return "...";
    }
    
    Her er et eksempel på kald af proceduren:
    % mk_mailto nh@it-c.dk
    <a href="mailto:nh@it-c.dk"> nh@it-c.dk </a>
    
  7. Skriv proceduren mk_email_ulist, som tager en liste af emailadresser som argument og returnerer (med return) HTML-kode for en ikke-ordnet liste af emailadresser (HTML tag <ul>). Hver emailadresse skal forekomme i HTML-koden som et mailto anker, dvs. du kan med fordel gøre brug af procedureren mk_mailto ovenfor. Brug kommandoen lsort til at sikre at emailadresserne bliver listet i alfabetisk rækkefølge. Følgende skabelon kan anvendes:
    proc mk_email_ulist { xs } {
      set xs_sorted [lsort ...];
      set res "<ul>\n";
      foreach ... ... {
        append res [...] "\n";
      }
      append res "</ul>\n";
      return $res;
    }
    
    Her er et eksempel på et kald af mk_email_ulist:
    % mk_email_ulist [list "lise@itu.dk" "kenneth@itu.dk"] 
    <ul>
    <li><a href="mailto:kenneth@itu.dk"> kenneth@itu.dk </a>
    <li><a href="mailto:lise@itu.dk"> lise@itu.dk </a>
    </ul>
    
    Bemærk at emailadressen kenneth@itu.dk listes før emailadressen lise@itu.dk.
Gem alle besvarelser til opgaverne ovenfor i filen /web/login/www/oevelse4/opgaveA.tclhug.it.edu.

Opgave B (35 procent) - Election

Denne opgave er inspireret af opgave 4 i eksamenssættet for Grundlæggende Programmering, efterår 2000.

Du skal lave en web-service til stemmeoptælling. Web-servicen skal have to knapper mærket "Bush" og "Gore" og til højre for hver af knapperne information om antallet af stemmer afgivet til de to kandidater. Antallet af stemmer skal også være skjult for brugeren, dvs. med et inddatafelt input af type hidden.

Det hele skal programmeres i en fil kaldet /web/login/www/oevelse4/election.tcl. Besvarelsen ligger meget tæt op af eksemplet taeller2.tcl gennemgået til den fjerde forelæsning. Nedenfor ser du henholdsvis en skabelon til din besvarelse og et skærmdump af den vejledende løsning:

proc home_page { title body } { ... }

proc form_update { bush gore } {
  return "<center><h2>Election</h2>
          <form method=post action=election.tcl>
          <input type=hidden name=bush value=\" ... \">
          <input type=hidden name=gore value=\" ... \">
          <input type=submit name=submit value=Bush><b> ... </b><p>
          <input type=submit name=submit value=Gore><b> ... </b>
          </form>
          </center>"
}

set_form_variables 0

if {[info exists ...] &&
    [info exists ... ]} {
  if {[info exists ... ] && [string compare ... "..."] == 0} {
    incr ...
  } else {
    incr ...
  }
} else {
  set bush 49820518
  set gore 50158094
}

ns_return 200 text/html [home_page "Election" [form_update $bush $gore]]
Election
Endelig skal du indsætte et link til servicen fra din index.html side på hug.it.edu.

Opgave C (35 procent) - Gæt et tal

Denne opgave illustrerer hvorledes skjulte (hidden) formvariabler kan bruges til at implementere tilstand i et webprogram.

Din opgave er at lave et spil ``Gæt et tal'', som skal køre på din webserver på hug.it.edu. Spillet skal implementeres i filen /web/login/www/oevelse4/gaet_et_tal.tcl.

Ideen med spillet er, at webserveren bestemmer et tal mellem 0 og 100 (med randomRange kommandoen) som brugeren skal gætte. Hver gang brugeren indtaster et gæt i et formfelt, giver webserveren brugeren besked om hvorvidt gættet er for stort, for lille eller rigtigt. I tilfælde af at gættet er rigtigt skal brugeren lykønskes og have muligheden for at starte et nyt spil. Hvis derimod det gættede tal er for lille eller for stort skal brugeren have mulighed for et nyt gæt.

Spillet kan passende gøre brug af følgende tre procedurer, som placeres øverst i filen /web/login/www/oevelse4/gaet_et_tal.tcl:

proc home_page { title body } {
  return "
  <html>
  <head>
  <title>$title</title>
  </head>
  <body>
  $body
  <hr>
  <a href=\"mailto:login@itu.dk\">login@itu.dk</a>
  </body>
  </html>"
}

proc my_return_page { title body } {
  ns_return 200 text/html [home_page $title $body]
}

proc indtast_gaet_form { tal } {
  return "
  <form method=post action=gaet_et_tal.tcl>
  <input type=hidden name=tilfaeldigt_tal value=$tal>
  Indtast dit gæt:<p>
  <input type=text name=gaet size=7>
  <input type=submit value=Gæt>
  </form>"
}

Den første procedure kender vi fra forelæsningerne. Den anden procedure my_return_page tager som argumenter en titel og en krop og returnerer en HTML-side med titlen og kroppen indsat. Husk at ændre emailadressen i my_return_page proceduren. Den tredje procedure indtast_gaet_form tager et tal som argument og returnerer HTML-kode for en form til indtastning af et gæt. Når brugeren ``submitter'' formen, sendes gættet og indholdet af den skjulte formvariabel tilfaeldigt_tal til siden gaet_et_tal.tcl som form-argumenter.

Her er en skitse over hvorledes resten af filen /web/login/www/oevelse4/gaet_et_tal.tcl kan se ud:

# Sæt variablerne `gaet´ og `tilfaeldigt_tal´. Hvis variablen
# `tilfaeldigt_tal´ ikke er sat, da genereres et nyt tilfældigt
# tal og en introduktionsside til spillet "Gæt et tal" vises
# til brugeren
set_form_variables 0

if {![info exists tilfaeldigt_tal]} {
  # Variablen `tilfaeldigt_tal´ er ikke sat! Generer tilfældigt
  # tal (med randomRange) og returner en HTML-introduktionsside
  # med en form til indtastning af et gæt.
  ...
} elseif {![info exists gaet] || [string compare $gaet ""] == 0} {
  # Variablen `gaet` mangler, så vi spørger igen uden at
  # generere et nyt tilfældigt tal.
  ... 
} elseif {$gaet > $tilfaeldigt_tal} {
  # Returner en HTML-side med en form til indtastning af et nyt
  # gæt og en besked om at gættet var for stort.
  ... 
} elseif {$gaet < $tilfaeldigt_tal} {
  # Returner en HTML-side med en form til indtastning af et nyt
  # gæt og en besked om at gættet var for lille.
  ...
} else {
  # Returner en HTML-side med en lykønskning og et link til et 
  # nyt spil.
  ...
}
Din opgave er altså at udfylde ovenstående skelet med relevante kald til my_return_page proceduren.

Indsæt et link til spillet fra din index.html side på hug.it.edu.

Her følger tre skærmdumps af den vejledende løsning:

Gaet Et Tal 1 Gaet Et Tal 2 Gaet Et Tal 3

mael@it.edu, nh@it.edu