예제 #1
0
파일: day23.py 프로젝트: gboyegadada/algos
    def add(self, node: Machine):

        if verbose: node.toggle_verbose()

        new_addr = len(self.__nodes)
        node.run(new_addr)

        self.__nodes.append({'machine': node, 'message_queue': deque()})
예제 #2
0
class SpringDroid:
    def __init__(self, m):
        self.__m = m
        self.__cpu = Machine(self.__m[:])

        if verbose: self.__cpu.toggle_verbose()

    def run(self, program):
        cpu = self.__cpu

        cpu.boot()
        cpu.run()

        self.out()

        final = program.pop()

        for line in list(program):
            self.instruct(line, silent=True)

        self.instruct(final)

    def out(self, tostring: bool = True, silent: bool = False):
        cpu = self.__cpu

        o = []

        while cpu.has_output():
            b = cpu.output()
            o.append(b if b > 127 else chr(b))

        so = ''.join(map(str, o))

        if not silent:
            print(so)

        return so if tostring else o

    def instruct(self,
                 command: str,
                 tostring: bool = True,
                 silent: bool = False):
        '''
    - convert text command to ASCII and feed to computer.
    - return output
    '''

        if not silent:
            print('INSTR:', command)

        cpu = self.__cpu

        for c in map(ord, command):
            cpu.run(c)

        cpu.run(10)  # return

        return self.out(tostring, silent)
예제 #3
0
  def __init__(self, m):
    self.__m = m
    self.__cpu = Machine(self.__m[:])
    self.__history = []
    
    self.__bounds = (0, 0, 0, 0)
    self.__pos = (0, 0)
    self.__map = OrderedDict({(0, 0): 1})

    if verbose: self.__cpu.toggle_verbose()
예제 #4
0
    def reset(self):
        if not self.__map: return

        self.__pos = (0, 0)
        self.__move_count = 0
        self.__tank_pos = None

        self.__map = OrderedDict()
        self.__cpu = Machine(self.__m[:])
        if verbose: self.__cpu.toggle_verbose()

        return self
예제 #5
0
파일: day25.py 프로젝트: gboyegadada/algos
    def __init__(self, m):
        self.__m = m
        self.__cpu = Machine(self.__m[:])
        self.__history = []

        self.__move_count = 0
        self.__safe_items = {
            'asterisk', 'polygon', 'tambourine', 'mug', 'cake', 'jam',
            'easter egg', 'klein bottle'
        }

        if verbose: self.__cpu.toggle_verbose()
예제 #6
0
파일: day13.py 프로젝트: gboyegadada/algos
    def __init__(self, m):
        self.__cpu = Machine(m)
        self.__minx = self.__miny = self.__maxx = self.__maxy = 0
        '''
    we only need to track (x)
    '''
        self.__player_x = 0
        self.__ball_x = 0
        self.__canvas = defaultdict(lambda: ' ')
        self.__scores = 0
        self.__tiles = {0: ' ', 1: '|', 2: '⬜', 3: '➖', 4: '⚪'}

        if verbose: self.__cpu.toggle_verbose()
예제 #7
0
    def __init__(self, m):
        self.__m = m
        self.__cpu = Machine(self.__m[:])
        self.__history = []

        self.__bounds = (0, 0, 0, 0)
        self.__pos = (0, 0)
        self.__tank_pos = None
        self.__move_count = 0
        self.__map = OrderedDict({(0, 0): Droid.OK})
        self.__tiles = {0: '⬜', 1: '.', 2: '⭐'}

        if verbose: self.__cpu.toggle_verbose()
예제 #8
0
    def __init__(self, m):
        self.__m = m
        self.__cpu = Machine(self.__m[:])
        self.__history = []

        self.__bounds = (0, 0, 0, 0)
        self.__pos = (0, 0)
        self.__bot_pos = (0, 0, ord('^'))
        self.__moves = []
        self.__map = OrderedDict()
        self.__alignment_parameters = 0
        self.__star_dust = 0

        if verbose: self.__cpu.toggle_verbose()
예제 #9
0
    def run(self, display=True):

        moves = self.traverse()

        m = self.__m[:]
        m[0] = 2
        cpu = self.__cpu = Machine(m)
        subs = self.subroutines(moves)

        if verbose: cpu.toggle_verbose()
        ''' 1. MAIN '''
        for instr in map(ord, subs['MAIN']):
            cpu.run(instr)

        cpu.run(10)  # return
        self.video(display)
        ''' 2. SUBROUTINES '''
        for i in range(3):
            key = ('A', 'B', 'C')[i]

            for instr in map(ord, subs[key]):
                cpu.run(instr)

                self.video(display)

            cpu.run(10)  # return
            self.video(display)
        ''' 3. VIDEO FEED: YES '''
        cpu.run(ord('y' if display else 'n'))
        cpu.run(10)  # return
        self.video(display)

        return self.video(display)
예제 #10
0
  def __init__(self, m):
    self.__cpu = Machine(m)

    '''
    {current, min, max}

    '''
    self.__x, self.__y = (0, 0, 0), (0, 0, 0)
    self.__panels = defaultdict(lambda: '.')
    self.__color = 0

    '''
    < : 0
    ^ : 1
    > : 2
    v : 3

    '''
    self.__direction = 1

    if verbose: self.__cpu.toggle_verbose()
예제 #11
0
파일: day25.py 프로젝트: gboyegadada/algos
class Bot:
    NORTH = 'north'
    SOUTH = 'south'
    WEST = 'west'
    EAST = 'east'

    def __init__(self, m):
        self.__m = m
        self.__cpu = Machine(self.__m[:])
        self.__history = []

        self.__move_count = 0
        self.__safe_items = {
            'asterisk', 'polygon', 'tambourine', 'mug', 'cake', 'jam',
            'easter egg', 'klein bottle'
        }

        if verbose: self.__cpu.toggle_verbose()

    def map(self, _display=True):

        history = self.__history
        p = 0
        move = self.NORTH
        tries = {}
        inventory = set()
        seen_items = set()
        safe_items = self.__safe_items
        checkpoint_map = []
        disable_pickups = False

        self.__cpu.run()
        o = ''.join(list(map(chr, self.__cpu.dump_output(clear=True))))

        print('MAIN OUTPUT:', o)

        while True and not self.__cpu.halted():
            sleep(0.2)
            '''
      here, we will use (D)epth (F)irst (S)earch algo to traverse
      the entire map, collect all items and find our way to the checkpoint.

      '''
            p = self.location(o)

            if p not in tries:
                tries[p] = set(self.moves(o))

            if tries[p]:
                print(f'AVAILABLE TRIES FOR [ {p.upper()} ]:', tries[p])
                backtrack = False

                prev = move
                move = tries[p].pop()

                if tries[p] and prev == self.reverse(move):
                    prev = move
                    move = tries[p].pop()
                    tries[p].add(prev)

            else:
                backtrack = True

                if not history:
                    '''
            no where to backtrack to. this will happen when we've explored 
            every other path and are forced to backtrack all the back to the beginning.

            END PROGRAM
            '''
                    print('NO HISTORY')

                    if checkpoint_map and len(seen_items) == len(safe_items):
                        print('ALL SET: NAVIGATE TO CHECKPOINT')
                        print('SEEN ITEMS:', seen_items)
                        print('Hit enter to continue >_')

                        sys.stdin.readline()

                        path = checkpoint_map[::-1]

                        while path:
                            self.instruct(path.pop())

                        move = self.EAST

                    else:
                        print('MISSING ITEMS OR NO CHECKPOINT PATH')
                        print('PATH:', checkpoint_map)
                        print('SEEN ITEMS:', seen_items)
                        break

                else:
                    move = self.reverse(history.pop())

            o = self.instruct(move)

            for item in self.items(o):
                if item not in 'molten lava escape pod giant electromagnet photons infinite loop' and (
                        not disable_pickups or item not in seen_items):
                    self.instruct(f'take {item}')
                    inventory.add(item)
                    seen_items.add(item)

                else:
                    pass  # print('SKIPPED:', item)

            if 'checkpoint' in o:
                print('CHECKPOINT')
                '''
        Save path to checkpoint for later
        '''
                checkpoint_map = history.copy()
                ''' 
        Make sure ALL safe items are collected before 
        initiating brute force.
        '''
                if len(seen_items) != len(safe_items):
                    continue

                else:
                    print('============ ALL SET ================')
                    self.instruct('inv')
                    print('=====================================')
                    print('Hit enter to continue >_')

                    sys.stdin.readline()

                    self.brute()
                    break

            if "You can't go that way" not in o:

                if not backtrack:
                    history.append(move)

    def brute(self):
        '''
    try all possible combinations of items at the checkpoint.
    '''

        for i in range(3, 6):
            print(f'TRYING SETS OF {i}')
            print('-------------------------------------')
            print('Hit enter to continue >_')
            sys.stdin.readline()

            item_combinations = set(combinations(self.__safe_items, i))

            while item_combinations:
                current_set = item_combinations.pop()
                print('TRYING WITH FOLLOWING INVENTORY:', current_set)

                _o = self.items(self.instruct('inv', silent=True))

                for item in [x for x in _o if x not in current_set]:
                    self.instruct(f'drop {item}', silent=True)

                for item in [x for x in current_set if x not in _o]:
                    self.instruct(f'take {item}', silent=True)

                _o = self.instruct('inv')
                ''' TRY '''
                _o = self.instruct('east')

                if not re.search(r'(heavier|lighter) than', _o):
                    print('YAYYYY (?):', _o)
                    return

                sleep(0.2)

        print('SECURITY BREACH FAILED. TRY AGAIN.')

    def instruct(self, command: str, join: bool = True, silent: bool = False):
        '''
    - convert text command to ASCII and feed to computer.
    - return output
    '''

        if not silent:
            print('INSTR:', command)

        cpu = self.__cpu

        for c in map(ord, command):
            cpu.run(c)

        cpu.run(10)  # return

        o = list(map(chr, cpu.dump_output(clear=True)))

        if not silent:
            print('OUTPUT:', ''.join(o))

        return ''.join(o) if join else o

    def moves(self, o):
        '''
    extract available moves from output
    '''

        res = re.findall(r'- (north|south|east|west)', ''.join(o))

        if res:
            pass  # print('MOVES:', res)

        return res

    def items(self, o):
        '''
    extract items from output
    '''

        res = re.findall(r'- ([ a-z]+)', o)

        if res:
            res = [
                x for x in res if x not in {'north', 'south', 'east', 'west'}
            ]
            # if res: print('ITEMS:', res)

        return res

    def location(self, o):
        '''
    extract location from output
    '''

        res = re.findall(r'== ([ a-z]+) ==', o.lower())

        return res[0]

    def reverse(self, direction=None):
        if direction == None: direction = self.__history[-1]

        return {
            self.NORTH: self.SOUTH,
            self.SOUTH: self.NORTH,
            self.WEST: self.EAST,
            self.EAST: self.WEST
        }[direction]
예제 #12
0
class Droid:
    WALL = 0
    OK = 1
    OXYGEN = 2
    UNEXPLORED = 3

    MOV_NORTH = 1
    MOV_SOUTH = 2
    MOV_WEST = 3
    MOV_EAST = 4

    def __init__(self, m):
        self.__m = m
        self.__cpu = Machine(self.__m[:])
        self.__history = []

        self.__bounds = (0, 0, 0, 0)
        self.__pos = (0, 0)
        self.__tank_pos = None
        self.__move_count = 0
        self.__map = OrderedDict({(0, 0): Droid.OK})
        self.__tiles = {0: '⬜', 1: '.', 2: '⭐'}

        if verbose: self.__cpu.toggle_verbose()

    def map(self, display=True):
        self.reset()

        cpu = self.__cpu
        history = self.__history
        p = self.__pos = (0, 0)
        nswe = set(range(1, 5))
        move = self.MOV_NORTH
        tries = {p: {self.reverse(self.MOV_NORTH)}}

        while True:
            '''
      here, we will use (D)epth (F)irst (S)earch algo to traverse
      the entire map. 
      
      we will also capture tank's position and steps when it is found.
      the goal here is to traverse every single path (even after the tank is found) by 
      going all the way to end of each path and backtracking till we find a new one.
      Loop:
      ------------------------------------------------------------------
      - each position is a new node/vertex
      - each vertex potentially has 4 directions to try except for where
        it is coming from. [ example: if we took a step NORTH, then SOUTH is excluded 
        from future potential tries. ]
      - once a direction is tried, we add to the list of tries for the current position/node/vertex (x, y).
      - if the node's tries are exhausted N, W, E ... then backtrack 1 step
      - hmmm... we've been here before innit? oui ! mon Dieu ! 
      - in the node we backtracked to, check if we have any untried directions left.
      - if [ not ]: backtrack again. if [ yes ]: pop a move from remaining tries and go on your merry way.
      REPEAT
      '''

            if p not in tries:
                tries[p] = {self.reverse(move)}

            if len(tries[p]) < 4:
                backtrack = False

                move = nswe.difference(tries[p]).pop()
                tries[p].add(move)

            else:
                backtrack = True

                if not history:
                    '''
            no where to backtrack to. this will happen when we've explored 
            every other path and are forced to backtrack all the back to the beginning.
            END PROGRAM
            '''
                    break

                move = self.reverse(history.pop())

            cpu.run(move)
            o = cpu.output()

            if o in {self.OK, self.OXYGEN}:
                p = self.xy(move, p)
                self.__pos = p
                self.__bounds = self.update_bounds()

                if not backtrack:
                    history.append(move)
                    self.__map[p] = o

                if o == self.OXYGEN:
                    '''
          + capture oxygen tank [position: x, y] and [steps] it took to get to it.
          + there is only 1 path but if there were more than 1, to get the shortest path,
            we'd simply replace with the lowest count each time we hit the oxygen tank.
          '''
                    self.__move_count = len(
                        self.__history) if self.__move_count == 0 else min(
                            self.__move_count, len(self.__history))
                    self.__tank_pos = p

                if display:
                    self.display()

        return self.__tank_pos, self.__move_count, self.__map

    def reverse(self, direction=None):
        if direction == None: direction = self.__history[-1]

        return {
            self.MOV_NORTH: self.MOV_SOUTH,
            self.MOV_SOUTH: self.MOV_NORTH,
            self.MOV_WEST: self.MOV_EAST,
            self.MOV_EAST: self.MOV_WEST
        }[direction]

    def xy(self, move, from_xy: tuple = None):
        x, y = from_xy if from_xy else self.__pos

        dnswe = {
            self.MOV_NORTH: (0, -1),
            self.MOV_SOUTH: (0, 1),
            self.MOV_WEST: (-1, 0),
            self.MOV_EAST: (1, 0)
        }

        return tuple(a + b for a, b in zip((x, y), dnswe[move]))

    def update_bounds(self):
        mxy, xy = list(self.__bounds), self.__pos

        return tuple([min(p1, p2) for p1, p2 in zip(mxy[:2], xy)] +
                     [max(p1, p2) for p1, p2 in zip(mxy[2:], xy)])

    def display(self):
        minx, miny, maxx, maxy = self.__bounds
        maxx, maxy = abs(minx) + maxx, abs(miny) + maxy
        px, py = self.__pos

        # subprocess.call("clear")

        dash = 'Steps: {}, Max (x): {}, Max (y): {}'.format(
            len(self.__history), maxx, maxy)

        print(dash)
        print('.' * (maxx + 1))

        grid = [[' '] * (maxx + 1) for _ in range(maxy + 1)]

        for (x, y), v in self.__map.items():
            x += abs(minx)
            y += abs(miny)

            if x < 0 or x > maxx or y < 0 or y > maxy: break

            try:
                grid[y][x] = self.__tiles[v]
            except:
                print('DEBUG', x, y, maxx, maxy)
                exit()
                break

        prev = grid[py + abs(miny)][px + abs(minx)]

        rx, ry = px + abs(minx), py + abs(miny)
        if prev != self.__tiles[self.OXYGEN]:
            grid[ry][rx] = '🛸'
        else:
            grid[ry][rx - 1] = '🛸'

        for l in grid:
            print(''.join(l))

        print('\n')
        print('.' * (maxx + 1))
        print(dash)

        # sleep(0.1)

    def reset(self):
        if not self.__map: return

        self.__pos = (0, 0)
        self.__move_count = 0
        self.__tank_pos = None

        self.__map = OrderedDict()
        self.__cpu = Machine(self.__m[:])
        if verbose: self.__cpu.toggle_verbose()

        return self
예제 #13
0
class Drone:

  def __init__(self, m):
    self.__m = m
    self.__cpu = Machine(self.__m[:])
    self.__history = []
    
    self.__bounds = (0, 0, 0, 0)
    self.__pos = (0, 0)
    self.__map = OrderedDict({(0, 0): 1})

    if verbose: self.__cpu.toggle_verbose()



  def points(self, silent = False, bounds = 0):
    p = self.__pos = (0, 0)

    points = 0
    ship_pos = None

    for y in range(bounds):
      for x in range(bounds):
        p = self.__pos = (x, y)

        o = self.ping(x, y)
        self.__map[p] = '#' if o == 1 else '.'
        self.update_bounds(p)
        points += o

    if not silent: 
      display(self.__map, self.__bounds)

    return points, ship_pos


  def position(self, bounds = 0):
    x, y = 0, 0

    while True:
      
      lower_left = None

      while True:
        '''
        find lower left corner first
        '''

        lower_left = self.ping(x, y)

        if lower_left == 1: break
        
        x += 1


      b = bounds - 1 # make corners inclusive

      ''' lower right corner '''
      x2 = x + b
      lower_right = self.ping(x2, y)
      
      ''' upper left corner '''
      upper_left = self.ping(x, y-b)

      ''' upper right corner '''
      upper_right = self.ping(x2, y-b)

      ''' 
      test:

      check that the spot just above the top right corner is
      not a (#).

      making the sure the box fits right on the edge.
      '''
      upper_right_test = self.ping(x2, y-bounds)

      if upper_left and lower_left and lower_right and upper_right and not upper_right_test:
        return (x, y-b)

      y += 1

    ''' FAILED '''
    return (0, 0)


  def ping(self, x, y):
    cpu = self.__cpu
  
    cpu.boot()

    cpu.run(x)
    cpu.run(y)

    return cpu.output()


  def update_bounds(self, xy):
    mxy = list(self.__bounds)

    self.__bounds = tuple([min(p1, p2) for p1, p2 in zip(mxy[:2], xy)] + [max(p1, p2) for p1, p2 in zip(mxy[2:], xy)])
예제 #14
0
파일: day23.py 프로젝트: gboyegadada/algos
    def read(self, n: Machine):
        o = []
        for _ in range(3):
            o.append(n.output())

        return o

    def add(self, node: Machine):

        if verbose: node.toggle_verbose()

        new_addr = len(self.__nodes)
        node.run(new_addr)

        self.__nodes.append({'machine': node, 'message_queue': deque()})


'''
Solution 1 & 2
'''

net = Network()

for _ in range(50):
    node = Machine(mreset[:])

    net.add(node)

net.start()
예제 #15
0
파일: day23.py 프로젝트: gboyegadada/algos
    def read(self, n: Machine):
        o = []
        for _ in range(3):
            o.append(n.output())

        return o
예제 #16
0
  def __init__(self, m):
    self.__m = m
    self.__cpu = Machine(self.__m[:])

    if verbose: self.__cpu.toggle_verbose()
예제 #17
0
class Bot:
    SCAFFOLD = 35
    SPACE = 46
    CORNER = 64
    NORTH = 94
    SOUTH = 118
    WEST = 60
    EAST = 62
    LN = 10
    TILES = {35: '⬜', 46: '.', 2: '⭐'}

    def __init__(self, m):
        self.__m = m
        self.__cpu = Machine(self.__m[:])
        self.__history = []

        self.__bounds = (0, 0, 0, 0)
        self.__pos = (0, 0)
        self.__bot_pos = (0, 0, ord('^'))
        self.__moves = []
        self.__map = OrderedDict()
        self.__alignment_parameters = 0
        self.__star_dust = 0

        if verbose: self.__cpu.toggle_verbose()

    def run(self, display=True):

        moves = self.traverse()

        m = self.__m[:]
        m[0] = 2
        cpu = self.__cpu = Machine(m)
        subs = self.subroutines(moves)

        if verbose: cpu.toggle_verbose()
        ''' 1. MAIN '''
        for instr in map(ord, subs['MAIN']):
            cpu.run(instr)

        cpu.run(10)  # return
        self.video(display)
        ''' 2. SUBROUTINES '''
        for i in range(3):
            key = ('A', 'B', 'C')[i]

            for instr in map(ord, subs[key]):
                cpu.run(instr)

                self.video(display)

            cpu.run(10)  # return
            self.video(display)
        ''' 3. VIDEO FEED: YES '''
        cpu.run(ord('y' if display else 'n'))
        cpu.run(10)  # return
        self.video(display)

        return self.video(display)

    def ready(self):
        return self.__cpu.halted()

    def subroutines(self, moves):
        routines = {}
        '''
    Initially solved manually not proud 
    but this was DAY THREE 😳
    FUNC_MAIN = 'A,A,B,B,C,B,C,B,C,A'
    FUNC_A = 'L,10,L,10,R,6'
    FUNC_B = 'R,12,L,12,L,12'
    FUNC_C = 'L,6,L,10,R,12,R,12'
    
    routines[0] = FUNC_MAIN
    routines[A] = FUNC_A
    routines[B] = FUNC_B
    routines[C] = FUNC_C
    
    UPDATE: DAY AFTER
    ------------------------------------------
    build list of candidate functions (collect repeated sequences)
    1. begin from [i:i+2] 
    2. count occurences of sub in rest of string
    3. if zero, increment i
    4. if repetitions found, store count, increment j and try [i:j] until j >= j + (len(moves) - j) // 2
    5. increment i and goto step 1
    '''
        path, n, seen = ','.join(moves), '', set()

        counts, l, i, j = {}, len(moves), 0, 2

        while i < l:
            n = ','.join(moves[i:j])

            if n not in seen:
                seen.add(n)
                c = ','.join(moves[j:]).count(n)

                if c > 1:
                    counts[n] = c

            if j >= j + (l - j) // 2 or c == 0:
                i += 1
                j = i + 2
            else:
                j += 1

        print('PATH:', path, '\n')

        # for p, c in counts.items():
        #   print('PATH:', p, '==>', c)
        '''
    do a little checksum using combinations of candidate functions
    to narrow down list and group candidate functions into trios. 
    '''
        h = path.replace(',', '')  # for checksum
        trios = set()
        total_count = 0
        for _abc in combinations(counts.keys(), 3):
            total_count += 1
            a, b, c = map(lambda s: s.replace(',', ''), _abc)
            '''
      check if total length of the overall path matches 
      combined steps of candidate functions (minus commas).
      '''
            checksum = (h.count(a) *
                        len(a)) + h.count(b) * len(b) + h.count(c) * len(c)
            if len(h) == checksum:
                trios.add(_abc)

        print(
            f'ABC CANDIDATES: {len(trios)} trios found out of {total_count} combinations.'
        )
        '''
    simulate traversal with each set of functions and stop when we
    find a function trio that takes us all the way to the end of the maze.
    '''
        abc, fn_queue, queue = {}, [], ''
        while trios and queue != path:
            func_set = trios.pop()
            abc, queue, fn_queue = dict(zip('ABC', func_set)), '', []

            while queue != path:
                match = False
                for i, fn in enumerate(func_set):
                    new_queue = f'{queue},{fn}' if queue != '' else fn

                    if path.startswith(new_queue):
                        queue = new_queue
                        fn_queue.append('ABC'[i])
                        match = True
                        break

                if not match:
                    break

        print('ABC DEFS:', abc, fn_queue)
        '''
    DONE !!
    return subroutines
    '''
        routines['MAIN'] = ','.join(fn_queue)
        for k, f in abc.items():
            routines[k] = f

        return routines

    def map(self, display=True):
        cpu = self.__cpu

        cpu.run()

        self.video(display)

        m, acc, inter, corners = self.__map, 0, 0, []
        for (x, y), v in m.items():
            if v != Bot.SCAFFOLD:
                continue

            n = neighbours(m, (x, y), lambda np, v: v == Bot.SCAFFOLD)

            if len(n) == 4:
                acc += (x - 1) * y
                m[(x, y)] = 79
                inter += 1

            elif len(n) == 2 and corner((x, y), n):
                m[(x, y)] = 64
                corners.append((x, y))

        self.__alignment_parameters = acc

        return self.__map, self.__bot_pos

    def get_map(self):
        return self.__map

    def video(self, show=True):
        cpu = self.__cpu
        pos = self.__pos = (0, 0)

        while cpu.has_output():

            o = cpu.output()

            if o == self.LN:
                x, y = pos

                if x == 0:
                    pos = (x, 0)

                else:
                    pos = (0, y + 1)

                self.update_bounds(pos)

            elif o > 127:
                self.__star_dust = o
                break

            else:
                '''capture robot position and direction'''
                if o in {self.NORTH, self.SOUTH, self.WEST, self.EAST}:
                    if self.__bot_pos[0] == 0:
                        self.__bot_pos = (*pos, o)

                self.__map[pos] = o

                x, y = pos
                pos = (x + 1, y)

                self.update_bounds(pos)

        pos = (0, 0)
        self.update_bounds(pos)

        if show:
            display(self.__map, self.get_bounds())

        return self.__map, self.__bot_pos

    def traverse(self):
        m = self.__map.copy()

        prev = None

        x, y, facing = self.__bot_pos

        pos = tuple([x, y])
        d, facing = self.turn(facing, pos, None)

        moves = []

        while True:

            s, pos, prev = self.steps(pos, facing)
            # print('DEBUG', s, pos, chr(m[pos]), prev, chr(d), chr(facing))

            if s == 0:
                break

            moves.append('{},{}'.format(chr(d), s))

            if pos not in m or m.get(pos, None) != self.CORNER:
                # print('DEBUG HALT NOT A CORNER', pos, s)
                break

            d, facing = self.turn(facing, pos, prev)

        self.__moves = moves
        self.__bot_pos = (*pos, facing)

        return moves

    def steps(self, pos, facing):
        m, steps, prev = self.__map, 0, None

        p = tuple(pos)
        p = self.move(p, facing)

        while p in m and m.get(p) not in {self.CORNER, self.SPACE}:
            steps += 1
            prev = tuple(pos)
            pos = p

            p = self.move(p, facing)

        if m.get(p, None) == self.CORNER:
            steps += 1
            prev = tuple(pos)
            pos = p

        return steps, pos, prev

    def turn(self, facing, pos, prev):
        '''
    turn() is doing 2 things:
    1. figure out which side the neighbouring scaffold node is on
    2. determine where robot is facing after turn
    '''
        n = neighbours(self.__map, pos,
                       lambda np, v: v == Bot.SCAFFOLD and np != prev)[0]

        if n[0] != pos[0]:  # N < -- > S
            f = ord('<') if n[0] < pos[0] else ord('>')

        else:  # W < -- > E
            f = ord('^') if n[1] < pos[1] else ord('v')

        if '{} {}'.format(chr(facing), chr(f)) in {'^ <', '< v', 'v >', '> ^'}:
            return (ord('L'), f)
        elif '{} {}'.format(chr(facing),
                            chr(f)) in {'^ >', '> v', 'v <', '< ^'}:
            return (ord('R'), f)

    def move(self, pos, facing):

        dnswe = {
            self.NORTH: (0, -1),
            self.SOUTH: (0, 1),
            self.WEST: (-1, 0),
            self.EAST: (1, 0)
        }

        return tuple(a + b for a, b in zip(pos, dnswe[facing]))

    def get_bounds(self):
        _, _, maxx, maxy = self.__bounds
        return (maxx, maxy)

    def update_bounds(self, xy):
        mxy = list(self.__bounds)

        self.__bounds = tuple([min(p1, p2) for p1, p2 in zip(mxy[:2], xy)] +
                              [max(p1, p2) for p1, p2 in zip(mxy[2:], xy)])

    def get_stardust_count(self):
        return self.__star_dust

    def get_alignment_parameters(self):
        return self.__alignment_parameters
예제 #18
0
class Robot:
  def __init__(self, m):
    self.__cpu = Machine(m)

    '''
    {current, min, max}

    '''
    self.__x, self.__y = (0, 0, 0), (0, 0, 0)
    self.__panels = defaultdict(lambda: '.')
    self.__color = 0

    '''
    < : 0
    ^ : 1
    > : 2
    v : 3

    '''
    self.__direction = 1

    if verbose: self.__cpu.toggle_verbose()


  def start(self, start_color):
    if start_color: self.__panels[(0, 0)] = '#'

    while not self.__cpu.halted():

      self.__cpu.run(1 if self.__panels[(self.__x[0], self.__y[0])] == '#' else 0)

      self.paint(self.__cpu.output())

      self.turn(self.__cpu.output())
      self.move()


  def display(self):
    _, minx, maxx = self.__x
    _, miny, maxy = self.__y


    grid = [[' ']*(maxx+1) for _ in range(maxy+1)]

    for (x, y), v in self.__panels.items():
      if x < 0 or y < 0: break

      if v == '#': grid[y][x] = v

    for l in grid: print(''.join(l))
    
    print('\n', '--------------------------------------\n', 'COUNT', len(self.__panels), '\n\n')

  def turn(self, lr):
    if verbose: print('FROM ', ['<', '^', '>', 'v'][self.__direction]*4, lr)
    if lr == 0: self.left()
    else: self.right()

    if verbose: print('TURNED ', ['<', '^', '>', 'v'][self.__direction]*4)


  def left(self):
    self.__direction += (3 if self.__direction == 0 else -1)

    return self.__direction

  def right(self):
    self.__direction += (-3 if self.__direction == 3 else 1)

    return self.__direction

  def move(self):
    x, minx, maxx = self.__x
    y, miny, maxy = self.__y

    # <- left
    if self.__direction == 0: 
      if verbose: print('MOV <----', x)
      x -= 1
      minx = min(minx, x)

      if verbose: print('x:', x)

    # -> right
    elif self.__direction == 2: 
      if verbose: print('MOV ---->', x)
      x += 1
      maxx = max(maxx, x)

      if verbose: print('x:', x)

    # -> up
    elif self.__direction == 1: 
      if verbose: print('MOV ^^^^^^', y)
      y -= 1
      miny = min(miny, y)

      if verbose:  print('y:', y)

    # -> down
    elif self.__direction == 3: 
      if verbose: print('MOV vvvvvv', y)
      y += 1
      maxy = max(maxy, y)
        
      if verbose: print('y:', y)

    self.__x, self.__y = (x, minx, maxx), (y, miny, maxy)
      

  def paint(self, color = None):
    if color != None: self.__color = color
  

    self.__panels[(self.__x[0], self.__y[0])] = ('.' if self.__color == 0 else '#') 
예제 #19
0
파일: day13.py 프로젝트: gboyegadada/algos
class Arcade9000Turbo:
    def __init__(self, m):
        self.__cpu = Machine(m)
        self.__minx = self.__miny = self.__maxx = self.__maxy = 0
        '''
    we only need to track (x)
    '''
        self.__player_x = 0
        self.__ball_x = 0
        self.__canvas = defaultdict(lambda: ' ')
        self.__scores = 0
        self.__tiles = {0: ' ', 1: '|', 2: '⬜', 3: '➖', 4: '⚪'}

        if verbose: self.__cpu.toggle_verbose()

    def play(self, auto: bool = False):
        self.__cpu.run()

        while not self.__cpu.halted() or self.__cpu.has_output():
            x = self.__cpu.output()
            y = self.__cpu.output()

            if x == -1 and y == 0:
                '''
        player's current score

        '''
                self.__scores = self.__cpu.output()
                self.display()

            elif x != None and y != None:
                '''
        draw a tile to the screen

        '''
                self.draw(x, y, self.__cpu.output())
                self.display()

            elif auto and self.__cpu.waiting():
                m = 0
                if self.__ball_x > self.__player_x:
                    m = 1
                    print('_/_ >')

                elif self.__ball_x < self.__player_x:
                    m = -1
                    print('_\\_ >')
                else:
                    print('_|_ >')

                self.__cpu.run(m)

            elif self.__cpu.waiting():
                print('_|_ >')
                self.input()

    def input(self):
        try:
            self.__cpu.run(int(sys.stdin.readline()))
        except ValueError:
            print('Invalid input (hint: enter -1, 0, or 1 ):')
            self.input()

    def display(self):
        grid = [[' '] * (self.__maxx + 1) for _ in range(self.__maxy + 1)]

        count = 0
        for (x, y), v in self.__canvas.items():
            if x < 0 or y < 0: break
            if v == self.__tiles[2]: count += 1
            grid[y][x] = v

        subprocess.call("clear")
        for l in grid:
            print(''.join(l))

        print('\n')
        print('.' * (self.__maxx + 1))

        print('Score: {0}, Blocks: {1}'.format(self.__scores, count))

    def draw(self, x, y, tile_id):
        self.__canvas[(x, y)] = self.__tiles[tile_id]

        self.__minx = min(self.__minx, x)
        self.__maxx = max(self.__maxx, x)
        self.__miny = min(self.__miny, y)
        self.__maxy = max(self.__maxy, y)

        if tile_id == 4:
            '''
      track ball displacement
      '''
            self.__ball_x = x
        elif tile_id == 3:
            '''
      track player position
      '''
            self.__player_x = x