def perform(level, box, options):
	forward_offset = options['Forward offset']
	right_offset = options['Right offset']
	up_offset = options['Up offset']
	relative_position = options['Relative position']
	generate_surrounding_box = options['Generate surrounding box']
	if generate_surrounding_box:
		forward_offset += 1
		up_offset += 1
	if relative_position == 'North':
		execution_center = ((box.minx + box.maxx) // 2 - right_offset, box.miny - up_offset + 2, box.maxz + forward_offset - 1)
	elif relative_position == 'East':
		execution_center = (box.minx - forward_offset, box.miny - up_offset + 2, (box.minz + box.maxz) // 2 - right_offset)
	elif relative_position == 'South':
		execution_center = ((box.minx + box.maxx) // 2 + right_offset, box.miny - up_offset + 2, box.minz - forward_offset)
	elif relative_position == 'West':
		execution_center = (box.maxx + forward_offset - 1, box.miny - up_offset + 2, (box.minz + box.maxz) // 2 + right_offset)
	include_air = options['Include air']
	include_blocks = options['Include blocks']
	include_null_block_data = options['Include null block data']
	include_entities = options['Include entities']
	include_commandblockoutput_command = options['Include "gamerule commandBlockOutput false" command']
	include_logadmincommands_command = options['Include "gamerule logAdminCommands false" command']
	add_initialization_commands = options['Add initialization commands']
	add_finalization_commands = options['Add finalization commands']
	block_to_enqueue_input = re.split(r'\s*,\s*', options['Blocks to enqueue'].strip())
	blocks_to_enqueue = []
	for block_id in xrange(0, len(materials.block_map) - 1):
		if materials.block_map[block_id] in block_to_enqueue_input:
			blocks_to_enqueue.append(block_id)
	nbt_tags_to_ignore = re.split(r'\s*,\s*', options['NBT tags to ignore']) + ['x', 'y', 'z']
	save_command_to_file = options['Save the command to a file instead of to a Command Block']
	ignore_maximum_command_block_command_length = options['Ignore maximum Command Block command length']
	box_wall_material_block = options['Box wall material block']
	box_wall_material_data = options['Box wall material data value']
	box_floor_material_block = options['Box floor material block']
	box_floor_material_data = options['Box floor material data value']
	box_ceiling_material_block = options['Box ceiling material block']
	box_ceiling_material_data = options['Box ceiling material data value']
	add_box_signs = options['Add box signs']

	add_credits = True

	command = 'summon minecraft:falling_block ~ ~1 ~ {id:"minecraft:falling_block",Block:"minecraft:redstone_block",Time:1,Passengers:[{id:"minecraft:falling_block",Block:"minecraft:activator_rail",Time:1,Passengers:['
	unformatted_command = command
	first_element = True

	if include_commandblockoutput_command:
		command_part = '{id:"minecraft:commandblock_minecart",Command:"gamerule commandBlockOutput false"}'
		command += '\n\t' + command_part
		unformatted_command += command_part
		first_element = False

	if include_logadmincommands_command:
		if not first_element:
			command += ','
			unformatted_command += ','
		first_element = False
		command_part = '{id:"minecraft:commandblock_minecart",Command:"gamerule logAdminCommands false"}'
		command += '\n\t' + command_part
		unformatted_command += command_part

	if add_initialization_commands:
		file = mcplatform.askOpenFile('Select the text file containing the initialization commands...', False, ['txt'])
		if file is not None:
			input = open(file)
			if input is not None:
				for line in input.read().splitlines():
					if not first_element:
						command += ','
						unformatted_command += ','
					first_element = False
					command_part = '{id:"minecraft:commandblock_minecart",Command:"' + escape_string(line) + '"}'
					command += '\n\t' + command_part
					unformatted_command += command_part
				input.close()

	if include_blocks:
		if include_air:
			air_blocks = []
			for x in xrange(box.minx, box.maxx):
				air_blocks.append([])
				for y in xrange(box.miny, box.maxy):
					air_blocks[x - box.minx].append([])
					for z in xrange(box.minz, box.maxz):
						air_blocks[x - box.minx][y - box.miny].append(True)
			for cuboid in subdivide_in_cuboids(air_blocks, 32768, False, True, False):
				if not first_element:
					command += ','
					unformatted_command += ','
				first_element = False
				if volume(cuboid[0][0], cuboid[0][1], cuboid[0][2], cuboid[1][0], cuboid[1][1], cuboid[1][2]) == 1:
					command_part = '{id:"minecraft:commandblock_minecart",Command:"setblock ~' + str(cuboid[0][0] + box.minx - execution_center[0]) + ' ~' + str(cuboid[0][1] + box.miny - execution_center[1]) + ' ~' + str(cuboid[0][2] + box.minz - execution_center[2]) + ' minecraft:air'
				else:
					command_part = '{id:"minecraft:commandblock_minecart",Command:"fill ~' + str(cuboid[0][0] + box.minx - execution_center[0]) + ' ~' + str(cuboid[0][1] + box.miny - execution_center[1]) + ' ~' + str(cuboid[0][2] + box.minz - execution_center[2]) + ' ~' + str(cuboid[1][0] + box.minx - execution_center[0]) + ' ~' + str(cuboid[1][1] + box.miny - execution_center[1]) + ' ~' + str(cuboid[1][2] + box.minz - execution_center[2]) + ' minecraft:air'
				if include_null_block_data:
					command_part += ' 0'
				command_part += '"}'
				command += '\n\t' + command_part
				unformatted_command += command_part

		blocks = []
		for x in xrange(box.minx, box.maxx):
			blocks.append([])
			for y in xrange(box.miny, box.maxy):
				blocks[x - box.minx].append([])
				for z in xrange(box.minz, box.maxz):
					blocks[x - box.minx][y - box.miny].append((level.blockAt(x, y, z), level.blockDataAt(x, y, z), level.tileEntityAt(x, y, z)))
		enqueued = []
		for x in xrange(0, len(blocks)):
			for y in xrange(0, len(blocks[x])):
				for z in xrange(0, len(blocks[x][y])):
					block = blocks[x][y][z]
					if block[0] >= 1:
						for cuboid in subdivide_in_cuboids(blocks, 32768, False, block, (-1, 0, None)):
							if volume(cuboid[0][0], cuboid[0][1], cuboid[0][2], cuboid[1][0], cuboid[1][1], cuboid[1][2]) == 1:
								command_part = '{id:"minecraft:commandblock_minecart",Command:"setblock ~' + str(cuboid[0][0] + box.minx - execution_center[0]) + ' ~' + str(cuboid[0][1] + box.miny - execution_center[1]) + ' ~' + str(cuboid[0][2] + box.minz - execution_center[2]) + ' ' + materials.block_map[block[0]]
							else:
								command_part = '{id:"minecraft:commandblock_minecart",Command:"fill ~' + str(cuboid[0][0] + box.minx - execution_center[0]) + ' ~' + str(cuboid[0][1] + box.miny - execution_center[1]) + ' ~' + str(cuboid[0][2] + box.minz - execution_center[2]) + ' ~' + str(cuboid[1][0] + box.minx - execution_center[0]) + ' ~' + str(cuboid[1][1] + box.miny - execution_center[1]) + ' ~' + str(cuboid[1][2] + box.minz - execution_center[2]) + ' ' + materials.block_map[block[0]]
							if include_null_block_data or block[1] != 0 or (block[1] == 0 and block[2] is not None):
								command_part += ' ' + str(block[1])
							if block[2] is not None:
								command_part += ' replace ' + escape_string(nbt_to_string(block[2], nbt_tags_to_ignore))
							command_part += '"}'
							if block[0] not in blocks_to_enqueue:
								if not first_element:
									command += ','
									unformatted_command += ','
								first_element = False
								command += '\n\t' + command_part
								unformatted_command += command_part
							else:
								enqueued.append(command_part)
		for enqueued_command in enqueued:
			if not first_element:
				command += ','
				unformatted_command += ','
			first_element = False
			command += '\n\t' + enqueued_command
			unformatted_command += enqueued_command

	if include_entities:
		for (chunk, slices, point) in level.getChunkSlices(box):
			for entity in chunk.Entities:
				entity_x = entity['Pos'][0].value
				entity_y = entity['Pos'][1].value
				entity_z = entity['Pos'][2].value
				if (entity_x, entity_y, entity_z) in box:
					if not first_element:
						command += ','
						unformatted_command += ','
					first_element = False
					command_part = '{id:"minecraft:commandblock_minecart",Command:"summon ' + str(entity['id'].value) + ' ~' + str((Decimal(entity_x - execution_center[0]) - Decimal('0.5')).normalize()) + ' ~' + str((Decimal(entity_y - execution_center[1]) - Decimal('0.0625')).normalize()) + ' ~' + str((Decimal(entity_z - execution_center[2]) - Decimal('0.5')).normalize()) + ' ' + escape_string(nbt_to_string(entity, nbt_tags_to_ignore)) + '"}'
					command += '\n\t' + command_part
					unformatted_command += command_part

	if generate_surrounding_box:
		if volume(box.minx - 1, box.miny - 1, box.minz - 1, box.maxx, box.maxy, box.maxz) <= 32768:
			if not first_element:
				command += ','
				unformatted_command += ','
			first_element = False
			command_part = '{id:"minecraft:commandblock_minecart",Command:"fill ~' + str(box.minx - 1 - execution_center[0]) + ' ~' + str(box.miny - 1 - execution_center[1]) + ' ~' + str(box.minz - 1 - execution_center[2]) + ' ~' + str(box.maxx - execution_center[0]) + ' ~' + str(box.maxy - execution_center[1]) + ' ~' + str(box.maxz - execution_center[2]) + ' ' + escape_string(box_wall_material_block) + ' ' + str(box_wall_material_data) + ' outline"}'
			command += '\n\t' + command_part
			unformatted_command += command_part
		else:
			wall_blocks = []
			for x in xrange(0, box.maxx - box.minx + 2):
				wall_blocks.append([])
				for y in xrange(0, box.maxy - box.miny):
					wall_blocks[x].append([])
					for z in xrange(0, box.maxz - box.minz + 2):
						if x == 0 or x == box.maxx - box.minx + 1 or z == 0 or z == box.maxz - box.minz + 1:
							wall_blocks[x][y].append(True)
						else:
							wall_blocks[x][y].append(False)
			for cuboid in subdivide_in_cuboids(wall_blocks, 32768, False, True, False):
				if not first_element:
					command += ','
					unformatted_command += ','
				first_element = False
				command_part = '{id:"minecraft:commandblock_minecart",Command:"fill ~' + str(cuboid[0][0] - 1 + box.minx - execution_center[0]) + ' ~' + str(cuboid[0][1] + box.miny - execution_center[1]) + ' ~' + str(cuboid[0][2] - 1 + box.minz - execution_center[2]) + ' ~' + str(cuboid[1][0] - 1 + box.minx - execution_center[0]) + ' ~' + str(cuboid[1][1] + box.miny - execution_center[1]) + ' ~' + str(cuboid[1][2] - 1 + box.minz - execution_center[2]) + ' ' + escape_string(box_wall_material_block)
				if include_null_block_data or box_wall_material_data != 0:
					command_part += ' ' + str(box_wall_material_data)
				command_part += '"}'
				command += '\n\t' + command_part
				unformatted_command += command_part

		if add_box_signs:
			file = mcplatform.askOpenFile('Select the text file containing the signs to put on front of the box...', False, ['txt'])
			if file is not None:
				input = open(file)
				if input is not None:
					signs = OrderedDict()
					signs_line = 0
					coordinate = (0, 0)
					for line in input.read().splitlines():
						if signs_line == 0:
							if line != '':
								coordinates = re.split(r'\s*,\s*', line.strip())
								coordinate = (int(coordinates[0]), int(coordinates[1]))
								signs[coordinate] = []
								signs_line += 1
						else:
							signs[coordinate].append(line)
							signs_line += 1
						if signs_line == 9:
							signs_line = 0

					for coordinate, sign in signs.items():
						if relative_position == 'North':
							world_coordinate = (box.minx - 1 + coordinate[0] - execution_center[0], box.miny - 1 + coordinate[1] - execution_center[1], box.maxz + 1 - execution_center[2])
							sign_data = 3
						elif relative_position == 'East':
							world_coordinate = (box.minx - 2 - execution_center[0], box.miny - 1 + coordinate[1] - execution_center[1], box.minz - 1 + coordinate[0] - execution_center[2])
							sign_data = 4
						elif relative_position == 'South':
							world_coordinate = (box.maxx - coordinate[0] - execution_center[0], box.miny - 1 + coordinate[1] - execution_center[1], box.minz - 2 - execution_center[2])
							sign_data = 2
						else:
							world_coordinate = (box.maxx + 1 - execution_center[0], box.miny - 1 + coordinate[1] - execution_center[1], box.maxz - coordinate[0] - execution_center[2])
							sign_data = 5

						if not first_element:
							command += ','
							unformatted_command += ','
						first_element = False
						command_part = '{id:"minecraft:commandblock_minecart",Command:"setblock ~' + str(world_coordinate[0]) + ' ~' + str(world_coordinate[1]) + ' ~' + str(world_coordinate[2]) + ' minecraft:wall_sign ' + str(sign_data) + ' replace {'
						for i in xrange(0, min(4, len(sign))):
							sign_text = sign[i]
							sign_command = sign[i + 4] if len(sign) > i + 4 and len(sign[i + 4]) > 0 else ''
							if i > 0:
								command_part += ','
							command_part += 'Text' + str(i + 1) + r':\"'
							if sign_text.startswith('{'):
								if sign_command != '':
									command_part += escape_string(escape_string('{"text":"","extra":[' + sign_text + ']'))
								else:
									command_part += escape_string(escape_string(sign_text))
							elif sign_text.startswith('['):
								if sign_command != '':
									command_part += escape_string(escape_string('{"text":"","extra":' + sign_text))
								else:
									command_part += escape_string(escape_string(sign_text))
							elif sign_text.startswith('"'):
								if sign_command != '':
									command_part += escape_string(escape_string('{"text":' + sign_text))
								else:
									command_part += escape_string(escape_string(sign_text))
							else:
								if sign_command != '':
									command_part += escape_string(escape_string('{"text":"' + escape_string(sign_text) + '"'))
								else:
									command_part += escape_string(escape_string('"' + sign_text + '"'))
							if sign_command != '':
								command_part += escape_string(escape_string(',"clickEvent":{"action":"run_command","value":"' + escape_string(sign_command) + '"}}'))
							command_part += r'\"'
						command_part += '}"}'
						command += '\n\t' + command_part
						unformatted_command += command_part

		floor_ceiling_blocks = []
		for x in xrange(0, box.maxx - box.minx + 2):
			floor_ceiling_blocks.append([])
			floor_ceiling_blocks[x].append([])
			for z in xrange(0, box.maxz - box.minz + 2):
				floor_ceiling_blocks[x][0].append(True)
		for cuboid in subdivide_in_cuboids(floor_ceiling_blocks, 32768, False, True, False):
			if not first_element:
				command += ','
				unformatted_command += ','
			first_element = False
			command_part = '{id:"minecraft:commandblock_minecart",Command:"fill ~' + str(cuboid[0][0] - 1 + box.minx - execution_center[0]) + ' ~' + str(cuboid[0][1] - 1 + box.miny - execution_center[1]) + ' ~' + str(cuboid[0][2] - 1 + box.minz - execution_center[2]) + ' ~' + str(cuboid[1][0] - 1 + box.minx - execution_center[0]) + ' ~' + str(cuboid[1][1] - 1 + box.miny - execution_center[1]) + ' ~' + str(cuboid[1][2] - 1 + box.minz - execution_center[2]) + ' ' + escape_string(box_floor_material_block)
			if include_null_block_data or box_floor_material_data != 0:
				command_part += ' ' + str(box_floor_material_data)
			command_part += '"}'
			command += '\n\t' + command_part
			unformatted_command += command_part

			command_part = '{id:"minecraft:commandblock_minecart",Command:"fill ~' + str(cuboid[0][0] - 1 + box.minx - execution_center[0]) + ' ~' + str(cuboid[0][1] + box.maxy - execution_center[1]) + ' ~' + str(cuboid[0][2] - 1 + box.minz - execution_center[2]) + ' ~' + str(cuboid[1][0] - 1 + box.minx - execution_center[0]) + ' ~' + str(cuboid[1][1] + box.maxy - execution_center[1]) + ' ~' + str(cuboid[1][2] - 1 + box.minz - execution_center[2]) + ' ' + escape_string(box_ceiling_material_block)
			if include_null_block_data or box_ceiling_material_data != 0:
				command_part += ' ' + str(box_ceiling_material_data)
			command_part += '"}'
			command += ',\n\t' + command_part
			unformatted_command += ',' + command_part

	if add_finalization_commands:
		file = mcplatform.askOpenFile('Select the text file containing the finalization commands...', False, ['txt'])
		if file is not None:
			input = open(file)
			if input is not None:
				for line in input.read().splitlines():
					if not first_element:
						command += ','
						unformatted_command += ','
					first_element = False
					command_part = '{id:"minecraft:commandblock_minecart",Command:"' + escape_string(line) + '"}'
					command += '\n\t' + command_part
					unformatted_command += command_part
				input.close()

	if add_credits:
		if not first_element:
			command += ','
			unformatted_command += ','
		first_element = False
		command_part = '{id:"minecraft:commandblock_minecart",Command:"' + escape_string('tellraw @p {"color":"yellow","text":"Generated with Mamo\'s ","extra":[{"color":"blue","underlined":true,"text":"Structure spawner generator","clickEvent":{"action":"open_url","value":"https://github.com/xMamo/Structure-spawner-generator"},"hoverEvent":{"action":"show_text","value":"Click here if you want this filter too!"}},"."]}') + '"}'
		command += '\n\t' + command_part
		unformatted_command += command_part

	if not first_element:
		command += ','
		unformatted_command += ','
	command_part = r'{id:"minecraft:commandblock_minecart",Command:"setblock ~ ~1 ~ minecraft:command_block 0 replace {auto:1b,Command:\"fill ~ ~-3 ~ ~ ~ ~ minecraft:air'
	if include_null_block_data:
		command_part += ' 0'
	command_part += r'\"}"}'
	command += '\n\t' + command_part
	unformatted_command += command_part
	command_part = '{id:"minecraft:commandblock_minecart",Command:"kill @e[type=minecraft:commandblock_minecart,r=0]"}'
	command += ",\n\t" + command_part + '\n]}]}'
	unformatted_command += "," + command_part + ']}]}'

	if not ignore_maximum_command_block_command_length and len(unformatted_command) > 32500:
		editor.Notify('Unfortunately no command could be generated, as it would be longer than the Command Block command length limit of 32500 characters.')
		return

	command_output = None
	if save_command_to_file:
		output_file = mcplatform.askSaveFile(None, 'Select the text file to which you want to save the command...', 'command.txt', 'Text file (*.txt)\0*.txt\0\0', None)
		if output_file is not None:
			command_output = open(output_file, mode = 'w')

	if save_command_to_file and command_output is not None:
		command_output.write((command + '\n').encode('UTF-8'))
		command_output.flush()
		command_output.close()
	else:
		schematic = MCSchematic((1, 1, 1), None, None, level.materials)
		schematic.setBlockAt(0, 0, 0, 137)
		command_block = TAG_Compound()
		command_block['id'] = TAG_String('minecraft:command_block')
		command_block['x'] = TAG_Int(0)
		command_block['y'] = TAG_Int(0)
		command_block['z'] = TAG_Int(0)
		command_block['Command'] = TAG_String(unformatted_command)
		schematic.addTileEntity(command_block)
		editor.addCopiedSchematic(schematic)
示例#2
0
def generate(comb_equation,
             use_input_color_key=None,
             use_output_color_key=None):

    inputs = comb_equation.inputs
    minterms = comb_equation.minterms

    form = form_tall if len(minterms) > 5 else form_short
    formBox = formBox_tall if len(minterms) > 5 else formBox_short
    implicantLimit = 13 if len(minterms) > 5 else 5

    while len(minterms) % implicantLimit != 0:
        minterms.append({})

    numXCopies = int(math.ceil(len(inputs) / 4))
    sizeX = numXCopies * form.Width + 2
    numYCopies = int(math.ceil(len(minterms) / implicantLimit))
    sizeY = numYCopies * form.Height + 3
    sizeZ = form.Length + 1

    #    print sizeX, sizeY, sizeZ

    level = MCSchematic(shape=(sizeX, sizeY, sizeZ))
    box = BoundingBox((0, 0, 0), (sizeX, sizeY, sizeZ))

    # ================================================================================================

    # Paste the schematic the number of times we know we'll need

    pasteX = 0
    for i in range(numXCopies):
        pasteY = 1
        for i in range(numYCopies):
            level.copyBlocksFrom(form, formBox, (pasteX, pasteY, 0))
            pasteY += form.Height
        pasteX += form.Width

    # Fill the bottom plane with a ground

    # level.fillBlocks(BoundingBox((0, 0, 0), (sizeX, 1, sizeZ)), alphaMaterials.BlockofIron)

    # Build X-ways across each row corresponding to each term

    cx = 0
    cy = 2
    cz = 1
    numTerms = 0
    side = CLOSE_SIDE

    relative_input_locations = {}

    for termIndex in range(len(minterms)):

        term = minterms[termIndex]

        cx = 0
        for i in inputs:

            if i in term.keys():
                mat = TORCH if term[i] else REDSTONE
            else:
                mat = AIR

            data = TORCH_POINTING_NEG_Z if (cz == 1) else TORCH_POINTING_POS_Z

            level.setBlockAt(cx, cy, cz, mat)
            level.setBlockDataAt(cx, cy, cz, data)

            if termIndex == 0:
                sx = cx
                sy = cy - 2
                sz = cz + 4
                for iter_sz in [sz, sz + 1, sz + 2, sz + 3]:
                    level.setBlockAt(sx, sy, iter_sz, WOOL)
                    data = WOOL_BLACK if use_input_color_key == None else use_input_color_key[
                        i]
                    level.setBlockDataAt(sx, sy, iter_sz, data)

                relative_input_locations[i] = [sx, sy, sz + 2]

            cx += 2

        # Build the slice of the side scaffolding that goes on this row's height level:
        # -----------------------------------------------------------------------------
        prevCy = cy
        prevCz = cz

        cx = box.width - 2

        if side == CLOSE_SIDE:
            cz -= 1
            cy -= 1
        elif side == FAR_SIDE:
            cz += 1
            cy -= 1

        if len(term) > 0:
            level.setBlockAt(cx, cy, cz, TORCH)
            level.setBlockDataAt(cx, cy, cz, TORCH_POINTING_POS_X)

        cx += 1
        cy -= 1

        if numTerms in [0, 1]:
            level.setBlockAt(cx, cy, cz, DOUBLE_SLAB)
            level.setBlockDataAt(cx, cy, cz, DOUBLE_SLAB_STONE)
        else:
            level.setBlockAt(cx, cy, cz, SLAB)
            level.setBlockDataAt(cx, cy, cz, STONE_SLAB_TOP)

        cy += 1

        level.setBlockAt(cx, cy, cz, REDSTONE)

        if side == CLOSE_SIDE:
            cz += 1
        elif side == FAR_SIDE:
            cz -= 1

        level.setBlockAt(cx, cy, cz, SLAB)
        level.setBlockDataAt(cx, cy, cz, STONE_SLAB_TOP)

        cy += 1

        level.setBlockAt(cx, cy, cz, REDSTONE)

        if side == CLOSE_SIDE:
            currentCloseTowerTopY = cy
            currentCloseTowerTopZ = cz
        elif side == FAR_SIDE:
            currentFarTowerTopY = cy
            currentFarTowerTopZ = cz

        cy = prevCy
        cz = prevCz
        # -----------------------------------------------------------------------------

        # Switch sides

        side = FAR_SIDE if (side == CLOSE_SIDE) else CLOSE_SIDE

        # The z location alternates depending on the side

        if side == CLOSE_SIDE: cz = 1
        if side == FAR_SIDE: cz = 8

        # Keep track of the number of terms

        numTerms += 1

        # JUMP LOGIC
        # Normal case: cy goes up by one, we are working term by term up one paste of the schematic
        # Special case: We have done 13 terms, and need to 'jump' to the next paste of the schematic
        #    This requires some special connecting and bridging.

        # ------------------------------------------------------------------------------------------
        if numTerms == implicantLimit:

            sx = box.width - 1
            sy = currentCloseTowerTopY
            sz = currentCloseTowerTopZ

            sz += 1

            level.setBlockAt(sx, sy, sz, WOOL)
            level.setBlockDataAt(sx, sy, sz, WOOL_BLACK)

            sz += 1

            level.setBlockAt(sx, sy, sz, TORCH)
            level.setBlockDataAt(sx, sy, sz, TORCH_POINTING_POS_Z)

            sy += 1

            for itr_sz in [sz, sz - 1, sz - 2]:
                level.setBlockAt(sx, sy, itr_sz, WOOL)
                level.setBlockDataAt(sx, sy, itr_sz, WOOL_BLACK)

            sy += 1

            level.setBlockAt(sx, sy, sz, TORCH)
            level.setBlockDataAt(sx, sy, sz, TORCH_ON_GROUND)

            sz -= 1

            level.setBlockAt(sx, sy, sz, REDSTONE)

            sz -= 1

            level.setBlockAt(sx, sy, sz, REPEATER)

            # If we are finished with the whole thing, make the lead the exposes
            # The signal to the rest of the world

            if termIndex == len(minterms) - 1:

                sz += 2
                sy += 1

                data = WOOL_BLACK if use_output_color_key == None else use_output_color_key[
                    comb_equation.name]

                for iter_sz in range(sz, sz + 7, 1):
                    level.setBlockAt(sx, sy, iter_sz, WOOL)
                    level.setBlockDataAt(sx, sy, iter_sz, data)
                    sy += 1
                    level.setBlockAt(sx, sy, iter_sz, REDSTONE)
                    sy -= 1

                sz += 7

                level.setBlockAt(sx, sy, sz, WOOL)
                level.setBlockDataAt(sx, sy, sz, data)

                sy += 1

                level.setBlockAt(sx, sy, sz, REPEATER)
                level.setBlockDataAt(sx, sy, sz, REPEATER_TOWARD_POS_Z)

                lead_location = [sx, sy, sz]

            # -----------------------------------------------------

            sx = box.width - 1
            sy = currentFarTowerTopY
            sz = currentFarTowerTopZ

            sz -= 1

            level.setBlockAt(sx, sy, sz, WOOL)
            level.setBlockDataAt(sx, sy, sz, WOOL_BLACK)

            sy += 1

            level.setBlockAt(sx, sy, sz, 75)
            level.setBlockDataAt(sx, sy, sz, 5)

            sz += 1

            level.setBlockAt(sx, sy, sz, WOOL)
            level.setBlockDataAt(sx, sy, sz, WOOL_BLACK)

            sz -= 1
            sy += 1

            level.setBlockAt(sx, sy, sz, WOOL)
            level.setBlockDataAt(sx, sy, sz, WOOL_BLACK)

            sz += 1

            level.setBlockAt(sx, sy, sz, REDSTONE)

            sz += 1

            level.setBlockAt(sx, sy, sz, WOOL)
            level.setBlockDataAt(sx, sy, sz, WOOL_BLACK)

            sy += 1

            level.setBlockAt(sx, sy, sz, TORCH)
            level.setBlockDataAt(sx, sy, sz, TORCH_ON_GROUND)

            # Now reset the variables for working up the next paste:

            cy += 4
            numTerms = 0
            side = CLOSE_SIDE
            cz = 1

        else:

            cy += 1

#    level.setBlockAt(0, 0, 0, 20)
#    level.setBlockAt(box.width-1, box.height-1, box.length-1, 20)

#    # Flip the entire schematic around to help make the fitting routine more 'sane'
#    # Also adjust location variables (like the locations of the lead and inputs) to
#    # reflect the Z-flip
#
#    level.flipEastWest()
#    lead_location[2] = sizeZ - 1 - lead_location[2]
#    for ril in relative_input_locations.values():
#        ril[2] = sizeZ - 1 - ril[2]

#    level.setBlockAt(*lead_location, blockID = 35)
#    level.setBlockDataAt(*lead_location, newdata = 0)
#
#    for ril in relative_input_locations.values():
#        level.setBlockAt(*ril, blockID = GLASS)

    ret = CombinationalElement(level)
    ret.relative_output_locations = {comb_equation.name: lead_location}
    ret.relative_input_locations = relative_input_locations
    ret.size = (sizeX, sizeY, sizeZ)

    return ret
示例#3
0
def fit_elements(meta_input, element_list, OPTIONS):

    schematic_bufferX = 3
    #schematic_bufferZ = 4

    # Also, the schematics must be spaced out a certain length as well
    total_schematic_lengthX = sum(s.size[0] for s in element_list)
    sizeX = total_schematic_lengthX + schematic_bufferX * len(element_list) + 2

    sizeZ = element_list[0].size[2]
    sizeZ += 2 * max(len(meta_input.input_domain), len(
        meta_input.output_range)) + 6

    sizeY = max(s.size[1] for s in element_list) + 5

    level = MCSchematic(shape=(sizeX, sizeY, sizeZ))
    box = BoundingBox((0, 0, 0), (sizeX, sizeY, sizeZ))

    cx, cy, cz = 2, 0, 0

    schematic_origins = {}
    for s in element_list:

        schematic_origins[s] = [cx, cy, cz]

        level.copyBlocksFrom(s.schematic, BoundingBox((0, 0, 0), s.size),
                             (cx, cy, cz))

        cx += s.size[0] + schematic_bufferX

    # The schematics contain their own *relative* input locations in a dict of the form
    # input name --> (x, y, z). We wish to make a giant composite list of all the *absolute* locations
    # of the inputs, this time of the form (x, y, z) --> input name. We obtain the absolute
    # location by adding the individual schematic origin (in our coordinate system) with the
    # schematic's relative coordinate.

    absolute_input_locations = {}
    for s in element_list:
        for key, value in s.relative_input_locations.items():
            abs_loc = add_tuples(schematic_origins[s], value)
            absolute_input_locations[abs_loc] = key

    # The z value for all the input locations will be the same. We just need to grab an arbitrary
    # one and use it to define the starting z location for the input rails

    input_z = 5 + absolute_input_locations.keys()[0][2]
    input_rail_z_values = {}
    for i in meta_input.input_domain:
        input_rail_z_values[i] = input_z
        input_z += 2

    absolute_output_locations = {}
    for s in element_list:
        for key, value in s.relative_output_locations.items():
            abs_loc = add_tuples(schematic_origins[s], value)
            absolute_output_locations[abs_loc] = key

    output_z = 4 + absolute_output_locations.keys()[0][2]
    output_rail_z_values = {}
    for i in meta_input.output_range:
        output_rail_z_values[i] = output_z
        output_z += 2

    # Step through the input locations and build backward to to the point where it joins
    # up with the appropriate input rail. The rail will actually be built later.

    for input_loc, input_name in absolute_input_locations.items():

        cx, cy, cz = input_loc[0], input_loc[1], input_loc[2]

        cz += 1

        while (cz < input_rail_z_values[input_name] - 1):
            level.setBlockAt(cx, cy, cz, REDSTONE)
            cz += 1

        level.setBlockAt(cx, cy, cz, REPEATER)

        cz += 1
        level.setBlockAt(cx, cy, cz, WOOL)
        level.setBlockDataAt(cx, cy, cz,
                             meta_input.input_color_key[input_name])

        cy += 1
        level.setBlockAt(cx, cy, cz, REDSTONE)

    # Step through the output locations and build backward to to the point where it joins
    # up with the appropriate output rail. The rail will actually be built later.

    for output_loc, output_name in absolute_output_locations.items():

        if OPTIONS["make_output_rail"] == False:
            continue

        cx, cy, cz = output_loc[0], output_loc[1], output_loc[2]

        cz += 1

        while (cz < output_rail_z_values[output_name] - 1):
            level.setBlockAt(cx, cy, cz, REDSTONE)
            cy -= 1
            level.setBlockAt(cx, cy, cz, WOOL)
            level.setBlockDataAt(cx, cy, cz,
                                 meta_input.output_color_key[output_name])
            cy += 1
            cz += 1

        level.setBlockAt(cx, cy, cz, REPEATER)
        level.setBlockDataAt(cx, cy, cz, REPEATER_TOWARD_POS_Z)

        cy -= 1
        level.setBlockAt(cx, cy, cz, WOOL)
        level.setBlockDataAt(cx, cy, cz,
                             meta_input.output_color_key[output_name])
        cy += 1

        cz += 1
        level.setBlockAt(cx, cy, cz, WOOL)
        level.setBlockDataAt(cx, cy, cz,
                             meta_input.output_color_key[output_name])

        cy += 1
        level.setBlockAt(cx, cy, cz, REDSTONE)

    # Now build the input rails!

    for input_name, input_z_value in input_rail_z_values.items():
        cx, cy, cz = 0, 2, input_z_value
        while cx < sizeX:

            cy -= 1

            if level.blockAt(cx, cy, cz) != REDSTONE:
                level.setBlockAt(cx, cy, cz, WOOL)
                level.setBlockDataAt(cx, cy, cz,
                                     meta_input.input_color_key[input_name])
            level.setBlockAt(cx, cy, cz - 1, WOOL)
            level.setBlockDataAt(cx, cy, cz - 1, WOOL_BLACK)
            level.setBlockAt(cx, cy, cz + 1, WOOL)
            level.setBlockDataAt(cx, cy, cz + 1, WOOL_BLACK)

            cy += 1

            level.setBlockAt(cx, cy, cz, REDSTONE)

            cx += 1

    # We need to put repeaters on the input rail. There are multiple ways to do so. If POSSIBLE,
    # use the gap method. To do this we need to perform the following algorithm to find the
    # gaps inbetween inputs.

    # Find the x values of the 'gaps' between clusters
    # of inputs. These are nice open spots to put repeaters. The following is a 'find the gap'
    # algorithm that ends up with a list of x values where repeaters should be placed (rep_locs)

    # Get the x values of the inputs
    input_x_values = list(x[0] for x in absolute_input_locations.keys())
    input_x_values.sort()

    # Get the differences between each pair of input x values
    diffs = list(input_x_values[i] - input_x_values[i - 1]
                 for i in range(1, len(input_x_values)))

    # Where these differences are more than 2, that means that we had a jump in the x values.
    # Obtain the indexes of the two input x values on either side of the jump
    gap_index_pairs = list(
        (i, i + 1) for i in range(len(diffs)) if diffs[i] > 2)

    # Finally, for each index pair, we want the x value in between the x values at those indices:
    # input_x_values[x] ---------------- (*) --------------- input_x_values[y] for each (x, y) pair in gap_index_pairs
    rep_locs = list(input_x_values[x] +
                    int((input_x_values[y] - input_x_values[x]) / 2)
                    for x, y in gap_index_pairs)

    # Now put repeaters on the input rail

    # We can get away with gap method if the rep_locs are within 15 spaces apart. Otherwise,
    # we'll HAVE to use an ugly-ass method

    rep_loc_spacings = list(rep_locs[i] - rep_locs[i - 1]
                            for i in range(1, len(rep_locs)))

    if len(rep_loc_spacings) > 0:
        rep_loc_max_spacing = max(rep_loc_spacings)
    else:
        # The method fails... just set max spacing to something ridiculous so that it does the other method
        rep_loc_max_spacing = 100

    if rep_loc_max_spacing <= 14:

        print "inputs - gap method"

        # GAP METHOD -- very nice looking, but doesn't work when the input domain is very large
        # because there *won't be any* gaps within 15 units, so it will place no repeaters.

        cy = 2
        for iter_cx in rep_locs:
            for iter_cz in input_rail_z_values.values():
                level.setBlockAt(iter_cx, cy, iter_cz, REPEATER)
                level.setBlockDataAt(iter_cx, cy, iter_cz,
                                     REPEATER_TOWARD_POS_X)

    else:

        print "inputs - method 2"

        # Method 2 -- aesthetically displeasing... has to fudge around the block edges and produces
        # lines of repeaters with 'imperfections' from scooting the necessary ones

        for input_name, input_z_value in input_rail_z_values.items():
            cx, cy, cz = 12, 2, input_z_value
            while cx < sizeX:
                if level.blockAt(cx, cy - 1, cz) == REDSTONE:
                    level.setBlockAt(cx - 2, cy, cz, REPEATER)
                    level.setBlockDataAt(cx - 2, cy, cz, REPEATER_TOWARD_POS_X)
                elif level.blockAt(cx - 1, cy - 1, cz) == REDSTONE:
                    level.setBlockAt(cx + 1, cy, cz, REPEATER)
                    level.setBlockDataAt(cx + 1, cy, cz, REPEATER_TOWARD_POS_X)
                elif level.blockAt(cx + 1, cy - 1, cz) == REDSTONE:
                    level.setBlockAt(cx - 1, cy, cz, REPEATER)
                    level.setBlockDataAt(cx - 1, cy, cz, REPEATER_TOWARD_POS_X)
                else:
                    level.setBlockAt(cx, cy, cz, REPEATER)
                    level.setBlockDataAt(cx, cy, cz, REPEATER_TOWARD_POS_X)
                cx += 12

    if OPTIONS["make_output_rail"]:

        # Now build the output rails!

        outputHeight = absolute_output_locations.keys()[0][1] + 2

        for output_name, output_z_value in output_rail_z_values.items():

            cx, cy, cz = 0, outputHeight, output_z_value
            while cx < sizeX:

                cy -= 1

                if level.blockAt(cx, cy, cz) != REDSTONE:
                    level.setBlockAt(cx, cy, cz, WOOL)
                    level.setBlockDataAt(
                        cx, cy, cz, meta_input.output_color_key[output_name])
                level.setBlockAt(cx, cy, cz - 1, WOOL)
                level.setBlockDataAt(cx, cy, cz - 1, WOOL_BLACK)
                level.setBlockAt(cx, cy, cz + 1, WOOL)
                level.setBlockDataAt(cx, cy, cz + 1, WOOL_BLACK)

                cy += 1

                level.setBlockAt(cx, cy, cz, REDSTONE)

                cx += 1

        # We need to find gaps for the gap method again

        output_x_values = list(x[0] for x in absolute_output_locations.keys())
        output_x_values.sort()

        diffs = list(output_x_values[i] - output_x_values[i - 1]
                     for i in range(1, len(output_x_values)))

        gap_index_pairs = list(
            (i, i + 1) for i in range(len(diffs)) if diffs[i] > 2)

        rep_locs = list(output_x_values[x] +
                        int((output_x_values[y] - output_x_values[x]) / 2)
                        for x, y in gap_index_pairs)

        if len(rep_loc_spacings) > 0:
            rep_loc_max_spacing = max(rep_loc_spacings)
        else:
            # The method fails... just set max spacing to something ridiculous so that it does the other method
            rep_loc_max_spacing = 100

        if rep_loc_max_spacing < 14:

            print "outputs - gap method"

            # GAP METHOD -- very nice looking, but doesn't work when the input domain is very large
            # because there *won't be any* gaps within 15 units, so it will place no repeaters.

            cy = outputHeight
            for iter_cx in rep_locs:
                for iter_cz in output_rail_z_values.values():
                    level.setBlockAt(iter_cx, cy, iter_cz, REPEATER)
                    level.setBlockDataAt(iter_cx, cy, iter_cz,
                                         REPEATER_TOWARD_NEG_X)

        else:

            print "outputs - method 2"

            # Method 2 -- aesthetically displeasing... has to fudge around the block edges and produces
            # lines of repeaters with 'imperfections' from scooting the necessary ones

            for output_name, output_z_value in output_rail_z_values.items():
                cx, cy, cz = 12, outputHeight, output_z_value
                while cx < sizeX:
                    if level.blockAt(cx, cy - 1, cz) == REDSTONE:
                        level.setBlockAt(cx - 2, cy, cz, REPEATER)
                        level.setBlockDataAt(cx - 2, cy, cz,
                                             REPEATER_TOWARD_NEG_X)
                    elif level.blockAt(cx - 1, cy - 1, cz) == REDSTONE:
                        level.setBlockAt(cx + 1, cy, cz, REPEATER)
                        level.setBlockDataAt(cx + 1, cy, cz,
                                             REPEATER_TOWARD_NEG_X)
                    elif level.blockAt(cx + 1, cy - 1, cz) == REDSTONE:
                        level.setBlockAt(cx - 1, cy, cz, REPEATER)
                        level.setBlockDataAt(cx - 1, cy, cz,
                                             REPEATER_TOWARD_NEG_X)
                    else:
                        level.setBlockAt(cx, cy, cz, REPEATER)
                        level.setBlockDataAt(cx, cy, cz, REPEATER_TOWARD_NEG_X)
                    cx += 12

    return level