using System; using System.Collections.Generic; using Vector2I = Vector.Vector2I; using static IBoard; public abstract class AbstractBoard : IBoard { private readonly int rows; private readonly int cols; protected readonly IPiece[,] pieces; protected readonly List moveRecords = new(); protected readonly int MAX_RECORDS; public int Rows => rows; public int Cols => cols; public event EventHandler OnSetPiece; public event EventHandler OnInsert; public event EventHandler OnRemove; public event EventHandler OnMove; public event EventHandler OnAddRecord; public event EventHandler OnUndoRecord; public AbstractBoard(int rows, int cols, int maxRecords = int.MaxValue) { this.rows = rows; this.cols = cols; pieces = new IPiece[rows, cols]; MAX_RECORDS = maxRecords; } public virtual bool IsPosOutOfRange(Vector2I arrayPos) { return arrayPos.X < 0 || arrayPos.X >= Rows || arrayPos.Y < 0 || arrayPos.Y >= Cols; } public virtual IPiece GetPiece(Vector2I arrayPos) { if (IsPosOutOfRange(arrayPos)) return null; return pieces[arrayPos.X, arrayPos.Y]; } public virtual IPiece SetPiece(IPiece piece, Vector2I pos) { if (IsPosOutOfRange(pos)) return null; IPiece oldPiece = pieces[pos.X, pos.Y]; pieces[pos.X, pos.Y] = piece; if (piece != null) piece.Pos = pos; // if (oldPiece != null) oldPiece.Pos = Vector2I.Zero; OnSetPiece?.Invoke(this, new SetPieceEventArgs { OldPiece = oldPiece, NewPiece = piece, Pos = pos }); return oldPiece; } public virtual bool InsertPiece(IPiece piece, Vector2I pos) { if (GetPiece(pos) != null && piece == null) { return false; } OnInsert?.Invoke(this, piece); SetPiece(piece, pos); return true; } public virtual bool MovePiece(Vector2I from, Vector2I to) { if (IsPosOutOfRange(to) || IsPosOutOfRange(from)) { return false; } IPiece piece = GetPiece(from); if (GetPiece(to) != null && piece == null) { return false; } OnMove?.Invoke(this, new MoveEventArgs { From = from, To = to, Piece = piece }); SetPiece(null, from); SetPiece(piece, to); return true; } public virtual IPiece RemovePiece(Vector2I pos) { IPiece piece = GetPiece(pos); OnRemove?.Invoke(this, piece); return SetPiece(null, pos); } public virtual void Clear() { Clear(true); } public virtual void Clear(bool clearRecords) { for (int i = 0; i < Rows; i++) { for (int j = 0; j < Cols; j++) { RemovePiece(new Vector2I(i, j)); } } if (clearRecords) ClearRecords(); } public virtual void ClearRecords() { moveRecords.Clear(); } public virtual void AddRecord(IPiece From, IPiece To, Vector2I FromPos, Vector2I ToPos) { if (moveRecords.Count >= MAX_RECORDS) { moveRecords.RemoveAt(0); } MoveRecord record = new(From, To, FromPos, ToPos); OnAddRecord?.Invoke(this, record); moveRecords.Add(record); } public virtual void UndoRecord() { if (moveRecords.Count == 0) return; MoveRecord record = moveRecords[^1]; moveRecords.RemoveAt(moveRecords.Count - 1); // 恢复新位置的棋子,order is very inmportant if (record.From != null) { MovePiece(record.ToPos, record.FromPos); } // 恢复旧位置的棋子 if (record.To != null) { InsertPiece(record.To, record.ToPos); } OnUndoRecord?.Invoke(this, record); } public class MoveRecord { public IPiece From { get; } public IPiece To { get; } public Vector2I FromPos { get; } public Vector2I ToPos { get; } public MoveRecord(IPiece From, IPiece To, Vector2I FromPos, Vector2I ToPos) { this.From = From; this.To = To; this.ToPos = ToPos; this.FromPos = FromPos; } } }