< Summary

Information
Class: BallSort.Engine.Solver
Assembly: BallSort.Engine
File(s): /home/runner/work/BallSort/BallSort/src/BallSort.Engine/Solver.cs
Tag: 238
Line coverage
100%
Covered lines: 47
Uncovered lines: 0
Coverable lines: 47
Total lines: 125
Line coverage: 100%
Branch coverage
100%
Covered branches: 24
Total branches: 24
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
Solve()100%22100%
Explore()100%1010100%
PostProcessMoves(...)100%22100%
RemoveBounces(...)100%1010100%

File(s)

/home/runner/work/BallSort/BallSort/src/BallSort.Engine/Solver.cs

#LineLine coverage
 1using BallSort.Engine.Game;
 2using BallSort.Engine.Logic;
 3using BallSort.Engine.Models;
 4
 5namespace BallSort.Engine;
 6
 7public class Solver
 8{
 9    private readonly Board _board;
 10
 11    private readonly MoveGenerator _moveGenerator;
 12
 13    private readonly BoardHasher _boardHasher;
 14
 2615    private readonly Stack<Move> _moves = [];
 16
 2617    private readonly HashSet<ulong[]> _visited = new(new BoardHashEqualityComparer());
 18
 19    private int[] _lastTouched;
 20
 2621    public Solver(Board board)
 22    {
 2623        _board = board;
 24
 2625        _moveGenerator = new MoveGenerator(_board);
 26
 2627        _boardHasher = new BoardHasher(_board);
 2628    }
 29
 30    public (bool Solved, List<Move> Moves) Solve()
 31    {
 2632        _moves.Clear();
 33
 2634        _visited.Clear();
 35
 2636        _visited.Add(_boardHasher.GetHash());
 37
 2638        if (Explore())
 39        {
 2440            var moveList = _moves.Reverse().ToList();
 41
 2442            PostProcessMoves(moveList);
 43
 2444            return (true, moveList);
 45        }
 46
 247        return (false, null);
 48    }
 49
 50    private bool Explore()
 51    {
 623252        var lastMove = _moves.Count > 0 ? _moves.Peek() : Move.NullMove;
 53
 623254        var moves = _moveGenerator.GetMoves(lastMove);
 55
 3171656        foreach (var move in moves)
 57        {
 1047858            _board.Move(move);
 59
 1047860            if (_board.IsSolved())
 61            {
 2462                _moves.Push(move);
 63
 2464                return true;
 65            }
 66
 1045467            var hash = _boardHasher.GetHash();
 68
 1045469            if (_visited.Add(hash))
 70            {
 620671                _moves.Push(move);
 72
 620673                if (Explore())
 74                {
 168075                    return true;
 76                }
 77
 452678                _moves.Pop();
 79            }
 80
 877481            _board.UndoLastMove();
 82        }
 83
 452884        return false;
 170485    }
 86
 87    private void PostProcessMoves(List<Move> moves)
 88    {
 2489        _lastTouched = new int[_board.Width];
 90
 18691        while (RemoveBounces(moves)) { }
 2492    }
 93
 94    private bool RemoveBounces(List<Move> moves)
 95    {
 18696        Array.Fill(_lastTouched, -1);
 97
 1668098        for (var index = 0; index < moves.Count; index++)
 99        {
 8316100            var move = moves[index];
 101
 8316102            var previousIndex = _lastTouched[move.Source];
 103
 8316104            if (previousIndex >= 0 && previousIndex == _lastTouched[move.Target])
 105            {
 2666106                var previous = moves[previousIndex];
 107
 2666108                if (previous.Source == move.Target && previous.Target == move.Source)
 109                {
 162110                    moves.RemoveAt(index);
 111
 162112                    moves.RemoveAt(previousIndex);
 113
 162114                    return true;
 115                }
 116            }
 117
 8154118            _lastTouched[move.Source] = index;
 119
 8154120            _lastTouched[move.Target] = index;
 121        }
 122
 24123        return false;
 124    }
 125}