| | 1 | | using System.Collections.Generic; |
| | 2 | | using System.Linq; |
| | 3 | | using LanguageExt; |
| | 4 | | using static FpMineSweeper.Prelude; |
| | 5 | |
|
| | 6 | | namespace FpMineSweeper |
| | 7 | | { |
| 20 | 8 | | public record MineField(int Width, int Height, IEnumerable<Cell> Cells) |
| 5 | 9 | | { |
| 5 | 10 | | protected IEnumerable<(int X, int Y)> NearCellGenerator((int X, int Y) pos) |
| 12 | 11 | | { |
| 5 | 12 | | IEnumerable<(int X, int Y)> NearCellsInner() |
| 12 | 13 | | { |
| 12 | 14 | | yield return (pos.X - 1, pos.Y - 1); |
| 12 | 15 | | yield return (pos.X, pos.Y - 1); |
| 12 | 16 | | yield return (pos.X + 1, pos.Y - 1); |
| 12 | 17 | | yield return (pos.X - 1, pos.Y); |
| 12 | 18 | | yield return (pos.X + 1, pos.Y); |
| 12 | 19 | | yield return (pos.X - 1, pos.Y + 1); |
| 12 | 20 | | yield return (pos.X, pos.Y + 1); |
| 12 | 21 | | yield return (pos.X + 1, pos.Y + 1); |
| 12 | 22 | | } |
| 5 | 23 | |
|
| 61 | 24 | | bool CheckBoundary((int X, int Y) pos) => pos switch |
| 61 | 25 | | { |
| 142 | 26 | | (var x, var y) when x < 0 || y < 0 || x >= Width || y >= Height => false, |
| 92 | 27 | | _ => true |
| 61 | 28 | | }; |
| 5 | 29 | |
|
| 12 | 30 | | return NearCellsInner().Where(CheckBoundary); |
| 12 | 31 | | } |
| 5 | 32 | | } |
| | 33 | |
|
| | 34 | | public record MineFieldInit : MineField |
| | 35 | | { |
| | 36 | | public MineFieldInit(int width, int height) |
| | 37 | | : base(width, height, Enumerable.Empty<Cell>()) |
| | 38 | | { |
| | 39 | | } |
| | 40 | |
|
| | 41 | | public MineFieldReady SetBombs(IEnumerable<(int X, int Y)> bombPosGenerator) => |
| | 42 | | new(this with |
| | 43 | | { |
| | 44 | | Cells = from y in Enumerable.Range(0, Height) |
| | 45 | | from x in Enumerable.Range(0, Width) |
| | 46 | | select (x, y) into pos |
| | 47 | | join bombPos in from bombPosInner in bombPosGenerator |
| | 48 | | select new { Pos = bombPosInner } |
| | 49 | | on pos equals bombPos.Pos into bombPosGroup |
| | 50 | | from bombPosGroupItem in bombPosGroup.DefaultIfEmpty(null) |
| | 51 | | join nearBombCount in from bombPosInner in bombPosGenerator |
| | 52 | | from nearBombPos in NearCellGenerator(bombPosInner) |
| | 53 | | group nearBombPos by nearBombPos into nearBombPosGroup |
| | 54 | | select new |
| | 55 | | { |
| | 56 | | Pos = nearBombPosGroup.Key, |
| | 57 | | Count = nearBombPosGroup.Count() |
| | 58 | | } |
| | 59 | | on pos equals nearBombCount.Pos into nearBombCountGroup |
| | 60 | | from nearBombCountGroupItem in nearBombCountGroup.DefaultIfEmpty() |
| | 61 | | select cell(pos, |
| | 62 | | bombPosGroupItem is not null, |
| | 63 | | nearBombCountGroupItem.Count) |
| | 64 | | }); |
| | 65 | | } |
| | 66 | |
|
| | 67 | | public record MineFieldReady : MineField |
| | 68 | | { |
| | 69 | | public MineFieldReady(MineFieldInit mineFieldInit) : |
| | 70 | | base(mineFieldInit.Width, mineFieldInit.Height, mineFieldInit.Cells) |
| | 71 | | { |
| | 72 | | } |
| | 73 | | } |
| | 74 | | } |