Esempio n. 1
0
        public EvaluationInfo Eval(GameState gamestate)
        {
            //Set2PlyEvaluation();

            SetGameState(gamestate);

            string s = Command("eval");

            int start = s.IndexOf("static:") + "static:".Length;//"2 ply:") + "2 ply:".Length;
            int end = s.IndexOf('\r', start);

            s = s.Substring(start, end - start);

            string[] t = s.Trim().Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);

            EvaluationInfo eval_info = new EvaluationInfo()
            {
                Win = double.Parse(t[0]),
                WinGammon = double.Parse(t[1]),
                WinBackgammon = double.Parse(t[2]),
                LoseGammon = double.Parse(t[3]),
                LoseBackgammon = double.Parse(t[4])
            };

            eval_info.Lose = 1.0 - eval_info.Win;

            //Set0PlyEvaluation(0.005);

            return eval_info;
        }
Esempio n. 2
0
 public DoubleHint DoubleHint(GameState gamestate)
 {
     return GetDoubleHint(gamestate);//new DoubleHint() { Action = ParseDoubleAction(Hint(gamestate)) };
 }
Esempio n. 3
0
 public DoubleResponseHint DoubleResponseHint(GameState gamestate)
 {
     return ParseDoubleResponse(Hint(gamestate));
 }
Esempio n. 4
0
        // 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;
        }
Esempio n. 5
0
        // 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;
        }
Esempio n. 6
0
        public PlayHint PlayHint(GameState gamestate)
        {
            List<PlayHint> play_hints = PlayHint(gamestate, 1);
            if (play_hints == null)
                return null;

            return play_hints[0];
        }
Esempio n. 7
0
        /// <summary>
        /// Doesn't use the match id for setting up the position.
        /// </summary>
        /// <param name="gamestate"></param>
        public void SetGameState(GameState gamestate)
        {
            bool set_cube = true;
            if (gamestate.GameType == GameType.Money)
            {
                int wager = gamestate.Stake * gamestate.Cube.Value;
                bool capped = (wager >= gamestate.Limit);
                // Evaluate as a single point match if the game is capped or the cube is centered (jacoby rule) and leave the cube at the center.
                if (gamestate.DiceRolled && (capped || gamestate.Cube.Centered))
                {
            //					Console.WriteLine("EVALUATING AS A MATCH");
                    Command("new match 1");
                    set_cube = false;
                }
                else
                {
                    int max_points = (int)(gamestate.Limit / gamestate.Stake);

                    if (max_points * gamestate.Stake < gamestate.Limit)
                        max_points++;

                    if (max_points < 1)
                        max_points = 1;

                    if (gamestate.Stake < gamestate.Limit && (met_stake != gamestate.Stake || met_limit != gamestate.Limit))
                    {
            //						Console.WriteLine("Setting money MET.");
                        MatchEquityTable.CreateRakelessMet("gnubg/met.xml", gamestate.Stake, gamestate.Limit);

                        Command("set met met.xml");

                        met_stake = gamestate.Stake;
                        met_limit = gamestate.Limit;
                    }

                    Command("new match " + max_points);
                }
            }
            else if (gamestate.GameType == GameType.Match) // What is only set in matches.
            {
                Command("new match " + gamestate.MatchTo);

                Command("set score " + gamestate.Score(0) + " " + gamestate.Score(1));
                // The score (after 0 games) is: gnubg 2, Administrator 2 (match to 3 points, post-Crawford play).

                // Need to be 1-away from match length to be able to set crawford game.
                if (gamestate.MatchTo - gamestate.Score(0) == 1 ||
                    gamestate.MatchTo - gamestate.Score(1) == 1)
                    Command("set crawford " + (gamestate.IsCrawford ? "true" : "false"));
                // Cannot set Crawford play for money sessions.
                // This game is the Crawford game (no doubling allowed).
            }
            else
            {
            }

            // This also clears the dice!
            Command("set turn " + gamestate.PlayerOnRoll);

            SetBoardSimple(gamestate);

            if (gamestate.OfferType == OfferType.Double)
            {
                Command("set turn " + gamestate.Cube.Owner);
                Command("set cube owner " + gamestate.Cube.Owner);// gamestate.PlayerOnRoll);
                Command("set cube value " + (gamestate.Cube.Value / 2));

                Command("double");
            }
            else if (gamestate.OfferType == OfferType.Resign)
            {
                if (gamestate.ResignOfferValue == ResignValue.None)
                    Console.WriteLine("Resign offer but ResignValue == None!");

                Command("resign " + (int)gamestate.ResignOfferValue);
            }
            else
            {
                if (gamestate.DiceRolled)
                    Command("set dice " + gamestate.Dice[0] + " " + gamestate.Dice[1]);
                // The dice have been set to 6 and 6.

                if (gamestate.Cube.Centered || !set_cube)
                {
                    Command("set cube center");
                    // The cube has been centred.
                }
                else
                {
                    Command("set cube owner " + gamestate.Cube.Owner);
                    // gnubg now owns the cube.

                    Command("set cube value " + gamestate.Cube.Value);
                    // The cube has been set to 2.
                }
            }
        }
        public static Bitmap Render(int player, int width, int height, GameState gamestate, ref List<BoundingChequer> bounding_chequers)
        {
            bounding_chequers.Clear();

            int[] board = gamestate.Board.BoardRelativeTo(player);

            int field_width = (int)(0.30 * width);
            int bar_width = (int)(0.08 * width);
            int left_space = (int)(0.16 * width);
            int right_space = (int)(0.16 * width);

            int field_height = (int)(0.92 * height);
            int upper_space = (int)(0.04 * height);
            int lower_space = (int)(0.04 * height);

            int chequer_diameter = (int)(field_width / 6.0);
            int chequer_radius = (int)(chequer_diameter / 2.0);

            int die_width = chequer_diameter;

            int slot_width = chequer_diameter;

            Bitmap bitmap = new Bitmap(width, height);

            Graphics g = Graphics.FromImage(bitmap);

            g.Clear(Color.LightGray);

            Brush[] player_brushes = new Brush[] { Brushes.Brown, Brushes.White };

            int[] slots = new int[24] { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };

            int base_x = left_space;
            int base_y = upper_space;

            int base_y_down = height - lower_space - chequer_diameter;

            int x = base_x;
            int count = -1, y = -1;

            Brush brush;

            FontFamily fm = new FontFamily("Tahoma");
            Font font = new Font(fm, 17, FontStyle.Bold);

            // Cube
            float cube_y = gamestate.Cube.Centered ? ((float)(height / 2.0 - die_width / 2.0)) : (gamestate.Cube.Owner == 1 ? upper_space : (height - lower_space - die_width));
            g.DrawImageUnscaled(GameStateRenderer.CreateDie(gamestate.Cube.Value, die_width, Brushes.Black, Brushes.White), (int)(left_space / 2.0 - die_width / 2.0), (int)cube_y);

            // Finished counts
            string finished_text = gamestate.Board.FinishedCount(1).ToString();
            SizeF text_size = g.MeasureString(finished_text, font);

            if (gamestate.Board.FinishedCount(1) > 0)
                g.DrawString(finished_text, font, Brushes.White, new PointF((float)(width - right_space / 2.0 - text_size.Width / 2.0), base_y));

            finished_text = gamestate.Board.FinishedCount(0).ToString();
            text_size = g.MeasureString(finished_text, font);

            if (gamestate.Board.FinishedCount(0) > 0)
                g.DrawString(finished_text, font, Brushes.Brown, new PointF((float)(width - right_space / 2.0 - text_size.Width / 2.0), (float)(height - lower_space - text_size.Height)));

            for (int s = 0; s < 12; s++)
            {
                int tri_x = x - ((slot_width / 2) - chequer_radius);
                int tri_y_down = upper_space + (int)(6 * chequer_diameter);
                int try_y_down2 = height - lower_space;//left_space + (int)(5.5 * chequer_diameter) + (int)(5.5 * chequer_diameter);

                Brush triangle_brush = (s % 2 == 0) ? Brushes.DarkGray : Brushes.White;

                g.FillPolygon(triangle_brush, new Point[] { new Point(tri_x, base_y), new Point(tri_x + slot_width, base_y), new Point(tri_x + slot_width / 2, base_y + 5 * chequer_diameter) });
                g.FillPolygon(triangle_brush, new Point[] { new Point(tri_x, try_y_down2 + 1), new Point(tri_x + slot_width / 2, tri_y_down), new Point(tri_x + slot_width, try_y_down2 + 1) });

                /*string text = (slots[s] + 1).ToString();
                SizeF size = g.MeasureString(text, font);
                float text_x = (float)(x + chequer_radius) - size.Width / 2.0f;
                g.DrawString(text, font, Brushes.Blue, new PointF(text_x, left_space - size.Height));

                text = (slots[12 + s] + 1).ToString();
                size = g.MeasureString(text, font);
                text_x = (float)(x + chequer_radius) - size.Width / 2.0f;
                g.DrawString(text, font, Brushes.Blue, new PointF(text_x, try_y_down2 + 2));*/

                // render up
                count = board[slots[s]];
                y = base_y;
                //int player = (count > 0) ? 0 : 1;//board[slots[s]].Player;
                brush = player_brushes[(count > 0) ? 0 : 1];
                bool hero = (count > 0) ? true : false;
                if (count < 0) count *= -1;
                for (int c = 0; c < count; c++)
                {
                    if (c % 5 == 0)
                        y = base_y + chequer_radius;
                    if (c % 10 == 0)
                        y = base_y;

                    g.FillEllipse(brush, x, y, chequer_diameter, chequer_diameter);
                    g.DrawEllipse(Pens.Black, x, y, chequer_diameter, chequer_diameter);

                    if (hero)
                        bounding_chequers.Add(new BoundingChequer(new Rectangle(x, y, chequer_diameter, chequer_diameter), slots[s]));

                    y += chequer_diameter;
                }

                // render down
                count = board[slots[12 + s]];
                y = base_y_down;
                //player = (count > 0) ? 0 : 1;
                brush = player_brushes[(count > 0) ? 0 : 1];
                hero = (count > 0) ? true : false;
                if (count < 0) count *= -1;
                for (int c = 0; c < count; c++)
                {
                    if (c % 5 == 0)
                        y = base_y_down - chequer_radius;
                    if (c % 10 == 0)
                        y = base_y_down;

                    g.FillEllipse(brush, x, y, chequer_diameter, chequer_diameter);
                    g.DrawEllipse(Pens.Black, x, y, chequer_diameter, chequer_diameter);

                    if (hero)
                        bounding_chequers.Add(new BoundingChequer(new Rectangle(x, y, chequer_diameter, chequer_diameter), slots[12 + s]));

                    y -= chequer_diameter;
                }

                x += slot_width;

                if (s == 5)
                    x = left_space + 6 * slot_width + bar_width + (slot_width / 2) - chequer_radius;
            }

            // Captured
            x = (int)(width / 2.0) - chequer_radius;

            // Player's
            count = gamestate.Board.CapturedCount(player);
            y = base_y + 4 * chequer_diameter;

            brush = player_brushes[0];
            for (int c = 0; c < count; c++)
            {
                if (c % 5 == 0)
                    y = base_y + 4 * chequer_diameter - chequer_radius;
                if (c % 10 == 0)
                    y = base_y + 4 * chequer_diameter;

                g.FillEllipse(brush, x, y, chequer_diameter, chequer_diameter);
                g.DrawEllipse(Pens.Black, x, y, chequer_diameter, chequer_diameter);

                bounding_chequers.Add(new BoundingChequer(new Rectangle(x, y, chequer_diameter, chequer_diameter), 24));

                y -= chequer_diameter;
            }

            // Opponent's
            count = gamestate.Board.CapturedCount(1 - player);
            y = height - lower_space - 5 * chequer_diameter;

            brush = player_brushes[1];
            for (int c = 0; c < count; c++)
            {
                if (c % 5 == 0)
                    y = height - lower_space - 5 * chequer_diameter + chequer_radius;
                if (c % 10 == 0)
                    y = height - lower_space - 5 * chequer_diameter;

                g.FillEllipse(brush, x, y, chequer_diameter, chequer_diameter);
                g.DrawEllipse(Pens.Black, x, y, chequer_diameter, chequer_diameter);

                // bounding_chequers.Add(new BoundingChequer(new Rectangle(x, y, chequer_diameter, chequer_diameter), 25));

                y += chequer_diameter;
            }

            // Dice
            /*SizeF size; string text;
            int[] dice = gamestate.Dice;
            if (dice[0] != 0)
            {
                text = dice[0].ToString() + "," + dice[1].ToString();
                size = g.MeasureString(text, font);

                g.DrawString(text, font, Brushes.Blue, new PointF(left_space + 3 * slot_width - size.Width / 2, height / 2 - size.Height / 2));
            }*/

            if (gamestate.DiceRolled)
            {
                int[] dice_x = new int[2];
                if (player == gamestate.PlayerOnRoll)
                {
                    dice_x[0] = (int)(left_space + field_width * 0.25 - die_width * 0.5);
                    dice_x[1] = (int)(left_space + field_width * 0.75 - die_width * 0.5);
                }
                else
                {
                    dice_x[0] = (int)(left_space + field_width + bar_width + field_width * 0.25 - die_width * 0.5);
                    dice_x[1] = (int)(left_space + field_width + bar_width + field_width * 0.75 - die_width * 0.5);
                }

                g.DrawImageUnscaled(CreateDie(gamestate.Dice[0], die_width, player_brushes[gamestate.PlayerOnRoll], player_brushes[1 - gamestate.PlayerOnRoll]), dice_x[0], (int)(height * 0.5 - die_width * 0.5));
                g.DrawImageUnscaled(CreateDie(gamestate.Dice[1], die_width, player_brushes[gamestate.PlayerOnRoll], player_brushes[1 - gamestate.PlayerOnRoll]), dice_x[1], (int)(height * 0.5 - die_width * 0.5));
            }

            // Outer borders
            g.DrawRectangle(Pens.Black, 0, 0, width - 1, height - 1);

            // Fields
            g.DrawRectangle(Pens.Black, left_space, upper_space, field_width, field_height); // Left
            g.DrawRectangle(Pens.Black, width - right_space - field_width, upper_space, field_width, field_height); // Right

            return bitmap;
        }
Esempio n. 9
0
        private void buttonRoll_Click(object sender, EventArgs e)
        {
            watch.Stop();

            GameStateTurnAction gsta = new GameStateTurnAction(currentGameState.Clone(), watch.ElapsedMilliseconds, TurnAction.Roll);

            turns.Add(gsta);

            textBoxLog.Text += "Turn action added" + " " + watch.ElapsedMilliseconds + "ms." + Environment.NewLine;
            textBoxLog.SelectionStart = textBoxLog.Text.Length;
            textBoxLog.ScrollToCaret();

            buttonRoll.Enabled = false;
            buttonRoll.Visible = false;

            currentGameState.SetDice(random.Next(1, 7), random.Next(1, 7));
            originalGameState = currentGameState.Clone();

            legalPlays = currentGameState.Board.LegalPlays(currentGameState.PlayerOnRoll, currentGameState.Dice);

            if (legalPlays.Count == 0)
            {
                this.Render();
                this.Refresh();

                legalPlays.Clear();
                madeMoves.Clear();
                unusedDice.Clear();

                currentGameState.ChangeTurn();

                Thread.Sleep(1000);

                UpdateControls();

                return;
            }

            unusedDice.AddRange(currentGameState.Dice);

            if (currentGameState.Dice[0] == currentGameState.Dice[1])
                unusedDice.AddRange(currentGameState.Dice);

            UpdateControls();
        }
Esempio n. 10
0
        /// <summary>
        /// Compares this to another game state and determines if they are the same.
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public bool Equals(GameState state)
        {
            if (this.player_on_roll != state.PlayerOnRoll)
                return false;
            if (this.PlayerOnTurn != state.PlayerOnTurn)
                return false;
            if (this.Dice[0] != state.Dice[0] || this.Dice[1] != state.Dice[1])
                return false;
            if (this.Cube.Owner != state.Cube.Owner || this.Cube.Value != state.Cube.Value)
                return false;
            if (this.ResignOfferValue != state.ResignOfferValue)
                return false;

            return this.Board.Equals(state.Board);
        }
        public static Bitmap Render(GameState gamestate)
        {
            Board board = gamestate.Board;
            int cheq_rad = 6;
            int slot_width = 18, bar_width = 15, border_width = 20, middle_height = 8;
            int cheq_diam = cheq_rad * 2;

            int total_width = 2 * border_width + 12 * slot_width + bar_width + 1;
            int total_height = 2 * border_width + 2 * (int)(5.5 * cheq_diam) + middle_height + 1;
            Bitmap render = new Bitmap(total_width, total_height);

            //int[] slots = new int[24] {0,1,2,3,4,5,6,7,8,9,10,11,23,22,21,20,19,18,17,16,15,14,13,12};
            int[] slots = new int[24] { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };

            int base_x = border_width + (slot_width / 2) - cheq_rad;
            int base_y = border_width;

            int base_y_down = border_width + (int)(5.5 * cheq_diam) + middle_height + (int)(4.5 * cheq_diam);

            Graphics g = Graphics.FromImage(render);
            g.Clear(Color.LightGray);
            g.DrawRectangle(Pens.Turquoise, 0, 0, total_width - 1, total_height - 1);
            g.DrawRectangle(Pens.DarkGray, border_width - 1, border_width - 1, slot_width * 6 + 2, cheq_diam * 11 + middle_height + 2);
            g.DrawRectangle(Pens.DarkGray, border_width + slot_width * 6 + bar_width - 1, border_width - 1, slot_width * 6 + 2, cheq_diam * 11 + middle_height + 2);

            Dictionary<int, Brush> player2brush = new Dictionary<int, Brush>();
            player2brush[0] = Brushes.Brown;
            player2brush[1] = Brushes.White;

            int x = base_x;

            FontFamily fm = new FontFamily("Tahoma");
            Font font = new Font(fm, 7, FontStyle.Bold);

            // cube
            string cube_text = gamestate.Cube.Value.ToString();
            SizeF text_size = g.MeasureString(cube_text, font);

            g.DrawString(cube_text, font, Brushes.Blue, new PointF(border_width / 2 - text_size.Width / 2, total_height / 2 - text_size.Height / 2));

            // finished counts
            /*string finished_text = "C:{" + gamestate.Board.CapturedCount(0) + ", " + gamestate.Board.CapturedCount(1) + "}";
            finished_text += " F:{" + gamestate.Board.FinishedCount(0) + ", " + gamestate.Board.FinishedCount(1) + "}";
            SizeF text_size = g.MeasureString(finished_text, font);*/

            /*
            for (int s = 0; s < 12; s++)
            {
                int tri_x = x - ((slot_width / 2) - cheq_rad);
                int tri_y_down = border_width + (int)(6 * cheq_diam) + middle_height;
                int try_y_down2 = border_width + (int)(5.5 * cheq_diam) + middle_height + (int)(5.5 * cheq_diam);
                g.FillPolygon(Brushes.LightGoldenrodYellow, new Point[] { new Point(tri_x, base_y), new Point(tri_x + slot_width, base_y), new Point(tri_x + slot_width / 2, base_y + 5 * cheq_diam) });
                g.FillPolygon(Brushes.LightGoldenrodYellow, new Point[] { new Point(tri_x, try_y_down2 + 1), new Point(tri_x + slot_width / 2, tri_y_down), new Point(tri_x + slot_width, try_y_down2 + 1) });

                string text = (slots[s] + 1).ToString();
                SizeF size = g.MeasureString(text, font);
                float text_x = (float)(x + cheq_rad) - size.Width / 2.0f;
                g.DrawString(text, font, Brushes.Blue, new PointF(text_x, border_width - size.Height));

                text = (slots[12 + s] + 1).ToString();
                size = g.MeasureString(text, font);
                text_x = (float)(x + cheq_rad) - size.Width / 2.0f;
                g.DrawString(text, font, Brushes.Blue, new PointF(text_x, try_y_down2 + 2));

                int[] dice = gamestate.Dice;
                if (dice[0] != 0)
                {
                    text = dice[0].ToString() + "," + dice[1].ToString();
                    size = g.MeasureString(text, font);

                    g.DrawString(text, font, Brushes.Blue, new PointF(border_width + 3 * slot_width - size.Width / 2, total_height / 2 - size.Height / 2));
                }

                // render up
                int count = board.Count(slots[s]);
                int y = base_y;
                int player = board[slots[s]].Player;
                for (int c = 0; c < count; c++)
                {
                    if (c % 5 == 0)
                        y = base_y + cheq_rad;
                    if (c % 10 == 0)
                        y = base_y;

                    g.FillEllipse(player2brush[player], x, y, cheq_diam, cheq_diam);
                    g.DrawEllipse(Pens.Black, x, y, cheq_diam, cheq_diam);

                    y += cheq_diam;
                }

                // render down
                count = board.Count(slots[12 + s]);
                y = base_y_down;
                player = board[slots[12 + s]].Player;
                for (int c = 0; c < count; c++)
                {
                    if (c % 5 == 0)
                        y = base_y_down - cheq_rad;
                    if (c % 10 == 0)
                        y = base_y_down;

                    g.FillEllipse(player2brush[player], x, y, cheq_diam, cheq_diam);
                    g.DrawEllipse(Pens.Black, x, y, cheq_diam, cheq_diam);

                    y -= cheq_diam;
                }

                x += slot_width;

                if (s == 5)
                    x = border_width + 6 * slot_width + bar_width + (slot_width / 2) - cheq_rad;
            }
            */
            return render;
        }
Esempio n. 12
0
        public GameState Clone()
        {
            GameState gamestate = new GameState(this.game_type);
            gamestate.board = this.board.Clone();
            gamestate.crawford = this.crawford;
            gamestate.cube.Owner = this.cube.Owner;
            gamestate.cube.Value = this.cube.Value;
            gamestate.dice[0] = this.dice[0];
            gamestate.dice[1] = this.dice[1];
            gamestate.limit = this.limit;
            gamestate.match_to = this.match_to;
            gamestate.offer = this.offer;
            gamestate.player_on_roll = this.player_on_roll;
            gamestate.player_on_turn = this.player_on_turn;
            gamestate.resign_offer_value = this.resign_offer_value;
            gamestate.score[0] = this.score[0];
            gamestate.score[1] = this.score[1];
            gamestate.stake = this.stake;
            gamestate.names = this.names;

            return gamestate;
        }
Esempio n. 13
0
        public static string Serialize(GameState gs)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(gs.crawford.ToString());
            sb.Append(" " + gs.cube.Owner);
            sb.Append(" " + gs.cube.Value);

            sb.Append(" " + gs.dice[0]);
            sb.Append(" " + gs.dice[1]);

            sb.Append(" " + gs.game_type.ToString());

            sb.Append(" " + gs.limit);
            sb.Append(" " + gs.match_to);
            sb.Append(" " + gs.offer.ToString());
            sb.Append(" " + gs.player_on_roll);
            sb.Append(" " + gs.player_on_turn);
            sb.Append(" " + gs.resign_offer_value);
            sb.Append(" " + gs.score[0]);
            sb.Append(" " + gs.score[1]);
            sb.Append(" " + gs.stake);

            sb.Append("#" + Board.Serialize(gs.board));

            return sb.ToString();
        }
Esempio n. 14
0
        public static GameState Deserialize(string s)
        {
            string[] ss = s.Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries);

            GameState gs = new GameState(GameType.Match);

            gs.board = Board.Deserialize(ss[1]);

            ss = ss[0].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            int i=0;
            gs.crawford = bool.Parse(ss[i]);
            i++;

            gs.cube.Owner = int.Parse(ss[i]);
            i++;

            gs.cube.Value = int.Parse(ss[i]);
            i++;

            gs.dice[0] = int.Parse(ss[i]);
            i++;

            gs.dice[1] = int.Parse(ss[i]);
            i++;

            gs.game_type = (GameType)Enum.Parse(typeof(GameType), ss[i]);
            i++;

            gs.limit = int.Parse(ss[i]);
            i++;

            gs.match_to = int.Parse(ss[i]);
            i++;

            gs.offer = (OfferType)Enum.Parse(typeof(OfferType), ss[i]);
            i++;

            gs.player_on_roll = int.Parse(ss[i]);
            i++;

            gs.player_on_turn = int.Parse(ss[i]);
            i++;

            gs.resign_offer_value = (ResignValue)Enum.Parse(typeof(ResignValue), ss[i]);
            i++;

            gs.score[0] = int.Parse(ss[i]);
            i++;

            gs.score[1] = int.Parse(ss[i]);
            i++;

            gs.stake = int.Parse(ss[i]);

            return gs;
        }
Esempio n. 15
0
        public string Hint(GameState gamestate)
        {
            // Command("new match " + gamestate.MatchTo);
            // SetBoardSimple(gamestate);
            // string matchid_response = Command("set matchid " + MatchID(gamestate));

            SetGameState(gamestate);

            // TODO: Current results give no difference with or without clear hint, without it, there might be performance boost. Investigate further.
            //Command("clear hint");

            return Command("hint");
        }
Esempio n. 16
0
        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();
        }
Esempio n. 17
0
        /// <summary>
        /// Assumes dice have been rolled and game is still going.
        /// </summary>
        /// <param name="state"></param>
        /// <returns>Returns null if there are no legal moves.</returns>
        public List<PlayHint> PlayHint(GameState gamestate, int max_hints)
        {
            SetGameState(gamestate);

            // TODO: Current results give no difference with or without clear hint, without it, there might be performance boost. Investigate further.
            //Command("clear hint");

            return ParseMoveHints(Command("hint " + max_hints), gamestate.Dice, gamestate);
        }
Esempio n. 18
0
        /// <summary>
        /// Gnubg treats positive counts as for the player on turn, and negative for the other.
        /// The first slot is the captured count for the player on turn, last slot is for the capture count of the other.
        /// Gnubg calculates the finished pieces for both players automatically.
        /// 26 integers are represented the following way:
        /// #Captured count for the player on roll# #Slot 1# ... #Slot 24# #Captured count for the other player#
        /// The slots start from the home board of the player on roll.
        /// </summary>
        /// <param name="game_state"></param>
        private void SetBoardSimple(GameState gamestate)
        {
            string simple_board = "";

            simple_board += gamestate.Board.CapturedCount(gamestate.PlayerOnRoll);

            int[] board = gamestate.Board.BoardRelativeTo(gamestate.PlayerOnRoll);

            for (int i = 0; i < 24; i++)
                simple_board += " " + board[i].ToString();

            simple_board += " " + gamestate.Board.CapturedCount(1 - gamestate.PlayerOnRoll);

            //Console.WriteLine(simple_board);
            //Console.WriteLine(Command("set board simple " + simple_board));
            Command("set board simple " + simple_board);
        }
Esempio n. 19
0
 public ResignResponseHint ResignResponseHint(GameState gamestate)
 {
     return ParseResignResponse(Hint(gamestate));
 }
Esempio n. 20
0
        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;
        }
Esempio n. 21
0
        DoubleHint GetDoubleHint(GameState gamestate)
        {
            string hint = Hint(gamestate);

            Console.WriteLine(gamestate);

            int start = hint.IndexOf("No double") + 9;
            int end = hint.IndexOf("\r\n", start);

            string h = hint.Substring(start, end - start);
            if (h.Contains("("))
                h = h.Substring(0, h.IndexOf("("));
            double noDoubleEq = double.Parse(h.Trim());

            start = hint.IndexOf("Double, pass") + 12;
            end = hint.IndexOf("\r\n", start);
            h = hint.Substring(start, end - start);
            if (h.Contains("("))
                h = h.Substring(0, h.IndexOf("("));

            double doubePassEq = double.Parse(h.Trim());

            start = hint.IndexOf("Double, take") + 12;
            end = hint.IndexOf("\r\n", start);
            h = hint.Substring(start, end - start);
            if (h.Contains("("))
                h = h.Substring(0, h.IndexOf("("));

            double doubeTakeEq = double.Parse(h.Trim());

            start = hint.LastIndexOf(":");
            string sub = hint.Substring(start + 1);
            if (sub.Contains("("))
                sub = sub.Remove(sub.LastIndexOf("("));

            if (sub.Contains("\r\n\r\n" + this.prompt))
                sub = sub.Remove(sub.LastIndexOf("\r\n\r\n" + this.prompt));

            if (sub.Contains(","))
                sub = sub.Remove(sub.IndexOf(","));

            sub = sub.Trim();
            sub = sub.ToLowerInvariant();

            // We should double when the cube is centered and it's a money game.
            if ((gamestate.GameType == GameType.Money && gamestate.Cube.Centered) && (sub == "too good to double" || sub == "too good to redouble"))
            {
                return new DoubleHint(DoubleAction.Double, doubeTakeEq, doubePassEq, noDoubleEq);
            }

            return new DoubleHint(string2doubleaction[sub], doubeTakeEq, doubePassEq, noDoubleEq);
        }
Esempio n. 22
0
 /// <summary>
 /// TODO: Solve the "I'm sorry, but SetMatchID cannot handle positions where a double has been offered" bullshit.
 /// </summary>
 /// <param name="gamestate"></param>
 /// <returns></returns>
 public static string MatchID(GameState gamestate)
 {
     Console.WriteLine("Cube owner: " + gamestate.Cube.Owner);
     return MatchID(
         gamestate.Dice[0],
         gamestate.Dice[1],
         gamestate.PlayerOnTurn,
         (int)gamestate.ResignOfferValue,
         (gamestate.OfferType == OfferType.Double) ? 1 : 0,
         gamestate.PlayerOnRoll,
         (gamestate.Cube.Owner >= 0) ? gamestate.Cube.Owner : 2,
         gamestate.IsCrawford ? 1 : 0,
         gamestate.MatchTo,
         gamestate.Score(0),
         gamestate.Score(1),
         gamestate.Cube.Value,
         (int)GnuBGGameState.GAME_PLAYING
         );
 }
Esempio n. 23
0
        private List<PlayHint> ParseMoveHints(string hints, int[] dice, GameState gamestate)
        {
            if (hints.StartsWith("There are no legal moves."))
                return null;

            List<PlayHint> move_hints = new List<PlayHint>();

            //string[] hs = hints.Split(new char[] { ']' });
            string[] hs = hints.Split(new string[] { ". " }, StringSplitOptions.RemoveEmptyEntries);
            string hint = "";

            // Skip the first one.
            for (int i = 1; i < hs.Length; i++)
            {
                hint = hs[i];
                int s = hint.IndexOf("-ply");
                if (s < 0)
                    continue;

                int e = hint.IndexOf("Eq.:");
                if (e < 0)
                {
                    e = hint.IndexOf("MWC");
                }
                if (e < 0)
                {
                    e = hint.IndexOf("uity");
                }

                // Parse equity.
                int eq_e = hint.IndexOfAny(new char[] { '(', '\r' }, e + 4);
                double eq = double.Parse(hint.Substring(e + 4, eq_e - (e + 4)));

                hint = hint.Substring(s + 4, e - s - 4).Trim();

                // Console.WriteLine("GnuBg: " + hint);
                string[] moves_strings = hint.Split(new char[] { ' ' });
                int count = 0;
                List<Move> moves = new List<Move>();
                foreach (string move_string in moves_strings)
                {
                    Move move = ParseMoveHint(move_string, out count, moves_strings.Length, dice, gamestate);
                    for (int c = 0; c < count; c++)
                        moves.Add(move);
                }

                PlayHint play_hint = new PlayHint(moves, eq);

                play_hint.Play.SortHiToLow();

                move_hints.Add(play_hint);
            }

            return move_hints;
        }
Esempio n. 24
0
        // See drawboard.c in Gnubg source files.
        public static string ToGnuBgASCII(GameState gs, string[] player_names)
        {
            string[] a = new string[7];

            string achX = "     X6789ABCDEF";
            string achO = "     O6789ABCDEF";

            a[0] = string.Format("O: {0}", player_names[0]);
            a[6] = string.Format("X: {0}", player_names[1]);

            if (gs.Score(0) == 1)
                a[1] = string.Format("{0} point", gs.Score(0));
            else
                a[1] = string.Format("{0} points", gs.Score(0));

            if (gs.Score(1) == 1)
                a[5] = string.Format("{0} point", gs.Score(1));
            else
                a[5] = string.Format("{0} points", gs.Score(1));

            if (gs.OfferType == OfferType.Double)
            {
                a[(gs.PlayerOnTurn == 1) ? 4 : 2] = string.Format("Cube offered at {0}", gs.Cube.Value);
            }
            else
            {
                int index = (gs.PlayerOnRoll == 1) ? 4 : 2;

                if (gs.DiceRolled)
                    a[index] += string.Format("Rolled {0}{1}", gs.Dice[0], gs.Dice[1]);
                else if (!gs.HasOffer)
                    a[index] = "On roll";
                else
                {
                }

                if (gs.Cube.Centered)
                {
                    if (gs.GameType == GameType.Match)
                        a[3] += string.Format("{0} point match (Cube: {1})", gs.MatchTo, gs.Cube.Value);
                    else
                        a[3] += string.Format("(Cube: {0})", gs.Cube.Value);
                }
                else
                {
                    a[(gs.Cube.Owner == 1) ? 6 : 0] = string.Format("{0}: {1} (Cube: {2})", (gs.Cube.Owner == 1) ? "X" : "O", "CubeOwnersName", gs.Cube.Value);

                    if (gs.GameType == GameType.Match)
                        a[3] += string.Format("{0} point match", gs.MatchTo);
                }
            }

            if (gs.OfferType == OfferType.Resign)
            {
                string[] resign_strigns = new string[] { "single game", "gammon", "backgammon" };
                a[(gs.PlayerOnRoll == 1) ? 4 : 2] += string.Format(", resigns {0}", resign_strigns[(int)gs.ResignOfferValue - 1]);
            }

            Board b = gs.Board;
            Console.WriteLine(b.CapturedCount(0) + " " + b.CapturedCount(1));
            if (gs.PlayerOnRoll == 0)
                b = SwapSides(b);

            string s = "";

            s += string.Format(" {0,-15} {1}: ", "GNU Backgammon", "Position ID");

            s += "4HPwATDg6+ABMA";//GnuBg.ToPositionID(gs.Board, gs.PlayerOnRoll);

            s += Environment.NewLine;

            s += string.Format("                 {0}   : {1}" + Environment.NewLine, "Match ID", "MQHgAAAACAAA"); //GnuBg.ToMatchID(gs);

            s += (gs.PlayerOnRoll == 1) ? " +13-14-15-16-17-18------19-20-21-22-23-24-+     " : " +12-11-10--9--8--7-------6--5--4--3--2--1-+     ";

            s += a[0] + Environment.NewLine;
            Console.WriteLine(b.CapturedCount(0) + " " + b.CapturedCount(1));
            int x = 0, y = 0;
            for (y = 0; y < 4; y++)
            {
                s += " ";
                s += "|";

                for (x = 12; x < 18; x++)
                {
                    s += " ";
                    s += (b.PointCount(1, x) > y) ? "X" : (b.PointCount(0, 23 - x) > y) ? "O" : " "; // X or O or ' ' TODO!
                    s += " ";
                }

                s += "|";
                s += " ";
                s += b.CapturedCount(0) > y ? "O" : " "; // O or ' ' TODO!
                s += " ";
                s += "|";

                for (; x < 24; x++)
                {
                    s += " ";
                    s += (b.PointCount(1, x) > y) ? "X" : (b.PointCount(0, 23 - x) > y) ? "O" : " "; // X or O or ' ' TODO!
                    s += " ";
                }

                s += "|";
                s += " ";

                for (x = 0; x < 3; x++)
                    s += b.FinishedCount(0) > (5 * x + y) ? "O" : " "; // O or ' ' TODO!

                s += " ";

                if (y < 2 && a[y + 1] != "")
                {
                    s += a[y + 1];
                }

                s += Environment.NewLine;
            }

            s += " ";
            s += "|";

            for (x = 12; x < 18; x++)
            {
                s += " ";
                s += b.PointCount(1, x) > 0 ? achX[b.PointCount(1, x)] : achO[b.PointCount(0, 23 - x)];// TODO, WTF?
                s += " ";
            }

            s += "|";
            s += " ";
            s += achO[b.CapturedCount(0)]; // TODO!
            s += " ";
            s += "|";

            for (; x < 24; x++)
            {
                s += " ";
                s += b.PointCount(1, x) > 0 ? achX[b.PointCount(1, x)] : achO[b.PointCount(0, 23 - x)]; // TODO!
                s += " ";
            }

            s += "|";
            s += " ";

            for (x = 0; x < 3; x++)
                s += b.FinishedCount(0) > (5 * x + 4) ? "O" : " "; ; // TODO!

            s += Environment.NewLine;

            s += (gs.PlayerOnRoll == 1) ? "v" : "^";

            s += "|                  |BAR|                  |     ";

            s += a[3];

            s += Environment.NewLine;

            s += " ";
            s += "|";

            for (x = 11; x > 5; x--)
            {
                s += " ";
                s += b.PointCount(1, x) > 0 ? achX[b.PointCount(1, x)] : achO[b.PointCount(0, 23 - x)]; // TODO!
                s += " ";
            }

            s += "|";
            s += " ";
            s += achX[b.CapturedCount(1)]; // TODO!
            s += " ";
            s += "|";

            for (; x >= 0; x--)
            {
                s += " ";
                s += b.PointCount(1, x) > 0 ? achX[b.PointCount(1, x)] : achO[b.PointCount(0, 23 - x)]; // TODO!
                s += " ";
            }

            s += "|";
            s += " ";

            for (x = 0; x < 3; x++)
                s += b.FinishedCount(1) > (5 * x + 4) ? "X" : " "; // TODO!

            s += Environment.NewLine;

            for (y = 3; y >= 0; y--)
            {
                s += " ";
                s += "|";

                for (x = 11; x > 5; x--)
                {
                    s += " ";
                    s += b.PointCount(1, x) > y ? "X" : b.PointCount(0, 23 - x) > y ? "O" : " "; // TODO!
                    s += " ";
                }

                s += "|";
                s += " ";
                s += b.CapturedCount(1) > y ? "X" : " "; // TODO!
                s += " ";
                s += "|";

                for (; x >= 0; x--)
                {
                    s += " ";
                    s += b.PointCount(1, x) > y ? "X" : b.PointCount(0, 23 - x) > y ? "O" : " "; // TODO!
                    s += " ";
                }

                s += "|";
                s += " ";

                for (x = 0; x < 3; x++)
                    s += b.FinishedCount(1) > (5 * x + y) ? "X" : " "; // TODO!

                s += " ";

                if (y < 2)
                    s += a[5 - y];

                s += Environment.NewLine;
            }

            s += (gs.PlayerOnRoll == 1) ? " +12-11-10--9--8--7-------6--5--4--3--2--1-+     " : " +13-14-15-16-17-18------19-20-21-22-23-24-+     ";

            s += a[6];

            s += Environment.NewLine;

            Console.WriteLine(s);

            return s;
        }