Created
December 10, 2022 20:00
Advent of Code 2022 Day 5, batch file with ASCII art animation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@echo off | |
setlocal EnableDelayedExpansion | |
REM CONFIG | |
REM number of stacks supported | |
set maxstack=20 | |
REM line on which to draw the stacks | |
set baseline=23 | |
REM Offset from the left of drawing stacks | |
set lpad=5 | |
REM animation: 0=none, 1=snap, 2=fast, 3=full | |
set animation=3 | |
REM #$E# makes prompt echo the escape character, which is then captured and stored in a variable. | |
REM The escape is used for ANSI escape sequences for color an positioning | |
REM ANSI escape codes cheat sheet https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 | |
for /F "delims=#" %%a in ('prompt #$E# ^& for %%a in ^(1^) do rem') do set "esc=%%a" | |
REM #$H# makes prompt echo a backspace character, which is used twice in a string, to backspace | |
REM the . and the second space, leaving just a signle space to be echoed. | |
for /F "delims=#" %%a in ('prompt #$H# ^& for %%a in ^(1^) do rem') do set "space=.%%a %%a" | |
REM input file or defaults | |
set file=%1 | |
if "%file%"=="" set file=Day5.test.txt | |
call :simulate 9000 | |
set part1=%result% | |
echo That was the 9000 bare. Now the 9000 will simulate the 9001. Standby. | |
timeout /t 3 | |
call :simulate 9001 | |
echo. | |
echo Part 1: %part1% | |
echo Part 2: %result% | |
exit /b | |
:simulate | |
set result= | |
set CrateMoverVersion=%1 | |
set laststack=0 | |
for /l %%a in (0,1,%maxstack%) do ( | |
set stack%%a= | |
set len%%a=0 | |
) | |
REM hide caret | |
echo %esc%[?25l | |
for /f "tokens=* delims=" %%a in (%file%) do ( | |
set line=%%a | |
if "!line:~0,2!"==" 1" ( | |
call :init_stack | |
call :start | |
) else if "!line!"=="" ( | |
REM Doesn't work? This was supposed to be the empty line before the commands | |
) else if "!line:~0,4!"=="move" ( | |
call :execute "!line!" | |
) else ( | |
call :stack "!line!" | |
) | |
) | |
for /l %%a in (1,1,%laststack%) do ( | |
set /a len=!len%%a!-1 | |
set stack=stack%%a | |
call set box=%%!stack!:~!len!%% | |
set result=!result!!box! | |
) | |
REM Position below animation, and restore cursor and color | |
echo %esc%[%baseline%H%esc%[1E%esc%[?25h%esc%[0m | |
exit /b | |
:start | |
REM Before the first move | |
cls | |
call :drawcrane | |
exit /b | |
:init_stack | |
for /l %%a in (1,1,%maxstack%) do ( | |
if "!stack%%a!"=="" ( if !laststack!==0 set /a laststack=%%a-1 | |
) else echo Stack %%a = !stack%%a! with a height of !len%%a! | |
) | |
echo %laststack% stacks | |
cls | |
exit /b | |
:stack | |
set line=%~1 | |
echo !line! | |
for /l %%a in (1,1,%maxstack%) do ( | |
set /a position=%%a*4-3 | |
call set box=%%line:~!position!,1%% | |
if "!box!" neq " " ( | |
call set /a len%%a+=1 | |
call set stack%%a=!box!!stack%%a! | |
) | |
) | |
exit /b | |
:execute | |
for /f "tokens=2,4,6" %%b in ("%~1") do ( | |
set /a from=%%c-1 | |
set /a to=%%d-1 | |
if %CrateMoverVersion%==9001 ( | |
REM Simulating the 9001 using the 9000, by doing all the multi-moves | |
REM through a separate stack, reversing the sub-stacks twice | |
REM So this is actually slower, but since we're just simulating the result | |
if %%b==1 ( | |
call :single %%c %%d | |
) else ( | |
for /l %%e in (1,1,%%b) do call :single %%c 0 | |
for /l %%e in (1,1,%%b) do call :single 0 %%d | |
) | |
) else ( | |
for /l %%e in (1,1,%%b) do call :single %%c %%d | |
) | |
) | |
exit /b | |
:single | |
set /a len%1-=1 | |
call set box=%%stack%1:~!len%1!%% | |
if %animation% geq 1 call :animate %1 %2 !box! !len%1! !len%2! | |
call set stack%1=%%stack%1:~0,!len%1!%% | |
call set /a len%2+=1 | |
set stack%2=!stack%2!!box! | |
if %animation% geq 1 call :drawstacks | |
exit /b | |
:animate | |
rem from, to, box, height1 (new), height2 (old) | |
call :drawstacks | |
if %animation% lss 2 exit /b | |
set /a x=%1*4-3+%lpad% | |
set /a x2=%2*4-3+%lpad% | |
set step=1 | |
if %x% geq %x2% set step=-1 | |
set /a y=%baseline% - %4 | |
echo %esc%[!y!;!x!f%esc%[0m[%3] | |
REM How high to lift (max height of stacks between, +2) | |
set lift=0 | |
for /l %%a in (%1,%step%,%2) do ( | |
if !lift! lss !len%%a! set lift=!len%%a! | |
) | |
set /a lift=%baseline%-%lift%-2 | |
REM lower the cable | |
if %animation% geq 3 for /l %%a in (1,1,!y!) do ( | |
call :waitalittle | |
call :drawcable !x! %%a | |
) | |
REM Lift up | |
for /l %%a in (%y%,-1,%lift%) do ( | |
if %animation% geq 3 ( | |
call :waitalittle longer | |
call :drawcable !x! %%a | |
) | |
set /a p=%%a+1 | |
if %%a geq 1 echo %esc%[%%a;!x!f%esc%[0m[%3] | |
if !p! leq %y% echo %esc%[!p!;!x!f%esc%[30m%space%%space%%space% | |
) | |
REM Move over | |
for /l %%a in (%x%,%step%,%x2%) do ( | |
if %animation% geq 3 ( | |
call :waitalittle | |
call :drawcable %%a %lift% | |
) | |
if %lift% geq 1 ( | |
set /a p=%%a-%step% | |
echo %esc%[%lift%;%%af%esc%[0m[%3] | |
echo %esc%[%lift%;!p!f%esc%[30m[ ] | |
echo %esc%[%lift%;%%af%esc%[0m[%3] | |
) | |
) | |
REM Lower on to target stack | |
set /a y=%baseline% - %5 | |
for /l %%a in (%lift%,1,%y%) do ( | |
if %animation% geq 3 ( | |
call :waitalittle longer | |
call :drawcable !x2! %%a | |
) | |
set /a p=%%a-1 | |
if %%a geq 1 echo %esc%[%%a;!x2!f%esc%[0m[%3] | |
if %animation% lss 3 if !p! geq %lift% if !p! geq 1 echo %esc%[!p!;!x2!f%esc%[30m[ ] | |
) | |
REM pull up the cable | |
if %animation% geq 3 for /l %%a in (%y%,-1,1) do ( | |
call :waitalittle | |
call :drawcable !x2! %%a | |
if %%a lss %y% echo %esc%[%%a;!x2!f%esc%[0m%space%%space% | |
) | |
echo %esc%[24;1H%esc%[0m | |
exit /b | |
:drawcable | |
REM draw cable X, Length | |
set /a cy=%2-1 | |
for /l %%a in (%cy%,-1,1) do ( | |
if %%a==%cy% ( | |
echo %esc%[%%a;%1f%esc%[0m%space%A%space% | |
) else ( | |
echo %esc%[%%a;%1f%esc%[0m%space%^|%space% | |
) | |
) | |
exit /b | |
:drawcrane | |
set x=50 | |
set init=%esc%[38;5;8m%esc%[H | |
for /l %%y in (1,4,20) do ( | |
echo !init!%esc%[%x%C ^|/ \^|/ \^|/ \^| | |
echo %esc%[%x%C ^|\ /^|\ /^|\ /^| | |
echo %esc%[%x%C ^| \/ ^| \/ ^| \/ ^| | |
echo %esc%[%x%C ^| /\ ^| /\ ^| /\ ^| | |
set init= | |
) | |
echo %esc%[%x%C ^|/ \^|/ \^|/ \^| | |
echo %esc%[%x%C /^|\ /^|\ /^|\ /^|\ | |
echo %esc%[%x%C^| ^| ^|^| ^|^| ^|^| ^| | |
echo %esc%[93m%esc%[14;56HCrateMover%esc%[15;59H9000 | |
if %CrateMoverVersion%==9001 echo %esc%[93m%esc%[17;55Hrunning 9001%esc%[18;55Hcompatibility%esc%[19;59Hmode | |
exit /b | |
:drawstacks | |
setlocal | |
for /l %%s in (1,1,%laststack%) do ( | |
set /a max=!len%%s! | |
set /a x=%%s*4-3+%lpad% | |
for /l %%b in (0,1,!max!) do ( | |
set /a y=%baseline%-%%b | |
REM always end with an empty black box, to erase a previous one | |
if !y! geq 1 if %%b==!max! ( echo %esc%[!y!;!x!H%esc%[30m[!stack%%s:~%%b,1!] | |
) else echo %esc%[!y!;!x!H%esc%[0m[!stack%%s:~%%b,1!] | |
) | |
set /a y=%baseline%+2 | |
echo %esc%[!y!;!x!H%esc%[0m!len%%s!. | |
) | |
echo %esc%[0m | |
exit /b | |
:waitalittle | |
set delay=5000 | |
if "%1"=="longer" set delay=20000 | |
for /l %%b in (0,1,%delay%) do rem de nada. #todo time a bigger loop to determine a reasonable loop number, nibbles style | |
exit /b |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[D] | |
[N] [C] | |
[Z] [M] [P] | |
1 2 3 | |
move 1 from 2 to 1 | |
move 3 from 1 to 3 | |
move 2 from 2 to 1 | |
move 1 from 1 to 2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment