Example #1
0
def test_matrix():
    name = 'LA004_tgt.mdl'
    data = data_files.lightning_problem(name)
    m = Matrix.parse(data)
    assert m.R == 20

    print(f'Central vertical slice of {name}')
    print('with a blip in the bottom left corner')
    print('and a hole in the middle')
    x = m.R // 2

    m0 = Matrix(m)
    assert m0 == m
    assert m.num_full == 559
    m[Pos(m.R // 2, 1, 1)] = True
    assert m.num_full == 560
    assert m0 != m
    m[Pos(m.R // 2, 4, 8)] = False
    assert m.num_full == 559

    for y in reversed(range(m.R)):
        s = []
        for z in range(m.R):
            if m[Pos(x, y, z)]:
                s.append('*')
            else:
                s.append('.')
        print(' '.join(s))

    assert m.count_inside_region(Pos(0, 0, 0), Pos(m.R - 1, m.R - 1,
                                                   m.R - 1)) == 559
Example #2
0
def test_pathfinding():
    matrix = [
        #   z
        #  ---->
        [
            [1, 0, 0],  # |
            [0, 1, 0],  # | y
            [0, 0, 0]
        ],  # v
        # x = 0
        [[0, 0, 0], [0, 0, 0], [1, 1, 1]],
        # x = 1
        [[0, 0, 1], [0, 1, 1], [0, 0, 0]],
        # x = 2
    ]
    m = Matrix(3)
    for x, slice in enumerate(matrix):
        for y, row in enumerate(slice):
            for z, cell in enumerate(row):
                m[Pos(x, y, z)] = bool(cell)

    dst, path = cpp.path_to_nearest_of(m, Pos(0, 0, 1), [Pos(0, 0, 1)])
    assert dst == Pos(0, 0, 1)
    assert path == []

    dst, path = cpp.path_to_nearest_of(m, Pos(0, 0, 1), [Pos(0, 2, 1)])
    assert dst == Pos(0, 2, 1)
    assert len(path) == 2
    for cmd in path:
        print(cmd_from_cpp(cmd))

    assert cpp.path_to_nearest_of(m, Pos(0, 0, 1), [Pos(100, 0, 0)]) is None
Example #3
0
def test_safe_to_change():
    matrix = [
        #   z
        #  ---->
        [
            [1, 0, 0],  # |
            [1, 1, 0],  # | y
            [0, 0, 0]
        ],  # v
        # x = 0
        [[0, 0, 0], [0, 0, 0], [0, 0, 0]],
        # x = 1
        [[0, 0, 0], [0, 0, 0], [0, 0, 0]],
        # x = 2
    ]
    m = Matrix(3)
    for x, slice in enumerate(matrix):
        for y, row in enumerate(slice):
            for z, cell in enumerate(row):
                m[Pos(x, y, z)] = bool(cell)
    m0 = Matrix(m)

    assert cpp.safe_to_change(m, Pos(0, 0, 1))
    assert m == m0
    assert cpp.safe_to_change(m, Pos(2, 0, 1))
    assert m == m0
    assert cpp.safe_to_change(m, Pos(0, 1, 1))
    assert m == m0
    assert not cpp.safe_to_change(m, Pos(0, 1, 0))
    assert m == m0
    assert cpp.safe_to_change(m, Pos(0, 2, 1))
    assert m == m0
    assert not cpp.safe_to_change(m, Pos(2, 2, 2))
    assert m == m0
def process_command(state, bot, cmd) -> Tuple[Set[Pos], Callable[..., None]]:
    '''Checks preconditions and returns (volatile set, effect) pair.'''
    c = bot.pos
    if isinstance(cmd, Halt):
        if c != Pos(0, 0, 0):
            raise PreconditionError()
        if len(state.bots) != 1:
            raise PreconditionError()
        if state.harmonics != LOW:
            raise PreconditionError()

        def effect():
            state.bots = []

        return {c}, effect

    elif isinstance(cmd, Wait):

        def effect():
            pass

        return {c}, effect

    elif isinstance(cmd, Flip):

        def effect():
            if state.harmonics == HIGH:
                state.harmonics = LOW
            elif state.harmonics == LOW:
                state.harmonics = HIGH
            else:
                assert state.harmonics

        return {c}, effect

    elif isinstance(cmd, SMove):
        assert cmd.lld.is_long_linear()
        c1 = c + cmd.lld
        if not c1.is_inside_matrix(state.R):
            raise PreconditionError()
        vol = set(enum_region_cells(c, c1))
        for p in vol:
            if state[p] != 0:
                raise PreconditionError()

        def effect():
            bot.pos = c1
            state.energy += 2 * cmd.lld.mlen()

        return vol, effect

    elif isinstance(cmd, LMove):
        assert cmd.sld1.is_short_linear()
        assert cmd.sld2.is_short_linear()
        c1 = c + cmd.sld1
        c2 = c1 + cmd.sld2
        if not c1.is_inside_matrix(state.R):
            raise PreconditionError()
        if not c2.is_inside_matrix(state.R):
            raise PreconditionError()
        vol = set(enum_region_cells(c, c1)) + set(enum_region_cells(c1, c2))
        for p in vol:
            if state[p] != 0:
                raise PreconditionError()

        def effect():
            bot.pos = c2
            state.energy += 2 * (cmd.sld1.mlen() + 2 + cmd.sld2.mlen())

        return vol, effect

    elif isinstance(cmd, Fission):
        assert cmd.nd.is_near()
        assert bot.seeds
        c1 = c + cmd.nd
        if not c1.is_inside_matrix(state.R):
            raise PreconditionError()
        if state[c1] != 0:
            raise PreconditionError()
        if len(bot.seeds) < m + 1:
            raise PreconditionError()
        bot.seeds.sort()

        def effect():
            new_bot = Bot(bid=bot.seeds[0], pos=c1, seeds=bot.seeds[1:m + 1])
            bot.seeds = bot.seeds[m + 1:]
            state.bots.append(new_bot)
            state.energy += 24

        return {c, c1}, effect

    elif isinstance(cmd, Fill):
        assert cmd.nd.is_near()
        c1 = c + cmd.nd
        if not c1.is_inside_matrix(state.R):
            raise PreconditionError()

        def effect():
            if state[c1] == 0:
                state[c1] = 1
                state.energy += 12
            elif state[c1] == 1:
                state.energy += 6

        return {c, c1}, effect

    elif isinstance(cmd, FusionP):
        raise NotImplementedError()  # TODO

    elif isinstance(cmd, FusionS):
        raise NotImplementedError()  # TODO

    else:
        assert False, cmd
 def __init__(self, R):
     self.R = R
     self.matrix = Model(R)
     self.harmonics = LOW
     self.energy = 0
     self.bots = [Bot(1, Pos(0, 0, 0), list(range(39)))]  # TODO
def enum_region_cells(c1: Pos, c2: Pos):
    for x in range(min(c1.x, c2.x), max(c1.x, c2.x) + 1):
        for y in range(min(c1.y, c2.y), max(c1.y, c2.y) + 1):
            for z in range(min(c1.z, c2.z), max(c1.z, c2.z) + 1):
                yield Pos(x, y, z)
Example #7
0
def test_pack():
    p = Pos(1, 2, 3)
    assert Pos.unpack(10, p.pack(10)) == p
Example #8
0
    def solve(self, name: str, src_model: Optional[bytes],
              tgt_model: Optional[bytes]) -> SolverResult:
        if src_model is not None:
            src_model = Matrix.parse(src_model)
        if tgt_model is not None:
            tgt_model = Matrix.parse(tgt_model)
        if src_model is None:
            src_model = Matrix(tgt_model.R)
        if tgt_model is None:
            tgt_model = Matrix(src_model.R)

        logger.info((src_model, tgt_model))

        R = src_model.R

        cur_model = Matrix(src_model)

        trace = []
        bot_pos = Pos(0, 0, 0)
        logger.info(f'R = {R}')

        while cur_model != tgt_model:
            changed = False
            for nd in cpp.enum_near_diffs():
                p = bot_pos + nd
                if not p.is_inside(R):
                    continue
                if cur_model[p] == tgt_model[p]:
                    continue
                if not cpp.safe_to_change(cur_model, p):
                    continue
                if cur_model[p]:
                    trace.append(cpp.Void(nd))
                    cur_model[p] = False
                else:
                    trace.append(cpp.Fill(nd))
                    cur_model[p] = True
                changed = True
                break
            if changed:
                continue

            p = cpp.path_to_nearest_safe_change_point(cur_model, bot_pos,
                                                      cur_model, tgt_model)
            if p is None:
                return SolverResult(Pass(),
                                    extra=dict(msg='no reachable targets'))

            target, path = p
            for cmd in path:
                trace.append(cmd)
                bot_pos += cmd.move_offset()
            assert bot_pos == target

        # get back
        p = cpp.path_to_nearest_of(cur_model, bot_pos, [Pos(0, 0, 0)])
        if p is None:
            return SolverResult(Fail(),
                                extra=dict(msg="done but can't reach exit"))
        trace.extend(p[1])
        trace.append(cpp.Halt())

        trace = [cmd_from_cpp(cmd) for cmd in trace]
        trace = commands.compose_commands(trace)
        return SolverResult(trace)
Example #9
0
 def __iter__(self):
     for x in range(self.pos_min.x, self.pos_max.x + 1):
         for y in range(self.pos_min.y, self.pos_max.y + 1):
             for z in range(self.pos_min.z, self.pos_max.z + 1):
                 yield Pos(x, y, z)
Example #10
0
 def __init__(self, pos1: Pos, pos2: Pos):
     self.pos_min = pos1.min(pos2)
     self.pos_max = pos1.max(pos2)