Friday 31 March 2023

"Cribbage" in Microsoft BASIC by Sheppard Yarrow (1979)


I was working on trying to port to Micro Color BASIC "Cribbage" in Microsoft BASIC. The program was ported to MS BASIC by Steven Williams from Sheppard Yarrow's original source from Creative Computing (May 1979) and then published in David Ahl' Big Computer Games book (1984). I can't play Cribbage, but my volunteer tester, George Phillips from over on the MC-10 Facebook group, told me it couldn't score runs properly. So I combed the code for typos, compared the original Creative Computing listing and the MS version.  The only major typo I could find was in line 560 which read:

540 C(1,J)=M(I1,J)
550 C(2,J)=M(I2,J)
560 C(3,J)=M(I3,J)
570 C(4,J)=Y(I4,J)

It should have read:

540 C(1,J)=M(I1,J)
550 C(2,J)=M(I2,J)
560 C(3,J)=Y(I3,J)
570 C(4,J)=Y(I4,J)

The first 2 cards are the computer's discards being assigned to C() from M() done at lines 540 and 550 and the second 2 discards from you are done at line 560 and 570.  These make up the "crib" and George reported that the crib was messed up.  So, I looked and noticed the asymmetric distribution between the M()s and Y()s being assigned to C().  

But besides that typo and a multitude of improperly closed FOR/NEXT loops (which I fixed) I couldn't seem to get the runs search subroutines to work.

So I began digging deep into these subroutines by creating a test-bed routine for just the 3 run subroutine and discovered it was definitely not working. The program has to figure out complex runs like 4,3,2,2,2, which give you 3 separate 3 runs, and the like. Yarrow obviously felt he had an algorithm that worked, but I couldn't get the 3 run subroutine to recognize even a simple run fed to it directly in my test-bed. How could a game published in Creative Computing, and then David Ahl's Big Computer Games in BASIC (conceivably another million seller) be so broken?  How could all 3 subroutines break at once?

Well I think I finally cracked it. The sorting before doing the run check subroutines (5,4 or 3), says in the REM comments that it orders in ascending sequence, but it actually does descending. When I turn my test sequences around, the subroutine worked!!!!!!!

George was also doing some looking at the code.  As he commented,
Yeah, you'd think that if it had a flaw it would be a subtle one. I took a look at the original code. It looks like it is kinda doing the right thing. Sorting the cards and then looking for a sequence of increasing values. That should find simple runs though it is far from obvious that it handles double runs and the like.
I'd come to the same generals sense of the subroutines. But when I looked at the sorting routine I began to wonder if it really was ordering the list of cards (by values 13-1) in an ascending way.  From test input, and the output of the test-bed it looked like the cards were actually going into the subroutine in a descending sequence.  You can try it out yourself.

Here's my test-bed routine for the 3 run search subroutine:

10 CLS:S(1)=1:S(2)=2:S(3)=3:S(4)=3:REM** THESE ARE READ FROM DATA IN THE ORIGINAL ONLY ONCE
20 REM** INPUT CARDS
5375 FORC1=1TO5:PRINT"CARD"C1;:INPUTM$:W(C1,4)=VAL(M$):NEXT
5380 FORC1=1TO5:PRINTW(C1,4);:NEXT:PRINT:PRINT:REM** PRINT CARD SEQUENCE
5400 GOSUB5700
5410 PRINT"END":END
5700 REM** CHECK FOR A 3 CARD RUN
5710 FORL=1TO3
5720 D=W(L,4)-S(1)
5730 FORI=1TO3
5740 S(I)=S(I)+D
5750 NEXTI
5760 FORI=1TO3
5770 PRINTW(L+I-1,4),S(I):IFW(L+I-1,4)<>S(I)THEN5820
5780 NEXTI
5790 REM** A 3 CARD RUN
5800 P=P+S(4):REM** INCREMENT SCORE
5810 PRINT"RUN FOUND":RETURN
5820 NEXTL
5830 PRINT"NO RUN FOUND":RETURN
Here's the original sorting routine:
5280 REM** SORT HAND INTO ASCENDING
5290 REM  SEQUENCE
5300 FORI=1TO5
5310 FORJ=1TO5
5320 IFW(I,4)<=W(J,4)THEN5360
5330 K=W(I,4)
5340 W(I,4)=W(J,4)
5350 W(J,4)=K
5360 NEXTJ
5370 NEXTI
But if I reversed the sorting (at least by my updated test-bed routine above) it worked!
5280 REM** SORT HAND INTO ASCENDING
5290 REM  SEQUENCE
5300 FORI=1TO5
5310 FORJ=1TO5
5320 IFW(I,4)>=W(J,4)THEN5360
5330 K=W(I,4)
5340 W(I,4)=W(J,4)
5350 W(J,4)=K
5360 NEXTJ
5370 NEXTI
Try an card order like 2,2,3,4,12 or 2,10,11,12,12

I'll let you folks know with an addendum here whether the reversal fixes all of the search routines and whether it is actually able to find double runs and the like.

If folks want to help, the current "fixed" version can be tried here using the online MC-10 Emulator by Mike Tinnes.  Select CRIBBAGE from the Cassette menu and then type RUN and hit Enter in the main (green) emulator screen:


I also, on the recommendation of  George, added in some "Press ENTER to continue" prompts and the ability to type "Y" at most prompts to have your cards re-displayed.  And I altered most PRINT statements to use my 32 character screen width word wrap routine.


ADDENDUM

George told me that it seems to recognize runs now.  Including double runs. Here's one hand he said it scored correctly:


Hopefully, we've got all the major bugs out now....

Nope, Spoke too soon.  Looked through subsequent issues of Creative Computing and found a correction by Yarrow in Aug 1979 issue:


I implemented it for the Microsoft version as follows:
2710 IFC<>1THEN2840
2705 IFM5<>1THEN2840:REM CORRECTION CC AUG 1979
2720 FORJ9=1TO4

I also found this discussion in the Oct 1979 volume:

CRIBBAGE Debugged 

Dear Editor: 

Several readers have contacted me concerning my 
CRIBBAGE program (May 1979) and brought to light three 
problems. The first is a real bug: the computer will on occa¬ 
sion after a “GO” situation, replay a card it has already 
played. The correction involves the addition of a line of code 
as follows: 

2605 IF M5 <>1 THEN 2730 

The second problem is an irrelevant bug in that line 2710 
should be 19=VC(B9,1). The lijie as currently written causes 
no problem, and may be entirely eliminated. This section of 
code is only used when the computer’s hand consists of four 
5’s. The correction will cause the computer to play the first 5 
in its hand; leaving the line as is or removing it causes the 
computer to play the fourth 5 in its hand. 

The third problem turns out to be a bug which will appear 
or not appear depending on how a particular BASIC language 
processes FOR/NEXT loops. Consider the following 
instructions: 

3210 FORK=lTOI 
3220 FOR L=K+1 TO I 
...
3270 NEXTL 
3280 NEXTK 

IBM BASIC evaluates the limit of the FOR/NEXT loop 
before processing the loop; therefore, when K reaches the 
value of I the FOR/NEXT loop on L will not be executed 
because I + 1 is greater than I to start. On the TRS-80 
however, BASIC evaluates the limit of the FOR/NEXT loop 
at the end of the loop and therefore will execute the loop with 
L equal to 1+1 which causes all sorts of problems during the 
play of the hand. To eliminate this "bug" (?) change line 3220 
to read FOR L=K TO I. 

I couldn't find any mention of the correction of the problem with the sort routine I discuss above.  Which is weird.  But I did notice a reference to the game on a database of video games site: https://videogamegeek.com/videogame/247086/cribbage-1979

No one has rated the game on that site, which makes me wonder whether its "brokenness" meant that people were excited by the game, but ultimately disappointed by its performance and few ever really played it.  However, that speculation is frustrated somewhat by another reference I found in Czech computer magazine from back in the day:


A little Google translate done on the article reveals that the bulk of it is simply explaining the rules of the Cribbage to a non-English speaking audience who are unfamiliar with the game.  However, there is a small discussion at the end of the Microsoft version:
-------------------------------------------------- -------
*** PC version specifics ***
-------------------------------------------------- --------
At the "Remove" prompt, enter a number between 1 and 52 in this space
will remove the package for the cards. The cards in your hand are in the game
numbered 1 - 6, for inputs use the numbers, not in card values. If you are forced to say "GO" write "go" or "GO" instead of numbers and cards.
The computer shuffles and deals the cards, generates a reversed card,
keep track of the score and correctness of the points obtained during the game. He won't let
you go past 31, but he does not check if you have a card that
you could play If you miscalculate the value in your hand or
in the game, you don't have to doubt that the computer calls out mercilessly
"MUGGINS".
The program uses a relatively simple strategy consisting of
the cards whose point total has the highest value are also held.
There are many more sophisticated strategies that you can play with
introduced in a book about card games. Here, however, there is too much
it didn't work out.
Nice game
TOPSOFT
Kralupy nad Vltava
1987
==============================

Mr. Vltava says "Nice Game" at the end of his review. So obviously there must have been a working version out there that didn't suffer from the catastrophic error of the reversed sorting routine.  But I can't find mention of a correction of this anywhere. But I can't see how the source as printed could do anything except reverse the order.  It's not a typo by me.  Here's the original article.

It kind of makes me question reality.  Maybe my MC-10 and its Micro Color BASIC are part of some parallel universe, in which sort routines work backwards?!  If anyone could shed light on this matter, I would really appreciate it if they could leave a comment and put my mind at ease.

No comments:

Post a Comment