This is Cribbage.m in view mode; [Download] [Up]
// indent:4 tabsize:4 font:fixed-width
//
// The Cribbage Solitaire module.
//
// Copyright 1994 by David Fedchenko. All rights reserved.
//
#import "Cribbage.h"
#import "CribbagePrefs.h"
#import "localstrings.h"
#import "CribDrawDelegate.h"
#import "CribLayoutDelegate.h"
@implementation Cribbage
//--------------------------------------------------------------------------
// - startGame:
//
// returns: (id) self
//
// Start a new game. Get confirmation from the user before aborting a
// game in progress.
//--------------------------------------------------------------------------
- startGame:sender
{
[super startGame:sender];
return [self setupGame:YES];
}
//--------------------------------------------------------------------------
// - restartGame:
//
// returns: (id) self
//
// Restart the game in progress.
//--------------------------------------------------------------------------
- restartGame:sender
{
[super restartGame:sender];
return [self setupGame:NO];
}
//--------------------------------------------------------------------------
// - setupGame:
//
// returns: (id) self
//
// Setup a new game. If "redeal" is true, deal a new deck, otherwise
// use the same cards as the previous game.
//--------------------------------------------------------------------------
- setupGame:(BOOL)redeal
{
id idDrawPile;
id idLayouts[16];
int i;
[gameWindow disableFlushWindow];
[self loadCardArray:idLayouts];
for (i = 0; i < 16; i++)
{
[idLayouts[i] setBackgroundColor:desktopColor];
[idLayouts[i] setCardSize:cardSize];
[idLayouts[i] setDelegate:idLayoutDelegate];
[[idLayouts[i] cardPile] freeCards];
[idLayouts[i] display];
}
[idLayoutDelegate setStrict:[prefs strict]];
[idLayoutDelegate setDrawPileView:idDraw];
[idDraw setBackgroundColor:desktopColor];
[idDraw setCardSize:cardSize];
[idDraw setDelegate:idDrawDelegate];
idDrawPile = [idDraw cardPile];
[idDrawPile freeCards];
if (redeal)
{
[[idDrawPile addDeck] shuffle];
// make a copy of the CardPile for restart option
if (!idPrevDeck)
{
idPrevDeck = [[CardPile allocFromZone:[self zone]]
initForCardSize:cardSize];
}
else
{
[idPrevDeck freeCards];
[idPrevDeck setCardSize:cardSize];
}
[idPrevDeck addCopyOfPile:idDrawPile];
}
else
{
if (idPrevDeck)
{
// copy the saved deck back to the game deck
[idPrevDeck setCardSize:cardSize];
[idDrawPile addCopyOfPile:idPrevDeck];
}
else
{
// this shouldn't happen, but just in case...
[[[idDrawPile freeCards] addDeck] shuffle];
}
}
[[idDrawPile cardAt:CS_TOP] flip];
[idScore1 setStringValue:""];
[idScore2 setStringValue:""];
[idScore3 setStringValue:""];
[idScore4 setStringValue:""];
[idScore5 setStringValue:""];
[idScore6 setStringValue:""];
[idScore7 setStringValue:""];
[idScore8 setStringValue:""];
[idFinalScore setStringValue:""];
[idHeelsScore setStringValue:""];
[gameWindow display];
[gameWindow reenableFlushWindow];
[gameWindow flushWindow];
[gameWindow makeKeyAndOrderFront:self];
return self;
}
//--------------------------------------------------------------------------
// - checkForWin
//
// returns: (id) self
//
// First make sure the tableau is filled and if it is, go score each hand.
// Each hand is loaded into a scoring array along with the card on top of
// the draw pile and then scored as a cribbage hand. A winning layout will
// total 61 or more for all 8 hands.
//--------------------------------------------------------------------------
- checkForWin
{
id idCards[16];
id idHand[5];
id idStarter = [[idDraw cardPile] cardAt:CS_TOP];
int i;
int j = 0;
int hand[8];
int total = 0;
if ([[idDraw cardPile] cardCount] != 36)
{
return self;
}
[self loadCardArray:idCards];
for (i = 0; i < 16 ; i++)
{
idCards[i] = [[idCards[i] cardPile] cardAt:CS_TOP];
}
if ([idStarter value] == CS_JACK)
{
[idHeelsScore setIntValue:2];
total += 2;
}
else
{
[idHeelsScore setIntValue:0];
}
idHand[0] = idStarter;
for (i = 0; i < 16; i += 4)
{
idHand[1] = idCards[i];
idHand[2] = idCards[i + 1];
idHand[3] = idCards[i + 2];
idHand[4] = idCards[i + 3];
hand[j] = [self scoreHand:idHand];
total += hand[j];
j++;
}
for (i = 0; i < 4; i++)
{
idHand[1] = idCards[i];
idHand[2] = idCards[i + 4];
idHand[3] = idCards[i + 8];
idHand[4] = idCards[i + 12];
hand[j] = [self scoreHand:idHand];
total += hand[j];
j++;
}
[idScore1 setIntValue:hand[0]];
[idScore2 setIntValue:hand[1]];
[idScore3 setIntValue:hand[2]];
[idScore4 setIntValue:hand[3]];
[idScore5 setIntValue:hand[4]];
[idScore6 setIntValue:hand[5]];
[idScore7 setIntValue:hand[6]];
[idScore8 setIntValue:hand[7]];
[idFinalScore setIntValue:total];
[prefs setHighScore:total];
if (total >= 61)
{
[self win];
}
return self;
}
//--------------------------------------------------------------------------
// - gameWindow
//
// returns: (id) gameWindow
//
// Returns the window the game is being played in so updating can happen
// cleanly when cards are being moved around.
//--------------------------------------------------------------------------
- gameWindow
{
return gameWindow;
}
//--------------------------------------------------------------------------
// - clickShift:
//
// returns: (id) self
//
// The action for the arrow buttons which shift the cards around in the
// tableau. This is really only useful when playing in strict mode so
// all sides of the played cards can be made available.
//--------------------------------------------------------------------------
- clickShift:sender
{
int i;
int j;
int c = 0;
id idCards[16];
int vStart;
int hStart;
int vEnd;
int hEnd;
int vStep;
int hStep;
int c1;
int c2;
BOOL fVert = YES;
vStart = 0; vStep = 1;
hStart = 0; hStep = 1;
switch ([sender tag])
{
case 0: // Up
fVert = YES;
break;
case 1: // Right
hStart = 3; hStep = -1;
fVert = NO;
break;
case 2: // Down
vStart = 3; vStep = -1;
fVert = YES;
break;
case 3: // Left
fVert = NO;
break;
default:
break;
}
[self loadCardArray:idCards];
for (i = 0; i < 4; i++)
{
c += (fVert) ? [[idCards[vStart * 4 + i] cardPile] cardCount]
: [[idCards[i * 4 + hStart] cardPile] cardCount];
}
if (c)
{
return self;
}
vEnd = 3 - vStart + ((fVert) ? 0 : vStep);
hEnd = 3 - hStart + ((fVert) ? hStep : 0);
for (i = vStart; i != vEnd; i += vStep)
{
for (j = hStart; j != hEnd; j += hStep)
{
c1 = i * 4 + j;
c2 = c1 + ((fVert) ? vStep * 4 : hStep);
[[idCards[c1] cardPile] empty];
[[idCards[c1] cardPile] addPile:[idCards[c2] cardPile]];
}
}
for (i = 0; i < 4; i++)
{
if (fVert)
{
[[idCards[(3 - vStart) * 4 + i] cardPile] empty];
}
else
{
[[idCards[i * 4 + (3 - hStart)] cardPile] empty];
}
}
[gameWindow display];
return self;
}
//--------------------------------------------------------------------------
// - loadCardArray:
//
// returns: (id) self
//
// Used by several other methods to map the cardViews into an array for
// easier manipulations.
//--------------------------------------------------------------------------
- loadCardArray:(id [])array
{
array[0] = idLayout11;
array[1] = idLayout12;
array[2] = idLayout13;
array[3] = idLayout14;
array[4] = idLayout21;
array[5] = idLayout22;
array[6] = idLayout23;
array[7] = idLayout24;
array[8] = idLayout31;
array[9] = idLayout32;
array[10] = idLayout33;
array[11] = idLayout34;
array[12] = idLayout41;
array[13] = idLayout42;
array[14] = idLayout43;
array[15] = idLayout44;
return self;
}
//--------------------------------------------------------------------------
// - scoreHand:
//
// returns: (int) score
//
// The main workhorse of this game. This scores a single hand in which the
// starter is in the 0 position of the array. It scores flush, 15s, and
// runs/pairs in seperate passes.
//--------------------------------------------------------------------------
-(int) scoreHand:(id [])idHand
{
int score = 0;
CardSuit cs = CS_LOWVALUE;
int c = 0;
int i;
int gridA[15] = {0};
int gridB[15] = {0};
int * pGridA;
int * pGridB;
int count[13] = {0};
int values[5] = {0, 0, 2, 6, 12};
int length = 0;
int run = -1;
int runscore;
// First check for a flush
for (i = 1; i < 5; i++)
{
if (i == 1)
{
cs = [idHand[1] suit];
}
c += ([idHand[i] suit] == cs);
// check for "his knobs"
if (([idHand[i] value] == CS_JACK) &&
([idHand[i] suit] == [idHand[0] suit]))
{
score++;
}
}
if (c == 4)
{
c += ([idHand[0] suit] == cs);
}
else
{
c = 0;
}
score += c;
// Now figure out the 15s
for (c = 0; c < 5; c++)
{
i = [idHand[c] value] + 1;
if (i > 10)
{
i = 10;
}
pGridB = &gridB[i];
gridB[i - 1]++;
pGridA = gridA;
while (i < 15)
{
*pGridB++ += *pGridA++;
i++;
}
for (i = 0; i < 15; i++)
{
gridA[i] = gridB[i];
}
}
score += gridA[14] * 2;
// Now look for pairs and runs
for (i = 0; i < 5; i++)
{
count[[idHand[i] value]]++;
}
for (i = 0; i < 13; i++)
{
score += values[count[i]];
if (run == -1)
{
if (count[i])
{
length++;
}
else
{
if (length > 2)
{
run = i - length;
}
else
{
length = 0;
}
}
}
}
if (run == -1 && length > 2)
{
run = i - length;
}
if (run != -1)
{
runscore = length;
for (i = 0; i < length; i++)
{
runscore *= count[run + i];
}
score += runscore;
}
return score;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.