LoginSignup
3
2

More than 1 year has passed since last update.

brainfuckで関数スタイルとクラススタイルの比較

Last updated at Posted at 2019-03-19

@silver801 さんが投稿された「Pythonでbrainfuckインタプリタ(楔形文字も出る)」を拝見しました。

Pythonにはswitch-caseみたいなやつがないのでif-else祭りになりました。if-else節が長くなるときは一般にはdictを使えと言われてるけど、こういうとき(パターンマッチの後にいろいろ処理を書きたいとき)はどうするのがいいんだろうか?

とのことなので、処理を関数化してdictにしてみました。

関数スタイル

import sys

class Brain:
    pass

def inc(brain):
    brain.mem[brain.ptr] += 1

def dec(brain):
    brain.mem[brain.ptr] -= 1

def fore(brain):
    brain.ptr += 1
    if brain.ptr > len(brain.mem):
        print("overflow!")
        sys.exit(1)

def back(brain):
    if brain.ptr == 0:
        print("Can't decrement anymore")
    brain.ptr -= 1

def putc(brain):
    # chr: char -> code point
    print(chr(brain.mem[brain.ptr]), end="")  # no line break

def getc(brain):
    # ord: code point -> char
    brain.mem[brain.ptr] = ord(sys.stdin.buffer.read(1))

def begin(brain):
    if brain.mem[brain.ptr] == 0:
        nest = 1
        while nest != 0:
            brain.head += 1
            if brain.head == len(brain.code):
                print("']' is missing")
                sys.exit(1)
            if brain.code[brain.head] == '[':
                nest += 1
            elif brain.code[brain.head] == ']':
                nest -= 1

def end(brain):
    if brain.mem[brain.ptr] != 0:
        nest = 1
        while nest != 0:
            brain.head -= 1
            if brain.head < 0:
                print("'[' is missing")
            if brain.code[brain.head] == ']':
                nest += 1
            elif brain.code[brain.head] == '[':
                nest -= 1

def nop(brain):
    pass  # ignore other symbol

def brainfuck(code, mem_size=30000):
    operations = {
        "+": inc,    # increment the value at the pointer.
        "-": dec,    # decrement the value at the pointer.
        ">": fore,   # increment the pointer.
        "<": back,   # decrement the pointer.
        ".": putc,   # output the value at the  pointer as utf-8 character.
        ",": getc,   # accept one byte of input, storing its value in the mem at the  pointer.
        "[": begin,  # if the byte at the pointer is zero, then jump it to the matching ']'
        "]": end,    # if the byte at the pointer is nonzero, then jump it buck to the matching '['
    }
    brain = Brain()
    brain.code = code
    brain.mem = [0] * mem_size
    brain.ptr = 0
    brain.head = 0  # (tape reading) head
    while brain.head < len(code):
        operations.get(code[brain.head], nop)(brain)
        brain.head += 1


def main():
    args = sys.argv
    if len(args) < 2:
        code = sys.stdin.read()
    else:
        path = args[1]
        with open(path) as f:
            code = f.read()
    brainfuck(code)

if __name__ == "__main__":
    main()

データと関数がバラバラに定義されています。
データと関数をまとめてクラスにしてみます。

クラススタイル

import sys

class Brain:


    def inc(self):
        self.mem[self.ptr] += 1

    def dec(self):
        self.mem[self.ptr] -= 1

    def fore(self):
        self.ptr += 1
        if self.ptr > len(self.mem):
            print("overflow!")
            sys.exit(1)

    def back(self):
        if self.ptr == 0:
            print("Can't decrement anymore")
        self.ptr -= 1

    def putc(self):
        # chr: char -> code point
        print(chr(self.mem[self.ptr]), end="")  # no line break

    def getc(self):
        # ord: code point -> char
        self.mem[self.ptr] = ord(sys.stdin.buffer.read(1))

    def begin(self):
        if self.mem[self.ptr] == 0:
            nest = 1
            while nest != 0:
                self.head += 1
                if self.head == len(self.code):
                    print("']' is missing")
                    sys.exit(1)
                if self.code[self.head] == '[':
                    nest += 1
                elif self.code[self.head] == ']':
                    nest -= 1

    def end(self):
        if self.mem[self.ptr] != 0:
            nest = 1
            while nest != 0:
                self.head -= 1
                if self.head < 0:
                    print("'[' is missing")
                if self.code[self.head] == ']':
                    nest += 1
                elif self.code[self.head] == '[':
                    nest -= 1

    def nop(self):
        pass  # ignore other symbol

    def fuck(self, code, mem_size=30000):
        operations = {
            "+": self.inc,    # increment the value at the pointer.
            "-": self.dec,    # decrement the value at the pointer.
            ">": self.fore,   # increment the pointer.
            "<": self.back,   # decrement the pointer.
            "[": self.begin,  # if the byte at the pointer is zero, then jump it to the matching ']'
            "]": self.end,    # if the byte at the pointer is nonzero, then jump it buck to the matching '['
            ".": self.putc,   # output the value at the  pointer as utf-8 character.
            ",": self.getc,   # accept one byte of input, storing its value in the mem at the  pointer.
        }
        self.code = code
        self.mem = [0] * mem_size
        self.ptr = 0
        self.head = 0
        while self.head < len(code):
            operations.get(code[self.head], self.nop)()
            self.head += 1


def main():
    args = sys.argv
    if len(args) < 2:
        code = sys.stdin.read()
    else:
        path = args[1]
        with open(path) as f:
            code = f.read()
    Brain().fuck(code)

if __name__ == "__main__":
    main()

比較

横並びにして比較してみましょう。

import sys                                                  import sys

class Brain:                                                class Brain:
    pass                                                    

def inc(brain):                                                 def inc(self):
    brain.mem[brain.ptr] += 1                                       self.mem[self.ptr] += 1

def dec(brain):                                                 def dec(self):
    brain.mem[brain.ptr] -= 1                                       self.mem[self.ptr] -= 1

def fore(brain):                                                def fore(self):
    brain.ptr += 1                                                  self.ptr += 1
    if brain.ptr > len(brain.mem):                                  if self.ptr > len(self.mem):
        print("overflow!")                                              print("overflow!")
        sys.exit(1)                                                     sys.exit(1)

def back(brain):                                                def back(self):
    if brain.ptr == 0:                                              if self.ptr == 0:
        print("Can't decrement anymore")                                print("Can't decrement anymore")
    brain.ptr -= 1                                                  self.ptr -= 1

def putc(brain):                                                def putc(self):
    # chr: char -> code point                                       # chr: char -> code point
    print(chr(brain.mem[brain.ptr]), end="")                        print(chr(self.mem[self.ptr]), end="")

def getc(brain):                                                def getc(self):
    # ord: code point -> char                                       # ord: code point -> char
    brain.mem[brain.ptr] = ord(sys.stdin.buffer.read(1))            self.mem[self.ptr] = ord(sys.stdin.buffer.read(1))

def begin(brain):                                               def begin(self):
    if brain.mem[brain.ptr] == 0:                                   if self.mem[self.ptr] == 0:
        nest = 1                                                        nest = 1
        while nest != 0:                                                while nest != 0:
            brain.head += 1                                                 self.head += 1
            if brain.head == len(brain.code):                               if self.head == len(self.code):
                print("']' is missing")                                         print("']' is missing")
                sys.exit(1)                                                     sys.exit(1)
            if brain.code[brain.head] == '[':                               if self.code[self.head] == '[':
                nest += 1                                                       nest += 1
            elif brain.code[brain.head] == ']':                             elif self.code[self.head] == ']':
                nest -= 1                                                       nest -= 1

def end(brain):                                                 def end(self):
    if brain.mem[brain.ptr] != 0:                                   if self.mem[self.ptr] != 0:
        nest = 1                                                        nest = 1
        while nest != 0:                                                while nest != 0:
            brain.head -= 1                                                 self.head -= 1
            if brain.head < 0:                                              if self.head < 0:
                print("'[' is missing")                                         print("'[' is missing")
            if brain.code[brain.head] == ']':                               if self.code[self.head] == ']':
                nest += 1                                                       nest += 1
            elif brain.code[brain.head] == '[':                             elif self.code[self.head] == '[':
                nest -= 1                                                       nest -= 1

def nop(brain):                                                 def nop(self):
    pass                                                            pass

def brainfuck(code, mem_size=30000):                            def fuck(self, code, mem_size=30000):
    operations = {                                                  operations = {
        "+": inc,                                                       "+": self.inc,    
        "-": dec,                                                       "-": self.dec,    
        ">": fore,                                                      ">": self.fore,   
        "<": back,                                                      "<": self.back,   
        ".": putc,                                                      "[": self.begin,  
        ",": getc,                                                      "]": self.end,    
        "[": begin,                                                     ".": self.putc,   
        "]": end,                                                       ",": self.getc,   
    }                                                               }
    brain = Brain()                                         
    brain.code = code                                               self.code = code
    brain.mem = [0] * mem_size                                      self.mem = [0] * mem_size
    brain.ptr = 0                                                   self.ptr = 0
    brain.head = 0                                                  self.head = 0
    while brain.head < len(code):                                   while self.head < len(code):
        operations.get(code[brain.head], nop)(brain)                    operations.get(code[self.head], self.nop)()
        brain.head += 1                                                 self.head += 1

def main():                                                 def main():
    args = sys.argv                                             args = sys.argv
    if len(args) < 2:                                           if len(args) < 2:
        code = sys.stdin.read()                                     code = sys.stdin.read()
    else:                                                       else:
        path = args[1]                                              path = args[1]
        with open(path) as f:                                       with open(path) as f:
            code = f.read()                                             code = f.read()
    brainfuck(code)                                             Brain().fuck(code)

if __name__ == "__main__":                                  if __name__ == "__main__":
    main()                                                      main()

Brainの中のbrainは自分自身なのでselfという名称にするのが一般的ですが、
brain のままにすれば、ほとんど一緒ですね。

3
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2