Javaの数当てゲームは、プログラミング学習で定番の教材です。使うのはRandom・Scanner・while文・if文の4つだけ。3ステップで作れます。
コピペでそのまま動く完成コードも用意しました。試行回数制限・難易度設定・リプレイ機能や、3桁への範囲変更といった発展的な出題にも対応できるところまで進めます。
参考書を読み込むだけでは身につかず、手を動かして初めて定着した、というのが私自身の学習の実感です。この記事も、読むより先に動かす順番で組みました。
「すぐにコードを動かしたい!」という方は、完成コード(コピペOK)へジャンプしてください。
Java数当てゲームのルールとプレイイメージ

数当てゲームとは、コンピュータが決めた秘密の数を、プレイヤーが「もっと大きい」「もっと小さい」というヒントを頼りに当てるゲームです。
数当てゲームは、プログラミング学習の題材として定番のゲームです。シンプルですが、奥は深いです。変数・条件分岐・繰り返しという3大要素をすべて使うため、多くのプログラミング教材で最初のゲーム課題に選ばれます。まずは、そのルールと実際のプレイの流れを見ていきましょう。
読み方と表記
読み方は「かずあてゲーム」です。
記事や教材によって「数当てゲーム」「数あてゲーム」「数字当てゲーム」と複数の表記が使われていますが、いずれも同じゲームを指します。
本記事ではコードのクラス名(NumberGuessingGame)との整合性を取り、漢字表記の「数当てゲーム」で統一します。
ルール
数当てゲームの基本的なルールはシンプルです。
- コンピュータがランダムな数を決める: 0から100までの範囲で、一つの整数を秘密裏に選ぶ
- プレイヤーが数を予想する: プレイヤーは、コンピュータが選んだと思われる数を入力する
- コンピュータがヒントを出す: プレイヤーが入力した数とコンピュータが選んだ数を比較し、「もっと大きい」「もっと小さい」といったヒントを出す
- 正解するまで繰り返す: プレイヤーはヒントを頼りに、正解の数にたどり着くまで予想と入力を繰り返す
- 正解!: 見事、コンピュータが選んだ数と同じ数を入力できればゲームクリア
ルールは簡単ですが、ヒントを元に効率よく正解に近づく戦略を考えたり、試行回数に制限を設けたりすることで、ゲーム性を高められます。
プレイイメージ
実際にプレイすると、以下のようになります。
このような対話形式でゲームが進んでいきます。プログラミングで作ることで、この一連の流れを自動化できるのです。
ステップ①:Randomで正解の数を決める

最初のステップは、ゲームの核となる「コンピュータが秘密の数を決める」処理の実装です。Javaでランダムな数を生成するにはRandomクラスを使います。
Randomの使い方
Randomクラスは、さまざまな種類の乱数を生成する機能を提供します。Randomクラスを使うには、まずオブジェクトを作成します。
コードの最初にimport java.util.Random;と書くことで、Randomクラスが使えるようになります。
そして new Random() でオブジェクトを作り、nextInt() メソッドを呼び出すことで、ランダムな整数を取得します。
範囲設定
nextInt(n)メソッドは、0以上n未満の整数をランダムに返します。
したがって、0から100までの範囲の整数が欲しい場合は、n に101を指定します。
nextInt(101)の実行で、randomNumberに0から100までのいずれかの整数がランダムに代入されます。
randomNumberが、プレイヤーが当てるべき正解の数です。
ステップ②:Scannerでプレイヤーの予想を受け取る

次に、プレイヤーが予想した数をキーボードから入力してもらう処理を作ります。これには Scannerクラスが便利です。
Scannerの使い方
Scannerクラスは、キーボードからの入力やファイルからの読み込みなど、さまざまな入力ソースからデータを読み取るためのクラスです。
Randomと同様に、import java.util.Scanner;でScanner クラスをインポートします。
new Scanner(System.in)で、キーボードからデータを読み取るScannerオブジェクトを作成します。
nextInt()メソッドは、入力された文字列を整数(int)に変換して返します。
最後に、使い終わったScannerはscanner.close();で閉じるのがお作法(マナー)です。
💡 ハマりポイント:Scannerをclose()せずに放置すると、Eclipseでは既定の設定で「Resource leak」の警告が表示されます(ほかのIDEでも設定によって同様の警告が出ます)。
ただし、複数のScannerをSystem.inに対して作ってclose()すると問題です。
内部的に標準入力ストリームが閉じてしまい、閉じたScannerをもう一度使うとIllegalStateException、後から新しく作ったScannerで読み取ろうとするとNoSuchElementExceptionが出ます。
1つのScannerをプログラム全体で使い回し、最後に1回だけclose()するのが安全です。
エラー処理
scanner.nextInt()は整数を期待しますが、もしユーザーが文字などを入力すると、エラー (例外) が発生してプログラムが停止してしまいます。
本格的なアプリケーションでは、このような予期せぬ入力に対応する「エラーハンドリング(予期せぬ入力への対処)」が必要です。
hasNextInt()で整数かどうかを確認する方法や、try-catch構文で例外を捕まえる方法があります。
本記事はシンプルさを優先し、エラーハンドリングは省略します。
補足すると、Javaを学び始めた頃はNullPointerExceptionや今回のInputMismatchExceptionのような例外に何度も遭遇しました。
そのたびにスタックトレースを読むことすら苦痛でした。
ですが「どの行で」「なぜ」例外が起きたかをエラーメッセージから読み取る練習を重ねると、次第に例外は"怖いもの"ではなく"原因を教えてくれるヒント"だと感じられるようになります。
数当てゲームであえて文字を入力してエラーを起こしてみるのも、良い練習になります。
ステップ③:if文とwhile文でヒントを出して繰り返す

if-else文で大小を比較する
プレイヤーの入力 (playerGuess) と正解の数 (randomNumber) を比較するには if-else文を使います。
playerGuessがrandomNumberより大きければ、「もっと小さいです」と表示します。playerGuessがrandomNumberより小さければ、「もっと大きいです」と表示します。- どちらでもなければ (つまり等しければ)、「正解!」と表示します。
while文で正解するまで繰り返す
一度だけの予想ではゲームになりません。正解するまで何度も予想とヒントの表示を繰り返す必要があります。これには while文が適しています。
「プレイヤーの入力と正解の数が等しくない間」という条件でループさせ、ループの中で入力とヒント表示を行います。
上のコードでは、whileループを使って、playerGuessとrandomNumberが一致しない限り、入力を促し、ヒントを表示し続けます。
一致した時点で elseブロックが実行され、正解メッセージが表示されてループが終了します。試行回数をカウントする変数 attemptsも追加しました。
💡 なぜ playerGuess = -1 で初期化するのか:今回のゲームは「0〜100の整数」を扱います。
そのため、ユーザーが絶対に入力しない値(=範囲外の-1)で初期化しておきます。
こうすることで、while (playerGuess != randomNumber)の条件を初回必ず真にしてループに入れます。
do-whileで書く方法もありますが、初期値で制御するパターンは「ループに入る前から条件式が成立している」ことを明示できる定番テクニックです。
実行方法
コードを書き終えたら、実際に動かしてみましょう。ファイル名は必ずクラス名と同じNumberGuessingGame.javaにする必要があります。
1行目のjavacコマンドでソースコードをコンパイルし、2行目のjavaコマンドで実行します。
IntelliJ IDEAやEclipse、Visual Studio CodeなどのIDEを使っている場合は、実行ボタン(▶)を押すだけで同様に動きます。
Java 11以降なら、javacを省略してjava NumberGuessingGame.javaとソースファイルを直接指定して実行することもできます。
入力待ちで止まったように見えるときは、ターミナルに数字を打ってEnterキーを押してください。
完成コード(コピペOK)
3つのステップを組み合わせると、Javaによる数当てゲームの完成です。以下のコードをそのままコピーして実行できます。
完成コード全文
上のコードは、ステップ①〜③の要素を組み合わせたものです。
main メソッドの中に、ゲームの準備、開始メッセージ、メインループ、終了処理という流れで記述されています。
メソッド分割:playGame()にゲーム本体を切り出す
完成コードが動いたら、次はコードをメソッドに分けて整理してみましょう。
メソッドを使うと、処理のかたまりに名前をつけて部品化でき、コードが読みやすくなります。
メソッド分割は、オブジェクト指向プログラミング(データと処理をまとめて管理する考え方)の入り口です。
メソッド分離例
ゲームのメインロジックを playGame() というメソッドに切り出すと、main メソッドがスッキリします。
main メソッドが「playGame() を呼ぶだけ」というシンプルな役割になりました。
ゲームロジックが独立したことで、後から機能を追加したり変更したりしやすくなります。
ちなみに、最初からメソッド分割しようとして手が止まる初心者は多いです。
実務でも「まず動くコードをmainにベタ書き → 動作確認後にメソッド抽出(リファクタリング)」という流れの方が、設計に悩まず学習が進みます。
本記事もあえてステップ①〜③で全部mainに書き、完成後にメソッド分割する順序にしているのはこの理由です。
実際、Java学習でつまずく人の多くは「参考書を読んで理解したつもり」で止まってしまいます。私自身もそうでした。
知識として知っていることと、実際に手を動かして完成させられることの間には大きな差があります。
数当てゲームのような小さな教材で、写経(コピペで動かす)→改造(試行回数制限などを追加する)の順に慣れていきましょう。最後は自作(似た別のゲームを一から作る)に挑戦すると、理解がぐっと深まります。
これが体感的にいちばん定着の早い学習ルートです。
応用実装:試行回数制限・リプレイ・難易度設定・3桁対応
基本の数当てゲームが完成したら、さらに面白くするための機能を追加してみましょう。
試行回数制限
簡単な難易度調整として、試行回数に上限を設ける方法があります。whileループの条件に、試行回数のチェックを追加します。
while の条件を attempts < maxAttempts && !isCorrect に変更します。
そして、ループ内で attempts が maxAttempts に達したらゲームオーバーのメッセージを表示するようにします。
リプレイ機能
ゲームをクリアしたあと「もう一度遊ぶか?」を聞いて、繰り返しプレイできるようにしてみましょう。
ゲーム全体を外側の do-while ループで囲むだけで実現できます。
do-while ループは「最低1回は実行し、条件が真の間繰り返す」構文です。ゲーム終了後に「y」を入力すると新しいゲームが始まります。
難易度設定
試行回数と難易度、両方とも固定のままでいいのでしょうか。実は、ゲーム開始時にプレイヤーに難易度を選んでもらい、それに応じて数の範囲や試行回数を変える設計もできます。
- 最初に難易度 (例: 1:簡単, 2:普通, 3:難しい) を入力してもらいます。
if文やswitch文を使って、選ばれた難易度に応じて、randomNumberの範囲 (nextIntの引数) やmaxAttemptsの値を設定します。
難易度設計では、単に数値を変えるだけでなく「試行回数に対して範囲がどれくらい広いか」のバランスにも注意が必要です。
たとえば上のサンプルコードの「難しい」設定(範囲0〜500・試行回数8回)を検証してみましょう。
範囲501通りを二分探索(毎回ちょうど半分に絞り込む最適な予想)で当てるには理論上9回必要です。
つまり8回では、最善を尽くしても外れる可能性が残ります。
自分で難易度を調整する際は、範囲の個数をNとしたとき、試行回数がlog₂(N)を切り上げた回数以上になっているかを目安に検証してみてください。
少しの工夫でゲームはもっと面白くなります。ぜひ挑戦してみてください。
3桁対応
「3桁の数当てゲーム」として出題したい場合は、random.nextInt(1000)とすることで0〜999の範囲に変更できます。範囲1000通りを二分探索で当てるには理論上10回必要になるため、maxAttemptsもあわせて10回前後に調整すると、無理なく遊べる難易度になります。
正解の数を常に3桁で表示したい場合は、System.out.printf("%03d%n", randomNumber);のようにprintfと書式指定子%03dを使うと、桁数を揃えて表示できます。
よくある質問(FAQ)
数当てゲームを実装するときに、初心者がつまずきやすいポイントをQ&A形式でまとめました。
Q1. 数字以外を入力するとどうなりますか?
scanner.nextInt()は整数のみを期待します。ユーザーが「abc」など文字を入力するとInputMismatchExceptionが発生してプログラムが停止します。本格的に対応する場合は、hasNextInt()で整数かどうかを事前判定するか、try-catch構文で例外を捕捉します。学習目的の今回は、シンプルさを優先して例外処理を省略しています。
Q2. 何度実行しても同じ乱数が出てしまうのはなぜですか?
new Random()は、他の呼び出しと重複しにくい値(現在時刻をもとにした値など)をシードとして使うため、通常は実行ごとに異なる乱数が生成されます。同じ値が連続する場合は、ループ内でRandomオブジェクトを毎回 new し直していないか確認してください。Randomはループの外で1回だけ生成し、nextInt()を繰り返し呼び出すのが正しい使い方です。
Q3. 数の範囲を1〜100に変えるにはどうすればいいですか?
random.nextInt(101)は0以上100以下を返します。1〜100にしたい場合はrandom.nextInt(100) + 1と書き換えます。nextInt(n)は「0以上n未満」を返す仕様なので、最大値を含めたいときは引数に+1、最小値を1以上にしたいときは戻り値に+1します。Java 17以降であれば、random.nextInt(1, 101)のように下限と上限(上限は含まない)を直接指定する書き方も使えます。
Q4. 完成コードは何行くらいで書けますか?
コメント・空行を含めても50行弱で書けます。本記事の「完成コード(コピペOK)」セクションのコードは、import文2行・クラス宣言・mainメソッド内の準備〜終了処理まで含めて48行です。基本文法だけで書ける、初心者向けとして手頃なサイズのプログラムです。
Q5. while文とdo-while文はどちらを使うべきですか?
基本のゲームループにはwhile文、「もう一度プレイ」機能を追加する際はdo-while文が向いています。while文は条件を先に判定するため0回で終わる可能性がありますが、do-while文は必ず1回は実行されるため「最低1ゲームは遊ばせたい」といった場面に適しています。
Q6. 実行時にコンパイルエラーが出た場合はどうすればいいですか?
まずエラーメッセージに表示された行番号を確認し、セミコロンの付け忘れや括弧の対応を見直してください。よくあるコンパイルエラーのパターンと解決法は、関連記事(Javaコンパイルエラー原因5選と解決法)でまとめて解説しています。
Q7. 0〜9のような小さい範囲の乱数にするにはどうすればいいですか?
random.nextInt(10)のように、nextInt()の引数を欲しい範囲の個数に変更するだけです。nextInt(n)は「0以上n未満」を返すため、0〜9の10通りが欲しい場合は引数に10を指定します。
まとめ
本記事では、Javaプログラミング入門として、数当てゲームの作り方を解説しました。
数当てゲームを作ることで、Javaの基本的な要素を実践的に学べています。
RandomやScannerの使い方、if文の条件分岐、while文の繰り返し。
プログラミングの根幹となる概念を、実際にコードとして書いて動かしたからです。
さらに、メソッドへの切り出しやリプレイ機能の実装を通じて、「動くコードをより良いコードへ改善する」という開発の流れも体験できました。
次は、じゃんけんゲームやTodoリストアプリなど、少し複雑なプログラムに挑戦してみてください。
学べるポイント
- 標準ライブラリの活用:
RandomやScannerといった、Javaが提供する便利なクラスの使い方。 - 変数とデータ型:
intを中心としたデータの扱い方。 - 制御構造:
if文による判断とwhile/do-while文による繰り返し。 - 基本的な入出力: コンソールへの表示 (
System.out.println) とキーボードからの入力 (Scanner)。 - メソッドへの分離: コードを部品化して読みやすく、改修しやすくする設計の第一歩。
- プログラムの構造:
mainメソッドを中心とした基本的なプログラムの組み立て方。
| REV. | DATE | 内容 |
|---|---|---|
| 6 | 2026-10-04 | 記載内容の事実確認と修正 |
| 5 | 2026-09-21 | 2026年9月時点の情報で全体を見直し |
| 4 | 2026-09-14 | 2026年9月時点の情報で全体を見直し(古い記述を2件更新) |
| 3 | 2026-08-31 | 2026年8月時点の情報で全体を見直し |
| … ほか1回の改訂 | ||
| 1 | 2025-05-29 | 初版 |






