[Back to MISC SWAG index] [Back to Main SWAG index] [Original]
{_____________________________________________________________________________
| Filename: CODE.PAS
| Title: Spite & Malice
| Written By: Benjamin Arnoldy and Raechel Kula
|_____________________________________________________________________________
| Contents:
| The procedures: Deal, WhoseTurn, PickupCards, Decision, GetMove,
| CheckMove, MoveCard
| Oject: Pile
|_____________________________________________________________________________
| Synopsis:
| This program allows the user to select either another person, or the
computer as the opponent, then play the opponent in the card game
| Spite & Malice. The interface is textual.
|_____________________________________________________________________________
| Description:
| No references at this time.
|_____________________________________________________________________________
| Environment:
| TurboPASCAL for the PC.
|_____________________________________________________________________________
| Version History:
|
| Version 5.1 -- May 8, 1996
| Raechel Kula & Benjamin Arnoldy
| Improved interface and Decision.
|
| Version 5.0 -- May 7, 1996
| Raechel Kula & Benjamin Arnoldy
| Code is cleaned up and ready for presentation.
|
| Version 4.3 -- May 6, 1996
| Raechel Kula & Benjamin Arnoldy
| Additional testing, more tinkering with weights.
|
| Version 4.2 -- May 5, 1996
| Raechel Kula & Benjamin Arnoldy
| Added provisions in decision for jokers.
|
| Version 4.1 -- May 4, 1996
| Raechel Kula & Benjamin Arnoldy
| Testing and tinkering with weights to make
| the computer a better opponent.
|
| Version 4.0 -- May 3, 1996
| Raechel Kula & Benjamin Arnoldy
| An "operable" Decision procedure is
| in place.
|
| Version 3.1 -- May 2, 1996
| Raechel Kula & Benjamin Arnoldy
| Various Embellishments to make it an operable
| 2 player game (e.g. end of game stuff).
|
| Version 3.0 -- May 1, 1996
| Raechel Kula & Benjamin Arnoldy
| Ascii Graphical Interface is instituted.
|
| Version 2.9 -- April 30, 1996
| Raechel Kula & Benjamin Arnoldy
| Small display functions (CardString) coded.
|
| Version 2.2 -- April 28, 1996
| Raechel Kula & Benjamin Arnoldy
| CheckMove procedure ironed out.
|
| Version 2.1 -- April 26, 1996
| Raechel Kula & Benjamin Arnoldy
| Basic Main Program Procedures Modified to fit with new
| object structure.
|
| Version 2.0 -- April 25, 1996
| Raechel Kula & Benjamin Arnoldy
| Object Pile Coded.
|
| MidApril -- Meeting with Prof Squier & Subsequent Major Rethinking
|
| Version 1.1 -- Apr. 7, 1996
| Raechel Kula & Benjamin Arnoldy
| Pieces of Decision and CheckMove procedures are
| completed.
|
| Version 1.0 -- Mar. 29, 1996
| Raechel Kula & Benjamin Arnoldy
| WhoseTurn, PickupCards, MoveCard procedures are coded.
| The code successfully compiles.
|
| Version 0.2 -- Mar. 12, 1996
| Raechel Kula & Benjamin Arnoldy
| Deal and GetMove procedures are coded.
|
| Version 0.2 -- Mar. 5, 1996
| Raechel Kula & Benjamin Arnoldy
| GetValue and GetPlace procedures are coded.
|
| Version 0.1 -- Feb. 30, 1996
| Raechel Kula & Benjamin Arnoldy
| Main Program and Stubs
| Version 0.0
|____________________________________________________________________________}
program SpiteMalice;
uses CRT;
{=============================================================================
CONSTANTS
=============================================================================}
const DRAWPILE_MAX = 108;
HAND_MAX = 6;
SCOREPILE_MAX = 14;
DISCARDPILE_MAX = 108;
ACEPILE_MAX = 13;
TRASHPILE_MAX = 108;
MAXSIZE = 108;
NULL = -1;
{=============================================================================
TYPES
=============================================================================}
type CardVal_t = integer;
Pos_t = integer;
CardArray_t = array [1..108] of CardVal_t;
CardValTable_t = array [1..26] of CardVal_t;
choiceTable_t = array [1..26, 1..19] of integer;
{=============================================================================
OBJECT DECLARATION
=============================================================================}
type Pile = object
{public}
procedure Init;
procedure RandomShuffle;
procedure PutOnTop (CardtoPutOn: CardVal_t);
function RemoveFromTop: CardVal_t;
function SeeRandom (Pos: Pos_t): CardVal_t;
function DeleteByValue (value : CardVal_t): CardVal_t;
function IsPresent (CardtoFind: CardVal_t): boolean;
function NumCards: integer;
private
data: CardArray_t;
top: Pos_t; {top = slot with top card in it.}
end; {Object declaration}
{=============================================================================
OBJECT DEPENEDENT TYPES
=============================================================================}
Type pilepointer_t = ^Pile;
stack_t = array [1..26] of pilepointer_t;
{=============================================================================
GLOBAL VARIABLES
=============================================================================}
var DrawPile: Pile;
PlayerHand: Pile;
ComputerHand: Pile;
PlayerScorePile: Pile;
ComputerScorePile: Pile;
PlayerDiscardPile1: Pile;
PlayerDiscardPile2: Pile;
PlayerDiscardPile3: Pile;
PlayerDiscardPile4: Pile;
ComputerDiscardPile1: Pile;
ComputerDiscardPile2: Pile;
ComputerDiscardPile3: Pile;
ComputerDiscardPile4: Pile;
AcePile1: Pile;
AcePile2: Pile;
AcePile3: Pile;
AcePile4: Pile;
TrashPile: Pile;
ComputerTurn: boolean;
Game: boolean;
Valid, Discard, DecisionDiscard: boolean;
From, Tto: integer;
PosTable : stack_t;
TopCardTable: CardValTable_t;
pos: integer;
Winner: string;
ChoiceRate: choiceTable_t;
AnotherGame: boolean;
TwoPlayer: boolean;
MustMove: boolean;
{=============================================================================
OBJECT PROCEDURES & FUNCTIONS
=============================================================================}
{____________________________________________________________________
| Init
| Initializes a pile's array (data) and pointer (top)
|___________________________________________________________________}
procedure Pile.Init;
var Count: integer;
begin
top := MAXSIZE + 1;
for Count := 1 to MAXSIZE do
Pile.PutOnTop (NULL); {Stores NULL values in entire array.}
top := MAXSIZE + 1;
end; {procedure Init}
{____________________________________________________________________
| RandomShuffle
| Shuffles the cards in a pile.
|___________________________________________________________________}
procedure Pile.RandomShuffle;
var ShuffleArray: Pile; {Temporary Storage Pile}
Counter: Pos_t;
RandSlot: integer;
DeckSize: integer;
TopofDeck: Pos_t;
begin
DeckSize := DrawPile.NumCards;
TopofDeck := (MAXSIZE - DeckSize) + 1;
ShuffleArray.Init; {Initializing ShuffleArray}
ShuffleArray.top := TopofDeck;
for Counter := 1 to DeckSize do begin
RandSlot := Random (DeckSize) + 1; {'+1' due to Random range.}
While ShuffleArray.SeeRandom (RandSlot) <> NULL do
RandSlot := Random (DeckSize) + 1;
ShuffleArray.top := TopofDeck + Randslot;
{Set ShuffleArray's "top" pointer to slot beneath empty slot, so
that PutOnTop will put the card in the empty slot.}
ShuffleArray.PutOnTop (DrawPile.RemoveFromTop);
ShuffleArray.top := TopofDeck;
end; {for}
ShuffleArray.top := TopofDeck;
{Set ShuffleArray's "top" pointer to the top of the stack.}
for Counter := 1 to DeckSize do
DrawPile.PutOnTop (ShuffleArray.RemoveFromTop);
{Transfered shuffled ShuffleArray to DrawPile.}
end; {Procedure RandomShuffle}
{____________________________________________________________________
| PutOnTop
| Places a card value on the top of the pile.
|
|___________________________________________________________________}
procedure Pile.PutOnTop (CardtoPutOn: CardVal_t);
begin
top := top - 1; {Advance the top pointer to the empty slot above it.}
If top < 0 then begin
writeln ('ERROR. Array Overflow.');
HALT;
{Program is stopped if program attempts to a put a card on top of what
should be a full pile. This should never never happen given that the
size of the pile arrays are the same size as the number of cards.}
end;
data [top] := CardtoPutOn;
end; {procedure PutOnTop}
{____________________________________________________________________
| RemoveFromTop
| Removes the top card from a pile and return the value of
| of the card.
|___________________________________________________________________}
function Pile.RemoveFromTop: CardVal_t;
begin
RemoveFromTop := data [top];
data [top] := NULL;
top := top + 1; {Adjusts the top pointer so it points at the top card.}
end; {Procedure RemoveFromTop}
{____________________________________________________________________
| SeeRandom
| Allows the program to view the card value in any given
| position in a stack.
|___________________________________________________________________}
function Pile.SeeRandom (pos: Pos_t): CardVal_t;
begin
SeeRandom := data [top + pos - 1];
{The "- 1" in the equation defines position 1 as the top card.}
if (top + pos - 1) > MAXSIZE then
SeeRandom := NULL;
{if the seek excedes the boundaries, a null value is returned.}
end; {Procedure SeeRandom}
{____________________________________________________________________
| DeleteByValue
| Searches through a pile for a designated value, and "pulls"
| the card out, returning the card's value. After the card is
| removed, the gap in the stack is filled in by readjusting the
| cards.
|___________________________________________________________________}
function Pile.DeleteByValue (value : CardVal_t): CardVal_t;
var count:integer; hold : CardVal_t;
begin
count:=0;
Repeat
count :=count+1;
Until (data[count] = value);
hold := data[top];
data[top] := value;
data[count] := hold;
hold := Pile.RemoveFromTop;
end; {Procedure DeleteByValue}
{____________________________________________________________________
| IsPresent
| Searches through a pile, looking to see if a designated card
| value is present.
|___________________________________________________________________}
function Pile.IsPresent (CardtoFind: CardVal_t): boolean;
var
ValuePresent: boolean;
begin
ValuePresent := FALSE;
while ((ValuePresent = FALSE) OR (top > MAXSIZE)) do begin
top := top + 1;
If data [top] = CardtoFind then
ValuePresent := TRUE;
end; {While}
If ValuePresent = FALSE then
IsPresent := FALSE
else
IsPresent := TRUE;
end; {Function IsPresent}
{____________________________________________________________________
| NumCards
| Returns the number of cards in a pile.
|___________________________________________________________________}
function Pile.NumCards: integer;
begin
NumCards := (MAXSIZE - top) + 1;
{The "+ 1" in the equation takes into account that the position of top
contains a card.}
end; {function NumCards}
{============================================================================
GENERAL FUNCTIONS
============================================================================}
{____________________________________________________________________
| CardValue
| Converts card value (4..111) to orderinal value.
| (0 = Joker, 1,2,3,...10,11 = JACK,...)
|___________________________________________________________________}
function CardValue (Card: CardVal_t): integer;
begin
if Card = NULL then
CardValue := NULL
else
CardValue := Card DIV 8;
end; {function CardValue}
{____________________________________________________________________
| CardString
| Converts a card value to a string, for representation on the
| screen.
|___________________________________________________________________}
function CardString (Card: CardVal_t): string;
var
Number: integer;
Output: string;
begin
Number := Card DIV 8;
if Card = NULL then Output := '' else
if Number = 0 then Output := 'JO' else
if Number = 1 then Output := 'AC' else
if Number = 2 then Output := '02' else
if Number = 3 then Output := '03' else
if Number = 4 then Output := '04' else
if Number = 5 then Output := '05' else
if Number = 6 then Output := '06' else
if Number = 7 then Output := '07' else
if Number = 8 then Output := '08' else
if Number = 9 then Output := '09' else
if Number = 10 then Output := '10' else
if Number = 11 then Output := 'JA' else
if Number = 12 then Output := 'QU' else
if Number = 13 then Output := 'KI' else
Output := 'ERROR';
Number := Card MOD 4;
if Card = NULL then Output := '' else
if (Card DIV 8) = 0 then Output := Output + '!' else
if Number = 0 then Output := Output + chr(3) else
if Number = 1 then Output := Output + chr(4) else
if Number = 2 then Output := Output + chr(5) else
if Number = 3 then Output := Output + chr(6) else
Output := 'ERROR';
CardString := Output;
end; {function CardSuit}
{___________________________________________________________________
| AceTopCard
| Due to the possibility of a joker on an ace pile, this
| function returns the ordinal value of the card on the top of
| an ace pile -- if there's a joker it is converted to its
| ordinal value within the pile.
|___________________________________________________________________}
function AceTopCard (Number: integer): integer;
var position: integer;
begin
position := 1;
while (CardValue (PosTable [Number]^.SeeRandom (position)) = 0) do
position := position + 1;
AceTopCard := CardValue (PosTable [Number]^.SeeRandom (position)) +
position - 1;
end; {function AceTopCard}
{============================================================================
MAIN PROGRAM PROCEDURES
(Grouped with corresponding sub-procedures)
============================================================================}
{___________________________________________________________________
| Initialize
| Does all the Non-Object initialization.
|__________________________________________________________________}
procedure Initialize;
var count:integer;
begin
Randomize;
DrawPile.Init;
PlayerHand.Init;
ComputerHand.Init;
PlayerScorePile.Init;
ComputerScorePile.Init;
PlayerDiscardPile1.Init;
PlayerDiscardPile2.Init;
PlayerDiscardPile3.Init;
PlayerDiscardPile4.Init;
ComputerDiscardPile1.Init;
ComputerDiscardPile2.Init;
ComputerDiscardPile3.Init;
ComputerDiscardPile4.Init;
AcePile1.Init;
AcePile2.Init;
AcePile3.Init;
AcePile4.Init;
TrashPile.Init;
Game := TRUE;
{Set up Position Table}
PosTable[1] := @PlayerHand;
PosTable[2] := @PlayerHand;
PosTable[3] := @PlayerHand;
PosTable[4] := @PlayerHand;
PosTable[5] := @PlayerHand;
PosTable[6] := @PlayerHand;
PosTable[7] := @PlayerScorePile;
PosTable[8] := @PlayerDiscardPile1;
PosTable[9] := @PlayerDiscardPile2;
PosTable[10] := @PlayerDiscardPile3;
PosTable[11] := @PlayerDiscardPile4;
PosTable[12] := @AcePile1;
PosTable[13] := @AcePile2;
PosTable[14] := @AcePile3;
PosTable[15] := @AcePile4;
PosTable[16] := @ComputerDiscardPile1;
PosTable[17] := @ComputerDiscardPile2;
PosTable[18] := @ComputerDiscardPile3;
PosTable[19] := @ComputerDiscardPile4;
PosTable[20] := @ComputerHand;
PosTable[21] := @ComputerHand;
PosTable[22] := @ComputerHand;
PosTable[23] := @ComputerHand;
PosTable[24] := @ComputerHand;
PosTable[25] := @ComputerHand;
PosTable[26] := @ComputerScorePile;
end; {procedure Initialize}
{___________________________________________________________________
| InitTable
| Refreshes the values for the TopCardTable, which stores the
| values of the top card in all 26 positions.
|__________________________________________________________________}
procedure InitTable;
var count:integer;
begin
for count := 1 to 6 Do
TopCardTable[count] := PosTable[count]^.SeeRandom (count);
for count := 7 to 19 Do
TopCardTable[count] := PosTable[count]^.SeeRandom (1);
for count := 20 to 25 Do
TopCardTable[count] := PosTable[count]^.SeeRandom(count-19);
TopCardTable[26] := PosTable[26]^.SeeRandom(1);
end; {procedure InitTable}
{___________________________________________________________________
| Deal
| Deals the cards at the beginning of each game and decides,
| based on the outcome of the deal, who will go first.
|__________________________________________________________________}
procedure Deal;
var Card: CardVal_t;
Counter: integer;
PlayerScoreTop: CardVal_t;
ComputerScoreTop: CardVal_t;
begin
for Card := (1 +3) to (MAXSIZE +3) do
{Put 2 decks of cards in draw pile, +3 is necessary for the div and mod
to operate correctly.}
DrawPile.PutOnTop (Card);
DrawPile.RandomShuffle; {Shuffle the draw pile.}
for Counter := 1 to 5 do begin {Deal the hands}
PlayerHand.PutOnTop (DrawPile.RemoveFromTop);
ComputerHand.PutOnTop (DrawPile.RemoveFromTop);
end; {for}
for Counter := 1 to 14 do begin {Deal the score piles}
PlayerScorePile.PutOnTop (DrawPile.RemoveFromTop);
ComputerScorePile.PutOnTop (DrawPile.RemoveFromTop);
end; {for}
PlayerDiscardPile1.PutOnTop (DrawPile.RemoveFromTop);
PlayerDiscardPile2.PutOnTop (DrawPile.RemoveFromTop);
PlayerDiscardPile3.PutOnTop (DrawPile.RemoveFromTop);
PlayerDiscardPile4.PutOnTop (DrawPile.RemoveFromTop);
ComputerDiscardPile1.PutOnTop (DrawPile.RemoveFromTop);
ComputerDiscardPile2.PutOnTop (DrawPile.RemoveFromTop);
ComputerDiscardPile3.PutOnTop (DrawPile.RemoveFromTop);
ComputerDiscardPile4.PutOnTop (DrawPile.RemoveFromTop);
{Decide whose turn it is. ComputerTurn set to opposite, because
it will be reversed in upcoming WhoseTurn procedure.}
PlayerScoreTop := CardValue (PlayerScorePile.SeeRandom(1));
ComputerScoreTop := CardValue (ComputerScorePile.SeeRandom(1));
if PlayerScoreTop = 0 then
ComputerTurn := FALSE
else if ComputerScoreTop = 0 then
ComputerTurn := TRUE
else if PlayerScoreTop = ComputerScoreTop then
ComputerTurn := FALSE
else if PlayerScoreTop > ComputerScoreTop then
ComputerTurn := TRUE
else
ComputerTurn := FALSE;
end; {Deal}
{___________________________________________________________________
| OutString
| One of the procedures involving the interface.
| This procedure receives x,y coordinates for a screen position
| and outputs a string starting at that position.
|__________________________________________________________________}
procedure OutString (x,y: integer; toPrint: string);
begin
GotoXY (x,y);
write (toPrint);
end; {procedure OutString}
{____________________________________________________________________
| ColorDim
| One of the procedures involving the interface.
| Sets colors for displaying things involving the player whose
| turn it is not (hence, they are dimmed.)
|___________________________________________________________________}
procedure ColorDim;
begin
TextColor (LIGHTgray);
TextBackground (BLACK);
end; {procedure ColorDim}
{___________________________________________________________________
| ColorCard
| One of the procedures involving the interface.
| Sets colors for displaying a card of the player whose turn it
| is.
|___________________________________________________________________}
procedure ColorCard;
begin
TextColor (YELLOW);
TextBackGround (BLUE);
end; {procedure ColorCard}
{____________________________________________________________________
| ColorFrame
| One of the procedures involving the interface.
| Sets colors for highlighting the section of the frame
| involving the player whose turn it is.
|___________________________________________________________________}
procedure ColorFrame;
begin
TextColor (YELLOW);
TextBackground (BLACK);
end; {procedure ColorFrame}
{____________________________________________________________________
| ColorNormalText
| One of the procedures involving the interface.
| Sets colors for normal text and is also the colors which the
| game returns to upon exiting.
|___________________________________________________________________}
procedure ColorNormalText;
begin
TextColor (WHITE);
TextBackground (BLACK);
end; {procedure ColorNormalText}
{___________________________________________________________________
| ColorPosition
| One of the procedures involving the interface.
| Sets colors for the display of position indicators.
|__________________________________________________________________}
procedure ColorPosition;
begin
TextColor (WHITE);
TextBackground (RED);
end; {procedure ColorPosition}
{___________________________________________________________________
| TitleScreen
| Displays a title screen and asks whether the user would like
| a one-player or a two-player game. Accompanying procedures are
| called by TitleScreen
|__________________________________________________________________}
procedure Heart;
begin
TextColor (red);
TextBackground (LightGray);
write (char(3));
end;
procedure Club;
begin
TextColor (black);
TextBackground (LightGray);
write (char(5));
end;
procedure Diamond;
begin
TextColor (red);
TextBackground (lightgray);
write (char(4));
end;
procedure Spade;
begin
TextColor (black);
TextBackground (lightgray);
write (char(6));
end;
procedure SuitsCol (x, y, count: integer);
var c :integer;
begin
c := 0;
while (count > 0) Do begin
GotoXY (x, y+c*4);
Heart;
GotoXY (x, y+c*4+1);
Club;
GotoXY (x, y+c*4+2);
Diamond;
GotoXY (x, y+c*4+3);
Spade;
c := c + 1;
count := count - 1;
TextBackGround (black);
end; {while loop}
end; {SuitsCol}
procedure SuitsRow (x, y, count: integer);
var c :integer;
begin
c := 0;
while (count > 0) Do begin
GotoXY (x + (4*c), y);
Heart;
Club;
Diamond;
Spade;
c := c + 1;
count := count - 1;
TextBackground (black);
end; {while loop}
end; {SuitsRow}
procedure DrawTitleBox;
Begin
SuitsCol (25, 7, 2);
SuitsRow (25, 7, 8);
SuitsRow (25, 15, 8);
SuitsCol (57, 7, 2);
GotoXY (57, 15);
Heart;
end; {DrawTitleBox}
procedure Title;
begin
TextColor (white);
TextBackground (black);
OutString (28, 9, 'Welcome to Spite & Malice!');
end;
procedure Info (var TwoPlayer : boolean);
var response : char;
begin
repeat
OutString (33, 12, 'How many players?');
OutString (37, 13, '(');
TextColor (lightred);
OutString (38, 13, '1 ');
TextColor (white);
OutString (40, 13, 'or ');
TextColor (lightred);
OutString (43, 13, '2');
TextColor (white);
OutString (44, 13, ')');
GotoXY (40, 14);
readln (response);
until ((response = '1') OR (response = '2'));
if response = '1' then
TwoPlayer := FALSE
else
TwoPlayer := TRUE;
end;
procedure TitleScreen (var TwoPlayer:boolean);
var response: char;
Begin
TextBackground (black);
clrscr;
TextBackground (black);
DrawTitleBox;
Title;
Info (TwoPlayer);
TextBackground (black);
TextColor (white);
End; {procedure TitleScreen}
{___________________________________________________________________
| DrawFrame
| One of the procedures involving the interface.
| This procedure draws the ascii graphical skeleton of the
| screen. It also takes into account the turn in its choice of
| colors.
|__________________________________________________________________}
procedure DrawFrame (ComputerTurn: boolean);
var Row: integer;
Column: integer;
begin
{Clear screen with Black background.}
TextBackGround (BLACK);
TextColor (BLACK);
For Row:= 1 to 25 do
For Column := 1 to 80 do begin
if NOT ((Row = 25) and (Column = 80)) then
OutString (Column, Row, chr(219));
end; {for column}
if ComputerTurn = TRUE then
ColorDim
else
ColorFrame;
OutString (1,1,chr(201));
OutString (1,24,chr(200));
OutString (31,1,chr(203));
OutString (31,24,chr(202));
for Column := 2 to 30 do begin
OutString (Column,1,chr(205));
OutString (Column,24,chr(205));
end; {for}
For Row := 2 to 23 do begin
OutString (1,Row,chr(186));
OutString (31,Row,chr(186));
end; {for}
Outstring (1,18,chr(204));
Outstring (31,18,chr(185));
For Row := 2 to 30 do
OutString (Row,18,chr(205));
OutString (31,5,chr(204));
OutString (31,13,chr(204));
if ComputerTurn = TRUE then
ColorFrame
else
ColorDim;
For Column := 51 to 79 do begin
OutString (Column,1,chr(205));
OutString (Column,18,chr(205));
OutString (Column,24,chr(205));
end; {for}
For Row := 2 to 23 do begin
OutString (50,Row,chr(186));
OutString (80,Row,chr(186));
end; {for}
OutString (50,1,chr(203));
OutString (50,24,chr(202));
OutString (50,5,chr(185));
OutString (50,13,chr(185));
OutString (50,18,chr(204));
OutString (80,1,chr(187));
OutString (80,24,chr(188));
ColorFrame;
For Column := 32 to 49 do begin
OutString (Column,1,chr(205));
OutString (Column,5,chr(205));
OutString (Column,13,chr(205));
OutString (Column,24,chr(205));
end; {for}
TextColor (BLUE);
for Row := 2 to 4 do
for Column := 32 to 49 do
OutString (Column,Row,chr(219));
TextColor (WHITE);
TextBackground (BLUE);
OutString (34,2,'Spite & Malice');
OutString (34,3,'By Ben Arnoldy');
OutString (34,4,'& Raechel Kula');
end; {procedure DrawFrame}
{___________________________________________________________________
| DrawDiscards
| One of the procedures involved with the interface.
| This procedure sets up the discard portions of the screen.
|__________________________________________________________________}
procedure DrawDiscards (ComputerTurn:boolean);
var Counter: Pos_t;
begin
if ComputerTurn = TRUE then
ColorDim
else
ColorNormalText;
OutString (9,2,'Player Discard');
if ComputerTurn = TRUE then
ColorNormalText
else
ColorDim;
if (TwoPlayer = FALSE) then
OutString (58,2,'Computer Discard')
else if (TwoPlayer = TRUE) then
OutString (58,2,'Opponent Discard');
ColorPosition;
OutString (3,3,'H'+chr(26));
OutString (10,3,'I'+chr(26));
OutString (17,3,'J'+chr(26));
OutString (24,3,'K'+chr(26));
OutString (52,3,'P'+chr(26));
OutString (59,3,'Q'+chr(26));
OutString (66,3,'R'+chr(26));
OutString (73,3,'S'+chr(26));
for Counter := 1 to 14 do begin
if ComputerTurn = TRUE then
ColorDim
else
ColorCard;
OutString(6,2+Counter,
CardString (PlayerDiscardPile1.SeeRandom(Counter)));
OutString(13,2+Counter,
CardString (PlayerDiscardPile2.SeeRandom(Counter)));
OutString(20, 2+Counter,
CardString (PlayerDiscardPile3.SeeRandom(Counter)));
OutString(27, 2+Counter,
CardString (PlayerDiscardPile4.SeeRandom(Counter)));
if ComputerTurn = FALSE then
ColorDim
else
ColorCard;
OutString(55, 2+Counter,
CardString (ComputerDiscardPile1.SeeRandom(Counter)));
OutString(62, 2+Counter,
CardString (ComputerDiscardPile2.SeeRandom(Counter)));
OutString(69, 2+Counter,
CardString (ComputerDiscardPile3.SeeRandom(Counter)));
OutString(76, 2+Counter,
CardString (ComputerDiscardPile4.SeeRandom(Counter)));
end; {for}
{if there are too many cards in a discard pile to display...}
TextColor (LIGHTred);
TextBackground (BLACK);
for Counter := 1 to 4 do begin
if PosTable [7+Counter]^.NumCards > 14 then
OutString ((-2 + (Counter*7)),17,'more');
if PosTable [15+Counter]^.NumCards > 14 then
OutString ((44 + (Counter*7)),17,'more');
end; {for}
end; {procedure DrawDiscards}
{___________________________________________________________________
| DrawHands
| One of the procedures involved with the interface.
| This procedure displays the hands and scorepiles.
|__________________________________________________________________}
procedure DrawHands (ComputerTurn:boolean);
var CardFace: string;
begin
if ComputerTurn = TRUE then
ColorDim
else
ColorNormalText;
GotoXY (2,19);
write ('Player''s Hand:');
if ComputerTurn = FALSE then
ColorDim
else
ColorNormalText;
if (TwoPlayer = FALSE) then begin
GotoXY (51,19);
write ('Computer''s Hand:');
end
else if (TwoPlayer = TRUE) then begin
GotoXY (51,19);
write ('Opponent''s Hand:');
end;
ColorPosition;
OutString (3,21,'A'+chr(24));
OutString (8,21,'B'+chr(24));
OutString (13,21,'C'+chr(24));
OutString (18,21,'D'+chr(24));
OutString (23,21,'E'+chr(24));
OutString (28,21,'F'+chr(24));
OutString (52,21,'T'+chr(24));
OutString (57,21,'U'+chr(24));
OutString (62,21,'V'+chr(24));
OutString (67,21,'W'+chr(24));
OutString (72,21,'X'+chr(24));
OutString (77,21,'Y'+chr(24));
If ComputerTurn = TRUE then
ColorDim
else
ColorCard;
OutString(3,20,CardString (PlayerHand.SeeRandom(1)));
OutString(8,20,CardString (PlayerHand.SeeRandom(2)));
OutString(13,20,CardString (PlayerHand.SeeRandom(3)));
OutString(18,20,CardString (PlayerHand.SeeRandom(4)));
OutString(23,20,CardString (PlayerHand.SeeRandom(5)));
OutString(28,20,CardString (PlayerHand.SeeRandom(6)));
If ComputerTurn = FALSE then
ColorDim
else
ColorCard;
If TwoPlayer then begin
OutString(52,20,CardString (ComputerHand.SeeRandom(1)));
OutString(57,20,CardString (ComputerHand.SeeRandom(2)));
OutString(62,20,CardString (ComputerHand.SeeRandom(3)));
OutString(67,20,CardString (ComputerHand.SeeRandom(4)));
OutString(72,20,CardString (ComputerHand.SeeRandom(5)));
OutString(77,20,CardString (ComputerHand.SeeRandom(6)));
end {if}
else begin
CardFace := chr(168) + chr(63);
if ComputerHand.NumCards > 0 then
OutString(52,20,CardFace);
if ComputerHand.NumCards > 1 then
OutString(57,20,CardFace);
if ComputerHand.NumCards > 2 then
OutString(62,20,CardFace);
if ComputerHand.NumCards > 3 then
OutString(67,20,CardFace);
if ComputerHand.NumCards > 4 then
OutString(72,20,CardFace);
if ComputerHand.NumCards > 5 then
OutString(77,20,CardFace);
end; {if-else}
if ComputerTurn = TRUE then
ColorDim
else
ColorNormalText;
GotoXY (2,23);
write ('Score Pile: ', PlayerScorePile.NumCards,
' cards> ');
ColorPosition;
write('G'+chr(26));
TextColor (BLACK);
TextBackground (BLACK);
write(' ');
if ComputerTurn = TRUE then
ColorDim
else
ColorCard;
write (CardString (PlayerScorePile.SeeRandom(1)));
if ComputerTurn = FALSE then
ColorDim
else
ColorNormalText;
GotoXY (51,23);
write ('Score Pile: ', ComputerScorePile.NumCards,
' cards> ');
ColorPosition;
write('Z'+chr(26));
TextColor (BLACK);
TextBackground (BLACK);
write(' ');
if ComputerTurn = FALSE then
ColorDim
else
ColorCard;
write (CardString (ComputerScorePile.SeeRandom(1)));
end; {procedure DrawHands}
{___________________________________________________________________
| DrawAcePiles
| One of the procedures involved with the interface.
| This procedure draws the AcePile portion of the screen.
|__________________________________________________________________}
procedure DrawAcePiles;
var Counter: integer;
begin
ColorNormalText;
OutString (36,5,'Ace Piles:');
ColorPosition;
OutString (38,8,'L'+chr(26));
OutString (38,9,'M'+chr(26));
OutString (38,10,'N'+chr(26));
OutString (38,11,'O'+chr(26));
ColorCard;
for Counter := 1 to 4 do begin
OutString(41,7+Counter,CardString (TopCardTable [11+Counter] ));
if CardValue( TopCardTable [11+Counter] )=0 then
if AceTopCard (11+Counter) < 10 then
OutString(45,7+Counter,chr(AceTopCard (11+Counter) + 48))
else if AceTopCard (11+Counter) = 10 then
OutString(45,7+Counter,'10')
else if AceTopCard (11+Counter) = 11 then
OutString(45,7+Counter,'JA')
else if AceTopCard (11+Counter) = 12 then
OutString(45,7+Counter,'QU')
else if AceTopCard (11+Counter) = 13 then
OutString(45,7+Counter,'KI');
end; {for}
end; {Display}
{___________________________________________________________________
| DrawMessageBox
| One of the procedures involved with the interface.
| This procedure clears the message portion of the screen and
| prints a message displaying the turn.
|__________________________________________________________________}
procedure DrawMessageBox (ComputerTurn: boolean);
var
Column: integer;
Row: integer;
begin
TextColor (BLACK);
TextBackground (BLACK);
for Column := 32 to 49 do
for Row := 14 to 23 do
OutString (Column,Row,chr(219));
ColorNormalText;
if ((ComputerTurn = TRUE) AND (TwoPlayer = FALSE)) then begin
GotoXY (33,15);
write ('Computer''s Turn');
end
else if ((ComputerTurn = TRUE) AND (TwoPlayer = TRUE)) then begin
GotoXY (33,15);
write ('Opponent''s Turn');
end
else begin
GotoXY (34,15);
write ('Player''s Turn');
end;
end; {procedure DrawMessageBox}
{___________________________________________________________________
| Display
| This procedure directs the interface procedures for a complete
| redrawing of the screen.
|__________________________________________________________________}
procedure Display;
begin
clrscr;
DrawFrame (ComputerTurn);
DrawDiscards (ComputerTurn);
DrawHands (ComputerTurn);
DrawAcePiles;
DrawMessageBox (ComputerTurn);
end; {Display}
{___________________________________________________________________
| PickUpHand
| Picks up the required number of cards from the draw pile and
| places them in the hand of the person whose turn it is.
| This procedure also checks to see if the draw pile has run out
| of cards. If so the trash pile is placed in the draw pile and
| the draw pile is subsequently reshuffled.
|___________________________________________________________________}
Procedure PickupHand (var Hand : pile);
var numToGet, count, Counter : integer;
begin
If (Hand.NumCards > 3)Then
numToGet := 1
Else
numToGet := (5 - Hand.NumCards);
For count := 1 to numToGet Do begin
If DrawPile.NumCards = 0 then begin {Draw pile out of card, replenish}
For Counter := 1 to TrashPile.NumCards do
DrawPile.PutOnTop (TrashPile.RemoveFromTop);
DrawPile.RandomShuffle;
end; {if}
Hand.PutOnTop (DrawPile.RemoveFromTop);
end; {for}
end; {procedure PickupHand}
{____________________________________________________________________
| PickUpCards
| Sends correct hand to the PickupHand procedure according to
| whose turn it is.
|___________________________________________________________________}
Procedure PickupCards;
begin
If ComputerTurn Then
PickupHand (ComputerHand)
Else
PickupHand (PlayerHand);
InitTable; {Refresh the Top Card Table}
end; {PickupCards}
{____________________________________________________________________
| HouseKeeping
| Performs some checks after a card has been moved.
| These checks include: removing completed ace piles,
| checking for completed game, and checking for
| insufficient cards to discard.
|___________________________________________________________________}
procedure HouseKeeping;
var Counter: integer;
Counter2: integer;
begin
InitTable; {Keep current top card information updated.}
{Clean up any full ace piles.}
for Counter := 12 to 15 do
if PosTable [Counter]^.NumCards = 13 then
for Counter2 := 1 to 13 do
TrashPile.PutOnTop (PosTable [Counter]^.RemoveFromTop);
{Check for Game over.}
if ComputerScorePile.NumCards = 0 then
begin
Game := FALSE;
Discard := TRUE;
Winner := 'Computer';
end; {if}
if PlayerScorePile.NumCards = 0 then
begin
Game := FALSE;
Discard := TRUE;
Winner := 'Player';
end; {if}
{Run out of cards before discard.}
If ((Discard = FALSE) AND ComputerTurn AND
(ComputerHand.NumCards = 0)) then
PickUpCards;
If ((Discard = FALSE) AND (NOT ComputerTurn) AND
(PlayerHand.NumCards = 0)) then
PickUpCards;
end; {procedure HouseKeeping}
{____________________________________________________________________
| MoveCard
| Moves a card from one pile to another as specified.
|___________________________________________________________________}
Procedure MoveCard (From, Tto : integer);
var frompile : pilepointer_t; value: CardVal_t;
dummy: integer;
begin
if ((From < 7) Or ((From > 19) AND (From < 26))) then begin
frompile :=PosTable[From];
value := TopCardTable[From];
dummy := frompile^.DeleteByValue(value);
PosTable[Tto]^.PutOnTop(value);
end
else
PosTable[Tto]^.PutOnTop (PosTable[From]^.RemoveFromTop);
HouseKeeping; {Calls the HouseKeeping procedure}
end; {procedure MoveCard}
{____________________________________________________________________
| WhoseTurn
| This procedure changes the turns.
|___________________________________________________________________}
Procedure WhoseTurn (var ComputerTurn : boolean);
begin
If ComputerTurn Then
ComputerTurn := False
Else
ComputerTurn := True;
end; {WhoseTurn}
{____________________________________________________________________
| CheckMove
| Checks to see if the move proposed is a) valid, and
| b) a discard.
|___________________________________________________________________}
Procedure CheckMove(var From, Tto: integer);
var
TopCard: integer;
position: Pos_t;
Counter: Pos_t;
EmptyAcePile: boolean;
begin
InitTable;
Valid := TRUE;
Discard := FALSE;
MustMove := FALSE;
If TopCardTable [From] = NULL then
Valid := FALSE; {Invalid if moving from empty space.}
If (Valid AND ((Tto < 8) OR (Tto > 19))) then
Valid := FALSE;{Invalid if proposed to move card to ScorePiles or Hands}
If (Valid AND ComputerTurn AND ((Tto < 12) OR (From < 12))) then
Valid := FALSE; {Invalid if computer proposed to or from player's side.}
If (VALID AND (NOT ComputerTurn) AND ((Tto > 15) OR (From > 15))) then
Valid := FALSE; {Invalid if player proposed to or from computer's side.}
If (VALID AND ((From > 11) AND (From < 16))) then
Valid := FALSE; {Invalid if to Acepile from Acepile.}
if (VALID AND (((Tto > 7) AND (Tto < 12)) OR ((Tto > 15) AND (Tto < 20)))
AND (((From < 12) AND (From > 6)) OR ((From = 26) OR
((From > 15) AND (From < 20))))) then
Valid := FALSE; {Invalid if to discard from a discard or score pile.}
{Ace on top of Discard Pile must be played first.}
EmptyAcePile := FALSE;
for Counter := 1 to 4 do
if PosTable [Counter + 11]^.NumCards = 0 then
EmptyAcePile := TRUE;
if (EmptyAcePile AND Valid) then
for Counter := 1 to 4 do begin
if ((ComputerTurn) AND (CardValue (TopCardTable [Counter + 15]) = 1)
AND (From <> (Counter + 15))
AND (NOT(CardValue(TopCardTable[From])=1))) then
Valid := FALSE;
if ((NOT ComputerTurn) AND (CardValue (TopCardTable[Counter+7]) = 1)
AND (From <> (Counter + 7))
AND (NOT(CardValue(TopCardTable[From])=1))) then
Valid := FALSE;
end; {for}
if (EmptyAcePile AND Valid) then
for Counter := 1 to 4 do begin
if ((ComputerTurn) AND (CardValue (TopCardTable [Counter + 15]) = 1)
AND (From = (Counter + 15))
OR (CardValue(TopCardTable[From])=1)) then begin
Valid := True;
MustMove := True;
end; {if}
end; {for} {forces computer to play ace when
To/From scores below threshold}
{Ace Piles Check}
if (VALID AND ((Tto > 11) AND (Tto < 16))) then begin
TopCard := AceTopCard (Tto);
If ((TopCard = NULL) AND (CardValue (TopCardTable [From]) <> 1)) then
Valid := FALSE {If placing non-ace on empty ace pile.}
else if TopCard = NULL then
Valid := TRUE
else if CardValue(TopCardTable[From]) = 0 then
Valid := TRUE {In all cases but as ace, joker is valid.}
else if ((TopCard + 1) <> CardValue (TopCardTable[From])) then
Valid := FALSE; {If it is not next card in series.}
end; {if}
{Discard Check}
if (Valid AND ((ComputerTurn AND ((Tto < 20) AND (Tto > 15) AND (From > 19)
AND (From < 26))) OR (NOT ComputerTurn AND ((Tto < 12) AND (Tto > 7)
AND (From < 7) AND (From > 0))))) then
if PosTable [Tto]^.NumCards > 0 then begin
Discard := TRUE;
if ComputerTurn then
For Counter := 16 to 19 do
if PosTable [Counter]^.NumCards = 0 then begin
Valid := FALSE;
Discard := FALSE;
end; {if}
if NOT ComputerTurn then
For Counter := 8 to 11 do
if PosTable [Counter]^.NumCards = 0 then begin
Valid := FALSE;
Discard := FALSE;
end; {if}
end; {if}
end;{CheckMove}
{____________________________________________________________________
| GetMove
| Requested a proposal for a move from the player.
|___________________________________________________________________}
Procedure GetMove (var From, Tto: integer);
var FromChar, ToChar: char;
begin
Display;
ColorNormalText;
OutString (33,17,'Enter positions');
ColorDim;
OutString (35,18,'(@ to Quit)');
ColorNormalText;
OutString (33,19,'Move a card');
OutString (33,20,'from: ');
readln (FromChar);
OutString (33,21,'to: ');
readln (ToChar);
From := ord(UpCase(FromChar)) - 64;
Tto := ord(UpCase(ToChar)) - 64;
{-64 to adjust for alphabet's position in ASCII table.}
if ((From = 0) OR (Tto = 0)) then begin {quit}
ColorNormalText;
clrscr;
HALT;
end; {if}
if ((From < 1) OR (From > 26) OR (Tto < 1) OR (From > 26)) then begin
From := 1;
Tto := 1;
end; {if}
end; {GetMove}
{____________________________________________________________________
| ResultsofCheck
| Displays a message regarding the results of the check in
| CheckMove.
|___________________________________________________________________}
procedure ResultsofCheck;
begin
DrawMessageBox (ComputerTurn); {Calls the DrawMessageBox procedure}
ColorNormalText;
OutString (33,17,'Proposed Move:');
GotoXY (33,18);
write ('From: ',chr(From + 64));
GotoXY (33,19);
write ('To: ',chr(Tto + 64));
GotoXY (33,21);
if NOT Valid then begin
TextColor (WHITE+BLINK);
write ('Is NOT Valid!!');
end
else begin
TextColor (WHITE);
write ('Is Valid.');
end; {if else}
TextColor (RED+BLINK);
OutString (33,23,'Press <Enter>...');
readln;
end; {ResultsofCheck}
{_____________________________________________________________________
| PlayAgainBox
| Displays Box and asks player if he/she wants to play again
|_____________________________________________________________________}
procedure PlayAgainBox;
Begin
ColorNormalText;
clrscr;
DrawTitleBox;
ColorNormalText;
OutString (27, 11, 'Would you like to play again?');
OutString (37, 12, '(');
TextColor (LightRed);
OutString (38, 12, 'Y ');
TextColor (white);
OutString (40, 12, 'or ');
TextColor (lightRed);
OutString (43, 12, 'N');
TextColor (white);
OutString (44, 12, ')');
End;
{____________________________________________________________________
| GameOverDisplay
| Notifies player that the game is over, displays who won, and
| asks the player if he/she would like to play again.
|___________________________________________________________________}
Procedure GameOverDisplay (Winner: string);
var Response: char;
Valid: boolean;
begin
ColorNormalText;
clrscr;
DrawTitleBox;
ColorNormalText;
OutString (36, 10, 'Game Over!!');
OutString (32, 12, 'The ');
OutString (36, 12, Winner);
OutString (44, 12, ' wins!');
readln;
{Play Again?}
Valid := FALSE;
Repeat
PlayAgainBox;
readln (Response);
if (Upcase (Response) = 'Y') then begin
AnotherGame := TRUE;
Valid := TRUE;
end
else
if (Upcase (Response) = 'N') then begin
AnotherGame := FALSE;
Valid := TRUE;
end
else
Valid := FALSE;
Until Valid;
end; {function AnotherGame}
{___________________________________________________________________
| SetUp
| One of Decision's evaluative functions.
| This function adds a negative weight if a play will result in
| setting up the player to play from his/her score pile.
|__________________________________________________________________}
Function SetUp: integer;
const
WEIGHT = -20;
SWEIGHT =-10;
var
position: integer;
Points: integer;
CardCanPlay: integer;
ScoreCard: integer;
CardPlayed: integer;
begin
Points := 0;
ScoreCard := CardValue (TopCardTable [7]);
CardPlayed := AceTopCard (Tto) + 1;
CardCanPlay := CardPlayed + 1;
If CardCanPlay = ScoreCard then begin
Points := WEIGHT;
For position := 16 to 26 do begin
if CardValue (TopCardTable [position]) = ScoreCard then
Points := 0;
if position = From then
if CardValue (PosTable [position]^.SeeRandom(2)) = ScoreCard then
Points := 0;
end; {for}
end; {if}
If (Points = WEIGHT) AND (From = 26) then
Points := SWEIGHT;
SetUp := Points;
end; {function SetUp}
{___________________________________________________________________
| Block
| One of Decision's evaluative functions.
| This function adds a positive weight if the play results in
| preventing the player from playing from his score pile.
|__________________________________________________________________}
function Block: integer;
const
WEIGHT = 25;
var
Points: integer;
ScoreCard: integer;
CardPlayed: integer;
begin
Points := 0;
ScoreCard := CardValue (TopCardTable [7]);
CardPlayed := AceTopCard (Tto) + 1;
If CardPlayed = ScoreCard then
Points := WEIGHT;
Block := points;
end; {Block}
{___________________________________________________________________
| PlayMore
| One of Decision's evaluative functions.
| This function adds a positive weight if a play results in the
| computer being able to play more cards.
| It also adds a positive weight if a play allows the computer to
| move a card.
|___________________________________________________________________}
function PlayMore: integer;
const
WEIGHT = 15; {If move allows the computer to move more cards.}
WEIGHT2 = 10; {If Computer can move a card.}
var
position: integer;
Points: integer;
CardCanPlay: integer;
CardPlayed: integer;
begin
Points := WEIGHT2; {Just for being able to play a card.}
CardPlayed := AceTopCard (Tto) + 1;
CardCanPlay := CardPlayed + 1;
position := 16;
While (Position < 27) do begin
if CardValue (TopCardTable [position]) = CardCanPlay then
Points := WEIGHT;
if position = From then
if CardValue(PosTable [position]^.SeeRandom (2)) = CardCanPlay then
Points := WEIGHT;
position := position + 1;
end; {While}
{Special case for Jokers}
If CardValue (TopCardTable [From]) = 0 then
Points := Points - WEIGHT;
PlayMore := Points;
end; {function PlayMore}
{____________________________________________________________________
| MoreCards
| One of Decision's evaluative functions
| This function adds weight to a play that will result in the
| computer being able to pick up more cards at the beginning of
| its next turn. Additional weight is given to a play that will
| result in the computer being able to pick up 5 more cards this
| turn.
|____________________________________________________________________}
function MoreCards: integer;
const WEIGHT = 10;
WEIGHT2 = 20;
var HolestoFill: integer;
Counter: integer;
Points: integer;
begin
Points := 0;
{creates empty discard pile, ie a hole to fill}
If ((From >15) AND (From <20) AND (PosTable [From]^.NumCards = 1) AND
(NOT CardValue(TopCardTable [From]) = 0)) then
Points := WEIGHT;
{takes into account the holes}
HolestoFill := 0;
If ((From > 19) AND (From < 26 )) then begin
Points := WEIGHT;
For Counter := 16 to 19 do begin
If PosTable [Counter]^.NumCards = 0 then
HolestoFill := HolestoFill + 1;
end; {for}
If (ComputerHand.NumCards - HolestoFill) = 0 then
Points := WEIGHT2;
{special case for Jokers}
If CardValue (TopCardTable [From]) = 0 then
Points := Points - WEIGHT;
end; {if}
MoreCards := Points;
end; {MoreCards}
{_____________________________________________________________________
| HelpScore
| One of Decision's evaluative functions
| This function will add positive weight to a play that results
| in the computer being able to play from its score pile.
|____________________________________________________________________}
function HelpScore: integer;
const WEIGHT = 30;
var ScoreCard: integer;
CardPlayed: integer;
CardCanPlay: integer;
Points: integer;
begin
Points := 0;
ScoreCard := CardValue (TopCardTable [26]);
CardPlayed := AceTopCard (Tto) + 1;
CardCanPlay := CardPlayed + 1;
If CardCanPlay = ScoreCard then
Points := WEIGHT;
HelpScore := Points;
end; {function HelpScore}
{_____________________________________________________________________
| Score
| One of Decision's evaluative functions.
| This function adds positive weight to a score pile play.
|____________________________________________________________________}
function Score: integer;
const WEIGHT = 60;
WEIGHT2 = 10;
var ScoreCard: integer;
position: integer;
Points: integer;
Begin
Points := 0;
if From = 26 then begin
ScoreCard := CardValue (TopCardTable [26]);
if (((AceTopCard (Tto) + 1) = ScoreCard) OR (ScoreCard = 0)) then begin
Points := WEIGHT;
if ((ScoreCard + 1) = CardValue (TopCardTable [7])) then begin
Points := WEIGHT2;
position := 16;
while (position < 26) do begin
position := position + 1;
if ((TopCardTable [position] = 0) OR
(TopCardTable [position] = (ScoreCard +1))) then
Points := WEIGHT;
end; {While}
end; {if}
end; {if}
end; {if}
Score := Points;
end; {function Score}
{_____________________________________________________________________
| SameScore
| One of DiscardDecision's evaluative functions
| This function adds a negative weight to a discard
| of a card that is the same value as the computer's score
| pile.
|____________________________________________________________________}
function SameScore: integer;
const WEIGHT = -5;
JWEIGHT = -20;
var Points: integer;
begin
Points := 0;
If (CardValue(TopCardTable[From]) = CardValue (TopCardTable[26])) then
Points := WEIGHT;
{special case for Jokers}
If CardValue (TopCardTable[From]) = 0 then
Points := JWEIGHT;
SameScore := Points;
end; {function SameScore}
{_____________________________________________________________________
| Order
| One of DecisionDiscard's evaluative functions
| This function uses weights to prioritize a discard to the closest
| possible lower value in relation to the top cards of the discard
| piles.
|____________________________________________________________________}
function Order: integer;
const WEIGHT1 = 20;
WEIGHT2 = 11;
WEIGHT3 = 4;
WEIGHT4 = -5;
JWEIGHT = -20;
var next: CardVal_t;
Points: integer;
begin
next := CardValue (TopCardTable [Tto]) - 1;
if (CardValue (TopCardTable [From]) = next)
then Points := WEIGHT1;
if ((CardValue (TopCardTable [From]) + 1) = next)
then Points := WEIGHT2;
if ((CardValue (TopCardTable[From]) + 1) < next)
then Points := WEIGHT3;
if (CardValue (TopCardTable [From]) > next)
then Points := WEIGHT4;
{special case for Jokers}
if CardValue (TopCardTable [From]) = 0 then
Points := JWEIGHT;
Order := Points;
end; {Order}
{_____________________________________________________________________
| HighCard
| One of DecisionDiscard's evaluative functions.
| This function weights the possible cards to fill in a space
| in the discard piles. It adds most weight to the highest
| valued card.
|____________________________________________________________________}
function HighCard: integer;
var count, Points: integer;
begin
Points := 0;
if ((PosTable [16]^.NumCards = 0) OR (PosTable [17]^.NumCards = 0) OR
(PosTable [18]^.NumCards = 0) OR (PosTable [19]^.NumCards = 0)) then
for count := 20 to 25 do
if (CardValue(TopCardTable [From]) >
CardValue (TopCardTable [count])) then
Points := Points + 1;
HighCard := Points * 2;
end; {function HighCard}
{_____________________________________________________________________
| DiscardDecision
| This procedure is responsible for applying the various weights
| on to the decision surrounding the computer's discard.
|____________________________________________________________________}
Procedure DiscardDecision (var From, Tto: integer);
var max: integer;
f, t: integer;
Begin
For f := 20 to 25 Do
For t := 16 to 19 Do begin
From := f;
Tto := t;
CheckMove (From, Tto);
If Not (Valid) Then
ChoiceRate[f, t] := -10000
Else
ChoiceRate[f, t] := ((HighCard) + (Order) + (SameScore));
end; {for}
From := 20;
Tto := 16;
max := 0;
For f := 20 to 25 Do
For t := 16 to 19 Do begin
If (ChoiceRate[f, t] > ChoiceRate[From, Tto]) Then begin
max := ChoiceRate[f, t];
From := f;
Tto := t;
end; {if}
end; {for}
End; {DiscardDecision}
{_____________________________________________________________________
| Decision
| This procedure is responsible for applying the weights to the
| decision surrounding the computer's choice of moves.
|____________________________________________________________________}
Procedure Decision (var From, Tto: integer);
const Threshold = 10;
var Max: integer;
f, t: integer;
Begin
Display;
For f := 1 to 26 do
For t := 1 to 19 do
ChoiceRate [f, t] := 0;
For f := 16 to 26 Do
For t := 12 to 15 Do begin
From := f;
Tto := t;
CheckMove(From, Tto);
If Not (Valid) Then
ChoiceRate[f, t] := -10000
Else
ChoiceRate[f, t] := ((SetUp) + (Block) +
(PlayMore) + (MoreCards) + (HelpScore) + (Score));
end; {for}
{Tests Threshold}
From := 16;
Tto := 12;
max := 0;
For f := 16 to 26 Do
For t := 12 to 15 Do begin
If (ChoiceRate[f, t] > ChoiceRate[From, Tto]) Then begin
max := ChoiceRate[f, t];
From := f;
Tto := t;
end; {if}
end; {for}
If (Max < Threshold) AND (NOT(MustMove)) Then
DiscardDecision (From, Tto);
End; {Decision}
{============================================================================
MAIN PROGRAM
============================================================================}
BEGIN {Main Program}
Repeat
TitleScreen (TwoPlayer);
Initialize;
Deal;
While (Game) Do begin
WhoseTurn (ComputerTurn);
PickupCards;
Repeat
If ((ComputerTurn) AND (NOT TwoPlayer)) Then
Decision (From, Tto)
Else
GetMove (From, Tto);
CheckMove(From, Tto);
ResultsofCheck;
If Valid then
MoveCard (From, Tto);
Until (Discard);
End; {While Loop}
GameOverDisplay (Winner);
Until (NOT AnotherGame);
END. {Main Program}
[Back to MISC SWAG index] [Back to Main SWAG index] [Original]