#Python, 1761
Kind of burnt out on this question, so couldn't bring myself to golf it. Either way, right now it's the only solution that solves everything within the time limit (longest, #3, takes 27 seconds).
pieces = {}
taken = set()
goals = set()
y = 0
while True:
try:
for x, c in enumerate(input()):
if c == ".": continue
if c == "g":
goals.add((x, y))
else:
if c in "0123456789":
if c not in pieces: pieces[c] = set()
pieces[c].add((x, y))
taken.add((x, y))
y += 1
except: break
def translate_comp(coords):
o = min(sorted(coords))
return set((c[0] - o[0], c[1] - o[1]) for c in coords)
similar = {}
for piece in pieces:
k = tuple(translate_comp(pieces[piece]))
if k not in similar: similar[k] = []
similar[k].append(piece)
seen = set()
states = [(pieces, taken, ())]
while states:
state = states.pop(0)
if not goals - state[0]["0"]:
names = {
(-1, 0): "L",
(1, 0): "R",
(0, 1): "D",
(0, -1): "U",
}
print(len(state[2]))
print(" ".join(piece + names[d] for d, piece in state[2]))
break
for piece in pieces:
for d in ((-1, 0), (1, 0), (0, 1), (0, -1)):
new_pieces = state[0].copy()
new_pieces[piece] = {(c[0] + d[0], c[1] + d[1]) for c in state[0][piece]}
new_taken = state[1] - state[0][piece]
# Collision
if new_pieces[piece] & new_taken:
continue
gist = tuple(frozenset().union(*(new_pieces[piece] for piece in similar_set))
for similar_set in similar.values())
if gist in seen:
continue
seen.add(gist)
new_taken |= new_pieces[piece]
states.append((new_pieces, new_taken, state[2] + ((d, piece),)))