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.