В первой части я рассказал, как использовать массив для хранения состояния нескольких врагов. Но с массивом или без, а состояние каждого врага всё равно нужно обработать.
Само по себе это не проблема, просто сколько есть врагов – столько раз надо надо написать инструкцию для обработки. Компьютерные программы в принципе только и занимаются тем, что перебирают большие массивы данных – в тысячи и миллионы байт. Конечно, писать миллион строк для перебора миллиона байт – совсем неразумная идея.
До сих пор мы обсуждали только то, как в памяти хранятся данные. Но программа не просто хранит данные, она должна с ними что-то сделать: сложить, умножить, переместить и т.д. Но кто именно этим занимается? Процессор, который выполняет машинные инструкции. А откуда берутся машинные инструкции? Мы пишем программу на каком-то языке программирования, а транслятор этого языка переводит текст программы в машинные инструкции. Но как эти инструкции попадают в процессор?
Так же как и данные, инструкции для процессора находятся в памяти компьютера. Каждая инструкция, конечно, записана в виде чисел и имеет свой адрес в памяти.
Когда мы говорим "загрузить программу", на самом деле происходит следующее: файл программы, который состоит из уже готовых машинных инструкций, копируется в память. Теперь в памяти есть кусок, заполненный машинными инструкциями. А по сути это просто массив чисел.
Процессор устроен так, что всегда смотрит на какой-то адрес памяти и читает из него инструкции. Это происходит автоматически внутри процессора, и остановить это нельзя. Процессор действует примерно так:
"Сейчас мой указатель показывает на адрес 0. Я читаю из адреса 0 машинную инструкцию. Её длина 2 байта, поэтому я сразу прибавлю к указателю 2. Теперь я займусь выполнением инструкции... Всё, выполнил, и готов выполнять следующую. Сейчас мой указатель показывает на адрес 2. Я читаю из адреса 2 машинную инструкцию..."
И этот процесс продолжается без остановки.
Например, программа загрузилась в память начиная с адреса 512. Чтобы процессор начал её выполнять, нужно установить его указатель на 512. И тогда он такой:
"Сейчас мой указатель показывает на адрес 512. Я читаю из адреса 512 машинную инструкцию..."
То есть начнет выполнять именно нашу загруженную программу.
С нашей стороны ничего не требуется делать руками. Загрузку программы в память и передачу нужного адреса процессору осуществляет операционная система.
Считывая и выполняя инструкции по порядку, процессор через некоторое время дойдет до конца программы. Но очевидно, что вы можете запустить игру и играть в нее часами и даже сутками, и она не завершится. Почему? Потому что процессор не доходит до конца программы. А не доходит он до конца потому, что его указатель инструкций меняет сама программа. Программа может послать процессор на любой адрес, то есть прервать его обычный порядок выполнения. Для этого, конечно, существует специальная машинная инструкция, которая условно выглядит как
[иди на][адрес]
Когда процессор встречает такую инструкцию, он записывает в свой указатель адрес, который получил из инструкции. И следующим шагом продолжает выполнение с этого адреса.
Скажем, если по адресу 200 процессор нашел инструкцию "перейди на адрес 100", то процессор перейдет на адрес 100, будет выполнять инструкцию за инструкцией, и в конце концов опять дойдет до адреса 200, где опять встретит инструкцию "перейди на адрес 100". Перейдя на адрес 100, он продолжит выполнять инструкции и снова дойдет до адреса 200, и снова перейдет на адрес 100, и т.д. Таким образом, процессор попал в цикл: он не может дойти до конца программы, потому что снова и снова повторяет инструкции, расположенные между адресами 100 и 200.
Нетрудно заметить, что это бесконечный цикл: процессору никогда из него не выйти. Самый короткий, бессмысленный и беспощадный вариант бесконечного цикла это
100 GOTO 100
Это инструкция на языке BASIC. Каждая строка программы в Бейсике пронумерована, то есть можно сказать, что она имеет адрес. Первое число 100 это как раз номер строки. А дальше идет инструкция: перейди на строку с номером 100.
Таким образом, получился цикл из одной инструкции, из которого выйти невозможно. Такого же эффекта можно добиться и во многих других языках:
a: goto a;
В этом случае говорят, что программа зациклилась или повисла. Сделать тут уже ничего нельзя, и нужно принудительно прекращать работу программы, а в некоторых случаях даже перезагружать компьютер.
Очевидно, пользы от бесконечного цикла ровно никакой. Для того, чтобы цикл был полезен, он должен отработать столько раз, сколько нам нужно, и затем прекратиться. Как это сделать, я расскажу здесь: