/// <summary> /// Plays a single state of bingo, uses the balls specified in playing_balls. /// </summary> /// <param name="s"></param> static void Play(BingoGameState s, bool single_ball) { BingoGameInterfaces.BallDataInterface bdi; if (s.session_event.ball_data != null) { bdi = s.session_event.ball_data; } else { bdi = s.game_event.balls; } if (bdi == null) { return; } if (s.winning_cards == null) { return; } if (s.playing_cards.Count == 0) { return; } s.winning_cards.Clear(); int[] playing_balls; playing_balls = bdi.GetBalls(s.game.ignore_b_balls, s.game.ignore_i_balls, s.game.ignore_n_balls, s.game.ignore_g_balls, s.game.ignore_o_balls); s.starting_balls = playing_balls.Length; if (playing_balls.Length == 0) { if (!single_ball) { // draw ball should be written as wait mode.... and throw exceptions I suppose bdi.DrawBall(); bdi.WaitForBall(); playing_balls = bdi.GetBalls(s.game.ignore_b_balls, s.game.ignore_i_balls, s.game.ignore_n_balls, s.game.ignore_g_balls, s.game.ignore_o_balls); } else { return; // balls need to be setup ahead of time } } // so this plays a single game. lock (s.game) { if (playing_balls == null || playing_balls.Length == 0) { // Check to see if we are ignoring a column. If so, Length == 0 // is a legitimate length and we should continue calling balls. if ((!s.game.ignore_b_balls && !s.game.ignore_i_balls && !s.game.ignore_n_balls && !s.game.ignore_g_balls && !s.game.ignore_o_balls) || playing_balls == null) { // this is used to skip ball counts... return just 1 ball needed. s.bestaway = 1; return; } } int faces = s.playing_cards[0].card.GetLength(0); int columns = s.playing_cards[0].card.GetLength(2); do { // int pack_number = 0; int card_id = 0; s.game_event.playing_balls = playing_balls; s.bestaway = s.session_event.session.max_balls; s.bestwin = playing_balls.Length; foreach (PlayerPack pack in s.playing_packs) { int away; if (!pack.pack_info.flags.upickem) { continue; } int face_size = pack.pack_info.face_size; foreach (BingoCardState card in pack.Cards[s.game.game_ID]) { int mark_count = 0; BingoCardState.BingoCardPatternMarkInfo marks = card.GetCurrentMark(0); if (card.MarkNew(marks, faces, columns, playing_balls)) { mark_count++; } if (card.CheckCrazy(marks, face_size)) { away = 0; } else { away = face_size - marks.mark_index; } if (away < s.bestaway) { s.bestaway = away; } if (away == 0) { int ball_count = 0; for (int n = 0; n < playing_balls.Length; n++) { if (playing_balls[n] > 0) { ball_count++; } } // this card is a winner. // there is also a game.bestwin now // perhaps we should remove s.bestwin? // but I thik maybe we need a lock on the game? // { // this is in a ball-length check mode. if (card.BallCount < ball_count) { // had this as a message box... but ... should silence it... it is a flaw somewhere. Log.log("Sleeper bingo found on card " + card.unit_card_number + " in " + card.BallCount + " balls instead of " + playing_balls.Length + " balls"); } wininfo tmpwin; s.AddWinner(tmpwin = new wininfo(card_id, card)); if (Local.StoreToDatabase) { Local.bingo_tracking.StoreVerifiedCard(card.player.ID, card.pack.pack_info.ID, card.cardset_card_number, tmpwin.mask, card.card); } } } } } foreach (BingoGame game in s.game_event.games) { if (game.upick_size > 0) { /* * foreach( BingoCardState card in s.playing_cards ) * { * BingoCardState.BingoCardPatternMarkInfo cardmarks; * card.MarkNew( cardmarks = card.GetCurrentMark( 0 ), faces, columns, playing_balls ); * int away = game.upick_size - cardmarks.mark_index; * if( away < s.bestaway ) * s.bestaway = away; * } */ } else { foreach (Pattern pattern in game.patterns) { if (pattern.algorithm == PatternDescriptionTable.match_types.CrazyMultiCard || pattern.algorithm == PatternDescriptionTable.match_types.TopMiddleBottom || pattern.algorithm == PatternDescriptionTable.match_types.TopMiddleBottomCrazy ) { foreach (BingoCardState card in s.playing_cards) { foreach (Pattern sub_pattern in pattern.pattern_list) { int sub_pattern_index = pattern.pattern_list.IndexOf(sub_pattern); card.MarkNew(card.GetCurrentMark(sub_pattern_index), faces, columns, playing_balls); } } foreach (PlayerPack pack in s.playing_packs) { int away; if (check_pack(pack, game.ballset_number, pattern)) { s.AddWinner(new wininfo(card_id, pack.Cards[game.ballset_number][0])); away = 0; } else { if (pack.state != null) { away = pack.state[game.ballset_number].best_card_away; } else { away = 75; } } if (away < s.bestaway) { s.bestaway = away; } } } else if (pattern.algorithm == PatternDescriptionTable.match_types.CrazyMark) { foreach (BingoCardState card in s.playing_cards) { int away; faces = card.pack.pack_info.flags.double_action ? 2 : 1; if (!card.MarkNew(card.GetCurrentMark(0), faces, columns, playing_balls)) { continue; } if (card.marks[0].mark_index == pattern.repeat_count) { away = 0; } else { away = pattern.repeat_count - card.marks[0].mark_index; } if (away < s.bestaway) { s.bestaway = away; } } } if (pattern.algorithm == PatternDescriptionTable.match_types.ExternalJavaEngine) { foreach (BingoCardState card in s.playing_cards) { int away; faces = card.pack.pack_info.flags.double_action ? 2 : 1; if (check_single_card(card, s.game_event, s.game_event_index, playing_balls, faces, columns, 0)) { away = 0; } else { away = card.BestAway(); } if (away < s.bestaway) { s.bestaway = away; } // count is the count of balls that this card won in. // compared with one of the above matchings. // these are common to all prior code. if (away == 0) { int ball_count = 0; for (int n = 0; n < playing_balls.Length; n++) { if (playing_balls[n] > 0) { ball_count++; } } // this card is a winner. //if( s.game.game_number == 10 ) #if null if (false) { xperdex.classes.Log.log("winner on start:" + card.pack.start_card + " face:" + card); xperdex.classes.Log.log("player: " + card.player.card + " unit:" + card.pack.unit_number); xperdex.classes.Log.log("game " + s.game.game_number + " card:" + (card.unit_card_number) ); } #endif // there is also a game.bestwin now // perhaps we should remove s.bestwin? // but I thik maybe we need a lock on the game? // { // this is in a ball-length check mode. if (card.BallCount < ball_count) { // had this as a message box... but ... should silence it... it is a flaw somewhere. Log.log("Sleeper bingo found on card " + card.unit_card_number + " in " + card.BallCount + " balls instead of " + playing_balls.Length + " balls"); } wininfo tmpwin; s.AddWinner(tmpwin = new wininfo(card_id, card)); if (Local.StoreToDatabase) { Local.bingo_tracking.StoreVerifiedCard(card.player.ID, card.pack.pack_info.ID, card.cardset_card_number, tmpwin.mask, card.card); } } } //card_number++; } card_id++; } // end or cards else if ((pattern.algorithm == PatternDescriptionTable.match_types.Normal) || (pattern.algorithm == PatternDescriptionTable.match_types.TwoGroups) || (pattern.algorithm == PatternDescriptionTable.match_types.TwoGroupsPrime) || (pattern.algorithm == PatternDescriptionTable.match_types.TwoGroupsNoOver) || (pattern.algorithm == PatternDescriptionTable.match_types.TwoGroupsPrimeNoOver)) { foreach (BingoCardState card in s.playing_cards) { int away; faces = card.pack.pack_info.flags.double_action ? 2 : 1; if (check_single_card(card, s.game_event, s.game_event_index, playing_balls, faces, columns, 0)) { away = 0; } else { away = card.BestAway(); } if (away < s.bestaway) { s.bestaway = away; } // count is the count of balls that this card won in. // compared with one of the above matchings. // these are common to all prior code. if (away == 0) { int ball_count = 0; for (int n = 0; n < playing_balls.Length; n++) { if (playing_balls[n] > 0) { ball_count++; } } // this card is a winner. // there is also a game.bestwin now // perhaps we should remove s.bestwin? // but I thik maybe we need a lock on the game? // { // this is in a ball-length check mode. if (card.BallCount < ball_count) { // had this as a message box... but ... should silence it... it is a flaw somewhere. Log.log("Sleeper bingo found on card " + card.unit_card_number + " in " + card.BallCount + " balls instead of " + playing_balls.Length + " balls"); } wininfo tmpwin; s.AddWinner(tmpwin = new wininfo(card_id, card)); if (Local.StoreToDatabase) { Local.bingo_tracking.StoreVerifiedCard(card.player.ID, card.pack.pack_info.ID, card.cardset_card_number, tmpwin.mask, card.card); } } } //card_number++; } card_id++; } // end or cards } } } if (s.bestwincount == 0) { if (!single_ball) { // no cards I guess... somehow we called all balls and got no winners. int maxBallsInPlay = s.session_event.session.max_balls - ((s.game.ignore_b_balls) ? 15 : 0) - ((s.game.ignore_i_balls) ? 15 : 0) - ((s.game.ignore_n_balls) ? 15 : 0) - ((s.game.ignore_g_balls) ? 15 : 0) - ((s.game.ignore_o_balls) ? 15 : 0); //if( playing_balls != null && playing_balls.Length == s.session_event.session.max_balls ) if (playing_balls != null && playing_balls.Length == maxBallsInPlay) { break; } // need at least this many more balls anyhow... for (int skip = 0; skip < s.bestaway; skip++) { bdi.DrawBall(); bdi.WaitForBall(); } playing_balls = bdi.GetBalls(s.game.ignore_b_balls, s.game.ignore_i_balls, s.game.ignore_n_balls, s.game.ignore_g_balls, s.game.ignore_o_balls); } } else { break; } } // end for players while(!single_ball); if (!s.game.progressive) { bdi.DropBalls(); // game finished? } } if (s.bestwincount > 0) { // this bit of code is run // after all players and all cards have been played // we compute stats for the game. CountStarburst(s); CountHotball(ref s, playing_balls); if (s.bestwin <= playing_balls.Length) { lock (s.game_event) { s.game_event.wins += s.bestwincount; //s.game_event.best_wins[s.bestwin] += s.bestwincount; } } } s.game_event.playing_balls = playing_balls; // certain modes don't set s.game if (s.game != null) { //Local.bingo_tracking.SaveWinners( s.wining_cards ); //Local.bingo_tracking.CloseGame(); s.game.playing = false; // all done playign this game... all stats updates appropriately. } }
// double action determines whether card[X,,] goes from 0-0 or 0-1 (triple action? 0-2?) // check one card, get the best mask, and the best count_away // return the number of balls in ball array it won on. public static bool check_single_card( BingoCardState card , BingoGameEvent game_event , int game_index , int[] playing_balls , int faces , int columns , int pattern_index ) { int mark_count = 0; if (card.pack.pack_info.flags.big3) { card.CheckBig3(card.marks[0]); } else { //foreach( BingoGame game in game_event.games ) BingoGame game = game_event.games[game_index]; { foreach (Pattern pattern in game.patterns) { BingoCardState.BingoCardPatternMarkInfo marks = card.GetCurrentMark(pattern_index); switch (pattern.algorithm) { case PatternDescriptionTable.match_types.ExternalJavaEngine: break; default: if (card.MarkNew(marks, faces, columns, playing_balls)) { mark_count++; } break; } } } if (mark_count == 0) { return(false); } { // get last marked cardmask //foreach( BingoGame game in game_event.games ) { if (game.patterns[0].algorithm == PatternDescriptionTable.match_types.CrazyMark) { return(card.CheckCrazy(card.marks[0], game.patterns[0].repeat_count)); } else if (game.patterns[0].algorithm == PatternDescriptionTable.match_types.ExternalJavaEngine) { //return } else { List <int> patterns = game.pattern_list.pattern_bitmask_list; //foreach ( int check_mask in patterns ) { if (card.CheckPattern(card.marks[0], patterns)) { card.WinningGame = game; card.WinningGameEvent = game_event; return(true); } } // end of foreach( pattern ) } } } } return(false); }