private void StartNew() { currentGameState = new GameState(GameType.Money); currentGameState.Stake = 1; currentGameState.Limit = 8; currentGameState.Board.InitializeBoard(BackgammonVariation.Standard); currentGameState.PlayerOnRoll = 0; currentGameState.PlayerOnTurn = 0; int[] startRoll = new int[2] { 0, 0 }; while (startRoll[0] == startRoll[1]) { startRoll[0] = random.Next(1, 7); startRoll[1] = random.Next(1, 7); } currentGameState.SetDice(startRoll[0], startRoll[1]); currentGameState.PlayerOnRoll = currentGameState.PlayerOnTurn = random.Next(2); SetTurn(currentGameState.PlayerOnTurn); if (currentGameState.PlayerOnTurn == 1) HandleAI(); else { unusedDice.AddRange(currentGameState.Dice); if (currentGameState.Dice[0] == currentGameState.Dice[1]) unusedDice.AddRange(currentGameState.Dice); legalPlays = currentGameState.Board.LegalPlays(currentGameState.PlayerOnRoll, currentGameState.Dice); originalGameState = currentGameState.Clone(); } UpdateControls(); }
public static GameState GnuBGIDToGameState(string gnubg_id, ref string error) { GameState gs = new GameState(GameType.Match); error = ""; if (!gnubg_id.Contains(':') || gnubg_id.Length != 27) // 14 (position id) + 12 (match id) + 1 (':') { error = "Invalid GNUBG ID."; return null; } string[] tmp = gnubg_id.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (tmp.Length != 2) return null; string pos_id = tmp[0]; string match_id = tmp[1]; if (match_id.Length != 12) { if (match_id.Length < 12) error = "Match ID length too short."; else error = "Match ID length too long."; return null; } Board board = BoardFromPositionID(pos_id, ref error); if (board == null) return null; gs.Board = board; List<bool> bits2 = new List<bool>(); List<bool> bits = new List<bool>(); foreach (char c in match_id) { if (!base64.Contains(c)) { error = "Match ID contains an invalid character."; return null; } int dec = base64.IndexOf(c); for (int i = 5; i >= 0; i--) { bits.Add((powers2[i] & dec) == powers2[i]); bool bit = (powers2[i] & dec) == powers2[i]; Console.Write(bit ? 1 : 0); if (bits.Count == 8) { bits.Reverse(); bits2.AddRange(bits); bits.Clear(); } } } // 1-4 cube int cube = BoolListToInt(bits2.Take(4).Reverse()); if (cube > 15) { error = "Invalid cube value."; return null; } // 5-6 cube owner int cube_owner = BoolListToInt(bits2.Skip(4).Take(2).Reverse()); if (cube_owner == 3) gs.CenterCube(); else gs.SetCube((int)Math.Pow(2, cube), cube_owner); // 7 player on roll gs.PlayerOnRoll = bits2[6] ? 1 : 0; // 8 crawford gs.IsCrawford = bits2[7]; // TODO, check if moneygame and this is set, return null // 9-11 game state, 000 for no game started, 001 for playing a game, 010 if the game is over, 011 if the game was resigned, or 100 if the game was ended by dropping a cube. int game_state = BoolListToInt(bits2.Skip(8).Take(2).Reverse()); if (game_state < 0 || game_state > 4) { error = "Invalid game state in Match ID."; return null; } // Do nothing with game state for now. // TODO: handle game_state this or not? // 12 player on turn gs.PlayerOnTurn = bits2[11] ? 1 : 0; // 13 double offered bool double_offered = bits2[12]; // 14-15 resignation offered int resign_value = BoolListToInt(bits2.Skip(13).Take(2).Reverse()); if (double_offered && resign_value > 0) { error = "Cannot offer double and resign at the same time."; return null; } int[] dice = new int[2]; // 16-18 first die dice[0] = BoolListToInt(bits2.Skip(15).Take(3).Reverse()); // 19-21 first die dice[1] = BoolListToInt(bits2.Skip(18).Take(3).Reverse()); if ((dice[0] == 0 && dice[1] != 0) || (dice[1] == 0 && dice[0] != 0) || dice[0] > 6 || dice[1] > 6) { error = "Invalid dice."; return null; } if (dice[0] > 0 && double_offered) { error = "Cannot offer double when dice have been thrown."; return null; } gs.SetDice(dice[0], dice[1]); if (double_offered) { gs.OfferType = OfferType.Double; gs.SetCube(2 * gs.Cube.Value, gs.Cube.Owner); // This is because GameState was designed so that on double offer, the cube value stored in gamestate is the actual offer value. In contrast, Gnubg stores the non-doubled value. } if (resign_value > 0) { gs.OfferType = OfferType.Resign; gs.ResignOfferValue = (ResignValue)resign_value; } // 22-36 match length, zero indicates a money game int match_length = BoolListToInt(bits2.Skip(21).Take(15).Reverse()); // TODO: What do we do with money game, ie. match length = 0? gs.MatchTo = match_length; // 37-51 player 0 score int score0 = BoolListToInt(bits2.Skip(36).Take(15).Reverse()); // 52-66 player 1 score int score1 = BoolListToInt(bits2.Skip(51).Take(15).Reverse()); gs.SetScore(score0, score1); /*Console.WriteLine(); foreach (bool bit in bits2) Console.Write(bit ? 1 : 0); Console.WriteLine();*/ //Console.WriteLine(gs); return gs; }
// TODO, unfinished. // See drawboard.c to see how FIBS ID handling is done in gnubg. // http://www.fibs.com/fibs_interface.html#board_state public static GameState FromFIBS(string id, ref string error) { GameState gs = new GameState(GameType.Match); error = ""; string[] s = id.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (s.Length != 53) return null; if (s[0] != "board") return null; //string[] player_names = new string[] { s[1], s[2] }; gs.SetName(0, s[1]); gs.SetName(1, s[2]); int match_length = 0; if (!int.TryParse(s[3], out match_length)) { error = "FIBS ID parsing error: Incorrect match length."; return null; } gs.MatchTo = match_length; int player0score, player1score; if (!int.TryParse(s[4], out player0score) || !int.TryParse(s[5], out player1score)) { error = "FIBS ID parsing error: Invalid match score."; return null; } gs.SetScore(player0score, player1score); int count; int[] total_counts = new int[2]; for (int p = 0; p < 26; p++) { if (!int.TryParse(s[6 + p], out count)) { error = "FIBS ID parsing error: Invalid board."; return null; } if (p == 0) { if (count > 0) return null; gs.Board.SetCaptured(1, -count); total_counts[1] += -count; } if (p == 25) { if (count < 0) return null; gs.Board.SetCaptured(0, count); total_counts[0] += count; } if (p >= 1 && p <= 24 && count != 0) { gs.Board.SetPoint(0, 6 + p - 1, count); total_counts[count > 0 ? 0 : 1] += Math.Abs(count); } } int turn; if (!int.TryParse(s[32], out turn)) return null; gs.PlayerOnTurn = (turn == -1) ? 0 : 1; int[] dice = new int[2]; if (!int.TryParse(s[33], out dice[0]) && !int.TryParse(s[34], out dice[1])) return null; if (dice[0] > 0 && dice[1] > 0) gs.SetDice(dice[0], dice[1]); int cube_value; if (!int.TryParse(s[35], out cube_value)) return null; return gs; }