获取所有相似的块

时间:2018-08-09 01:06:24

标签: java bukkit

我正在尝试将所有类似的障碍都弄清楚。但是我的代码似乎只能以5 x 5的块半径获取块。

我尝试使用while方法

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;
}

我还想添加一个上限,例如,示例仅允许它打破25个方块,但我不知道如何添加它,而不是阻止它在一个方向上找到25个方块,然后在有意义的情况下停止。

1 个答案:

答案 0 :(得分:1)

在这里,我试图尽可能地注释代码,任何建议都值得赞赏。

//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());
}