| | 1 | | using BallSort.Engine.Game; |
| | 2 | | using BallSort.Engine.Models; |
| | 3 | |
|
| | 4 | | namespace BallSort.Engine.Logic; |
| | 5 | |
|
| | 6 | | public class MoveGenerator |
| | 7 | | { |
| | 8 | | private readonly Board _board; |
| | 9 | |
|
| | 10 | | private int _moveId; |
| | 11 | |
|
| 6 | 12 | | public MoveGenerator(Board board) |
| | 13 | | { |
| 6 | 14 | | _board = board; |
| 6 | 15 | | } |
| | 16 | |
|
| | 17 | | public List<Move> GetMoves(Move lastMove) |
| | 18 | | { |
| 368 | 19 | | var moves = new List<Move>(); |
| | 20 | |
|
| 7608 | 21 | | for (var x = 0; x < _board.Width; x++) |
| | 22 | | { |
| 3436 | 23 | | var ball = _board.Top(x); |
| | 24 | |
|
| 3436 | 25 | | if (ball == Colour.Empty) |
| | 26 | | { |
| | 27 | | continue; |
| | 28 | | } |
| | 29 | |
|
| 3312 | 30 | | if (_board.IsComplete(x)) |
| | 31 | | { |
| | 32 | | continue; |
| | 33 | | } |
| | 34 | |
|
| 2164 | 35 | | var newMoves = GetMoves(ball, x); |
| | 36 | |
|
| 7444 | 37 | | foreach (var move in newMoves) |
| | 38 | | { |
| 1558 | 39 | | if (! (move.Source == lastMove.Target && move.Target != lastMove.Source)) |
| | 40 | | { |
| 1494 | 41 | | moves.Add(move); |
| | 42 | | } |
| | 43 | | } |
| | 44 | | } |
| | 45 | |
|
| 368 | 46 | | return moves; |
| | 47 | | } |
| | 48 | |
|
| | 49 | | private List<Move> GetMoves(Colour ball, int source) |
| | 50 | | { |
| 2164 | 51 | | var moves = new List<Move>(); |
| | 52 | |
|
| 2164 | 53 | | var move = CheckForCompletion(ball, source); |
| | 54 | |
|
| 2164 | 55 | | if (move != Move.NullMove) |
| | 56 | | { |
| 262 | 57 | | moves.Add(move); |
| | 58 | | } |
| | 59 | |
|
| 2164 | 60 | | moves.AddRange(CheckForMerges(ball, source)); |
| | 61 | |
|
| 2164 | 62 | | if (_board.BallCount(source) != 1) |
| | 63 | | { |
| 1886 | 64 | | move = CheckForEmpty(source); |
| | 65 | | } |
| | 66 | |
|
| 2164 | 67 | | if (move != Move.NullMove) |
| | 68 | | { |
| 544 | 69 | | moves.Add(move); |
| | 70 | | } |
| | 71 | |
|
| 2164 | 72 | | return moves; |
| | 73 | | } |
| | 74 | |
|
| | 75 | | private Move CheckForCompletion(Colour ball, int source) |
| | 76 | | { |
| 42060 | 77 | | for (var x = 0; x < _board.Width; x++) |
| | 78 | | { |
| 19128 | 79 | | if (x == source) |
| | 80 | | { |
| | 81 | | continue; |
| | 82 | | } |
| | 83 | |
|
| 17084 | 84 | | if (_board.Top(x) == ball && _board.Capacity(x) == 1) |
| | 85 | | { |
| 262 | 86 | | return new Move(source, x, ++_moveId); |
| | 87 | | } |
| | 88 | | } |
| | 89 | |
|
| 1902 | 90 | | return Move.NullMove; |
| | 91 | | } |
| | 92 | |
|
| | 93 | | private Move CheckForEmpty(int source) |
| | 94 | | { |
| 32656 | 95 | | for (var x = 0; x < _board.Width; x++) |
| | 96 | | { |
| 14940 | 97 | | if (_board.IsEmpty(x)) |
| | 98 | | { |
| 498 | 99 | | return new Move(source, x, ++_moveId); |
| | 100 | | } |
| | 101 | | } |
| | 102 | |
|
| 1388 | 103 | | return Move.NullMove; |
| | 104 | | } |
| | 105 | |
|
| | 106 | | private List<Move> CheckForMerges(Colour ball, int source) |
| | 107 | | { |
| 2164 | 108 | | var moves = new List<Move>(); |
| | 109 | |
|
| 12984 | 110 | | for (var i = _board.Height - 2; i > 0; i--) |
| | 111 | | { |
| 89936 | 112 | | for (var x = 0; x < _board.Width; x++) |
| | 113 | | { |
| 40640 | 114 | | if (x == source || _board.IsEmpty(x) || _board.IsFull(x) || _board.Capacity(x) == 1 || _board.IsComplete |
| | 115 | | { |
| | 116 | | continue; |
| | 117 | | } |
| | 118 | |
|
| 7544 | 119 | | if (_board.Top(x) == ball && _board.TopRunLength(x) == i) |
| | 120 | | { |
| 752 | 121 | | moves.Add(new Move(source, x, ++_moveId)); |
| | 122 | | } |
| | 123 | | } |
| | 124 | | } |
| | 125 | |
|
| 2164 | 126 | | return moves; |
| | 127 | | } |
| | 128 | | } |