while ループは条件が false になるまでループブロックを実行します。この種のループは事前に繰り返し処理すべき回数がわからない場合に適しています。Swift には、while ループが 2 種類あります。

  • while は、繰り返し処理のたびに、最初に条件を評価します。
  • repeatwhile は、繰り返し処理のたびに、最後に条件を評価します。

while

while ループは、条件の評価から開始します。条件が true の場合、条件が false になるまでループブロックを繰り返します。

while ループの一般的な形式は、次のようになります。

while condition {
    statements
}

この例は、シンプルな「蛇と梯子」(Chutes and Ladders としても知られる)ゲームです。

image: snakesAndLadders_2x

ゲームのルールは、以下のようになります。

  • ボードには 25 マスあり、目的は 25 マス目に到着するか、越えることです。
  • 各ターンで、6 面のサイコロを振って出た数だけ、矢印の方向にマスを移動します。
  • 梯子の下側で止まった場合、梯子の上側に移動します。
  • 蛇の頭側で止まった場合、蛇の下側に移動します。

ゲームボードは、Int 値の配列で表現されています。サイズは定数 finalSquare で、配列の初期化と、勝利条件の判定に使用されます。ボードは 25 個ではなく、(0 から 25 までの)26 個の Int 値ゼロで初期化されます。

let finalSquare = 25
var board = [Int](count: finalSquare + 1, repeatedValue: 0)

いくつかのマスには、蛇および梯子用に特別な値が設定されています。梯子の下側のマスには、ボード上方に進めるためのプラス値があります。一方で、蛇の頭側のマスには、ボード下方に戻すためのマイナス値があります。

board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08

マス 3 は梯子の下側で、マス 11 に進みます。これを表現するために、board[03] を整数値の 83 と 11 の差)に相当する +08 としています。単項プラス演算子 (+i) を付けて単項マイナス演算子 (-i) と釣り合わせ、10 未満の数値をゼロ埋めすることで、すべてのボード定義がそろうようにしています。(調整する必要は無いですが、コードがすっきりします。)

プレイヤーの開始マスは「ゼロ」で、ボード左下の外になります。最初のサイコロで、プレイヤーはボード上を移動することになります。

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!")

この例では、サイコロについてシンプルなアプローチを採っています。ランダムな数値を生成せずに、diceRoll の値を 0 で開始しています。while でループするたびに、diceRoll を 1 増加させ、大きくなりすぎることがないようチェックしています。この戻り値が 7 のときに、サイコロが大きくなりすぎたと判定し、サイコロは 1にリセットされます。diceRoll の値は、12345612、と続くことになります。

サイコロを振った後、プレイヤーは diceRoll の数だけマスを進みます。サイコロの数によっては、25 マス目を通り越す場合がありますが、そこでゲーム終了となります。このシナリオに対処するために、プレイヤーが梯子や蛇を上下に移動する board[square] の値を square 値に追加する前に、square が board 配列の count プロパティよりも小さいことをチェックします。

このチェックが実行されない場合、board[square] が board 配列の範囲外の値にアクセスしようとし、エラーを引き起こします。square が 26 の場合には、コードは配列のサイズより大きい board[26] の値をチェックしようとしてしまいます。

現在の while ループの終了時に、ループを再実行すべきかの条件がチェックされます。プレイヤーが移動して 25 マス目に達するか、または越えた場合、ループの条件は false と評価され、ゲーム終了となります。

while ループは、while ループの開始時点でゲームの長さが明確でないため、このケースに適しています。特定の条件が満たされるまでループは実行されます。

repeat-while

while ループのもう一方のバリエーションが repeatwhile ループで、ループ条件の前にまず一度ループブロックを実行します。そして、条件が false になるまでループを繰り返します。

NOTE
Swift の repeatwhile ループは、他の言語での dowhile ループに類似しています。

repeatwhile ループの一般的な形式は、次のようになります。

repeat {
    statements
} while condition

次の例は再び「蛇と梯子」で、while ループでなく repeatwhile ループで記述されています。finalSquareboardsquarediceRoll の値は、while ループとまったく同じように初期化されています。

let finalSquare = 25
var board = [Int](count: finalSquare + 1, repeatedValue: 0)
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
var square = 0
var diceRoll = 0

ゲームのこのバージョンでは、ループ内での最初のアクションは梯子と蛇をチェックすることです。ボード上にプレイヤーをそのまま 25 マス目に進める梯子は無いため、梯子を進み上がってゲームに勝つことはありません。そのため、ループ内での最初のアクションとして蛇と梯子をチェックしても安全です。

ゲーム開始時に、プレイヤーはゼロマス目にいます。board[0] は常に 0 で、何の影響もありません。

repeat {
    // 蛇や梯子で上下に移動
    square += board[square]
    // サイコロを振る
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }
    // 出た数だけ進む
    square += diceRoll
} while square < finalSquare
print("Game over!")

蛇と梯子をチェック後、サイコロを振り、プレイヤーは diceRoll の数だけ進み、現在のループを終了します。

ループの条件 (while square < finalSquare) は前と同じですが、今回は最初のループ実行が終了するまで評価されません。repeatwhile ループの仕組みは、前の例での whileループよりもこのゲームに適しています。上の repeatwhile ループでは、square がボード上にあることをループの while 条件が確認できた後すぐに、square += board[square] が常に実行されます。前のバージョンにあった配列の範囲を確認する処理を無くすことができています。


Portions of this page are translations based on work created and shared by Apple and used according to terms described in the Creative Commons Attribution 4.0 International License.