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

Problem 28

オブジェクト指向

この問題は、人が原点から歩くと考えると、数学を使わなくて済みます。これをPythonで考えると、こんなクラスを作りたくなります。

class cWalker:
    def __init__(self):
        self.x = 0
        self.y = 0
        self.v = 1
    
    def value(self):
        return self.v
    
    def walk(self):
        if self.x < 0:
            if self.y < 0:
                ...

原点に対し右下にいたなら左へ動く、などと行動を書けばよいです。同じようなことをバッチファイルでできないでしょうか。
pというオブジェクトのxというプロパティはp_xとします。メソッドはcWalker_valueなどとします。こう決めれば書けると思いますが、さらにp_classにクラス名を格納しておくと、いろいろ面白いことができると思います。コンストラクタは、

call :new cWalker p

と呼ぶことにします。そうすると、

call :cWalker_cWalker p

が呼ばれて、pのクラス名と必要なプロパティが設定されます。一般には引数も設定できるとよりよいですね。ただ、shiftで%*が変わらないので効率よくは書けません。あるいは引数の数の上限決めるかです。
メソッドは、

call :method p value

と呼ぶと、p_classよりクラス名がわかって、

call :cWalker_value p

が呼ばれます。あとは地道にメソッドを実装するだけです。

@echo off

setlocal enabledelayedexpansion
set /a N = 1001
set /a M = %N% * 2 - 2
call :new cWalker p
call :method p value
set /a s = %ERRORLEVEL%
for /L %%k in (1, 1, %M%) do (
    call :method p walk
    call :method p value
    set /a s += !ERRORLEVEL!
)
echo %s%
exit /b 0

rem // call :new classname var
:new
    set %2_class=%1
    call :%1_%1 %2
    exit /b 0

rem // call :method var methodname
:method
    call set classname=%%%1_class%%
    call :%classname%_%2 %1
    exit /b %ERRORLEVEL%

:cWalker_cWalker
    set /a %1_x = 0
    set /a %1_y = 0
    set /a %1_v = 1
    exit /b 0

:cWalker_value
    setlocal
    set /a v = "%1_v"
    exit /b %v%

:cWalker_walk
    set /a x = "%1_x"
    set /a y = "%1_y"
    set /a v = "%1_v"
    if %x% LSS 0 (
        if %y% LSS 0 (
            set /a %1_y += -%y% * 2
            set /a %1_v += -%x% * 2
        ) else (
            set /a %1_x += -%x% * 2
            set /a %1_v += %y% * 2
        )
    ) else (
        if %y% LSS 0 (
            set /a %1_x += -%x% * 2
            set /a %1_v += -%y% * 2
        ) else (
            set /a %1_x += 1
            set /a %1_y += -%y% * 2 - 1
            set /a %1_v += %x% * 2 + 2
        )
    )
    
    exit /b 0