◂ 15 décembre 2024 ▸
Warehouse Woes : Déplacer des caisses façon sokoban, mais avec des caisses prenant deux places en largeur.
########## … ###
##.#...OO# … O.#
#O#O.....O … ..#
⋮
#..O.O.O.. … #O#
#.....O.OO … OO#
########## … ###
<v><v><> …
>^><<>vv …
⋮
Toute petite optimisation possible (qui ne fait gagner aucun temps) quand on touche une boîte horizontalement : s'occuper directement de la partie non touchée, qu'on sait être derrière.
- code_part_1_2.py
- code_part1_simple_affichageConsole.py
- code_part2_affichageConsole.py
- diff_adaptationAlgo_2_PourPartie_1.diffy
- diff_optimPushingHorizontally.diffy
- affichage_console_partie1.png
- affichage_console_partie2.png
- Visualisation superbe sur YouTube ⬀ En 3D avec images réalistes et faite par Paul Bonsma
from time import sleep
PRINT_MOVES = True
with open("input.txt", 'r', encoding='utf-8') as f:
lines = [line[:-1] for line in f.readlines()]
sep = lines.index("")
grid = [list(line) for line in lines[:sep]]
instructions = ''.join(lines[sep+1:])
for y,line in enumerate(grid):
new_line = []
for c in line:
if c in '#.':
new_line.extend(2*[c])
elif c == '@':
new_line.extend(['@','.'])
else:
new_line.extend(['[',']'])
grid[y] = new_line
DIRECTIONS = {'>':(1,0), '<':(-1,0), 'v':(0,1), '^':(0,-1)}
y = next(y for y,line in enumerate(grid) if '@' in line)
x = grid[y].index('@')
##### AFFICHAGE dans la console #####
GREEN, BLUE, RED, RED_BG, DARKG, YELLOW, ORG, ORG_BG, PURP, PURP_BG, BOLD, BLACK_BG, RESET, INVISIBLE, LIGHTG, LIGHTG_BG, CYAN_BG = [ '\033[' + s + 'm' for s in
'34 32 31 41 90 93 33 43 35 45 01 40 0 08 37 47 46'.split()]
MOVE_TOPLEFT, CLEAR, CLEAR_UP, CLEAR_MOVE = '\033[H', '\033[J', '\033[1J', '\033[2J' # CLEAR = '\033[3J' # deletes all buffer
def print_grid(grid, clear_screen = False, subtitle=None):
REPLACEMENTS = { '@': PURP_BG + PURP + chr(9664) + chr(9654) + RESET, # (9668+9658, 9686+9687)
'#': BLACK_BG + BOLD + '##' + RESET,
'.': INVISIBLE + '..' + RESET,
'[': ORG + '▐' + LIGHTG + ORG_BG + '▒░' + RESET + ORG + '▌' + RESET,
']': '',
}
if clear_screen:
text = MOVE_TOPLEFT + CLEAR
else:
text = ''
for y,line in enumerate(grid):
text += ''.join(REPLACEMENTS.get(c,c) for c in line) + '\n'
if subtitle:
text = text + subtitle + '\n'
print(text)
sleep(0.1)
print_grid(grid, True, 'starting soon…')
sleep(.7)
##### DÉBUT ALGO #####
def next_grid(grid, x, y, depl_x, depl_y):
### Find what needs to move
pushed = set()
todo = set([(x, y)])
while todo:
bx, by = todo.pop()
pushed.add( (bx,by) )
nx, ny = bx + depl_x, by + depl_y
if (nx,ny) in pushed or (nx,ny) in todo:
continue
next_c = grid[ny][nx]
if next_c == '#':
return None # Obstacle ! Nothing to do, return None to signal it.
elif next_c in '[]':
todo.add( (nx, ny) ) # Always process the touched part of the box
if not depl_y: # If pushing horizontally
todo.add( (bx+2*depl_x, by) ) # process other part
elif next_c == '[': # If pushing vertically on the left
todo.add( (bx+1,ny) ) # process the right part of the box
else: # If pushing vertically on the right
todo.add( (bx-1,ny) ) # process the left part
### And push everything!
grid_n = [line[:] for line in grid]
for bx,by in pushed:
grid_n[by][bx] = '.'
for bx,by in pushed:
grid_n[by+depl_y][bx+depl_x] = grid[by][bx]
if PRINT_MOVES:
print_grid(grid_n, True, f"{i+1}/{len(instructions)}")
return grid_n
for i,instruction in enumerate(instructions):
depl_x, depl_y = DIRECTIONS[instruction]
new_grid = next_grid(grid, x, y, depl_x, depl_y)
if new_grid:
grid = new_grid
x, y = x + depl_x, y + depl_y
if not PRINT_MOVES: # always print once at the end
print_grid(grid)
print("Réponse partie 2:", sum( 100*y + x
for y in range(len(grid))
for x in range(len(grid[0]))
if grid[y][x] == '[' ) )