0

我试图了解如何解决这种循环依赖。我可以在网上找到的所有示例都建议使用 limited with,但随后它们演示了两种基本类型的使用,而这更高级一些。循环依赖关系在下面的两个文件之间。我以为是介于package Chessboard ...和之间的Piece类型,但现在我不太确定。在声明类型后尝试将该package Chessboard ...行放在 chess_types.ads 中Piece并删除 Chessboard 的useandwith会导致错误:this primitive operation is declared too latefor the Moveprocedure。我被困在如何摆脱这种依赖。任何帮助将非常感激!

谢谢

棋盘广告:

with Ada.Containers.Indefinite_Vectors;
use Ada.Containers;
with Chess_Types;
use Chess_Types;

package Chessboard is new Indefinite_Vectors(Board_Index, Piece'Class);

chess_types.ads:

with Ada.Containers.Indefinite_Vectors;
use Ada.Containers;
with Chessboard;
use Chessboard;

package Chess_Types is
   subtype Board_Index is Integer range 1 .. 64;
   type Color is (Black, White);
   type Piece is tagged
      record
         Name : String (1 .. 3) := "   ";
         Alive : Boolean := False;
         Team  : Color;
         Coordinate : Integer;
      end record;
   procedure Move_Piece(Board: in Vector; P: in Piece; Move_To: in Integer);
end Chess_Types;

更多评论中的问题代码:

Chess_Types.Piece_Types.ads:

package Chess_Types.Piece_Types is

   type Pawn is new Piece with
      record
         First_Move : Boolean := True;
      end record;
   overriding
   procedure Move_Piece(Board: in CB_Vector'Class; Po: in Pawn; Move_To: in Board_Index);

   -- Other piece types declared here

end Chess_Types.Piece_Types;

Chess_Types.Piece_Types.adb:

with Ada.Text_IO;
use Ada.Text_IO;

package body Chess_Types.Piece_Types is
   procedure Move_Piece(Board: in CB_Vector'Class; Po: in Pawn; Move_To: in Board_Index) is
      Index_From, Index_To : Board_Index;
      Move_From : Board_Index := Po.Coordinate;
   begin
      -- Obtain locations of Pawn to move from (Index_From) and to (Index_To)
      -- in terms of the single dimension vector
      for I in Board.First_Index .. Board.Last_Index loop
         if Board.Element(I).Coordinate = Move_From then
            Index_From := I;
         end if;
         if Board.Element(I).Coordinate = Move_To then
            Index_To := I;
         end if;
      end loop;

      -- Determine if the requested move is legal, and if so, do the move.
      -- More possibilties to be entered, very primitive for simple checking.
      if Move_To - Move_From = 2 and then Po.First_Move = True then
         Board.Swap(I => Index_From, J => Index_To); -- "actual for "Container" must be a variable"
         Board.Element(Index_From).First_Move := False; -- "no selector for "First_Move" for type "Piece'Class"
      elsif Move_To - Po.Coordinate = 1 then
         Board.Swap(Index_From, Index_To); -- "actual for "Container" must be a variable"
      end if;

      -- Test to make sure we are in the right Move_Piece procedure
      Put_Line("1");

   end Move_Piece;

-- Other piece type move_piece procedures defined here

end Chess_types.Piece_Types;

作为进一步理解的注释,每个片段的 Coordinate 分量对应于ICCF 数字符号,即两位数,因此向量和 ICCF 符号之间需要进行某种类型的转换,因此整个 for 循环的原因在开始。

4

3 回答 3

1

要回答评论中的第二个问题:

要使用 First_Move,程序必须知道它是一个 Pawn。如果对象以 Piece'Class 类型声明,则不能访问仅为其中一种派生类型定义的组件。(在大多数 OO 语言中都是如此。)这可能表明您的设计存在缺陷。如果您有一个将 Piece'Class 作为参数的过程,但您想做一些只对 Pawn 有意义的事情,那么也许您应该向您的 Piece 添加另一个操作,该操作对大多数片段执行默认操作(也许它什么都不做),然后为 Pawn 覆盖它。其他可能性是使用类型转换:

procedure Something (P : Piece'Class) is ...

    if Pawn(P).First_Move then ...

如果 P 不是 Pawn,则会引发异常。如果你想先测试,你可以说“if P in Pawn”。我有时会编写如下代码:

    if P in Pawn then
        declare
            P_Pawn : Pawn renames Pawn(P);
        begin
            if P_Pawn.First_Move then ...
        end;
    end if;

但是最好定义一个新的多态操作。(注意:我没有测试过上面的代码,希望我没有在某个地方出现语法错误。)

于 2013-07-10T22:00:52.937 回答
1

据我了解,这会做你想要的。

with Ada.Containers.Indefinite_Vectors;
use Ada.Containers;

package Chess_Types is

   subtype Board_Index is Integer range 1 .. 64;
   type Color is (Black, White);
   type Piece is abstract tagged
      record
         Name : String (1 .. 3) := "   ";
         Alive : Boolean := False;
         Team  : Color;
         Coordinate : Board_Index;
      end record;
   type Piece_Ptr is access all Piece'Class;

   package Chessboard is new Indefinite_Vectors(Board_Index, Piece_Ptr);

   procedure Move_Piece (Board   : in Chessboard.Vector;
                         P       : in Piece'Class;
                         Move_To : in Board_Index) is abstract;
end Chess_Types;

笔记:

  1. Piece现在是抽象的,Move_Piece方法也是如此。这将意味着您现在需要派生其他片段类型(包piece_type-rook.ads,带有move_piece方法rook)等...
  2. Chessboard 现在包含指针(类宽指针),使用时要注意分配、解除分配、深拷贝、浅拷贝问题。
  3. 您现在应该能够调用Move_Piecea 的任何取消引用piece_ptr并将其分派到正确的方法。
  4. Move_To参数现在与Board_Index. (Coordinate也加入进来)——这似乎有点笨拙,也许重新考虑一下。(也许定义二维数组的行和列索引?--不需要 Indefinite_Vectors)
于 2013-07-10T19:15:12.980 回答
1

这是困难的一个。看起来limited with和泛型一起玩得不好。使其工作的唯一方法是返回使用您自己的访问类型:

with Ada.Containers.Vectors;
use Ada.Containers;
limited with Chess_Types;
use Chess_Types;

package Chessboard_Package is
    subtype Board_Index is Integer range 1 .. 64;
    type Piece_Acc is access all Piece'Class;      
    package Chessboard is new Vectors(Board_Index, Piece_Acc);
end Chessboard_Package;

我不得不将实例化放入一个新包中,并将 Board_Index 也移到那里。另外,我将其更改为 Vectors,因为 Piece_Acc 是确定类型,使用 Indefinite_Vectors 没有意义。但无论如何,这违背了目的。我只是不确定 Ada 是否能给你一种方法来用这样的两个包做你想做的事。

即使在一个包中做到这一点也不容易:

with Ada.Containers.Indefinite_Vectors;
use Ada.Containers;

package Chess_Types is

   subtype Board_Index is Integer range 1 .. 64;
   type Color is (Black, White);
   type Piece is tagged record ... end record;

   type CB_Vector is tagged;
   procedure Move_Piece (Board   : in CB_Vector'Class;
                         P       : in Piece;
                         Move_To : in Board_Index);

   package Chessboard is new Indefinite_Vectors(Board_Index, Piece'Class);

   type CB_Vector is new Chessboard.Vector with null record;

end Chess_Types;

这可以编译,但我必须添加额外的东西来绕过一些语言规则(特别是,当你实例化一个泛型时,它会“冻结”所有先前标记的类型,这样你就不能再声明该类型的新原始操作); 此外,我必须将 Board 参数设置为类范围的类型,以避免遇到有关多个标记类型的原始操作的规则。

于 2013-07-10T19:49:54.480 回答