home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload
/
ShartewareOverload.cdr
/
games
/
tbridge.zip
/
PLAY.BR
< prev
next >
Wrap
Text File
|
1986-06-01
|
41KB
|
1,296 lines
{ ╔══════════════════════════════════════════════════════╗
║ PLAY.BR Module of BRIDGE.PAS ║ ║
║ ║
║ Last modified 10/29/85 ║
║ ║
║ Plays the cards for the computer or gets plays ║
║ from the player and updates playing information. ║
╚══════════════════════════════════════════════════════╝
}
function findHigh(Hand: HandType; s: SuitType): CardNoType;
{ Find Highest Card }
var
High: CardNoType;
begin
High := 0;
while (Sdist[Hand,High].Suit <> s) or
Sdist[Hand,High].Played do
High := High+1;
findHigh := High;
end; { findHigh }
function findLow(Hand: HandType; s: SuitType): CardNoType;
{ Find Lowest Card }
var
Low: CardNoType;
begin
Low := 12;
while (Sdist[Hand, Low].Suit <> s) or
Sdist[Hand, Low].Played do
Low := Low-1;
findLow := Low;
end; { findLow }
type
ExpandValueType = -1..15;
function Highest(hand4: integer; s: SuitType): ExpandValueType;
{ Return Value of Highest Card }
var
Hand: HandType;
begin
Hand := hand4 and 3;
if Sdata[Hand].l[s] = 0 then
Highest := -1
else
Highest := Sdist[Hand,findHigh(Hand,s)].Value;
end; { Highest }
function Lowest(hand4: integer; s: SuitType): ExpandValueType;
{ Return Value of Lowest Card }
var
Hand : HandType;
begin
Hand := hand4 and 3;
if Sdata[Hand].l[s] = 0 then
Lowest := Ace + 1
else
Lowest := Sdist[Hand,findLow(Hand,s)].Value;
end; { Lowest }
function Highmax(hand4: integer; s: SuitType;
MaxVal: ExpandValueType): ExpandValueType;
{ Return Value of the Highest Card, which is
lower or equal to MaxVal }
var
Hand: HandType;
No: CardNoType;
begin
Hand:=hand4 and 3;
Highmax:=-1;
for No:=0 to 12 do
if not Sdist[Hand,No].Played then
if (Sdist[Hand,No].Suit=s) then
if (Sdist[Hand,No].Value<=MaxVal) then
begin
Highmax:=Sdist[Hand,No].Value;
Exit;
end;
end; { Highmax }
procedure PlayCard(Hand: HandType; No: CardNoType);
{ Plays the Card and updates Game, Sdist, Sdata, Sim and TrickNo }
begin
with Sdist[Hand,No],Sim do
begin
Played := true;
with Sdata[Hand] do
l[Suit] := l[Suit]-1;
Game[Round].Hand := Hand;
Game[Round].No := No;
if Round and 3 = 0 then
begin
LeadSuit := Suit; { Lead }
BestCard := Sdist[Hand,No];
BestHand := Hand;
end
else
if (Suit = BestCard.Suit) and (Value > BestCard.Value) or
(Suit <> BestCard.Suit) and (Suit = Contract.Trump) then
begin
BestCard := Sdist[Hand,No]; { Best Card }
BestHand := Hand;
end;
Round := Round+1;
if Round and 3 = 0 then
begin
if not odd(BestHand+Dummy) then
WonTricks := WonTricks+1;
LeadHand := BestHand; TrickNo := TrickNo+1;
end;
PlayingHand := (LeadHand+Round) and 3;
end; { with }
end; { PlayCard }
procedure ResetTrick;
{ Reestablishes the situation in Sim, Sdist, Sdata and TrickNo
one trick earlier (inverts 4 calls of PlayCard) }
var
Cnt: 0..3;
begin
with Sim do
begin
if not odd(LeadHand+Dummy) then
WonTricks := WonTricks-1;
for Cnt := 3 downto 0 do
begin
Round := Round-1;
with Game[Round],Sdist[Hand,No] do
begin
Played := false;
with Sdata[Hand] do l[Suit] := l[Suit]+1;
end;
end;
with Game[Round] do
begin
LeadHand := Hand;
PlayingHand := LeadHand;
LeadSuit := Sdist[Hand,No].Suit;
end;
TrickNo := TrickNo-1;
end;
end; { ResetTrick }
procedure TestSuit(PlayingHand: HandType; s: SuitType;
var TopTricks: integer;
var winning: boolean);
{ TopTricks is the Number of TopTricks in the Suit for PlayingHand.
winning is true if All cards in the Suit are winners }
var
MaxVal : ExpandValueType; { Highest Card }
HighHand : HandType; { Hand with Highest Card }
OpponentVal : ExpandValueType; { Opponents Highest Card }
Highval : array[HandType] of { Table of Highest cards }
ExpandValueType;
h : HandType;
i : CardNoType;
Len : LengthType;
begin
CheckKBD;
TopTricks := 0;
winning := false;
MaxVal := -1;
for h := North to West do
begin
Highval[h] := Highest(h,s); { Find Highest Card }
if MaxVal < Highval[h] then
begin
MaxVal := Highval[h];
HighHand := h;
end;
end;
if MaxVal >= 0 then
if not odd(HighHand+PlayingHand) then
begin
{ Find opponents Highest Card }
OpponentVal := Max(Highval[(HighHand+1) and 3],
Highval[(HighHand-1) and 3]);
for i := 0 to 12 do with Sdist[HighHand,i] do { Count TopTricks }
if not Played and (Suit = s) and (Value > OpponentVal) then
TopTricks := TopTricks+1;
for i := 0 to 12 do
with Sdist[(HighHand+2) and 3,i] do
if not Played and (Suit = s) and (Value > OpponentVal) then
TopTricks := TopTricks+1;
Len := Max(Sdata[HighHand].l[s], Sdata[(HighHand+2) and 3].l[s]);
TopTricks := Min(TopTricks,Len);
{ The Suit is winning if PlayingHand can take All Tricks
from Top }
winning := TopTricks >= Max(Sdata[(HighHand+1) and 3].l[s],
Sdata[(HighHand-1) and 3].l[s]);
if winning then TopTricks := Len;
end;
end; { TestSuit }
function TopTrick(PlayingHand: HandType; s: SuitType): integer;
{ Returns the Number of TopTricks for the side.
A negative Number means that the opponents has TopTricks.
The Number is calculated by using TestSuit }
var
Top : integer;
winning : boolean;
begin
TestSuit(PlayingHand,s,Top,winning);
if Top = 0 then
begin
TestSuit((PlayingHand+1) and 3,s,Top,winning);
Top := -Top;
end;
TopTrick := Top;
end; { TopTrick }
{ Contains the different lead Suits used in the search }
var
Count : array[0..13] of record
{ Sorted table of Suits }
Suits : array[1..4] of SuitType;
{ Evaluation of Suits }
Evaluation : array[SuitType] of integer;
{ Counter for Suit table }
Cnt : 0..4;
end;
type
ExpandCardNoType = -1..12;
function SelectLead: ExpandCardNoType;
{ Selects a lead in the position.
The function will return a new suggestion for a lead
every time it is called (-1 means No more suggestions).
The function uses the record Count[TrickNo]
(suggestion Number Cnt is in the Suit Suits[Cnt])
All calculations are performed in the Sim record }
function SelectSuit(Number: integer): SuitType;
{ Selects the Suit in which the lead should be Played.
Number is the suggestion Number.
The Suits and the evaluations are placed in Count[TrickNo].
All calculations are performed in the Sim records }
procedure SortSuits;
{ Sort Suits in Count }
var
t1,t2 : 1..4;
Suit : SuitType;
begin
with Count[TrickNo] do
for t1 := 1 to 3 do for t2 := t1+1 to 4 do
if Evaluation[Suits[t1]] < Evaluation[Suits[t2]] then
begin
Suit := Suits[t2];
Suits[t2] := Suits[t1];
Suits[t1] := Suit;
end;
end; { SortSuits }
function DeclarerLeadEvalu(s: SuitType): integer;
{ Evaluate the Suit as lead from declarer or Dummy }
var
Evalu : integer;
Short : HandType;
ShortLen : LengthType;
Val : integer;
begin
CheckKBD;
with Sim,Sdata[PlayingHand],Contract do
begin
Evalu := 0;
if s = Trump then
begin
{ Draw Trump until the opponents have No more }
if (Sdata[(PlayingHand+1) and 3].l[Trump] > 0) or
(Sdata[(PlayingHand-1) and 3].l[Trump] > 0) then
Evalu := 200;
end
else
if Trump <> NT then
begin
{ Try to establish a Ruff trick }
Short := (PlayingHand + 2) and 3;
if Sdata[Short].l[s] > l[s] then
Short := PlayingHand;
ShortLen := Sdata[Short].l[s];
Val := Sdata[(Short+2) and 3].l[s]-2*ShortLen;
if (Val > 0) and (Sdata[Short].l[Trump] > 0) then
begin
with Sdata[(Short+1) and 3] do
if (l[s] <= ShortLen) and (l[Trump] > 0) then
Val := 0;
with Sdata[(Short-1) and 3] do
if (l[s] <= ShortLen) and (l[Trump] > 0) then
Val := 0;
if Val > 0 then
Evalu := 200+Val;
end;
end; { if }
DeclarerLeadEvalu := Evalu;
end;
end; { DeclarerLeadEvalu }
function OpponentLeadEvalu(s: SuitType): integer;
{ Evaluate the Suit as lead from Opponent to declarer }
var
Evalu : integer;
RuffRisk : boolean;
TopTricks : integer;
winning : boolean;
begin
CheckKBD;
with Sim,Sdata[PlayingHand],Contract do
begin
Evalu := 0;
RuffRisk := false;
if (Trump <> NT) and (s <> Trump) then
begin
{ Check if declarer or Dummy can Ruff Suit }
with Sdata[(PlayingHand+1) and 3] do
if (l[s] = 0) and (l[Trump] > 0) then
RuffRisk := true;
with Sdata[(PlayingHand-1) and 3] do
if (l[s] = 0) and (l[Trump] > 0) then
RuffRisk := true;
end;
if not RuffRisk then
begin
TestSuit(PlayingHand,s,TopTricks,winning);
if TopTricks > 0 then
begin
Evalu := 200+TopTricks; { Take TopTricks }
if winning then
Evalu := Evalu+4;
end
else
if Trump <> NT then
begin
{ Try to establish a Ruff trick }
with Sdata[PlayingHand] do
if (l[s] <= 1) and (l[Trump] > 0) then
Evalu := 200;
with Sdata[(PlayingHand+2) and 3] do
if (l[s] <= 1) and (l[Trump] > 0) then
Evalu := 200;
end;
end;
OpponentLeadEvalu := Evalu;
end; { with }
CheckKBD;
end; { OpponentLeadEvalu }
function SuitEvalu(s: SuitType): integer;
{ Evaluate the strength of the Suit }
var
Evalu : integer;
TopTricks : integer;
winning : boolean;
m,n : integer;
begin
CheckKBD;
with Sim,Sdata[PlayingHand],Contract do
begin
if s = Trump then
Evalu := 100 { Play Trump }
else
begin
m := Sdata[North].l[s]+Sdata[South].l[s]; { Play best Suit }
n := Sdata[East ].l[s]+Sdata[West ].l[s];
if not odd(PlayingHand) then
Evalu := 96+m-2*n
else
Evalu := 96+n-2*m;
if not odd(PlayingHand+Dummy) then
begin
Evalu := Evalu+24;
TestSuit(PlayingHand,s,TopTricks,winning);
if TopTricks > 0 then
begin
Evalu := 128+TopTricks; { Take TopTricks }
if winning then
Evalu := Evalu+4;
end;
end;
end;
SuitEvalu := Evalu;
end;
end; { SuitEvalu }
var
Lastlead : TrumpType; { The Suit which was last lead by the side }
LastNo : integer; { The trick Number of last lead by the side }
s : SuitType;
Evalu : integer;
i : integer;
label 10;
begin
CheckKBD;
with Sim,Sdata[PlayingHand],Count[TrickNo] do
begin
{ When the procedure is called for the first suggestion,
All Suits are evaluated, sorted and stored in the record
Count[TrickNo]. Suggestion Number Number is then simply
the Suit Suits[Number] }
if Number = 1 then
begin
{ Find Suit of last lead by this side }
Lastlead := NT;
for i := FirstNo to TrickNo-1 do with Game[i*4] do
if not odd(PlayingHand+Hand) then
begin
Lastlead := Sdist[Hand,No].Suit;
LastNo := i;
end;
for s := Club to Spade do
begin
if l[s] = 0 then { Evaluate each Suit }
Evalu := -1000
else
begin
if not odd(PlayingHand+Dummy) then { Most important rules }
Evalu := DeclarerLeadEvalu(s)
else
Evalu := OpponentLeadEvalu(s);
if s = Lastlead then { Continue playing same Suit as in last lead }
Evalu := Max(Evalu+40,Count[LastNo].Evaluation[Lastlead]);
if Evalu = 0 then { Second most important rules }
Evalu := SuitEvalu(s);
end;
Evaluation[s] := Evalu;
Suits[Ord(s)+1] := s;
end;
SortSuits; { Sort Suits }
end;
SelectSuit := Suits[Number]; { Return suggested Suit }
end { with };
CheckKBD;
end; { SelectSuit }
function SuitTreatment(CardSuit: SuitType): CardNoType;
{ Decides which Card in CardSuit should be Played }
var
Low : boolean; { program plays Lowest Card in CardSuit }
Highval, { Players Highest Card }
PartnerVal : ExpandValueType; { Partners Highest Card }
begin
CheckKBD;
with Sim,Sdata[PlayingHand] do
begin
Low := true; { Play Low normally }
if l[CardSuit] > 1 then
begin
{ Play High if both opponents have singletons }
if (Sdata[(PlayingHand+1) and 3].l[CardSuit] <= 1) and
(Sdata[(PlayingHand-1) and 3].l[CardSuit] <= 1) then
Low := false
else
begin
Highval := Highest(PlayingHand ,CardSuit);
PartnerVal := Highest(PlayingHand+2,CardSuit);
if PartnerVal < Highval then
begin
{ Play High if Partner cannot take trick }
if (Highmax(PlayingHand+1,CardSuit,Highval) > PartnerVal) or
(Highmax(PlayingHand-1,CardSuit,Highval) > PartnerVal) then
Low := false;
end
else
{ Play High to make a finesse }
if (Sdata[(PlayingHand+2) and 3].l[CardSuit] >= 2) and
(Sdata[(PlayingHand+1) and 3].l[CardSuit] >= 3) then
if Highest(PlayingHand+1,CardSuit) = PartnerVal-1 then
if Highest(PlayingHand-1,CardSuit) > Highval then
Low := false;
if not Low then
begin
{ Play Low if the Opponent has Highest Card singleton }
if Sdata[(PlayingHand+1) and 3].l[CardSuit] = 1 then
if Highest(PlayingHand+1,CardSuit) > Highval then
Low := true;
if Sdata[(PlayingHand-1) and 3].l[CardSuit] = 1 then
if Highest(PlayingHand-1,CardSuit) > Highval then
Low := true;
end; { if }
end; { else }
end; { if }
if Low then
SuitTreatment := findLow(PlayingHand,CardSuit)
else
SuitTreatment := findHigh(PlayingHand,CardSuit);
end { with };
CheckKBD;
end; { SuitTreatment }
var
CardSuit: SuitType;
begin { SelectLead }
with Count[TrickNo] do
{ Decide if any more suggestions should be made, and
calculate eventually next suggestion }
if Cnt >= 2 then
SelectLead := -1
else
begin
Cnt := Cnt+1;
CardSuit := SelectSuit(Cnt);
if (Cnt > 1) and (Evaluation[Suits[1]]-
Evaluation[CardSuit] >= BranchValue) then
SelectLead := -1
else
SelectLead := SuitTreatment(CardSuit);
end;
end; { SelectLead }
function DiscardCard: CardNoType;
{ Find the Card with Lowest Value }
var
CardSuit : SuitType; { Chosen Suit }
Minval, { Minimal Card Value }
Evalu : integer; { Card Value }
Hold : boolean; { Hold opponents Suit }
Highval,
LowVal,
OpponentVal,
Val : ExpandValueType;
s : SuitType;
Hand : HandType;
top0,top1 : integer;
TopTricks : integer;
winning : boolean;
OwnVal,
OppVal,
v : integer;
function Trickval(Top: integer): integer;
{ Calculate Value of TopTricks.
OwnVal is Value of a Player trick.
OppVal is Value of an Opponent trick }
begin
if Top >= 0 then
Trickval := Top*OwnVal
else
Trickval := Top*OppVal;
end; { Trickval }
begin
CheckKBD;
with Sim,Sdata[PlayingHand],Contract do
begin
Minval := MaxInt;
for s := Club to Spade do
if l[s] > 0 then
begin
if s = Trump then { Evaluate the importance of each of the Suits }
Evalu := 500 { do not discard Trump }
else
begin
LowVal := Lowest(PlayingHand,s); { do not discard High Card }
if LowVal > 10 then
Evalu := 8+LowVal
else
begin
{ Penalty for leaving High Card unprotected.
Otherwise Hold the longest Suit }
Highval := Highest(PlayingHand,s);
if (Highval > 10) and (Highval <> Ace) and
(l[s] <= Ace+1-Highval) then
Evalu := Highval
else
Evalu := l[s];
if odd(PlayingHand+Dummy) then { if Player have No more trumps,
then discard longest Suit }
if Trump <> NT then
if l[Trump] = 0 then
Evalu := -l[s];
end;
Hold := false; { Hold opponents Suit unless the Player has
trumps or Partner leads next trick }
if odd(PlayingHand+Dummy) or (Trump = NT) then
begin
Hold := odd(PlayingHand+BestHand);
with BestCard do
if Suit = LeadSuit then
Val := Value
else
Val := Ace+1;
Hand := (PlayingHand+1) and 3;
while Hand <> LeadHand do
begin
OpponentVal := Highest(Hand,LeadSuit);
if (OpponentVal < 0) and (Trump <> NT) then
if Sdata[Hand].l[Trump] > 0 then
OpponentVal := Ace+1;
if Val <= OpponentVal then
begin
Val := OpponentVal;
Hold := odd(PlayingHand+Hand);
end;
Hand := (Hand+1) and 3;
end;
end;
top1 := TopTrick(PlayingHand,s);
{ TOP1 is the present Number of TopTricks for side.
TOP0 is the Number of TopTricks if PlayingHand
discards a Card in the Suit }
with Sdist[PlayingHand,findHigh(PlayingHand,s)],
Sdata[PlayingHand] do
begin
Played := true;
l[s] := l[s]-1;
top0 := TopTrick(PlayingHand,s);
Played := false; l[s] := l[s]+1;
end;
OwnVal := 40; { Evaluate the importance of the lost TopTricks }
OppVal := 20;
if (Trump <> NT) and
((top1 > 0) = odd(PlayingHand+Dummy)) then
if (abs(top1) > Sdata[(Dummy+1) and 3].l[s]) or
(abs(top1) > Sdata[(Dummy-1) and 3].l[s]) then
OppVal := 8;
if Hold then
begin
v := OppVal;
OppVal := OwnVal;
OwnVal := v;
end;
Evalu := Evalu+(Trickval(top1)-Trickval(top0));
end;
if Evalu < Minval then
begin
Minval := Evalu;
CardSuit := s;
end;
end { for Suit };
DiscardCard := findLow(PlayingHand,CardSuit);
{ Discard Lowest Card in the chosen Suit }
end { with };
CheckKBD;
end { DiscardCard };
function SelectCard: CardNoType;
{ Selects a Card in the position.
The procedure does not handle leads in the search
(this is Done by SelectLead).
The procedure can only be called once, and gives thus
only one suggestion (in contrary to SelectLead).
All calculations are performed in the Sim records }
function FollowSuit: CardNoType;
{ Follow Suit and play a Card in the lead Suit }
var
Low : boolean; { program plays Lowest Card in CardSuit }
findLower : boolean; { program plays Lowest Card,
which is higher than OpponentVal }
OpponentVal, { Opponents Highest Card }
Highval, { Players Highest Card }
PartnerVal : ExpandValueType; { Partners Highest Card }
TopTricks : integer;
winning : boolean;
No : CardNoType;
begin
CheckKBD;
with Sim,Sdata[PlayingHand] do
begin
Low := true;
if (BestCard.Suit = LeadSuit) and (l[LeadSuit] > 1) then
begin
Highval := Highest(PlayingHand,LeadSuit);
if BestCard.Value <= Highval then
{ It is possible to play the Highest Card }
case Round and 3+1 of
2 : begin { 2nd Hand }
{ Play Low if Partner can take trick, else
play High if it will get the trick, else
play High if it will press the Opponent, else
play Low in 2nd Hand }
OpponentVal := Max(Highest(PlayingHand+1,LeadSuit),
BestCard.Value);
PartnerVal := Highest(PlayingHand+2,LeadSuit);
Low := (PartnerVal > OpponentVal)
or (OpponentVal > Highval)
and ((PartnerVal > BestCard.Value) or
(Sdata[(PlayingHand+1) and 3].l[LeadSuit] = 1));
findLower := (Round <= Rel.Round+2)
and (Highval > OpponentVal);
end;
3: begin { 3rd Hand }
{ Play Low if Partner is sure to win trick }
OpponentVal := Highest(PlayingHand+1,LeadSuit);
Low := not odd(BestHand+PlayingHand) and
(OpponentVal < BestCard.Value);
if not Low then
begin
findLower := true; { Play High in 3rd Hand }
OpponentVal := Highmax(PlayingHand+1,LeadSuit,Highval);
if OpponentVal < BestCard.Value then
if odd(BestHand+PlayingHand) then
OpponentVal := BestCard.Value
else
Low := true;
end;
end;
4: begin { 4th Hand }
{ Get trick unless Partner has it }
if odd(BestHand+PlayingHand) then
begin
Low := false;
findLower := true;
OpponentVal := BestCard.Value;
end;
end;
end { case };
end; { if }
if Low then
FollowSuit := findLow(PlayingHand, LeadSuit)
else
begin
FollowSuit := findHigh(PlayingHand, LeadSuit);
if findLower then
for No := 0 to 12 do
with Sdist[PlayingHand,No] do
if not Played and
(Suit = LeadSuit) and (Value > OpponentVal) then
FollowSuit := No;
end;
end { with };
CheckKBD;
end { FollowSuit };
function SelectRuff: ExpandCardNoType;
{ Check whether and with which trumph
the trick should be ruffed }
var
Ruff : boolean; { Ruff the trick }
Low : boolean; { program plays Lowest Card in CardSuit }
findLower : boolean; { program plays Lowest Card,
which is higher than OpponentVal }
OpponentVal : ExpandValueType; { Opponents Highest Trump }
No : CardNoType;
begin
with Sim,Sdata[PlayingHand],Contract do
begin
if Trump = NT then
Ruff := false
else
Ruff := (Sdata[PlayingHand].l[Trump] > 0)
and ((BestCard.Suit <> Trump) or
(Highest(PlayingHand,Trump) > BestCard.Value));
if Ruff then
begin
{ Ruff if it gets the trick }
case Round and 3+1 of
2 : Ruff := Highest(PlayingHand+2,LeadSuit) <=
Max(Highest(PlayingHand+1,LeadSuit),BestCard.Value);
3 : Ruff := odd(PlayingHand+BestHand) or
(BestCard.Suit = LeadSuit) and
(Highest(PlayingHand+1,LeadSuit) > BestCard.Value);
4 : Ruff := odd(PlayingHand+BestHand);
end { case };
if Ruff then
begin
Low := true;
with BestCard do
if Suit = Trump then
if Highest(PlayingHand,Trump) > Value then
begin
Low := false;
findLower := true;
OpponentVal := Value;
end
else
Ruff := false;
end;
end;
if not Ruff then
SelectRuff := -1
else
if Low then
SelectRuff := findLow(PlayingHand,Trump)
else
begin
SelectRuff := findHigh(PlayingHand,Trump);
if findLower then
for No := 0 to 12 do
with Sdist[PlayingHand,No] do
if not Played and (Suit = Trump)
and (Value > OpponentVal) then
SelectRuff := No;
end;
end { with };
end { SelecTrump };
var
CardNo: ExpandCardNoType;
begin { SelectCard }
with Sim,Sdata[PlayingHand] do
if Round and 3 = 0 then
begin
{ Find lead by calling SelectLead
(must not be used in the search) }
Count[TrickNo].Cnt := 0; FirstNo := TrickNo;
SelectCard := SelectLead;
end
else
begin
if l[LeadSuit] > 0 then
{ Follow Suit and play a Card in the lead Suit }
SelectCard := FollowSuit
else
begin
CardNo := SelectRuff; { Void Suit, Ruff the trick or Discard a Card }
if CardNo >= 0 then
SelectCard := CardNo
else
SelectCard := DiscardCard;
end;
end;
end { SelectCard };
procedure Analyse(var Result: integer);
{ Performs the analysis of the given position (in the Sim records).
When the analysis is finished the Number of won Tricks
for the declarer is placed in Result }
var
MaxVal : array[-1..13] of integer; { Alfa-Beta values }
CardNo : ExpandCardNoType; { Counters }
Back : -1..13;
i : IndexType;
h : 1..3;
label Call,Loop;
begin
CheckKBD;
with Sim do
begin
if Round and 3 <> 0 then { Finish this trick }
for h := Round and 3 to 3 do
PlayCard(PlayingHand,SelectCard);
FirstNo := TrickNo;
Call: { Initialize MaxVal[TrickNo] }
if odd(PlayingHand+Dummy) then
MaxVal[TrickNo] := -WonTricks+TrickNo-14
else
MaxVal[TrickNo] := WonTricks+1;
if TrickNo = FirstNo then
MaxVal[FirstNo-1] := TrickNo-13-MaxVal[FirstNo]
else
begin
Back := TrickNo;
repeat
Back := Back-1
until (MaxVal[TrickNo] > 0) = (MaxVal[Back] > 0);
if MaxVal[TrickNo] < MaxVal[Back] then
MaxVal[TrickNo] := MaxVal[Back];
end;
Count[TrickNo].Cnt := 0; { Initiate SelectLead }
Loop: { Test cut-off }
Back := TrickNo;
repeat
Back := Back-1
until (MaxVal[TrickNo] > 0) <> (MaxVal[Back] > 0);
if MaxVal[TrickNo]+MaxVal[Back] >= 0 then
begin
Back := Back+1; { Take Back All Tricks lead by the Player }
MaxVal[Back] := MaxVal[TrickNo];
while TrickNo > Back do ResetTrick;
end
else
begin
CardNo := SelectLead; { Find next lead }
if CardNo >= 0 then
begin
PlayCard(PlayingHand,CardNo); { Play the whole trick }
for h := 1 to 3 do
PlayCard(PlayingHand,SelectCard);
goto Call;
end;
end;
if TrickNo > FirstNo then
begin
ResetTrick; { Backup MaxVal-Value }
if (MaxVal[TrickNo] > 0) = (MaxVal[TrickNo+1] > 0) then
MaxVal[TrickNo] := MaxVal[TrickNo+1]
else
MaxVal[TrickNo] := -MaxVal[TrickNo+1];
goto Loop;
end;
end; { with }
CheckKBD;
Result := abs(MaxVal[TrickNo])-1; { Save Result and reestablish situation }
for i := Sim.Round-1 downto Rel.Round do
with Game[i],Sdist[Hand,No],Sdata[Hand] do
begin
Played := false;
l[Suit] := l[Suit]+1;
end;
Sim := Rel;
TrickNo := Rel.Round div 4;
CheckKBD;
end; { Analyse }
procedure FindCard(var BestChoice: CardNoType;
var Redeal, Auto, Hint : boolean);
{ Finds a Card to play. The Rel records contains the actual
situation.
TrickNo, Game, Contract, BLIND and Info are alse updated.
The Number of the chosen Card is returned in BestChoice.
if the Hand is controlled by the human,
the Card is Read from input }
var
Comp : boolean; { Computer controls Hand }
All : boolean; { All cards can be Played }
Cardstat: array[CardNoType] of { Statistics about cards }
record
Try: boolean; { Card should be tried }
Stat: integer; { Statistical Evaluation }
end;
function CountTry: LengthType;
{ Counts the Number of cards which should be tried }
var
Count : LengthType;
No : CardNoType;
begin
Redeal := False;
Count := 0;
for No := 0 to 12 do
if Cardstat[No].Try then
Count := Count+1;
CountTry := Count;
end; { CountTry }
procedure InitSearch;
{ Copies Rel in Sim, and finds the cards, which shall be analysed }
procedure SelectTry;
{ Selects the cards which should be analysed }
var
LastCard : array[SuitType] of ValueType;
{ Strength of last chosen Card in the Suit }
h : HandType;
i : CardNoType;
begin
with Rel,Rdata[PlayingHand],Contract do
begin
for i := 12 downto 0 do
with Rdist[PlayingHand,i],Cardstat[i] do
if Try then
begin
{ Always Try Lowest Card in a Suit }
if Value <> Lowest(PlayingHand,Suit) then
begin
{ Never Try two different equally strong cards }
Try := false;
if Value > LastCard[Suit]+1 then
for h := North to West do
if Highmax(h,Suit,Value-1) > LastCard[Suit] then
Try := true;
if not Try then if PlayingHand <> LeadHand then
if (Suit = BestCard.Suit) and
(LastCard[Suit] < BestCard.Value) then
Try := true;
if not Try then
LastCard[Suit] := Value;
if Try then
begin
if PlayingHand = LeadHand then
Try := Value > 8 { Try to lead All High cards }
else
if (Suit = BestCard.Suit) or (Suit = Trump) then
begin
{ Try cards which gets the trick }
if Suit = BestCard.Suit then
Try := Value > BestCard.Value
else
Try := Suit = Trump;
{ in 4th Hand Try only Lowest Card, which gets the trick }
if Try then
if (Value <= 8) or (PlayingHand = (LeadHand+3) and 3) then
if not ((Suit = BestCard.Suit) and
(LastCard[Suit] < BestCard.Value)) then
Try := false;
end
else
Try := false;
end; { if }
end;
if Try then
LastCard[Suit] := Value;
end;
end; { with }
end; { SelectTry }
var
i : CardNoType;
begin { InitSearch }
Sim := Rel;
with Rel,Rdata[PlayingHand] do
begin
if PlayingHand <> Dummy then { Check if Computer controls the Hand }
begin
Comp := Computer[PlayingHand];
if Comp and not Auto then
PlayMessage(PlayingHand, Hint);
end
else
begin
Comp := Computer[(Dummy+2) and 3];
if Comp and not Auto then
PlayMessage(Dummy, Hint);
end;
CheckKBD;
if PlayingHand = LeadHand then { Check if All cards can be Played }
All := true
else
All := l[LeadSuit] = 0;
for i := 0 to 12 do { Check which cards can be Played }
with Rdist[PlayingHand,i],Cardstat[i] do
begin
Stat := 0;
Try := not Played and (All or (Suit = LeadSuit));
end;
if Comp then
if CountTry > 1 then
SelectTry; { Select the cards to be analysed further }
CheckKBD;
end; { with }
end; { InitSearch }
var
DealNo : integer; { Deal counter }
Result : integer; { Result of analysis }
StatEvalu : integer; { Evaluation of Result }
MaxStat : integer; { Maximal statistical Evaluation }
TryNo : CardNoType;
Choice : ExpandCardNoType;
MinValue : ValueType;
Suit : SuitType;
label 10,20;
begin { findCard }
CheckKBD;
InitSearch;
with Sim do
if CountTry = 1 then
begin
for TryNo := 0 to 12 do { Find the only Card }
if Cardstat[TryNo].Try then
BestChoice := TryNo;
end
else
if Comp then
begin
GotoCardPos(PlayingHand); { Find Card for Computer }
DealNo := 0; { Heuristic Evaluation }
if Heurisfac <> 0 then
while ((DealNo < MaxDeals) and not Cheat
or (DealNo < 1)) and (CountTry > 1) do
begin
DealNo := DealNo + 1;
Sdist := Rdist;
Sdata := Rdata;
if not Cheat then
begin
DealCards;
ChangeCards;
end;
SortCards;
with Sdist[PlayingHand,SelectCard] do
for TryNo := 0 to 12 do
with Cardstat[TryNo] do
if Try and (Sdist[PlayingHand,TryNo].Suit = Suit) and
(Sdist[PlayingHand,TryNo].Value <= Value) then
begin
Stat := Stat + Heurisfac;
goto 10;
end;
10:
CheckKBD;
end; { if }
DealNo := 0; { Search }
if SearchFac <> 0 then
while ((DealNo < MaxDeals) and not Cheat or (DealNo < 1))
and (CountTry > 1) do
begin
DealNo := DealNo+1;
Sdist := Rdist;
Sdata := Rdata;
if not Cheat then
begin
DealCards;
ChangeCards;
end;
SortCards;
for TryNo := 0 to 12 do
if Cardstat[TryNo].Try then
begin
PlayCard(PlayingHand, TryNo); { Analyse Card }
Analyse(Result);
StatEvalu := Result-(6+Contract.Level); { Calculate Evaluation }
if StatEvalu < 0 then
StatEvalu := StatEvalu-2;
if odd(PlayingHand + Dummy) then
StatEvalu := -StatEvalu;
with Cardstat[TryNo] do
Stat := Stat + StatEvalu * SearchFac;
end; { if }
end; { while }
MaxStat := -MaxInt; { Find best Choice }
for TryNo := 12 downto 0 do
with Cardstat[TryNo] do if Try then
if Stat > MaxStat then
begin
BestChoice := TryNo;
MaxStat := Stat;
end;
end
else
begin
repeat { Read Card from keyboard }
PlayMenu;
Choice := -1;
Answer(PlayingHand, Command, false, Redeal);
{ The third paramater indicates that we are not Bidding }
if Redeal then
Exit;
if (Command = 'O') then
begin
Command := '';
Auto := true;
Exit;
end;
if (Command = 'H') then
begin
Command := '';
Hint := true;
Exit;
end;
if (Command = '') and All then
Choice := DiscardCard
else
for TryNo := 0 to 12 do
with Rdist[PlayingHand,TryNo],Cardstat[TryNo] do
if Try then
if (Command = ValueName[Value] + TrumpName[Suit][1]) or
((Command = ValueName[Value]) or
(Command = '') and not All) then
Choice := TryNo;
if Choice < 0 then
Error(' INVALID PLAY ');
until Choice >= 0;
BestChoice := Choice;
end;
end; { findCard }
procedure MakeCard(BestChoice: CardNoType; AutoSet : boolean);
{ Play the Card in the real situation, and Update the Rel records }
var
PlayHand : HandType; { PlayingHand }
Card : CardType; { Played Card }
begin
CheckKBD;
Sim := Rel; { Copy the Rel records }
Sdist := Rdist;
Sdata := Rdata;
PlayHand := Sim.PlayingHand;
Card := Sdist[PlayHand,BestChoice];
with Sim,Card,Info[PlayHand] do
begin
if Minl[Suit] > 0 then { Updata Info }
Minl[Suit] := Minl[Suit]-1;
if (Round and 3 <> 0) and (Suit <> LeadSuit) then
Minl[LeadSuit] := -1;
CheckKBD;
PlayCard(PlayHand,BestChoice); { Play the Card }
CheckKBD;
Rel := Sim; { Restore the Rel records }
Rdist := Sdist;
Rdata := Sdata;
if Round = 1 then { Setup screen }
begin
ClearIt; { ClearTable and bid window }
PrintPlayScreen;
end;
PrintSuit(PlayHand,Card.Suit); { Print the Card and the new situation }
PrintCard(PlayHand,Card);
if Round and 3 = 0 then
begin
PrintwonTricks;
if AutoSet then
Delay(LongDelay)
else
ClearTblMsg;
ClearTable;
end;
end;
end; { MakeCard }
procedure PlayCards(var BestChoice : CardNoType;
var Redeal : boolean);
{ finds the cards to plays and plays them for each of
the thirteen tricks or until the user cancels the game }
var
SavedHands : PlayerHand;
HandsSaved, Auto, Hint, HintPlayed : boolean;
procedure SetAuto;
{ puts play into auto mode }
procedure SetHands;
{ Set hands for autoplay }
var
CurHand : HandType;
begin
for CurHand := North to West do
begin
SavedHands[CurHand] := Computer[CurHand];
Computer[CurHand] := true;
end;
end; { SetHands }
begin { SetAuto }
HandsSaved := true;
Command := '';
SetHands;
PrintScreen(Dummy); { Show all hands for AutoPlay }
PrintContract;
PrintWonTricks;
ClearMenu;
Message(' AutoPlay ');
FindCard(BestChoice, Redeal, Auto, Hint);
end; { SetAuto }
procedure ResetHands;
{ Restore the hands that the user plays }
var
CurHand : HandType;
begin
for CurHand := North to West do
begin
Computer[CurHand] := SavedHands[CurHand];
end;
end; { ResetHands }
procedure SetHint;
begin
with Rel do
begin
if (PlayingHand = Dummy) then
begin
Computer[(PlayingHand + 2) and 3] := true;
Hint := true;
FindCard(BestChoice, Redeal, Auto, Hint);
ShowHint(Rel.PlayingHand,
Rdist[PlayingHand, BestChoice], HintPlayed);
Computer[(PlayingHand + 2) and 3] := false;
end
else
begin
Computer[PlayingHand] := true;
Hint := true;
FindCard(BestChoice, Redeal, Auto, Hint);
ShowHint(Rel.PlayingHand,
Rdist[PlayingHand, BestChoice], HintPlayed);
Computer[PlayingHand] := false;
end;
end; { with }
end; { SetHint }
begin
Auto := false;
HandsSaved := false;
repeat
Hint := false;
HintPlayed := false;
FindCard(BestChoice, Redeal, Auto, Hint);
if Redeal then
begin
GameNo := GameNo - 1;
Exit;
end;
if Hint then
SetHint
else
if Auto and not HandsSaved then
SetAuto;
if (not Hint) or HintPlayed then
MakeCard(BestChoice, HandsSaved);
until TrickNo = 13;
if HandsSaved then { AutoPlay over reset the hands }
ResetHands;
end; { PlayCards }
{ end PLAY.BR }