HiLo-international

Summary

HJG HiLo is a simple number-guessing game: for each guess, you get the answer "too high" or "too low", until you guess right.

Code


 #!/bin/sh
 # Restart with tcl: -*- mode: tcl; tab-width: 4; -*- \
 exec wish $0 ${1+"$@"}

 #: HiLo-international.tcl - HaJo Gurt - 2005-10-31
 #: Simple number-guessing-game, international version with msgcat
 #
 # 2005-06-21 First release / PT: Portuguese messages
 # 2005-07-03 Text-highlights
 # 2005-10-31 IT: Italian messages

 #########1#########2#########3#########4#########5#########6#########7#####

  package require Tk
  package require msgcat
  namespace import msgcat::mc msgcat::mcset

 # Tcl 8.4 initializes the locale from ::env(LC_ALL) or ::env(LC_MESSAGES),
 # but on Windows these might not be set, so you have to select yourself:
 #msgcat::mclocale en
  msgcat::mclocale de               ;# <=====<< Select language

 # Load messages from file:
 #msgcat::mcload [file join [file dirname [info script]] msgs]

 # EN (alternative wording):
  mcset en "You needed %d guesses." "Number of guesses: %d"
  # To avoid "You needed 1 guesses."

 # DE - German messages:
  mcset de "HiLo-international"     "Zahlenraten-International"
  mcset de "New game"               "Neues Spiel"
  mcset de "Guess"                  "Eingabe"
  mcset de "Guess my number"        "Raten Sie meine Zahl"
  mcset de "%d is too low"          "%d ist zu niedrig"
  mcset de "%d is too high"         "%d ist zu hoch"
  mcset de "%d is correct."         "%d ist richtig."
 #mcset de "You needed %d guesses." "Sie haben %d Versuche gebraucht."
 #                                   ....+....1....+....2....+....3..
  mcset de "You needed %d guesses." "Anzahl Rateversuche: %d"  ;# shorter

 # IT - Italian messages:
  mcset it "HiLo-international"     "Alto-Basso Internazionale"
  mcset it "New game"               "Nuovo gioco"
  mcset it "Guess"                  "Indovina"
  mcset it "Guess my number"        "Indovina il mio numero"
  mcset it "%d is too low"          "%d troppo basso"
  mcset it "%d is too high"         "%d troppo alto"
  mcset it "%d is correct."         "%d giusto."
  mcset it "You needed %d guesses." "Numero di tentativi : %d"

 # PT - Portuguese messages:
  mcset pt "HiLo-international"     "Adivinhe meu número"
  mcset pt "New game"               "Novo jogo"
  mcset pt "Guess"                  "Palpite"
  mcset pt "Guess my number"        "Adivinhe meu número"
  mcset pt "%d is too low"          "%d é muito baixo"
  mcset pt "%d is too high"         "%d é muito alto"
  mcset pt "%d is correct."         "%d está correto"
 #mcset pt "You needed %d guesses." "Você precisou de %d tentativas."
  mcset pt "You needed %d guesses." "Você acertou em %d tentativas."


 #########1#########2#########3#########4#########5#########6#########7#####

  proc random { {range 100} } {
  #: Return a number in the range 0 .. $range-1
    return [expr {int(rand()*$range)}]
  }

  proc Disp { {w .res1} {str ""} {tag ""} } {
  #: Output string to one of the text-widgets
    $w insert end "\n"
    $w insert end $str $tag
    $w see end          ;# scroll to bottom
  }

  proc Disable {} {
  #: Disable entry-widget, highlight frame around Newgame-Button
    .f2a  config -bg green
    .f2b  config -bg grey
    .inp1 config -state readonly
  }

  proc NewGame {} {
  #: Start a new game, put GUI in start-position
    set ::nGuess  0
   #set ::Secret 13
    set ::Secret [expr {[random $::Max] +1 }]

    .f2a  config -bg grey
    .f2b  config -bg green
    .inp1 config -state normal

    .res1 delete 0.0 end
    .res2 delete 0.0 end
    Disp .res1 "  [mc "Guess my number"]:\n" Hi
    Disp .res2 "  (1 .. $::Max)\n"           Hi
  }

  proc TestNum {str} {
  #: Validate input into entry-widget: Check if input is numeric
    set ok [string is integer $str]  
    if {$ok==0} {bell}               ;# alert: invalid input
    return $ok
  }

 #########1#########2#########3#########4#########5#########6#########7#####

  proc Update {} {
  #: Process input from entry-widget, update display
    global Secret Guess nGuess

  # Check input:
    if {$Guess eq ""} {
      bell               ;# alert: empty input
    } else {
      incr nGuess
      if {$Guess <  $Secret} { Disp .res1 [mc "%d is too low"  $Guess] }
      if {$Guess >  $Secret} { Disp .res2 [mc "%d is too high" $Guess] }
      if {$Guess == $Secret} { Disable
                               Disp .res1 [mc "%d is correct." $Guess] Ok
                               Disp .res1 [mc "You needed %d guesses." $nGuess];
                             }
    }
    set Guess ""         ;# clear input-field
  }

 #########1#########2#########3#########4#########5#########6#########7#####

  proc Init {} {
  #: Initialize values, build GUI
    global Max Secret Guess nGuess
    set Max 100

    frame  .f1
    frame  .f2      -padx 2 -relief ridge -borderwidth 3  
    pack   .f1 .f2  -padx 2 -pady 2

    frame  .f2a -borderwidth 3
    frame  .f2x                     ;# Frame for spacer
    frame  .f2b -borderwidth 3
    pack   .f2a .f2x .f2b  -in .f2  -side left  -padx 2 -pady 2  -fill y

    text   .res1 -width 25 -height 10
    text   .res2 -width 20 -height 10
    pack   .res1 .res2  -in .f1  -side left
    # Styles for text-highlights:
    .res1 tag configure "Hi"  -background lightblue -underline 1
    .res2 tag configure "Hi"  -background lightblue -underline 0
    .res1 tag configure "Ok"  -background red       -foreground white

    tk_optionMenu .opt1 Max 16 32 64 100 128 256 512 1000 1024 2048 4096 8192
    button        .but1 -text [mc "New game"] -command {NewGame}
    label         .lx   -text ""  -anchor c -padx 4 -bg grey          ;# Spacer
    label         .lab1 -text "[mc "Guess"]:"
    entry         .inp1 -width 5  -textvariable Guess -validate key -validatecommand {TestNum %P}
    pack          .opt1 .but1     -in .f2a  -side left  -padx 2 -pady 2
    pack          .lx             -in .f2x
    pack          .lab1 .inp1     -in .f2b  -side left  -padx 2 -pady 2

    bind          .inp1 <Return> {Update}

   #wm title . "HiLo-international"
    wm title . [mc HiLo-international]
    focus -force .inp1
  }

  Init
  NewGame

Comments

HJG Another small demo for using msgcat.
The GUI is done with frames, pack, entry, tk_optionMenu and two text-areas for output.
These are used to separate the "too low" and "too high"-results.

See also: HiLo (the Tcl / text-only-version) and HiLo2 (the simple GUI-version without msgcat).


gold 9/20/2020, added pix, # TCL source code above left unchanged.


Figure 1. HiLo-international Screenshot


HiLo-international Screenshot