-- миниигра птички-рыбки
s8_birds_and_fishes_minigame = {} -- название таблицы миниигры, должно совпадать с имненем файла
local self = s8_birds_and_fishes_minigame -- для удобства, чтобы вместо s12_example_minigame.some_var писать self.some_var

self.params = 
{
	sound_pos =
	{ -- клик по лунке
		blocked = "mini_game_mini_game_birds_and_fishes_false_01", -- - Игрок кликает на лунку, к которой путь заблокирован
		correct_pos = "mini_game_mini_game_birds_and_fishes_true_01", -- Игрок поремещаетт фигурку на правильное место
		move = "mini_game_mini_game_birds_and_fishes_select_02" -- к этой лунке поехала фигурка
	},
	sound_object =
	{ -- звуки  объекта
		select = "mini_game_mini_game_birds_and_fishes_select_01", -- выделяет фигурку
		move = "mini_game_mini_game_birds_and_fishes_go_01" -- как едет фигурка
	},
	fade_move_time = 600, -- время угасания звука движения фигурки
	
	speed = 250, -- скорость движения, пиксели в секунду
	pos_amount = 15, -- количество позиций для фишек на поле
	dibs_amount = 10, -- количество фишек в игре
	pos_width = 40,  -- ширина позиции фишки
	pos_height = 40, -- высота позиции фишки
	clip_selection_on_move = "effect02", -- клип, подсвечивающий лунку, к которой едет птичка
	layer_on_move = 1, -- на каком слое лежит подсвечивающий лунку клип
	clip_on_correct_cell = "effect01", -- клип, проигрывающийся при установлении фигурки на одну из ячеек, в которой она должна быть в конце
	layer_correct_cell = 0, -- на каком слое подсвечивающий верную лунку клип
	clip_on_wrong_click = "cross", -- клип, который проигрывается, когда указываем на ячейку, до которой нет пути
	layer_wrong_click = 0, -- слой проигрывающегося неверного клика
	clip_show_enabled = "effect03", -- клип, подсвечивающий при выделении фишки все ячейки, до которой фигурка может доползти
	layer_show_enabled_layer = 1, -- на каком слое показывать clip_show_enabled
	enabled_fade_time = 500, -- за сколько мс пропадают клипы на выделение
	positions = { -- описание точек, в которых может находиться фишка
		{ -- номер позиции: 1
			state =  "fish", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "bird", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(937, 617), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				2
			}
		},
		{ -- номер позиции: 2
			state =  "fish", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "bird", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(683, 589), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				1, 3, 6
			}
		},
		{ -- номер позиции: 3
			state =  "fish", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "bird", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(851, 505), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				2, 4
			}
		},
		{ -- номер позиции: 4
			state =  "fish", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "bird", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(884, 331), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				3, 5
			}
		},
		{ -- номер позиции: 5
			state =  "fish", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "bird", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(757, 206), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				4
			}
		},
		{ -- номер позиции: 6
			state =  "free", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "free", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(506, 641), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				2, 7
			}
		},
		{ -- номер позиции: 7
			state =  "free", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "free", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(569, 475), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				6, 8, 10
			}
		},
		{ -- номер позиции: 8
			state =  "free", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "free", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(670, 328), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				7, 9
			}
		},
		{ -- номер позиции: 9
			state =  "free", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "free", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(540, 202), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				8
			}
		},
		{ -- номер позиции: 10
			state =  "free", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "free", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(432, 359), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				7, 13
			}
		},
		{ -- номер позиции: 11
			state =  "bird", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "fish", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(213, 681), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				12
			}
		},
		{ -- номер позиции: 12
			state =  "bird", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "fish", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(370, 577), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				11, 13
			}
		},
		{ -- номер позиции: 13
			state =  "bird", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "fish", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(256, 436), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				12, 10, 14
			}
		},
		{ -- номер позиции: 14
			state =  "bird", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "fish", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(244, 259), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				13, 15
			}
		},
		{ -- номер позиции: 15
			state =  "bird", -- состояние позиции: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			end_state = "fish", -- в каком состоянии должна находиться позиция на момент окончания игры: "bird" - на ней стоит птичка, "fish" - на ней стоит рыбка, "free" - свободна
			pos = sf.misc.FloatVector(54, 258), -- положение фишки на экране
			neighbours = { -- список позиций, в которые можно перейти из данной
				14
			}
		}
	}	
}
-- проверка, закончилась ли у нас игра
function self.CheckEnd(_owner)
	local alright = true;
	-- надо проверить, находятся ли все позиции в своем финальном положении
	for i = 1, self.params.pos_amount do
		if (self.position_state[i] ~= self.params.positions[i].end_state) then
			-- положение i-ой фишки не совпало с ее конечным положением, игра не завершена
			alright = false;
			break
		end
	end
	
	if (alright == true) then
	-- закончить миниигру
		self.win = true
	end
end

function self.Init(_owner) -- функция, инициализирующая миниигру; в ней стоит инициализировать все переменные, нужные миниигре
	sminigames.SetStandartScriptName(_owner, s8_birds_and_fishes_minigame) 
	
	-- инициализация переменных
	-- создаем таблицу состояний позиций
	self.position_state = {}
	for i = 1, self.params.pos_amount do
		table.insert(self.position_state, self.params.positions[i].state)
	end
	
	self.objects = {}
	-- создаем птичек
	local i = 1
	local initialized = {}
	while true do
		local image_widget =  __cast(_owner.GetWidget("bird_"..i, true), sf.gui.CImageWidget)
		
		if not image_widget then 
			break 
		end
		
		local clip_widget 
		clip_widget = sf.gui.CClipWidget("", 0, 0)
		clip_widget.GetClip().Load("bird0"..i, true)
		clip_widget.SetOffset(0, 0)
		clip_widget.SetSize(0, 0)
		_owner.AddWidget(clip_widget)

		-- создаем объект для птички
		local o = {image = image_widget, object_type = "bird", clip = clip_widget }
		table.insert(self.objects, o)
		table.insert(initialized, false)
		
		i = i + 1		
	end
	
	-- создаем рыбок
	local i = 1
	while true do
		local image_widget = __cast(_owner.GetWidget("fish_"..i, true), sf.gui.CImageWidget)
		if not image_widget then 
			break 
		end
		
		local clip_widget
		
		clip_widget = sf.gui.CClipWidget("", 0, 0)
		clip_widget.GetClip().Load("fish0"..i, true)
		clip_widget.SetOffset(0, 0)
		clip_widget.SetSize(0, 0)
		_owner.AddWidget(clip_widget)
		--end
		-- создаем объект для рыбки
		local o = {image = image_widget, object_type = "fish", clip = clip_widget }
		table.insert(self.objects, o)
		table.insert(initialized, false)
		
		i = i + 1		
	end
	
	--заполняем позиции виджетов
	for i = 1, self.params.pos_amount do
		local ob_type = self.params.positions[i].state
		if (ob_type ~= "free") then
			for j = 1, #self.objects do
				if (initialized[j] == false and ob_type == self.objects[j].object_type) then
					initialized[j] = true
					local width, height = self.objects[j].image.GetSize().X, self.objects[j].image.GetSize().Y
					self.objects[j].image.SetOffset(self.params.positions[i].pos.X - width/2, self.params.positions[i].pos.Y - height)
					self.objects[j].clip.SetSize(0, 0)
					break
				end
			end			
		end
	end
-- поигрывается, когда движется	
	local id = self.params.clip_selection_on_move or ""
	local layer = self.params.layer_on_move or 0
	self.clip_on_move = sf.gui.CClipWidget("", layer, 0)
	self.clip_on_move.GetClip().Load(id, true)
	self.on_move_size = self.clip_on_move.GetClip().GetViewSize()
	self.clip_on_move.SetOffset(0, 0)
	self.clip_on_move.SetSize(0, 0)
	_owner.AddWidget(self.clip_on_move) 
-- проигрывается, когда встали на нужное место	
	id = self.params.clip_on_correct_cell or ""
	layer = self.params.layer_correct_cell or 0
	self.clip_on_correct = sf.gui.CClipWidget("", layer, 0) 
	self.clip_on_correct.GetClip().Load(id, true)
	self.on_correct_size = self.clip_on_correct.GetClip().GetViewSize()
	self.clip_on_correct.SetOffset(0, 0)
	self.clip_on_correct.SetSize(0, 0)
	_owner.AddWidget(self.clip_on_correct) 
		
-- проигрывается, когда нельзя идти
	id = self.params.clip_on_wrong_click or ""
	layer = self.params.layer_wrong_click or 0
	self.clip_cross = sf.gui.CClipWidget("", layer, 0) 
	self.clip_cross.GetClip().Load(id, true)
	self.cross_size = self.clip_cross.GetClip().GetViewSize()
	self.clip_cross.SetOffset(0, 0)
	self.clip_cross.SetSize(0, 0)
	_owner.AddWidget(self.clip_cross) 		
	
	__assert(#self.objects == self.params.dibs_amount, 
		"Кол-во изображений не совпадает с кол-вом фишек, сейчас "..#self.objects.." должно быть "..self.params.dibs_amount)
	
	self.selected = -1 -- сейчас не выделена фишка (номер выделенного объекта)
	self.sel_pos = -1 -- номер выделенной позиции
	
	self.cur_way = {} -- по какому пути движется объект
	self.cur_line = -1 -- по какому участку пути сейчас двигаемся
	self.moving = -1 -- какой объект движется
	self.obj_pos = {x = 0, y = 0} -- позиция движущегося объекта
	self.last_start = 0 -- начало движения от последней точки
	self.last_length = 0 -- сколько должны двигаться от этой точки
	
	self.timer = __create_timer() -- создаем таймер, который будет использоваться для движения объекта
		
	self.win = false -- победили?
end

-- выделяет фишку
function self.Select(_owner, _i)
	self.Deselect(_owner)
	
	if self.params.sound_object.select then
		sound(self.params.sound_object.select)
	end
	
	local pos = self.objects[_i].image.GetOffset()
	local width, height = self.objects[_i].image.GetSize().X, self.objects[_i].image.GetSize().Y
	
	self.objects[_i].clip.SetOffset(pos.X, pos.Y)
	self.objects[_i].clip.SetSize(width, height)
	self.objects[_i].image.SetLayer(2)
end

-- снимает выделение
function self.Deselect(_owner)
	if self.selected ~= -1 then
		self.DeleteEnabledCellsClips(_owner)
		self.objects[self.selected].clip.SetSize(0, 0)
		self.objects[self.selected].image.SetLayer(3)
	end
end

-- удаляет клипы с подсветкой доступных ячеек
function self.DeleteEnabledCellsClips(_owner)
	if self.enabled_cells and #self.enabled_cells > 0 then
		for _, clip in pairs(self.enabled_cells) do
			_owner.RemoveWidget(clip)
		end
		self.enabled_cells = {}
	end
end

-- создает клипы с выделением для всех доступных из данной точки позиций
function self.SelectEnabledCells(_owner, _selected)
	local matr = self.MakeTransitionMatrix()
	local enabled = {}
	for i = 1, #self.params.positions do
		if self.position_state[i] == "free" and i ~= _selected then
			local way = self.FindWay(matr, _selected, i)
			if way then
				table.insert(enabled, i)
			end
		end
	end
	if not self.enabled_cells then
		self.enabled_cells = {}
	end
	for i = 1, #enabled do
		local pos_num = enabled[i]
		local pos = self.params.positions[pos_num].pos
		local widget = sf.gui.CClipWidget("", 0, 0)
		local layer = self.params.layer_show_enabled or 0
		widget.SetLayer(layer)
		local id = self.params.clip_show_enabled or ""
		widget.GetClip().Load(id, true)
		local sz = widget.GetClip().GetViewSize()
		widget.SetOffset(pos.X - sz.X/2, pos.Y - sz.Y/2)
		_owner.AddWidget(widget)
		
		table.insert(self.enabled_cells, widget)
	end
end

-- ищет фишку, в ктороую попадают заданные координаты; если фишка не найдена, возвращает nil
function self.FindDibByPos(_owner, _x, _y)
	local i

	for i = 1, #self.objects do
		local pos = self.objects[i].image.GetOffset()
		local width, height = self.objects[i].image.GetSize().X, self.objects[i].image.GetSize().Y

		if (pos.X <= _x) and (_x <= pos.X + width) and (pos.Y <= _y) and (_y <= pos.Y + height) then
		-- проверяем, видимая ли часть фишки
			if (sminigames.IsVisiblePoint(self.objects[i].image.GetImage(), _x - pos.X, _y - pos.Y)) then
				-- если у нас уже была выделена фишка, надо погасить свечение вокруг нее
				self.Select(_owner, i)
				
				
				return i
			end
		end
	end
end

-- обработка нажатия кнопки мыши
function self.OnMouseDown(_owner, _pos, _button, _keyboard_state, _broadcast)
	-- если фишка двигается, то не обрабатываем клик
	if _broadcast or self.moving >= 0 then return false end
	
	-- анализируем, во что мы попали
	local dib_in_pos = self.FindDibByPos(_owner, _pos.X, _pos.Y) -- попали в какую-нибудь фишку?
	if dib_in_pos then
		-- попали в фишку - надо определить, на какой она позиции стоит
		local pos_x, pos_y  = self.objects[dib_in_pos].image.GetOffset().X, self.objects[dib_in_pos].image.GetOffset().Y
		local width, height = self.objects[dib_in_pos].image.GetSize().X, self.objects[dib_in_pos].image.GetSize().Y
		local center = { -- центр позиции совпадает с серединой нижнего края фишки
			X = pos_x + width/2,
			Y = pos_y + height
		} 
		-- теперь ищем позицию, которая приблизительно такая же, как найденная
		for i = 1, self.params.pos_amount do
			local posi = self.params.positions[i].pos
			if (math.abs(posi.X - center.X) < self.params.pos_width/2 ) and (math.abs(posi.Y - center.Y) < self.params.pos_height/2) then
				-- мы попали в эту позицию
				self.selected = dib_in_pos
				self.sel_pos = i
				self.SelectEnabledCells(_owner, i)
				break
			end
		end
	else
		-- попали не в фишку... значит могли попасть в позицию
		for i = 1, self.params.pos_amount do
			local posi = self.params.positions[i].pos
			if (math.abs(posi.X - _pos.X) < self.params.pos_width/2 ) and (math.abs(posi.Y - _pos.Y) < self.params.pos_height/2) then
				-- мы попали в эту позицию
				if self.selected ~= -1 then
					--  надо генерить путь от выделенной фишки к этой позиции
					local matr = self.MakeTransitionMatrix()

					local way = self.FindWay(matr, self.sel_pos, i)
					if (way == nil) then
						-- нет пути - ошибка. потом надо будет заменить на клип 
						local pos_clip_x, pos_clip_y = self.params.positions[i].pos.X, self.params.positions[i].pos.Y
						self.clip_cross.SetOffset(pos_clip_x - self.cross_size.X/2, pos_clip_y - self.cross_size.Y/2)
						self.clip_cross.SetSize(self.cross_size.X, self.cross_size.Y)
						self.clip_cross.GetClip().SetTime(0)
						self.clip_cross.GetClip().Play()
						
						if self.params.sound_pos.blocked then
							sound(self.params.sound_pos.blocked)
						end
					else
						-- инициализировать движение и изменить состояние selected на free, а i на object_type
						if #way > 1 then
							local pos_clip_x, pos_clip_y = self.params.positions[way[1]].pos.X, self.params.positions[way[1]].pos.Y
							self.clip_on_move.SetOffset(pos_clip_x - self.on_move_size.X/2, pos_clip_y - self.on_move_size.Y/2)
							self.clip_on_move.SetSize(self.on_move_size.X, self.on_move_size.Y)
						
							local w = self.ReverseArray(way)
							self.position_state[self.sel_pos] = "free"
							self.position_state[i] = self.objects[self.selected].object_type
							self.sel_pos = w[#w]
					
							self.cur_way = w -- указываем, по какому пути мы идем
							self.moving = self.selected -- движется выбранный объект
							self.cur_line = 1
							self.obj_pos.x = self.objects[self.selected].image.GetOffset().X + self.objects[self.selected].image.GetSize().X/2
							self.obj_pos.y = self.objects[self.selected].image.GetOffset().Y + self.objects[self.selected].image.GetSize().Y/2
					
							self.UpdateMovingTimer()
							
							self.fade_start  = self.timer.Get().GetTime()
							
							if self.params.sound_pos.move then
								sound(self.params.sound_pos.move)
							end
						end
					end
				end
				
				break
			end
		end
	end
	
	self.CheckEnd(_owner)
	return true
end


-- поиск пути между позициями _start_pos и _end_pos
-- _adj_matr - матрица смежности
-- ! путь выводится, начиная с _end_pos
function self.FindWay(_adj_matr, _start_pos, _end_pos)
	local isSeen = {} -- просматривали ли вершину
	local last = {} -- номер последней помеченой вершины
	local dst = {} -- текущие кратчайшие расстояния от start_pos до end_pos
	local pos_amount = self.params.pos_amount
	for j = 1, pos_amount do
		table.insert(isSeen, 0)
		table.insert(dst, -100) -- бесконечность
	end

	dst[_start_pos] = 0
	isSeen[_start_pos] = 1
	last = _start_pos
	-- поиск кратчайших расстояний от start_pos до остальных вершин графа (алгоритм Дейкстры)
	for j = 1, (pos_amount-1) do
		for i = 1, pos_amount do
			if (isSeen[i] == 0 and _adj_matr[last][i] == 1) then -- не помечена и связана с последней вершиной
				if (dst[i] < 0) then
					dst[i] = dst[last] + 1
				else
					dst[i] = math.min((dst[last] + 1), dst[i])
				end
			end
		end
		local min_dist = -100
		for x = 1, pos_amount do
			if (isSeen[x] == 0) then
				if (min_dist < 0) then
					min_dist = dst[x]
					last = x
				else
					if (dst[x] >= 0) then
						if (min_dist > dst[x]) then
							min_dist = dst[x]
							last = x
						end
					end
				end
			end
		end
		isSeen[last] = 1
	end
	
	-- построим сам путь
	if (dst[_end_pos] >= 0) then --если путь существует
		local way = {_end_pos} -- первым элементом будет последний элемент
		local verse = _end_pos
		while (verse ~= _start_pos) do
			for i = 1, pos_amount do
				if (dst[i] + 1 == dst[verse] and _adj_matr[i][way[#way]] == 1) then -- мы пришли сюда из этой вершины
					table.insert(way, i)
					verse = i
					break
				end
			end
		end
		
		return way -- построили список вершин в пути
	else
		return nil
	end
end

--создает матрицу смежности для текущего состояния поля
function self.MakeTransitionMatrix()
	local matr = {}
	local pos_amount = self.params.pos_amount
	-- заполняем нулями
	for i = 1, pos_amount do
		table.insert(matr, {})
		for j = 1, pos_amount do
			table.insert(matr[i], 0)
		end
	end
	-- выставляем единички в нужных местах
	for i = 1, pos_amount do
		if (self.position_state[i] == "free" or i == self.sel_pos) then
			local j = 1
			while (self.params.positions[i].neighbours[j]) do
				if (self.position_state[self.params.positions[i].neighbours[j]] == "free" or self.params.positions[i].neighbours[j] == self.sel_pos) then
					matr[i][self.params.positions[i].neighbours[j]] = 1
					matr[self.params.positions[i].neighbours[j]][i] = 1
				end
				j = j +1
			end
		end
	end
	
	return matr
end

-- выдает массив  _arr в обратном порядке
function self.ReverseArray(_arr)
	local size = #_arr
	local res = {}
	while (size > 0) do
		table.insert(res, _arr[size])
		size = size - 1
	end
	return res
end

-- обновление плавного исчезновения клипов
function self.UpdateFadeClips(_owner)
	if self.fade_start and self.enabled_cells then
		local need = self.params.enabled_fade_time
		local cur_time = (self.timer.Get().GetTime() - self.fade_start)/need
		if cur_time > 1 then
			cur_time = 1
		end
		for i, clip in ipairs(self.enabled_cells) do
			local color = sf.graphics.Color(clip.GetColor())
			color.Alpha = 255*(1 - cur_time)
			clip.SetColor(color)
		end
		if cur_time == 1 then
			self.fade_start = nil
			self.DeleteEnabledCellsClips(_owner)
		end
	end
end

-- обновление миниигры 
function self.OnUpdate(_owner)
	if (self.moving <= 0) then 
		return 
	end
	self.UpdateFadeClips(_owner)
	
	local ind_end = self.cur_way[self.cur_line + 1]

	local ind_start = self.cur_way[self.cur_line]
	
	if self.params.sound_object.move then
		sound(self.params.sound_object.move)
	end
	
	local width, height = self.objects[self.moving].image.GetSize().X, self.objects[self.moving].image.GetSize().Y
	local current_time = (self.timer.Get().GetTime() - self.last_start)/self.last_length
    if current_time > 1 then 
		current_time = 1  -- мы не можем зайти дальше точки 
	end
    -- вычисляем новую координату  объекта по величине сдвига
	local start_pos = self.params.positions[ind_start].pos
	local end_pos = self.params.positions[ind_end].pos
	self.obj_pos.x = start_pos.X + (end_pos.X - start_pos.X )*current_time 
	self.obj_pos.y = start_pos.Y + (end_pos.Y - start_pos.Y)*current_time 
    self.objects[self.moving].image.SetOffset(self.obj_pos.x - width/2, self.obj_pos.y - height)
	self.objects[self.moving].clip.SetOffset(self.obj_pos.x - width/2, self.obj_pos.y - height)
	
	local now = self.timer.Get().GetTime()
	if (now  >= self.last_length +  self.last_start) then -- идем дольше, чем рассчитанное время пути в этом отрезке?
		self.cur_line = self.cur_line + 1 -- перемещаемся на следующий отрезок пути
		if (self.cur_line == #self.cur_way) then
			-- дошли до конца пути, надо убрать информацию о движении
			local new_x = self.params.positions[self.cur_way[self.cur_line]].pos.X - width/2
			local new_y = self.params.positions[self.cur_way[self.cur_line]].pos.Y - height
			self.objects[self.moving].image.SetOffset(new_x, new_y)
			self.objects[self.moving].image.SetLayer(3)
			self.objects[self.moving].clip.SetSize(0, 0)
						
			self.clip_on_move.SetSize(0, 0) -- спрятали клип с выделением точки назначения
			if self.objects[self.moving].object_type == self.params.positions[ self.cur_way[#self.cur_way] ].end_state then
			-- проиграть клип, что фишка на одной из нужных позиций
			--__message("На месте!")
				local new_pos = self.params.positions[ self.cur_way[#self.cur_way] ].pos
				self.clip_on_correct.SetOffset(new_pos.X - self.on_correct_size.X/2, new_pos.Y - self.on_correct_size.Y/2)
				self.clip_on_correct.SetSize(self.on_correct_size.X, self.on_correct_size.Y)
				self.clip_on_correct.GetClip().SetTime(0)
				self.clip_on_correct.GetClip().Play()
				
				if self.params.sound_pos.correct_pos then
					sound(self.params.sound_pos.correct_pos)
				end
				
				if self.params.sound_object.move and self.params.fade_move_time then
					stop_sound(self.params.sound_object.move, self.params.fade_move_time)
				end
			end
			
			self.cur_way = {} -- по какому пути движется объект
			self.cur_line = -1 -- по какому участку пути сейчас двигаемся
			self.moving = -1 -- какой объект движется
			self.obj_pos = {x = 0, y = 0} -- позиция движущегося объекта
			
			self.selected = -1
			self.sel_pos = -1
			
			if (self.win) then -- пометка о победе меняется в начале движения, а игра должна закончиться только после окончания последнего перемещения
				--self.DeleteWidgets(_owner)
				_owner.SetGameResult(1)
				_owner.OnEndGame()
			end
		else -- пересчитать следующую длину
			self.UpdateMovingTimer()
		end
	end
end

-- запоминает момент начала движения от точки и вычисляет время движения до следующей точки отрезка
function self.UpdateMovingTimer()
	self.last_start = self.timer.Get().GetTime() -- начало движения	
	
	local height = self.objects[self.moving].image.GetSize().Y
	local end_pos = self.params.positions[self.cur_way[self.cur_line + 1]].pos

	local distance_sqr1 = (self.obj_pos.x - end_pos.X)*(self.obj_pos.x - end_pos.X)
	local distance_sqr2 = (self.obj_pos.y + height/2 - end_pos.Y)*(self.obj_pos.y + height/2 - end_pos.Y)
	
	self.last_length = 1000*math.sqrt(distance_sqr1 + distance_sqr2) / self.params.speed
end

function self.DeleteWidgets(_owner)
	for i = 1, #self.objects do
		self.objects[i].clip.SetSize(0,0)
		self.objects[i].clip.GetClip().Stop() -- отключили звук в клипе
		_owner.RemoveWidget(self.objects[i].clip)
	end
end
