From 832b489a1fcd4a743eb015d19819b31b31de25b3 Mon Sep 17 00:00:00 2001 From: Shyrokyi Vladislav Date: Sun, 11 Jul 2021 20:11:15 +0300 Subject: [PATCH 01/13] [REFACTORING] Remove classes extended for ulong --- C#/Board.cs | 5 ----- C#/Core.cs | 5 ----- C#/Element.cs | 2 -- C#/RandomElementGenerator.cs | 2 -- C#/UpdateLoop.cs | 2 -- ConsoleOut/Program.cs | 6 +++--- 6 files changed, 3 insertions(+), 19 deletions(-) diff --git a/C#/Board.cs b/C#/Board.cs index b1fa808..09418c1 100644 --- a/C#/Board.cs +++ b/C#/Board.cs @@ -119,9 +119,4 @@ public override int GetHashCode() } } - public class Board : Board - { - public Board(int height, int width, ulong initValue) : base(height, width, () => initValue) { } - } - } diff --git a/C#/Core.cs b/C#/Core.cs index 92e0bc5..b475494 100644 --- a/C#/Core.cs +++ b/C#/Core.cs @@ -153,9 +153,4 @@ public Core Build() #endregion } - public class Core : Core - { - public Core(Board board) : base(board) { } - } - } diff --git a/C#/Element.cs b/C#/Element.cs index 466e295..8fc35c8 100644 --- a/C#/Element.cs +++ b/C#/Element.cs @@ -57,6 +57,4 @@ public Element Build() #endregion } - public class Element : Element { } - } diff --git a/C#/RandomElementGenerator.cs b/C#/RandomElementGenerator.cs index 54ff830..0620e64 100644 --- a/C#/RandomElementGenerator.cs +++ b/C#/RandomElementGenerator.cs @@ -89,6 +89,4 @@ public RandomElementGenerator Build() #endregion } - public class RandomElementGenerator : RandomElementGenerator { } - } diff --git a/C#/UpdateLoop.cs b/C#/UpdateLoop.cs index 08fb224..a0ab388 100644 --- a/C#/UpdateLoop.cs +++ b/C#/UpdateLoop.cs @@ -221,6 +221,4 @@ public UpdateLoop Build() #endregion } - public class UpdateLoop : UpdateLoop { } - } diff --git a/ConsoleOut/Program.cs b/ConsoleOut/Program.cs index e9f0f6f..9dcc869 100644 --- a/ConsoleOut/Program.cs +++ b/ConsoleOut/Program.cs @@ -9,13 +9,13 @@ public static class Program { public static void Main(string[] args) { - var board = new Board(4, 4, 0); - var elementGenerator = RandomElementGenerator.Builder() + var board = new Board(4, 4, () => 0); + var elementGenerator = RandomElementGenerator.Builder() .SetEmptyChecker(element => element == 0) .Build(); elementGenerator.AddToPool(2, 95); elementGenerator.AddToPool(4, 5); - var app = Core.Builder() + var app = Core.Builder() .SetBoard(board) .SetBaseValue(0) .SetMerge((value, oldValue) => value + oldValue) From 484618a9396213f0a3694b0c84bda404460fc997 Mon Sep 17 00:00:00 2001 From: Shyrokyi Vladislav Date: Sun, 11 Jul 2021 20:16:06 +0300 Subject: [PATCH 02/13] [REFACTORING] Rename main class --- C#/{Core.cs => BoardBehavior.cs} | 8 ++++---- ConsoleOut/Program.cs | 4 ++-- Core_2048.csproj | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) rename C#/{Core.cs => BoardBehavior.cs} (96%) diff --git a/C#/Core.cs b/C#/BoardBehavior.cs similarity index 96% rename from C#/Core.cs rename to C#/BoardBehavior.cs index b475494..e6dd3e3 100644 --- a/C#/Core.cs +++ b/C#/BoardBehavior.cs @@ -4,11 +4,11 @@ namespace Core_2048 { - public class Core + public class BoardBehavior { public Action, Element>> Updated; - public Core(Board board) + public BoardBehavior(Board board) { Board = board; } @@ -138,9 +138,9 @@ public CoreBuilder SetElementGenerator(IElementGenerator elementGenerator) return this; } - public Core Build() + public BoardBehavior Build() { - return new Core(_board) + return new BoardBehavior(_board) { Merge = _merge, Predictor = _predictor, diff --git a/ConsoleOut/Program.cs b/ConsoleOut/Program.cs index 9dcc869..3d103fa 100644 --- a/ConsoleOut/Program.cs +++ b/ConsoleOut/Program.cs @@ -15,7 +15,7 @@ public static void Main(string[] args) .Build(); elementGenerator.AddToPool(2, 95); elementGenerator.AddToPool(4, 5); - var app = Core.Builder() + var app = BoardBehavior.Builder() .SetBoard(board) .SetBaseValue(0) .SetMerge((value, oldValue) => value + oldValue) @@ -43,7 +43,7 @@ public static void Main(string[] args) } } - private static void Render(Core app) + private static void Render(BoardBehavior app) { Console.Clear(); var prevRow = -1; diff --git a/Core_2048.csproj b/Core_2048.csproj index d3fede0..998721b 100644 --- a/Core_2048.csproj +++ b/Core_2048.csproj @@ -39,7 +39,7 @@ - + From 84db59bd015169a17e5d20b623068c370a7dc275 Mon Sep 17 00:00:00 2001 From: Shyrokyi Vladislav Date: Sun, 11 Jul 2021 20:25:26 +0300 Subject: [PATCH 03/13] [REFACTORING] Remove Element builder --- C#/Board.cs | 11 ++++---- C#/BoardBehavior.cs | 22 ++++++++-------- C#/Element.cs | 49 ------------------------------------ C#/RandomElementGenerator.cs | 11 ++++---- C#/UpdateLoop.cs | 22 ++++++++-------- 5 files changed, 36 insertions(+), 79 deletions(-) diff --git a/C#/Board.cs b/C#/Board.cs index 09418c1..16a722a 100644 --- a/C#/Board.cs +++ b/C#/Board.cs @@ -29,11 +29,12 @@ public IEnumerator> GetEnumerator() { for (var column = 0; column < _values.GetLength(1); column++) { - yield return Element.Builder() - .SetRow(row) - .SetColumn(column) - .SetValue(_values[row, column]) - .Build(); + yield return new Element() + { + Row = row, + Column = column, + Value = _values[row, column] + }; } } } diff --git a/C#/BoardBehavior.cs b/C#/BoardBehavior.cs index e6dd3e3..3fe02f1 100644 --- a/C#/BoardBehavior.cs +++ b/C#/BoardBehavior.cs @@ -76,16 +76,18 @@ public UpdateLoop.Drop DropFactory(bool isIncreasing) public UpdateLoop.Get GetterFactory(bool isAlongRow) { return isAlongRow - ? new UpdateLoop.Get((outerItem, innerItem) => Element.Builder() - .SetRow(outerItem) - .SetColumn(innerItem) - .SetValue(Board.Get(outerItem, innerItem)) - .Build()) - : (outerItem, innerItem) => Element.Builder() - .SetRow(innerItem) - .SetColumn(outerItem) - .SetValue(Board.Get(innerItem, outerItem)) - .Build(); + ? new UpdateLoop.Get((outerItem, innerItem) => new Element + { + Row = outerItem, + Column = innerItem, + Value = Board.Get(outerItem, innerItem) + }) + : (outerItem, innerItem) => new Element + { + Row = innerItem, + Column = outerItem, + Value = Board.Get(innerItem, outerItem) + }; } #region Builder diff --git a/C#/Element.cs b/C#/Element.cs index 8fc35c8..f93849e 100644 --- a/C#/Element.cs +++ b/C#/Element.cs @@ -6,55 +6,6 @@ public class Element public int Column; public int Row; public T Value; - - #region Builder - - public static ElementBuilder Builder() - { - return new ElementBuilder(); - } - - public class ElementBuilder - { - private int _column; - private int _row; - private T _value; - - public ElementBuilder SetRow(int row) - { - _row = row; - - return this; - } - - public ElementBuilder SetColumn(int column) - { - _column = column; - - return this; - } - - public ElementBuilder SetValue(T value) - { - _value = value; - - return this; - } - - public Element Build() - { - var build = new Element - { - Row = _row, - Column = _column, - Value = _value - }; - - return build; - } - } - - #endregion } } diff --git a/C#/RandomElementGenerator.cs b/C#/RandomElementGenerator.cs index 0620e64..5393f53 100644 --- a/C#/RandomElementGenerator.cs +++ b/C#/RandomElementGenerator.cs @@ -40,11 +40,12 @@ public Element GetNewElement(Board board) where predicate.Invoke(resultPercentage) select element; - return Element.Builder() - .SetRow(randomPosition.Row) - .SetColumn(randomPosition.Column) - .SetValue(resultElements.First()) - .Build(); + return new Element + { + Row = randomPosition.Row, + Column = randomPosition.Column, + Value = resultElements.First() + }; } public void AddToPool(T value, int percentage) diff --git a/C#/UpdateLoop.cs b/C#/UpdateLoop.cs index a0ab388..47c854b 100644 --- a/C#/UpdateLoop.cs +++ b/C#/UpdateLoop.cs @@ -65,11 +65,12 @@ private ChangeElementAction ExecuteWithMerge(int outerItem, int innerItem, int n var previous = _get(outerItem, innerItem); var newElement = _get(outerItem, newInnerItem); - var next = Element.Builder() - .SetRow(newElement.Row) - .SetColumn(newElement.Column) - .SetValue(_merge(newElement.Value, previous.Value)) - .Build(); + var next = new Element + { + Row = newElement.Row, + Column = newElement.Column, + Value = _merge(newElement.Value, previous.Value) + }; return new ChangeElementAction { @@ -84,11 +85,12 @@ private ChangeElementAction ExecuteWithoutMerge(int outerItem, int innerItem, in var previous = _get(outerItem, innerItem); var newElement = _get(outerItem, newInnerItem); - var next = Element.Builder() - .SetRow(newElement.Row) - .SetColumn(newElement.Column) - .SetValue(previous.Value) - .Build(); + var next = new Element() + { + Row = newElement.Row, + Column = newElement.Column, + Value = previous.Value + }; return new ChangeElementAction { From bf29f151866b1e545b2a8938e4e128dc0e04808a Mon Sep 17 00:00:00 2001 From: Shyrokyi Vladislav Date: Sun, 11 Jul 2021 20:27:45 +0300 Subject: [PATCH 04/13] [REFACTORING] Rename Element to Cell --- C#/Board.cs | 10 +++++----- C#/BoardBehavior.cs | 8 ++++---- C#/BoardHelper.cs | 2 +- C#/{Element.cs => Cell.cs} | 2 +- C#/IElementGenerator.cs | 2 +- C#/RandomElementGenerator.cs | 4 ++-- C#/UpdateLoop.cs | 10 +++++----- Core_2048.csproj | 2 +- 8 files changed, 20 insertions(+), 20 deletions(-) rename C#/{Element.cs => Cell.cs} (80%) diff --git a/C#/Board.cs b/C#/Board.cs index 16a722a..70b615a 100644 --- a/C#/Board.cs +++ b/C#/Board.cs @@ -5,7 +5,7 @@ namespace Core_2048 { - public class Board : IEnumerable> + public class Board : IEnumerable> { public delegate void Mapper(T value, int row, int column); @@ -23,13 +23,13 @@ public Board(int height, int width, Func valueInitiator) public int Height { get; } public int Width { get; } - public IEnumerator> GetEnumerator() + public IEnumerator> GetEnumerator() { for (var row = 0; row < _values.GetLength(0); row++) { for (var column = 0; column < _values.GetLength(1); column++) { - yield return new Element() + yield return new Cell() { Row = row, Column = column, @@ -56,9 +56,9 @@ public Board Set(int row, int column, T value) return this; } - public Board Set(Element element) + public Board Set(Cell cell) { - Set(element.Row, element.Column, element.Value); + Set(cell.Row, cell.Column, cell.Value); return this; } diff --git a/C#/BoardBehavior.cs b/C#/BoardBehavior.cs index 3fe02f1..255987c 100644 --- a/C#/BoardBehavior.cs +++ b/C#/BoardBehavior.cs @@ -6,7 +6,7 @@ namespace Core_2048 public class BoardBehavior { - public Action, Element>> Updated; + public Action, Cell>> Updated; public BoardBehavior(Board board) { @@ -33,7 +33,7 @@ public void AddNew() public void Update(bool isAlongRow, bool isIncreasing) { var changes = CalculateChanges(isAlongRow, isIncreasing); - var updateMap = new Dictionary, Element>(); + var updateMap = new Dictionary, Cell>(); foreach (var changeElementAction in changes) { var prev = changeElementAction.Previous; @@ -76,13 +76,13 @@ public UpdateLoop.Drop DropFactory(bool isIncreasing) public UpdateLoop.Get GetterFactory(bool isAlongRow) { return isAlongRow - ? new UpdateLoop.Get((outerItem, innerItem) => new Element + ? new UpdateLoop.Get((outerItem, innerItem) => new Cell { Row = outerItem, Column = innerItem, Value = Board.Get(outerItem, innerItem) }) - : (outerItem, innerItem) => new Element + : (outerItem, innerItem) => new Cell { Row = innerItem, Column = outerItem, diff --git a/C#/BoardHelper.cs b/C#/BoardHelper.cs index 051d955..2d691fd 100644 --- a/C#/BoardHelper.cs +++ b/C#/BoardHelper.cs @@ -7,7 +7,7 @@ namespace Core_2048 public static class BoardHelper { - public static IEnumerable> GetEmpties(Board board, Predicate emptyChecker) + public static IEnumerable> GetEmpties(Board board, Predicate emptyChecker) { return board.Where(value => emptyChecker.Invoke(value.Value)); } diff --git a/C#/Element.cs b/C#/Cell.cs similarity index 80% rename from C#/Element.cs rename to C#/Cell.cs index f93849e..090ce54 100644 --- a/C#/Element.cs +++ b/C#/Cell.cs @@ -1,7 +1,7 @@ namespace Core_2048 { - public class Element + public class Cell { public int Column; public int Row; diff --git a/C#/IElementGenerator.cs b/C#/IElementGenerator.cs index bf94e3f..50585b7 100644 --- a/C#/IElementGenerator.cs +++ b/C#/IElementGenerator.cs @@ -4,7 +4,7 @@ namespace Core_2048 public interface IElementGenerator { - Element GetNewElement(Board board); + Cell GetNewElement(Board board); } } diff --git a/C#/RandomElementGenerator.cs b/C#/RandomElementGenerator.cs index 5393f53..08f0f29 100644 --- a/C#/RandomElementGenerator.cs +++ b/C#/RandomElementGenerator.cs @@ -13,7 +13,7 @@ public class RandomElementGenerator : IElementGenerator private int _allPercentage; private Predicate _emptyChecker; - public Element GetNewElement(Board board) + public Cell GetNewElement(Board board) { var empties = BoardHelper.GetEmpties(board, _emptyChecker).ToList(); if (empties.Count == 0) @@ -40,7 +40,7 @@ public Element GetNewElement(Board board) where predicate.Invoke(resultPercentage) select element; - return new Element + return new Cell { Row = randomPosition.Row, Column = randomPosition.Column, diff --git a/C#/UpdateLoop.cs b/C#/UpdateLoop.cs index 47c854b..1b96f9d 100644 --- a/C#/UpdateLoop.cs +++ b/C#/UpdateLoop.cs @@ -9,7 +9,7 @@ public class UpdateLoop : IEnumerable.ChangeElementAction> { public delegate int Drop(int index); - public delegate Element Get(int outerItem, int innerItem); + public delegate Cell Get(int outerItem, int innerItem); public delegate bool IsInnerCondition(int index); @@ -65,7 +65,7 @@ private ChangeElementAction ExecuteWithMerge(int outerItem, int innerItem, int n var previous = _get(outerItem, innerItem); var newElement = _get(outerItem, newInnerItem); - var next = new Element + var next = new Cell { Row = newElement.Row, Column = newElement.Column, @@ -85,7 +85,7 @@ private ChangeElementAction ExecuteWithoutMerge(int outerItem, int innerItem, in var previous = _get(outerItem, innerItem); var newElement = _get(outerItem, newInnerItem); - var next = new Element() + var next = new Cell() { Row = newElement.Row, Column = newElement.Column, @@ -112,8 +112,8 @@ private int CalculateNewItem(int innerItem, int outerItem) public class ChangeElementAction { - public Element Next; - public Element Previous; + public Cell Next; + public Cell Previous; } #region Builder diff --git a/Core_2048.csproj b/Core_2048.csproj index 998721b..998d2a8 100644 --- a/Core_2048.csproj +++ b/Core_2048.csproj @@ -40,7 +40,7 @@ - + From 70f68545b717928fb94fced30cdd3773e62cab2f Mon Sep 17 00:00:00 2001 From: Shyrokyi Vladislav Date: Sun, 11 Jul 2021 20:28:44 +0300 Subject: [PATCH 05/13] [REFACTORING] Rename IElementGenerator to ICellGenerator --- C#/BoardBehavior.cs | 12 ++++++------ C#/{IElementGenerator.cs => ICellGenerator.cs} | 2 +- ...domElementGenerator.cs => RandomCellGenerator.cs} | 6 +++--- ConsoleOut/Program.cs | 2 +- Core_2048.csproj | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) rename C#/{IElementGenerator.cs => ICellGenerator.cs} (67%) rename C#/{RandomElementGenerator.cs => RandomCellGenerator.cs} (93%) diff --git a/C#/BoardBehavior.cs b/C#/BoardBehavior.cs index 255987c..bbaa7bb 100644 --- a/C#/BoardBehavior.cs +++ b/C#/BoardBehavior.cs @@ -17,11 +17,11 @@ public BoardBehavior(Board board) public UpdateLoop.Merge Merge { get; set; } public UpdateLoop.Predictor Predictor { get; set; } public T BaseValue { get; set; } - public IElementGenerator ElementGenerator { get; set; } + public ICellGenerator CellGenerator { get; set; } public void AddNew() { - var element = ElementGenerator.GetNewElement(Board); + var element = CellGenerator.GetNewElement(Board); if (element == null) { return; @@ -103,7 +103,7 @@ public class CoreBuilder private UpdateLoop.Merge _merge; private UpdateLoop.Predictor _predictor; private T _baseValue; - private IElementGenerator _elementGenerator; + private ICellGenerator _cellGenerator; public CoreBuilder SetBoard(Board board) { @@ -133,9 +133,9 @@ public CoreBuilder SetBaseValue(T baseValue) return this; } - public CoreBuilder SetElementGenerator(IElementGenerator elementGenerator) + public CoreBuilder SetElementGenerator(ICellGenerator cellGenerator) { - _elementGenerator = elementGenerator; + _cellGenerator = cellGenerator; return this; } @@ -147,7 +147,7 @@ public BoardBehavior Build() Merge = _merge, Predictor = _predictor, BaseValue = _baseValue, - ElementGenerator = _elementGenerator + CellGenerator = _cellGenerator }; } } diff --git a/C#/IElementGenerator.cs b/C#/ICellGenerator.cs similarity index 67% rename from C#/IElementGenerator.cs rename to C#/ICellGenerator.cs index 50585b7..962437d 100644 --- a/C#/IElementGenerator.cs +++ b/C#/ICellGenerator.cs @@ -2,7 +2,7 @@ namespace Core_2048 { - public interface IElementGenerator + public interface ICellGenerator { Cell GetNewElement(Board board); } diff --git a/C#/RandomElementGenerator.cs b/C#/RandomCellGenerator.cs similarity index 93% rename from C#/RandomElementGenerator.cs rename to C#/RandomCellGenerator.cs index 08f0f29..d581ea5 100644 --- a/C#/RandomElementGenerator.cs +++ b/C#/RandomCellGenerator.cs @@ -5,7 +5,7 @@ namespace Core_2048 { - public class RandomElementGenerator : IElementGenerator + public class RandomCellGenerator : ICellGenerator { private readonly Dictionary _pool = new Dictionary(); @@ -78,9 +78,9 @@ public GeneratorBuilder SetEmptyChecker(Predicate emptyChecker) return this; } - public RandomElementGenerator Build() + public RandomCellGenerator Build() { - return new RandomElementGenerator + return new RandomCellGenerator { _emptyChecker = _emptyChecker }; diff --git a/ConsoleOut/Program.cs b/ConsoleOut/Program.cs index 3d103fa..c2ea35a 100644 --- a/ConsoleOut/Program.cs +++ b/ConsoleOut/Program.cs @@ -10,7 +10,7 @@ public static class Program public static void Main(string[] args) { var board = new Board(4, 4, () => 0); - var elementGenerator = RandomElementGenerator.Builder() + var elementGenerator = RandomCellGenerator.Builder() .SetEmptyChecker(element => element == 0) .Build(); elementGenerator.AddToPool(2, 95); diff --git a/Core_2048.csproj b/Core_2048.csproj index 998d2a8..638cf3a 100644 --- a/Core_2048.csproj +++ b/Core_2048.csproj @@ -41,8 +41,8 @@ - - + + From 6005608c98fbfaaaf8e9379ecf4fa28e9dbe2b41 Mon Sep 17 00:00:00 2001 From: Shyrokyi Vladislav Date: Sun, 11 Jul 2021 21:27:38 +0300 Subject: [PATCH 06/13] [REFACTORING] Remove UpdateLoop builder --- C#/BoardBehavior.cs | 28 ++++++---- C#/UpdateLoop.cs | 126 +++++++------------------------------------- 2 files changed, 38 insertions(+), 116 deletions(-) diff --git a/C#/BoardBehavior.cs b/C#/BoardBehavior.cs index bbaa7bb..06f8e97 100644 --- a/C#/BoardBehavior.cs +++ b/C#/BoardBehavior.cs @@ -54,16 +54,24 @@ public void Update(bool isAlongRow, bool isIncreasing) var innerStart = isIncreasing ? 0 : innerCount - 1; var innerEnd = isIncreasing ? innerCount - 1 : 0; - return UpdateLoop.Builder() - .SetDrop(DropFactory(isIncreasing)) - .SetReverseDrop(DropFactory(!isIncreasing)) - .SetGetter(GetterFactory(isAlongRow)) - .SetMerge(Merge) - .SetPredictor(Predictor) - .SetBaseValue(BaseValue) - .SetOuterCount(outerCount) - .SetInnerCondition(innerStart, innerEnd) - .Build(); + return new UpdateLoop( + BaseValue, + DropFactory(isIncreasing), + GetterFactory(isAlongRow), + innerEnd, + innerStart, + index => + { + var minIndex = Math.Min(innerStart, innerEnd); + var maxIndex = Math.Max(innerStart, innerEnd); + + return minIndex <= index && index <= maxIndex; + }, + Merge, + outerCount, + Predictor, + DropFactory(!isIncreasing) + ); } public UpdateLoop.Drop DropFactory(bool isIncreasing) diff --git a/C#/UpdateLoop.cs b/C#/UpdateLoop.cs index 1b96f9d..0d2a452 100644 --- a/C#/UpdateLoop.cs +++ b/C#/UpdateLoop.cs @@ -31,6 +31,26 @@ public class UpdateLoop : IEnumerable.ChangeElementAction> private Predictor _predictor; private Drop _reverseDrop; + public UpdateLoop(T baseValue, Drop drop, Get get, int innerEnd, int innerStart, + IsInnerCondition isInnerCondition, Merge merge, int outerCount, Predictor predictor, Drop reverseDrop) + { + if (baseValue == null) + { + throw new ArgumentNullException(nameof(baseValue)); + } + + _baseValue = baseValue; + _drop = drop ?? throw new ArgumentNullException(nameof(drop)); + _get = get ?? throw new ArgumentNullException(nameof(get)); + _innerEnd = innerEnd; + _innerStart = innerStart; + _isInnerCondition = isInnerCondition ?? throw new ArgumentNullException(nameof(isInnerCondition)); + _merge = merge ?? throw new ArgumentNullException(nameof(merge)); + _outerCount = outerCount; + _predictor = predictor ?? throw new ArgumentNullException(nameof(predictor)); + _reverseDrop = reverseDrop ?? throw new ArgumentNullException(nameof(reverseDrop)); + } + public IEnumerator GetEnumerator() { for (var outerItem = 0; outerItem < _outerCount; outerItem++) @@ -115,112 +135,6 @@ public class ChangeElementAction public Cell Next; public Cell Previous; } - - #region Builder - - public static UpdateLoopBuilder Builder() - { - return new UpdateLoopBuilder(); - } - - public class UpdateLoopBuilder - { - private T _baseValue; - private Drop _drop; - private Get _get; - private int _innerEnd; - private int _innerStart; - private IsInnerCondition _isInnerCondition; - private Merge _merge; - - private int _outerCount; - - private Predictor _predictor; - private Drop _reverseDrop; - - public UpdateLoopBuilder SetDrop(Drop drop) - { - _drop = drop; - - return this; - } - - public UpdateLoopBuilder SetReverseDrop(Drop reverseDrop) - { - _reverseDrop = reverseDrop; - - return this; - } - - public UpdateLoopBuilder SetMerge(Merge merge) - { - _merge = merge; - - return this; - } - - public UpdateLoopBuilder SetGetter(Get get) - { - _get = get; - - return this; - } - - public UpdateLoopBuilder SetPredictor(Predictor predictor) - { - _predictor = predictor; - - return this; - } - - public UpdateLoopBuilder SetOuterCount(int outerCount) - { - _outerCount = outerCount; - - return this; - } - - public UpdateLoopBuilder SetInnerCondition(int innerStart, int innerEnd) - { - _isInnerCondition = index => - { - var minIndex = Math.Min(innerStart, innerEnd); - var maxIndex = Math.Max(innerStart, innerEnd); - - return minIndex <= index && index <= maxIndex; - }; - _innerStart = innerStart; - _innerEnd = innerEnd; - - return this; - } - - public UpdateLoopBuilder SetBaseValue(T baseValue) - { - _baseValue = baseValue; - - return this; - } - - public UpdateLoop Build() - { - return new UpdateLoop - { - _drop = _drop, - _reverseDrop = _reverseDrop, - _merge = _merge, - _get = _get, - _outerCount = _outerCount, - _isInnerCondition = _isInnerCondition, - _innerStart = _innerStart, - _innerEnd = _innerEnd, - _predictor = _predictor, - _baseValue = _baseValue - }; - } - } - - #endregion } } From 28bb8558c43defb6d5092e6e62901e9a68feeda2 Mon Sep 17 00:00:00 2001 From: Shyrokyi Vladislav Date: Sun, 11 Jul 2021 21:46:39 +0300 Subject: [PATCH 07/13] [REFACTORING] Remove BoardBehavior builder --- C#/BoardBehavior.cs | 72 +++++-------------------------------------- ConsoleOut/Program.cs | 14 ++++----- 2 files changed, 14 insertions(+), 72 deletions(-) diff --git a/C#/BoardBehavior.cs b/C#/BoardBehavior.cs index 06f8e97..d391ebf 100644 --- a/C#/BoardBehavior.cs +++ b/C#/BoardBehavior.cs @@ -8,9 +8,15 @@ public class BoardBehavior { public Action, Cell>> Updated; - public BoardBehavior(Board board) + public BoardBehavior(Board board, UpdateLoop.Merge merge, UpdateLoop.Predictor predictor, T baseValue, + ICellGenerator cellGenerator, Action, Cell>> updated = null) { + Updated = updated; Board = board; + Merge = merge; + Predictor = predictor; + BaseValue = baseValue; + CellGenerator = cellGenerator; } public Board Board { get; set; } @@ -97,70 +103,6 @@ public UpdateLoop.Get GetterFactory(bool isAlongRow) Value = Board.Get(innerItem, outerItem) }; } - - #region Builder - - public static CoreBuilder Builder() - { - return new CoreBuilder(); - } - - public class CoreBuilder - { - private Board _board; - private UpdateLoop.Merge _merge; - private UpdateLoop.Predictor _predictor; - private T _baseValue; - private ICellGenerator _cellGenerator; - - public CoreBuilder SetBoard(Board board) - { - _board = board; - - return this; - } - - public CoreBuilder SetMerge(UpdateLoop.Merge merge) - { - _merge = merge; - - return this; - } - - public CoreBuilder SetPredictor(UpdateLoop.Predictor predictor) - { - _predictor = predictor; - - return this; - } - - public CoreBuilder SetBaseValue(T baseValue) - { - _baseValue = baseValue; - - return this; - } - - public CoreBuilder SetElementGenerator(ICellGenerator cellGenerator) - { - _cellGenerator = cellGenerator; - - return this; - } - - public BoardBehavior Build() - { - return new BoardBehavior(_board) - { - Merge = _merge, - Predictor = _predictor, - BaseValue = _baseValue, - CellGenerator = _cellGenerator - }; - } - } - - #endregion } } diff --git a/ConsoleOut/Program.cs b/ConsoleOut/Program.cs index c2ea35a..f02894d 100644 --- a/ConsoleOut/Program.cs +++ b/ConsoleOut/Program.cs @@ -15,13 +15,13 @@ public static void Main(string[] args) .Build(); elementGenerator.AddToPool(2, 95); elementGenerator.AddToPool(4, 5); - var app = BoardBehavior.Builder() - .SetBoard(board) - .SetBaseValue(0) - .SetMerge((value, oldValue) => value + oldValue) - .SetPredictor((current, target) => current == target) - .SetElementGenerator(elementGenerator) - .Build(); + var app = new BoardBehavior( + board, + (value, oldValue) => value + oldValue, + (current, target) => current == target, + 0, + elementGenerator + ); app.AddNew(); app.Updated += elements => { From 8e47639e984baebcc5db1a1734224a0dc25c12d9 Mon Sep 17 00:00:00 2001 From: Shyrokyi Vladislav Date: Sun, 11 Jul 2021 22:17:17 +0300 Subject: [PATCH 08/13] [REFACTORING] Change merge, predicate delegates, and base value properties to ICellBehavior interface --- C#/BoardBehavior.cs | 20 ++++++++------------ C#/ICellBehavior.cs | 12 ++++++++++++ C#/UpdateLoop.cs | 34 +++++++++++----------------------- ConsoleOut/Program.cs | 38 +++++++++++++++++++++++++++++++------- Core_2048.csproj | 1 + 5 files changed, 63 insertions(+), 42 deletions(-) create mode 100644 C#/ICellBehavior.cs diff --git a/C#/BoardBehavior.cs b/C#/BoardBehavior.cs index d391ebf..4ec3af2 100644 --- a/C#/BoardBehavior.cs +++ b/C#/BoardBehavior.cs @@ -8,21 +8,19 @@ public class BoardBehavior { public Action, Cell>> Updated; - public BoardBehavior(Board board, UpdateLoop.Merge merge, UpdateLoop.Predictor predictor, T baseValue, - ICellGenerator cellGenerator, Action, Cell>> updated = null) + private ICellBehavior _cellBehavior; + + public BoardBehavior(Board board, + ICellGenerator cellGenerator, + ICellBehavior cellBehavior, Action, Cell>> updated = null) { Updated = updated; Board = board; - Merge = merge; - Predictor = predictor; - BaseValue = baseValue; CellGenerator = cellGenerator; + _cellBehavior = cellBehavior; } public Board Board { get; set; } - public UpdateLoop.Merge Merge { get; set; } - public UpdateLoop.Predictor Predictor { get; set; } - public T BaseValue { get; set; } public ICellGenerator CellGenerator { get; set; } public void AddNew() @@ -44,7 +42,7 @@ public void Update(bool isAlongRow, bool isIncreasing) { var prev = changeElementAction.Previous; var next = changeElementAction.Next; - Board.Set(prev.Row, prev.Column, BaseValue) + Board.Set(prev.Row, prev.Column, _cellBehavior.GetCellBaseValue()) .Set(next); updateMap.Add(prev, next); } @@ -61,7 +59,7 @@ public void Update(bool isAlongRow, bool isIncreasing) var innerEnd = isIncreasing ? innerCount - 1 : 0; return new UpdateLoop( - BaseValue, + _cellBehavior, DropFactory(isIncreasing), GetterFactory(isAlongRow), innerEnd, @@ -73,9 +71,7 @@ public void Update(bool isAlongRow, bool isIncreasing) return minIndex <= index && index <= maxIndex; }, - Merge, outerCount, - Predictor, DropFactory(!isIncreasing) ); } diff --git a/C#/ICellBehavior.cs b/C#/ICellBehavior.cs new file mode 100644 index 0000000..87fbc15 --- /dev/null +++ b/C#/ICellBehavior.cs @@ -0,0 +1,12 @@ +namespace Core_2048 +{ + + public interface ICellBehavior + { + bool IsBaseCell(Cell cell); + bool IsMergeCells(Cell previous, Cell next); + T MergeCells(Cell previous, Cell next); + T GetCellBaseValue(); + } + +} diff --git a/C#/UpdateLoop.cs b/C#/UpdateLoop.cs index 0d2a452..8e25f4b 100644 --- a/C#/UpdateLoop.cs +++ b/C#/UpdateLoop.cs @@ -13,41 +13,29 @@ public class UpdateLoop : IEnumerable.ChangeElementAction> public delegate bool IsInnerCondition(int index); - public delegate T Merge(T newValue, T oldValue); - - public delegate bool Predictor(T current, T target); - - private T _baseValue; + private ICellBehavior _cellBehavior; private Drop _drop; private Get _get; private int _innerEnd; private int _innerStart; private IsInnerCondition _isInnerCondition; - private Merge _merge; private int _outerCount; - private Predictor _predictor; private Drop _reverseDrop; - public UpdateLoop(T baseValue, Drop drop, Get get, int innerEnd, int innerStart, - IsInnerCondition isInnerCondition, Merge merge, int outerCount, Predictor predictor, Drop reverseDrop) + public UpdateLoop(ICellBehavior cellBehavior, Drop drop, Get get, int innerEnd, int innerStart, + IsInnerCondition isInnerCondition, + int outerCount, Drop reverseDrop) { - if (baseValue == null) - { - throw new ArgumentNullException(nameof(baseValue)); - } - - _baseValue = baseValue; + _cellBehavior = cellBehavior ?? throw new ArgumentNullException(nameof(cellBehavior)); _drop = drop ?? throw new ArgumentNullException(nameof(drop)); _get = get ?? throw new ArgumentNullException(nameof(get)); _innerEnd = innerEnd; _innerStart = innerStart; _isInnerCondition = isInnerCondition ?? throw new ArgumentNullException(nameof(isInnerCondition)); - _merge = merge ?? throw new ArgumentNullException(nameof(merge)); _outerCount = outerCount; - _predictor = predictor ?? throw new ArgumentNullException(nameof(predictor)); _reverseDrop = reverseDrop ?? throw new ArgumentNullException(nameof(reverseDrop)); } @@ -57,15 +45,15 @@ public IEnumerator GetEnumerator() { for (var innerItem = _innerStart; _isInnerCondition(innerItem); innerItem = _reverseDrop(innerItem)) { - if (Equals(_get(outerItem, innerItem).Value, _baseValue)) + if (_cellBehavior.IsBaseCell(_get(outerItem, innerItem))) { continue; } var newInnerItem = CalculateNewItem(innerItem, outerItem); - var isMerge = _isInnerCondition(newInnerItem) && _predictor( - _get(outerItem, newInnerItem).Value, - _get(outerItem, innerItem).Value + var isMerge = _isInnerCondition(newInnerItem) && _cellBehavior.IsMergeCells( + _get(outerItem, newInnerItem), + _get(outerItem, innerItem) ); yield return isMerge @@ -89,7 +77,7 @@ private ChangeElementAction ExecuteWithMerge(int outerItem, int innerItem, int n { Row = newElement.Row, Column = newElement.Column, - Value = _merge(newElement.Value, previous.Value) + Value = _cellBehavior.MergeCells(previous, newElement) }; return new ChangeElementAction @@ -125,7 +113,7 @@ private int CalculateNewItem(int innerItem, int outerItem) do { newInnerItem = _drop(newInnerItem); - } while (_isInnerCondition(newInnerItem) && Equals(_get(outerItem, newInnerItem).Value, _baseValue)); + } while (_isInnerCondition(newInnerItem) && _cellBehavior.IsBaseCell(_get(outerItem, newInnerItem))); return newInnerItem; } diff --git a/ConsoleOut/Program.cs b/ConsoleOut/Program.cs index f02894d..c93f112 100644 --- a/ConsoleOut/Program.cs +++ b/ConsoleOut/Program.cs @@ -15,13 +15,7 @@ public static void Main(string[] args) .Build(); elementGenerator.AddToPool(2, 95); elementGenerator.AddToPool(4, 5); - var app = new BoardBehavior( - board, - (value, oldValue) => value + oldValue, - (current, target) => current == target, - 0, - elementGenerator - ); + var app = new BoardBehavior(board, elementGenerator, new BaseCellBehavior()); app.AddNew(); app.Updated += elements => { @@ -84,6 +78,36 @@ private static void Render(BoardBehavior app) } } + internal class BaseCellBehavior : ICellBehavior + { + private readonly ulong _baseValue; + + public BaseCellBehavior(ulong baseValue = 0) + { + _baseValue = baseValue; + } + + public bool IsBaseCell(Cell cell) + { + return cell.Value == _baseValue; + } + + public bool IsMergeCells(Cell previous, Cell next) + { + return previous.Value == next.Value; + } + + public ulong MergeCells(Cell previous, Cell next) + { + return previous.Value + next.Value; + } + + public ulong GetCellBaseValue() + { + return _baseValue; + } + } + internal enum Direction { Up, diff --git a/Core_2048.csproj b/Core_2048.csproj index 638cf3a..8f952c2 100644 --- a/Core_2048.csproj +++ b/Core_2048.csproj @@ -41,6 +41,7 @@ + From 33d1aacbca1f334d006e56fea5b300d6d5855866 Mon Sep 17 00:00:00 2001 From: Shyrokyi Vladislav Date: Sun, 11 Jul 2021 22:28:03 +0300 Subject: [PATCH 09/13] [FIX] Encapsulated fields in BoardBehavior --- C#/BoardBehavior.cs | 43 +++++++++++++++++++++++++------------------ ConsoleOut/Program.cs | 12 ++++++------ 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/C#/BoardBehavior.cs b/C#/BoardBehavior.cs index 4ec3af2..a46981e 100644 --- a/C#/BoardBehavior.cs +++ b/C#/BoardBehavior.cs @@ -6,32 +6,39 @@ namespace Core_2048 public class BoardBehavior { - public Action, Cell>> Updated; + private readonly Board _board; + private readonly ICellBehavior _cellBehavior; + private readonly ICellGenerator _cellGenerator; - private ICellBehavior _cellBehavior; + private Action, Cell>> _updated; - public BoardBehavior(Board board, - ICellGenerator cellGenerator, - ICellBehavior cellBehavior, Action, Cell>> updated = null) + public BoardBehavior(Board board, ICellGenerator cellGenerator, ICellBehavior cellBehavior, Action, Cell>> updated = null) { - Updated = updated; - Board = board; - CellGenerator = cellGenerator; + _updated = updated; + _board = board; + _cellGenerator = cellGenerator; _cellBehavior = cellBehavior; } - public Board Board { get; set; } - public ICellGenerator CellGenerator { get; set; } + public void AddUpdatedListener(Action, Cell>> action) + { + _updated += action; + } + + public void RemoveUpdatedListener(Action, Cell>> action) + { + _updated -= action; + } public void AddNew() { - var element = CellGenerator.GetNewElement(Board); + var element = _cellGenerator.GetNewElement(_board); if (element == null) { return; } - Board.Set(element); + _board.Set(element); } public void Update(bool isAlongRow, bool isIncreasing) @@ -42,18 +49,18 @@ public void Update(bool isAlongRow, bool isIncreasing) { var prev = changeElementAction.Previous; var next = changeElementAction.Next; - Board.Set(prev.Row, prev.Column, _cellBehavior.GetCellBaseValue()) + _board.Set(prev.Row, prev.Column, _cellBehavior.GetCellBaseValue()) .Set(next); updateMap.Add(prev, next); } - Updated?.Invoke(updateMap); + _updated?.Invoke(updateMap); } public IEnumerable.ChangeElementAction> CalculateChanges(bool isAlongRow, bool isIncreasing) { - var outerCount = isAlongRow ? Board.Height : Board.Width; - var innerCount = isIncreasing ? Board.Width : Board.Height; + var outerCount = isAlongRow ? _board.Height : _board.Width; + var innerCount = isIncreasing ? _board.Width : _board.Height; var innerStart = isIncreasing ? 0 : innerCount - 1; var innerEnd = isIncreasing ? innerCount - 1 : 0; @@ -90,13 +97,13 @@ public UpdateLoop.Get GetterFactory(bool isAlongRow) { Row = outerItem, Column = innerItem, - Value = Board.Get(outerItem, innerItem) + Value = _board.Get(outerItem, innerItem) }) : (outerItem, innerItem) => new Cell { Row = innerItem, Column = outerItem, - Value = Board.Get(innerItem, outerItem) + Value = _board.Get(innerItem, outerItem) }; } } diff --git a/ConsoleOut/Program.cs b/ConsoleOut/Program.cs index c93f112..6a5a4ee 100644 --- a/ConsoleOut/Program.cs +++ b/ConsoleOut/Program.cs @@ -17,12 +17,12 @@ public static void Main(string[] args) elementGenerator.AddToPool(4, 5); var app = new BoardBehavior(board, elementGenerator, new BaseCellBehavior()); app.AddNew(); - app.Updated += elements => + app.AddUpdatedListener(elements => { app.AddNew(); - Render(app); - }; - Render(app); + Render(board); + }); + Render(board); while (true) { var direction = Input(); @@ -37,12 +37,12 @@ public static void Main(string[] args) } } - private static void Render(BoardBehavior app) + private static void Render(Board board) { Console.Clear(); var prevRow = -1; var pattern = new Func(value => $" {value} |"); - app.Board.ForEach((value, row, column) => + board.ForEach((value, row, column) => { var cell = pattern(value); if (prevRow == row) From 20d04aa604f97585324c375db4b805d1bff93070 Mon Sep 17 00:00:00 2001 From: Shyrokyi Vladislav Date: Sun, 11 Jul 2021 22:39:56 +0300 Subject: [PATCH 10/13] [FIX] Encapsulating UpdateLoop class - moved into BoardBehavior --- C#/BoardBehavior.cs | 23 ++++-- C#/UpdateLoop.cs | 179 ++++++++++++++++++++++---------------------- 2 files changed, 103 insertions(+), 99 deletions(-) diff --git a/C#/BoardBehavior.cs b/C#/BoardBehavior.cs index a46981e..4e89427 100644 --- a/C#/BoardBehavior.cs +++ b/C#/BoardBehavior.cs @@ -4,7 +4,7 @@ namespace Core_2048 { - public class BoardBehavior + public partial class BoardBehavior { private readonly Board _board; private readonly ICellBehavior _cellBehavior; @@ -12,7 +12,8 @@ public class BoardBehavior private Action, Cell>> _updated; - public BoardBehavior(Board board, ICellGenerator cellGenerator, ICellBehavior cellBehavior, Action, Cell>> updated = null) + public BoardBehavior(Board board, ICellGenerator cellGenerator, ICellBehavior cellBehavior, + Action, Cell>> updated = null) { _updated = updated; _board = board; @@ -57,7 +58,7 @@ public void Update(bool isAlongRow, bool isIncreasing) _updated?.Invoke(updateMap); } - public IEnumerable.ChangeElementAction> CalculateChanges(bool isAlongRow, bool isIncreasing) + public IEnumerable CalculateChanges(bool isAlongRow, bool isIncreasing) { var outerCount = isAlongRow ? _board.Height : _board.Width; var innerCount = isIncreasing ? _board.Width : _board.Height; @@ -65,7 +66,7 @@ public void Update(bool isAlongRow, bool isIncreasing) var innerStart = isIncreasing ? 0 : innerCount - 1; var innerEnd = isIncreasing ? innerCount - 1 : 0; - return new UpdateLoop( + return new UpdateLoop( _cellBehavior, DropFactory(isIncreasing), GetterFactory(isAlongRow), @@ -83,17 +84,17 @@ public void Update(bool isAlongRow, bool isIncreasing) ); } - public UpdateLoop.Drop DropFactory(bool isIncreasing) + private UpdateLoop.Drop DropFactory(bool isIncreasing) { return isIncreasing - ? new UpdateLoop.Drop(innerIndex => innerIndex - 1) + ? new UpdateLoop.Drop(innerIndex => innerIndex - 1) : innerIndex => innerIndex + 1; } - public UpdateLoop.Get GetterFactory(bool isAlongRow) + private UpdateLoop.Get GetterFactory(bool isAlongRow) { return isAlongRow - ? new UpdateLoop.Get((outerItem, innerItem) => new Cell + ? new UpdateLoop.Get((outerItem, innerItem) => new Cell { Row = outerItem, Column = innerItem, @@ -106,6 +107,12 @@ public UpdateLoop.Get GetterFactory(bool isAlongRow) Value = _board.Get(innerItem, outerItem) }; } + + public class ChangeElementAction + { + public Cell Next; + public Cell Previous; + } } } diff --git a/C#/UpdateLoop.cs b/C#/UpdateLoop.cs index 8e25f4b..45e22ed 100644 --- a/C#/UpdateLoop.cs +++ b/C#/UpdateLoop.cs @@ -5,123 +5,120 @@ namespace Core_2048 { - public class UpdateLoop : IEnumerable.ChangeElementAction> + public partial class BoardBehavior { - public delegate int Drop(int index); + private class UpdateLoop : IEnumerable + { + public delegate int Drop(int index); - public delegate Cell Get(int outerItem, int innerItem); + public delegate Cell Get(int outerItem, int innerItem); - public delegate bool IsInnerCondition(int index); + public delegate bool IsInnerCondition(int index); - private ICellBehavior _cellBehavior; + private ICellBehavior _cellBehavior; - private Drop _drop; - private Get _get; - private int _innerEnd; - private int _innerStart; - private IsInnerCondition _isInnerCondition; + private Drop _drop; + private Get _get; + private int _innerEnd; + private int _innerStart; + private IsInnerCondition _isInnerCondition; - private int _outerCount; + private int _outerCount; - private Drop _reverseDrop; + private Drop _reverseDrop; - public UpdateLoop(ICellBehavior cellBehavior, Drop drop, Get get, int innerEnd, int innerStart, - IsInnerCondition isInnerCondition, - int outerCount, Drop reverseDrop) - { - _cellBehavior = cellBehavior ?? throw new ArgumentNullException(nameof(cellBehavior)); - _drop = drop ?? throw new ArgumentNullException(nameof(drop)); - _get = get ?? throw new ArgumentNullException(nameof(get)); - _innerEnd = innerEnd; - _innerStart = innerStart; - _isInnerCondition = isInnerCondition ?? throw new ArgumentNullException(nameof(isInnerCondition)); - _outerCount = outerCount; - _reverseDrop = reverseDrop ?? throw new ArgumentNullException(nameof(reverseDrop)); - } + public UpdateLoop(ICellBehavior cellBehavior, Drop drop, Get get, int innerEnd, int innerStart, + IsInnerCondition isInnerCondition, + int outerCount, Drop reverseDrop) + { + _cellBehavior = cellBehavior ?? throw new ArgumentNullException(nameof(cellBehavior)); + _drop = drop ?? throw new ArgumentNullException(nameof(drop)); + _get = get ?? throw new ArgumentNullException(nameof(get)); + _innerEnd = innerEnd; + _innerStart = innerStart; + _isInnerCondition = isInnerCondition ?? throw new ArgumentNullException(nameof(isInnerCondition)); + _outerCount = outerCount; + _reverseDrop = reverseDrop ?? throw new ArgumentNullException(nameof(reverseDrop)); + } - public IEnumerator GetEnumerator() - { - for (var outerItem = 0; outerItem < _outerCount; outerItem++) + public IEnumerator GetEnumerator() { - for (var innerItem = _innerStart; _isInnerCondition(innerItem); innerItem = _reverseDrop(innerItem)) + for (var outerItem = 0; outerItem < _outerCount; outerItem++) { - if (_cellBehavior.IsBaseCell(_get(outerItem, innerItem))) + for (var innerItem = _innerStart; _isInnerCondition(innerItem); innerItem = _reverseDrop(innerItem)) { - continue; + if (_cellBehavior.IsBaseCell(_get(outerItem, innerItem))) + { + continue; + } + + var newInnerItem = CalculateNewItem(innerItem, outerItem); + var isMerge = _isInnerCondition(newInnerItem) && _cellBehavior.IsMergeCells( + _get(outerItem, newInnerItem), + _get(outerItem, innerItem) + ); + + yield return isMerge + ? ExecuteWithMerge(outerItem, innerItem, newInnerItem) + : ExecuteWithoutMerge(outerItem, innerItem, newInnerItem); } - - var newInnerItem = CalculateNewItem(innerItem, outerItem); - var isMerge = _isInnerCondition(newInnerItem) && _cellBehavior.IsMergeCells( - _get(outerItem, newInnerItem), - _get(outerItem, innerItem) - ); - - yield return isMerge - ? ExecuteWithMerge(outerItem, innerItem, newInnerItem) - : ExecuteWithoutMerge(outerItem, innerItem, newInnerItem); } } - } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - private ChangeElementAction ExecuteWithMerge(int outerItem, int innerItem, int newInnerItem) - { - var previous = _get(outerItem, innerItem); - var newElement = _get(outerItem, newInnerItem); - - var next = new Cell + IEnumerator IEnumerable.GetEnumerator() { - Row = newElement.Row, - Column = newElement.Column, - Value = _cellBehavior.MergeCells(previous, newElement) - }; + return GetEnumerator(); + } - return new ChangeElementAction + private ChangeElementAction ExecuteWithMerge(int outerItem, int innerItem, int newInnerItem) { - Previous = previous, - Next = next - }; - } + var previous = _get(outerItem, innerItem); + var newElement = _get(outerItem, newInnerItem); - private ChangeElementAction ExecuteWithoutMerge(int outerItem, int innerItem, int newInnerItem) - { - newInnerItem = _reverseDrop(newInnerItem); - var previous = _get(outerItem, innerItem); - var newElement = _get(outerItem, newInnerItem); + var next = new Cell + { + Row = newElement.Row, + Column = newElement.Column, + Value = _cellBehavior.MergeCells(previous, newElement) + }; - var next = new Cell() - { - Row = newElement.Row, - Column = newElement.Column, - Value = previous.Value - }; + return new ChangeElementAction + { + Previous = previous, + Next = next + }; + } - return new ChangeElementAction + private ChangeElementAction ExecuteWithoutMerge(int outerItem, int innerItem, int newInnerItem) { - Previous = previous, - Next = next - }; - } + newInnerItem = _reverseDrop(newInnerItem); + var previous = _get(outerItem, innerItem); + var newElement = _get(outerItem, newInnerItem); - private int CalculateNewItem(int innerItem, int outerItem) - { - var newInnerItem = innerItem; - do - { - newInnerItem = _drop(newInnerItem); - } while (_isInnerCondition(newInnerItem) && _cellBehavior.IsBaseCell(_get(outerItem, newInnerItem))); + var next = new Cell() + { + Row = newElement.Row, + Column = newElement.Column, + Value = previous.Value + }; - return newInnerItem; - } + return new ChangeElementAction + { + Previous = previous, + Next = next + }; + } - public class ChangeElementAction - { - public Cell Next; - public Cell Previous; + private int CalculateNewItem(int innerItem, int outerItem) + { + var newInnerItem = innerItem; + do + { + newInnerItem = _drop(newInnerItem); + } while (_isInnerCondition(newInnerItem) && _cellBehavior.IsBaseCell(_get(outerItem, newInnerItem))); + + return newInnerItem; + } } } From d6cc0e0e12fd9973fa5640becc59305bddb879a3 Mon Sep 17 00:00:00 2001 From: Shyrokyi Vladislav Date: Sun, 11 Jul 2021 23:12:18 +0300 Subject: [PATCH 11/13] [REFACTORING] Moved iterating logic into UpdateLoop --- C#/BoardBehavior.cs | 47 +---------------------- C#/UpdateLoop.cs | 90 +++++++++++++++++++++++++-------------------- 2 files changed, 52 insertions(+), 85 deletions(-) diff --git a/C#/BoardBehavior.cs b/C#/BoardBehavior.cs index 4e89427..3ea8e80 100644 --- a/C#/BoardBehavior.cs +++ b/C#/BoardBehavior.cs @@ -60,52 +60,7 @@ public void Update(bool isAlongRow, bool isIncreasing) public IEnumerable CalculateChanges(bool isAlongRow, bool isIncreasing) { - var outerCount = isAlongRow ? _board.Height : _board.Width; - var innerCount = isIncreasing ? _board.Width : _board.Height; - - var innerStart = isIncreasing ? 0 : innerCount - 1; - var innerEnd = isIncreasing ? innerCount - 1 : 0; - - return new UpdateLoop( - _cellBehavior, - DropFactory(isIncreasing), - GetterFactory(isAlongRow), - innerEnd, - innerStart, - index => - { - var minIndex = Math.Min(innerStart, innerEnd); - var maxIndex = Math.Max(innerStart, innerEnd); - - return minIndex <= index && index <= maxIndex; - }, - outerCount, - DropFactory(!isIncreasing) - ); - } - - private UpdateLoop.Drop DropFactory(bool isIncreasing) - { - return isIncreasing - ? new UpdateLoop.Drop(innerIndex => innerIndex - 1) - : innerIndex => innerIndex + 1; - } - - private UpdateLoop.Get GetterFactory(bool isAlongRow) - { - return isAlongRow - ? new UpdateLoop.Get((outerItem, innerItem) => new Cell - { - Row = outerItem, - Column = innerItem, - Value = _board.Get(outerItem, innerItem) - }) - : (outerItem, innerItem) => new Cell - { - Row = innerItem, - Column = outerItem, - Value = _board.Get(innerItem, outerItem) - }; + return new UpdateLoop(_cellBehavior, _board, isAlongRow, isIncreasing); } public class ChangeElementAction diff --git a/C#/UpdateLoop.cs b/C#/UpdateLoop.cs index 45e22ed..34e7d67 100644 --- a/C#/UpdateLoop.cs +++ b/C#/UpdateLoop.cs @@ -9,53 +9,40 @@ public partial class BoardBehavior { private class UpdateLoop : IEnumerable { - public delegate int Drop(int index); + private readonly ICellBehavior _cellBehavior; + private readonly Board _board; + private readonly bool _isIncreasing; + private readonly bool _isAlongRow; - public delegate Cell Get(int outerItem, int innerItem); + private int OuterCount => _isAlongRow ? _board.Height : _board.Width; + private int InnerCount => _isIncreasing ? _board.Width : _board.Height; - public delegate bool IsInnerCondition(int index); + private int InnerStart => _isIncreasing ? 0 : InnerCount - 1; + private int InnerEnd => _isIncreasing ? InnerCount - 1 : 0; - private ICellBehavior _cellBehavior; - - private Drop _drop; - private Get _get; - private int _innerEnd; - private int _innerStart; - private IsInnerCondition _isInnerCondition; - - private int _outerCount; - - private Drop _reverseDrop; - - public UpdateLoop(ICellBehavior cellBehavior, Drop drop, Get get, int innerEnd, int innerStart, - IsInnerCondition isInnerCondition, - int outerCount, Drop reverseDrop) + public UpdateLoop(ICellBehavior cellBehavior, Board board, bool isAlongRow, bool isIncreasing) { _cellBehavior = cellBehavior ?? throw new ArgumentNullException(nameof(cellBehavior)); - _drop = drop ?? throw new ArgumentNullException(nameof(drop)); - _get = get ?? throw new ArgumentNullException(nameof(get)); - _innerEnd = innerEnd; - _innerStart = innerStart; - _isInnerCondition = isInnerCondition ?? throw new ArgumentNullException(nameof(isInnerCondition)); - _outerCount = outerCount; - _reverseDrop = reverseDrop ?? throw new ArgumentNullException(nameof(reverseDrop)); + _board = board ?? throw new ArgumentNullException(nameof(board)); + _isAlongRow = isAlongRow; + _isIncreasing = isIncreasing; } public IEnumerator GetEnumerator() { - for (var outerItem = 0; outerItem < _outerCount; outerItem++) + for (var outerItem = 0; outerItem < OuterCount; outerItem++) { - for (var innerItem = _innerStart; _isInnerCondition(innerItem); innerItem = _reverseDrop(innerItem)) + for (var innerItem = InnerStart; IsInnerCondition(innerItem); innerItem = ReverseDrop(innerItem)) { - if (_cellBehavior.IsBaseCell(_get(outerItem, innerItem))) + if (_cellBehavior.IsBaseCell(Get(outerItem, innerItem))) { continue; } var newInnerItem = CalculateNewItem(innerItem, outerItem); - var isMerge = _isInnerCondition(newInnerItem) && _cellBehavior.IsMergeCells( - _get(outerItem, newInnerItem), - _get(outerItem, innerItem) + var isMerge = IsInnerCondition(newInnerItem) && _cellBehavior.IsMergeCells( + Get(outerItem, newInnerItem), + Get(outerItem, innerItem) ); yield return isMerge @@ -72,8 +59,8 @@ IEnumerator IEnumerable.GetEnumerator() private ChangeElementAction ExecuteWithMerge(int outerItem, int innerItem, int newInnerItem) { - var previous = _get(outerItem, innerItem); - var newElement = _get(outerItem, newInnerItem); + var previous = Get(outerItem, innerItem); + var newElement = Get(outerItem, newInnerItem); var next = new Cell { @@ -91,11 +78,11 @@ private ChangeElementAction ExecuteWithMerge(int outerItem, int innerItem, int n private ChangeElementAction ExecuteWithoutMerge(int outerItem, int innerItem, int newInnerItem) { - newInnerItem = _reverseDrop(newInnerItem); - var previous = _get(outerItem, innerItem); - var newElement = _get(outerItem, newInnerItem); + newInnerItem = ReverseDrop(newInnerItem); + var previous = Get(outerItem, innerItem); + var newElement = Get(outerItem, newInnerItem); - var next = new Cell() + var next = new Cell { Row = newElement.Row, Column = newElement.Column, @@ -114,11 +101,36 @@ private int CalculateNewItem(int innerItem, int outerItem) var newInnerItem = innerItem; do { - newInnerItem = _drop(newInnerItem); - } while (_isInnerCondition(newInnerItem) && _cellBehavior.IsBaseCell(_get(outerItem, newInnerItem))); + newInnerItem = Drop(newInnerItem); + } while (IsInnerCondition(newInnerItem) && _cellBehavior.IsBaseCell(Get(outerItem, newInnerItem))); return newInnerItem; } + + private Cell Get(int outerItem, int innerItem) + { + return _isAlongRow + ? new Cell { Row = outerItem, Column = innerItem, Value = _board.Get(outerItem, innerItem) } + : new Cell { Row = innerItem, Column = outerItem, Value = _board.Get(innerItem, outerItem) }; + } + + private int Drop(int innerIndex) + { + return _isIncreasing ? innerIndex - 1 : innerIndex + 1; + } + + private int ReverseDrop(int innerIndex) + { + return !_isIncreasing ? innerIndex - 1 : innerIndex + 1; + } + + private bool IsInnerCondition(int index) + { + var minIndex = Math.Min(InnerStart, InnerEnd); + var maxIndex = Math.Max(InnerStart, InnerEnd); + + return minIndex <= index && index <= maxIndex; + } } } From a0f836658efb98b67d9b5da5f576b4c778259ffd Mon Sep 17 00:00:00 2001 From: Shyrokyi Vladislav Date: Tue, 13 Jul 2021 23:01:42 +0300 Subject: [PATCH 12/13] [REFACTORING] Remove builder on RandomCellGenerator --- C#/RandomCellGenerator.cs | 38 +++++++------------------------------- ConsoleOut/Program.cs | 4 +--- 2 files changed, 8 insertions(+), 34 deletions(-) diff --git a/C#/RandomCellGenerator.cs b/C#/RandomCellGenerator.cs index d581ea5..4319143 100644 --- a/C#/RandomCellGenerator.cs +++ b/C#/RandomCellGenerator.cs @@ -8,10 +8,15 @@ namespace Core_2048 public class RandomCellGenerator : ICellGenerator { private readonly Dictionary _pool = new Dictionary(); - private readonly Random _random = new Random(); + private readonly Predicate _emptyChecker; + private int _allPercentage; - private Predicate _emptyChecker; + + public RandomCellGenerator(Predicate emptyChecker) + { + _emptyChecker = emptyChecker; + } public Cell GetNewElement(Board board) { @@ -59,35 +64,6 @@ public void AddToPool(T value) var percentage = _pool.Count != 0 ? _allPercentage / _pool.Count : 1; AddToPool(value, percentage); } - - #region Builder - - public static GeneratorBuilder Builder() - { - return new GeneratorBuilder(); - } - - public class GeneratorBuilder - { - private Predicate _emptyChecker; - - public GeneratorBuilder SetEmptyChecker(Predicate emptyChecker) - { - _emptyChecker = emptyChecker; - - return this; - } - - public RandomCellGenerator Build() - { - return new RandomCellGenerator - { - _emptyChecker = _emptyChecker - }; - } - } - - #endregion } } diff --git a/ConsoleOut/Program.cs b/ConsoleOut/Program.cs index 6a5a4ee..246f3e4 100644 --- a/ConsoleOut/Program.cs +++ b/ConsoleOut/Program.cs @@ -10,9 +10,7 @@ public static class Program public static void Main(string[] args) { var board = new Board(4, 4, () => 0); - var elementGenerator = RandomCellGenerator.Builder() - .SetEmptyChecker(element => element == 0) - .Build(); + var elementGenerator = new RandomCellGenerator(element => element == 0); elementGenerator.AddToPool(2, 95); elementGenerator.AddToPool(4, 5); var app = new BoardBehavior(board, elementGenerator, new BaseCellBehavior()); From 2dfb730e8493b089e9208ed9e201abdc25fe6037 Mon Sep 17 00:00:00 2001 From: Shyrokyi Vladislav Date: Wed, 14 Jul 2021 22:20:34 +0300 Subject: [PATCH 13/13] [UPDATED] File README.md --- README.md | 59 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b31d014..6057a7e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -2048 +2048 [![Nuget](https://img.shields.io/nuget/v/Core_2048)](https://www.nuget.org/packages/Core_2048) ==== My take mini sdk libs for creating the 2048 game in C#. Suitable for any engine from console app to Unity game. Only @@ -6,34 +6,59 @@ My take mini sdk libs for creating the 2048 game in C#. Suitable for any engine * canvas size * base value, which means blank cells -* configuring merging elements value -* configuring predicate elements value +* configuring merging cells value +* configuring predicate cells value * customizable amount of value for new cells with customizable chance of creation for each individual case -* generic for the element value (Convenient for use in game engines) +* generic for the cells value (Convenient for use in game engines) ## Easy to implements in your game: -1. Create a game board with height, width and initialized value -2. Create a generator of random elements, set the check to an empty element and add a list of elements to the pool to generate with a specified percentage probability (Or you can create your own generator by implementing ***IElementGenerator***) -3. Create ***Core*** with **board**, **baseValue**, **merge** delegate, **predictor**, **element generator** -4. Call ***AddNew*** for generating and add new element on board -4. In the game loop, call the ***Update*** with arguments: - * ***isAlongRow*** - true when movement **left** and **right** if render from up to down; - * ***isIncreasing*** - true when movement **left** and **up** (if board render from **up** to **down**) or **down** (if board render from **down** to **up**); -5. Add listeners on ***Updated*** action to see if cells moved after ant action. -6. Call ***AddNew*** method when need add new value at board. -7. Create Render method in your engine. In Core class has methods for base iteration and there is updating map with movement info for easier implementation of interaction with external object. +1. Create a game `Board` by your generic type with **height**, **width** and **initialized function**. +2. Create a generator of random cells `RandomCellGenerator`, set the check to an empty cell and add a list of cells to the pool to generate with a specified percentage probability (Or you can create your own generator by implementing `IElementGenerator`). +3. Create an implementation of the `ICellBehavior` interface to define base cells and behavior for merging cells. +4. Create `BoardBehavior` with `Board`, class implementing `ICellBehavior`, and `CellGenerator`. +5. Call `AddNew` for generating and add new element on board. +6. In the game loop, call the `Update` with arguments: + * `isAlongRow` - true when movement **left** and **right** if render from up to down; + * `isIncreasing` - true when movement **left** and **up** (if board render from **up** to **down**) or **down** (if board render from **down** to **up**); +7. Add listeners on `Updated` action to see if cells moved after ant action. +8. Call `AddNew` method when need add new value at board. +9. Create `Render` method in your engine. In Core class has methods for base iteration and there is updating map with movement info for easier implementation of interaction with external object. Sample console project in ConsoleOut directory. ### Example code: +```csharp +var board = new Board(4, 4, () => 0); +var elementGenerator = new RandomCellGenerator(element => element == 0); +elementGenerator.AddToPool(2, 95); +elementGenerator.AddToPool(4, 5); +var app = new BoardBehavior(board, elementGenerator, new BaseCellBehavior()); +app.AddNew(); +app.AddUpdatedListener(elements => +{ + app.AddNew(); + Render(board); +}); +Render(board); +while (true) +{ + var direction = Input(); + if (direction == null) + { + continue; + } -![screenshot](doc/2048_console_app_code.png "Source code for a console app") + var isAlongRow = direction == Direction.Left || direction == Direction.Right; + var isIncreasing = direction == Direction.Left || direction == Direction.Up; + app.Update(isAlongRow, isIncreasing); +} +``` ### Here's how it looks like: -![screenshot](doc/ConsoleOut.png "Console app for 2048") +![screenshot](https://raw.githubusercontent.com/VladShyrokyi/2048-1/master/doc/ConsoleOut.png "Console app for 2048") ### Also implementation in Unity: -![screenshot](doc/GameInUnity.gif "Unity app for 2048") +![screenshot](https://raw.githubusercontent.com/VladShyrokyi/2048-1/master/doc/GameInUnity.gif "Unity app for 2048")