6

There is an armorstand on one of the red regions. How to count blocks that are including to the region the armorstand stands on? The result has to be stored to a scoreboard. Red regions can have any shape and size, and also have some number of holes.

The illustration of it is below: dd

3
  • Can the shape be 3D?
    – ginkgo
    Jun 7, 2022 at 21:02
  • No, the shape can be 2D only. Jun 7, 2022 at 21:34
  • 1
    I've made a small beta that gets basic x and z but not indents in them but thats all I've been able to do youtube.com/watch?v=eIjxiOSDnB4
    – noahhhha
    Jun 27, 2022 at 1:11

2 Answers 2

3
+50

My idea is to use a flood fill algorithm

enter image description here

Before we start the loop, we do

  1. Spawn a temporary armor stand (called "filled") on the start tile (if the starting point is allowed to be outside the red region, you need to add an if to the execute command

    execute as @e[tag=,type=minecraft:armor_stand] at @s run summon minecraft:armor_stand ~ ~ ~ {Tags:[filled]}
    
  2. Start an loop executing every tick

    setblock ~ ~ ~1 minecraft:redstone_block
    
  3. Reset scoreboard to 0

    /scoreboard players set count region 0
    

In the loop, do:

  1. For each cardinal direction, try to spawn a new armor stand, if the location is not occupied and the new location is above a red wool block
    execute as @e[tag=filled,type=minecraft:armor_stand] at @s positioned ~-1 ~ ~ unless entity @e[type=minecraft:armor_stand,tag=filled,distance=...9] if block ~ ~-1 ~ minecraft:red_wool run summon minecraft:armor_stand ~ ~ ~ {Tags:[filled]}
    execute as @e[tag=filled,type=minecraft:armor_stand] at @s positioned ~1 ~ ~ unless entity @e[type=minecraft:armor_stand,tag=filled,distance=...9] if block ~ ~-1 ~ minecraft:red_wool run summon minecraft:armor_stand ~ ~ ~ {Tags:[filled]}
    execute as @e[tag=filled,type=minecraft:armor_stand] at @s positioned ~ ~ ~1 unless entity @e[type=minecraft:armor_stand,tag=filled,distance=...9] if block ~ ~-1 ~ minecraft:red_wool run summon minecraft:armor_stand ~ ~ ~ {Tags:[filled]}
    execute as @e[tag=filled,type=minecraft:armor_stand] at @s positioned ~ ~ ~-1 unless entity @e[type=minecraft:armor_stand,tag=filled,distance=...9] if block ~ ~-1 ~ minecraft:red_wool run summon minecraft:armor_stand ~ ~ ~ {Tags:[filled]}
    
  2. Use comparators to monitor the spawning process, if no armorstands are spawned, we have filled the area

After the loop, we need to cleanup:

  1. Update the scoreboard
    execute as @e[type=minecraft:armor_stand,tag=filled] run scoreboard players add count region 1
    
  2. Cleanup the progress armorstands
    execute as @e[type=minecraft:armor_stand,tag=filled] run kill @s
    
  3. Stop the repeating clock
    setblock ~ ~ ~-11 air
    

World download: https://files.ferrybig.me/s/HCd9mgKSB9jPSPJt (though the descriptions in the answer should be good enough to recreate this)

2
  • I know how to improve this mechanism and remove all the redstone, but the algorithm is absolutely correct. Excellent! Jul 6, 2022 at 4:25
  • You could post your improved version of the algorithm in a new self-answer. It would benefit the future readers. I am not that familiar with all the command block "code golf" tricks
    – Ferrybig
    Jul 6, 2022 at 7:11
1

I've created a datapack that solves this problem by the @Ferrybig's algorithm but with no redstone, functions only.

Setup

First of all, it creates a scoreboard that will be displayed at the sidebar.

setup.mcfunction

scoreboard objectives add area_counter dummy
scoreboard objectives setdisplay sidebar area_counter

Main

Next, we need to set the initial value of the main counter variable. The only way to loop a mcfunction code fragment I know is by recursion, so we create another function count_area.

NB. I replaced most armor_stand with area_effect_cloud for optimization.

main.mcfunction

scoreboard players set count area_counter 0

execute as @e[tag=,type=minecraft:armor_stand] at @s run summon minecraft:area_effect_cloud ~ ~ ~ {Tags:[filled], Duration:1000}

execute as @e[tag=filled,type=minecraft:area_effect_cloud] at @s if block ~ ~-1 ~ minecraft:red_wool run function ac:count_area

execute as @e[tag=filled,type=minecraft:area_effect_cloud] run scoreboard players add count area_counter 1

kill @e[tag=filled,type=minecraft:area_effect_cloud]

Count_area

This is the most difficult part of the solution. First, we set the initial values for following variables:

count_area.mcfunction. 1/3

scoreboard players set has_been_executed area_counter 0
scoreboard players set north area_counter 0
scoreboard players set south area_counter 0
scoreboard players set east area_counter 0
scoreboard players set west area_counter 0

Next, we check every cardinal direction for red wool block exactly like in @Ferrybig's answer.

count_area.mcfunction. 2/3

execute store success score north area_counter as @e[type=minecraft:area_effect_cloud,tag=filled] at @s positioned ~ ~ ~-1 unless entity @e[type=minecraft:area_effect_cloud,tag=filled,distance=...9] if block ~ ~-1 ~ minecraft:red_wool run summon minecraft:area_effect_cloud ~ ~ ~ {Tags:[filled], Duration:1000}
execute store success score south area_counter as @e[type=minecraft:area_effect_cloud,tag=filled] at @s positioned ~ ~ ~1 unless entity @e[type=minecraft:area_effect_cloud,tag=filled,distance=...9] if block ~ ~-1 ~ minecraft:red_wool run summon minecraft:area_effect_cloud ~ ~ ~ {Tags:[filled], Duration:1000}
execute store success score east area_counter as @e[type=minecraft:area_effect_cloud,tag=filled] at @s positioned ~1 ~ ~ unless entity @e[type=minecraft:area_effect_cloud,tag=filled,distance=...9] if block ~ ~-1 ~ minecraft:red_wool run summon minecraft:area_effect_cloud ~ ~ ~ {Tags:[filled], Duration:1000}
execute store success score west area_counter as @e[type=minecraft:area_effect_cloud,tag=filled] at @s positioned ~-1 ~ ~ unless entity @e[type=minecraft:area_effect_cloud,tag=filled,distance=...9] if block ~ ~-1 ~ minecraft:red_wool run summon minecraft:area_effect_cloud ~ ~ ~ {Tags:[filled], Duration:1000}

Finally, we sum every successful summoning to the has_been_executed and check for it actually has. If it has, the function runs itself.

count_area.mcfunction. 3/3

scoreboard players operation has_been_executed vars += north area_counter
scoreboard players operation has_been_executed vars += south area_counter
scoreboard players operation has_been_executed vars += east area_counter
scoreboard players operation has_been_executed vars += west area_counter

execute unless score has_been_executed area_counter matches 0 run function ac:count_area
You can download the complete datapack here: https://www.mediafire.com/file/2f4l67zem23jl09/area_counter.zip/file

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .