我试图了解如何修复此循环依赖项。我在网上找到的所有例子都建议使用有限的,但后来他们演示了两种基本类型的使用,而这是更先进的。循环依赖关系位于以下两个文件之间。我认为它介于package Chessboard ...
和Piece
类型之间,但现在我不太确定。在声明package Chessboard ...
类型后尝试将Piece
行放入chess_types.ads并删除棋盘的use
和with
会导致错误: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表示法之间需要进行某种类型的转换,因此需要整个循环开始。
答案 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;
注意:
Piece
现在是抽象的,Move_Piece
方法也是如此。这意味着您现在需要派生您的其他作品类型(包piece_type-rook.ads
,使用move_piece
rook
方法等等... Move_Piece
的任何解除引用时调用piece_ptr
,并让它发送到正确的方法。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;
但是定义一个新的多态操作是可取的。 (注意:我没有测试过上面的代码,希望我没有在某处出现语法错误。)