def move_z(delta):
    if delta == 0: return single()
    c = 1 - 2 * (delta < 0)
    delta = abs(delta)
    full_steps = delta // JUMP_LONG
    last = delta - JUMP_LONG * full_steps
    return singles([SMove(Diff(0,0,c * JUMP_LONG))] * full_steps + [SMove(Diff(0,0,c * last))] * (last > 0))
    def filling_func(x, y, z, zup, bbox):
        bbox_min, bbox_max = bbox

        lookahead = (0 if z == bbox_max.z else int(reassembly))\
                        if zup else (0 if z == bbox_min.z else -int(reassembly))
        lookbehind = (0 if z == bbox_min.z else -int(reassembly))\
                        if zup else (0 if z == bbox_max.z else int(reassembly))

        if reassembly and model_src[Pos(x, y - offset, z + lookahead)]:
            if lookahead != 0:
                commands.append(Void(Diff(0, -offset, lookahead)))
        if x != bbox_min.x:
            action = choose_action(model_src, model_tgt,
                                   Pos(x - 1, y - offset, z))
            if action is not None:
                commands.append(action(Diff(-1, -offset, 0)))
        if not reassembly or lookbehind != 0:
            action = choose_action(model_src, model_tgt,
                                   Pos(x, y - offset, z + lookbehind),
                                   lookbehind != 0)
            if action is not None:
                commands.append(action(Diff(0, -offset, lookbehind)))
        if x != bbox_max.x:
            action = choose_action(model_src, model_tgt,
                                   Pos(x + 1, y - offset, z))
            if action is not None:
                commands.append(action(Diff(1, -offset, 0)))
Ejemplo n.º 3
0
def distribute_roots(x, y, z, full_w, last_w, seeds):
    if full_w == 0: return single()
    if full_w == 1 and last_w == 0: return single()

    return +single(Fission(Diff(-1,0,0),6)) + \
           (+single(Fission(Diff(1,0,0),max(seeds-7-1,0))) // single()) + \
           (-(single(FusionP(Diff(-1,0,0))) // single(FusionS(Diff(1,0,0)))) // (move_x(G_DIST) + distribute_roots(x+G_DIST, y, z, full_w - 1, last_w, seeds-7-1)))
Ejemplo n.º 4
0
def fusion(positions):
    '''Return a sequence of commands that merges the bot ids given in bids.
    Assumes bids is in increasing order and their corresponding positions are in
    an empty xz plane, have identical y and z coordinates and increasing x
    coordinates. Assumes no other bots exist. Returns commands that end with all
    bots merged into the first one.'''
    commands = []
    while len(positions) > 1:
        newpositions = []
        i = 0
        while i < len(positions):
            if i + 1 < len(positions):
                if positions[i].x + 1 == positions[i + 1].x:
                    # FUSE
                    commands.append(FusionP(Diff(1, 0, 0)))
                    commands.append(FusionS(Diff(-1, 0, 0)))
                    newpositions.append(positions[i])
                    i += 2
                else:
                    # MOVE CLOSER
                    dist = Diff(max(-15, positions[i] + 1 - positions[i + 1]),
                                0, 0)
                    commands.append(Wait())
                    commands.append(SMove(dist))
                    newpositions.append(positions[i])
                    newpositions.append(positions[i + 1] + dist)
                    i += 2
            else:
                dist = Diff(max(-15, positions[i - 1] + 1 - positions[i]), 0,
                            0)
                commands.append(SMove(dist))
                newpositions.append(positions[i] + dist)
                i += 1
        positions = newpositions
    return commands
Ejemplo n.º 5
0
def move_x(dx):
    if dx == 0: return []
    c = 1 - 2 * (dx < 0)
    dx = abs(dx)
    full_steps = dx // JUMP_LONG
    last = dx - JUMP_LONG * full_steps
    return [SMove(Diff(c * JUMP_LONG, 0, 0))
            ] * full_steps + [SMove(Diff(c * last, 0, 0))] * (last > 0)
def return_home_gen(f: 'Pos', t: 'Pos'):
    # y is last
    for x in split_linear_move(Diff(-f.x, 0, 0)):
        yield x
    for x in split_linear_move(Diff(0, 0, -f.z)):
        yield x
    for x in split_linear_move(Diff(0, -f.y, 0)):
        yield x
Ejemplo n.º 7
0
def move_y(dy):
    if dy == 0: return []
    c = 1 - 2 * (dy < 0)
    dy = abs(dy)
    full_steps = dy // JUMP_LONG
    last = dy - JUMP_LONG * full_steps
    return [SMove(Diff(0, c * JUMP_LONG, 0))
            ] * full_steps + [SMove(Diff(0, c * last, 0))] * (last > 0)
Ejemplo n.º 8
0
def move_z(dz):
    if dz == 0: return []
    c = 1 - 2 * (dz < 0)
    dz = abs(dz)
    full_steps = dz // JUMP_LONG
    last = dz - JUMP_LONG * full_steps
    return [SMove(Diff(0, 0, c * JUMP_LONG))
            ] * full_steps + [SMove(Diff(0, 0, c * last))] * (last > 0)
Ejemplo n.º 9
0
def spawn_down(model, x, y, z):
    prog = single()

    if model[Pos(x,y-1,z)]:
        prog += single(Void(Diff(0,-1,0)))
    prog += +single(Fission(Diff(0,-1,0), 0))

    return prog
Ejemplo n.º 10
0
def snake_fill_gen(m: 'Model', a: Pos, b: Pos):
    prevPos = a
    nextPos = a

    # The main idea is to skip path points where model has no voxels below it.
    # And then go to the next "job" using long lenear move. We always above our
    # buildings so we will never collide with anything.
    for diff in snake_path_gen(a, b):
        nextPos = nextPos + diff

        fillBelow = False
        for d in [Diff(0, -1, 0), Diff(0, -1, 1), Diff(0, -1, -1)]:
            if inside_region((nextPos + d), a, b) and m[nextPos + d]:
                fillBelow = True
        if fillBelow:
            dx = nextPos.x - prevPos.x
            dy = nextPos.y - prevPos.y
            dz = nextPos.z - prevPos.z

            # y first
            for x in split_linear_move(Diff(0, dy, 0)):
                yield x
            for x in split_linear_move(Diff(0, 0, dz)):
                yield x
            for x in split_linear_move(Diff(dx, 0, 0)):
                yield x

            for d in [Diff(0, -1, 0), Diff(0, -1, 1), Diff(0, -1, -1)]:
                if inside_region((nextPos + d), a, b) and m[nextPos + d]:
                    yield Cmd.Fill(d)
                    m[nextPos + d] = False

            prevPos = nextPos

    yield prevPos
Ejemplo n.º 11
0
def navigate(f: 'Pos', t: 'Pos'):
    # y is last
    dx = t.x - f.x
    dy = t.y - f.y
    dz = t.z - f.z
    if dy > 0:
        for x in split_linear_move(Diff(0, dy, 0)): yield x
    for x in split_linear_move(Diff(0, 0, dz)): yield x
    for x in split_linear_move(Diff(dx, 0, 0)): yield x
    if dy < 0:
        for x in split_linear_move(Diff(0, dy, 0)): yield x
Ejemplo n.º 12
0
def print_strip_below(model, i, lbound, z0, rbound, depth, last_layer):
    prog = single()
    for z in range(z0, z0 + depth):
        if model[Pos(lbound,i,z)]:
            prog += single(Fill(Diff(0,-1,0)))
        for x in range(lbound + 1, rbound):
            prog += single(SMove(Diff(1,0,0)))
            if model[Pos(x,i,z)]:
                prog += single(Fill(Diff(0,-1,0)))
        prog += move_x(-1 * (rbound - lbound - 1))
        prog += single(SMove(Diff(0,0,1))) # TODO: optimise this part, make an L move
    prog += move_z(-1 * (depth + last_layer * z0))
    return prog
Ejemplo n.º 13
0
    def move_and_unfork(strips):
        if not strips: return single()

        # Wait for everyone on the right to finish
        prog = single() // move_and_unfork(strips[1:])

        # Move our child bot to the left
        prog += single() // move_x(-1 * (strips[0] - 1))

        # Unfork the bot immediately to the right
        prog += -single(FusionP(Diff(1,0,0))) // single(FusionS(Diff(-1,0,0)))

        return prog
Ejemplo n.º 14
0
def move_in_empty_space(diff):
    # Move in XZ plane first, that way we can use this to float above model.
    commands = []
    if diff.dx != 0:
        for dx in long_distances(diff.dx):
            commands.append(SMove(Diff(dx, 0, 0)))
    if diff.dz != 0:
        for dz in long_distances(diff.dz):
            commands.append(SMove(Diff(0, 0, dz)))
    if diff.dy != 0:
        for dy in long_distances(diff.dy):
            commands.append(SMove(Diff(0, dy, 0)))

    return commands
Ejemplo n.º 15
0
    def move_and_unfork(strips):
        if not strips: return []
        ticks = []

        # Wait for everyone on the right to finish
        ticks.extend(wait_for(move_and_unfork(strips[1:])))

        # Move our child bot to the left
        ticks.extend(wait_for(sequential(move_x(-1 * (strips[0] - 1)))))

        # Unfork the bot immediately to the right
        ticks.append([FusionP(Diff(1, 0, 0)), FusionS(Diff(-1, 0, 0))])

        return ticks
Ejemplo n.º 16
0
    def spawn_bots(self, x, y):
        row = [1]
        p = 1
        for i in range(x - 1):
            p = self[p].spawn_keep(Diff(1, 0, 0), y - 1)
            row.append(p)
            yield from self.step()

        all_rows = [row]
        for j in range(y - 1):
            row = [self[i].spawn_keep(Diff(0, 1, 0), 0) for i in row]
            all_rows.append(row)
            yield from self.step()

        self.grid = all_rows
Ejemplo n.º 17
0
def print_strip_below(model, i, lbound, rbound, last_layer):
    moves = []
    for z in range(1, model.R - 1):
        if model[Pos(lbound, i, z)]:
            moves.append(Fill(Diff(0, -1, 0)))
        logging.debug('xyz = %d %d %d', lbound, i, z)
        for x in range(lbound + 1, rbound):
            logging.debug('xyz = %d %d %d', x, i, z)
            moves.append(SMove(Diff(1, 0, 0)))
            if model[Pos(x, i, z)]:
                moves.append(Fill(Diff(0, -1, 0)))
        moves.extend(move_x(-1 * (rbound - lbound - 1)))
        moves.append(SMove(Diff(
            0, 0, 1)))  # TODO: optimise this part, make an L move
    moves.extend(move_z(-1 * (model.R - 2 + last_layer)))
    return moves
Ejemplo n.º 18
0
    def fork_and_move_new(seeds, space_right):
        if not seeds: return []
        #logger.debug('space_right = %d', space_right)

        # Each bot gets its own strip
        bots = 1 + len(seeds)
        #logger.debug('Bots = %d', bots)
        strip_width = floor(space_right / bots)
        #logger.debug('Strip width = %d', strip_width)
        strips.append(strip_width)
        nonlocal strips_sum
        strips_sum += strip_width

        ticks = []

        # fork right giving them all our seeds
        ticks.append([Fission(Diff(1, 0, 0), len(seeds) - 1)])

        # move the new bot to its position
        ticks.extend(wait_for(sequential(move_x(strip_width - 1))))

        # Let the new bot do the same
        ticks.extend(
            wait_for(fork_and_move_new(seeds[1:], space_right - strip_width)))

        return ticks
Ejemplo n.º 19
0
def deploy_cube(model, x, y, z, width, height, depth):
    prog7  = move_z(depth) + spawn_down(model, x + (width-1), y, z + (depth+1)) + \
             (single() // drill_down(model, x + (width-1), y-1, z + (depth+1), height-1))

    prog57 = move_x(width-2) + spawn_down(model, x + (width-1), y, z) + \
             (+single(Fission(Diff(0,0,1), 1)) // single()) + \
             (single() // move_y(-height+1) // prog7)

    prog3  = move_z(depth) + spawn_down(model, x, y, z + (depth+1)) + \
             (single() // drill_down(model, x, y - 1, z + (depth+1), height-1))

    prog1  = +single(Fission(Diff(0,-1,0), 0)) + \
             (+single(Fission(Diff(0,0,1), 1)) // single()) + \
             (+single(Fission(Diff(1,0,0), 3)) // single() // single()) + \
             (single() // move_y(-height+1) // prog3 // prog57)

    return prog1
Ejemplo n.º 20
0
def print_hyperrectangle(model, x, z, width, height, depth):
    prog = single()
    for i in range(height):
        last = i == height - 1
        prog += print_strip_below(model, i, x, z, x + width, depth, last)
        if not last:
            prog += single(SMove(Diff(0,1,0)))
    return prog
Ejemplo n.º 21
0
def test_illegal_smoves():
    em = Cpp.Emulator(set_cpp_state())

    # bot 2 moves out of bounds
    assert em.check_add_command(ctp(pc.Wait())) == ''
    msg = em.check_command(ctp(pc.SMove(Diff(0, 0, 3))))
    assert msg != ''

    # bot 2 moves through the filled area
    msg = em.check_command(ctp(pc.SMove(Diff(3, 0, 0))))
    assert msg != ''

    # ...
    c = ctp(pc.Wait())
    em.add_command(c)
    em.add_command(c)
    em.run_step()

    # bot 1 moves through bot 2
    msg = em.check_command(ctp(pc.SMove(Diff(0, 0, 3))))
    assert msg != ''

    # bot 2 moves through volatile area
    assert em.check_add_command(ctp(pc.Fill(Diff(0, 1, 1)))) == ''
    msg = em.check_command(ctp(pc.SMove(Diff(0, 1, 0))))
    assert msg != ''

    # bots 2 & 3 move freely
    assert em.check_add_command(ctp(pc.SMove(Diff(1, 0, 0)))) == ''
    assert em.check_add_command(ctp(pc.SMove(Diff(0, 4, 0)))) == ''
    assert em.steptrace_is_complete()
    em.run_step()
Ejemplo n.º 22
0
def encode_sld(v : Diff):
    assert v.is_short_linear()
    if v.dx:
        return 0b01_0000 | (v.dx + 5)
    if v.dy:
        return 0b10_0000 | (v.dy + 5)
    if v.dz:
        return 0b11_0000 | (v.dz + 5)
    assert False, f'Invalid sld: {v}'
Ejemplo n.º 23
0
def encode_lld(v : Diff):
    assert v.is_long_linear()
    if v.dx:
        return 0b010_0000 | (v.dx + 15)
    if v.dy:
        return 0b100_0000 | (v.dy + 15)
    if v.dz:
        return 0b110_0000 | (v.dz + 15)
    assert False, f'Invalid lld: {v}'
Ejemplo n.º 24
0
def fill_plot(model, model_height, plot):
    pos, plot_height = plot
    trace = []
    while True:
        for diff in eight_around_one_below(pos, model.R):
            if model[pos + diff]:
                trace.append(Fill(diff))
        if pos.y == plot_height:
            break
        else:
            shift = Diff(0, 1, 0)
            trace.append(SMove(shift))
            pos += shift

    if pos.y != model_height:
        shift = Diff(0, model_height - pos.y, 0)
        trace.extend(move_in_empty_space(shift))
        pos += shift
    return trace, pos
Ejemplo n.º 25
0
def bfs(m, src: 'Point', dst: 'Point'):
    weights = Matrix(m.R)
    sources = Matrix(m.R)

    queue = [src]
    weights[src] = 1
    while len(queue) and weights[dst] == 0:
        p = queue.pop(0)

        ds = [
            Diff(0, 1, 0),
            Diff(0, -1, 0),
            Diff(1, 0, 0),
            Diff(-1, 0, 0),
            Diff(0, 0, 1),
            Diff(0, 0, -1)
        ]
        for d in ds:
            nxt = p + d
            if nxt.is_inside_matrix(m.R) and not m[nxt] and not weights[nxt]:
                queue.append(nxt)
                weights[nxt] = weights[p] + 1
                sources[nxt] = p

    if weights[dst] == 0:
        return None
    else:
        res = []
        p = dst
        while p != src:
            res.insert(0, p)
            p = sources[p]
        return res
Ejemplo n.º 26
0
def lld_table():
    for i in range(1, 16):
        yield Diff( i,  0,  0)
        yield Diff(-i,  0,  0)
        yield Diff( 0,  i,  0)
        yield Diff( 0, -i,  0)
        yield Diff( 0,  0,  i)
        yield Diff( 0,  0, -i)
Ejemplo n.º 27
0
def nearby_voxel(voxel: 'Pos'):
    '''
    Compute a voxel near enough to the requested voxel so that `Fill`ing it is possible
    but not *on* the requested voxel (as a bot cannot `Fill` the voxel it is occupying).

    Right now, just the voxel's top neighbor. This will most likely need to change, as that voxel
    may already be full or may have another bot there. Can actually be any voxel within a near
    coordinate difference (nd) of the requested one.
    '''
    
    #TODO: detect a voxel near the requested one that is not occupied by an already-filled
    #      voxel or another bot

    return voxel + Diff(0, 1, 0)
Ejemplo n.º 28
0
def solve(source, target):
    state = State(source, target)

    state.bots[0].command = Fission(Diff(1, 0, 0), 20)
    state.tick()

    state.bots[0].command = Fill(Diff(0, 1, 0))
    state.bots[1].command = SMove(Diff(0, 1, 0))
    state.tick()

    state.bots[1].command = Void(Diff(-1, 0, 0))
    state.tick()

    state.bots[0].fuse(state.bots[1])
    state.tick()

    pprint(state.bots)

    state.bots[0].command = Halt()
    state.tick()

    print(state.correct())
    pprint(state.trace)
    return state.dump_trace()
Ejemplo n.º 29
0
def drill_down(model, x, y, z, depth) -> GroupProgram:
    prog = single()

    while depth > 0:
        if model[Pos(x, y - 1, z)]:
            prog += single(Void(Diff(0, -1, 0)))

        step = 1
        for i in range(2, depth + 1):
            if model[Pos(x, y - i, z)]:
                break
            else:
                step += 1
        prog += move_y(-step)
        y -= step
        depth -= step
    return prog
Ejemplo n.º 30
0
def collapse_cube(width, height, depth):
    # Move 2 up to 1 (4 to 3, 6 to 5, 8 to 7)
    prog_contract_up = (single() // move_y(height - 1)) + -(
        single(FusionP(Diff(0, -1, 0))) // single(FusionS(Diff(0, 1, 0))))
    # Move 3 back to 1 (7 to 5)
    prog_contract_back = (single() // move_z(-depth)) + -(
        single(FusionP(Diff(0, 0, 1))) // single(FusionS(Diff(0, 0, -1))))
    # Move 5 left to 1
    prog_contract_left = (single() // move_x(-width + 2)) + -(
        single(FusionP(Diff(1, 0, 0))) // single(FusionS(Diff(-1, 0, 0))))

    return (prog_contract_up**4) + (prog_contract_back**2) + prog_contract_left