{-----------------------------------------------------------------------------
Rainbow Graphics Solitaire
Copyright (c) 1986 Marc E. Kenig
This program is donated to the public domain. This program, any copy
of it or any enhanced version upon which this program or its data
is based, may NOT be sold without the express permission of the author.
It is always and forever to be distributed free of charge as shareware.
------------------------------------------------------------------------------}
type
suit = (spade,diamond,club,heart);
const
number_of_columns = 7;
suit_name : array [spade..heart] of char = ('S',
'D','C','H');
procedure help;
var
ch:char;
begin
graphicsoff;
clrscr;
Normvideo;
writeln(' S O L I T A I R E FOR DEC-RAINBOW w/GRAPHICS OPTION');
writeln(' Copyright(c)1987 Marc E. Kenig - All rights reserved');
writeln;
writeln(' Solitaire, also known as "patience" in english speaking parts of the world,');
writeln('is an irritating card game to play alone against a shuffled deck of cards. The');
writeln('object is to re-arrange the deck into 4 descending columns of alternating suit');
writeln('beginning with the king. For a tutorial on solitaire basics see the help file');
writeln('shipped with this program or Charles Goren''s book on the subject.');
writeln(' This program implements the standard game: arrange 7 columns into 4 (king');
writeln('high) of alternating suit. Empty rows may only be filled by kings drawn from');
writeln('the deck or other columns beginning with a king. Draw from the deck one time');
writeln('through or lose. Sorry, no cheating mode is implemented. Drawing is automatic');
writeln('and will stop when a card can be used. You must use the card.');
writeln(' There are 4 commands each activated by a single keystroke (not echoed):');
writeln(' C - Move card(s) from one column to another. Columns (labled)');
writeln(' are numbered starting at 1, from the left.');
writeln(' D - Try to draw a card from the deck. Drawing continues until a card can');
writeln(' (and must) be used. No card''s found in 1 circuit through, you lose.');
writeln('? or H - This text again.');
writeln(' Q - Quit. After you quit or lose, the deck is displayed.');
writeln(' The Deck appears on the rightmost side, face down until you draw.');
writeln(' Press any key to continue....');
read(kbd,ch);
graphicson;
end;
procedure init_pip(var pip_offs: pip_array);
var
i: integer;
begin
for i:=1 to 5 do
pip_offs[i].x:=12;
pip_offs[1].y:=19;
pip_offs[2].y:=37;
pip_offs[3].y:=46;
pip_offs[4].y:=55;
pip_offs[5].y:=73;
for i:=6 to 8 do
begin
pip_offs[i].x:=36;
pip_offs[i].y:=pip_offs[i-4].y;
end;
for i:=9 to 13 do
begin
pip_offs[i].x:=60;
pip_offs[i].y:=pip_offs[i-8].y;
end;
end;
procedure init_deck;
var
s: suit;
c,i: integer;
begin
c:=1;
for s:=spade to heart do
for i:=1 to 13 do
begin
cards[c].pip:=s;
cards[c].rank:=i;
c:=c+1;
end;
deck_top:=1;
deck_last:=52;
end;
procedure drawblank(x,x1,y,y1:integer);
begin
if y1>239 then
y1:=239;
color(1);
drawbar(x,x1,y,y1);
color(0);
drawline(x-1,y-1,x-1,y1+1);
drawline(x-1,y1+1,x1+1,y1+1);
drawline(x1+1,y1+1,x1+1,y-1);
drawline(x1+1,y-1,x-1,y-1);
end;
procedure draw_back(card_x,card_y: integer);
var
x,y: integer;
begin
color(1);
drawbar(card_x,card_x+90,card_y,card_y+80);
color(3);
Backgroundcolor(2);
preblanking:=false;
Pattern(122,2);
for x:=5 to 85 do
drawline(card_x+5,card_y+75,card_x+x,card_y+5);
for y:=6 to 75 do
drawline(card_x+5,card_y+75,card_x+85,card_y+y);
Pattern(255,15);
Backgroundcolor(0);
end;
function card_color(strng:str1): integer;
begin
if color_dsp then
case ord(strng[1]) of
128,129: card_color:=2;
else card_color:=0
end
else
case ord(strng[1]) of
128,130,131: card_color:=0;
else card_color:=2;
end;
end;
procedure draw_corner(card_x,card_y: integer; strng: str1; i: integer);
begin
color(card_color(strng));
if ord(strng[1])=128 then color(2);
charcursor(card_x+2,card_y+9);
charscale(5.0,7.0,6,7);
case i of
1: drawstring('A');
2: drawstring('2');
3: drawstring('3');
4: drawstring('4');
5: drawstring('5');
6: drawstring('6');
7: drawstring('7');
8: drawstring('8');
9: drawstring('9');
10: drawstring('10');
11: drawstring('J');
12: drawstring('Q');
13: drawstring('K');
end;
if i>10 then
begin
charscale(5.0,7.0,6,10);
charcursor(card_x+2,card_y+25);
drawstring(strng);
end;
end;
procedure draw_face_card(card_x,card_y: integer; str: str1; i: integer);
begin
color(1);
drawblank(card_x,card_x+90,card_y,card_y+80);
draw_corner(card_x,card_y,str,i);
{ if color_dsp then
if ord(str[1]) in [128,129] then
color(2)
else
color(0)
else}
color(card_color(str[1]));
if ord(str[1])=128 then color(2);
charscale(20.0,20.0,6,10);
charcursor(card_x+25,card_y+60);
drawstring(chr(132+(i-11)));
draw_corner(card_x,card_y,str,i);
end;
procedure draw_pip_card(card_x,card_y: integer; str: str1; i: integer);
begin
color(1);
drawblank(card_x,card_x+90,card_y,card_y+80);
draw_corner(card_x,card_y,str,i);
charscale(5.0,7.0,6,10);
color(card_color(str));
case i of
1: begin
if ord(str[1])=131 then
begin
charscale(20.0,20.0,6,10);
charcursor(card_x+25,card_y+60);
end
else
charcursor(card_x+pip_offs[7].x,card_y+pip_offs[7].y);
drawstring(str);
charscale(5.0,7.0,6,10);
end;
2: begin
charcursor(card_x+pip_offs[6].x,card_y+pip_offs[1].y);
drawstring(str);
charcursor(card_x+pip_offs[8].x,card_y+pip_offs[5].y);
drawstring(str);
end;
3: begin
charcursor(card_x+pip_offs[6].x,card_y+pip_offs[1].y);
drawstring(str);
charcursor(card_x+pip_offs[7].x,card_y+pip_offs[3].y);
drawstring(str);
charcursor(card_x+pip_offs[8].x,card_y+pip_offs[5].y);
drawstring(str);
end;
4: begin
charcursor(card_x+pip_offs[1].x,card_y+pip_offs[1].y);
drawstring(str);
charcursor(card_x+pip_offs[5].x,card_y+pip_offs[5].y);
drawstring(str);
charcursor(card_x+pip_offs[9].x,card_y+pip_offs[9].y);
drawstring(str);
charcursor(card_x+pip_offs[13].x,card_y+pip_offs[13].y);
drawstring(str);
end;
5: begin
charcursor(card_x+pip_offs[1].x,card_y+pip_offs[1].y);
drawstring(str);
charcursor(card_x+pip_offs[5].x,card_y+pip_offs[5].y);
drawstring(str);
charcursor(card_x+pip_offs[7].x,card_y+pip_offs[7].y);
drawstring(str);
charcursor(card_x+pip_offs[9].x,card_y+pip_offs[9].y);
drawstring(str);
charcursor(card_x+pip_offs[13].x,card_y+pip_offs[13].y);
drawstring(str);
end;
6: begin
charcursor(card_x+pip_offs[1].x,card_y+pip_offs[1].y);
drawstring(str);
charcursor(card_x+pip_offs[3].x,card_y+pip_offs[3].y);
drawstring(str);
charcursor(card_x+pip_offs[5].x,card_y+pip_offs[5].y);
drawstring(str);
charcursor(card_x+pip_offs[9].x,card_y+pip_offs[9].y);
drawstring(str);
charcursor(card_x+pip_offs[11].x,card_y+pip_offs[11].y);
drawstring(str);
charcursor(card_x+pip_offs[13].x,card_y+pip_offs[13].y);
drawstring(str);
end;
7: begin
charcursor(card_x+pip_offs[1].x,card_y+pip_offs[1].y);
drawstring(str);
charcursor(card_x+pip_offs[3].x,card_y+pip_offs[3].y);
drawstring(str);
charcursor(card_x+pip_offs[5].x,card_y+pip_offs[5].y);
drawstring(str);
charcursor(card_x+pip_offs[6].x,card_y+pip_offs[6].y);
drawstring(str);
charcursor(card_x+pip_offs[9].x,card_y+pip_offs[9].y);
drawstring(str);
charcursor(card_x+pip_offs[11].x,card_y+pip_offs[11].y);
drawstring(str);
charcursor(card_x+pip_offs[13].x,card_y+pip_offs[13].y);
drawstring(str);
end;
8: begin
charcursor(card_x+pip_offs[1].x,card_y+pip_offs[1].y);
drawstring(str);
charcursor(card_x+pip_offs[3].x,card_y+pip_offs[3].y);
drawstring(str);
charcursor(card_x+pip_offs[5].x,card_y+pip_offs[5].y);
drawstring(str);
charcursor(card_x+pip_offs[6].x,card_y+pip_offs[6].y);
drawstring(str);
charcursor(card_x+pip_offs[8].x,card_y+pip_offs[8].y);
drawstring(str);
charcursor(card_x+pip_offs[9].x,card_y+pip_offs[9].y);
drawstring(str);
charcursor(card_x+pip_offs[11].x,card_y+pip_offs[11].y);
drawstring(str);
charcursor(card_x+pip_offs[13].x,card_y+pip_offs[13].y);
drawstring(str);
end;
9: begin
charcursor(card_x+pip_offs[1].x,card_y+pip_offs[1].y);
drawstring(str);
charcursor(card_x+pip_offs[2].x,card_y+pip_offs[2].y);
drawstring(str);
charcursor(card_x+pip_offs[4].x,card_y+pip_offs[4].y);
drawstring(str);
charcursor(card_x+pip_offs[5].x,card_y+pip_offs[5].y);
drawstring(str);
charcursor(card_x+pip_offs[7].x,card_y+pip_offs[7].y);
drawstring(str);
charcursor(card_x+pip_offs[9].x,card_y+pip_offs[9].y);
drawstring(str);
charcursor(card_x+pip_offs[10].x,card_y+pip_offs[10].y);
drawstring(str);
charcursor(card_x+pip_offs[12].x,card_y+pip_offs[12].y);
drawstring(str);
charcursor(card_x+pip_offs[13].x,card_y+pip_offs[13].y);
drawstring(str);
end;
10: begin
charcursor(card_x+pip_offs[1].x,card_y+pip_offs[1].y);
drawstring(str);
charcursor(card_x+pip_offs[2].x,card_y+pip_offs[2].y);
drawstring(str);
charcursor(card_x+pip_offs[4].x,card_y+pip_offs[4].y);
drawstring(str);
charcursor(card_x+pip_offs[5].x,card_y+pip_offs[5].y);
drawstring(str);
charcursor(card_x+pip_offs[6].x,card_y+pip_offs[6].y);
drawstring(str);
charcursor(card_x+pip_offs[8].x,card_y+pip_offs[8].y);
drawstring(str);
charcursor(card_x+pip_offs[9].x,card_y+pip_offs[9].y);
drawstring(str);
charcursor(card_x+pip_offs[10].x,card_y+pip_offs[10].y);
drawstring(str);
charcursor(card_x+pip_offs[12].x,card_y+pip_offs[12].y);
drawstring(str);
charcursor(card_x+pip_offs[13].x,card_y+pip_offs[13].y);
drawstring(str);
end;
end;
end;
procedure draw_a_card(a_card: card; card_x,card_y: integer);
var
str: str1;
begin
str[0]:=chr(1);
case a_card.pip of
diamond: str[1]:=chr(128);
heart: str[1]:=chr(129);
club: str[1]:=chr(130);
spade: str[1]:=chr(131);
end;
if a_card.rank=0 then draw_back(card_x,card_y)
else if a_card.rank<=10 then
draw_pip_card(card_x,card_y,str,a_card.rank)
else
draw_face_card(card_x,card_y,str,a_card.rank);
end;
procedure shuffle;
var
h: card;
t,c,i,j: integer;
begin
t:=600+random(2000);
for c:=1 to t do
begin
i:=1+random(52);
j:=1+random(52);
while i=j do
j:=1+random(51);
h.pip:=cards[i].pip;
h.rank:=cards[i].rank;
cards[i].pip:=cards[j].pip;
cards[i].rank:=cards[j].rank;
cards[j].pip:=h.pip;
cards[j].rank:=h.rank;
end;
end;
procedure init_column;
var
i: integer;
begin
for i:=0 to number_of_columns do
with column[i] do
begin
tot_cards:=0;
up:=0;
down:=0;
column[i].up_cards[0].rank:=0;
column[i].up_cards[0].pip:=spade;
end;
end;
procedure deal;
var
i,j: integer;
begin
for i:=1 to number_of_columns do
begin
column[i].tot_cards:=column[i].tot_cards+1;
column[i].up:=1;
column[i].up_cards[1]:=cards[deck_top];
deck_top:=deck_top+1;
for j:=i+1 to number_of_columns do
with column[j] do
begin
tot_cards:=tot_cards+1;
down:=down+1;
down_cards[down]:=cards[deck_top];
deck_top:=deck_top+1;
end;
end;
deck_next:=deck_top;
end;
procedure gblank_col(i: integer);
begin
color(0);
drawbar((i-1)*100+2,i*100+2,0,240);
end;
procedure gdraw_col(i:integer; Acolumn: colm);
var
col_x,col_y,j: integer;
val: string[2];
begin
col_x:=(i-1)*100+2;
charcursor(col_x+1,12);
color(1);
charscale(5.0,7.0,6,10);
drawstring('Col: '+col_name[i]);
col_y:=14;
with Acolumn do
begin
if tot_cards=0 then
begin
gblank_col(i);
color(1);
charcursor(col_x+1,12);
drawstring('Col: '+col_name[i]);
drawstring(' *EMPTY*')
end
else
begin
str(down:2,val);
drawstring(' DOWN:'+val);
for j:=1 to up do
begin
draw_a_card(up_cards[j],col_x,col_y);
col_y:=col_y+17;
end;
end;
end;
end;
procedure gdisplay;
var
i: integer;
ch:char;
begin
clearallplanes;
for i:= 1 to number_of_columns do
begin
gblank_col(i);
gdraw_col(i,column[i]);
end;
end;
function get_column: integer;
var
c: char;
col: integer;
begin
read(kbd,c);
col:=ord(c)-ord('0');
if col=0 then
get_column:=-1
else
while (col<1) or (col>number_of_columns) do
begin
preblanking:=true;
Charcursor(700,180);
drawstring('Illegal column');
read(kbd,c);
col:=ord(c)-ord('0');
end;
get_column:=col;
end;
function opposite(pip1,pip2: suit): boolean;
begin
opposite:=((pip1 in [spade,club]) and (pip2 in [heart,diamond]))
or ((pip1 in [heart,diamond]) and (pip2 in [spade,club]));
end;
procedure play;
var
i,j,from_column, to_column: integer;
cmd: char;
procedure column_move;
var
moved: boolean;
begin
moved:=false;
preblanking:=true;
charcursor(700,200);
drawstring('From column:');
from_column:=get_column;
charcursor(700,210);
drawstring('To column:');
to_column:=get_column;
if (column[to_column].tot_cards<>0) then
begin
if (opposite(column[from_column].up_cards[1].pip,
column[to_column].up_cards[column[to_column].up].pip)
and (column[from_column].up_cards[1].rank+1
=column[to_column].up_cards[column[to_column].up].rank))
then
begin
moved:=true;
for i:=1 to column[from_column].up do
begin
column[to_column].up:=column[to_column].up+1;
column[to_column].up_cards[column[to_column].up]:=
column[from_column].up_cards[i];
column[from_column].tot_cards:=column[from_column].tot_cards-1;
column[to_column].tot_cards:=column[to_column].tot_cards+1;
end;
if column[from_column].tot_cards > 0 then
begin
column[from_column].up_cards[1]:=column[from_column].
down_cards[column[from_column].down];
column[from_column].down:=column[from_column].down-1;
column[from_column].up:=1;
end
else
column[from_column].up:=0;
end;
end
else if (column[from_column].up_cards[1].rank=13) then
begin
moved:=true;
for i:=1 to column[from_column].up do
begin
column[to_column].up:=column[to_column].up+1;
column[to_column].up_cards[column[to_column].up]:=
column[from_column].up_cards[i];
column[from_column].tot_cards:=column[from_column].tot_cards-1;
column[to_column].tot_cards:=column[to_column].tot_cards+1;
end;
if column[from_column].tot_cards > 0 then
begin
column[from_column].up_cards[1]:=column[from_column].
down_cards[column[from_column].down];
column[from_column].down:=column[from_column].down-1;
column[from_column].up:=1;
end
else
column[from_column].up:=0;
end;
if moved then
begin
preblanking:=false;
gblank_col(from_column);
gdraw_col(from_column,column[from_column]);
gblank_col(to_column);
gdraw_col(to_column,column[to_column]);
end;
color(0);
drawbar(700,800,180,240);
end;
procedure card_draw;
var
deck_look,i,j: integer;
c: char;
save,save2: card;
function usable(cd: card):boolean;
var
i: integer;
ok: boolean;
begin
ok:=false;
for i:=1 to number_of_columns do
if (cd.rank=13) and (column[i].up=0) then ok:=true
else if (column[i].up<>0) then
ok:=ok
or (
(opposite(column[i].up_cards[column[i].up].pip,cd.pip)
and (column[i].up_cards[column[i].up].rank-1=cd.rank))
);
usable:=ok
end;
begin
save2:=cards[deck_top];
repeat
for i:=1 to 3 do
begin
save:=cards[deck_top];
for j:=deck_top to deck_last-1 do
cards[j]:=cards[j+1];
cards[deck_last]:=save;
end;
cards[deck_last]:=cards[deck_last-2];
cards[deck_last-2]:=save;
preblanking:=false;
draw_a_card(cards[deck_top],700,40);
until usable(cards[deck_top]) or ((cards[deck_top].pip=save2.pip)
and (cards[deck_top].rank=save2.rank));
if (not usable(cards[deck_top]))
and (cards[deck_top].pip=save2.pip)
and (cards[deck_top].rank=save2.rank) then
begin
clrscr;
you_lose:=true;
ok:=false
end
else
begin
color(1);
charcursor(700,200);
drawstring('Column: ');
j:=get_column;
while not (
( opposite(column[j].up_cards[column[j].up].pip,
cards[deck_top].pip)
and (column[j].up_cards[column[j].up].rank-1=
cards[deck_top].rank)
)
or
((column[j].up=0) and (cards[deck_top].rank=13))
)
do
begin
preblanking:=true;
charcursor(700,200);
drawstring('No, Column:');
j:=get_column;
end;
with column[j] do
begin
tot_cards:=tot_cards+1;
up:=up+1;
up_cards[up]:=cards[deck_top];
end;
deck_top:=deck_top+1;
end;
if ok then
begin
gblank_col(j);
preblanking:=false;
gdraw_col(j,column[j]);
draw_back(700,40);
end;
color(0);
drawbar(700,800,180,240);
end;
begin
while ok do
begin
color(1);
PreBlanking:=true;
charcursor(700,180);
drawstring('Move-> ');
read(kbd,cmd);
cmd:=upcase(cmd);
case cmd of
'C': column_move;
'D': card_draw;
'Q': begin
ok:=false;
you_lose:=true;
end;
'?',
'H': help;
else write(chr(7));
end;
if deck_top=deck_last then
begin
you_lose:=false;
ok:=false
end;
{ display }
end;
end;
procedure display_deck;
var
col_x,col_y,I: integer;
ch: char;
begin
charcursor(20,20);
charscale(10.0,14.0,12,14);
if you_lose then
begin
color(0);
drawbar(0,700,0,240);
color(1);
drawstring('You lose, sorry. The deck contained:');
col_x:=1;
col_y:=40;
preblanking:=false;
for i:=deck_top to deck_last do
begin
draw_a_card(cards[i],col_x,col_y);
col_x:=col_x+40;
col_y:=col_y+2;
if col_x>600 then
begin
col_x:=10;
col_y:=80;
end;
end;
end
else
begin
charscale(10.0,14.0,12,14);
preblanking:=true;
drawstring('Congratulations, you win.');
end;
color(1);
preblanking:=true;
charscale(10.0,14.0,12,14);
charcursor(1,200);
drawstring('Type any character to exit...');
read(kbd,ch);
clearallplanes;
end;
begin
{ required initialization }
LeftMargin:=15;RightMargin:=15; { used by DrawString }
TopMargin:=10;BottomMargin:=10; { used by DrawString }
for P:=0 to 255 do ScrollMap[P]:=P;
HighResolution:=true; { Change to 'true' for high resolution demo }
Ginitialize; { Initialize }
LoadScrollMap(ScrollMap); { Load scroll map }
DualMonitor:=false; { Dual CRTs }
{ end of required initialization }
ClearAllPlanes;
Pattern(255,4); { Draw all lines as solid lines }
PreBlanking:=false;
normvideo;
writeln('Welcome to Rainbow Graphics Solitaire(c).');
Write('C)olor or B)lack&White display: ');
readln(ch);
while not (Upcase(ch) in ['C','B']) do
begin
Write('C)olor or B)lack&White display: ');
readln(ch);
end;
if Upcase(ch)='C' then
begin
ColorMap[00]:=$00; ColorMap[16]:=$00; { 0 black }
ColorMap[01]:=$FF; ColorMap[17]:=$FF; { 1 white }
ColorMap[02]:=$F0; ColorMap[18]:=$06; { 2 red }
ColorMap[03]:=$0F; ColorMap[19]:=$F0; { 3 green }
Operation(0,15); { REPLACE write to all planes }
Color_dsp:=true;
end
else
begin
ColorMap[00]:=$00; ColorMap[16]:=$00; { 0 black }
ColorMap[01]:=$FF; ColorMap[17]:=$FF; { 1 white }
ColorMap[02]:=$00; ColorMap[18]:=$22; { 2 black }
ColorMap[03]:=$00; ColorMap[19]:=$00; { 3 black }
Operation(0,15); { REPLACE write to all plane }
Color_dsp:=false;
end;
LoadColorMap(ColorMap); { Load color map }
writeln('WARNING: You must have a Rainbow Graphics card to play this game, or else');
writeln('you won''t see anything!!!');
writeln('Type an "H" or a "?" for HELP,');
writeln('Otherwise, type any character to start game...');
read(kbd,ch);
if (Upcase(ch)='H') or (ch='?') then help;
graphicson;
clearallplanes;
Backgroundcolor(3);
init_pip(pip_offs);
init_deck;
shuffle;
init_column;
deal;
gdisplay;
draw_back(700,40);
ok:=true;
play;
display_deck;
clrscr;
Normvideo;
graphicsoff;
end.