新向量包和过程之间的循环依赖

时间:2013-07-10 18:44:30

标签: ada

我试图了解如何修复此循环依赖项。我在网上找到的所有例子都建议使用有限的,但后来他们演示了两种基本类型的使用,而这是更先进的。循环依赖关系位于以下两个文件之间。我认为它介于package Chessboard ...Piece类型之间,但现在我不太确定。在声明package Chessboard ...类型后尝试将Piece行放入chess_types.ads并删除棋盘的usewith会导致错误:this primitive operation is declared too late对于Move程序。我坚持如何摆脱这种依赖。任何帮助将不胜感激!

谢谢

chessboard.ads:

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 numeric notation,这是两位数,因此在向量和ICCF表示法之间需要进行某种类型的转换,因此需要整个循环开始。

3 个答案:

答案 0 :(得分: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_Piece的任何解除引用时调用piece_ptr,并让它发送到正确的方法。
  4. Move_To参数现在与Board_Index的类型相同。 (Coordinate也引入了一行) - 这看起来有点笨重,也许重新考虑一下。 (行和列指数可能定义了2D数组? - 不需要Indefinite_Vectors)

答案 1 :(得分: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。此外,我将其更改为向量,因为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参数设置为类范围类型,以避免遇到有关多个标记类型的基本操作的规则。

答案 2 :(得分: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,则会引发异常。如果你想先测试,你可以说“如果P在Pawn”。我有时写代码如下:

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

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