Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,5 @@ gen
/output.mlpd
/.vscode/
.DS_Store
/coverage/lcov.info
/HexCore.Tests/coverage/lcov.info
10 changes: 10 additions & 0 deletions HexCore.Website/App.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
35 changes: 35 additions & 0 deletions HexCore.Website/Data/GraphData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Linq;
using HexCore;

namespace HexCore.Website.Data
{
public class GraphData
{
public Graph Graph { get; set; }
public MovementTypes MovementTypes { get; set; }

public List<PawnData> Pawns { get; set; }

public List<Coordinate2D> SelectedPawnMovementRange { get; set; } = new List<Coordinate2D>();

public Dictionary<int, Dictionary<int, CellState>> SortedCells { get; set; }

public bool CellExists(int row, int column)
{
return SortedCells.ContainsKey(row) && SortedCells[row].ContainsKey(column);
}

public List<List<HexTileData>> TileData;

public CellState CurrentlySelectedCell { get; set; }
public PawnData CurrentlySelectedPawnData { get; set; }

public int MaxColumnNumber => SortedCells
.Select(row => row.Value.Keys.Max() + 1)
.Concat(new[] {0})
.Max();

public int MaxRowNumber => SortedCells.Keys.Max() + 1;
}
}
273 changes: 273 additions & 0 deletions HexCore.Website/Data/GraphService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
using System;
using System.Collections.Generic;
using System.Linq;
using HexCore;
using HexCore.Website.Pages;

namespace HexCore.Website.Data
{
public static class Movements
{
public static TerrainType Ground = new TerrainType(1, "Ground");
public static TerrainType Water = new TerrainType(2, "Water");
public static MovementType WalkingType = new MovementType(1, "Walking");
public static MovementType SwimmingType = new MovementType(2, "Swimming");
public static MovementType HeavyType = new MovementType(3, "Heavy Type");
}
public class GraphService
{
private GraphData _graphData;

public event Action GraphDataUpdated;

private static Dictionary<int, Dictionary<int, CellState>> CreateTwoDimensionalMap(IEnumerable<CellState> cells)
{
var sortedCoordinates = new Dictionary<int, Dictionary<int, CellState>>();
foreach (var cell in cells)
{
var coordinate2d = cell.Coordinate3.To2D(OffsetTypes.OddRowsRight);
var row = coordinate2d.Y;
var col = coordinate2d.X;
if (!sortedCoordinates.ContainsKey(row))
{
sortedCoordinates.Add(row, new Dictionary<int, CellState>());
}
sortedCoordinates[row].Add(col, cell);
}

return sortedCoordinates;
}

private static List<PawnData> CreatePawns()
{
var knightPawn = new PawnData
{
Name = "Knight",
CurrentPosition = new Coordinate2D(1, 0, OffsetTypes.OddRowsRight),
MovementType = Movements.HeavyType,
MovementRange = 2,
Color = "red"
};
var orcPawn = new PawnData{
Name = "Orc",
CurrentPosition = new Coordinate2D(2, 3, OffsetTypes.OddRowsRight),
MovementType = Movements.WalkingType,
MovementRange = 2,
Color = "green"
};
var hydraPawn = new PawnData{
Name = "Hydra",
CurrentPosition = new Coordinate2D(2, 2, OffsetTypes.OddRowsRight),
MovementType = Movements.SwimmingType,
MovementRange = 2,
Color = "blue"
};

return new List<PawnData> {knightPawn, orcPawn, hydraPawn};
}

private static MovementTypes CreateMovementTypes()
{
return new MovementTypes(
new ITerrainType[] { Movements.Ground, Movements.Water },
new Dictionary<IMovementType, Dictionary<ITerrainType, int>>
{
[Movements.WalkingType] = new Dictionary<ITerrainType, int>
{
[Movements.Ground] = 1,
[Movements.Water] = 2
},
[Movements.SwimmingType] = new Dictionary<ITerrainType, int>
{
[Movements.Ground] = 2,
[Movements.Water] = 1
},
[Movements.HeavyType] = new Dictionary<ITerrainType, int>
{
[Movements.Ground] = 1,
[Movements.Water] = 99
}
}
);
}

private GraphData CreateGraph()
{
var movementTypes = CreateMovementTypes();

// Nice round shape
var graph = new Graph(new []
{
new CellState(false, new Coordinate2D(1, 0, OffsetTypes.OddRowsRight), Movements.Ground),
new CellState(false, new Coordinate2D(2, 0, OffsetTypes.OddRowsRight), Movements.Ground),
new CellState(false, new Coordinate2D(3, 0, OffsetTypes.OddRowsRight), Movements.Ground),
new CellState(false, new Coordinate2D(0, 1, OffsetTypes.OddRowsRight), Movements.Water),
new CellState(false, new Coordinate2D(1, 1, OffsetTypes.OddRowsRight), Movements.Ground),
new CellState(false, new Coordinate2D(2, 1, OffsetTypes.OddRowsRight), Movements.Ground),
new CellState(false, new Coordinate2D(3, 1, OffsetTypes.OddRowsRight), Movements.Ground),
new CellState(false, new Coordinate2D(0, 2, OffsetTypes.OddRowsRight), Movements.Water),
new CellState(false, new Coordinate2D(1, 2, OffsetTypes.OddRowsRight), Movements.Water),
new CellState(false, new Coordinate2D(2, 2, OffsetTypes.OddRowsRight), Movements.Water),
new CellState(false, new Coordinate2D(3, 2, OffsetTypes.OddRowsRight), Movements.Ground),
new CellState(false, new Coordinate2D(4, 2, OffsetTypes.OddRowsRight), Movements.Water),
new CellState(false, new Coordinate2D(0, 3, OffsetTypes.OddRowsRight), Movements.Water),
new CellState(false, new Coordinate2D(1, 3, OffsetTypes.OddRowsRight), Movements.Water),
new CellState(false, new Coordinate2D(2, 3, OffsetTypes.OddRowsRight), Movements.Ground),
new CellState(false, new Coordinate2D(3, 3, OffsetTypes.OddRowsRight), Movements.Ground),
new CellState(false, new Coordinate2D(1, 4, OffsetTypes.OddRowsRight), Movements.Water),
new CellState(false, new Coordinate2D(2, 4, OffsetTypes.OddRowsRight), Movements.Ground),
new CellState(false, new Coordinate2D(3, 4, OffsetTypes.OddRowsRight), Movements.Ground),
}, movementTypes);

var pawns = CreatePawns();
// Blocking our pawns positions, so no pawns can occupy the same position at the same time
// or use it for movement
graph.BlockCells(pawns.Select(pawn => pawn.CurrentPosition));

var graphData = new GraphData
{
Graph = graph,
MovementTypes = movementTypes,
Pawns = pawns,
SortedCells = CreateTwoDimensionalMap(graph.GetAllCells()),
TileData = new List<List<HexTileData>>()
};

_graphData = graphData;
foreach (var rowIndex in Enumerable.Range(0, _graphData.MaxRowNumber))
{
_graphData.TileData.Add(new List<HexTileData>());
foreach (var columnIndex in Enumerable.Range(0, _graphData.MaxColumnNumber))
{
_graphData.TileData[rowIndex].Add(new HexTileData
{
IsEmptySpace = IsEmptySpace(rowIndex, columnIndex),
IsSelected = IsCurrentlySelected(rowIndex, columnIndex),
ShowMoveButton = NeedsToShowMoveButton(rowIndex, columnIndex),
Pawn = GetPawn(rowIndex, columnIndex),
CellState = GetCellState(rowIndex, columnIndex),
Coordinate2D = RowAndColumnToOffsetOrr(rowIndex, columnIndex)
});
}
}

SelectCell(graph.GetAllCells()[0]);
return graphData;
}

public GraphData GetGraph()
{
return _graphData ??= CreateGraph();
}

private void HideAllMoveButtons()
{
foreach (var tile in _graphData.TileData.SelectMany(tileRow => tileRow))
{
tile.ShowMoveButton = false;
}
}

private PawnData GetPawn(CellState cell)
{
var coordinate = cell.Coordinate3.To2D(OffsetTypes.OddRowsRight);
return _graphData.Pawns.Find(pawn => pawn.CurrentPosition.Equals(coordinate));
}

private PawnData GetPawn(int row, int column)
{
if (IsEmptySpace(row, column)) return null;
var coordinate = RowAndColumnToOffsetOrr(row, column);
return _graphData.Pawns.Find(pawn => pawn.CurrentPosition.Equals(coordinate));

}

private void UnselectCell(CellState cellState)
{
if (cellState == null) return;
var coordinate2D = cellState.Coordinate3.To2D(OffsetTypes.OddRowsRight);
_graphData.TileData[coordinate2D.Y][coordinate2D.X].IsSelected = false;
}

private void SelectPawn(PawnData pawn)
{
_graphData.CurrentlySelectedPawnData = pawn;

if (pawn == null) return;
var movementRange = _graphData.Graph.GetMovementRange(
pawn.CurrentPosition, pawn.MovementRange, pawn.MovementType
);

foreach (var coordinate2 in movementRange)
{
_graphData.TileData[coordinate2.Y][coordinate2.X].ShowMoveButton = true;
}
}

private static Coordinate2D RowAndColumnToOffsetOrr(int row, int column)
{
return new Coordinate2D(column, row, OffsetTypes.OddRowsRight);
}

private bool IsEmptySpace(int row, int column)
{
return !_graphData.Graph.Contains(RowAndColumnToOffsetOrr(row, column));
}

private bool IsCurrentlySelected(int row, int column)
{
return _graphData.CurrentlySelectedCell == GetCellState(row, column);
}

private CellState GetCellState(int row, int column)
{
return IsEmptySpace(row, column) ? null : _graphData.SortedCells[row][column];
}

private bool NeedsToShowMoveButton(int row, int column)
{
if (!_graphData.CellExists(row, column)) return false;
var coordinate = _graphData.SortedCells[row][column].Coordinate3.To2D(OffsetTypes.OddRowsRight);
return _graphData.SelectedPawnMovementRange.Contains(coordinate);
}

private HexTileData GetTileData(Coordinate3D coordinate3D)
{
var coordinate2D = coordinate3D.To2D(OffsetTypes.OddRowsRight);
return _graphData.TileData[coordinate2D.Y][coordinate2D.X];
}

public void SelectCell(CellState cell)
{
HideAllMoveButtons();
UnselectCell(_graphData.CurrentlySelectedCell);

// Apply current selection
var tileData = GetTileData(cell.Coordinate3);
_graphData.CurrentlySelectedCell = cell;
tileData.IsSelected = true;

// Add pawn to selection if there's a pawn on a cell
var pawnOnCell = GetPawn(cell);
SelectPawn(pawnOnCell);

GraphDataUpdated?.Invoke();
}

public void MoveCurrentlySelectedPawn(Coordinate2D moveTo)
{
var pawn = _graphData.CurrentlySelectedPawnData;

// Remove pawn from old position
_graphData.TileData[pawn.CurrentPosition.Y][pawn.CurrentPosition.X].Pawn = null;
_graphData.Graph.UnblockCells(pawn.CurrentPosition);

// Place pawn into new position
pawn.CurrentPosition = moveTo;
_graphData.Graph.BlockCells(pawn.CurrentPosition);
_graphData.TileData[pawn.CurrentPosition.Y][pawn.CurrentPosition.X].Pawn = pawn;

GraphDataUpdated?.Invoke();
}
}
}
12 changes: 12 additions & 0 deletions HexCore.Website/Data/HexTileData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace HexCore.Website.Data
{
public class HexTileData
{
public bool IsEmptySpace { get; set; }
public PawnData Pawn;
public bool ShowMoveButton { get; set; }
public bool IsSelected { get; set; }
public CellState CellState { get; set; }
public Coordinate2D Coordinate2D { get; set; }
}
}
16 changes: 16 additions & 0 deletions HexCore.Website/Data/PawnData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using HexCore;

namespace HexCore.Website.Data
{
public class PawnData
{
public Coordinate2D CurrentPosition { get; set; }
public string Name { get; set; }

public MovementType MovementType { get; set; }

public int MovementRange { get; set; }

public string Color { get; set; }
}
}
36 changes: 36 additions & 0 deletions HexCore.Website/HexCore.Website.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="HexCore" Version="4.0.2" />
<PackageReference Include="Markdig" Version="0.20.0" />
</ItemGroup>

<ItemGroup>
<Content Update="Pages\GraphComponent.razor">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
<Content Update="Pages\GraphDemo.razor">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
<Content Update="wwwroot\css\site.css">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="Pages\HexTile.razor">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
<Content Update="wwwroot\img\logo.svg">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="wwwroot\scripts\script.js">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>

</Project>
Loading