You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

面向对象设计下国际象棋棋子位置双向查询最优存储方案

推荐最优实现方案

直接采用你偏向的「Board维护双向字典+移除Piece类存储位置属性」的方案,这是面向对象实现棋类游戏的业内标准做法,核心优势是彻底消灭双数据源同步问题,你担心的双字典冗余完全可以忽略:32个棋子的两个字典内存占用可忽略不计,查询都是O(1)完全满足性能要求。

1. 改造Board类

  • 私有存储新增Dictionary<Piece, Spot> _pieceToSpot
  • 保留原有Dictionary<Spot, Piece> _spotToPiece实现点位查棋子的需求
  • 把MovePiece、RemovePiece、PlacePiece这些修改状态的方法全部改为internal访问级别,仅允许同程序集的Piece类调用,对外暴露的公共接口只保留只读的CheckSpot、GetPiecePosition等查询方法
public class Board : IBoard
{
    private uint _width;
    private uint _height;
    private Dictionary<Spot, Piece> _spotToPiece;
    private Dictionary<Piece, Spot> _pieceToSpot;

    public Board(uint width, uint height)
    {
        _width = width;
        _height = height;
        _spotToPiece = new Dictionary<Spot, Piece>();
        _pieceToSpot = new Dictionary<Piece, Spot>();
    }

    // 公共只读查询:给定点位查棋子
    public Piece CheckSpot(Spot spot)
    {
        spot = transformSpot(spot);
        _spotToPiece.TryGetValue(spot, out var piece);
        return piece;
    }

    // 公共只读查询:给定棋子查位置
    public Spot GetPiecePosition(Piece piece)
    {
        _pieceToSpot.TryGetValue(piece, out var spot);
        return spot;
    }

    // internal修改方法:仅同程序集可调用
    internal bool RemovePiece(Piece piece)
    {
        if (_pieceToSpot.TryGetValue(piece, out var spot))
        {
            _pieceToSpot.Remove(piece);
            _spotToPiece.Remove(spot);
            return true;
        }
        return false;
    }

    internal Spot MovePiece(Spot destination, Piece pieceToBeMoved)
    {
        RemovePiece(pieceToBeMoved);
        return PlacePiece(destination, pieceToBeMoved);
    }

    private Spot PlacePiece(Spot destination, Piece pieceToPlace)
    {
        var transformedDestination = transformSpot(destination);
        // 原有占位校验逻辑
        _spotToPiece.Add(transformedDestination, pieceToPlace);
        _pieceToSpot.Add(pieceToPlace, transformedDestination);
        return transformedDestination;
    }

    private Spot transformSpot(Spot spot)
    {
        // 原有坐标转换逻辑
    }
}

2. 改造Piece类

  • 移除自身存储的_currentPosition字段,位置查询统一调用_board.GetPiecePosition(this)
  • 不需要再处理位置同步逻辑,所有状态修改都走Board的internal方法
public abstract class Piece : IPiece
{
    protected IBoard _board;
    public ColorType Color { get; protected set; }

    public Piece(ColorType color, Spot initialPosition, IBoard board)
    {
        _board = board ?? throw new ArgumentNullException(nameof(board));
        Color = color;
        // 初始化时调用Board的放置逻辑
        ((Board)_board).PlacePiece(initialPosition, this);
    }

    public Spot CurrentPosition => _board.GetPiecePosition(this);

    public void Move()
    {
        // 原有移动规则计算逻辑,用CurrentPosition获取自身位置
        var destination = new Spot(x,y);
        var occupyingPiece = _board.CheckSpot(destination);
        occupyingPiece?.RemovePiece();
        // 调用Board的internal移动方法
        ((Board)_board).MovePiece(destination, this);
    }

    public void RemovePiece()
    {
        ((Board)_board).RemovePiece(this);
    }
}

3. 核心优势

  • 彻底解决同步问题:Board是位置信息的唯一权威来源,双字典的维护逻辑全部封装在Board内部,所有修改操作都是原子性的,不可能出现数据不一致
  • 访问权限安全:修改状态的方法都是internal,只要把Board和Piece放在同一个程序集,外部代码完全没法调用这些敏感方法,不需要友元就能实现权限隔离
  • 符合面向对象设计:Piece依然持有自身移动规则的逻辑,符合你的设计预期,位置查询的性能开销可以忽略不计

内容的提问来源于stack exchange,提问作者Blasterdude8

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 11:06:03