Создание копии объекта в c#
Пытаюсь реализовать метод поиска в ширину для решения 8-головоломки. Задача - найти путь решения от начального положения поля до конченого. На вход подаются 3 строки начального положения поля головоломки, например:
1 2 3
4 5 6
7 0 8
Вместо пустой ячейки на поле использую 0. Дальше эти значения записываются в виде двумерного массива в поле state объекта startState, и в нем автоматически вычисляются индексы i, j положения нуля в массиве. Также задается итоговое поле решенной головоломки (объект goalState):
1 2 3
4 5 6
7 8 0
Далее передаю эти объекты в метод doSearch - в котором реализуется поиск в ширину. В алгоритме поиска пытаюсь передать первый элемент из списка Open в метод findSuccessors. В этом методе пытаюсь скопировать переданный в метод объект node в объект node_copy с помощью конструктора клонирования объекта класса FieldState:
FieldState node_copy = new FieldState(node);
Далее мне необходимо по положению нуля в поле посмотреть, какие варианты ходов возможны (чтобы 0 не выходил за поле) и для скопированного объекта изменить положение нуля (поменять местами его с соседней ячейкой поля, если это возможно). После чего скопированный объект должен заноситься в список successors для продолжения поиска в ширину. Проблема заключается в том, что при вызове конструктора
FieldState node_copy = new FieldState(node);
Объекту node_copy присваивается ссылка на объект node, и копии объекта не создается. Пробовал реализовать интерфейс IClonable, получается то же самое. Не пойму, в чем причина. С с# до этого не работал, для интереса захотелось написать на нем, но столкнулся с такой проблемой. Буду рад, если кто-то поможет.
Полный код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace App8Logic
{
//Класс для создания объекта-состояния игрового поля
public class FieldState
{
//Индексы положения 0 в массиве
public int i { get; set; }
public int j { get; set; }
//Массив состояния игрового поля
public int[,] state { get; set; }
//Ссылка на предыдущее состояние поля
public FieldState predcessor { get; set; }
//Конструктор копирования объекта
public FieldState(FieldState obj) {
i = obj.i;
j = obj.j;
state = obj.state;
predcessor = obj.predcessor;
}
//Конструктор для создания объекта по вводу состояния игрового поля
public FieldState(int[,] array)
{
for (int i1 = 0; i1 < 3; i1++) {
for (int j1 = 0; j1 < 3; j1++) {
if (array[i1, j1] == 0) {
i = i1;
j = j1;
}
}
}
state = array;
}
}
//Класс для поиска в ширину
public class Search
{
//На вход подаются конечное и начальное состояния игрового поля
public static FieldState doSearch(FieldState startState, FieldState goalState) {
//Создается очередь с открытыми состояниями (которые нужно проверить)
Queue <FieldState> Open = new Queue <FieldState>();
//Создается очередь с закрытыми состояниями (которые уже проверены)
Queue<FieldState> Closed = new Queue<FieldState>();
//В очередь добавляется начальное состояние поля
Open.Enqueue(startState);
//Пока очередь не пуста
while (Open.Count != 0) {
//Достается первое состояние из очереди
FieldState nodeX = Open.Dequeue();
//Если это конченое состояние, возвращаем его
if (nodeX == goalState)
{
return nodeX;
}
//Если нет, находим возможные состояния игрового поля после 1 хода
List<FieldState> successors =Successors.findSuccessors(nodeX);
//Для каждого состояния
foreach (FieldState successor in successors) {
//Если оно не в списке, помещаем его туда
if (!Open.Contains(successor) && !Closed.Contains(successor)) {
Open.Enqueue(successor);
}
}
//Помещаем исследованное состояние в список Closed
Closed.Enqueue(nodeX);
}
//Если поиск неудачен, возвращаем последнее состояние поля
return Closed.Last();
}
}
//Класс для поиска возможных ходов игрового поля
public class Successors {
public static List<FieldState> findSuccessors(FieldState node)
{
//Создаем список для возможных ходов
List<FieldState> successors = new List<FieldState>();
//Проверка возможности перемещения пустой ячейки вверх
if (node.i - 1 >= 0) {
//Копируем объект
FieldState node_copy = new FieldState(node);
//Перемещаем пустую ячейку на поле
node_copy.state[node_copy.i, node_copy.j] = node_copy.state[node_copy.i, node_copy.j-1];
node_copy.state[node_copy.i , node_copy.j- 1] = 0;
//Новый ход в список
successors.Add(node_copy);
//Удаляем копию объекта
node_copy = null;
}
//Проверка возможности перемещения пустой ячйки влево
if (node.j + 1 <= 2)
{
FieldState node_copy = new FieldState(node);
node_copy.state[node_copy.i, node_copy.j] = node_copy.state[node_copy.i, node_copy.j+1];
node_copy.state[node_copy.i, node_copy.j + 1] = 0;
successors.Add(node_copy);
node_copy = null;
}
//Проверка возможности перемещения пустой ячейки вниз
if (node.i + 1 <= 2)
{
FieldState node_copy = node;
node_copy.state[node_copy.i, node_copy.j] = node_copy.state[node_copy.i+1, node_copy.j];
node_copy.state[node_copy.i + 1, node_copy.j] = 0;
successors.Add(node_copy);
node_copy = null;
}
//Проверка возможности перемещения пустой ячейки вправо
if (node.j - 1 >= 0)
{
FieldState node_copy = node;
node_copy.state[node_copy.i, node_copy.j] = node_copy.state[node_copy.i, node_copy.j - 1];
node_copy.state[node_copy.i, node_copy.j - 1] = 0;
successors.Add(node_copy);
node_copy = null;
}
//Возвращаем возможные ходы
return successors;
}
}
class Program
{
static void Main(string[] args)
{
//Создаем итоговое состояние игрового поля
int[,] goal_array = { { 1,2,3},{ 4,5,6 },{7,8,0 } };
FieldState goalState = new FieldState(goal_array);
//Вводим начальное состояние игрового поля
int[,] start_array = new int[3, 3];
Console.WriteLine("Введите начальное положение игрового поля (в 3 строки)\n");
for (int i = 0; i <= 2; i++) {
string[] input = Console.ReadLine().Split(' ');
for (int j = 0; j <= 2; j++) {
start_array[i,j]= Convert.ToInt32(input[j]);
}
}
Console.WriteLine("\n");
FieldState startState = new FieldState(start_array);
//Получаем последние состояние игрового поля после поиска
FieldState nodeExit = Search.doSearch(startState, goalState);
//Далее будет нужно вывести предшественников в обратном порядке
/*
while (nodeExit.predcessor != null) {
for (int i = 0; i <= 2; i++)
{
Console.WriteLine(nodeExit.state[i, 0]+" "+ nodeExit.state[i, 1]+" "+ nodeExit.state[i, 2]);
}
Console.WriteLine("\n");
}
*/
Console.ReadKey();
}
}
}