Глубокое копирование массива С# без сериализации

По сути, у меня проблема в том, что мой алгоритм MinMax на самом деле не работает так, как предполагалось.

Мне нужно сделать так, чтобы части моего массива копировались в newPieces, чтобы pieces не менялось при изменении newPieces.

Вот выдержка из алгоритма MinMax:

private int MinMax(
    int depth, Piece[] pieces, bool blacksTurn, 
    List<Move> Moves, Game game, int alpha, Move nextMove) {

    Piece[] newPieces=new Piece[24];
    Moves=Game.possibleMoves(pieces, blacksTurn, false);
    if(depth==0||Moves.Count==0) {
        return Evaluation(ref pieces);
    }

    int value;

    if(blacksTurn==true) {
        foreach(Move i in Moves) {
            newPieces=DeepCopy.ObjectExtensions.Copy(pieces);
            game.MovePiece(newPieces, blacksTurn, i.Moving, i.Destination, true);
            game.DisplayBoard(pieces);
            value=minMax(depth-1, newPieces, !blacksTurn, Moves, game, alpha, nextMove);

            if(alpha>value) {
                alpha=value;
                nextMove=i;
            }

    // ... 

Вот класс Пьеса.

[StructLayout(LayoutKind.Sequential)]
public class Piece
{

    public CellReference Location;
    public bool isBlack { get; set; }
    public bool isKing { get; set; }
    private int Value { get; set; }
    public bool taken { get; set; }

    public Piece()
    {

    }

    public Piece(int i, bool isBlack, bool isKing, int CellsEast, int CellsNorth, bool taken)
    {
        this.Value = i;
        Location.CellsEast = CellsEast;
        Location.CellsNorth = CellsNorth;
        this.isBlack = isBlack;
        this.isKing = isKing;
        this.taken = taken;
    }
}

person Henry    schedule 12.03.2013    source источник
comment
Является ли Piece достаточно сложным, чтобы гарантировать наличие класса над структурой? В зависимости от того, что это за игра, есть также возможность вообще не копировать доску, а вместо этого записывать информацию, которая позволит вам отменить ход после его оценки.   -  person 500 - Internal Server Error    schedule 12.03.2013
comment
Это вопрос о более эффективной глубокой копии или о более эффективной мин-макс?   -  person    schedule 12.03.2013
comment
@DJKRAZE ОП специально запросил глубокую копию, MemberwiseClose задокументировано как выполнение поверхностной копии   -  person Peter Ritchie    schedule 12.03.2013
comment
Правильно, Питер.. Я проглядел, что удалю свой комментарий.   -  person MethodMan    schedule 12.03.2013
comment
@ 500 Я попытался изменить его на структуру, но все, казалось, сломалось, поэтому я изменил его обратно. Кроме того, как бы вы предложили записывать всю информацию?   -  person Henry    schedule 12.03.2013


Ответы (3)


Добавьте такой атрибут в класс/структуру Piece:

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public class Piece {

And the code is following

namespace DeepCopy {
    public static class ObjectExtensions {
        public static T[] Copy<T>(this T[] pieces) {
            return pieces.Select(x => {
                var handle=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T)));

                try {
                    Marshal.StructureToPtr(x, handle, false);
                    return (T)Marshal.PtrToStructure(handle, typeof(T));
                }
                finally {
                    Marshal.FreeHGlobal(handle);
                }
            }).ToArray();
        }
    }
}

Я временно изменил Piece.Value, чтобы сделать его общедоступным для теста, и протестировал его с помощью тестового класса.

public static partial class TestClass {
    public static void TestDeepCopy(Piece[] pieces) {
        Piece[] newPieces=new Piece[24];

        newPieces=DeepCopy.ObjectExtensions.Copy(pieces);

        newPieces[0].isKing=true;
        newPieces[0].Value=3;

        newPieces[1].isKing=true;
        newPieces[1].taken=true;
        newPieces[1].Value=4;

        Console.WriteLine("=== newPieces ===");
        foreach(var x in newPieces)
            Console.WriteLine(
                "x.isKing={0}; x.isBlack={1}; x.Value={2}",
                x.isKing, x.isBlack, x.Value
                );

        Console.WriteLine();
        Console.WriteLine("=== pieces ===");
        foreach(var x in pieces)
            Console.WriteLine(
                "x.isKing={0}; x.isBlack={1}; x.Value={2}",
                x.isKing, x.isBlack, x.Value
                );
    }

    public static void StartTest() {
        var pieceA=new Piece(1, false, false, 1, 1, false);
        var pieceB=new Piece(2, true, false, 1, 1, false);
        var pieces=new[] { pieceA, pieceB };
        TestDeepCopy(pieces);
    }
}

и это работает. Для выполнения теста звоните

TestClass.StartTest();
person Ken Kin    schedule 12.03.2013
comment
Это все еще не работает... Честно говоря, я в растерянности, каждая копия, похоже, дает одинаковые результаты, и все это все еще не работает. - person Henry; 13.03.2013
comment
Вау... что ты сделал? В чем проблема перед..? Я хотел бы узнать, что - person Ken Kin; 13.03.2013
comment
Ну, это снова облажался, но на этот раз, по крайней мере, я знаю, в чем проблема. Это вовсе не копирование, это на самом деле где-то зарыто в моей функции перемещения. Я действительно должен быть в состоянии найти проблему там, хотя. Так что твоя работа удалась, просто я ее напортачил ;D. - person Henry; 13.03.2013
comment
Возможно, стоит быть более осторожным с AllocHGlobal. Если он взрывается во время копирования, значит, у вас утечка памяти. - person Dustin Kingen; 13.03.2013

Я бы реализовал ICloneable ICloneable<T> на класс Piece.

public interface ICloneable<T>
{
    T Clone();
}

pieces.Select(p => p.Clone()).ToArray(); или просто используйте цикл foreach.

person Dustin Kingen    schedule 12.03.2013
comment
Я предлагаю реализовать только метод Clone. Нет никакой выгоды в реализации интерфейса ICloneable, и вы даже не можете иметь хороший возвращаемый тип, заставляя его быть object. - person Roman Starkov; 12.03.2013
comment
Или сделайте ICloneable<T>. - person Dustin Kingen; 12.03.2013
comment
Когда я это делаю, он говорит, что не может преобразовать тип object[] в Piece[]. - person Henry; 12.03.2013
comment
Реализуйте ICloneable‹T› на Piece, иначе вам нужно будет разыграть его pieces.Select(p => (Piece)p.Clone()).ToArray(). - person Dustin Kingen; 12.03.2013

Я думаю, это может помочь решить вашу проблему. Он использует интерфейс ICloneable, чтобы объекты знали, как клонировать самих себя.

person L-Four    schedule 12.03.2013