public List<Attempt> solve() {
        ArrayList<Attempt> successes = new ArrayList<Attempt>();
        if (isMetGoal()) {
            successes.add(this);
        } else if (isGoodAttempt()) {
            int moveIndex = -1;
            for (int i = 0; i < moves.length; i++) {
                if (null == moves[i]) {
                    moveIndex = i;
                    break;
                }
            }
            if (moveIndex >= 0) {
                System.out.println("recursing: " + this);
                ArrayList<Attempt> subAttempts = new ArrayList<Attempt>();
                Piece piece = pieces[moveIndex];
                for (int sumsIndex = 0; sumsIndex < piece.getSums().length; sumsIndex++) {
                    int[] sums = piece.getSums(sumsIndex);
                    int maxPosition = goal.length - sums.length;
                    for (int position = 0; position <= maxPosition; position++) {
                        int[] subGoal = Arrays.copyOf(goal, goal.length);
                        for (int i = 0; i < sums.length; i++) {
                            subGoal[i + position] -= sums[i];
                        }
                        Move newMove = new Move(sumsIndex, position);
                        subAttempts.add(makeSubAttempt(moveIndex, newMove, subGoal));
                    }
                }
                subAttempts.add(makeSubAttempt(moveIndex, Move.EMPTY, goal));
                for (Attempt subAttempt : subAttempts) {
                    successes.addAll(subAttempt.solve());
                }
            }
        }
        return successes;
    }