[Fix] ECS
This commit is contained in:
@@ -69,6 +69,7 @@ namespace Minesweeper.Commands
|
|||||||
}
|
}
|
||||||
|
|
||||||
var state = gameStateService.Current;
|
var state = gameStateService.Current;
|
||||||
|
var generatedOnThisCommand = false;
|
||||||
if (state != GameState.Preparing && state != GameState.Playing)
|
if (state != GameState.Preparing && state != GameState.Playing)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -85,6 +86,8 @@ namespace Minesweeper.Commands
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generatedOnThisCommand = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = boardService.OpenCell(command.X, command.Y);
|
var result = boardService.OpenCell(command.X, command.Y);
|
||||||
@@ -106,7 +109,15 @@ namespace Minesweeper.Commands
|
|||||||
gameStateService.SetState(GameState.Playing);
|
gameStateService.SetState(GameState.Playing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (generatedOnThisCommand)
|
||||||
|
{
|
||||||
boardEcsSyncService.SyncBoard(boardService);
|
boardEcsSyncService.SyncBoard(boardService);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
boardEcsSyncService.SyncCells(result.ChangedCells, boardService);
|
||||||
|
}
|
||||||
|
|
||||||
boardEcsSyncService.SyncGameState(gameStateService.Current, boardService.IsGenerated);
|
boardEcsSyncService.SyncGameState(gameStateService.Current, boardService.IsGenerated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,7 +156,7 @@ namespace Minesweeper.Commands
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boardEcsSyncService.SyncBoard(boardService);
|
boardEcsSyncService.SyncCells(result.ChangedCells, boardService);
|
||||||
boardEcsSyncService.SyncGameState(gameStateService.Current, boardService.IsGenerated);
|
boardEcsSyncService.SyncGameState(gameStateService.Current, boardService.IsGenerated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Minesweeper.Core
|
namespace Minesweeper.Core
|
||||||
{
|
{
|
||||||
public readonly struct BoardActionResult
|
public readonly struct BoardActionResult
|
||||||
{
|
{
|
||||||
public BoardActionResult(bool changed, bool hitMine, bool won, bool invalid)
|
public BoardActionResult(bool changed, bool hitMine, bool won, bool invalid, IReadOnlyList<BoardCellData> changedCells = null)
|
||||||
{
|
{
|
||||||
Changed = changed;
|
Changed = changed;
|
||||||
HitMine = hitMine;
|
HitMine = hitMine;
|
||||||
Won = won;
|
Won = won;
|
||||||
Invalid = invalid;
|
Invalid = invalid;
|
||||||
|
ChangedCells = changedCells;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Changed { get; }
|
public bool Changed { get; }
|
||||||
public bool HitMine { get; }
|
public bool HitMine { get; }
|
||||||
public bool Won { get; }
|
public bool Won { get; }
|
||||||
public bool Invalid { get; }
|
public bool Invalid { get; }
|
||||||
|
public IReadOnlyList<BoardCellData> ChangedCells { get; }
|
||||||
|
|
||||||
public static BoardActionResult NoChange => new BoardActionResult(false, false, false, false);
|
public static BoardActionResult NoChange => new BoardActionResult(false, false, false, false);
|
||||||
public static BoardActionResult InvalidAction => new BoardActionResult(false, false, false, true);
|
public static BoardActionResult InvalidAction => new BoardActionResult(false, false, false, true);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace Minesweeper.Core
|
|||||||
{
|
{
|
||||||
private readonly IGameSettingsService settingsService;
|
private readonly IGameSettingsService settingsService;
|
||||||
private readonly Random random = new Random();
|
private readonly Random random = new Random();
|
||||||
|
private readonly List<BoardCellData> changedCells = new List<BoardCellData>();
|
||||||
private CellData[,] cells;
|
private CellData[,] cells;
|
||||||
|
|
||||||
public BoardService(IGameSettingsService settingsService)
|
public BoardService(IGameSettingsService settingsService)
|
||||||
@@ -19,7 +20,9 @@ namespace Minesweeper.Core
|
|||||||
public int MinesCount { get; private set; }
|
public int MinesCount { get; private set; }
|
||||||
public bool IsGenerated { get; private set; }
|
public bool IsGenerated { get; private set; }
|
||||||
public int OpenedSafeCellsCount { get; private set; }
|
public int OpenedSafeCellsCount { get; private set; }
|
||||||
|
public int FlaggedCellsCount { get; private set; }
|
||||||
public int SafeCellsCount => Width * Height - MinesCount;
|
public int SafeCellsCount => Width * Height - MinesCount;
|
||||||
|
public IReadOnlyList<BoardCellData> LastChangedCells => changedCells;
|
||||||
|
|
||||||
public void InitializeEmptyBoard()
|
public void InitializeEmptyBoard()
|
||||||
{
|
{
|
||||||
@@ -27,7 +30,9 @@ namespace Minesweeper.Core
|
|||||||
Height = settingsService.SizeY;
|
Height = settingsService.SizeY;
|
||||||
MinesCount = Math.Min(settingsService.MinesCount, Width * Height - 1);
|
MinesCount = Math.Min(settingsService.MinesCount, Width * Height - 1);
|
||||||
OpenedSafeCellsCount = 0;
|
OpenedSafeCellsCount = 0;
|
||||||
|
FlaggedCellsCount = 0;
|
||||||
IsGenerated = false;
|
IsGenerated = false;
|
||||||
|
changedCells.Clear();
|
||||||
cells = new CellData[Width, Height];
|
cells = new CellData[Width, Height];
|
||||||
|
|
||||||
for (var x = 0; x < Width; x++)
|
for (var x = 0; x < Width; x++)
|
||||||
@@ -58,6 +63,7 @@ namespace Minesweeper.Core
|
|||||||
public BoardActionResult OpenCell(int x, int y)
|
public BoardActionResult OpenCell(int x, int y)
|
||||||
{
|
{
|
||||||
EnsureInitialized();
|
EnsureInitialized();
|
||||||
|
changedCells.Clear();
|
||||||
|
|
||||||
if (!IsGenerated || !IsInside(x, y))
|
if (!IsGenerated || !IsInside(x, y))
|
||||||
{
|
{
|
||||||
@@ -73,7 +79,8 @@ namespace Minesweeper.Core
|
|||||||
if (cell.IsMine)
|
if (cell.IsMine)
|
||||||
{
|
{
|
||||||
cell.IsOpened = true;
|
cell.IsOpened = true;
|
||||||
return new BoardActionResult(true, true, false, false);
|
AddChangedCell(cell);
|
||||||
|
return new BoardActionResult(true, true, false, false, changedCells);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cell.NeighborMines == 0)
|
if (cell.NeighborMines == 0)
|
||||||
@@ -85,12 +92,13 @@ namespace Minesweeper.Core
|
|||||||
OpenSafeCell(cell);
|
OpenSafeCell(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BoardActionResult(true, false, IsWin(), false);
|
return new BoardActionResult(true, false, IsWin(), false, changedCells);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BoardActionResult ToggleFlag(int x, int y)
|
public BoardActionResult ToggleFlag(int x, int y)
|
||||||
{
|
{
|
||||||
EnsureInitialized();
|
EnsureInitialized();
|
||||||
|
changedCells.Clear();
|
||||||
|
|
||||||
if (!IsInside(x, y))
|
if (!IsInside(x, y))
|
||||||
{
|
{
|
||||||
@@ -103,8 +111,19 @@ namespace Minesweeper.Core
|
|||||||
return BoardActionResult.NoChange;
|
return BoardActionResult.NoChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
cell.IsFlagged = !cell.IsFlagged;
|
if (cell.IsFlagged)
|
||||||
return new BoardActionResult(true, false, false, false);
|
{
|
||||||
|
cell.IsFlagged = false;
|
||||||
|
FlaggedCellsCount--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cell.IsFlagged = true;
|
||||||
|
FlaggedCellsCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddChangedCell(cell);
|
||||||
|
return new BoardActionResult(true, false, false, false, changedCells);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsInside(int x, int y)
|
public bool IsInside(int x, int y)
|
||||||
@@ -273,6 +292,12 @@ namespace Minesweeper.Core
|
|||||||
|
|
||||||
cell.IsOpened = true;
|
cell.IsOpened = true;
|
||||||
OpenedSafeCellsCount++;
|
OpenedSafeCellsCount++;
|
||||||
|
AddChangedCell(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddChangedCell(CellData cell)
|
||||||
|
{
|
||||||
|
changedCells.Add(ToData(cell));
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsWin()
|
private bool IsWin()
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ namespace Minesweeper.Core
|
|||||||
int MinesCount { get; }
|
int MinesCount { get; }
|
||||||
bool IsGenerated { get; }
|
bool IsGenerated { get; }
|
||||||
int OpenedSafeCellsCount { get; }
|
int OpenedSafeCellsCount { get; }
|
||||||
|
int FlaggedCellsCount { get; }
|
||||||
int SafeCellsCount { get; }
|
int SafeCellsCount { get; }
|
||||||
|
IReadOnlyList<BoardCellData> LastChangedCells { get; }
|
||||||
|
|
||||||
void InitializeEmptyBoard();
|
void InitializeEmptyBoard();
|
||||||
bool GenerateAfterFirstClick(int safeX, int safeY);
|
bool GenerateAfterFirstClick(int safeX, int safeY);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using Minesweeper.Core;
|
using Minesweeper.Core;
|
||||||
using Minesweeper.ECS.Components;
|
using Minesweeper.ECS.Components;
|
||||||
using Unity.Collections;
|
using Unity.Collections;
|
||||||
@@ -7,6 +8,10 @@ namespace Minesweeper.ECS
|
|||||||
{
|
{
|
||||||
public sealed class BoardEcsSyncService : IBoardEcsSyncService
|
public sealed class BoardEcsSyncService : IBoardEcsSyncService
|
||||||
{
|
{
|
||||||
|
private readonly Dictionary<int, Entity> cellsByIndex = new Dictionary<int, Entity>();
|
||||||
|
private int syncedWidth;
|
||||||
|
private int syncedHeight;
|
||||||
|
|
||||||
public void ClearBoard()
|
public void ClearBoard()
|
||||||
{
|
{
|
||||||
if (!TryGetEntityManager(out var entityManager))
|
if (!TryGetEntityManager(out var entityManager))
|
||||||
@@ -15,6 +20,9 @@ namespace Minesweeper.ECS
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClearCells(entityManager);
|
ClearCells(entityManager);
|
||||||
|
cellsByIndex.Clear();
|
||||||
|
syncedWidth = 0;
|
||||||
|
syncedHeight = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SyncBoard(IBoardService boardService)
|
public void SyncBoard(IBoardService boardService)
|
||||||
@@ -24,14 +32,27 @@ namespace Minesweeper.ECS
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (syncedWidth != boardService.Width || syncedHeight != boardService.Height || cellsByIndex.Count != boardService.Width * boardService.Height)
|
||||||
|
{
|
||||||
ClearCells(entityManager);
|
ClearCells(entityManager);
|
||||||
|
cellsByIndex.Clear();
|
||||||
|
syncedWidth = boardService.Width;
|
||||||
|
syncedHeight = boardService.Height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ClearChangedTags(entityManager);
|
||||||
|
}
|
||||||
|
|
||||||
var boardEntity = GetOrCreateSingleton<BoardConfigComponent>(entityManager);
|
var boardEntity = GetOrCreateSingleton<BoardConfigComponent>(entityManager);
|
||||||
entityManager.SetComponentData(boardEntity, new BoardConfigComponent
|
entityManager.SetComponentData(boardEntity, new BoardConfigComponent
|
||||||
{
|
{
|
||||||
Width = boardService.Width,
|
Width = boardService.Width,
|
||||||
Height = boardService.Height,
|
Height = boardService.Height,
|
||||||
MinesCount = boardService.MinesCount
|
MinesCount = boardService.MinesCount,
|
||||||
|
OpenedSafeCellsCount = boardService.OpenedSafeCellsCount,
|
||||||
|
FlaggedCellsCount = boardService.FlaggedCellsCount,
|
||||||
|
IsGenerated = ToByte(boardService.IsGenerated)
|
||||||
});
|
});
|
||||||
|
|
||||||
var archetype = entityManager.CreateArchetype(typeof(CellComponent));
|
var archetype = entityManager.CreateArchetype(typeof(CellComponent));
|
||||||
@@ -39,16 +60,45 @@ namespace Minesweeper.ECS
|
|||||||
for (var i = 0; i < cells.Count; i++)
|
for (var i = 0; i < cells.Count; i++)
|
||||||
{
|
{
|
||||||
var cell = cells[i];
|
var cell = cells[i];
|
||||||
var entity = entityManager.CreateEntity(archetype);
|
var index = ToIndex(cell.X, cell.Y, boardService.Width);
|
||||||
entityManager.SetComponentData(entity, new CellComponent
|
if (!cellsByIndex.TryGetValue(index, out var entity) || !entityManager.Exists(entity))
|
||||||
{
|
{
|
||||||
X = cell.X,
|
entity = entityManager.CreateEntity(archetype);
|
||||||
Y = cell.Y,
|
cellsByIndex[index] = entity;
|
||||||
IsMine = ToByte(cell.IsMine),
|
}
|
||||||
IsOpened = ToByte(cell.IsOpened),
|
|
||||||
IsFlagged = ToByte(cell.IsFlagged),
|
SetCell(entityManager, entity, cell, boardService.Width, false);
|
||||||
NeighborMines = cell.NeighborMines
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SyncCells(IReadOnlyList<BoardCellData> cells, IBoardService boardService)
|
||||||
|
{
|
||||||
|
if (cells == null || cells.Count == 0 || !TryGetEntityManager(out var entityManager))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var boardEntity = GetOrCreateSingleton<BoardConfigComponent>(entityManager);
|
||||||
|
entityManager.SetComponentData(boardEntity, new BoardConfigComponent
|
||||||
|
{
|
||||||
|
Width = boardService.Width,
|
||||||
|
Height = boardService.Height,
|
||||||
|
MinesCount = boardService.MinesCount,
|
||||||
|
OpenedSafeCellsCount = boardService.OpenedSafeCellsCount,
|
||||||
|
FlaggedCellsCount = boardService.FlaggedCellsCount,
|
||||||
|
IsGenerated = ToByte(boardService.IsGenerated)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ClearChangedTags(entityManager);
|
||||||
|
|
||||||
|
for (var i = 0; i < cells.Count; i++)
|
||||||
|
{
|
||||||
|
var cell = cells[i];
|
||||||
|
var index = ToIndex(cell.X, cell.Y, boardService.Width);
|
||||||
|
if (cellsByIndex.TryGetValue(index, out var entity) && entityManager.Exists(entity))
|
||||||
|
{
|
||||||
|
SetCell(entityManager, entity, cell, boardService.Width, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,6 +137,37 @@ namespace Minesweeper.ECS
|
|||||||
query.Dispose();
|
query.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ClearChangedTags(EntityManager entityManager)
|
||||||
|
{
|
||||||
|
var query = entityManager.CreateEntityQuery(typeof(CellChangedTag));
|
||||||
|
entityManager.RemoveComponent<CellChangedTag>(query);
|
||||||
|
query.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetCell(EntityManager entityManager, Entity entity, BoardCellData cell, int width, bool markChanged)
|
||||||
|
{
|
||||||
|
entityManager.SetComponentData(entity, new CellComponent
|
||||||
|
{
|
||||||
|
X = cell.X,
|
||||||
|
Y = cell.Y,
|
||||||
|
Index = ToIndex(cell.X, cell.Y, width),
|
||||||
|
IsMine = ToByte(cell.IsMine),
|
||||||
|
IsOpened = ToByte(cell.IsOpened),
|
||||||
|
IsFlagged = ToByte(cell.IsFlagged),
|
||||||
|
NeighborMines = cell.NeighborMines
|
||||||
|
});
|
||||||
|
|
||||||
|
if (markChanged && !entityManager.HasComponent<CellChangedTag>(entity))
|
||||||
|
{
|
||||||
|
entityManager.AddComponent<CellChangedTag>(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int ToIndex(int x, int y, int width)
|
||||||
|
{
|
||||||
|
return y * width + x;
|
||||||
|
}
|
||||||
|
|
||||||
private static Entity GetOrCreateSingleton<T>(EntityManager entityManager) where T : unmanaged, IComponentData
|
private static Entity GetOrCreateSingleton<T>(EntityManager entityManager) where T : unmanaged, IComponentData
|
||||||
{
|
{
|
||||||
var query = entityManager.CreateEntityQuery(typeof(T));
|
var query = entityManager.CreateEntityQuery(typeof(T));
|
||||||
|
|||||||
@@ -7,5 +7,8 @@ namespace Minesweeper.ECS.Components
|
|||||||
public int Width;
|
public int Width;
|
||||||
public int Height;
|
public int Height;
|
||||||
public int MinesCount;
|
public int MinesCount;
|
||||||
|
public int OpenedSafeCellsCount;
|
||||||
|
public int FlaggedCellsCount;
|
||||||
|
public byte IsGenerated;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using Unity.Entities;
|
||||||
|
|
||||||
|
namespace Minesweeper.ECS.Components
|
||||||
|
{
|
||||||
|
public struct CellChangedTag : IComponentData
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5702c8f40c71e7444a70e7aa73d8a9db
|
||||||
@@ -6,9 +6,11 @@ namespace Minesweeper.ECS.Components
|
|||||||
{
|
{
|
||||||
public int X;
|
public int X;
|
||||||
public int Y;
|
public int Y;
|
||||||
|
public int Index;
|
||||||
public byte IsMine;
|
public byte IsMine;
|
||||||
public byte IsOpened;
|
public byte IsOpened;
|
||||||
public byte IsFlagged;
|
public byte IsFlagged;
|
||||||
public int NeighborMines;
|
public int NeighborMines;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using Minesweeper.Core;
|
using Minesweeper.Core;
|
||||||
|
|
||||||
namespace Minesweeper.ECS
|
namespace Minesweeper.ECS
|
||||||
@@ -6,6 +7,7 @@ namespace Minesweeper.ECS
|
|||||||
{
|
{
|
||||||
void ClearBoard();
|
void ClearBoard();
|
||||||
void SyncBoard(IBoardService boardService);
|
void SyncBoard(IBoardService boardService);
|
||||||
|
void SyncCells(IReadOnlyList<BoardCellData> cells, IBoardService boardService);
|
||||||
void SyncGameState(GameState state, bool hasFirstClick);
|
void SyncGameState(GameState state, bool hasFirstClick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ namespace Minesweeper.Presentation.Presenters
|
|||||||
{
|
{
|
||||||
topPanelPresenter.SetCellPressActive(false);
|
topPanelPresenter.SetCellPressActive(false);
|
||||||
commandDispatcher.Dispatch(new OpenCellCommand(x, y));
|
commandDispatcher.Dispatch(new OpenCellCommand(x, y));
|
||||||
RefreshBoard();
|
RefreshChangedCellsOrBoard();
|
||||||
topPanelPresenter.RefreshCounters();
|
topPanelPresenter.RefreshCounters();
|
||||||
UpdateBoardInput();
|
UpdateBoardInput();
|
||||||
}
|
}
|
||||||
@@ -78,7 +78,7 @@ namespace Minesweeper.Presentation.Presenters
|
|||||||
private void OnCellFlagRequested(int x, int y)
|
private void OnCellFlagRequested(int x, int y)
|
||||||
{
|
{
|
||||||
commandDispatcher.Dispatch(new ToggleFlagCommand(x, y));
|
commandDispatcher.Dispatch(new ToggleFlagCommand(x, y));
|
||||||
RefreshBoard();
|
RefreshChangedCellsOrBoard();
|
||||||
topPanelPresenter.RefreshCounters();
|
topPanelPresenter.RefreshCounters();
|
||||||
UpdateBoardInput();
|
UpdateBoardInput();
|
||||||
}
|
}
|
||||||
@@ -156,6 +156,17 @@ namespace Minesweeper.Presentation.Presenters
|
|||||||
boardView.Refresh(readModel.GetCells(), IsFinalState());
|
boardView.Refresh(readModel.GetCells(), IsFinalState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RefreshChangedCellsOrBoard()
|
||||||
|
{
|
||||||
|
if (IsFinalState())
|
||||||
|
{
|
||||||
|
RefreshBoard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boardView.RefreshCells(readModel.GetChangedCells(), false);
|
||||||
|
}
|
||||||
|
|
||||||
private bool IsFinalState()
|
private bool IsFinalState()
|
||||||
{
|
{
|
||||||
var state = gameStateService.Current;
|
var state = gameStateService.Current;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace Minesweeper.Presentation.ReadModels
|
|||||||
public int Width => boardService.Width > 0 ? boardService.Width : settingsService.SizeX;
|
public int Width => boardService.Width > 0 ? boardService.Width : settingsService.SizeX;
|
||||||
public int Height => boardService.Height > 0 ? boardService.Height : settingsService.SizeY;
|
public int Height => boardService.Height > 0 ? boardService.Height : settingsService.SizeY;
|
||||||
public int MinesCount => boardService.MinesCount > 0 ? boardService.MinesCount : settingsService.MinesCount;
|
public int MinesCount => boardService.MinesCount > 0 ? boardService.MinesCount : settingsService.MinesCount;
|
||||||
public int FlaggedCellsCount => CountFlaggedCells();
|
public int FlaggedCellsCount => boardService.FlaggedCellsCount;
|
||||||
public int RemainingMinesCount => MinesCount - FlaggedCellsCount;
|
public int RemainingMinesCount => MinesCount - FlaggedCellsCount;
|
||||||
|
|
||||||
public bool TryGetCell(int x, int y, out BoardCellData cell)
|
public bool TryGetCell(int x, int y, out BoardCellData cell)
|
||||||
@@ -33,19 +33,10 @@ namespace Minesweeper.Presentation.ReadModels
|
|||||||
return boardService.GetCells();
|
return boardService.GetCells();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CountFlaggedCells()
|
public IReadOnlyList<BoardCellData> GetChangedCells()
|
||||||
{
|
{
|
||||||
var cells = boardService.GetCells();
|
return boardService.LastChangedCells;
|
||||||
var count = 0;
|
|
||||||
for (var i = 0; i < cells.Count; i++)
|
|
||||||
{
|
|
||||||
if (cells[i].IsFlagged)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,5 +14,6 @@ namespace Minesweeper.Presentation.ReadModels
|
|||||||
|
|
||||||
bool TryGetCell(int x, int y, out BoardCellData cell);
|
bool TryGetCell(int x, int y, out BoardCellData cell);
|
||||||
IReadOnlyList<BoardCellData> GetCells();
|
IReadOnlyList<BoardCellData> GetCells();
|
||||||
|
IReadOnlyList<BoardCellData> GetChangedCells();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ namespace Minesweeper.Presentation.Views
|
|||||||
private readonly Dictionary<int, CellView> cellsByCoordinate = new Dictionary<int, CellView>();
|
private readonly Dictionary<int, CellView> cellsByCoordinate = new Dictionary<int, CellView>();
|
||||||
private readonly Stack<CellView> pooledCells = new Stack<CellView>();
|
private readonly Stack<CellView> pooledCells = new Stack<CellView>();
|
||||||
private IReadOnlyList<BoardCellData> currentCells;
|
private IReadOnlyList<BoardCellData> currentCells;
|
||||||
|
private readonly List<BoardCellData> currentCellsCache = new List<BoardCellData>();
|
||||||
private bool inputEnabled = true;
|
private bool inputEnabled = true;
|
||||||
private bool currentRevealUnflaggedMines;
|
private bool currentRevealUnflaggedMines;
|
||||||
private bool resizeRefreshPending;
|
private bool resizeRefreshPending;
|
||||||
@@ -82,7 +83,7 @@ namespace Minesweeper.Presentation.Views
|
|||||||
Clear();
|
Clear();
|
||||||
currentBoardWidth = width;
|
currentBoardWidth = width;
|
||||||
currentBoardHeight = height;
|
currentBoardHeight = height;
|
||||||
currentCells = cells;
|
CacheCurrentCells(cells);
|
||||||
currentRevealUnflaggedMines = revealUnflaggedMines;
|
currentRevealUnflaggedMines = revealUnflaggedMines;
|
||||||
var layoutWasEnabled = gridLayoutGroup != null && gridLayoutGroup.enabled;
|
var layoutWasEnabled = gridLayoutGroup != null && gridLayoutGroup.enabled;
|
||||||
SetGridLayoutEnabled(false);
|
SetGridLayoutEnabled(false);
|
||||||
@@ -109,12 +110,23 @@ namespace Minesweeper.Presentation.Views
|
|||||||
|
|
||||||
public void Refresh(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines)
|
public void Refresh(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines)
|
||||||
{
|
{
|
||||||
currentCells = cells;
|
CacheCurrentCells(cells);
|
||||||
currentRevealUnflaggedMines = revealUnflaggedMines;
|
currentRevealUnflaggedMines = revealUnflaggedMines;
|
||||||
|
|
||||||
|
RefreshCells(cells, revealUnflaggedMines);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshCells(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines)
|
||||||
|
{
|
||||||
|
if (cells == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < cells.Count; i++)
|
for (var i = 0; i < cells.Count; i++)
|
||||||
{
|
{
|
||||||
var cell = cells[i];
|
var cell = cells[i];
|
||||||
|
UpdateCachedCell(cell);
|
||||||
if (cellsByCoordinate.TryGetValue(ToKey(cell.X, cell.Y), out var view))
|
if (cellsByCoordinate.TryGetValue(ToKey(cell.X, cell.Y), out var view))
|
||||||
{
|
{
|
||||||
view.Render(cell, uiConfig, currentPixelsPerUnitMultiplier, currentContentPadding, revealUnflaggedMines);
|
view.Render(cell, uiConfig, currentPixelsPerUnitMultiplier, currentContentPadding, revealUnflaggedMines);
|
||||||
@@ -250,12 +262,19 @@ namespace Minesweeper.Presentation.Views
|
|||||||
{
|
{
|
||||||
view = pooledCells.Pop();
|
view = pooledCells.Pop();
|
||||||
view.transform.SetParent(gridLayoutGroup.transform, false);
|
view.transform.SetParent(gridLayoutGroup.transform, false);
|
||||||
|
view.transform.SetAsLastSibling();
|
||||||
view.Initialize(cell.X, cell.Y);
|
view.Initialize(cell.X, cell.Y);
|
||||||
view.gameObject.SetActive(true);
|
view.gameObject.SetActive(true);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cellViewFactory.CreateCell(cell, gridLayoutGroup.transform);
|
view = cellViewFactory.CreateCell(cell, gridLayoutGroup.transform);
|
||||||
|
if (view != null)
|
||||||
|
{
|
||||||
|
view.transform.SetAsLastSibling();
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Clear()
|
private void Clear()
|
||||||
@@ -273,6 +292,31 @@ namespace Minesweeper.Presentation.Views
|
|||||||
}
|
}
|
||||||
|
|
||||||
cellsByCoordinate.Clear();
|
cellsByCoordinate.Clear();
|
||||||
|
currentCellsCache.Clear();
|
||||||
|
currentCells = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CacheCurrentCells(IReadOnlyList<BoardCellData> cells)
|
||||||
|
{
|
||||||
|
currentCellsCache.Clear();
|
||||||
|
if (cells != null)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < cells.Count; i++)
|
||||||
|
{
|
||||||
|
currentCellsCache.Add(cells[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCells = currentCellsCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateCachedCell(BoardCellData cell)
|
||||||
|
{
|
||||||
|
var index = cell.Y * currentBoardWidth + cell.X;
|
||||||
|
if (index >= 0 && index < currentCellsCache.Count)
|
||||||
|
{
|
||||||
|
currentCellsCache[index] = cell;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PoolCell(CellView cell)
|
private void PoolCell(CellView cell)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace Minesweeper.Presentation.Views
|
|||||||
void Hide();
|
void Hide();
|
||||||
void Rebuild(IReadOnlyList<BoardCellData> cells, int width, int height, ICellViewFactory cellViewFactory, bool revealUnflaggedMines);
|
void Rebuild(IReadOnlyList<BoardCellData> cells, int width, int height, ICellViewFactory cellViewFactory, bool revealUnflaggedMines);
|
||||||
void Refresh(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines);
|
void Refresh(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines);
|
||||||
|
void RefreshCells(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines);
|
||||||
void SetInputEnabled(bool enabled);
|
void SetInputEnabled(bool enabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ namespace Minesweeper.Presentation.Views
|
|||||||
public void Hide() { }
|
public void Hide() { }
|
||||||
public void Rebuild(IReadOnlyList<BoardCellData> cells, int width, int height, ICellViewFactory cellViewFactory, bool revealUnflaggedMines) { }
|
public void Rebuild(IReadOnlyList<BoardCellData> cells, int width, int height, ICellViewFactory cellViewFactory, bool revealUnflaggedMines) { }
|
||||||
public void Refresh(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines) { }
|
public void Refresh(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines) { }
|
||||||
|
public void RefreshCells(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines) { }
|
||||||
public void SetInputEnabled(bool enabled) { }
|
public void SetInputEnabled(bool enabled) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user