Task: Solve triangle solitare puzzle





Java: import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

public class IQPuzzle {

    public static void main(String[] args) {
        System.out.printf("  ");
        for ( int start = 1 ; start < Puzzle.MAX_PEGS ; start++ ) {
            System.out.printf("  %,6d", start);
        }
        System.out.printf("%n");
        for ( int start = 1 ; start < Puzzle.MAX_PEGS ; start++ ) {
            System.out.printf("%2d", start);
            Map<Integer,Integer> solutions = solve(start);    
            for ( int end = 1 ; end < Puzzle.MAX_PEGS ; end++ ) {
                System.out.printf("  %,6d", solutions.containsKey(end) ? solutions.get(end) : 0);
            }
            System.out.printf("%n");
        }
        int moveNum = 0;
        System.out.printf("%nOne Solution:%n");
        for ( Move m : oneSolution ) {
            moveNum++;
            System.out.printf("Move %d = %s%n", moveNum, m);
        }
    }
    
    private static List<Move> oneSolution = null;
    
    private static Map<Integer, Integer> solve(int emptyPeg) {
        Puzzle puzzle = new Puzzle(emptyPeg);
        Map<Integer,Integer> solutions = new HashMap<>();
        Stack<Puzzle> stack = new Stack<Puzzle>();
        stack.push(puzzle);
        while ( ! stack.isEmpty() ) {
            Puzzle p = stack.pop();
            if ( p.solved() ) {
                solutions.merge(p.getLastPeg(), 1, (v1,v2) -> v1 + v2);
                if ( oneSolution == null ) {
                    oneSolution = p.moves;
                }
                continue;
            }
            for ( Move move : p.getValidMoves() ) {
                Puzzle pMove = p.move(move);
                stack.add(pMove);
            }
        }
        
        return solutions;
    }
    
    private static class Puzzle {
        
        public static int MAX_PEGS = 16;
        private boolean[] pegs = new boolean[MAX_PEGS];  
        
        private List<Move> moves;

        public Puzzle(int emptyPeg) {
            for ( int i = 1 ; i < MAX_PEGS ; i++ ) {
                pegs[i] = true;
            }
            pegs[emptyPeg] = false;
            moves = new ArrayList<>();
        }

        public Puzzle() {
            for ( int i = 1 ; i < MAX_PEGS ; i++ ) {
                pegs[i] = true;
            }
            moves = new ArrayList<>();
        }

        private static Map<Integer,List<Move>> validMoves = new HashMap<>(); 
        static {
            validMoves.put(1, Arrays.asList(new Move(1, 2, 4), new Move(1, 3, 6)));
            validMoves.put(2, Arrays.asList(new Move(2, 4, 7), new Move(2, 5, 9)));
            validMoves.put(3, Arrays.asList(new Move(3, 5, 8), new Move(3, 6, 10)));
            validMoves.put(4, Arrays.asList(new Move(4, 2, 1), new Move(4, 5, 6), new Move(4, 8, 13), new Move(4, 7, 11)));
            validMoves.put(5, Arrays.asList(new Move(5, 8, 12), new Move(5, 9, 14)));
            validMoves.put(6, Arrays.asList(new Move(6, 3, 1), new Move(6, 5, 4), new Move(6, 9, 13), new Move(6, 10, 15)));
            validMoves.put(7, Arrays.asList(new Move(7, 4, 2), new Move(7, 8, 9)));
            validMoves.put(8, Arrays.asList(new Move(8, 5, 3), new Move(8, 9, 10)));
            validMoves.put(9, Arrays.asList(new Move(9, 5, 2), new Move(9, 8, 7)));
            validMoves.put(10, Arrays.asList(new Move(10, 6, 3), new Move(10, 9, 8)));
            validMoves.put(11, Arrays.asList(new Move(11, 7, 4), new Move(11, 12, 13)));
            validMoves.put(12, Arrays.asList(new Move(12, 8, 5), new Move(12, 13, 14)));
            validMoves.put(13, Arrays.asList(new Move(13, 12, 11), new Move(13, 8, 4), new Move(13, 9, 6), new Move(13, 14, 15)));
            validMoves.put(14, Arrays.asList(new Move(14, 13, 12), new Move(14, 9, 5)));
            validMoves.put(15, Arrays.asList(new Move(15, 14, 13), new Move(15, 10, 6)));
        }
        
        public List<Move> getValidMoves() {
            List<Move> moves = new ArrayList<Move>();
            for ( int i = 1 ; i < MAX_PEGS ; i++ ) {
                if ( pegs[i] ) {
                    for ( Move testMove : validMoves.get(i) ) {
                        if ( pegs[testMove.jump] && ! pegs[testMove.end] ) {
                            moves.add(testMove);
                        }
                    }
                }
            }
            return moves;
        }

        public boolean solved() {
            boolean foundFirstPeg = false;
            for ( int i = 1 ; i < MAX_PEGS ; i++ ) {
                if ( pegs[i] ) {
                    if ( foundFirstPeg ) {
                        return false;
                    }
                    foundFirstPeg = true;
                }
            }
            return true;
        }
        
        public Puzzle move(Move move) {
            Puzzle p = new Puzzle();
            if ( ! pegs[move.start] || ! pegs[move.jump] || pegs[move.end] ) {
                throw new RuntimeException("Invalid move.");
            }
            for ( int i = 1 ; i < MAX_PEGS ; i++ ) {
                p.pegs[i] = pegs[i];
            }
            p.pegs[move.start] = false;
            p.pegs[move.jump] = false;
            p.pegs[move.end] = true;
            for ( Move m : moves ) {
                p.moves.add(new Move(m.start, m.jump, m.end));
            }
            p.moves.add(new Move(move.start, move.jump, move.end));
            return p;
        }
        
        public int getLastPeg() {
            for ( int i = 1 ; i < MAX_PEGS ; i++ ) {
                if ( pegs[i] ) {
                    return i;
                }
            }
            throw new RuntimeException("ERROR:  Illegal position.");
        }
        
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("[");
            for ( int i = 1 ; i < MAX_PEGS ; i++ ) {
                sb.append(pegs[i] ? 1 : 0);
                sb.append(",");
            }
            sb.setLength(sb.length()-1);            
            sb.append("]");
            return sb.toString();
        }
    }
    
    private static class Move {
        int start;
        int jump;
        int end;
        
        public Move(int s, int j, int e) {
            start = s; jump = j; end = e;
        }
        
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("{");
            sb.append("s=" + start);
            sb.append(", j=" + jump);
            sb.append(", e=" + end);
            sb.append("}");
            return sb.toString();
        }
    }

}




VB: Imports System, Microsoft.VisualBasic.DateAndTime

Public Module Module1
    Const n As Integer = 5 
    Dim Board As String 
    Dim Starting As Integer = 1 
    Dim Target As Integer = 13 
    Dim Moves As Integer() 
    Dim bi() As Integer 
    Dim ib() As Integer 
    Dim nl As Char = Convert.ToChar(10) 

    
    Public Function Dou(s As String) As String
        Dou = "" : Dim b As Boolean = True
        For Each ch As Char In s
            If b Then b = ch <> " "
            If b Then Dou &= ch & " " Else Dou = " " & Dou
        Next : Dou = Dou.TrimEnd()
    End Function

    
    Public Function Fmt(s As String) As String
        If s.Length < Board.Length Then Return s
        Fmt = "" : For i As Integer = 1 To n : Fmt &= Dou(s.Substring(i * n - n, n)) &
                If(i = n, s.Substring(Board.Length), "") & nl
        Next
    End Function

    
    Public Function Triangle(n As Integer) As Integer
        Return (n * (n + 1)) / 2
    End Function

    
    Public Function Init(s As String, pos As Integer) As String
        Init = s : Mid(Init, pos, 1) = "0"
    End Function

    
    Public Sub InitIndex()
        ReDim bi(Triangle(n)), ib(n * n) : Dim j As Integer = 0
        For i As Integer = 0 To ib.Length - 1
            If i = 0 Then
                ib(i) = 0 : bi(j) = 0 : j += 1
            Else
                If Board(i - 1) = "1" Then ib(i) = j : bi(j) = i : j += 1
            End If
        Next
    End Sub

    
    Public Function solve(brd As String, pegsLeft As Integer) As String
        If pegsLeft = 1 Then 
            If Target = 0 Then Return "Completed" 
            If brd(bi(Target) - 1) = "1" Then Return "Completed" Else Return "fail"
        End If
        For i = 1 To Board.Length 
            If brd(i - 1) = "1" Then 
                For Each mj In Moves 
                    Dim over As Integer = i + mj 
                    Dim land As Integer = i + 2 * mj 
                    
                    If land >= 1 AndAlso land <= brd.Length _
                                AndAlso brd(land - 1) = "0" _
                                AndAlso brd(over - 1) = "1" Then
                        setPegs(brd, "001", i, over, land) 
                        
                        Dim Res As String = solve(brd.Substring(0, Board.Length), pegsLeft - 1)
                        
                        If Res.Length <> 4 Then _
                            Return brd & info(i, over, land) & nl & Res
                        setPegs(brd, "110", i, over, land) 
                    End If
                Next
            End If
        Next
        Return "fail"
    End Function

    
    Function info(frm As Integer, over As Integer, dest As Integer) As String
        Return "  Peg from " & ib(frm).ToString() & " goes to " & ib(dest).ToString() &
            ", removing peg at " & ib(over).ToString()
    End Function

    
    Sub setPegs(ByRef board As String, pat As String, a As Integer, b As Integer, c As Integer)
        Mid(board, a, 1) = pat(0) : Mid(board, b, 1) = pat(1) : Mid(board, c, 1) = pat(2)
    End Sub

    
    Sub LimitIt(ByRef x As Integer, lo As Integer, hi As Integer)
        x = Math.Max(Math.Min(x, hi), lo)
    End Sub

    Public Sub Main()
        Dim t As Integer = Triangle(n) 
        LimitIt(Starting, 1, t) 
        LimitIt(Target, 0, t)
        Dim stime As Date = Now() 
        Moves = {-n - 1, -n, -1, 1, n, n + 1} 
        Board = New String("1", n * n) 
        For i As Integer = 0 To n - 2 
            Mid(Board, i * (n + 1) + 2, n - 1 - i) = New String(" ", n - 1 - i)
        Next
        InitIndex() 
        Dim B As String = Init(Board, bi(Starting)) 
        Console.WriteLine(Fmt(B & "  Starting with peg removed from " & Starting.ToString()))
        Dim res As String() = solve(B.Substring(0, B.Length), t - 1).Split(nl)
        Dim ts As String = (Now() - stime).TotalMilliseconds.ToString() & " ms."
        If res(0).Length = 4 Then
            If Target = 0 Then
                Console.WriteLine("Unable to find a solution with last peg left anywhere.")
            Else
                Console.WriteLine("Unable to find a solution with last peg left at " &
                                  Target.ToString() & ".")
            End If
            Console.WriteLine("Computation time: " & ts)
        Else
            For Each Sol As String In res : Console.WriteLine(Fmt(Sol)) : Next
            Console.WriteLine("Computation time to first found solution: " & ts)
        End If
        If Diagnostics.Debugger.IsAttached Then Console.ReadLine()
    End Sub
End Module