Основы Swift / 6.2. Циклы While 1 - цикл while


Видео


Циклы while
Цикл while выполняет набор инструкций, пока его условие не становится ложным. Эти виды циклов наиболее хорошо подходят для ситуации, когда число итераций неизвестно до начала первой итерации. Swift предоставляет два вида циклов while:
  • while вычисляет своё условие в начале каждого прохождения через итерацию цикла
  • repeat-while вычисляет своё условие в конце каждого прохождения через итерацию цикла
Цикл while
Цикл while начинается с вычисления единственного условия. Если условие true, то набор инструкций будет повторяться, пока условие не станет false.

Этот пример демонстрирует простую игру "Змеи и лестницы". Пример игрового поля показан на рисунке:
Рисунок 6.2.1
                    
                    
                    
                
Правила игры
Правила для игры следующие:
  • Доска имеет 25 клеток, а цель игры - добраться до 25-ой клетки или выйти за её пределы.
  • Стартовый квадрат игрока есть "нулевой квадрат", что находится за границей левого нижнего угла доски.
  • Каждый ход Вы бросаете шестигранную кость и передвигаетесь на число клеток, следуя горизонтальному пути, показанному стрелкой.
  • Если Ваш ход оканчивается на нижней части лестницы, Вы поднимаетесь по ней.
  • Если Ваш ход заканчивается на голове змеи, то Вы передвигаетесь вниз по змее к хвосту.
@{6.2\1\1}

let finalSquare = 25
var board = [Int](repeating: 0, count: finalSquare + 1)
                    
Игровая доска представлена массивом типа Int. Его размер основан на константе с finalSquare, которая используется для инициализации массива, а также для проверки условия победы в этом примере. Так как игроки начинают за пределами доски, на "нулевом квадрате", то доска инициализируется с 26-ю нулевыми Int-значениями, а не 25-ю.
@{6.2\1\2}
Некоторые квадраты должны быть заданы в более конкретные значения для змей и лестниц. Клетки с лестницей имеют в основе положительное число для перемещения вверх по доске, тогда как клетки со змеиными головами имеют отрицательное значение для перемещения вниз по доске.

Квадрат 3 содержит начало лестницы, которая переместит Вас вверх в клетку 11. Чтобы отобразить это, board[03] устанавливается в +08, что является эквивалентом целому значению 8 (разница между 3 и 11). Чтобы выровнять значения и инструкции, унарный оператор плюс (+i) явно используется вместе с оператором минуса (-i), а числа, меньшие 10, претворяются нулём. (Хотя стилистическая техника не строго необходима, но она ведёт к более качественному коду.)
@{6.2\1\2}

board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
                
@{6.2\1\3}
Пример выше использует очень простой способ для бросания кубика. Вместо генерации случайного числа всё начинается с задания величине diceRoll значения 0. На каждой итерации цикла while diceRoll увеличивается на единицу и проверяется на то, не стала ли она слишком большой. Если она стала равной 7, то значит игральный кубик стал слишком большим и он будет сброшен в 1. В результате последовательность значений diceRoll всегда будет 1, 2, 3, 4, 5, 6, 1, 2 и так далее.

После броска кубика игрок передвигается вперёд на количество клеток, равное diceRoll. Возможно, что игральный кубик переместит игрока за клетку 25, в этом случае игра будет закончена. Чтобы реализовать этот сценарий, код проверяет, меньше ли square, чем свойство count массива board. Если square корректен, то значение, хранимое в board[square], будет добавлено к текущему значению square для перемещения игрока вниз или вверх по лестницам или змеям.

Если не производить эту проверку, то board[square] может попытаться получить доступ к значению за пределами границ массива board, что вызовет ошибку времени выполнения.

Текущая итерация цикла while будет завершена, а значение условия цикла будет проверено для выяснения того, выполняться циклу вновь или нет. Если игрок передвинулся на или за клетку номер 25, то условие цикла будет вычислено в false и игра завершится.

Цикл while в данном случае подходит, так как длина игры неизвестна заранее в начале цикла while. Вместо этого цикл будет выполняться, пока конкретное условие удовлетворяется.
@{6.2\1\3}

var square = 0
var diceRoll = 0
while square < finalSquare {
    // бросить кубик
    diceRoll += 1
    if diceRoll == 7 {diceRoll = 1}
    // сброс значения кубика
    square += diceRoll
    if square < board.count {
        // Если мы всё ещё на доске, переместиться вверх или вниз через змею или лестницу
        square += board[square]
    }
}
print("Game over!")