Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

wlh99

macrumors 6502
Original poster
Feb 7, 2008
272
0
I’m working on a texas hold’em game. I have a method getEveryonesBet that goes through a round of betting, makes sure all the bets are equal, collects money, puts it in the pot. In that method I call:
Code:
–(float)getBetFromPlayer:(Player *)player
which asks a player for a bet and returns it. This worked fine in earlier versions of my program which were console based. Now that it is GUI based, and event based, execution stops while my program waits for getBetFromPlayer to return.
I have “solved” the problem by running in a thread, but I know that isn’t the way to do it, and instead I need to convert to an event based program flow. I’m stuck and looking for ideas. Since getBetFromPlayer is nested in a couple loops, the event driven code would get very complicated any way I can think of.
Here is getEveryonesBet:
Code:
-(void) getEveryonesBet {
    
    // get Everyone's initial bet
	lastBet = 0;
	currentBet = -1.0;

	// while bets are not square (all the same) ask the next player for a bet.
	int j = 0;
	int oneRound = NO; // to insure at least one round of betting completes
	while ( ( ![self betsAreSquare] ) || ( oneRound==NO )  ) { // while bets are not square (all the same) ask the next player for a bet.
		
	
        currentBet = [gameView getBetFromPlayer:[players objectAtIndex:j]];
		while (currentBet < lastBet) {		// make sure bet is at least as high as previous bet
			[gameView invalidBet:lastBet];
			currentBet = [gameView getBetFromPlayer:[players objectAtIndex:j]];
		}
		
		lastBet = currentBet;
		
		// update the money in the pot
		pot += lastBet;
		[gameView updatePot:pot];
		
		// subtract bet from player
		Player *player = ((Player *)[players objectAtIndex:j]);
		player.money -= lastBet;
		if (player.money < 0) {
			pot += player.money; // don't allow more  added to pot than player has
			player.money = 0;
			[gameView updatePot:pot];
		}
		[player display];

 		if ( (++j)==[players count]) {j = 0;oneRound=TRUE;} // loop back to player 0 until while loop is satisfied.       
	} //while loop
	
} // get everyones bet

The entire project is at code.google.com/wlhcards
 
Can we start not with the code that you are writing, but how the application will be used? So I double-click your application. What would I see on the screen? What actions could I take? What would happen after each action?
 
Can we start not with the code that you are writing, but how the application will be used? So I double-click your application. What would I see on the screen? What actions could I take? What would happen after each action?

I get what you are asking, but the determination of the action to take isn't a simple one-to-one relationship.

I will need to have data members to keep track of what player is betting, and at what point in the game we are. I'll need to determine if the bet meets the minimum bet, if it is a raise then make other players bet again etc. It seems that what is handled pretty simply in the while loop I posted earlier gets messy fast.

That said, I am roughing it out: (I write in comments first while I work out logic, then they become documentation later) And it isn't as bad as I suppose it could be.

Code:
// -(IBAction) gotBetFromPlayer (Player *) player
// is bet from player we expect?
		// if not throw error
// is bet valid?
		// if not throw error and rebet
// bet is valid
		// lastbet=currentbet
		// subtract money from player
		// update money in the pot
		// gameView updatePot
		// player display
// have all players bet?
		// if not advance to next player
//are all bets square?
		// if not advance to next player
		//if yes call next of:
				// deal 2 cards
				// deal flop
				// deal turn
				// deal river
				// determine winner

That above code would replace the core game code which now is:

Code:
		[self deal2cards];
		[self getEveryonesBet];
		[self dealFlop];
		[self getEveryonesBet];
		[self dealTurn];
		[self getEveryonesBet];
		[self dealRiver];
		[self getEveryonesBet];
		[self determineWinner];
 
You need to change anything where you are expecting user interaction from "active" to "passive". You need an internal data model that represents the interaction you are currently expecting (say player 1 is about to make a bet: this means all other players are expected to do nothing). Your even handler methods then transition your internal state between a series of well defined states (so in the event hander you transition player 1's state to the correct one for the bet or fold made and move the action to the next available plater and if any other player attempts to play out of turn you ignore that/beep). You don't have loops or methods that "get" input from the users.
 
It's working(more or less, still a few bugs), although it's ugly and very hard to follow. It's what I was trying to avoid.

Code:
-(void)gotBetFromPlayer:(Player *) player {
	NSLog(@"gotBetFromPlayer");


// is bet from player we expect?
if (player != [players objectAtIndex:bettingPlayer]) {
	// if not throw error

	NSLog(@"Error! wrong player Bet!");
	
} else {
	// is bet valid?
	if (player.currentBet>=lastBet) {
		currentBet = player.currentBet;
		lastBet = currentBet;
		
		// subtract money from player
		if ( lastBet < player.money ) { // dont put more money in pot than player has
			player.money -= lastBet;
			pot += lastBet;
		} else {
			pot += player.money;
			player.money = 0;
		}
		[gameView updatePot:pot]; // display new pot amount	
		[player display];	

	
		// have all players bet?
		
		if ((++bettingPlayer)==[players count]) {
			// all players have bet
			bettingPlayer = 0;
			allPlayersBet = YES;
		}
		
		if (allPlayersBet == YES) {
			if ([self betsAreSquare]) { // if all bets are square
				allPlayersBet = NO;
				bettingPlayer = 0;
				lastBet = -1.0;
				switch (nextStep) {
					case wDealFlop:
						[self dealFlop];
						[gameView getBetFromPlayer:[players objectAtIndex:bettingPlayer]];
						nextStep++;
						break;
					case wDealTurn:
						[self dealTurn];
						[gameView getBetFromPlayer:[players objectAtIndex:bettingPlayer]];
						nextStep++;
						break;
					case wDealRiver:
						[self dealRiver];
						[gameView getBetFromPlayer:[players objectAtIndex:bettingPlayer]];
						nextStep++;
						break;
					case wDetermineWinner:
						[self determineWinner];
						[self endHand];
						nextStep++;
						break;
					default:
						break;
				}
				NSLog(@"nextStep = %d",nextStep);
				
				if (nextStep == wHandOver) { // case of end of Hand
					
					NSLog(@"End of Hand");
					currentBet = -1.0;
					lastBet = -1.0;
					bettingPlayer = 0;
					nextStep = wDeal2Cards;
					[self deal2cards];
					nextStep += 1;
					[gameView getBetFromPlayer:[players objectAtIndex:0]];
					
				}
		} // if all bets are square
			
	} // all players have bet
		
	[gameView getBetFromPlayer:[players objectAtIndex:bettingPlayer]];

		
		
	} else { // valid bet
		// this is not a valid bet
		[gameView invalidBet:lastBet];
}
 
	
	
}

	
	
	

} // gotBetFromPlayer
 
I have a few suggestions to make.

First of all at the top:

Code:
// is bet from player we expect?
if (player != [players objectAtIndex:bettingPlayer]) {
	// if not throw error

	NSLog(@"Error! wrong player Bet!");
	
}

Why not put a return; statement after the nslog? The only code that gets executed is your else statement if your condition fails.
You can save your self a set of brackets and some indentation.

And second of all, maybe you can separate the gotBetFromPlayer method's guts a bit more.

I think you could make that method only deal with a players bet. Perhaps have another method to deal with checking if all players have bet. After all, your method name seems to only deal with one player only.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.