Как я могу правильно скопировать набор объектов, не ссылаясь на оригиналы или дублируя те, на которые ссылаются несколько раз?
У меня есть GameState
объект. Он содержит такие вещи, как игроки, руки игроков и карты в них, состояние и расположение ресурсов игроков и так далее. Почти все связано, по крайней мере, с одной другой вещью - карты знают, в какой руке они находятся, ресурсы знают, к какому игроку они принадлежат, и так далее.
Я хотел бы создать систему, чтобы рассказать игроку разницу между двумя GameState
s. Было бы сравнить состояния и вернуться с "если бы вы сделали это действие, эти вещи изменились бы". Самый простой способ сделать это, кажется, дублировать GameState
и примените действие к дубликату, затем сравните дубликат с оригиналом.
Я рассмотрел некоторые реализации как для мелкого, так и для глубокого копирования, но я могу быстро предвидеть проблемы, когда один объект принадлежит двум разным объектам. Одним из примеров являются некоторые токены игроков; игрок имеет список всех своих токенов (например, игрок может подвести итоги того, где они все находятся), а пространство, в котором находятся токены, содержит список всех токенов, которые находятся на нем (например, если пространство зависит от чего-то, что может повлиять на все токены на нем). Если я сделаю глубокую копию, то игрок и пространство будут ссылаться на две разные копии одного и того же токена; если я сделаю мелкую копию, то все будет ссылаться на объекты, как они существуют в оригинале GameState
, Я не могу выбрать одну сторону, чтобы она всегда была мелкой, а другая - всегда глубокой, потому что, возможно, жетон будет удален с игрового поля и не будет находиться на свободном месте, или жетон будет отсоединен от игрока и позже поднят другим., При использовании могут быть даже карты, нацеленные на игрока, поэтому, если он нацелен на пользователя, это будет круговая ссылка.
По сути, я хочу сделать первую из этих трех диаграмм, но я не могу понять, как избежать второй и третьей ситуаций.
Я подозреваю, что нет простого способа сделать это вообще, но я полагаю, что я мог бы также спросить.
Я использую C# в Unity3D, на случай, если это важно.
2 ответа
Несколько месяцев назад я написал простой ИИ для шахматной игры Отелло. Мне нужно было передавать разные игровые состояния для каждого хода в моих функциях оценки. Я "клонировал" только основные данные, необходимые для вычислений, и передавал "клонированные данные" другим функциям. Внутри функций я делал вещи более или менее так же, как вы предлагали, т.е. моделировал результат для каждого движения в каждом состоянии.
Я думаю, что определение стратегии "клонирования" самостоятельно неизбежно. Тем не менее, вы можете извлечь только полезные данные из оригинала GameState
пример. Конечно, имя игрока не имеет значения, верно?
Вы можете получить некоторое преимущество от сериализации как ярлык клонирования. Я часто использую JSON.NET (NewtonSoft) для выполнения аналогичной операции, и пока ваши объекты не слишком сложны, вы обычно можете обойтись базовой процедурой "сериализация, затем десериализация". Кстати, JSON.NET хорошо обрабатывает циклические ссылки и тому подобное.
Я думаю, что ваша более сложная задача - показать пользователю информацию "что произойдет".