Skip to content

Commit de7b1ae

Browse files
author
RUBIUS\chebanovdd
committed
Added terminal sample.
1 parent 527a117 commit de7b1ae

37 files changed

+1306
-4
lines changed

.idea/.idea.Match3/.idea/.name

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/.idea.Match3/.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using Match3.App;
2+
using Match3.App.Interfaces;
3+
using Match3.Template;
4+
using Match3.Template.Interfaces;
5+
using Match3.Template.SequenceDetectors;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using Terminal.Match3.FillStrategies;
8+
using Terminal.Match3.Interfaces;
9+
using Terminal.Match3.TileGroupDetectors;
10+
11+
namespace Terminal.Match3
12+
{
13+
public static class DependencyInjection
14+
{
15+
public static void AddInfrastructure(this IServiceCollection services)
16+
{
17+
var gameBoardRenderer = new TerminalGameBoardRenderer();
18+
services.AddSingleton<IGameBoardRenderer>(gameBoardRenderer);
19+
services.AddSingleton<ITerminalGameBoardRenderer>(gameBoardRenderer);
20+
21+
var gameConfig = GetGameConfig(gameBoardRenderer);
22+
services.AddSingleton<GameConfig<ITerminalGridSlot>>(gameConfig);
23+
24+
var itemGenerator = new TerminalItemGenerator();
25+
services.AddSingleton<IItemGenerator>(itemGenerator);
26+
services.AddSingleton<IItemsPool<ITerminalItem>>(itemGenerator);
27+
28+
services.AddSingleton<TerminalGame>();
29+
services.AddSingleton<ITerminalInputSystem, TerminalInputSystem>();
30+
services.AddSingleton<IBoardFillStrategy<ITerminalGridSlot>, SimpleFillStrategy>();
31+
}
32+
33+
private static GameConfig<ITerminalGridSlot> GetGameConfig(TerminalGameBoardRenderer gameBoardRenderer)
34+
{
35+
return new GameConfig<ITerminalGridSlot>
36+
{
37+
GameBoardDataProvider = gameBoardRenderer,
38+
LevelGoalsProvider = new LevelGoalsProvider(),
39+
ItemSwapper = new TerminalItemSwapper(gameBoardRenderer),
40+
GameBoardSolver = GetGameBoardSolver(),
41+
SolvedSequencesConsumers = GetSolvedSequencesConsumers(gameBoardRenderer)
42+
};
43+
}
44+
45+
private static IGameBoardSolver<ITerminalGridSlot> GetGameBoardSolver()
46+
{
47+
return new GameBoardSolver<ITerminalGridSlot>(new ISequenceDetector<ITerminalGridSlot>[]
48+
{
49+
new VerticalLineDetector<ITerminalGridSlot>(),
50+
new HorizontalLineDetector<ITerminalGridSlot>()
51+
});
52+
}
53+
54+
private static ISolvedSequencesConsumer<ITerminalGridSlot>[] GetSolvedSequencesConsumers(
55+
ITerminalGameBoardRenderer gameBoardRenderer)
56+
{
57+
return new ISolvedSequencesConsumer<ITerminalGridSlot>[]
58+
{
59+
new TileGroupDetector(gameBoardRenderer)
60+
};
61+
}
62+
}
63+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Terminal.Match3.Enums
2+
{
3+
public enum TileGroup
4+
{
5+
Unavailable = 0,
6+
Available = 1,
7+
Locked = 2
8+
}
9+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
using System.Runtime.CompilerServices;
3+
using System.Threading.Tasks;
4+
using Match3.Template.Extensions;
5+
using Match3.Template.Interfaces;
6+
7+
namespace Terminal.Match3.Extensions
8+
{
9+
public static class AppModeExtensions
10+
{
11+
public static TaskAwaiter GetAwaiter(this IGameMode gameMode)
12+
{
13+
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
14+
15+
void OnFinished(object sender, EventArgs eventArgs)
16+
{
17+
gameMode.Finished -= OnFinished;
18+
gameMode.Deactivate();
19+
20+
tcs.SetResult();
21+
}
22+
23+
gameMode.Finished += OnFinished;
24+
gameMode.Activate();
25+
26+
return tcs.Task.GetAwaiter();
27+
}
28+
}
29+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
using System.Text;
3+
using Microsoft.Extensions.Hosting;
4+
5+
namespace Terminal.Match3.Extensions
6+
{
7+
public static class ConsoleOptionsExtensions
8+
{
9+
public static void SetCursorVisible(this ConsoleLifetimeOptions _, bool isVisible)
10+
{
11+
Console.CursorVisible = isVisible;
12+
}
13+
14+
public static void SetOutputEncoding(this ConsoleLifetimeOptions _, Encoding encoding)
15+
{
16+
Console.OutputEncoding = encoding;
17+
}
18+
19+
public static void SuppressStatusMessages(this ConsoleLifetimeOptions options)
20+
{
21+
options.SuppressStatusMessages = true;
22+
}
23+
}
24+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Collections.Generic;
2+
using Match3.App;
3+
using Match3.Core.Interfaces;
4+
5+
namespace Terminal.Match3.Extensions
6+
{
7+
public static class ItemsSequenceExtensions
8+
{
9+
public static IEnumerable<TGridSlot> GetUniqueGridSlots<TGridSlot>(
10+
this IEnumerable<ItemSequence<TGridSlot>> sequences, bool onlyMovable = false) where TGridSlot : IGridSlot
11+
{
12+
var solvedGridSlots = new HashSet<TGridSlot>();
13+
14+
foreach (var sequence in sequences)
15+
{
16+
foreach (var solvedGridSlot in sequence.SolvedGridSlots)
17+
{
18+
if (onlyMovable && solvedGridSlot.IsMovable == false)
19+
{
20+
continue;
21+
}
22+
23+
if (solvedGridSlots.Add(solvedGridSlot) == false)
24+
{
25+
continue;
26+
}
27+
28+
yield return solvedGridSlot;
29+
}
30+
}
31+
32+
solvedGridSlots.Clear();
33+
}
34+
}
35+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using Cysharp.Threading.Tasks;
6+
using Match3.App;
7+
using Terminal.Match3.Interfaces;
8+
9+
namespace Terminal.Match3.FillStrategies.Jobs
10+
{
11+
public class ItemsShowJob : Job
12+
{
13+
private const char Stage1 = '✵';
14+
private const char Stage2 = '❄';
15+
private const int StagesDelay = 150;
16+
private const ConsoleColor StageColor = ConsoleColor.DarkGray;
17+
18+
private readonly char[] _icons;
19+
private readonly ConsoleColor[] _colors;
20+
private readonly IReadOnlyList<ITerminalItem> _items;
21+
private readonly ITerminalGameBoardRenderer _terminalGameBoardRenderer;
22+
23+
public ItemsShowJob(ITerminalGameBoardRenderer terminalGameBoardRenderer,
24+
IReadOnlyList<ITerminalItem> items) : base(0)
25+
{
26+
_terminalGameBoardRenderer = terminalGameBoardRenderer;
27+
28+
_items = items;
29+
_icons = new char[items.Count];
30+
_colors = new ConsoleColor[items.Count];
31+
}
32+
33+
public override async UniTask ExecuteAsync(CancellationToken cancellationToken = default)
34+
{
35+
StoreData();
36+
37+
await SetIcon(Stage1, StageColor, cancellationToken);
38+
await SetIcon(Stage2, StageColor, cancellationToken);
39+
40+
RestoreData();
41+
RedrawGameBoard();
42+
}
43+
44+
private void StoreData()
45+
{
46+
for (var i = 0; i < _items.Count; i++)
47+
{
48+
_icons[i] = _items[i].Icon;
49+
_colors[i] = _items[i].Color;
50+
}
51+
}
52+
53+
private async UniTask SetIcon(char icon, ConsoleColor color, CancellationToken cancellationToken = default)
54+
{
55+
foreach (var item in _items)
56+
{
57+
item.Icon = icon;
58+
item.Color = color;
59+
}
60+
61+
RedrawGameBoard();
62+
await Task.Delay(StagesDelay, cancellationToken);
63+
}
64+
65+
private void RestoreData()
66+
{
67+
for (var i = 0; i < _items.Count; i++)
68+
{
69+
_items[i].Icon = _icons[i];
70+
_items[i].Color = _colors[i];
71+
}
72+
}
73+
74+
private void RedrawGameBoard()
75+
{
76+
_terminalGameBoardRenderer.RedrawGameBoard();
77+
}
78+
}
79+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Match3.App;
4+
using Match3.App.Interfaces;
5+
using Match3.Template.Interfaces;
6+
using Terminal.Match3.FillStrategies.Jobs;
7+
using Terminal.Match3.Interfaces;
8+
using Terminal.Match3.Extensions;
9+
10+
namespace Terminal.Match3.FillStrategies
11+
{
12+
public class SimpleFillStrategy : IBoardFillStrategy<ITerminalGridSlot>
13+
{
14+
private readonly TerminalItem _notAvailableItem;
15+
private readonly IItemsPool<ITerminalItem> _itemsPool;
16+
private readonly ITerminalGameBoardRenderer _gameBoardRenderer;
17+
18+
public SimpleFillStrategy(ITerminalGameBoardRenderer terminalGameBoardRenderer,
19+
IItemsPool<ITerminalItem> itemsPool)
20+
{
21+
_itemsPool = itemsPool;
22+
_notAvailableItem = new TerminalItem(' ', ConsoleColor.DarkGray);
23+
_gameBoardRenderer = terminalGameBoardRenderer;
24+
}
25+
26+
public string Name => "Simple Fill Strategy";
27+
28+
public IEnumerable<IJob> GetFillJobs(IGameBoard<ITerminalGridSlot> gameBoard)
29+
{
30+
var itemsToShow = new List<ITerminalItem>();
31+
32+
for (var rowIndex = 0; rowIndex < gameBoard.RowCount; rowIndex++)
33+
{
34+
for (var columnIndex = 0; columnIndex < gameBoard.ColumnCount; columnIndex++)
35+
{
36+
var gridSlot = gameBoard[rowIndex, columnIndex];
37+
ITerminalItem item;
38+
39+
if (gridSlot.CanSetItem)
40+
{
41+
item = _itemsPool.GetItem();
42+
itemsToShow.Add(item);
43+
}
44+
else
45+
{
46+
item = _notAvailableItem;
47+
}
48+
49+
gridSlot.SetItem(item);
50+
}
51+
}
52+
53+
return new[] { new ItemsShowJob(_gameBoardRenderer, itemsToShow) };
54+
}
55+
56+
public IEnumerable<IJob> GetSolveJobs(IGameBoard<ITerminalGridSlot> gameBoard,
57+
IEnumerable<ItemSequence<ITerminalGridSlot>> sequences)
58+
{
59+
var itemsToShow = new List<ITerminalItem>();
60+
61+
foreach (var solvedGridSlot in sequences.GetUniqueGridSlots(true))
62+
{
63+
var newItem = _itemsPool.GetItem();
64+
var currentItem = solvedGridSlot.Item;
65+
66+
solvedGridSlot.SetItem(newItem);
67+
itemsToShow.Add(newItem);
68+
69+
_itemsPool.ReturnItem(currentItem);
70+
}
71+
72+
return new Job[]
73+
{
74+
new ItemsShowJob(_gameBoardRenderer, itemsToShow)
75+
};
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)