diff --git a/.gitignore b/.gitignore index 4e6f349..7ecfc1a 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,10 @@ bin/ *.sln *.error *.key* + +# cs project files +!*.csproj + +# Test files +Test/bin +Test/obj \ No newline at end of file diff --git a/Chinese_Chess.csproj b/Chinese_Chess.csproj new file mode 100644 index 0000000..1748c47 --- /dev/null +++ b/Chinese_Chess.csproj @@ -0,0 +1,15 @@ + + + net6.0 + net7.0 + net8.0 + true + + enable + + + + + + + \ No newline at end of file diff --git a/Scripts/Lib/RPClient.cs b/Scripts/Lib/RPClient.cs index 3881fd0..0fe1c42 100644 --- a/Scripts/Lib/RPClient.cs +++ b/Scripts/Lib/RPClient.cs @@ -4,21 +4,26 @@ using Godot.Collections; namespace RPPackage { public partial class RPClientBaseEDWS : EventDrivenWebSocket { - public delegate void RPClientEventHandler(string cmd, Dictionary data); + public delegate void RPClientEventHandler(string cmd, Dictionary? data); public delegate void RPClientErrorHandler(string errCode, string type, string cmd, string errMsg); - public event RPClientEventHandler OnRPCUser; - public event RPClientEventHandler OnRPCRegion; - public event RPClientEventHandler OnRPCSession; - public event RPClientEventHandler OnRPCMsg; - public event RPClientErrorHandler OnRPCError; + public event RPClientEventHandler? OnRPCUser; + public event RPClientEventHandler? OnRPCRegion; + public event RPClientEventHandler? OnRPCSession; + public event RPClientEventHandler? OnRPCMsg; + public event RPClientErrorHandler? OnRPCError; public RPClientBaseEDWS() : base() { OnText += (text) => { // GD.Print($"response: {text}"); - RPMessage msg = RPHelper.HandleIncomingMessage(text); + RPMessage? msg = RPHelper.HandleIncomingMessage(text); + if (msg == null) { + MakeRPCError("9999", "Unknown Msg", "Error", null); + return; + } if (msg.Code != "0000") { - OnRPCError?.Invoke(msg.Code, msg.Type, msg.Cmd, msg.Data.ToString()); + OnRPCError?.Invoke(msg.Code ?? "9999", msg.Type, msg.Cmd, + msg.Data?.ToString() ?? ""); return; } switch (msg.Type) { @@ -35,32 +40,36 @@ public partial class RPClientBaseEDWS : EventDrivenWebSocket { OnRPCMsg?.Invoke(msg.Cmd, msg.Data); break; default: - OnRPCError?.Invoke(msg.Code, "unknown", msg.Cmd, msg.Data.ToString()); + MakeRPCError(msg.Code, "unknown", msg.Cmd, msg.Data?.ToString()); break; } }; } - protected void MakeRPCError(string errCode, string type, string cmd, string errMsg) { - this.OnRPCError?.Invoke(errCode, type, cmd, errMsg ?? "null"); + protected void MakeRPCError(string errCode, string type, string cmd, string? errMsg) { + OnRPCError?.Invoke(errCode, type, cmd, errMsg ?? "null"); } } public partial class RPClientEDWS : RPClientBaseEDWS { - string userName; - string userId; - string userToken; - string regionId; + string? userName; + string? userId; + string? userToken; + string? regionId; - public string GetUserId() { return userId; } + public string? GetUserId() { return userId; } - public delegate void SessionRecvHandle(Dictionary msg); - public event SessionRecvHandle OnPRCSessionRecv; + public delegate void SessionRecvHandle(Dictionary? msg); + public event SessionRecvHandle? OnPRCSessionRecv; - public event RPClientEventHandler OnPRCSessionExit; + public event RPClientEventHandler? OnPRCSessionExit; public RPClientEDWS() : base() { OnRPCUser += (cmd, msg) => { + if (msg == null) { + MakeRPCError("0000", "User", "unknown", "unknown"); + return; + } switch (cmd) { case "init": userId = msg["userId"].AsString(); @@ -113,7 +122,7 @@ public partial class RPClientEDWS : RPClientBaseEDWS { OnRPCMsg += (cmd, msg) => { switch(cmd) { case "echo": - GD.Print(msg["_"].AsString()); + GD.Print(msg?["_"].AsString()); break; default: break; @@ -148,7 +157,7 @@ public partial class RPClientEDWS : RPClientBaseEDWS { } public delegate bool UserInitCallback(); - private UserInitCallback _userInitCallback; + private UserInitCallback? _userInitCallback; public bool UserInit(string userName, string fingerPrint, UserInitCallback callback) { if (this.GetIsConnected() == false) { return false; @@ -201,14 +210,14 @@ public partial class RPClientEDWS : RPClientBaseEDWS { public delegate bool RegionInspectCallback( Array> _ ); - private RPClientEventHandler _regionRecvCallback; + private RPClientEventHandler? _regionRecvCallback; public bool RegionInspect(string regionId, RegionInspectCallback callback) { if (this.GetIsConnected() == false || this.userId == null) { return false; } _regionRecvCallback = null; _regionRecvCallback += (cmd, msg) => { - if (cmd != "inspect") { + if (cmd != "inspect" || msg == null) { return; } callback(msg["_"].AsGodotArray>()); @@ -228,17 +237,18 @@ public partial class RPClientEDWS : RPClientBaseEDWS { public delegate bool SessionAckCreateCallback( string sessionId, bool res, - string reqUserId, - string reqUserName + string? reqUserId, + string? reqUserName ); - private RPClientEventHandler _sessionAckCreateCallback; + private RPClientEventHandler? _sessionAckCreateCallback; public void RegSessionAckCreateCallback(SessionAckCreateCallback recvCallback) { _sessionAckCreateCallback = null; _sessionAckCreateCallback += (cmd, msg) => { + if (msg == null) return; string sessionId = msg["sessionId"].AsString(); bool res = msg.ContainsKey("res") && msg["res"].AsBool(); - string reqUserId = msg.ContainsKey("reqUserId") ? msg["reqUserId"].AsString() : null; - string reqUserName = msg.ContainsKey("reqUserName") ? msg["reqUserName"].AsString() : null; + string? reqUserId = msg.ContainsKey("reqUserId") ? msg["reqUserId"].AsString() : null; + string? reqUserName = msg.ContainsKey("reqUserName") ? msg["reqUserName"].AsString() : null; recvCallback(sessionId, res, reqUserId, reqUserName); }; } diff --git a/Scripts/Lib/RPHelper.cs b/Scripts/Lib/RPHelper.cs index aca60bf..1e50e5d 100644 --- a/Scripts/Lib/RPHelper.cs +++ b/Scripts/Lib/RPHelper.cs @@ -9,12 +9,14 @@ public static class RPHelper return message.ToDictionary(); } - public static RPMessage DeserializeRPMessage(Dictionary data) + public static RPMessage? DeserializeRPMessage(Dictionary data) { - return new RPMessage - { - Type = data.ContainsKey("type") ? (string)data["type"] : null, - Cmd = data.ContainsKey("cmd") ? (string)data["cmd"] : null, + if (!data.ContainsKey("type") || !data.ContainsKey("cmd")) { + return null; + } + return new RPMessage { + Type = (string)data["type"], + Cmd = (string)data["cmd"], Code = data.ContainsKey("code") ? (string)data["code"] : null, Uid = data.ContainsKey("uid") ? (string)data["uid"] : null, Token = data.ContainsKey("token") ? (string)data["token"] : null, @@ -28,7 +30,7 @@ public static class RPHelper ws.SendJsonEx(RPHelper.SerializeRPMessage(message)); } - public static RPMessage HandleIncomingMessage(string jsonMessage) + public static RPMessage? HandleIncomingMessage(string jsonMessage) { var dataDict = Json.ParseString(jsonMessage).AsGodotDictionary(); if (dataDict != null) diff --git a/Scripts/Lib/RPMessage.cs b/Scripts/Lib/RPMessage.cs index 732db51..335cf4f 100644 --- a/Scripts/Lib/RPMessage.cs +++ b/Scripts/Lib/RPMessage.cs @@ -4,20 +4,21 @@ using Godot.Collections; namespace RPPackage { public class RPMessage { - public string Type { get; set; } - public string Cmd { get; set; } - public Dictionary Data { get; set; } + public string Type { get; set; } = string.Empty; + public string Cmd { get; set; } = string.Empty; + public Dictionary? Data { get; set; } - public string Uid { get; set; } - public string Token { get; set; } - public string Code { get; set; } + public string? Uid { get; set; } + public string? Token { get; set; } + public string? Code { get; set; } public Dictionary ToDictionary() { - var dict = new Dictionary(); - if (Type != null) - dict.Add("type", Type); - if (Cmd != null) - dict.Add("cmd", Cmd); + var dict = new Dictionary { + // if (Type != null) + { "type", Type }, + // if (Cmd != null) + { "cmd", Cmd } + }; if (Data != null) dict.Add("data", Data); diff --git a/Scripts/Lib/gdws.cs b/Scripts/Lib/gdws.cs index e17fa59..248db63 100644 --- a/Scripts/Lib/gdws.cs +++ b/Scripts/Lib/gdws.cs @@ -2,16 +2,16 @@ using Godot; using Godot.Collections; public partial class EventDrivenWebSocket : WebSocketPeer { - public delegate void WebSocketEventHandler(string eventName, params object[] args); + public delegate void WebSocketEventHandler(string eventName, params object[]? args); public delegate void WSBinMsgEventHandler(byte[] args); public delegate void WSMsgEventHandler(string args); - public event WebSocketEventHandler OnOpen; - public event WSBinMsgEventHandler OnMessage; - public event WSMsgEventHandler OnText; - public event WSBinMsgEventHandler OnBinary; - public event WebSocketEventHandler OnClose; - public event WebSocketEventHandler OnError; + public event WebSocketEventHandler? OnOpen; + public event WSBinMsgEventHandler? OnMessage; + public event WSMsgEventHandler? OnText; + public event WSBinMsgEventHandler? OnBinary; + public event WebSocketEventHandler? OnClose; + public event WebSocketEventHandler? OnError; private bool isConnected = false; private bool isCloseEventFired = false; @@ -32,7 +32,7 @@ public partial class EventDrivenWebSocket : WebSocketPeer { } public void ConnectToUrlEx(string url, double delayTime = 3, - TlsOptions tlsClientOptions = null) { + TlsOptions? tlsClientOptions = null) { if (connectingTime >= 0) { return; } diff --git a/Scripts/Src/AbstractBoard.cs b/Scripts/Src/AbstractBoard.cs index f5c19d5..af269fd 100644 --- a/Scripts/Src/AbstractBoard.cs +++ b/Scripts/Src/AbstractBoard.cs @@ -6,20 +6,20 @@ using static IBoard; public abstract class AbstractBoard : IBoard { private readonly int rows; private readonly int cols; - protected readonly IPiece[,] pieces; + 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? OnSetPiece; + public event EventHandler? OnInsert; + public event EventHandler? OnRemove; + public event EventHandler? OnMove; - public event EventHandler OnAddRecord; - public event EventHandler OnUndoRecord; + public event EventHandler? OnAddRecord; + public event EventHandler? OnUndoRecord; public AbstractBoard(int rows, int cols, int maxRecords = int.MaxValue) { this.rows = rows; @@ -32,15 +32,15 @@ public abstract class AbstractBoard : IBoard { return arrayPos.X < 0 || arrayPos.X >= Rows || arrayPos.Y < 0 || arrayPos.Y >= Cols; } - public virtual IPiece GetPiece(Vector2I arrayPos) { + 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) { + public virtual IPiece? SetPiece(IPiece? piece, Vector2I pos) { if (IsPosOutOfRange(pos)) return null; - IPiece oldPiece = pieces[pos.X, pos.Y]; + 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; @@ -64,8 +64,8 @@ public abstract class AbstractBoard : IBoard { return false; } - IPiece piece = GetPiece(from); - if (GetPiece(to) != null && piece == null) { + IPiece? piece = GetPiece(from); + if (GetPiece(to) != null || piece == null) { return false; } @@ -75,8 +75,9 @@ public abstract class AbstractBoard : IBoard { return true; } - public virtual IPiece RemovePiece(Vector2I pos) { - IPiece piece = GetPiece(pos); + public virtual IPiece? RemovePiece(Vector2I pos) { + IPiece? piece = GetPiece(pos); + if (piece == null) return null; OnRemove?.Invoke(this, piece); return SetPiece(null, pos); } @@ -96,7 +97,7 @@ public abstract class AbstractBoard : IBoard { moveRecords.Clear(); } - public virtual void AddRecord(IPiece From, IPiece To, Vector2I FromPos, Vector2I ToPos) { + public virtual void AddRecord(IPiece? From, IPiece? To, Vector2I FromPos, Vector2I ToPos) { if (moveRecords.Count >= MAX_RECORDS) { moveRecords.RemoveAt(0); } @@ -125,12 +126,12 @@ public abstract class AbstractBoard : IBoard { } public class MoveRecord { - public IPiece From { get; } - public IPiece To { get; } + 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) { + public MoveRecord(IPiece? From, IPiece? To, Vector2I FromPos, Vector2I ToPos) { this.From = From; this.To = To; this.ToPos = ToPos; diff --git a/Scripts/Src/AbstractPiece.cs b/Scripts/Src/AbstractPiece.cs index f5cdfb2..4f5bbf3 100644 --- a/Scripts/Src/AbstractPiece.cs +++ b/Scripts/Src/AbstractPiece.cs @@ -46,10 +46,10 @@ public abstract class AbstractPiece : IPiece { set => data = value; } - public event EventHandler OnPos; - public event EventHandler OnMove; - public event EventHandler OnSelected; - public event EventHandler OnName; + public event EventHandler? OnPos; + public event EventHandler? OnMove; + public event EventHandler? OnSelected; + public event EventHandler? OnName; public virtual bool Move(Vector2I pos) { if (!CanMove(pos)) { @@ -66,7 +66,7 @@ public abstract class AbstractPiece : IPiece { return $"{Name} at {pos}"; } - public AbstractPiece(string name = "", Vector2I pos = null) { + public AbstractPiece(string name = "", Vector2I? pos = null) { this.name = name; this.pos = pos ?? new(); } diff --git a/Scripts/Src/ChineseChess/CCBoard.cs b/Scripts/Src/ChineseChess/CCBoard.cs index 999c33f..83ba89c 100644 --- a/Scripts/Src/ChineseChess/CCBoard.cs +++ b/Scripts/Src/ChineseChess/CCBoard.cs @@ -6,7 +6,7 @@ using Vector2I = Vector.Vector2I; namespace ChineseChess; public class CCBoard : AbstractBoard { - public event EventHandler OnStepsChanged; + public event EventHandler? OnStepsChanged; private int steps = 0; public int Steps { get => steps; @@ -20,7 +20,7 @@ public class CCBoard : AbstractBoard public CCBoard() : base(9, 10) { } - public override void AddRecord(IPiece From, IPiece To, Vector2I FromPos, Vector2I ToPos) { + public override void AddRecord(IPiece? From, IPiece? To, Vector2I FromPos, Vector2I ToPos) { base.AddRecord(From, To, FromPos, ToPos); Steps += 1; } diff --git a/Scripts/Src/ChineseChess/CCMain.cs b/Scripts/Src/ChineseChess/CCMain.cs index 9fa4ccd..c2e5481 100644 --- a/Scripts/Src/ChineseChess/CCMain.cs +++ b/Scripts/Src/ChineseChess/CCMain.cs @@ -33,12 +33,19 @@ public class ChessCore { playerSelf = new(board, Player.PlayerType.Human); playerOpponent = new(board, Player.PlayerType.Human); - void func(object _self, IBoard.MoveEventArgs record) { + void func(object? _self, IBoard.MoveEventArgs record) { // 防止 Undo 时 Selected Clear 出现 Null Pointer Exception playerSelf.SelectedClear(); playerOpponent.SelectedClear(); - board.AddRecord(board.GetPiece(record.From), board.GetPiece(record.To), - record.From, record.To); + + // TODO FIXME it can be simple + if (record.From is null || record.To is null) { + return; + } + + IPiece? from = record.From is not null ? board.GetPiece(record.From) : null; + IPiece? to = record.To is not null ? board.GetPiece(record.To) : null; + board.AddRecord(from, to, record.From ?? new(), record.To ?? new()); } playerSelf.OnMove += func; playerOpponent.OnMove += func; diff --git a/Scripts/Src/ChineseChess/CCPiece.cs b/Scripts/Src/ChineseChess/CCPiece.cs index d18e247..4666351 100644 --- a/Scripts/Src/ChineseChess/CCPiece.cs +++ b/Scripts/Src/ChineseChess/CCPiece.cs @@ -7,7 +7,7 @@ using Vector; using static ChineseChess.ChessCore; public class CCPiece : AbstractPiece { - public string CNName { get; protected set; } + public string CNName { get; protected set; } = "unknown"; public TurnsSideType TurnsSide { get; } protected CCBoard board; protected Vector2I localPos = new(); @@ -16,14 +16,15 @@ public class CCPiece : AbstractPiece { new(new Vector2I(1, 0), new Vector2I(0, -1), new Vector2I(-4, 9)); static readonly Trans2DI transBlackGlobal2Local = new(new Vector2I(-1, 0), new Vector2I(0, 1), new Vector2I(4, 0)); - public CCPiece(CCBoard board = null, TurnsSideType turnsSide = TurnsSideType.Red, - string name = "", Vector2I pos = null) : base(name) { - this.board = board; + public CCPiece(CCBoard? board = null, TurnsSideType turnsSide = TurnsSideType.Red, + string name = "", Vector2I? pos = null) : base(name) { + this.board = board ?? new(); TurnsSide = turnsSide; OnPos += (sender, args) => { localPos = Global2Local(Pos); }; - Pos = pos != null ? Local2Global(pos) : Vector2I.Zero; + Pos = pos is not null ? Local2Global(pos) : Vector2I.Zero; + localPos = Global2Local(Pos); } public override bool CanMove(Vector2I to) { @@ -38,8 +39,8 @@ public class CCPiece : AbstractPiece { return TurnsSide == TurnsSideType.Red ? (transRedGlobal2Local * pos) : (transBlackGlobal2Local * pos); } - protected CCPiece GetCCPieceLocal(in Vector2I pos) { - return (CCPiece)board.GetPiece(Local2Global(pos)); + protected CCPiece? GetCCPieceLocal(in Vector2I pos) { + return (CCPiece?)board.GetPiece(Local2Global(pos)); } public virtual List CanMoveAllPosSelf() { @@ -49,7 +50,8 @@ public class CCPiece : AbstractPiece { public IEnumerable CanMoveAllPosLocal() { var self = CanMoveAllPosSelf().Select(item => item + localPos);// 转换局部坐标 var ret = self.Where(item => { - bool ret = GetCCPieceLocal(item) == null || GetCCPieceLocal(item).TurnsSide != TurnsSide; + CCPiece? piece = GetCCPieceLocal(item); + bool ret = piece is null || piece.TurnsSide != TurnsSide; // Console.WriteLine($"{item} can move: {ret}"); return ret; }); // 过滤无效位置 @@ -71,7 +73,7 @@ public class CCPiece : AbstractPiece { return board.IsPosOutOfRange(Local2Global(pos)); } - protected CCPiece GetRecursivePieceLocal(Vector2I origin, Vector2I pos) { + protected CCPiece? GetRecursivePieceLocal(Vector2I origin, Vector2I pos) { Vector2I with = origin + pos; while (!IsPosOutOfRangeLocal(with) && GetCCPieceLocal(with) == null) { with += pos; diff --git a/Scripts/Src/ChineseChess/CCPlayer.cs b/Scripts/Src/ChineseChess/CCPlayer.cs index b9b6d54..2525a2e 100644 --- a/Scripts/Src/ChineseChess/CCPlayer.cs +++ b/Scripts/Src/ChineseChess/CCPlayer.cs @@ -7,7 +7,7 @@ public class Player { private readonly CCBoard board; private readonly SelectedPiece selectedNode; - public EventHandler OnMove; + public EventHandler? OnMove; public bool CanMove { get; set; } = true; public enum PlayerType { @@ -24,7 +24,7 @@ public class Player { public void HandleBoardPosClick(Vector2I clickPos) { if (board.IsPosOutOfRange(clickPos)) return; // Console.WriteLine($"VirtualBoard {clickPos} clicked"); - IPiece clickChess = board.GetPiece(clickPos); + IPiece? clickChess = board.GetPiece(clickPos); if (!selectedNode.HasSelected()) { // Select piece @@ -45,9 +45,10 @@ public class Player { public void MoveAndRecord(Vector2I toPos, Vector2I fromPos) { // GD.Print($"{fromPos} move to {toPos}"); - IPiece toChess = board.GetPiece(toPos); - IPiece fromChess = board.GetPiece(fromPos); + IPiece? toChess = board.GetPiece(toPos); + IPiece? fromChess = board.GetPiece(fromPos); if (fromChess != null) fromChess.IsSelected = false; + else return; selectedNode.Clear(); if (!fromChess.CanMove(toPos)) { @@ -55,7 +56,8 @@ public class Player { } // MUST BE THERE !!! 防止删除节点后在启动回调导致错误 - OnMove?.Invoke(this, new IBoard.MoveEventArgs { From = fromPos, To = toPos }); + OnMove?.Invoke(this, new IBoard.MoveEventArgs + { From = fromPos, To = toPos, Piece = fromChess });; if (toChess != null) { board.RemovePiece(toPos); @@ -76,9 +78,9 @@ public class Player { private class SelectedPiece { // Called when the node enters the scene tree for the first time. private Vector2I selectedNodePos = Vector2I.MaxValue; - private IPiece piece; + private IPiece? piece = null; private readonly CCBoard board; - public ArrayList allowedPieces = null; + public ArrayList? allowedPieces = null; public SelectedPiece(CCBoard board) { this.board = board; @@ -87,7 +89,8 @@ public class Player { public void Clear() { if (selectedNodePos != Vector2I.MaxValue) { selectedNodePos = Vector2I.MaxValue; - piece.IsSelected = false; + if (piece != null) + piece.IsSelected = false; } // Console.WriteLine("SelectedPiece.Clear {0}", piece); } @@ -98,11 +101,13 @@ public class Player { return; } selectedNodePos = pos; + if (piece == null) + return; piece.IsSelected = true; Console.WriteLine("SelectedPiece.SetPos {0}", piece); } - public IPiece GetPiece() { + public IPiece? GetPiece() { return piece; } diff --git a/Scripts/Src/ChineseChess/CCTypes.cs b/Scripts/Src/ChineseChess/CCTypes.cs index dfe913b..31560ee 100644 --- a/Scripts/Src/ChineseChess/CCTypes.cs +++ b/Scripts/Src/ChineseChess/CCTypes.cs @@ -4,7 +4,7 @@ using Vector2I = Vector.Vector2I; namespace ChineseChess; public class CCGeneral : CCPiece { - public CCGeneral(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I pos = null) + public CCGeneral(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null) : base(board, turnsSide, name : "General", pos) { if (turnsSide == TurnsSideType.Red) { CNName = "帅"; @@ -31,7 +31,7 @@ public class CCGeneral : CCPiece { } public class CCAdvisor : CCPiece { - public CCAdvisor(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I pos = null) + public CCAdvisor(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null) : base(board, turnsSide, name : "Advisor", pos) { if (turnsSide == TurnsSideType.Red) { CNName = "仕"; @@ -58,7 +58,7 @@ public class CCAdvisor : CCPiece { } public class CCElephant : CCPiece { - public CCElephant(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I pos = null) + public CCElephant(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null) : base(board, turnsSide, name : "Bishop", pos) { if (turnsSide == TurnsSideType.Red) { CNName = "相"; @@ -85,7 +85,7 @@ public class CCElephant : CCPiece { } public class CCHorse : CCPiece { - public CCHorse(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I pos = null) + public CCHorse(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null) : base(board, turnsSide, name : "Horse", pos) { if (turnsSide == TurnsSideType.Red) { CNName = "馬"; @@ -125,7 +125,7 @@ public class CCHorse : CCPiece { } public class CCChariot : CCPiece { - public CCChariot(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I pos = null) + public CCChariot(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null) : base(board, turnsSide, name : "Chariot", pos) { if (turnsSide == TurnsSideType.Red) { CNName = "車"; @@ -145,7 +145,7 @@ public class CCChariot : CCPiece { break; } if (GetCCPieceLocal(ptr) != null) { - list.Add(ptr); + list.Add(ptr - localPos); break; } list.Add(ptr - localPos); @@ -161,7 +161,7 @@ public class CCChariot : CCPiece { } public class CCCannon : CCPiece { - public CCCannon(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I pos = null) + public CCCannon(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null) : base(board, turnsSide, name : "Cannon", pos) { if (turnsSide == TurnsSideType.Red) { CNName = "砲"; @@ -202,7 +202,7 @@ public class CCCannon : CCPiece { } public class CCPawn : CCPiece { - public CCPawn(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I pos = null) + public CCPawn(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null) : base(board, turnsSide, name : "Pawn", pos) { if (turnsSide == TurnsSideType.Red) { CNName = "兵"; diff --git a/Scripts/Src/IBoard.cs b/Scripts/Src/IBoard.cs index 5a83cf2..2ab69b2 100644 --- a/Scripts/Src/IBoard.cs +++ b/Scripts/Src/IBoard.cs @@ -6,15 +6,15 @@ public interface IBoard { public int Cols { get; } public class SetPieceEventArgs : EventArgs { - public IPiece OldPiece { get; set; } - public IPiece NewPiece { get; set; } - public Vector2I Pos { get; set; } + public IPiece? OldPiece { get; set; } + public IPiece? NewPiece { get; set; } + public Vector2I Pos { get; set; } = new(); } public class MoveEventArgs : EventArgs { - public IPiece Piece { get; set; } - public Vector2I From { get; set; } - public Vector2I To { get; set; } + public IPiece? Piece { get; set; } + public Vector2I From { get; set; } = new(); + public Vector2I To { get; set; } = new(); } event EventHandler OnInsert; @@ -23,10 +23,10 @@ public interface IBoard { event EventHandler OnSetPiece; bool IsPosOutOfRange(Vector2I pos); - IPiece GetPiece(Vector2I pos); - IPiece SetPiece(IPiece piece, Vector2I pos); + IPiece? GetPiece(Vector2I pos); + IPiece? SetPiece(IPiece piece, Vector2I pos); bool InsertPiece(IPiece piece, Vector2I pos); bool MovePiece(Vector2I from, Vector2I to); - IPiece RemovePiece(Vector2I pos); + IPiece? RemovePiece(Vector2I pos); void Clear(); } diff --git a/Scripts/Src/Vector.cs b/Scripts/Src/Vector.cs index 7f8a510..44b6dd9 100644 --- a/Scripts/Src/Vector.cs +++ b/Scripts/Src/Vector.cs @@ -51,7 +51,7 @@ public class Vector2I { return X * with.X + Y * with.Y; } - public override bool Equals(object obj) { + public override bool Equals(object? obj) { if (obj is Vector2I other) { return this == other; } diff --git a/Test/.gdignore b/Test/.gdignore new file mode 100644 index 0000000..e69de29 diff --git a/Test/Test.csproj b/Test/Test.csproj new file mode 100644 index 0000000..7e5d662 --- /dev/null +++ b/Test/Test.csproj @@ -0,0 +1,31 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + diff --git a/Test/UnitTest1.cs b/Test/UnitTest1.cs new file mode 100644 index 0000000..d763e15 --- /dev/null +++ b/Test/UnitTest1.cs @@ -0,0 +1,16 @@ +using Vector; + +namespace Test; +public class Tests +{ + [SetUp] + public void Setup() + { + } + + [Test] + public void Test1() + { + Assert.Pass(); + } +} \ No newline at end of file diff --git a/Test/src/TestVector.cs b/Test/src/TestVector.cs new file mode 100644 index 0000000..3246fa1 --- /dev/null +++ b/Test/src/TestVector.cs @@ -0,0 +1,93 @@ +using Vector; +namespace Test; +public class TestsVector +{ + [SetUp] + public void Setup() + { + } + + [Test] + public void Test1() + { + Assert.Pass(); + } + + [Test] + public void TestVector2I_Constructors() + { + // Arrange & Act + var v1 = new Vector2I(); + var v2 = new Vector2I(1, 2); + var v3 = new Vector2I(v2); + + // Assert + Assert.That(v1.X, Is.EqualTo(0)); + Assert.That(v1.Y, Is.EqualTo(0)); + Assert.That(v2.X, Is.EqualTo(1)); + Assert.That(v2.Y, Is.EqualTo(2)); + Assert.That(v3.X, Is.EqualTo(1)); + Assert.That(v3.Y, Is.EqualTo(2)); + } + + [Test] + public void TestVector2I_Operators() + { + // Arrange + var v1 = new Vector2I(1, 2); + var v2 = new Vector2I(3, 4); + + // Act + var v3 = v1 + v2; + var v4 = v1 - v2; + var v5 = v1 * v2; + + // Assert + Assert.That(v3, Is.EqualTo(new Vector2I(4, 6))); + Assert.That(v4, Is.EqualTo(new Vector2I(-2, -2))); + Assert.That(v5, Is.EqualTo(new Vector2I(3, 8))); + } + + [Test] + public void TestTrans2DI_Constructors() + { + // Arrange & Act + var t1 = new Trans2DI(); + var t2 = new Trans2DI(new Vector2I(1, 0), new Vector2I(0, 1), new Vector2I(0, 0)); + var t3 = new Trans2DI(t2); + var t4 = new Trans2DI(1, 0, 0, 1, 0, 0); + + // Assert + Assert.That(t1.XAxis, Is.EqualTo(new Vector2I(1, 0))); + Assert.That(t1.YAxis, Is.EqualTo(new Vector2I(0, 1))); + Assert.That(t1.Origin, Is.EqualTo(new Vector2I(0, 0))); + + Assert.That(t2.XAxis, Is.EqualTo(new Vector2I(1, 0))); + Assert.That(t2.YAxis, Is.EqualTo(new Vector2I(0, 1))); + Assert.That(t2.Origin, Is.EqualTo(new Vector2I(0, 0))); + + Assert.That(t3.XAxis, Is.EqualTo(new Vector2I(1, 0))); + Assert.That(t3.YAxis, Is.EqualTo(new Vector2I(0, 1))); + Assert.That(t3.Origin, Is.EqualTo(new Vector2I(0, 0))); + + Assert.That(t4.XAxis, Is.EqualTo(new Vector2I(1, 0))); + Assert.That(t4.YAxis, Is.EqualTo(new Vector2I(0, 1))); + Assert.That(t4.Origin, Is.EqualTo(new Vector2I(0, 0))); + } + + [Test] + public void TestTrans2DI_Operators() + { + // Arrange + var t1 = new Trans2DI(new Vector2I(1, 0), new Vector2I(0, 1), new Vector2I(1, 2)); + var v1 = new Vector2I(3, 4); + + // Act + var v2 = t1 * v1; + var v3 = v1 * t1; + + // Assert + Assert.That(v2, Is.EqualTo(new Vector2I(4, 6))); + Assert.That(v3, Is.EqualTo(new Vector2I(2, 2))); + } +} \ No newline at end of file