Advent of code

 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.
  1. code_part_1_2.py
  2. code_part1_simple_affichageConsole.py
  3. code_part2_affichageConsole.py
  4. diff_adaptationAlgo_2_PourPartie_1.diffy
  5. diff_optimPushingHorizontally.diffy
  6. affichage_console_partie1.png
  7. affichage_console_partie2.png
  8. 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] == '[' )  )