public static double EVOpening(int d, double p) { double ev; string key = d + ":" + p; if (EVOpeningCache.TryGetValue(key, out ev)) { return(ev); } if (p >= MinOpen || p >= WinScore) { EVOpeningCache.Add(key, p); return(p); } ev = Dice.Permute[d] .Average(x => Farkle.GenerateActions(x) .Max(y => (double?)EVOpening(y.DiceToRoll, p + y.ScoreToAdd)) ?? 0D); ev = (p < MinBank || p < MinOpen) ? ev : Math.Max(ev, p); EVOpeningCache.Add(key, ev); Console.Write('.'); return(ev); }
public static double ChanceToWin(int d, double p) { double ev; string key = d + ":" + p; if (EVCache.TryGetValue(key, out ev)) { return(ev); } if (p >= WinScore && p >= MinBank) { EVCache.Add(key, 1); return(1); } ev = Dice.Permute[d] .Average(x => Farkle.GenerateActions(x) .Max(y => (double?)ChanceToWin(y.DiceToRoll, p + y.ScoreToAdd)) ?? 0D); EVCache.Add(key, ev); Console.Write('.'); return(ev); }
public static void Interactive() { Reset(); string cmd = string.Empty, cmdData = null, cmdData2 = null; while (!UserCommand.Quit.Equals(cmd)) { if (Mode == AIMode.Manual || State == GameState.NoGame || PlayerWithTheDice.Value.Type == PlayerType.Human) { Write("<farkler{0}> $ ", PlayerWithTheDice == null ? "" : " : " + PlayerWithTheDice.Value.Name); var cmdtext = Console.ReadLine().Replace(" ", " ").Trim().Split(' '); cmd = cmdtext[0]; cmdData = cmdtext.Length > 1 ? cmdtext[1] : null; cmdData2 = cmdtext.Length > 2 ? cmdtext[2] : null; } else { RandomRoll(); WriteLine(Roll); cmd = string.Empty; //Thread.Sleep(2000); } switch (cmd) { case UserCommand.Reset: Reset(); break; case UserCommand.AddPlayer: if (State == GameState.InGame) { WriteLine("ERR - cannot add a player while a game is in progress."); } else if (cmdData == null) { WriteLine("ERR - (p) Usage: p-PlayerName"); } else if (Players.Any(x => x.Name.Equals(cmdData))) { WriteLine("ERR - player with that name already exists."); } else { Players.AddFirst(new FarklePlayer(cmdData)); WriteLine("Added new player {0}, now there are {1} players.", cmdData, Players.Count); } break; case UserCommand.AddPlayerAI: if (State == GameState.InGame) { WriteLine("ERR - cannot add a player while a game is in progress."); } else if (cmdData == null) { WriteLine("ERR - (p) Usage: p-PlayerName"); } else if (Players.Any(x => x.Name.Equals(cmdData))) { WriteLine("ERR - player with that name already exists."); } else { Players.AddFirst(new FarklePlayer(cmdData, PlayerType.AI)); WriteLine("Added new AI player {0}, now there are {1} players.", cmdData, Players.Count); } break; case UserCommand.ModeAutomatic: Mode = AIMode.Automatic; WriteLine("Mode set to Automatic"); break; case UserCommand.ModeManual: Mode = AIMode.Manual; WriteLine("Mode set to Manual"); break; case UserCommand.RandomRoll: if (Roll != null) { WriteLine("ERR - cannot Roll until current roll is acted upon."); } else { RandomRoll(); WriteLine(Roll); } break; case UserCommand.Roll: if (Roll != null) { WriteLine("ERR - cannot Roll until current roll is acted upon."); } else if (cmdData == null || !Regex.IsMatch(cmdData, @"^\d{" + DiceToRoll + "}$")) { WriteLine("ERR - (r) Usage: r-122245"); } else { Roll = new Roll(cmdData); ActionsPossible = Farkle.GenerateActions(Roll); WriteLine(Roll); } break; case UserCommand.Action: if (PlayerWithTheDice.Value.Type != PlayerType.Human) { WriteLine("ERR - cannot perform Action, player is not human."); } else if (Roll == null) { WriteLine("ERR - cannot perform Action, there is no roll on the table."); } else if (cmdData == null) { WriteLine("ERR - (a) Usage: a-400-3 (a-points-dicetoroll)"); } else { int points; if (!int.TryParse(cmdData, out points)) { WriteLine("ERR - (a) Usage: a-400-3 (a-points-dicetoroll)"); break; } if (!ActionsPossible.Any(x => x.ScoreToAdd == points)) { WriteLine("ERR - no matching possible action."); break; } if (cmdData2 == null) { if (TurnScore + points < 300) { WriteLine("ERR - cannot bank less than 300 points."); break; } TurnScore += points; PlayerWithTheDice.Value.BankedScore += TurnScore; WriteLine("{0} BANKS {1}", CurrentPlayerInfo(), TurnScore); EndTurn(); } else { int dice; if (!int.TryParse(cmdData2, out dice)) { WriteLine("ERR - (a) Usage: a-400-3 (a-points-dicetoroll)"); break; } if (!ActionsPossible.Any(x => x.ScoreToAdd == points && x.DiceToRoll == dice)) { WriteLine("ERR - no matching possible action."); break; } TurnScore += points; DiceToRoll = dice; WriteLine("{0} STASHES {1} and WILL ROLL {2}", CurrentPlayerInfo(), points, dice); Roll = null; } } break; case UserCommand.NewGame: NewGame(); break; case UserCommand.Quit: State = GameState.NoGame; break; default: break; } if (GameState.NoGame.Equals(State)) { continue; } if (Roll != null) { bool turnIsOver = false; switch (PlayerWithTheDice.Value.Type) { case PlayerType.AI: turnIsOver = ChooseAndPerformAction(); Roll = null; ActionsPossible.Clear(); break; case PlayerType.Human: turnIsOver = false; if (!ActionsPossible.Any()) { TurnScore = 0; WriteLine("{0} BUSTED!", CurrentPlayerInfo()); turnIsOver = true; } break; } if (turnIsOver) { EndTurn(); } } FarklePlayer winner = Players.FirstOrDefault(x => x.BankedScore >= ExpectedValueCalc.WinScore); if (winner != null) { WriteLine("\n\n---------- {0} WINS! ----------", winner.Name); WriteLine("{0} Turns for an average of {1} points per turn.", winner.TurnsTaken, (double)winner.BankedScore / winner.TurnsTaken); NewGame(); State = GameState.NoGame; } } //while }
static void RandomRoll() { Roll = Dice.RandomRoll(DiceToRoll); ActionsPossible = Farkle.GenerateActions(Roll); }