home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.cs.arizona.edu
/
ftp.cs.arizona.edu.tar
/
ftp.cs.arizona.edu
/
icon
/
historic
/
v941.tgz
/
icon.v941src.tar
/
icon.v941src
/
ipl
/
progs
/
yahtz.icn
< prev
next >
Wrap
Text File
|
2000-07-29
|
15KB
|
576 lines
############################################################################
#
# 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