public Board(Coords size) { this.Size = size; lowerLeft = new Coords(Array.ConvertAll(size.ToInt32Array(), i => 1)); this.Valid = RuleType.Invalid; Transformation = IdentityTransformation; }
internal MoveDefinition(string pieceType, string label, Coords from, Coords to, Game game) { this.PieceType = pieceType; this.Label = label; this.From = from; this.To = to; this.Game = game; }
public static bool Match(Coords c1, Coords c2) { if (c1.coords.Length != c2.coords.Length) return false; for (int i = 0; i < c1.coords.Length; i++) { if (c1.placeholder[i] || c2.placeholder[i]) continue; if (c1.coords[i] != c2.coords[i]) return false; } return true; }
public CoordTransformer(Coords[] game, Coords[] board) { if (game.Length != board.Length) throw new ArgumentException("Lengths must be equal"); for (int i = 0; i < game.Length; i++) { if (board[i].Dimension != 2) throw new ArgumentException("Board coords must be in 2D!"); game2board.Add(game[i], board[i]); board2game.Add(board[i], game[i]); } }
public Coords GameToBoard(Coords c) { Coords ret; if (game2board.TryGetValue(c, out ret)) { return ret; } else { return new Coords(-1); } }
public Coords BoardToGame(Coords c) { Coords ret; if (board2game.TryGetValue(c, out ret)) { return ret; } else { return new Coords(-1); } }
public IEnumerable<MoveDefinition> EnumerateMovesFromCoord(GameState state, Coords c) { var ret = EnumeratePossibleMoves(state).Where(md => md.From != null && Coords.Match(c, md.From)); return ret; }
private void PossibleCoordsToArray(GameState state, int[] coords, int dimension, Player asker, List<Coords> outList) { if (dimension == Size.Dimension) { Coords c = new Coords(coords); if (IsValidByRules(state, c)) { outList.Add(Transformation(asker, c)); } return; } for (int i = 1; i <= Size[dimension]; i++) { var newCoords = new List<int>(coords); newCoords.Add(i); PossibleCoordsToArray(state, newCoords.ToArray(), dimension + 1, asker, outList); } }
private bool IsValidByRules(GameState state, Coords c) { Context ctx = new Context(state); ctx.SetXYZ(c, null); if (Valid == RuleType.Valid) { // We must match at least one rule foreach (var exp in ruleList) { bool b = (bool)exp.Eval(state, ctx); if (b) return true; } return false; } else { // We mustn't match any rule foreach (var exp in ruleList) { bool b = (bool)exp.Eval(state, ctx); if (b) return false; } return true; } }
private Coords IdentityTransformation(Player p, Coords c) { return c; }
public GameState TryMakeMove(GameState oldState, Coords from, Coords to) { GameState newState = oldState.Clone(); Context ctx = new Context(newState.GlobalContext); // Special vars x, y are from coordinates ctx.SetXYZ(from, newState.CurrentPlayer); ctx.SetVariable("from", Transform(from, newState.CurrentPlayer)); ctx.SetVariable("to", Transform(to, newState.CurrentPlayer)); ctx.SetVariable("NewGameState", newState); if (!MoveIsValidGlobal(newState, from, to, ctx)) return null; Piece piece = board.PieceAt(newState, from, null); Piece oppPiece = board.PieceAt(newState, to, null); bool isInlist = EnumerateMovesFromCoord(newState, from).Any( md => Coords.Match(md.From, from) && Coords.Match(md.To, to)); if (!isInlist) return null; foreach (var rule in moveRules) { // No offboard rules here if (rule.OffboardRule) continue; var fromT = Transform(from, newState.CurrentPlayer); var toT = Transform(to, newState.CurrentPlayer); if (!MoveIsValidForRule(newState, rule, null, fromT, toT, ctx)) continue; // Move is valid rule.RunAction(newState, ctx); // Perform the move piece = board.PieceAt(newState, from, null); if (!board.TryRemove(newState, from, null)) { // Original piece was removed, should not happen! throw new InvalidGameException("Cannot move from " + from.ToString() + ", piece " + oppPiece.ToString() + " was removed!"); } if (!board.TryPut(newState, to, piece, null)) { // Piece was not captured throw new InvalidGameException("Cannot move to " + to.ToString() + ", piece " + oppPiece.ToString() + " is in the way!"); } ctx.SetXYZ(to, newState.CurrentPlayer); // Move was performed oldStates.Add(oldState); newState.CurrentPlayer.PostMove(newState, ctx); PostMoveActions(newState); return newState; } // No suitable rule found. return null; }
internal bool MoveIsValidForRule(GameState currentState, MoveRule rule, Piece piece, Coords from, Coords to, Context ctx) { if (from != null) piece = board.PieceAt(currentState, from, currentState.CurrentPlayer); Piece oppPiece = board.PieceAt(currentState, to, currentState.CurrentPlayer); // Rule must be applicable to current piece if (rule.PieceType != piece.Type) return false; // Target should be empty if (rule.TargetMustBeEmpty && oppPiece != null) return false; if (rule.Condition != null) { bool cond = (bool)rule.Condition.Eval(currentState, ctx); if (!cond) return false; } if (rule.From == null) { if (!currentState.CurrentPlayer.GetOffboard(currentState).Contains(piece)) return false; //var toT = board.Transformation(CurrentPlayer, to); ///var toTExpr = board.Transformation(CurrentPlayer, (Coords)rule.To.Eval(ctx)); if (!Coords.Match(to, (Coords)rule.To.Eval(currentState, ctx))) return false; } else if (rule.To == null) { throw new NotImplementedException(); } else { // Check coords //var fromT = board.Transformation(CurrentPlayer, from); //var toT = board.Transformation(CurrentPlayer, to); //var fromTExpr = board.Transformation(CurrentPlayer, (Coords)rule.From.Eval(ctx)); //var toTExpr = board.Transformation(CurrentPlayer, (Coords)rule.To.Eval(ctx)); if (!Coords.Match(from, (Coords)rule.From.Eval(currentState, ctx))) return false; if (!Coords.Match(to, (Coords)rule.To.Eval(currentState, ctx))) return false; } return true; }
public bool IsValidBoardCoord(Coords c) { return board2game.ContainsKey(c); }
public static bool IsEmpty(Context ctx, Coords c) { return ctx.Game.board.PieceAt(ctx.GameState, c, ctx.GameState.CurrentPlayer) == null; }
public static bool Match(Context ctx, Coords from, Coords target, RegExp.Pattern.Direction direction, RegExp.Pattern pattern) { return pattern.Match(ctx.GameState, target, from, direction); }
public static IEnumerable<object> GetMatching(Context ctx, Coords from, Coords target, int direction, RegExp.Pattern pattern) { IEnumerable<Coords> c; if (pattern.CaptureAll(ctx.GameState, target, from, RegExp.Pattern.Direction.Any, out c)) { return c; } else { return new List<object>(); } }
internal Coords Transform(Coords c, Player asker) { return board.Transformation(asker, c); }
internal bool MoveIsValidGlobal(GameState currentState, Coords from, Coords to, Context ctx) { if (from != null && !board.IsValidPlace(currentState, from)) return false; if (to != null && !board.IsValidPlace(currentState, to)) return false; if (from == null && to == null) return false; if (from != null) { Piece piece = board.PieceAt(currentState, from, null); // Cannot move empty square if (piece == null) return false; // Cannot move opponent's piece if (piece.Owner != currentState.CurrentPlayer) return false; // Cannot stay in place // Why not? :) //if (Coords.Match(from, to)) return false; } return true; }
public bool IsValidPlace(GameState state, Coords c) { if (c.IsPlaceHolder) throw new ArgumentOutOfRangeException("Non-placeholder coords needed."); for (int i = 0; i < c.Dimension; i++) { if (c[i] < 1 || c[i] > Size[i]) return false; } return IsValidByRules(state, c); }
public MainWindow() { InitializeComponent(); offBoard.Selected += (sender, args) => { switch (selectState) { case SelectState.From: FromOffboard = args.Piece; selectState = SelectState.To; break; case SelectState.To: if (FromOffboard == args.Piece) { // Unselect it FromOffboard = null; selectState = SelectState.From; } else if (FromOffboard != null) { FromOffboard = args.Piece; } else { // Unsupported } break; case SelectState.Special: if (mustSelectFrom.Contains(args.Piece)) { SetSelected(args.Piece); } break; } gamePanel.InvalidateVisual(); offBoard.InvalidateVisual(); }; gamePanel.Selected += (sender, args) => { switch (selectState) { case SelectState.From: FromCoord = args.Coords; if (FromCoord != null) { selectState = SelectState.To; } break; case SelectState.To: if (fromCoord != null && Coords.Match(fromCoord, args.Coords)) { FromCoord = null; selectState = SelectState.From; } else { toCoord = args.Coords; MakeMove(); } break; case SelectState.Special: foreach (var kvp in game.GetPieces(gameState)) { if (Coords.Match(kvp.Key, args.Coords) && mustSelectFrom.Contains(kvp.Value)) { SetSelected(kvp.Value); return; } } break; } gamePanel.InvalidateVisual(); offBoard.InvalidateVisual(); }; App.Current.DispatcherUnhandledException += (sender, args) => { InvalidGameException ex = args.Exception as InvalidGameException; if (ex != null) { System.Windows.MessageBox.Show(ex.Message, "Invalid game", MessageBoxButton.OK, MessageBoxImage.Error); args.Handled = true; } }; }
internal void SetXYZ(Coords cIn, Player asker) { var c = Game.Transform(cIn, asker); if (c.Dimension >= 1) { SetVariable("x", c[0]); } if (c.Dimension >= 2) { SetVariable("y", c[1]); } if (c.Dimension >= 3) { SetVariable("z", c[2]); } }
private bool TenPredicate(GameState state, Coords coords) { return coords[1] == 10; }
public static Piece PieceAt(Context ctx, Coords c) { return ctx.Game.board.PieceAt(ctx.GameState, c, ctx.GameState.CurrentPlayer); }
public GameState TryMakeMoveFromOffboard(GameState oldState, Piece piece, Coords to) { GameState newState = oldState.Clone(); Context ctx = new Context(newState.GlobalContext); ctx.SetVariable("to", Transform(to, newState.CurrentPlayer)); ctx.SetVariable("NewGameState", newState); // piece cannot be null if (piece == null) return null; // Cannot move opponent's piece if (piece.Owner != newState.CurrentPlayer) return null; bool isInlist = EnumerateMovesFromOffboard(newState, piece).Any( md => md.From == null && Coords.Match(md.To, to) && md.PieceType == piece.Type); if (!isInlist) return null; if (!MoveIsValidGlobal(newState, null, to, ctx)) return null; Piece oppPiece = board.PieceAt(newState, to, null); foreach (var rule in moveRules) { // Only offboard rules here if (!rule.OffboardRule) continue; if (!MoveIsValidForRule(newState, rule, piece, null, to, ctx)) continue; // Move is valid rule.RunAction(newState, ctx); // Perform the move if (!newState.CurrentPlayer.RemoveOffBoard(newState, piece)) { // Original piece was removed, should not happen! throw new InvalidGameException("Cannot move from offboard, piece " + oppPiece.ToString() + " was removed!"); } if (!board.TryPut(newState, to, piece, null)) { // Piece was not captured throw new InvalidGameException("Cannot move to " + to.ToString() + ", piece " + oppPiece.ToString() + " is in the way!"); } ctx.SetXYZ(to, newState.CurrentPlayer); // Move was performed oldStates.Add(oldState); newState.CurrentPlayer.PostMove(newState, ctx); PostMoveActions(newState); return newState; } // No suitable rule found. return null; }
private void MakeMove() { if (fromOffboard != null && toCoord != null) { // From offboard to board var newGameState = game.TryMakeMoveFromOffboard(gameState, FromOffboard, toCoord); if (newGameState != null) gameState = newGameState; offBoard.Refresh(); gamePanel.InvalidateVisual(); } else if (fromCoord != null && toCoord != null) { // From coords to coords var newGameState = game.TryMakeMove(gameState, FromCoord, toCoord); if (newGameState != null) gameState = newGameState; offBoard.Refresh(); gamePanel.InvalidateVisual(); } if (game.GameOver) { if (game.PlayerCount == 1) { if (game.Winners.Count() == 1) { System.Windows.MessageBox.Show("You won!"); } else { System.Windows.MessageBox.Show("You lost!"); } } else { if (game.Winners.Count() == 0) { System.Windows.MessageBox.Show("Game over!\nThe game ended in a tie!"); } else if (game.Winners.Count() == 1) { System.Windows.MessageBox.Show("Game over!\nThe winner is: " + game.Winners.First().ToString()); } else { System.Windows.MessageBox.Show("Game over!\nThe winners are: " + string.Join(", ", game.Winners)); } } NewGame(); } selectState = SelectState.From; FromCoord = null; FromOffboard = null; toCoord = null; currentPlayerLabel.Content = gameState.CurrentPlayer.ToString(); }
public static void Place(Context ctx, string piecetype, Coords c) { Piece p = new Piece(piecetype, ctx.GameState.CurrentPlayer, ctx.Game); ctx.Game.board.TryPut(ctx.GameState, c, p, ctx.GameState.CurrentPlayer); }
private bool TargetPredicate(GameState state, Coords coords) { return Coords.Match(coords, new Coords(5, 7)); }
public Piece PieceAt(GameState state, Coords c, Player asker) { Piece p; if (state.Board.TryGetValue(Transformation(asker, c), out p)) return p; return null; }
private bool TruePredicate(GameState state, Coords coords) { return true; }
public bool TryRemove(GameState state, Coords cIn, Player asker) { Coords c = Transformation(asker, cIn); if (c.IsPlaceHolder) throw new ArgumentOutOfRangeException("Non-placeholder coords needed."); if (!IsValidPlace(state, c)) { throw new ArgumentOutOfRangeException("Coords must be inside the board."); } if (!state.Board.ContainsKey(c)) return false; state.Board.Remove(c); return true; }