Minigolf Solitaire

Golf is a form of patience (solitaire) in which you must remove cards from several tableaus, leaving as few as possible. Today, though, we're doing a round of Minigolf instead. Unlike Golf, there are 5 stacks, the cards only go up to 7, and there is no draw pile.

Here is the deal:

To begin, remove any exposed card. After that, remove exposed cards with a value one higher or one lower than the previous card, until you can't remove any more cards.

Note that 'A' is considered to be adjacent to both '7' and '2'.

Try to remove every card and get a hole in one!

Whilst I tried to split things logically into blocks (e.g. working forwards to a point, then working backwards from the end to see what else was left, and thus needed to be used first), this was mostly done by trial and error, so there's not really any "steps" to show beyond the final "hole in one" solution:

Or in animated form for intuitive verification:

• What dedication! Jan 28, 2020 at 7:33

I found a different answer by writing a python program to brute force find the solution using a depth first search(go as deep as possible until you can't make any more moves and then backtrack). I have't created an animation like they did to show the solution but I will show the output of the program and how to interpret it so that you can verify the solution.

Program output: (True, [3, 3, 1, 3, 1, 0, 4, 0, 4, 4, 2, 0, 2, 1, 1, 3, 2, 2, 0, 2, 3, 4, 0, 1, 4])

The list of numbers represents the index of the stack to pull off at each step. Note that it's 0 indexed, so 0 means pull off the leftmost stack. 2, for example, means pull off the third from the left stack.

Source Code

def duplicate_stacks(stacks):
return [stack[:] for stack in stacks]

def solve(stacks, last_played=None, past_moves=[]):
if all(len(stack)==0 for stack in stacks):
return True, past_moves

allowed_numbers = []
if not last_played:
allowed_numbers = [1,2,3,4,5,6,7]
else:
allowed_numbers.append(last_played % 7 + 1)
allowed_numbers.append((last_played-1) or 7)

allowed_moves = []
for i, stack in enumerate(stacks):
if len(stack) > 0 and stack[0] in allowed_numbers:
allowed_moves.append(i)

for move in allowed_moves:
new_stacks = duplicate_stacks(stacks)
last_played = new_stacks[move].pop(0)
solved, moves = solve(new_stacks, last_played, past_moves + [move])
if solved:
return solved, moves

return False, past_moves

question_stacks = [
[5,5,3,2,6],
[2,4,1,7,7],
[4,2,7,1,3],
[2,3,3,1,4],
[4,6,5,5,1]
]

print(solve(question_stacks))

• The code shouldn't be considered a spoiler right? Jan 28, 2020 at 17:27
• I don't think you need a spoiler tag for the code, it's a fairly standard algorithm, and it's no help unless you actually run it. Incidentally, I used a DFS to produce this puzzle as well. Jan 28, 2020 at 17:53
• @Woofmao How did you do that to guarantee something with a unique solution? Jan 28, 2020 at 17:56
• The solution isn't unique - your solution and @Alconja differ in the 5th move. I just generated random solvable deals until I found one reasonably difficult to solve by hand. Jan 28, 2020 at 18:39
• @Woofmao Ah interesting. I didn't actually notice that they differed, I didn't look that closely. Just noticed that the first few moves were the same, so it was likely the same Jan 28, 2020 at 18:43