Слёрм Universe - Python на примере Minecraft
Модули (часть 1)
Практика 8
Ну что, круто мы развеяли тайну первой строки (from mcpi.minecraft import Minecraft) в нашем коде? Теперь мы лучше понимает структуру программ - возможность одних модулей подключаться к другим. На прошлой лекции про random и time мы уже проходили то, что Python имеет богатый арсенал функций из своей стандартной библиотеки. Давайте вновь воспользуемся ими и решим следующую задачу.

Итак, создадим "взрывоопасный" игровой автомат с тремя ячейками под блоки. В каждой ячейке должен оказаться один случайный блок: либо золото, либо алмаз, либо камень. Пускай этот автомат строится сразу же после выполнения кода, а ЕСЛИ игрок окажется на блоке золота, то в его ячейках начнётся подбор случайных блоков. Если блоки в трёх ячейках совпадут, то автомат (бум!) сразу взорвётся.
Поехали! Давайте напишем код, который будет строить простенький корпус нашего игрового автомата:
from mcpi.minecraft import Minecraft
mc = Minecraft.create()

player_x, player_y, player_z = mc.player.getPos()
slot_machine_x = player_x + 5
slot_machine_y = player_y
slot_machine_z = player_z

for height_bias in range(4):
    for width_bias in range(5):
        mc.setBlock(slot_machine_x, slot_machine_y + height_bias, slot_machine_z + width_bias, 42)
        if height_bias == 1 or height_bias == 3 or width_bias == 0 or width_bias == 4:
            mc.setBlock(slot_machine_x - 1, slot_machine_y + height_bias, slot_machine_z + width_bias, 42)
        if height_bias == 2 and width_bias == 1 or height_bias == 2 and width_bias == 2 or height_bias == 2 and \
                width_bias == 3:
            mc.setBlock(slot_machine_x, slot_machine_y + height_bias, slot_machine_z + width_bias, 152)
Данный код при помощи циклов FOR и функции setBlock() возводит железное сооружение с пустым пространством вверху ("окошко" с тремя ячейкам), где и будут появляться три случайных блока. Обратите внимание, что за этим пустым "окошком" следуют блоки красного камня. Зачем? Скоро узнаете! Выполним код и посмотрим, что получилось:
Отлично, наш корпус готово!

Далее нам нужно добавить бесконечный цикл WHILE, в рамках которого будет постоянно проверяться блок под ногами нашего игрока, и если этот блок будет золотом, то игровой автомат запустится волшебной магией кода! Говоря простым языком, если сработает триггерное условие, то в пустом "окошке" (три пустых ячейки) нашего строения появятся три блока. Каждый из этих блоков должен случайным образом оказаться либо золотом, либо алмазом, либо камнем. Давайте немного дополним наш код:
from mcpi.minecraft import Minecraft
import random
mc = Minecraft.create()

player_x, player_y, player_z = mc.player.getPos()
slot_machine_x = player_x + 5
slot_machine_y = player_y
slot_machine_z = player_z
game_blocks = [41, 57, 1]
game_cell_coords = []

for height_bias in range(4):
    for width_bias in range(5):
        mc.setBlock(slot_machine_x, slot_machine_y + height_bias, slot_machine_z + width_bias, 42)
        if height_bias == 1 or height_bias == 3 or width_bias == 0 or width_bias == 4:
            mc.setBlock(slot_machine_x - 1, slot_machine_y + height_bias, slot_machine_z + width_bias, 42)
        if height_bias == 2 and width_bias == 1 or height_bias == 2 and width_bias == 2 or height_bias == 2 and \
                width_bias == 3:
            mc.setBlock(slot_machine_x, slot_machine_y + height_bias, slot_machine_z + width_bias, 152)
            game_cell_coords.append((slot_machine_x - 1, slot_machine_y + height_bias, slot_machine_z + width_bias))

while True:
    player_x, player_y, player_z = mc.player.getPos()
    if mc.getBlock(player_x, player_y - 1, player_z) == 41:
        for cell in game_cell_coords:
            cell_x, cell_y, cell_z = cell
            random_game_block = random.choice(game_blocks)
            mc.setBlock(cell_x, cell_y, cell_z, random_game_block)
В самом начале кода мы импортировали модуль random и сделали следующее:
  • Мы создали список game_bloks с тремя ID-номерами блоков, которые будут случайным образом появляться в ячейках игрового автомата;
  • Мы добавили ещё одну переменную game_cell_coords, в которую запишем координаты трёх ячеек нашего автомата после его строительства;
  • В самом конце кода строительства мы записываем в список game_cell_cords кортеж с координатами каждой пустой ячейки при помощи функции append().
  • Далее следует бесконечный цикл WHILE, в котором для каждой итерации цикла определяются координаты нашего игрока и записываются в переменные player_x, player_y и player_z;
  • А в теле этого цикла следует условие: ЕСЛИ наш игрок оказывается на золотом блоке, то при помощи цикла FOR в переменную cell для каждой его итерации записывается кортеж с координатами каждой отдельной ячейки игрового автомата;
  • Далее мы распаковываем кортеж с координатами каждой отдельной ячейки в переменные cell_x, celly_y и cell_z;
  • Супер! Теперь мы можем в каждую ячейку по их координатам cell_x, celly_y и cell_z добавлять блоки. Однако, мы хотим, чтобы эти блоки для каждой ячейки были случайными (либо золото, либо алмаз, либо камень). Для этого мы создали переменную random_game_block, в которую при помощи функции choice() модуля random мы записываем случайный ID блока из списка game_blocks;
  • Ну и наконец при помощи функции setBlock() устанавливаем блок со случайным ID в каждую из ячеек, передав в неё последним аргументом нашу переменную random_game_block.

Запустим наш код и встанем на блок с золотом:
Отлично, работает! Однако, блоки в ячейках появляются слишком быстро. А как сделать так, чтобы после установки блока в каждую из ячеек следовала пауза длиною в секунду? Правильно, используем функцию sleep() модуля time:
from mcpi.minecraft import Minecraft
import random
import time
mc = Minecraft.create()

player_x, player_y, player_z = mc.player.getPos()
slot_machine_x = player_x + 5
slot_machine_y = player_y
slot_machine_z = player_z
game_blocks = [41, 57, 1]
game_cell_coords = []

for height_bias in range(4):
    for width_bias in range(5):
        mc.setBlock(slot_machine_x, slot_machine_y + height_bias, slot_machine_z + width_bias, 42)
        if height_bias == 1 or height_bias == 3 or width_bias == 0 or width_bias == 4:
            mc.setBlock(slot_machine_x - 1, slot_machine_y + height_bias, slot_machine_z + width_bias, 42)
        if height_bias == 2 and width_bias == 1 or height_bias == 2 and width_bias == 2 or height_bias == 2 and \
                width_bias == 3:
            mc.setBlock(slot_machine_x, slot_machine_y + height_bias, slot_machine_z + width_bias, 152)
            game_cell_coords.append((slot_machine_x - 1, slot_machine_y + height_bias, slot_machine_z + width_bias))

while True:
    player_x, player_y, player_z = mc.player.getPos()
    if mc.getBlock(player_x, player_y - 1, player_z) == 41:
        for cell in game_cell_coords:
            cell_x, cell_y, cell_z = cell
            random_game_block = random.choice(game_blocks)
            mc.setBlock(cell_x, cell_y, cell_z, random_game_block)
            time.sleep(1)
Итак, мы импортировали модуль time, а после установки каждого блока в отдельную ячейку автомата добавили паузу длиною в секунду при помощи функции sleep(). Отлично!

Помните, в самом начале практики мы хотели, чтобы в том случае, если во всех трёх ячейках выпадут три ОДИНАКОВЫХ блока, автомат взорвался? Дополним наш код:
from mcpi.minecraft import Minecraft
import random
import time
mc = Minecraft.create()

player_x, player_y, player_z = mc.player.getPos()
slot_machine_x = player_x + 5
slot_machine_y = player_y
slot_machine_z = player_z
game_blocks = [41, 57, 1]
game_cell_coords = []
all_random_game_blocks = []

for height_bias in range(4):
    for width_bias in range(5):
        mc.setBlock(slot_machine_x, slot_machine_y + height_bias, slot_machine_z + width_bias, 42)
        if height_bias == 1 or height_bias == 3 or width_bias == 0 or width_bias == 4:
            mc.setBlock(slot_machine_x - 1, slot_machine_y + height_bias, slot_machine_z + width_bias, 42)
        if height_bias == 2 and width_bias == 1 or height_bias == 2 and width_bias == 2 or height_bias == 2 and \
                width_bias == 3:
            mc.setBlock(slot_machine_x, slot_machine_y + height_bias, slot_machine_z + width_bias, 152)
            game_cell_coords.append((slot_machine_x - 1, slot_machine_y + height_bias, slot_machine_z + width_bias))

while True:
    player_x, player_y, player_z = mc.player.getPos()
    if mc.getBlock(player_x, player_y - 1, player_z) == 41:
        for cell in game_cell_coords:
            cell_x, cell_y, cell_z = cell
            random_game_block = random.choice(game_blocks)
            mc.setBlock(cell_x, cell_y, cell_z, random_game_block)
            all_random_game_blocks.append(random_game_block)
            time.sleep(1)

        if all_random_game_blocks[0] == all_random_game_blocks[1] == all_random_game_blocks[2]:
            mc.postToChat("Бинго!")
            for cell in game_cell_coords:
                cell_x, cell_y, cell_z = cell
                mc.setBlock(cell_x, cell_y, cell_z, 46)
            break
  • Перед бесконечным циклом WHILE мы добавили пустой список all_random_game_blocks, куда будем записывать ID наших трёх установленных блоков в ячейки игрового автомата;
  • А после функции setBlock() в теле цикла FOR, где мы устанавливаем блоки в ячейки, мы записываем их ID в список all_random_game_blocks при помощи append();
  • И наконец в самом конце кода мы используем условие: ЕСЛИ (if) ID-номер первого блока в ячейке (all_random_game_blocks[0]) равняется (==) ID-номеру блока во второй ячейке (all_random_game_blocks[1]) и равняется (==) ID-блока в третьей ячейке (all_random_game_blocks[2]), ТО тогда мы выводим сообщение в чат "Бинго!" и, используя их координаты в списке game_cell_coords, устанавливаем на их место блоки с динамитом (ID 46), а ПОСЛЕ останавливаем весь цикл при помощи прерывания break, чтобы код завершил свою работу.

Отлично, теперь наш автомат стал "взрывоопасным". Давайте дополним наше условие, где мы проверяли наличие одинаковых блоков во всех трёх ячейках. Если так окажется, что блоки в них не одинаковы, то пусть они просто исчезнут:
from mcpi.minecraft import Minecraft
import random
import time
mc = Minecraft.create()

player_x, player_y, player_z = mc.player.getPos()
slot_machine_x = player_x + 5
slot_machine_y = player_y
slot_machine_z = player_z
game_blocks = [41, 57, 1]
game_cell_coords = []
all_random_game_blocks = []

for height_bias in range(4):
    for width_bias in range(5):
        mc.setBlock(slot_machine_x, slot_machine_y + height_bias, slot_machine_z + width_bias, 42)
        if height_bias == 1 or height_bias == 3 or width_bias == 0 or width_bias == 4:
            mc.setBlock(slot_machine_x - 1, slot_machine_y + height_bias, slot_machine_z + width_bias, 42)
        if height_bias == 2 and width_bias == 1 or height_bias == 2 and width_bias == 2 or height_bias == 2 and \
                width_bias == 3:
            mc.setBlock(slot_machine_x, slot_machine_y + height_bias, slot_machine_z + width_bias, 152)
            game_cell_coords.append((slot_machine_x - 1, slot_machine_y + height_bias, slot_machine_z + width_bias))

while True:
    player_x, player_y, player_z = mc.player.getPos()
    if mc.getBlock(player_x, player_y - 1, player_z) == 41:
        for cell in game_cell_coords:
            cell_x, cell_y, cell_z = cell
            random_game_block = random.choice(game_blocks)
            mc.setBlock(cell_x, cell_y, cell_z, random_game_block)
            all_random_game_blocks.append(random_game_block)
            time.sleep(1)

        if all_random_game_blocks[0] == all_random_game_blocks[1] == all_random_game_blocks[2]:
            mc.postToChat("Бинго!")
            for cell in game_cell_coords:
                cell_x, cell_y, cell_z = cell
                mc.setBlock(cell_x, cell_y, cell_z, 46)
            break
        else:
            for cell in game_cell_coords:
                cell_x, cell_y, cell_z = cell
                mc.setBlock(cell_x, cell_y, cell_z, 0)
                all_random_game_blocks.clear()
  • Итак, при помощи ELSE мы дополнили наше условие. Если блоки во всех трёх ячейках абсолютно одинаковы, то автомат взорвётся, А ИНАЧЕ (else), используя их координаты мы заменим их на блок воздуха (ID 0), тем самым они исяезнут;
  • А после при помощи функции clear() мы очищаем список all_random_game_blocks. Если этого не сделать, то когда мы вновь окажемся на блоке золота и в ячейках начнут вновь появляться новые блоки, список продолжит расти, а в нём останутся сведения о блоках, которые были до этого. Поэтому после каждой такой "игры на автомате" нужно очищать сведения о блоках, которые в нём были установлены раньше.

Отлично, мы завершили практику и создали действительно "взрывоопасный" автомат. Если в реальной жизни выигрыш в игровом автомате приносит гору монет, то в нашем случае - огромный взрыв! Попробуйте выполнить такой код и постарайтесь это делать далеко от жилища вашего игрока, а то мало ли, вдруг вам повезёт "сорвать" три блока одновременно.