バッチファイルでProject Euler(30)

Problem 11


スペースで区切るコードを書きましょう。頭から見ていってスペースがあったら配列に登録するだけです。

rem // 引数は 文字列 配列変数 バッファ
:split
    if %1 == "" (
        call :push %2 %3
        exit /b 0
    )
    set s=%~1
    set c=%s:~0,1%
    if "%c%" == " " (
        call :push %2 %3
        call :split "%s:~1%" %2
    ) else (
        call :split "%s:~1%" %2 %3%c%
    )
    exit /b 0

shift

引数は%1から%9で参照できます。%10はないので、それ以降の引数を参照することはできません。しかし実体はあって、shiftを使うと参照できるようになります。

@echo off

call :test 1 2 3 4
exit /b 0

:test
    echo %1 // 1
    shift
    echo %1 // 2

shiftすると、%0(関数自体)に%1、%1に%2がシフトします。また、shift /nとすると%n以降がシフトします。

rem // 引数は 配列変数 文字列
:split
    :loop_split
        if "%2" == "" exit /b 0
        call :push %1 %2
        shift /2
        goto :loop_split
@echo off

setlocal
set /a a.size = 0
set /a H = 0
for /F "delims=" %%s in (%1) do (
    call :split a %%s
    set /a H += 1
)
call :print_vector a
set /a W = %a.size% / %H%
call :reduce mul_max 0 %a.size% 0
echo %ERRORLEVEL%
exit /b 0

:split
    :loop_split
        if "%2" == "" exit /b 0
        call :push %1 %2
        shift /2
        goto :loop_split

:mul_max
    setlocal
    set /a mx = %1
    set /a x = %2 %% %W%
    set /a y = %2 / %W%
    
    set /a W_ = %W% - 4
    set /a H_ = %H% - 4
    
    set /a W_1 = %W% - 1
    set /a W_2 = %W% + 1
    
    rem // to right
    if %x% LEQ %W_% call :max_mul_seq %2 1
    if %y% LEQ %H_% (
        rem // down
        call :max_mul_seq %2 %W%
        if %x% GEQ 3 call :max_mul_seq %2 %W_1%
        if %x% LEQ %W_% call :max_mul_seq %2 %W_2%
    )
    exit /b %mx%

:max_mul_seq
    set /a m = 1
    set /a end = %1 + %2 * 3
    for /L %%k in (%1, %2, %end%) do set /a m *= "a_%%k"
    if %m% GTR %mx% set /a mx = %m%
    exit /b 0

:push
    set /a e = 1%2 %% 100
    call :push_vector %1 %e%
    exit /b 0

:push_vector
    set /a size = "%1.size"
    set /a %1_%size% = %2
    set /a %1.size += 1
    exit /b 0

:print_vector
    setlocal
    set vector=%1
    set /a size = "%vector%.size"
    if %size% == 0 echo %2 & exit /b 0
    set /a e = "%vector%_0"
    set s=%e%
    set /a k = 1
    :loop_print_vector
        if %k% == %size% echo %s% & exit /b 0
        set /a e = "%vector%_%k%"
        set s=%s% %e%
        set /a k += 1
        goto :loop_print_vector

:reduce
    setlocal
    set f=%1
    set /a first = %2
    set /a last = %3
    set /a init = %4
    if %first% == %last% exit /b %init%
    
    call :%f% %init% %first%
    set /a next = %first% + 1
    call :reduce %f% %next% %last% %ERRORLEVEL%
    exit /b %ERRORLEVEL%