Re: Потрібна допомога у розробці проекту
Останні правки:
PdnToBoardConverter
using System;
using Microsoft.Extensions.Logging;
namespace CheckersApi.Engine
{
public static class PdnToBoardConverter
{
public static int[,] Convert(string pdn)
{
var board = new int[8, 8];
var parts = pdn.Split(':');
if (parts.Length != 3)
return board;
string whitePart = parts[1].Replace("W", "");
string blackPart = parts[2].Replace("B", "");
Fill(board, whitePart, true);
Fill(board, blackPart, false);
return board;
}
private static void Fill(int[,] board, string part, bool isWhite)
{
if (string.IsNullOrWhiteSpace(part))
return;
var items = part.Split(',', StringSplitOptions.RemoveEmptyEntries);
foreach (var item in items)
{
bool isKing = item.StartsWith("K");
string numStr = isKing ? item[1..] : item;
if (!int.TryParse(numStr, out int square))
continue;
var (row, col) = SquareToCoords(square);
int value;
if (isWhite)
value = isKing ? 4 : 3; // white
else
value = isKing ? 2 : 1; // black
board[row, col] = value;
}
}
// ???? ПРАВИЛЬНА ФОРМУЛА (без переворотів)
private static (int row, int col) SquareToCoords(int square)
{
int index = square - 1;
int row = index / 4;
int col = (index % 4) * 2 + ((row % 2 == 0) ? 1 : 0);
return (row, col);
}
}
}MoveFormatter
namespace CheckersApi.Engine
{
internal static class MoveFormatter
{
internal static string Format(NativeKingsRow.CBmove m)
{
int from = ToSquare(m.from);
int to = ToSquare(m.to);
return m.jumps > 0
? $"{from}x{to}"
: $"{from}-{to}";
}
public static int ToSquare(NativeKingsRow.Coor c)
{
int row = c.y;
int offset = (row % 2 == 0) ? 1 : 0;
int pos = (c.x - offset) / 2;
int index = row * 4 + pos;
return index + 1;
}
}
}NativeKingsRowAdapter
using CheckersApi.Contracts;
using CheckersApi.Validation;
using System.Threading;
using Microsoft.Extensions.Logging;
namespace CheckersApi.Engine
{
public class NativeKingsRowAdapter : IEngineAdapter
{
private readonly ILogger<NativeKingsRowAdapter> _logger;
public NativeKingsRowAdapter(ILogger<NativeKingsRowAdapter> logger)
{
_logger = logger;
}
public SuggestResponse Suggest(SuggestRequest request, CancellationToken ct)
{
_logger.LogInformation("=== SUGGEST START ===");
string pdn = PdnNormalizer.Normalize(request.State.Position);
_logger.LogInformation("PDN: {Pdn}", pdn);
int[,] board = PdnToBoardConverter.Convert(pdn);
int color = pdn.StartsWith("B:") ? 1 : 2; // 1 = black, 2 = white
_logger.LogInformation("COLOR: {Color}", color);
var (rc, move, status) =
NativeKingsRow.GetMove(board, color, 0.3);
if (rc != 0 && rc != 3)
{
_logger.LogWarning("ENGINE FAILED");
return new SuggestResponse
{
Engine = "kingsrow-native",
BestMove = null,
Pv = new[] { status }
};
}
string bestMove = MoveFormatter.Format(move);
_logger.LogInformation("BEST MOVE: {Move}", bestMove);
return new SuggestResponse
{
Engine = "kingsrow-native",
BestMove = bestMove,
Pv = new[] { bestMove }
};
}
}
}NativeKingsRow
using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Extensions.Logging;
namespace CheckersApi.Engine
{
internal static class NativeKingsRow
{
private static bool _bound;
private static ILogger? _logger;
public static void SetLogger(ILogger logger)
{
_logger = logger;
}
[StructLayout(LayoutKind.Sequential)]
public struct Coor
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct CBmove
{
public Coor from;
public Coor to;
public int path1;
public int path2;
public int path3;
public int path4;
public int jumps;
public int newpiece;
}
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int GetMoveDelegate(
int[,] board,
int color,
double maxTime,
StringBuilder status,
ref int playnow,
int info,
int moreinfo,
ref CBmove move);
private static GetMoveDelegate? _getMove;
internal static void BindOnce(IntPtr dll, ILogger logger)
{
if (_bound) return;
_logger = logger;
_getMove = Marshal.GetDelegateForFunctionPointer<GetMoveDelegate>(
NativeLibrary.GetExport(dll, "getmove"));
_logger.LogInformation("getmove bind OK");
_bound = true;
}
internal static (int rc, CBmove move, string status) GetMove(
int[,] board,
int color,
double time)
{
if (_getMove == null)
throw new Exception("KingsRow not initialized");
_logger?.LogInformation("=== CALL getmove ===");
_logger?.LogInformation("COLOR: {Color}", color);
_logger?.LogInformation("TIME: {Time}", time);
PrintBoard(board);
var status = new StringBuilder(256);
var move = new CBmove();
int playnow = 0;
int rc = _getMove(
board,
color,
time,
status,
ref playnow,
0,
0,
ref move);
_logger?.LogInformation("RC: {Rc}", rc);
_logger?.LogInformation("STATUS: {Status}", status.ToString());
_logger?.LogInformation("MOVE: from({fx},{fy}) to({tx},{ty}) jumps={j}",
move.from.x, move.from.y,
move.to.x, move.to.y,
move.jumps);
return (rc, move, status.ToString());
}
private static void PrintBoard(int[,] board)
{
_logger?.LogInformation("=== BOARD ===");
for (int i = 0; i < 8; i++)
{
var row = "";
for (int j = 0; j < 8; j++)
{
row += board[i, j] + " ";
}
_logger?.LogInformation(row);
}
_logger?.LogInformation("=== END BOARD ===");
}
}
}РЕЗУЛЬТАТ
Building...
info: Program[0]
getmove bind OK
info: Program[0]
KingsRow initialized
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5200
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: A:\Documents\CheckersApi
info: CheckersApi.Engine.NativeKingsRowAdapter[0]
=== SUGGEST START ===
info: CheckersApi.Engine.NativeKingsRowAdapter[0]
PDN: B:W18,19,22,25,27,28,30,32:B1,5,6,7,10,12,14,16
info: CheckersApi.Engine.NativeKingsRowAdapter[0]
COLOR: 1
info: Program[0]
=== CALL getmove ===
info: Program[0]
COLOR: 1
info: Program[0]
TIME: 0.3
info: Program[0]
=== BOARD ===
info: Program[0]
0 1 0 0 0 0 0 0
info: Program[0]
1 0 1 0 1 0 0 0
info: Program[0]
0 0 0 1 0 0 0 1
info: Program[0]
0 0 1 0 0 0 1 0
info: Program[0]
0 0 0 3 0 3 0 0
info: Program[0]
0 0 3 0 0 0 0 0
info: Program[0]
0 3 0 0 0 3 0 3
info: Program[0]
0 0 3 0 0 0 3 0
info: Program[0]
=== END BOARD ===
info: Program[0]
RC: 2
0 0 3 0 0 0 3 0
info: Program[0]
=== END BOARD ===
0 0 3 0 0 0 3 0
info: Program[0]
0 0 3 0 0 0 3 0
0 0 3 0 0 0 3 0
info: Program[0]
=== END BOARD ===
info: Program[0]
RC: 2
info: Program[0]
STATUS: No moves
info: Program[0]
MOVE: from(0,0) to(0,0) jumps=0
warn: CheckersApi.Engine.NativeKingsRowAdapter[0]
ENGINE FAILED