diff options
Diffstat (limited to 'ipl/progs/yahtz.icn')
-rw-r--r-- | ipl/progs/yahtz.icn | 575 |
1 files changed, 575 insertions, 0 deletions
diff --git a/ipl/progs/yahtz.icn b/ipl/progs/yahtz.icn new file mode 100644 index 0000000..4c259b6 --- /dev/null +++ b/ipl/progs/yahtz.icn @@ -0,0 +1,575 @@ +############################################################################ +# +# File: yahtz.icn +# +# Subject: Program to play yahtzee +# +# Author: Chris Tenaglia +# +# Date: March 3, 1996 +# +############################################################################ +# +# This file is in the public domain. +# +############################################################################ +# +# Version: 1.3 +# +############################################################################ +# +# Modified by Richard Goerwitz with corrections by Phillip Lee Thomas +# +############################################################################ +# +# 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, random +# +############################################################################ + +link iolib +link random + +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) + randomize() + 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 |