# Мегаферма
Эта невероятно мощная технология дает доступ к нескольким дронам. 

Как и раньше, ты начинаешь с одним дроном. Дополнительные дроны нужно создать, и они пропадут после завершения программы.
Каждый дрон выполняет собственную отдельную программу. Новые дроны можно создать с помощью функции `spawn_drone(function)`.

`def drone_function():
    move(North)
    do_a_flip()

spawn_drone(drone_function)`

Новый дрон создается на той же позиции, где выполнена команда `spawn_drone(function)`. Он начинает выполнять указанную функцию и по завершении автоматически пропадает.

Дроны не сталкиваются друг с другом. 

Используй `max_drones()`, чтобы получить максимально возможное количество дронов.
Используй `num_drones()`, чтобы получить количество дронов, которые уже находятся на ферме.


## Пример:
`def harvest_column():
    for _ in range(get_world_size()):
        harvest()
        move(North)

while True:
    if spawn_drone(harvest_column):
        move(East)`

Первый дрон будет перемещаться горизонтально и создавать новые дроны. Созданные дроны будут перемещаться вертикально и собирать все на пути.

Если все доступные дроны уже созданы, `spawn_drone()` ничего не сделает и вернет `None`.

Вот еще один пример, где каждому дрону передается свое направление.
`for dir in [North, East, South, West]:
    def task():
        move(dir)
        do_a_flip()
    spawn_drone(task)`

<spoiler=показать подсказку> Существует суперполезная функция параллельного выполнения `for_all`, которая принимает любую функцию и запускает ее на каждой клетке фермы. При этом используются все доступные дроны.

`def for_all(f):
	def row():
		for _ in range(get_world_size()-1):
			f()
			move(East)
		f()
	for _ in range(get_world_size()):
		if not spawn_drone(row):
			row()
		move(North)

for_all(harvest)`

Здесь удобно использовать такую схему: сначала создается дрон, если это возможно, а если нет — ты выполняешь задание самостоятельно.

`if not spawn_drone(task):
	task()`
</spoiler>

## Ожидание другого дрона
Используй функцию `wait_for(drone)`, чтобы дождаться завершения работы другого дрона. Ты получаешь идентификатор `drone`, когда создаешь дрон.
`wait_for(drone)` возвращает значение, которое вернула бы функция, выполнявшаяся другим дроном.

`def get_entity_type_in_direction(dir):
    move(dir)
    return get_entity_type()

def zero_arg_wrapper():
    return get_entity_type_in_direction(North)
drone = spawn_drone(zero_arg_wrapper)
print(wait_for(drone))`

Обрати внимание, что создание дронов занимает время, поэтому не стоит добавлять их для каждой мелочи.

Можно использовать `has_finished(drone)`, чтобы узнать, закончил ли дрон, и не ждать лишнего.

## Отсутствие общей памяти
У каждого дрона собственная память, и он не может напрямую читать или записывать глобальные переменные другого дрона.

`x = 0

def increment():
    global x
    x += 1

wait_for(spawn_drone(increment))
print(x)`

Такой код выведет `0`, потому что новый дрон увеличил собственную копию глобальной переменной `x`, что не влияет на `x` первого дрона.

## Состояние гонки
Несколько дронов могут взаимодействовать с одной и той же клеткой фермы одновременно. Если два дрона попытаются взаимодействовать с одной и той же клеткой в течение одного тика, оба действия будут выполнены, но их результаты могут отличаться в зависимости от порядка.

Например, представь, что дроны `0` и `1` находятся над одним и тем же почти полностью выросшим деревом.
Дрон `0` вызывает
`use_item(Items.Fertilizer)`
Дрон `1` вызывает
`harvest()`

Если действия происходят одновременно, дерево сначала будет удобрено, а затем собрано. В этом случае ты получишь с него древесину. Однако, если дрон `1` окажется немного быстрее, дерево будет собрано до того, как его удобрили, и ты не получишь древесину.
Это называется «состояние гонки». Такая проблема часто встречается в параллельном программировании, где результат зависит от порядка выполнения операций.

Вот еще одна проблема, которая может возникнуть, если несколько дронов одновременно выполняют одинаковый код на одной и той же позиции.
`if get_water() < 0.5:
    use_item(Items.Water)`

Если несколько дронов выполняют код одновременно, они все выполнят первую строку и перейдут в блок `if`. Затем все они используют воду и потратят ее впустую.
К тому времени, как дрон достигнет второй строки, `get_water()` может быть уже не меньше `0.5`, потому что другой дрон тем временем полил эту клетку.