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); }
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; }
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; }
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; }