using Shogi.Contracts.Types; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Text.RegularExpressions; namespace Shogi.Contracts.Api; public class MovePieceCommand : IValidatableObject { /// /// For serialization. /// public MovePieceCommand() { this.To = string.Empty; } /// /// Move a piece on the board. /// public MovePieceCommand(string from, string to, bool isPromotion) { this.From = from; this.To = to; this.IsPromotion = isPromotion; } /// /// Add a piece to the board from the hand. /// public MovePieceCommand(WhichPiece pieceFromHand, string to) { this.PieceFromHand = pieceFromHand; this.To = to; } /// /// Mutually exclusive with . /// Set this property to indicate moving a piece from the hand onto the board. /// public WhichPiece? PieceFromHand { get; set; } /// /// Board position notation, like A3 or G1 /// Mutually exclusive with . /// Set this property to indicate moving a piece from the board to another position on the board. /// public string? From { get; set; } /// /// Board position notation, like A3 or G1 /// [Required] public string To { get; set; } public bool? IsPromotion { get; set; } public IEnumerable Validate(ValidationContext validationContext) { if (this.PieceFromHand.HasValue && !string.IsNullOrWhiteSpace(this.From)) { yield return new ValidationResult($"{nameof(this.PieceFromHand)} and {nameof(this.From)} are mutually exclusive properties."); } if (this.PieceFromHand.HasValue && this.IsPromotion.HasValue) { yield return new ValidationResult($"{nameof(this.PieceFromHand)} and {nameof(this.IsPromotion)} are mutually exclusive properties."); } if (!Regex.IsMatch(this.To, "[A-I][1-9]")) { yield return new ValidationResult($"{nameof(this.To)} must be a valid board position, between A1 and I9"); } if (!string.IsNullOrEmpty(this.From) && !Regex.IsMatch(this.From, "[A-I][1-9]")) { yield return new ValidationResult($"{nameof(this.From)} must be a valid board position, between A1 and I9"); } } }