Esempio n. 1
0
        public override TimedPlay TimedPlayOnRoll(GameState gamestate, List <PlayHint> hints, VenueUndoMethod undo_method)
        {
            TimedPlay play = new TimedPlay();

            foreach (Move move in hints[0].Play)
            {
                play.Add(new TimedMove(move, (int)this.moves[random.Next(this.moves.Count)].Key.Time, 0));
            }


            return(play);
        }
        /*public virtual List<TimedMove> SortAndTimeMoves(Play move_sequence, List<Play> legal_move_sequences, List<Move> forced_moves)
         * {
         * List<TimedMove> timed_moves = new List<TimedMove>();
         * Random random = new Random();
         *
         * foreach (Move move in forced_moves)
         * timed_moves.Add(new TimedMove(move, random.Next(0, 400), 0));
         *
         * // Assuming move_sequence doesn't contain forced_moves
         *
         * int complexity_factor = legal_move_sequences.Count;
         * if (move_sequence.Count == 1)
         * {
         * timed_moves.Add(new TimedMove(move_sequence[0], complexity_factor * 100, 0));
         * }
         * else if (move_sequence.Count > 1)
         * {
         *
         * }
         *
         * return timed_moves;
         * }*/

        public override TimedPlay TimedPlayOnRoll(GameState gamestate, Play play)
        {
            //Console.WriteLine("Sorting moves...");
            List <Play> legal_plays  = gamestate.Board.LegalPlays(gamestate.PlayerOnRoll, gamestate.Dice);
            List <Move> forced_moves = Board.ForcedMoves(legal_plays);

            //Console.Write("Forced moves: ");
            //foreach (Move move in forced_moves)
            //    Console.Write(move + " ");
            //Console.WriteLine();

            if (gamestate.Dice[0] != gamestate.Dice[1])
            {
                // Both are on the bar, sort the enter which uses bigger die as first.
                if (play.Count == 2 && play[0].IsEnter && play[1].IsEnter && play[1].To < play[0].To)
                {
                    play.Reverse();
                }

                // Third condition avoids sequences where the second move is dependant on the first one
                if (play.Count == 2 && /*remove me when fixed*/ !play[0].IsEnter && !play[1].IsEnter && forced_moves.Count == 0 && gamestate.Board.PointCount(gamestate.PlayerOnRoll, play[1].From) > 0)
                {
                    // Case where there are two moves and they share the same 'from' point, sort so that the one with bigger distance is first.
                    if (play[0].From == play[1].From && play[0].Distance < play[1].Distance)
                    {
                        play.Reverse();
                    }
                    // Chain move, instead of 3/1 6/3 make 6/3/1
                    else if (play[0].From == play[1].To)
                    {
                        play.Reverse();
                    }
                    // Same as above already properly sorted. Don't do anything. This condition avoids it being passed below if the second play is a hit and being reversed.
                    else if (play[1].From == play[0].To)
                    {
                        ;
                    }
                    // If only one is a hit, greedily sort it as the first move
                    else if (play[1].HasHits && !play[0].HasHits)
                    {
                        play.Reverse();
                    }
                    else if (!play[0].HasHits && play[1].HasHits)
                    {
                        play.Reverse();
                    }
                    else
                    {
                    }
                }
            }
            else
            {
                /*if (play.Count == 4)
                 * {
                 *
                 * }*/
            }

            TimedPlay timed_play = new TimedPlay();

            if (gamestate.Board.IsPureRace())
            {
                foreach (Move move in play)
                {
                    timed_play.Add(new TimedMove(move, random.Next(100, 500), random.Next(200)));
                }
            }
            else
            {
                int last_from = -2;
                foreach (Move move in play)
                {
                    if (move.From != last_from)
                    {
                        timed_play.Add(new TimedMove(move, random.Next(250, 700), random.Next(250)));
                    }
                    else
                    {
                        timed_play.Add(new TimedMove(move, random.Next(100, 250), random.Next(100)));
                    }
                    last_from = move.From;
                }
            }

            return(timed_play);
        }
Esempio n. 3
0
        public override TimedPlay TimedPlayOnRoll(GameState gamestate, List <PlayHint> hints, VenueUndoMethod undo_method)
        {
            List <Play> legal_plays  = gamestate.Board.LegalPlays(gamestate.PlayerOnRoll, gamestate.Dice);
            List <Move> forced_moves = Board.ForcedMoves(legal_plays);

            // Sort the moves.
            foreach (PlayHint hint in hints)
            {
                SortMoves(gamestate, hint.Play, legal_plays, forced_moves);
            }

            double optimal_move_equity = hints[0].Equity;

            double doubtful = 0.04;
            double bad      = 0.08;
            double very_bad = 0.16;

            /*List<PlayHint> good_hints = new List<PlayHint>();
             * List<PlayHint> doubtful_hints = new List<PlayHint>();
             * List<PlayHint> bad_hints = new List<PlayHint>();
             * List<PlayHint> very_bad_hints = new List<PlayHint>();
             *
             * // Skip the first one as it is the optimal one.
             * for (int i = 1; i < hints.Count; i++)
             * {
             *  double diff = optimal_move_equity - hints[i].Equity;
             *  if (diff >= very_bad)
             *      very_bad_hints.Add(hints[i]);
             *  else if (diff >= bad)
             *      very_bad_hints.Add(hints[i]);
             *  else if (diff >= doubtful)
             *      doubtful_hints.Add(hints[i]);
             *  else
             *      good_hints.Add(hints[i]);
             * }*/

            /*if (legal_plays.Count != hints.Count)
             * {
             *  Console.WriteLine("Legal plays and hint plays mis-match");
             *  Console.WriteLine("Legal plays: ");
             *  foreach (Play play in legal_plays)
             *      Console.WriteLine(play);
             *  Console.WriteLine("Hint plays: ");
             *  foreach (PlayHint hint in hints)
             *      Console.WriteLine(hint);
             *
             *  throw new Exception();
             * }*/

            // Is the play an obvious move? Check the equity difference to second best move.
            bool obvious_move = false;

            if (legal_plays.Count == 1 || (hints.Count > 1 && (hints[1].Equity - optimal_move_equity) > bad))
            {
                obvious_move = true;
            }

            List <Play> fake_plays = new List <Play>();

            if (!obvious_move && undo_method != VenueUndoMethod.None)
            {
                // Choose the amount of fake plays.
                int fake_plays_to_choose = 0;
                if (random.NextDouble() <= undo_probability)
                {
                    fake_plays_to_choose++;
                    while (random.NextDouble() < 0.1)
                    {
                        fake_plays_to_choose++;
                    }
                }

                // Choose the fake plays.
                for (int i = 0; i < fake_plays_to_choose; i++)
                {
                    int fake_play_index = 1;
                    while (random.Next(3) == 0)
                    {
                        fake_play_index++;
                        if (fake_play_index >= hints.Count)
                        {
                            fake_play_index = 0;
                        }
                    }

                    // Make it partial?
                    if (random.NextDouble() <= 0.3)
                    {
                        Play partial_play    = new Play();
                        int  moves_to_choose = 1;
                        while (random.Next(4) == 0)
                        {
                            moves_to_choose++;
                            if (moves_to_choose >= hints[fake_play_index].Play.Count)
                            {
                                moves_to_choose = 1;
                            }
                        }

                        for (int m = 0; m < moves_to_choose; m++)
                        {
                            partial_play.Add(hints[fake_play_index].Play[m]);
                        }

                        fake_plays.Add(partial_play);
                    }
                    else
                    {
                        fake_plays.Add(hints[fake_play_index].Play);
                    }
                }
            }

            TimedPlay timed_play = new TimedPlay();

            // Add undo sequences using fake plays.
            if (!obvious_move && hints.Count > 1 && fake_plays.Count > 0)
            {
                List <Move> made_moves = new List <Move>();
                //Queue<Move> made_moves = new Queue<Move>();
                //Stack<Move> made_moves = new Stack<Move>();

                foreach (Play fake_play in fake_plays)
                {
                    for (int i = 0; i < fake_play.Count; i++)
                    {
                        /*if (made_moves.Count > 0)
                         * {
                         *  int shared = 0;
                         *  while (shared < made_moves.Count && shared < fake_play.Count && made_moves[shared] == fake_play[shared])
                         *      shared++;
                         * }
                         * else*/
                        timed_play.Add(new TimedMove(fake_play[i], 0, 0));
                        //made_moves.Push(fake_play[i]);
                    }

                    // Undo all
                    if (undo_method == VenueUndoMethod.UndoLast)
                    {
                        for (int i = 0; i < fake_play.Count; i++)
                        {
                            timed_play.Add(TimedMove.CreateUndoMove(0, 0));
                        }
                    }
                    else
                    {
                        timed_play.Add(TimedMove.CreateUndoMove(0, 0));
                    }
                }

                int m = 0;
                // TODO: Some how check if current move and previous share some similar so not necessary undo all.

                foreach (Move move in hints[0].Play)
                {
                    timed_play.Add(new TimedMove(move, 0, 0));
                }
            }
            else
            {
                // No fake plays, add the optimal move.
                foreach (Move move in hints[0].Play)
                {
                    timed_play.Add(new TimedMove(move, 0, 0));
                }
            }


            int  last_from     = -2;
            bool was_last_undo = false;

            foreach (TimedMove timed_move in timed_play)
            {
                if (timed_move.IsUndo)
                {
                    if (was_last_undo)
                    {
                        timed_move.WaitBefore = Gaussian.Next(500, 200, 10000, 600, 1.5);
                        timed_move.WaitAfter  = random.Next(200);
                    }
                    else
                    {
                        timed_move.WaitBefore = Gaussian.Next(1000, 500, 10000, 2000, 1.5);
                        timed_move.WaitAfter  = Gaussian.Next(1000, 50, 10000, 2000, 1.5);
                    }

                    last_from = -2;

                    was_last_undo = true;

                    continue;
                }

                was_last_undo = false;

                if (timed_move.From != last_from)
                {
                    //timed_move.WaitBefore = Gaussian.Next(500, 250, 2000, 500, 3.0);
                    //timed_move.WaitAfter = random.Next(300);
                    timed_move.WaitBefore = Gaussian.Next(1000, 250, 2000, 1000, 3.0);
                    timed_move.WaitAfter  = random.Next(300);
                }
                else
                {
                    //timed_move.WaitBefore = Gaussian.Next(250, 100, 2000, 200, 3.0);
                    //timed_move.WaitAfter = random.Next(100);
                    timed_move.WaitBefore = Gaussian.Next(500, 250, 2000, 200, 3.0);
                    timed_move.WaitAfter  = random.Next(250);
                }

                // Speedup for pure race or when we have a blockade.
                if (random.NextDouble() <= 0.9 && (gamestate.Board.IsPureRace() || HasBlockaded(gamestate) || obvious_move))
                {
                    timed_move.WaitBefore = (int)(timed_move.WaitBefore * (0.4 + 0.3 * random.NextDouble()));
                    timed_move.WaitAfter  = (int)(timed_move.WaitAfter * (0.4 + 0.3 * random.NextDouble()));
                }

                last_from = timed_move.From;
            }

            // Normalize with coefficient.
            foreach (TimedMove timed_move in timed_play)
            {
                timed_move.WaitBefore = (int)(timed_move.WaitBefore * coefficient);
                timed_move.WaitAfter  = (int)(timed_move.WaitAfter * coefficient);
            }

            return(timed_play);
        }
        public override TimedPlay TimedPlayOnRoll(GameState gamestate, Play play)
        {
            //Console.WriteLine("Sorting moves...");
            List<Play> legal_plays = gamestate.Board.LegalPlays(gamestate.PlayerOnRoll, gamestate.Dice);
            List<Move> forced_moves = Board.ForcedMoves(legal_plays);
            //Console.Write("Forced moves: ");
            //foreach (Move move in forced_moves)
            //    Console.Write(move + " ");
            //Console.WriteLine();

            if (gamestate.Dice[0] != gamestate.Dice[1])
            {
                // Both are on the bar, sort the enter which uses bigger die as first.
                if (play.Count == 2 && play[0].IsEnter && play[1].IsEnter && play[1].To < play[0].To)
                    play.Reverse();

                // Third condition avoids sequences where the second move is dependant on the first one
                if (play.Count == 2 && /*remove me when fixed*/ !play[0].IsEnter && !play[1].IsEnter && forced_moves.Count == 0 && gamestate.Board.PointCount(gamestate.PlayerOnRoll, play[1].From) > 0)
                {
                    // Case where there are two moves and they share the same 'from' point, sort so that the one with bigger distance is first.
                    if (play[0].From == play[1].From && play[0].Distance < play[1].Distance)
                        play.Reverse();
                    // Chain move, instead of 3/1 6/3 make 6/3/1
                    else if (play[0].From == play[1].To)
                        play.Reverse();
                    // If only one is a hit, greedily sort it as the first move
                    else if (play[1].HasHits && !play[0].HasHits)
                        play.Reverse();
                    else if (!play[0].HasHits && play[1].HasHits)
                        play.Reverse();
                    else
                    {
                    }
                }
            }
            else
            {
                /*if (play.Count == 4)
                {

                }*/
            }

            TimedPlay timed_play = new TimedPlay();

            if (gamestate.Board.IsPureRace())
            {
                foreach (Move move in play)
                {
                    timed_play.Add(new TimedMove(move, random.Next(100, 500), random.Next(200)));
                }
            }
            else
            {
                foreach (Move move in play)
                {
                    timed_play.Add(new TimedMove(move, random.Next(250, 500), random.Next(250)));
                }
            }

            return timed_play;
        }
Esempio n. 5
0
        public override TimedPlay TimedPlayOnRoll(GameState gamestate, List <GR.Gambling.Backgammon.Tools.PlayHint> hints, GR.Gambling.Backgammon.Venue.VenueUndoMethod undo_method)
        {
            bool is_race    = gamestate.Board.IsPureRace();
            bool is_bearoff = (gamestate.Board.LastChequer(gamestate.PlayerOnRoll) < 6);

            int total_sleep_before_first = 0;

            if (gamestate.Board.CapturedCount(gamestate.PlayerOnRoll) != hints[0].Play.Count)
            {
                if (!is_race)
                {
                    total_sleep_before_first += random.Next(750, 1750);

                    if (random.Next(10) == 0)
                    {
                        total_sleep_before_first += random.Next(2500);
                    }
                }
                else
                {
                    if (!is_bearoff)
                    {
                        total_sleep_before_first += random.Next(250, 750);
                    }

                    if (random.Next(20) == 0)
                    {
                        total_sleep_before_first += random.Next(1000);
                    }
                    if (random.Next(40) == 0)
                    {
                        total_sleep_before_first += random.Next(2500);
                    }
                    if (random.Next(60) == 0)
                    {
                        total_sleep_before_first += random.Next(5000);
                    }
                }
            }

            int last_slot = -5;
            int last_dest = -5;

            int on_bar = gamestate.Board.CapturedCount(gamestate.PlayerOnRoll);

            TimedPlay play = new TimedPlay();

            int[] dice = gamestate.Dice;
            Play  p    = hints[0].Play;

            for (int i = 0; i < p.Count; i++)
            {
                int slot   = p[i].From;
                int before = 0;
                int after  = 0;
                int die    = p[i].From - p[i].To;

                if (!(die == dice[0] || die == dice[1]))
                {
                    die = System.Math.Max(dice[0], dice[1]);
                }

                if (i == 0)
                {
                    before += total_sleep_before_first;
                }

                if (i == (p.Count - 1) && random.Next(15) == 0)
                {
                    after += random.Next(300, 1300);
                }

                if (on_bar > 0)
                {
                    if (random.Next(8) == 0)
                    {
                        before += random.Next(500, 1000);
                    }
                }
                else if (!is_bearoff && i > 0 && slot != last_slot && (slot - die >= 0) && slot != last_dest && !p[i].IsEnter && (slot - die != last_dest))
                {
                    int diff = System.Math.Abs(slot - last_slot);

                    if ((last_slot >= 12 && slot < 12) || (slot >= 12 && last_slot < 12))
                    {
                        diff = 10;
                    }

                    if (diff <= 1)
                    {
                        before += random.Next(25, 75);
                    }
                    else if (diff <= 3)
                    {
                        before += random.Next(50, 350);
                    }
                    else if (diff <= 6)
                    {
                        before += random.Next(100, 500);
                    }
                    else
                    {
                        before += random.Next(150, 900);
                    }
                }
                else
                {
                }

                play.Add(new TimedMove(hints[0].Play[i], before, after));

                last_slot = slot;
                last_dest = p[i].To;
                on_bar--;
            }

            return(play);
        }
        public override TimedPlay TimedPlayOnRoll(GameState gamestate, List<PlayHint> hints, VenueUndoMethod undo_method)
        {
            List<Play> legal_plays = gamestate.Board.LegalPlays(gamestate.PlayerOnRoll, gamestate.Dice);
            List<Move> forced_moves = Board.ForcedMoves(legal_plays);

            // Sort the moves.
            foreach (PlayHint hint in hints)
            {
                SortMoves(gamestate, hint.Play, legal_plays, forced_moves);
            }

            double optimal_move_equity = hints[0].Equity;

            double doubtful = 0.04;
            double bad = 0.08;
            double very_bad = 0.16;

            /*List<PlayHint> good_hints = new List<PlayHint>();
            List<PlayHint> doubtful_hints = new List<PlayHint>();
            List<PlayHint> bad_hints = new List<PlayHint>();
            List<PlayHint> very_bad_hints = new List<PlayHint>();

            // Skip the first one as it is the optimal one.
            for (int i = 1; i < hints.Count; i++)
            {
                double diff = optimal_move_equity - hints[i].Equity;
                if (diff >= very_bad)
                    very_bad_hints.Add(hints[i]);
                else if (diff >= bad)
                    very_bad_hints.Add(hints[i]);
                else if (diff >= doubtful)
                    doubtful_hints.Add(hints[i]);
                else
                    good_hints.Add(hints[i]);
            }*/

            /*if (legal_plays.Count != hints.Count)
            {
                Console.WriteLine("Legal plays and hint plays mis-match");
                Console.WriteLine("Legal plays: ");
                foreach (Play play in legal_plays)
                    Console.WriteLine(play);
                Console.WriteLine("Hint plays: ");
                foreach (PlayHint hint in hints)
                    Console.WriteLine(hint);

                throw new Exception();
            }*/

            // Is the play an obvious move? Check the equity difference to second best move.
            bool obvious_move = false;
            if (legal_plays.Count == 1 || (hints.Count > 1 && (hints[1].Equity - optimal_move_equity) > bad))
                obvious_move = true;

            List<Play> fake_plays = new List<Play>();

            if (!obvious_move && undo_method != VenueUndoMethod.None)
            {
                // Choose the amount of fake plays.
                int fake_plays_to_choose = 0;
                if (random.NextDouble() <= undo_probability)
                {
                    fake_plays_to_choose++;
                    while (random.NextDouble() < 0.1)
                        fake_plays_to_choose++;
                }

                // Choose the fake plays.
                for (int i = 0; i < fake_plays_to_choose; i++)
                {
                    int fake_play_index = 1;
                    while (random.Next(3) == 0)
                    {
                        fake_play_index++;
                        if (fake_play_index >= hints.Count)
                            fake_play_index = 0;
                    }

                    // Make it partial?
                    if (random.NextDouble() <= 0.3)
                    {
                        Play partial_play = new Play();
                        int moves_to_choose = 1;
                        while (random.Next(4) == 0)
                        {
                            moves_to_choose++;
                            if (moves_to_choose >= hints[fake_play_index].Play.Count)
                                moves_to_choose = 1;
                        }

                        for (int m = 0; m < moves_to_choose; m++)
                        {
                            partial_play.Add(hints[fake_play_index].Play[m]);
                        }

                        fake_plays.Add(partial_play);
                    }
                    else
                        fake_plays.Add(hints[fake_play_index].Play);
                }
            }

            TimedPlay timed_play = new TimedPlay();

            // Add undo sequences using fake plays.
            if (!obvious_move && hints.Count > 1 && fake_plays.Count > 0)
            {
                List<Move> made_moves = new List<Move>();
                //Queue<Move> made_moves = new Queue<Move>();
                //Stack<Move> made_moves = new Stack<Move>();

                foreach (Play fake_play in fake_plays)
                {
                    for (int i = 0; i < fake_play.Count; i++)
                    {
                        /*if (made_moves.Count > 0)
                        {
                            int shared = 0;
                            while (shared < made_moves.Count && shared < fake_play.Count && made_moves[shared] == fake_play[shared])
                                shared++;
                        }
                        else*/
                        timed_play.Add(new TimedMove(fake_play[i], 0, 0));
                        //made_moves.Push(fake_play[i]);
                    }

                    // Undo all
                    if (undo_method == VenueUndoMethod.UndoLast)
                        for (int i = 0; i < fake_play.Count; i++)
                            timed_play.Add(TimedMove.CreateUndoMove(0, 0));
                    else
                        timed_play.Add(TimedMove.CreateUndoMove(0, 0));
                }

                int m = 0;
                // TODO: Some how check if current move and previous share some similar so not necessary undo all.

                foreach (Move move in hints[0].Play)
                    timed_play.Add(new TimedMove(move, 0, 0));
            }
            else
            {
                // No fake plays, add the optimal move.
                foreach (Move move in hints[0].Play)
                    timed_play.Add(new TimedMove(move, 0, 0));
            }

            int last_from = -2;
            bool was_last_undo = false;
            foreach (TimedMove timed_move in timed_play)
            {
                if (timed_move.IsUndo)
                {
                    if (was_last_undo)
                    {
                        timed_move.WaitBefore = Gaussian.Next(500, 200, 10000, 600, 1.5);
                        timed_move.WaitAfter = random.Next(200);
                    }
                    else
                    {
                        timed_move.WaitBefore = Gaussian.Next(1000, 500, 10000, 2000, 1.5);
                        timed_move.WaitAfter = Gaussian.Next(1000, 50, 10000, 2000, 1.5);
                    }

                    last_from = -2;

                    was_last_undo = true;

                    continue;
                }

                was_last_undo = false;

                if (timed_move.From != last_from)
                {
                    //timed_move.WaitBefore = Gaussian.Next(500, 250, 2000, 500, 3.0);
                    //timed_move.WaitAfter = random.Next(300);
                    timed_move.WaitBefore = Gaussian.Next(1000, 250, 2000, 1000, 3.0);
                    timed_move.WaitAfter = random.Next(300);
                }
                else
                {
                    //timed_move.WaitBefore = Gaussian.Next(250, 100, 2000, 200, 3.0);
                    //timed_move.WaitAfter = random.Next(100);
                    timed_move.WaitBefore = Gaussian.Next(500, 250, 2000, 200, 3.0);
                    timed_move.WaitAfter = random.Next(250);
                }

                // Speedup for pure race or when we have a blockade.
                if (random.NextDouble() <= 0.9 && (gamestate.Board.IsPureRace() || HasBlockaded(gamestate) || obvious_move))
                {
                    timed_move.WaitBefore = (int)(timed_move.WaitBefore * (0.4 + 0.3 * random.NextDouble()));
                    timed_move.WaitAfter = (int)(timed_move.WaitAfter * (0.4 + 0.3 * random.NextDouble()));
                }

                last_from = timed_move.From;
            }

            // Normalize with coefficient.
            foreach (TimedMove timed_move in timed_play)
            {
                timed_move.WaitBefore = (int)(timed_move.WaitBefore * coefficient);
                timed_move.WaitAfter = (int)(timed_move.WaitAfter * coefficient);
            }

            return timed_play;
        }
Esempio n. 7
0
        public override TimedPlay TimedPlayOnRoll(GameState gamestate, List<PlayHint> hints, VenueUndoMethod undo_method)
        {
            TimedPlay play = new TimedPlay();

            foreach (Move move in hints[0].Play)
            {
                play.Add(new TimedMove(move, (int)this.moves[random.Next(this.moves.Count)].Key.Time, 0));
            }

            return play;
        }
        public override TimedPlay TimedPlayOnRoll(GameState gamestate, List<GR.Gambling.Backgammon.Tools.PlayHint> hints, GR.Gambling.Backgammon.Venue.VenueUndoMethod undo_method)
        {
            bool is_race = gamestate.Board.IsPureRace();
            bool is_bearoff = (gamestate.Board.LastChequer(gamestate.PlayerOnRoll) < 6);

            int total_sleep_before_first = 0;
            if (gamestate.Board.CapturedCount(gamestate.PlayerOnRoll) != hints[0].Play.Count)
            {
                if (!is_race)
                {
                    total_sleep_before_first += random.Next(750, 1750);

                    if (random.Next(10) == 0)
                        total_sleep_before_first += random.Next(2500);
                }
                else
                {
                    if (!is_bearoff)
                        total_sleep_before_first += random.Next(250, 750);

                    if (random.Next(20) == 0)
                        total_sleep_before_first += random.Next(1000);
                    if (random.Next(40) == 0)
                        total_sleep_before_first += random.Next(2500);
                    if (random.Next(60) == 0)
                        total_sleep_before_first += random.Next(5000);
                }
            }

            int last_slot = -5;
            int last_dest = -5;

            int on_bar = gamestate.Board.CapturedCount(gamestate.PlayerOnRoll);

            TimedPlay play = new TimedPlay();

            int[] dice = gamestate.Dice;
            Play p = hints[0].Play;
            for (int i = 0; i < p.Count; i++)
            {
                int slot = p[i].From;
                int before = 0;
                int after = 0;
                int die = p[i].From - p[i].To;

                if (!(die == dice[0] || die == dice[1]))
                    die = System.Math.Max(dice[0], dice[1]);

                if (i == 0)
                    before += total_sleep_before_first;

                if (i == (p.Count - 1) && random.Next(15) == 0)
                    after += random.Next(300, 1300);

                if (on_bar > 0)
                {
                    if (random.Next(8) == 0)
                        before += random.Next(500, 1000);
                }
                else if (!is_bearoff && i > 0 && slot != last_slot && (slot - die >= 0) && slot != last_dest && !p[i].IsEnter && (slot - die != last_dest))
                {
                    int diff = System.Math.Abs(slot - last_slot);

                    if ((last_slot >= 12 && slot < 12) || (slot >= 12 && last_slot < 12))
                        diff = 10;

                    if (diff <= 1)
                        before += random.Next(25, 75);
                    else if (diff <= 3)
                        before += random.Next(50, 350);
                    else if (diff <= 6)
                        before += random.Next(100, 500);
                    else
                        before += random.Next(150, 900);
                }
                else
                {
                }

                play.Add(new TimedMove(hints[0].Play[i], before, after));

                last_slot = slot;
                last_dest = p[i].To;
                on_bar--;
            }

            return play;
        }