// total_hints = the number of parseble move hints in the gnubg string, ie. 6/off contains one, bar/23 6/3 contains two private Move ParseMoveHint(string move_string, out int count, int total_hints, int[] dice, GameState gamestate) { // from/to // from/to(count) // 'bar'/to // 'bar'/to(count) // from/'off' // from/'off'(count) // from/to*/to* // from/to*/to*/to* // from/'off' // get count and remove it from the string count = 1; int count_start_index = move_string.IndexOf('('); if (count_start_index > 0) { int count_end_index = move_string.IndexOf(')'); count = int.Parse(move_string.Substring(count_start_index + 1, count_end_index - count_start_index - 1)); move_string = move_string.Substring(0, count_start_index); } string[] point_strings = move_string.Split(new char[] { '/' }); List<int> points = new List<int>(); HashSet<int> hitpoints = new HashSet<int>(); bool is_number; foreach (string point_string in point_strings) { bool hit = point_string.Contains("*"); string clean_point_string = point_string; if (hit) clean_point_string = clean_point_string.Replace("*", ""); is_number = true; foreach (char c in clean_point_string) if (!char.IsDigit(c)) { is_number = false; break; } if (is_number) { int point = int.Parse(clean_point_string) - 1; points.Add(point); if (hit) hitpoints.Add(point); } } if (point_strings[0][0] == 'b') points.Insert(0, 24); if (point_strings[point_strings.Length - 1][0] == 'o') points.Insert(points.Count, -1); // points should be sorted from highest to lowest at this point // calculate the missing way points if (dice[0] != dice[1]) { if (count == 1 && points.Count == 2) { int distance = points[0] - points[1]; int bigger_die = Math.Max(dice[0], dice[1]); int smaller_die = Math.Min(dice[0], dice[1]); if (distance > bigger_die)//(points[0] - points[1]) == (dice[0] + dice[1])) { if (distance == (dice[0] + dice[1])) { // Must not contain hits, because gnubg tells about the hit points seperately. if (gamestate.Board.PointCount(gamestate.PlayerOnRoll, points[0] - bigger_die) >= 0) points.Insert(0, (points[0] - bigger_die)); else points.Insert(0, (points[0] - smaller_die)); } else if (points[0] - bigger_die < smaller_die) // bearoff from 6 with 52, need first to do the smaller one. { if (gamestate.Board.PointCount(gamestate.PlayerOnRoll, points[0] - smaller_die) >= 0) // Was broken without this condition on _ _ 8x 2o 2o 2o with dice 43 points.Insert(0, (points[0] - smaller_die)); else if (gamestate.Board.PointCount(gamestate.PlayerOnRoll, points[0] - smaller_die) == -1) points.Insert(0, (points[0] - bigger_die)); else { } } else { throw new InvalidOperationException("Cannot handle this. Help!"); } /*if (gamestate.Board.PointCount(gamestate.PlayerOnRoll, points[0] - bigger_die) > -2) points.Insert(0, (points[0] - bigger_die)); else points.Insert(0, (points[0] - smaller_die));*/ } // This is for lonely bearoffs like |_ _ x _ x x| with 41, gnubg gives one of the hints as '4/off'. // We want atleast 2 chequers on the field because otherwise adding a waypoint is unnecessary inbetween. else if (total_hints == 1 && gamestate.Board.FinishedCount(gamestate.PlayerOnRoll) <= 13 && points[1] == -1 && (points[0] - smaller_die >= 0) && gamestate.Board.PointCount(gamestate.PlayerOnRoll, points[0] - smaller_die) >= 0 && gamestate.Board.LastChequer(gamestate.PlayerOnRoll) <= points[0]) { points.Insert(0, (points[0] - smaller_die)); } else { } } } else { for (int i = 0; i < points.Count - 1; i++) { // This was broken with bearoffs without this condition (ie. 6/off with 44, the below else condition should handle this situation) /*if (points[i + 1] > -1) {*/ int gaps = (points[i] - points[i + 1]) / dice[0]; int mod = (points[i] - points[i + 1]) % dice[0]; if (mod > 0) gaps++; if (gaps > 1) { for (int c = 1; c < gaps; c++) { points.Insert(i + 1, points[i] - dice[0]); i++; } } /*} else { int gaps = (points[i] - points[i + 1]) / dice[0]; int mod = (points[i] - points[i + 1]) % dice[0]; if (mod > 0) { for (int c = 0; c < gaps; c++) { points.Insert(i + 1, points[i] - dice[0]); i++; } } }*/ } } Move move = new Move(); foreach (int point in points) { if (hitpoints.Contains(point)) move.AddHitPoint(point); else move.AddPoint(point); } return move; }
void Form1_MouseClick(object sender, MouseEventArgs e) { if (currentGameState.PlayerOnTurn == 0 && !currentGameState.HasOffer && currentGameState.DiceRolled && legalPlays.Count > 0 && madeMoves.Count < legalPlays[0].Count) { BoundingChequer chequer = ClickTest(e.Location); if (chequer == null) { return; } int[] dice = currentGameState.Dice; int from = chequer.Slot; if (dice[0] != dice[1]) { int die = -1; if (unusedDice.Count == 2) { if (e.Button == MouseButtons.Left) { die = Math.Max(unusedDice[0], unusedDice[1]); } else if (e.Button == MouseButtons.Right) { die = Math.Min(unusedDice[0], unusedDice[1]); } else { return; } } else { die = unusedDice[0]; } int to = chequer.Slot - die; if (to < -1) { to = -1; } Move move = new Move(from, to); if (currentGameState.Board.IsLegalMove(currentGameState.PlayerOnRoll, move, die)) { if (to >= 0 && currentGameState.Board.PointCount(currentGameState.PlayerOnRoll, to) == -1) { move.AddHitPoint(to); } watch.Stop(); /*Stack<Move> s = new Stack<Move>(); * foreach (Move m in madeMoves.Reverse()) * s.Push(m.Clone());*/ List <TimedMove> h = new List <TimedMove>(); foreach (TimedMove m in moveHistory) { h.Add(new TimedMove(m)); } TimedMove tmove = new TimedMove(move, (int)watch.ElapsedMilliseconds, 0); moves.Add(new GameStateMoveAction(currentGameState.Clone(), originalGameState, watch.ElapsedMilliseconds, tmove, h)); currentGameState.Board.MakeMove(currentGameState.PlayerOnRoll, move); madeMoves.Push(move); moveHistory.Add(tmove); unusedDice.Remove(die); usedDice.Push(die); UpdateControls(); } else { if (unusedDice.Count == 2) { die = (dice[0] == die) ? dice[1] : dice[0]; to = chequer.Slot - die; if (to < -1) { to = -1; } move = new Move(from, to); if (currentGameState.Board.IsLegalMove(currentGameState.PlayerOnRoll, move, die)) { if (to >= 0 && currentGameState.Board.PointCount(currentGameState.PlayerOnRoll, to) == -1) { move.AddHitPoint(to); } watch.Stop(); /*Stack<Move> s = new Stack<Move>(); * foreach (Move m in madeMoves.Reverse()) * s.Push(m.Clone());*/ //moves.Add(new GameStateMoveAction(currentGameState.Clone(), watch.ElapsedMilliseconds, move.Clone(), s)); List <TimedMove> h = new List <TimedMove>(); foreach (TimedMove m in moveHistory) { h.Add(new TimedMove(m)); } TimedMove tmove = new TimedMove(move, (int)watch.ElapsedMilliseconds, 0); moves.Add(new GameStateMoveAction(currentGameState.Clone(), originalGameState, watch.ElapsedMilliseconds, tmove, h)); currentGameState.Board.MakeMove(currentGameState.PlayerOnRoll, move); madeMoves.Push(move); moveHistory.Add(tmove); unusedDice.Remove(die); usedDice.Push(die); UpdateControls(); } } //else //Console.WriteLine("Illegal move " + from + "/" + to); } } else { int to = chequer.Slot - dice[0]; if (to < -1) { to = -1; } Move move = new Move(from, to); if (currentGameState.Board.IsLegalMove(currentGameState.PlayerOnRoll, move, dice[0])) { if (to >= 0 && currentGameState.Board.PointCount(currentGameState.PlayerOnRoll, to) == -1) { move.AddHitPoint(to); } watch.Stop(); /*Stack<Move> s = new Stack<Move>(); * foreach (Move m in madeMoves.Reverse()) * s.Push(m.Clone()); * * moves.Add(new GameStateMoveAction(currentGameState.Clone(), watch.ElapsedMilliseconds, move.Clone(), s));*/ List <TimedMove> h = new List <TimedMove>(); foreach (TimedMove m in moveHistory) { h.Add(new TimedMove(m)); } TimedMove tmove = new TimedMove(move, (int)watch.ElapsedMilliseconds, 0); moves.Add(new GameStateMoveAction(currentGameState.Clone(), originalGameState, watch.ElapsedMilliseconds, tmove, h)); currentGameState.Board.MakeMove(currentGameState.PlayerOnRoll, move); madeMoves.Push(move); moveHistory.Add(tmove); unusedDice.Remove(dice[0]); usedDice.Push(dice[0]); UpdateControls(); } } // Fix problem when making an illegal move the watch resets itsefl } }
void Form1_MouseClick(object sender, MouseEventArgs e) { if (currentGameState.PlayerOnTurn == 0 && !currentGameState.HasOffer && currentGameState.DiceRolled && legalPlays.Count > 0 && madeMoves.Count < legalPlays[0].Count) { BoundingChequer chequer = ClickTest(e.Location); if (chequer == null) return; int[] dice = currentGameState.Dice; int from = chequer.Slot; if (dice[0] != dice[1]) { int die = -1; if (unusedDice.Count == 2) { if (e.Button == MouseButtons.Left) die = Math.Max(unusedDice[0], unusedDice[1]); else if (e.Button == MouseButtons.Right) die = Math.Min(unusedDice[0], unusedDice[1]); else return; } else die = unusedDice[0]; int to = chequer.Slot - die; if (to < -1) to = -1; Move move = new Move(from, to); if (currentGameState.Board.IsLegalMove(currentGameState.PlayerOnRoll, move, die)) { if (to >= 0 && currentGameState.Board.PointCount(currentGameState.PlayerOnRoll, to) == -1) move.AddHitPoint(to); watch.Stop(); /*Stack<Move> s = new Stack<Move>(); foreach (Move m in madeMoves.Reverse()) s.Push(m.Clone());*/ List<TimedMove> h = new List<TimedMove>(); foreach (TimedMove m in moveHistory) h.Add(new TimedMove(m)); TimedMove tmove = new TimedMove(move, (int)watch.ElapsedMilliseconds, 0); moves.Add(new GameStateMoveAction(currentGameState.Clone(), originalGameState, watch.ElapsedMilliseconds, tmove, h)); currentGameState.Board.MakeMove(currentGameState.PlayerOnRoll, move); madeMoves.Push(move); moveHistory.Add(tmove); unusedDice.Remove(die); usedDice.Push(die); UpdateControls(); } else { if (unusedDice.Count == 2) { die = (dice[0] == die) ? dice[1] : dice[0]; to = chequer.Slot - die; if (to < -1) to = -1; move = new Move(from, to); if (currentGameState.Board.IsLegalMove(currentGameState.PlayerOnRoll, move, die)) { if (to >= 0 && currentGameState.Board.PointCount(currentGameState.PlayerOnRoll, to) == -1) move.AddHitPoint(to); watch.Stop(); /*Stack<Move> s = new Stack<Move>(); foreach (Move m in madeMoves.Reverse()) s.Push(m.Clone());*/ //moves.Add(new GameStateMoveAction(currentGameState.Clone(), watch.ElapsedMilliseconds, move.Clone(), s)); List<TimedMove> h = new List<TimedMove>(); foreach (TimedMove m in moveHistory) h.Add(new TimedMove(m)); TimedMove tmove = new TimedMove(move, (int)watch.ElapsedMilliseconds, 0); moves.Add(new GameStateMoveAction(currentGameState.Clone(), originalGameState, watch.ElapsedMilliseconds, tmove, h)); currentGameState.Board.MakeMove(currentGameState.PlayerOnRoll, move); madeMoves.Push(move); moveHistory.Add(tmove); unusedDice.Remove(die); usedDice.Push(die); UpdateControls(); } } //else //Console.WriteLine("Illegal move " + from + "/" + to); } } else { int to = chequer.Slot - dice[0]; if (to < -1) to = -1; Move move = new Move(from, to); if (currentGameState.Board.IsLegalMove(currentGameState.PlayerOnRoll, move, dice[0])) { if (to >= 0 && currentGameState.Board.PointCount(currentGameState.PlayerOnRoll, to) == -1) move.AddHitPoint(to); watch.Stop(); /*Stack<Move> s = new Stack<Move>(); foreach (Move m in madeMoves.Reverse()) s.Push(m.Clone()); moves.Add(new GameStateMoveAction(currentGameState.Clone(), watch.ElapsedMilliseconds, move.Clone(), s));*/ List<TimedMove> h = new List<TimedMove>(); foreach (TimedMove m in moveHistory) h.Add(new TimedMove(m)); TimedMove tmove = new TimedMove(move, (int)watch.ElapsedMilliseconds, 0); moves.Add(new GameStateMoveAction(currentGameState.Clone(), originalGameState, watch.ElapsedMilliseconds, tmove, h)); currentGameState.Board.MakeMove(currentGameState.PlayerOnRoll, move); madeMoves.Push(move); moveHistory.Add(tmove); unusedDice.Remove(dice[0]); usedDice.Push(dice[0]); UpdateControls(); } } // Fix problem when making an illegal move the watch resets itsefl } }
// total_hints = the number of parseble move hints in the gnubg string, ie. 6/off contains one, bar/23 6/3 contains two private Move ParseMoveHint(string move_string, out int count, int total_hints, int[] dice, GameState gamestate) { // from/to // from/to(count) // 'bar'/to // 'bar'/to(count) // from/'off' // from/'off'(count) // from/to*/to* // from/to*/to*/to* // from/'off' // get count and remove it from the string count = 1; int count_start_index = move_string.IndexOf('('); if (count_start_index > 0) { int count_end_index = move_string.IndexOf(')'); count = int.Parse(move_string.Substring(count_start_index + 1, count_end_index - count_start_index - 1)); move_string = move_string.Substring(0, count_start_index); } string[] point_strings = move_string.Split(new char[] { '/' }); List <int> points = new List <int>(); HashSet <int> hitpoints = new HashSet <int>(); bool is_number; foreach (string point_string in point_strings) { bool hit = point_string.Contains("*"); string clean_point_string = point_string; if (hit) { clean_point_string = clean_point_string.Replace("*", ""); } is_number = true; foreach (char c in clean_point_string) { if (!char.IsDigit(c)) { is_number = false; break; } } if (is_number) { int point = int.Parse(clean_point_string) - 1; points.Add(point); if (hit) { hitpoints.Add(point); } } } if (point_strings[0][0] == 'b') { points.Insert(0, 24); } if (point_strings[point_strings.Length - 1][0] == 'o') { points.Insert(points.Count, -1); } // points should be sorted from highest to lowest at this point // calculate the missing way points if (dice[0] != dice[1]) { if (count == 1 && points.Count == 2) { int distance = points[0] - points[1]; int bigger_die = Math.Max(dice[0], dice[1]); int smaller_die = Math.Min(dice[0], dice[1]); if (distance > bigger_die) //(points[0] - points[1]) == (dice[0] + dice[1])) { if (distance == (dice[0] + dice[1])) { // Must not contain hits, because gnubg tells about the hit points seperately. if (gamestate.Board.PointCount(gamestate.PlayerOnRoll, points[0] - bigger_die) >= 0) { points.Insert(0, (points[0] - bigger_die)); } else { points.Insert(0, (points[0] - smaller_die)); } } else if (points[0] - bigger_die < smaller_die) // bearoff from 6 with 52, need first to do the smaller one. { if (gamestate.Board.PointCount(gamestate.PlayerOnRoll, points[0] - smaller_die) >= 0) // Was broken without this condition on _ _ 8x 2o 2o 2o with dice 43 { points.Insert(0, (points[0] - smaller_die)); } else if (gamestate.Board.PointCount(gamestate.PlayerOnRoll, points[0] - smaller_die) == -1) { points.Insert(0, (points[0] - bigger_die)); } else { } } else { throw new InvalidOperationException("Cannot handle this. Help!"); } /*if (gamestate.Board.PointCount(gamestate.PlayerOnRoll, points[0] - bigger_die) > -2) * points.Insert(0, (points[0] - bigger_die)); * else * points.Insert(0, (points[0] - smaller_die));*/ } // This is for lonely bearoffs like |_ _ x _ x x| with 41, gnubg gives one of the hints as '4/off'. // We want atleast 2 chequers on the field because otherwise adding a waypoint is unnecessary inbetween. else if (total_hints == 1 && gamestate.Board.FinishedCount(gamestate.PlayerOnRoll) <= 13 && points[1] == -1 && (points[0] - smaller_die >= 0) && gamestate.Board.PointCount(gamestate.PlayerOnRoll, points[0] - smaller_die) >= 0 && gamestate.Board.LastChequer(gamestate.PlayerOnRoll) <= points[0]) { points.Insert(0, (points[0] - smaller_die)); } else { } } } else { for (int i = 0; i < points.Count - 1; i++) { // This was broken with bearoffs without this condition (ie. 6/off with 44, the below else condition should handle this situation) /*if (points[i + 1] > -1) * {*/ int gaps = (points[i] - points[i + 1]) / dice[0]; int mod = (points[i] - points[i + 1]) % dice[0]; if (mod > 0) { gaps++; } if (gaps > 1) { for (int c = 1; c < gaps; c++) { points.Insert(i + 1, points[i] - dice[0]); i++; } } /*} * else * { * int gaps = (points[i] - points[i + 1]) / dice[0]; * int mod = (points[i] - points[i + 1]) % dice[0]; * if (mod > 0) * { * for (int c = 0; c < gaps; c++) * { * points.Insert(i + 1, points[i] - dice[0]); * i++; * } * } * }*/ } } Move move = new Move(); foreach (int point in points) { if (hitpoints.Contains(point)) { move.AddHitPoint(point); } else { move.AddPoint(point); } } return(move); }