代码之家  ›  专栏  ›  技术社区  ›  Dan

把所有类似的木块放到静脉里

  •  1
  • Dan  · 技术社区  · 7 年前

    我想把所有类似的木块都做成一条静脉。但我的代码似乎只在半径为5 x 5的块中获取块。

    我用了一段时间的方法

    public List<Block> getVein(Block b){
        List<Block> blocks = similarNear(null, b);
        ListIterator<Block> toCheck = blocks.listIterator();
        while(toCheck.hasNext()) {
            Block current = toCheck.next();
            if(!blocks.contains(current))
                blocks.add(current);
            for(Block block : similarNear(blocks, current)) {
                if(!blocks.contains(block))
                    toCheck.add(block);
            }
        }
        return blocks;
    }
    

    和类似的

        public List<Block> similarNear(List<Block> current, Block block){
        List<Block> blocks = new ArrayList<Block>();
        Material mat = block.getType();
        Location loc = block.getLocation();
    
        if(loc.clone().add(0, -1, 1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(0, -1, 1).getBlock());
        if(loc.clone().add(0, -1, -1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(0, -1, -1).getBlock());
        if(loc.clone().add(1, -1, 0).getBlock().getType() == mat)
            blocks.add(loc.clone().add(1, -1, 0).getBlock());
        if(loc.clone().add(-1, -1, 0).getBlock().getType() == mat)
            blocks.add(loc.clone().add(-1, -1, 0).getBlock());
        if(loc.clone().add(1, -1, 1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(1, -1, 1).getBlock());
        if(loc.clone().add(-1, -1, -1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(-1, -1, -1).getBlock());
        if(loc.clone().add(-1, -1, 1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(-1, -1, 1).getBlock());
        if(loc.clone().add(1, -1, -1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(1, -1, -1).getBlock());
        if(loc.clone().add(0, -1, 0).getBlock().getType() == mat)
            blocks.add(loc.clone().add(0, -1, 0).getBlock());
    
        if(loc.clone().add(0, 0, 1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(0, 0, 1).getBlock());
        if(loc.clone().add(0, 0, -1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(0, 0, -1).getBlock());
        if(loc.clone().add(1, 0, 0).getBlock().getType() == mat)
            blocks.add(loc.clone().add(1, 0, 0).getBlock());
        if(loc.clone().add(-1, 0, 0).getBlock().getType() == mat)
            blocks.add(loc.clone().add(-1, 0, 0).getBlock());
        if(loc.clone().add(1, 0, 1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(1, 0, 1).getBlock());
        if(loc.clone().add(-1, 0, -1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(-1, 0, -1).getBlock());
        if(loc.clone().add(-1, 0, 1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(-1, 0, 1).getBlock());
        if(loc.clone().add(1, 0, -1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(1, 0, -1).getBlock());
    
        if(loc.clone().add(0, 1, 1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(0, 1, 1).getBlock());
        if(loc.clone().add(0, 1, -1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(0, 1, -1).getBlock());
        if(loc.clone().add(1, 1, 0).getBlock().getType() == mat)
            blocks.add(loc.clone().add(1, 1, 0).getBlock());
        if(loc.clone().add(-1, 1, 0).getBlock().getType() == mat)
            blocks.add(loc.clone().add(-1, 1, 0).getBlock());
        if(loc.clone().add(1, 1, 1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(1, 1, 1).getBlock());
        if(loc.clone().add(-1, 1, -1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(-1, 1, -1).getBlock());
        if(loc.clone().add(-1, 1, 1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(-1, 1, 1).getBlock());
        if(loc.clone().add(1, 1, -1).getBlock().getType() == mat)
            blocks.add(loc.clone().add(1, 1, -1).getBlock());
        if(loc.clone().add(0, 1, 0).getBlock().getType() == mat)
            blocks.add(loc.clone().add(0, 1, 0).getBlock());
    
     // Remove duplicate blocks
        List<Block> filtered = new ArrayList<>();
        for(Block b : blocks) {
            if(current == null) {
                filtered.add(b);
                continue;
            }else {
                if(!current.contains(b)) {
                    if(!filtered.contains(b))
                        filtered.add(b);
                }
            }
        }
    
        return filtered;
    }
    

    我还想添加一个cap-say示例,只允许它打破25个块,但我不知道如何在不阻止它在一个方向找到25个块的情况下进行添加,如果这有任何意义,就停止。

    1 回复  |  直到 7 年前
        1
  •  1
  •   caneva20 Italo Medeiros    7 年前

    在这里,我试图尽可能地对代码进行评论,任何建议都会受到赞赏。

    //Loops around a block to find other blocks that matches with the center (the given block)
    private ArrayList<Block> search(Block center) {
        //The maximum amount of blocks to find (the 'cap', our limit)
        final int max = 25;
    
        ArrayList<Block> blocks = new ArrayList<>();
        Queue<Block> toSearch = new LinkedList<>();
    
        //Add the center to list, so it has something to start the search
        toSearch.add(center);
    
        //While we have something to search and have not reached the limit (the 'cap')
        while (toSearch.size() > 0 && blocks.size() < max) {
            Block b = toSearch.remove(); //Get the block on top of the queue, (and remove it)
    
            blocks.add(b); //Since this block is already of the type we want, we add it the found list (in this case is the 'blocks' var)
    
            //Find all its neighbours
            for (Block around : findNeighbours(b)) {
                //We do this check here too 'cause findNeighbours() might return up to 26 blocks and it might be too much
                //eg. we have a max of 50 blocks and have already found 45, if findNeighbours find more than five blocks we want to ignore to others
                //that way we stay within our limit, and once this check is made once the whole loop will end
                if (blocks.size() >= max) {
                    break;
                }
    
                //Only add this block if not yet found/processed/searched
                if (toSearch.contains(around) || blocks.contains(around)) {
                    continue;
                }
    
                toSearch.add(around);
            }
    
            //If in our toSearch list we already enough blocks to fill our limit we stop the search and add as much as we need to fill up out limit.
            //This can save some resources when searching for common blocks like dirt and stone, which we might find a lot and not all of them will be added to our list
            if (toSearch.size() + blocks.size() >= max) {
                int remains = max - blocks.size(); //Gets how many more blocks we need to fulfill our goal (the limit)
    
                for (int i = 0; i < remains; i++) {
                    blocks.add(toSearch.remove());
                }
    
                break;
            }
        }
    
        return blocks;
    }
    
    //Finds all neighbours around a block
    private List<Block> findNeighbours(Block block) {
        //to avoid a bunch of ifs we use these 3 fors to loop over each axis (X, Y, Z)
    
        ArrayList<Block> blocks = new ArrayList<>();
    
        //SQUARED 'radius' to search around
        final int searchRadius = 1;
    
        for (int x = -searchRadius; x <= searchRadius; x++) {
            for (int y = -searchRadius; y <= searchRadius; y++) {
                for (int z = -searchRadius; z <= searchRadius; z++) {
                    if (x == 0 && y == 0 && z == 0) {continue;}
    
                    //Get the block at this location (x,y,z)
                    Block near = block.getLocation().clone().add(x, y, z).getBlock();
    
                    //Check if the found block is a valid match. eg: is the same type, has the same data/variant
                    if (match(near, block)) {
                        blocks.add(near);
                    }
                }
            }
        }
    
        return blocks;
    }
    
    //Checks if a matches to b
    private boolean match(Block a, Block b) {
        //Checks only the block type, ot its variant/data
        //return a.getType() == b.getType();
    
        //Checks its type and its data/variant (might not work on all bukkit/spigot versions)
        return a.getType() == b.getType() && a.getState().getData().equals(b.getState().getData());
    }