!---------------------------------! ! *** CRIB *** ! ! ! ! Cribbage Program - version 0.0 ! ! ! ! By Thomas M. Niccum ! ! 21 MARCH 1982 ! !---------------------------------! !---------------------------------! ! Maps ! !---------------------------------! MAP1 hand(3,6) MAP2 shdc,b,1 MAP2 value,b,1 MAP1 suit(4),s,8 MAP1 card(13),s,5 MAP1 deck'map(52),b,1 MAP1 crib'indicator(2),s,9 MAP1 play'stack(8) MAP2 play'suit,b,1 MAP2 play'card,b,1 MAP1 run'list(8),b,1 MAP1 tuple(5,10,5),b,1 MAP1 hand'indicator(3),s,10 MAP1 pair'score(4),b,1 MAP1 true,b,1,1 MAP1 false,b,1,0 !-------------------------------------------------------------------------! ! Main Program !-------------------------------------------------------------------------! main'program: CALL initialize CALL play END !-------------------------------------------------------------------------! ! Level 1 Subroutines !-------------------------------------------------------------------------! initialize: ?TAB(-1,0); ?TAB(9,10); "+-----------------------------------+" ?TAB(10,10);"| C R I B B A G E |" ?TAB(11,10);"| version 1.0 |" ?TAB(12,10);"| by Tom Niccum |" ?TAB(13,10);"+-----------------------------------+" suit(1)="Spades" suit(2)="Hearts" suit(3)="Diamonds" suit(4)="Clubs" card(1)="Ace" card(2)="Two" card(3)="Three" card(4)="Four" card(5)="Five" card(6)="Six" card(7)="Seven" card(8)="Eight" card(9)="Nine" card(10)="Ten" card(11)="Jack" card(12)="Queen" card(13)="King" crib'indicator(1)=" My Crib " crib'indicator(2)="Your Crib" hand'indicator(1)="Computer" hand'indicator(2)="Human" hand'indicator(3)="Crib" pair'score(2)=2 pair'score(3)=6 pair'score(4)=12 CALL tuple'initialize RANDOMIZE CALL cut'for'deal RETURN play: ?TAB(-1,0);TAB(1,35)"C R I B B A G E "; ?TAB(2,1);"My Hand is:"; ?TAB(12,1);"Your Hand is:"; ?TAB(6,60);" SCOREBOARD"; ?TAB(8,60);" The";TAB(8,70);" The "; ?TAB(9,60);"Human";TAB(9,70);"Computer"; ?TAB(10,60);"-----";TAB(10,70);"--------"; ?TAB(22,1);"The Up-card is:"; ?TAB(14,60);"------";crib'indicator(dealer);"------"; CALL init'screen CALL score'board CALL deal'hand CALL display'hand CALL discard CALL up'card CALL play'hand CALL tally'points IF dealer=1 THEN dealer=2 ELSE dealer=1 GOTO play !-------------------------------------------------------------------------! ! Level 2 Subroutines !-------------------------------------------------------------------------! tuple'initialize: FOR a=1 TO 5 FOR b=1 TO 10 FOR c=1 TO 5 tuple(a,b,c)=0 NEXT c NEXT b NEXT a tuple(1,1,1)=1 tuple(1,2,1)=2 tuple(1,3,1)=3 tuple(1,4,1)=4 tuple(1,5,1)=5 tc=0 FOR a=1 TO 4 FOR b=a+1 TO 5 tc=tc+1 tuple(2,tc,1)=a tuple(2,tc,2)=b NEXT b NEXT a tc=0 FOR a=1 TO 3 FOR b=a+1 TO 4 FOR c=b+1 TO 5 tc=tc+1 tuple(3,tc,1)=a tuple(3,tc,2)=b tuple(3,tc,3)=c NEXT c NEXT b NEXT a tc=0 FOR a=1 TO 2 FOR b=a+1 TO 3 FOR c=b+1 TO 4 FOR d=c+1 TO 5 tc=tc+1 tuple(4,tc,1)=a tuple(4,tc,2)=b tuple(4,tc,3)=c tuple(4,tc,4)=d NEXT d NEXT c NEXT b NEXT a tuple(5,1,1)=1 tuple(5,1,2)=2 tuple(5,1,3)=3 tuple(5,1,4)=4 tuple(5,1,5)=5 RETURN cut'for'deal: CALL init'deck'map ?TAB(20,10);:INPUT "Ready to cut for the Deal?" y$ IF ucs(y$[1,1])#"Y" THEN GOTO cut'for'deal CALL deal'one'card ?TAB(22,15);"You cut up the ";card(c);" of ";suit(s); h=c CALL deal'one'card ?TAB(23,15);" I got the ";card(c);" of ";suit(s); i=c IF i=h THEN ?tab(24,15);"** A Tie, lets do it again **"; : GOTO cut'for'deal IF h121 THEN winner=2 : loser=1 IF points(1)=>121 THEN winner=1 : loser=2 IF winner=0 THEN RETURN ?TAB(-1,0); ?TAB(10,20)"The Final Score:"; ?TAB(12,30);"Computer: ";points(1) USING "###"; ?TAB(13,30);"Human: ";points(2) USING "###"; ?TAB(16,20);"The ";hand'indicator(winner);" beats "; IF points(loser)>90 THEN ?"the ";hand'indicator(loser);"!!!"; IF points(loser)>90 THEN PRINT : GOTO end'it IF points(loser)<61 THEN d$=" double " ELSE d$="" ?" and ";d$;"skunks the ";hand'indicator(loser);"!!!" end'it: END deal'hand: CALL init'deck'map IF dealer=1 THEN first=2 : second=1 : increment=-1 IF dealer=2 THEN first=1 : second=2 : increment=1 FOR pair=1 TO 6 FOR player=first TO second step increment CALL deal'one'card shdc(player,pair)=s value(player,pair)=c NEXT player NEXT pair RETURN display'hand: CALL sort'players'cards IF dealer=1 THEN first=2 : second=1 : increment=-1 IF dealer=2 THEN first=1 : second=2 : increment=1 FOR pair=1 TO 6 FOR player=first TO second step increment ?TAB((player-1)*10+3+pair,4);SPACE(30); IF shdc(player,pair)=0 THEN GOTO skip'card IF player=1 THEN ?TAB((player-1)*10+3+pair,4);pair;"-";"*****";" of ";"********"; & ELSE ?TAB((player-1)*10+3+pair,4);pair;"-";card(value(player,pair));" of ";suit(shdc(player,pair)); skip'card: NEXT player NEXT pair RETURN discard: CALL computer'discard CALL human'discard RETURN up'card: CALL deal'one'card ?TAB(23,6);card(c);" of ";suit(s); up'card(1)=s : up'card(2)=c IF up'card(2)=11 THEN points(dealer)=points(dealer)+2 : & ?TAB((10*(dealer-1)+5),28);crib'indicator(dealer)[1,4];" Nobs, 2 points!!"; CALL score'board RETURN play'hand: ?TAB(7,35);SPACE(20);TAB(17,35);SPACE(20);TAB(18,35);SPACE(20); ?TAB(12,25);"Play Total =>"; player=dealer human'cards=4 computer'cards=4 stack'pointer=1 computer'go=0 : human'go=0 play'stack'total=0 play=1 next'play: IF player=1 THEN player=2 ELSE player=1 IF human'go=1 THEN player=1 IF computer'go=1 THEN player=2 ON player CALL computer'plays,human'plays IF computer'go#0 AND human'go#0 THEN CALL go'score :& computer'go=0 : human'go=0 : play'stack'total=0 : stack'pointer=0 :& IF computer'cards=0 THEN computer'go=1 & ELSE IF human'cards=0 THEN human'go=1 stack'pointer=stack'pointer+1 ?TAB(12,40);play'stack'total; IF play<=8 THEN GOTO next'play ?TAB(10,30);SPACE(15);TAB(23,30);SPACE(15);TAB(12,25);SPACE(25); RETURN tally'points: IF dealer=1 THEN non'dealer=2 ELSE non'dealer=1 player=non'dealer CALL tally'a'hand IF points(player)=>121 THEN CALL score'board player=dealer CALL tally'a'hand IF points(player)=>121 THEN CALL score'board player=3 !CRIB! CALL tally'a'hand IF points(dealer)=>121 THEN CALL score'board RETURN !-------------------------------------------------------------------------! ! Level 3 Subroutines !-------------------------------------------------------------------------! init'deck'map: FOR x=1 TO 52 deck'map(x)=0 NEXT x RETURN deal'one'card: s=int(rnd(1)*4)+1 c=int(rnd(1)*13)+1 v=((s-1)*13)+c IF deck'map(v)#0 THEN GOTO deal'one'card deck'map(v)=1 RETURN computer'discard: ?TAB(7,35);"I'm tossing two"; CALL evaluate'hand discard'1=toss'1 discard'2=toss'2 player=1 CALL show'discard RETURN human'discard: discard'1=0 : discard'2=0 ?TAB(17,35);"Your first toss"; INPUT discard'1 IF discard'1=<0 OR discard'1>6 THEN GOTO human'discard human'discard'2: ?TAB(18,35);"Your second toss"; INPUT discard'2 IF discard'2=<0 OR discard'2>6 OR discard'2=discard'1 THEN GOTO human'discard'2 player=2 CALL show'discard RETURN human'plays: IF human'cards=0 THEN RETURN ?TAB(23,30);"Play a card"; : INPUT x IF x<0 OR x>4 THEN GOTO human'plays ?TAB(5,28);SPACE(25)TAB(6,28);SPACE(25);;TAB(15,28);SPACE(25);TAB(16,28);SPACE(25); IF x=0 THEN human'go=1+computer'go : RETURN IF shdc(2,x)>10 THEN GOTO human'plays play'card=value(2,x) IF play'card>10 THEN play'card=10 IF play'stack'total+play'card>31 THEN GOTO human'plays play'suit(stack'pointer)=shdc(2,x) play'card(stack'pointer)=value(2,x) shdc(2,x)=shdc(2,x)+10 play'stack'total=play'stack'total+play'card ?TAB(13+x,1);SPACE(30); CALL play'stack'scoring play=play+1 human'cards=human'cards-1 IF human'cards=0 THEN human'go=1+computer'go RETURN computer'plays: IF computer'cards=0 THEN RETURN ?TAB(5,28);SPACE(25)TAB(6,28);SPACE(25);;TAB(15,28);SPACE(25);TAB(16,28);SPACE(25); ?TAB(10,30);SPACE(29); IF computer'cards>1 THEN CALL evaluate'play : GOTO skip'evaluate FOR y=1 TO 4 IF shdc(1,y)<10 THEN x=y : y=5 NEXT y play'card=value(1,x) IF play'card>10 THEN play'card=10 IF play'stack'total+play'card>31 THEN x=0 skip'evaluate: IF x=0 THEN computer'go=1+human'go : ?TAB(10,30);"GO!"; : RETURN ?TAB(10,30);"I Play the ";card(value(1,x));" of ";suit(shdc(1,x)); play'suit(stack'pointer)=shdc(1,x) play'card(stack'pointer)=value(1,x) shdc(1,x)=shdc(1,x)+10 play'stack'total=play'stack'total+play'card ?TAB(3+x,1);SPACE(30); CALL play'stack'scoring play=play+1 computer'cards=computer'cards-1 IF computer'cards=0 THEN computer'go=1+human'go RETURN go'score: IF play'stack'total<31 THEN points(human'go)=points(human'go)+1 : & CALL score'board : ?TAB((10*(human'go-1)+6),28);"A GO for 1!"; RETURN tally'a'hand: IF player#3 THEN ?TAB(-1,0);hand'indicator(player);"'s Hand Scoring" IF player=3 THEN ?TAB(-1,0);hand'indicator(dealer);"'s Crib scoring" ? ?"The hand shows:" FOR x=1 TO 4 IF shdc(player,x)>10 THEN shdc(player,x)=shdc(player,x)-10 play'suit(x)=shdc(player,x) play'card(x)=value(player,x) ?"The ";card(value(player,x));" of ";suit(shdc(player,x)) NEXT x play'suit(5)=up'card(1) play'card(5)=up'card(2) ?"The ";card(up'card(2));" of ";suit(up'card(1));" (Up Card)" FOR x=6 TO 8 play'suit(x)=0 play'card(x)=0 NEXT x CALL calculate'points IF fifteen'count>0 THEN ?fifteen'count;" Fifteens for ";fifteen'count*2 IF pair'count>0 THEN ?pair'count;" Pairs for ";pair'count*2 IF run'5'count>0 THEN ?run'5'count;" Runs of 5 for ";run'5'count*5 IF run'4'count>0 THEN ?run'4'count;" Runs of 4 for ";run'4'count*4 IF run'3'count>0 THEN ?run'3'count;" Runs of 3 for ";run'3'count*3 IF flush'count>0 THEN ?" A flush of ";flush'count;" for ";flush'count IF nibs'count>0 THEN ?" Nibs for ";nibs'count ? ?"Total Points for this hand is ";hand'points INPUT x IF player<3 THEN points(player)=points(player)+hand'points ELSE & points(dealer)=points(dealer)+hand'points RETURN !-------------------------------------------------------------------------! ! Level 4 Subroutines !-------------------------------------------------------------------------! evaluate'hand: optimal'score=0 toss'1=1 toss'2=2 for eh1=1 to 5 for eh2=eh1+1 to 6 y=1 for x=1 to 6 IF x#eh1 AND x#eh2 THEN & play'card(y)=value(1,x) : & play'suit(y)=shdc(1,x) : y=y+1 next x play'card(5)=-10 : play'suit(5)=-10 play'card(6)=-10 : play'suit(6)=-10 test'hand: CALL calculate'points CALL calculate'toss IF dealer=1 THEN sign=1 ELSE sign=-1 toss'points=toss'points*sign total'points=hand'points+toss'points IF total'points<=optimal'score THEN GOTO next'try optimal'score=total'points toss'1=eh1 toss'2=eh2 next'try: NEXT eh2 NEXT eh1 RETURN evaluate'play: run'test: IF stack'pointer<3 THEN GOTO fifteen'test r1=play'card(stack'pointer-2) r2=play'card(stack'pointer-1) d=ABS(r1-r2) IF d=0 OR d>2 THEN GOTO fifteen'test IF r1>r2 THEN t=r2 : r2=r1 : r1=t IF d=1 THEN runner'1=r1-1 : runner'2=r2+1 IF d=2 THEN runner'1=r1+1 : runner'2=0 IF play'stack'total+runner'1>31 then runner'1=0 IF play'stack'total+runner'2>31 THEN runner'2=0 IF runner'1+runner'2=0 THEN GOTO fifteen'test y=0 : z=0 FOR x=1 TO 4 IF value(1,x)=runner'1 AND shdc(1,x)<10 THEN y=x IF value(1,x)=runner'2 AND shdc(1,x)<10 THEN z=x NEXT x IF y+z=0 THEN GOTO fifteen'test IF y#0 AND z=0 THEN x=y : GOTO play'computer'card IF y=0 AND z#0 THEN x=z : GOTO play'computer'card t1=runner'1+play'stack'total t2=runner'2+play'stack'total IF t1=15 OR t1=31 THEN x=y ELSE x=z GOTO play'computer'card fifteen'test: x=0 next'fifteen'test: x=x+1 IF x>4 THEN x=0 : GOTO pair'test IF shdc(1,x)>10 THEN GOTO next'fifteen'test play'card=value(1,x) IF play'card>10 THEN play'card=10 IF play'stack'total+play'card=15 THEN GOTO play'computer'card IF play'stack'total+play'card=31 THEN GOTO play'computer'card IF play'stack'total+play'card>31 THEN GOTO next'fifteen'test GOTO next'fifteen'test pair'test: IF stack'pointer<2 THEN GOTO last'resort x=x+1 IF x>4 THEN x=0 : GOTO last'resort IF shdc(1,x)>10 THEN GOTO pair'test play'card=value(1,x) IF play'stack'total+play'card>31 THEN GOTO pair'test IF value(1,x)=play'card(stack'pointer-1) THEN GOTO play'computer'card GOTO pair'test last'resort: x=0 first'scan=true next'computer'card: x=x+1 IF x>4 AND first'scan=false then x=1 IF x>4 THEN x=0 : GOTO play'computer'card IF shdc(1,x)>10 THEN GOTO next'computer'card play'card=value(1,x) IF play'card>10 THEN play'card=10 IF play'stack'total+play'card>31 THEN GOTO next'computer'card IF play'card=5 AND first'scan=true AND & computer'cards>1 AND stack'pointer=1 AND & x<4 THEN first'scan=false:GOTO next'computer'card play'computer'card: IF play'card>10 THEN play'card=10 RETURN show'discard: shdc(3,((player-1)*2)+1)=shdc(player,discard'1) value(3,((player-1)*2)+1)=value(player,discard'1) shdc(3,((player-1)*2)+2)=shdc(player,discard'2) value(3,((player-1)*2)+2)=value(player,discard'2) shdc(player,discard'1)=0 shdc(player,discard'2)=0 value(player,discard'1)=0 value(player,discard'1)=0 x=0 compress: x=x+1 : IF x=5 THEN GOTO show'crib compress'2: IF shdc(player,x)#0 THEN GOTO compress FOR y=x TO 5 shdc(player,y)=shdc(player,y+1) : value(player,y)=value(player,y+1) NEXT y shdc(player,6)=0 : value(player,6)=0 GOTO compress'2 show'crib: FOR pair=1 TO 6 ?TAB((player-1)*10+3+pair,4);SPACE(30); IF pair>4 THEN GOTO skip'discard IF player=1 THEN ?TAB((player-1)*10+3+pair,4);pair;"-";"*****";" of ";"********"; & ELSE ?TAB((player-1)*10+3+pair,4);pair;"-";card(value(player,pair));" of ";suit(shdc(player,pair)); skip'discard: NEXT pair FOR x=1 TO ((player-1)*2)+2 ?TAB(15+x,60);x;"-";"*****";" ** ";"********" NEXT x RETURN play'stack'scoring: ?TAB(12,40);play'stack'total; IF play'stack'total=15 THEN points(player)=points(player)+2:& CALL score'board : ?TAB((10*(player-1)+5),28);"Fifteen for 2!"; IF play'stack'total=31 THEN points(player)=points(player)+2:& human'go=1 : computer'go=1 :& CALL score'board : ?TAB((10*(player-1)+5),28);"Thiry One for 2!"; IF stack'pointer<4 THEN GOTO skip'4'of'kind IF play'card(stack'pointer)=play'card(stack'pointer-1) AND & play'card(stack'pointer-1)=play'card(stack'pointer-2) AND & play'card(stack'pointer-2)=play'card(stack'pointer-3) THEN & points(player)=points(player)+12 : & CALL score'board : ?TAB((10*(player-1)+5),28);"Four of a Kind for 12!";& : GOTO skip'2'of'kind skip'4'of'kind: IF stack'pointer<3 THEN GOTO skip'3'of'kind IF play'card(stack'pointer)=play'card(stack'pointer-1) AND & play'card(stack'pointer-1)=play'card(stack'pointer-2) THEN & points(player)=points(player)+6 : & CALL score'board : ?TAB((10*(player-1)+5),28);"Three of a Kind for 6!";& : GOTO skip'2'of'kind skip'3'of'kind: IF stack'pointer<2 THEN GOTO skip'2'of'kind IF play'card(stack'pointer)=play'card(stack'pointer-1) THEN & points(player)=points(player)+2 : & CALL score'board : ?TAB((10*(player-1)+5),28);"Two of a Kind for 2!"; skip'2'of'kind: IF stack'pointer<3 THEN GOTO stack'score'exit !*** check for run of 5 *** IF stack'pointer<5 THEN GOTO check'run'of'4 FOR r=stack'pointer-4 TO stack'pointer run'list(r)=play'card(r) NEXT r r=5 CALL check'for'run IF run'points=5 THEN GOTO stack'score'exit check'run'of'4: IF stack'pointer<4 THEN GOTO check'run'of'3 FOR r=stack'pointer-3 TO stack'pointer run'list(r)=play'card(r) NEXT r r=4 CALL check'for'run IF run'points=4 THEN GOTO stack'score'exit check'run'of'3: IF stack'pointer<3 THEN GOTO stack'score'exit FOR r=stack'pointer-2 TO stack'pointer run'list(r)=play'card(r) NEXT r r=3 CALL check'for'run stack'score'exit: RETURN calculate'points: hand'points=0 CALL fifteens hand'points=hand'points+points CALL runs hand'points=hand'points+points CALL flushes hand'points=hand'points+points CALL pairs'and'better hand'points=hand'points+points CALL nibs hand'points=hand'points+points RETURN calculate'toss: toss'points=0 v1=value(1,eh1) s1=shdc(1,eh1) v2=value(1,eh2) s2=shdc(1,eh2) IF v1=5 THEN toss'points=toss'points+2 IF v2=5 THEN toss'points=toss'points+2 IF v1=v2 THEN toss'points=toss'points+2 IF v1+v2=15 THEN toss'points=toss'points+2 IF v1=11 AND dealer=2 THEN toss'points=toss'points+.25 IF v2=11 AND dealer=2 THEN toss'points=toss'points+.25 IF s1=s2 THEN toss'points=toss'points+.25 IF ABS(v1-v2)=1 THEN toss'points=toss'points+1 IF ABS(v1-v2)=2 THEN toss'points=toss'points+.5 RETURN !-------------------------------------------------------------------------! ! Level 5 Subroutines !-------------------------------------------------------------------------! fifteens: points=0 fifteen'count=0 FOR x=5 TO 2 STEP -1 FOR y=1 TO 10 fifteen=0 FOR z=1 TO x IF tuple(x,y,z)=0 THEN GOTO tuple'done play'card=play'card(tuple(x,y,z)) IF play'card>10 AND play'card<=13 THEN play'card=10 fifteen=fifteen+play'card tuple'done: NEXT z IF fifteen=15 THEN fifteen'count=fifteen'count+1 NEXT y NEXT x points=fifteen'count*2 RETURN pairs'and'better: points=0 pair'count=0 FOR y=1 TO 10 pair'found=true FOR z=1 TO 2 IF pair'found=false THEN GOTO pair'tuple'done IF tuple(2,y,z)=0 THEN pair'found=false : & GOTO pair'tuple'done IF z=1 THEN prior=play'card(tuple(2,y,z)) :& GOTO pair'tuple'done IF play'card(tuple(2,y,z))#prior THEN pair'found=false pair'tuple'done: NEXT z IF pair'found=true THEN points=points+2 : pair'count=pair'count+1 NEXT y RETURN runs: run'5'count=0 run'4'count=0 run'3'count=0 points=0 run'points=0 runs'of'four=false FOR a=1 TO 5 run'list(a)=play'card(a) NEXT a r=5 CALL sort'run CALL check'run IF run'points=5 THEN run'5'count=1 : points=points+5 : GOTO runs'exit FOR a=1 TO 5 FOR b=1 TO 4 run'list(b)=play'card(tuple(4,a,b)) NEXT b r=4 CALL sort'run CALL check'run IF run'points=4 THEN run'4'count=run'4'count+1 : points=points+4 : & runs'of'four=true NEXT a IF runs'of'four=true THEN GOTO runs'exit FOR a=1 TO 10 FOR b=1 TO 3 run'list(b)=play'card(tuple(3,a,b)) NEXT b r=3 CALL sort'run CALL check'run IF run'points=3 THEN run'3'count=run'3'count+1 : points=points+run'points NEXT a runs'exit: RETURN flushes: flush'count=0 points=0 IF play'suit(1)=play'suit(2) AND play'suit(2)=play'suit(3) AND & play'suit(3)=play'suit(4) THEN points=4 ELSE RETURN IF play'suit(5)=play'suit(4) THEN points=5 IF player=3 AND points=4 THEN points=0 flush'count=points RETURN nibs: nibs'count=0 points=0 FOR x=1 TO 4 IF play'card(x)=11 AND play'suit(x)=play'suit(5) & THEN points=1 NEXT x nibs'count=points RETURN check'for'run: CALL sort'run CALL check'run IF run'points=0 THEN RETURN points(player)=points(player)+run'points CALL score'board ?TAB((10*(player-1)+5),28);"Run of ";run'points;" for ";run'points; RETURN !-------------------------------------------------------------------------! ! Level 6 Subroutines !-------------------------------------------------------------------------! sort'run: FOR y=1 TO r-1 FOR z=r TO 2 STEP -1 IF run'list(z)=value(2,z-1) THEN GOTO next'bubble tmp=value(2,z-1):value(2,z-1)=value(2,z):value(2,z)=tmp tmp=shdc(2,z-1):shdc(2,z-1)=shdc(2,z):shdc(2,z)=tmp next'bubble: NEXT z NEXT y RETURN