For instance you could map an IP address to a site name with code like this:
set dns(127.0.1.1) localhost
set dns(64.233.169.99) www.google.com
set dns(199.111.20.4) www.emu.edu
You could then display a name instead of a number with code like:
foreach address {127.0.0.1 64.233.169.99 199.111.20.4} {
puts "ADDRESS: $address IS $dns($address)"
}
We can simulate a coin toss with the expr
command and its
rand()
function like this:
set result [expr {int(rand()*2)}]
The value in result will be either a 1 or a 0.
To report the results to a user, we don't want to say 1 or 0, we want to say "heads" or "tails".
This code will display heads for a single coin toss:
set text(0) "tails"
set text(1) "heads"
set result [expr {int(rand()*2)}]
puts "$text($result)"
Add a loop to this code to display the results of 10 coin tosses.
Once we've got a coin tossing application, we can make a simple histogram like this:
set counts(0) 0
set counts(1) 0
for {set i 0} {$i < 10} {incr i} {
set result [expr {int(rand()*2)}]
incr counts($result)
}
parray counts
Batman once captured TwoFace by getting him to agree to surrender if the coin-toss came up on edge.
Assume that there's a 1 in 100 chance of a coin toss landing on edge.
Rework the code above to generate a histogram that shows about 1 in 100 tosses landing on edge.
The results for 1000 tosses should look something like this:
counts(edge) = 8
counts(heads) = 500
counts(tails) = 492
solution
For example, this code implements part of a simple caesar cipher:
set cipher(a) b
set cipher(b) c
set cipher(c) d
set cipher(d) e
set cipher(e) f
set cipher(f) g
set str ""
foreach ch [split "beef" {}] {
append str $cipher($ch)
}
puts $str
All those set cipher...
lines are too long to type.
Use the trick in lesson exercise 4 of the encyrption lab to create a caesar cipher in a loop.
In order to test this, we'll also need an entry in the cipher associative array for the space.
This is tricky, since a space is a separator for Tcl. This code won't work:
set cipher( ) " "
We need to escape the space to force Tcl to use it as the index like this:
set cipher(\ ) " "
This problem reduces to "taking N things 1 at a time".
In real world terms, you can think of it as putting a single alphabet worth of Scrabble letters into hat, and pulling them one at a time. The first letter you pull will be the cipher for "A", the second letter will be for "B", etc.
In programming terms, we can do this by creating a list, selecting on element from the list at random, and then removing that element from the list.
Given a list of letters in alphabetic order (alphabet
and a
list of unused letters (unused
, the code to fill the associative
array looks like this:
foreach letter $alphabet {
set pos [expr {int([llength $unused] * rand())}]
set cipher($letter) [lindex $unused $pos]
set unused [lreplace $unused $pos $pos]
}
Extend this snippet into a small application that will display the enciphered version of the string "This is a Test".
That's because the Tcl random number generator doesn't always deliver the same random numbers.
Numeric pseudo-random number generators always generate the same sequence of numbers based on a given starting location. To avoid having programs always use the same random numbers, most applications (Tcl included) will seed the random number generator with a different starting value.
Most applications use the time of day in seconds as the seed.
Sometimes you need to use the same set of random numbers. For instance, if you encrypt a message using a transposition cipher that was created on your system, you will want me to be able to generate the same cipher at my end to decipher the message.
Tcl provides a function you can call to seed the random generator with
a known value. The srand
function does this. It's an
arithmetic function invoked in the expr
command.
The srand()
function sets the random number generator start point.
The Tcl interpreter calls this with the current time-in-seconds when it starts. This
ensures that you always get a different pattern of random numbers when you run an
application.
A line like this will force the random number generator to start from 0.
expr srand(0)
Modify the previous code to read arguments from the command line. The two arguments will be the seed to define the transposition cipher and the string to encrypt.
Using the same plaintext, but different seeds should look like this:
tclsh sol5.txt 1 "This is a test"
yJXh Xh g wlhw
tclsh sol5.txt 2 "This is a test"
quTl Tl n SxlS
Embrace and Extend the previous solution to include three procedures to create a cipher, encrypt or decrypt a message.
The new procedures will look like this:
proc makeCipher {cipherArrayName decipherArrayName key} {...}
proc encrypt {cipherArrayName plainText} {...}
proc dencrypt {decipherArrayName cipherText} {...}
Note the fact that the procedures are using call by name rather than call by value. When passing an associative array directly to a procedure, you must use Call by Name.
The application should accept a "-d" or "-e" flag on the command line to choose whether the message should be encrypted or decrypted, the key to use, and a message. Invoking the application will look like this:
tclsh sol6.tcl -e 1 test
returns "wlhw"
tclsh sol6.tcl -d 1 wlhw
returns "test"
Change the previous application to open and read a file, rather than just print text from the command line.
No solution for this one. You've got all the commands you need to write this application on your own.