home *** CD-ROM | disk | FTP | other *** search
- ############################################################################
- #
- # File: yahtz.icn
- #
- # Subject: Program to play yahtzee
- #
- # Author: Chris Tenaglia, modified by Richard Goerwitz with
- # corrections by Phillip Lee Thomas
- #
- # Date: June 22, 1992
- #
- ########################################################################
- #
- # Version: 1.3
- #
- ###########################################################################
- #
- # This hacked version will run under UNIX, and under DOS as well. It
- # should run out of the box on DOS as long as you stay in the current
- # directory. See the README file.
- #
- # This is a test version!! In accordance with the author's wishes,
- # I'd like to make it clear that I've altered all the screen I/O
- # routines, and have removed characters peculiar to VT terminals.
- # I've tried to keep intact the author's indentation and brace style.
- # Changes, where present, have been indicated by my initials. The
- # IPL-style header was added by me.
- #
- # -Richard Goerwitz.
- #
- ############################################################################
- #
- # Links: iolib
- #
- ############################################################################
-
- link iolib
-
- global players,slot,team,d,od,dice,round
- procedure main(param)
- paint()
- assign_players()
- every round := 1 to 13 do
- every play(!team)
- summarize()
- end
-
- #
- # DISPLAYS THE HEADER AND SEPARATOR LINE AT BEGINNING OF GAME
- #
- procedure paint()
- # Clear first, separately. Screws up on some terminals of you don't.
- writes(cls())
- # Check to be sure the terminal is big enough, and won't leave magic
- # cookies on the screen. -RLG
- if getval("ug"|"sg") > 0
- then stop("abort: Can't do magic cookie terminals!")
- if getval("li") < 24 | getval("co") < 80 then
- stop("abort: Your terminal is too small!")
- write(high(uhalf(" Y A H T Z E E ")))
- write(high(lhalf(" Y A H T Z E E ")))
- write(at(1,10),graf(repl("=",75)))
- end
-
- #
- # DISPLAYS THE FINAL SCORE OF ALL THE PLAYERS
- #
- procedure summarize()
- local player, card, top, bottom, i
-
- # blink, high, inverse was just too much for my terminal to handle -RLG
- write(at(1,11), high(chop("Final Score Summary")))
- every player := key(players) do
- {
- card := players[player]
- top := 0 ; every i := 1 to 6 do top +:= card[i]
- if top > 62 then top +:= 35
- bottom := 0 ; every i := 7 to 13 do bottom +:= card[i]
- write("Player ",high(left(player,14))," Top = ",right(top,5),
- " Bottom = ",right(bottom,5),
- " Total = ",right(top+bottom,5))
- }
- input("<press return>")
- end
-
- #
- # SETUP AND INITIALIZATION OF YAHTZEE ENVIRONMENT
- #
- procedure assign_players()
- local n, player
-
- n := 1 ; team := [] ; slot := [] ; d := list(6,"") ; od := list(5,0)
- &random := map(&clock,":","9")
- players := table("n/a")
- repeat
- {
- (player := input(("Name of player #" || n || ": "))) |
- stop("Game called off.")
- if player == "" then break
- n +:= 1
- put(team,player)
- players[player] := list(13,"*")
- }
- if n = 1 then stop("Nobody wants to play!")
-
- put(slot,"Ones") ; put(slot,"Twos") ; put(slot,"Threes")
- put(slot,"Fours") ; put(slot,"Fives") ; put(slot,"Sixes")
- put(slot,"3oK") ; put(slot,"4oK") ; put(slot,"FullH")
- put(slot,"SmStr") ; put(slot,"LgStr") ; put(slot,"Yahtzee")
- put(slot,"Chance")
-
- # VT-specific characters removed. -RLG
- d[1] := "+-----+| || o || |+-----+"
- d[2] := "+-----+| || o o || |+-----+"
- d[3] := "+-----+|o || o || o|+-----+"
- d[4] := "+-----+|o o|| ||o o|+-----+"
- d[5] := "+-----+|o o|| o ||o o|+-----+"
- d[6] := "+-----+|o o o|| ||o o o|+-----+"
- end
-
- #
- # THIS ROUTINE LETS A PLAYER TAKE THEIR TURN
- #
- procedure play(name)
- local shake, select
-
- writes(at(1,11),"It's ",high(name),"'s turn",chop())
- writes(at(1,getval("li")-1),high(name))
- input(", please press <RETURN> to begin.")
- score(name)
- dice := [] ; every 1 to 5 do put(dice,?6)
- depict()
- shake := obtain("Shake which ones : ")
- (shake === []) | (every dice[!shake] := ?6)
- depict()
- shake := obtain("Shake which ones (last chance) : ")
- (shake === []) | (every dice[!shake] := ?6)
- depict()
- repeat
- {
- select := input(at(1,22) || clip("Tally to which category (1-13) : "))
- numeric(select) | next
- (1 <= select <= 13) | next
- (players[name][select] == "*") | next
- break
- }
- tally(name,select)
- score(name)
- input(at(1,22) || clip("Press <RETURN>"))
- end
-
- #
- # THIS ROUTINE DRAWS THE DICE
- #
- procedure depict()
- local i, j, x
-
- every i := 1 to 5 do
- {
- x := 1
- writes(at(i*10+3,3),inverse(i))
- writes(at(i*10+4,9),inverse(dice[i]))
- every j := 4 to 8 do
- { # debug
- writes(at(i*10,j),graf(d[dice[i]][x:x+7]))
- x +:= 7
- }
- od[i] := dice[i]
- }
- end
-
- #
- # THIS ROUTINE LETS THE PLAYER DECIDE WHAT TO APPLY THE SHAKES TO
- #
- procedure tally(name,area)
- local sum, unit, flag, tmp, piece, hold
-
- case integer(area) of
- {
- 1 : { # ones
- sum := 0 ; every unit := !dice do if unit = 1 then sum +:= 1
- players[name][1] := sum
- }
- 2 : { # twos
- sum := 0 ; every unit := !dice do if unit = 2 then sum +:= 2
- players[name][2] := sum
- }
- 3 : { # threes
- sum := 0 ; every unit := !dice do if unit = 3 then sum +:= 3
- players[name][3] := sum
- }
- 4 : { # fours
- sum := 0 ; every unit := !dice do if unit = 4 then sum +:= 4
- players[name][4] := sum
- }
- 5 : { # fives
- sum := 0 ; every unit := !dice do if unit = 5 then sum +:= 5
- players[name][5] := sum
- }
- 6 : { # sixes
- sum := 0 ; every unit := !dice do if unit = 6 then sum +:= 6
- players[name][6] := sum
- }
- 7 : { # 3 of a kind
- sum := 0 ; flag := 0
- tmp := table(0) ; every unit := !dice do tmp[unit] +:= 1
- every piece := key(tmp) do
- if tmp[piece] >= 3 then flag := 1
- if flag = 1 then every sum +:= !dice
- players[name][7] := sum
- }
- 8 : { # four of a kind
- sum := 0 ; flag := 0
- tmp := table(0) ; every unit := !dice do tmp[unit] +:= 1
- every piece := key(tmp) do
- if tmp[piece] >= 4 then flag := 1
- if flag = 1 then every sum +:= !dice
- players[name][8] := sum
- }
- 9 : { # full house
- sum := 0 ; flag := 0
- tmp := table(0) ; every unit := !dice do tmp[unit] +:= 1
- every piece := key(tmp) do
- {
- if tmp[piece] = 3 then flag +:= 1
- if tmp[piece] = 2 then flag +:= 1
- }
- if flag = 2 then sum := 25
- players[name][9] := sum
- }
- 10 : { # small straight
- sum := 0 ; flag := 0
- hold := set() ; every insert(hold,!dice)
- tmp := sort(hold)
- if tmp[1]+1 = tmp[2] &
- tmp[2]+1 = tmp[3] &
- tmp[3]+1 = tmp[4] then flag := 1
- if tmp[2]+1 = tmp[3] &
- tmp[3]+1 = tmp[4] &
- tmp[4]+1 = tmp[5] then flag := 1
- if flag = 1 then sum := 30
- players[name][10] := sum
- }
- 11 : { # large straight
- sum := 0 ; flag := 0
- tmp := sort(dice)
- if tmp[1]+1 = tmp[2] &
- tmp[2]+1 = tmp[3] &
- tmp[3]+1 = tmp[4] &
- tmp[4]+1 = tmp[5] then flag := 1
- if flag = 1 then sum := 40
- players[name][11] := sum
- }
- 12 : { # yahtzee
- sum := 0 ; flag := 0
- tmp := table(0) ; every unit := !dice do tmp[unit] +:= 1
- every piece := key(tmp) do
- if tmp[piece] = 5 then flag := 1
- if flag = 1 then sum := 50
- players[name][12] := sum
- }
- 13 : { # chance
- sum := 0 ; every sum +:= !dice
- players[name][13] := sum
- }
- }
- end
-
- #
- # THIS ROUTINE OBTAINS A VALID SHAKER REQUEST
- #
- procedure obtain(prompt)
- local line, unit, units
-
- repeat
- {
- writes(at(1,22),prompt)
- (line := read()) | next
- if match("q",map(line)) then stop("Game Quit")
- if trim(line) == "" then return []
- units := parse(line,', \t')
- every unit := !units do
- (1 <= unit <= 5) | next
- break
- }
- return units
- end
-
- #
- # THIS ROUTINE PAINTS THE SCORECARD FOR A GIVEN PLAYER
- #
- procedure score(name)
- local st1, st2, i, bonus
-
- # Slight realignment. -RLG
- writes(at(1,11),chop(),at(18,11),under(),"Player = ",name," Round = ",under(round))
- writes(at(10,12)," 1 : Ones = ",players[name][1])
- writes(at(10,13)," 2 : Twos = ",players[name][2])
- writes(at(10,14)," 3 : Threes = ",players[name][3])
- writes(at(10,15)," 4 : Fours = ",players[name][4])
- writes(at(10,16)," 5 : Fives = ",players[name][5])
- writes(at(10,17)," 6 : Sixes = ",players[name][6])
- writes(at(40,12)," 7 : 3oK = ",players[name][7])
- writes(at(40,13)," 8 : 4oK = ",players[name][8])
- writes(at(40,14)," 9 : FullH = ",players[name][9])
- writes(at(40,15),"10 : SmStr = ",players[name][10])
- writes(at(40,16),"11 : LgStr = ",players[name][11])
- writes(at(40,17),"12 : Yahtzee = ",players[name][12])
- writes(at(40,18),"13 : Chance = ",players[name][13])
- st1 := 0 ; every i := 1 to 6 do st1 +:= numeric(players[name][i])
- if st1 > 62 then bonus := 35 else bonus := 0
- st2 := 0 ; every i := 7 to 13 do st2 +:= numeric(players[name][i])
- writes(at(10,19),"Bonus = ",clip(bonus))
- writes(at(10,20),"Subtotal = ",st1+bonus)
- writes(at(40,20),"Subtotal = ",st2)
- writes(at(37,21),"Grand Total = ",st1+st2+bonus)
- end
-
- #
- # From here down, all CT's VT-specific I/O codes have been replaced
- # with calls to iolib/itlib routines. The replacements were quite
- # easy to do because of the great modularity of the original program.
- # -RLG
- #
-
- #
- # VIDEO ROUTINE CLEARS SCREEN
- #
- procedure cls(str)
- static clear_string
- initial {
- clear_string := getval("cl") |
- (igoto(getval("cm"),1,1) || getval("cd")) |
- stop("abort: Your terminal can't clear screen!")
- }
- /str := ""
- return clear_string || str
- end
-
- #
- # VIDEO ROUTINE ERASES REST OF SCREEN
- #
- procedure chop(str)
- static clear_rest
- initial {
- clear_rest := getval("cd") |
- stop("abort: Sorry, your terminal must have cd capability.")
- }
- /str := ""
- return clear_rest || str
- end
-
- #
- # VIDEO ROUTINE OUTPUTS UPPER HALF OF DOUBLE SIZE MESSAGES
- #
- procedure uhalf(str)
- # Disabled for non-VT{2,3,4}XX terminals. I'd have left them in for
- # vt100s, but there are so many vt100 terminal emulation programs out
- # there that don't do the big characters that I thought better of it.
- # -RLG
- static isVT
- initial
- {
- if map(getname()) ? (tab(find("vt")+2), tab(any('234')), integer(tab(0)))
- then isVT := 1
- }
- if \isVT then
- {
- /str := ""
- if str == "" then return "\e#3"
- return "\e#3" || str
- }
- end
-
- #
- # VIDEO ROUTINE OUTPUTS BOTTOM HALF OF DOUBLE SIZE MESSAGES
- #
- procedure lhalf(str)
- static isVT
- initial
- {
- if map(getname()) ? (tab(find("vt")+2), tab(any('234')), integer(tab(0)))
- then isVT := 1
- }
- if \isVT then
- {
- /str := ""
- if str == "" then return "\e#4"
- return "\e#4" || str
- }
- end
-
- #
- # VIDEO ROUTINE OUTPUTS STRING AND CLEARS TO EOL
- #
- procedure clip(str)
- static clear_line
- initial
- {
- clear_line := getval("ce") | " "
- }
- /str := ""
- if str == "" then return clear_line
- return str ||:= clear_line
- end
-
- #
- # VIDEO ROUTINE OUTPUTS HIGHLIGHTED STRINGS
- #
- procedure high(str)
- static bold_code, off_other_modes
- initial
- {
- off_other_modes := ""
- every off_other_modes ||:= getval("me"|"ue"|"se")
- bold_code := off_other_modes || getval("md"|"us"|"so")
- }
- /str := ""
- return bold_code || str || off_other_modes
- end
-
- #
- # VIDEO ROUTINE OUTPUTS INVERSE VIDEO STRINGS
- #
- procedure inverse(str)
- static reverse_code, off_other_modes
- initial
- {
- off_other_modes := ""
- every off_other_modes ||:= getval("se"|"ue"|"me")
- reverse_code := off_other_modes || getval("so"|"us"|"md")
- }
- /str := ""
- return reverse_code || str || off_other_modes
- end
-
- #
- # VIDEO ROUTINE OUTPUTS UNDERLINED STRINGS
- #
- procedure under(str)
- static underline_code, off_other_modes
- initial
- {
- off_other_modes := ""
- every off_other_modes ||:= getval("ue"|"me"|"se")
- underline_code := off_other_modes || getval("us"|"md"|"so")
- }
- /str := ""
- return underline_code || str || off_other_modes
- end
-
- #
- # VIDEO ROUTINE OUTPUTS BLINKING STRINGS
- #
- procedure blink(str)
- static blink_code, off_other_modes
- initial
- {
- off_other_modes := ""
- every off_other_modes ||:= getval("me"|"se"|"ue")
- blink_code := off_other_modes || getval("mb"|"md"|"so"|"us")
- }
- /str := ""
- return blink_code || str || off_other_modes
- end
-
- #
- # VIDEO ROUTINE SETS NORMAL VIDEO MODE
- #
- procedure norm(str)
- static off_modes
- initial
- {
- off_modes := ""
- every off_modes ||:= getval("me"|"se"|"ue")
- }
- /str := ""
- return off_modes || str
- end
-
- #
- # VIDEO ROUTINE TURNS ON VT GRAPHICS CHARACTERS
- #
- procedure graf(str)
- # Again, disabled for non-VT{234}XX terminals. -RLG
- static isVT
- initial
- {
- if map(getname()) ? (tab(find("vt")+2), tab(any('234')), integer(tab(0)))
- then isVT := 1
- }
- /str := ""
- if \isVT then
- {
- if str == "" then return "\e(0"
- str := "\e(0" || str
- if (str[-3:0] == "\e(B")
- then return str
- else return str || "\e(B"
- }
- else return str
- end
-
- #
- # VIDEO ROUTINE TURNS OFF VT GRAPHICS CHARACTERS
- #
- procedure nograf(str)
- static isVT
- initial
- {
- if map(getname()) ? (tab(find("vt")+2), tab(any('234')), integer(tab(0)))
- then isVT := 1
- }
- /str := ""
- if \isVT then
- {
- if str == "" then return "\e(B"
- str := "\e(B" || str
- }
- return str
- end
-
- #
- # VIDEO ROUTINE SETS CURSOR TO GIVEN X,Y COORDINATES
- #
- procedure at(x,y)
- return igoto(getval("cm"), x, y)
- end
-
- ######### Here end the I/O routines I needed to alter. -RLG
-
- #
- # PARSES A STRING INTO A LIST WITH RESPECT TO A GIVEN DELIMITER
- #
- procedure parse(line,delims)
- local i, tokens
- static chars
- chars := &cset -- delims
- tokens := []
- line ? while tab(upto(chars)) do put(tokens,tab(many(chars)))
- #
- # My first time playing, I didn't put spaces between the numbers
- # for the dice. When you think about it, though, why bother?
- # They can't be any longer than one digit each, so there's no
- # ambiguity. This bit of code makes the game a bit more idiot-
- # proof. -RLG (one of the idiots)
- #
- if *!tokens > 1 then line ?
- {
- tokens := []
- if tab(upto(&digits)) then
- {
- while put(tokens, move(1)) do
- tab(upto(&digits)) | break
- put(tokens, integer(tab(0)))
- }
- }
- return tokens
- end
-
- #
- # TAKE AN INPUT STRING VIA GIVEN PROMPT
- #
- procedure input(prompt)
- writes(prompt)
- return read()
- end
-