このページでは、Django を利用した「数当てゲーム」の開発について解説していきます!
この Django での「数当てゲームの開発」に関する解説は前編・後編構成となっています。この前編では、数当てゲームを開発する上でポイントとなる内容の解説や、実際の数当てゲームの Django での作り方について解説していきます。
また、下記ページの後編では数当てゲームを拡張し、ログイン機能・ランキング機能等を搭載することで、よりウェブアプリっぽいアプリに仕立てていきます。
![Djangoでの数当てゲームの拡張の仕方・ポイントの解説ページアイキャッチ](https://daeudaeu.com/wp-content/uploads/2025/02/django-hit-blow-second-eyecatch-160x160.png)
題材がゲームなので作ってみて楽しいと思いますし、このページで解説する内容は、様々なゲームやアプリの開発に応用することもできると思いますので、是非ページを読み進めていっていただければと思います!
Contents
数当てゲーム
まず、今回開発するウェブアプリについて簡単に説明しておきます。
前述の通り、今回は「数当てゲーム」を開発していきます。数当てゲームとは、正解となる数字(今回は4桁の数字)を予想するゲームになります。特に、「数当てゲーム」の中でも、Hit & Blow (他にもマスターマインドや Numer0n とも呼ばれる) と呼ばれるゲームを開発していきます。
このゲームでは、予想を回答した際に、単に正解・不正解という情報だけでなく、「正解への近さ」の情報が出力されるようになっています。具体的には、下記の Hit 数と Blow 数が出力されるようになっています。
- Hit 数:正解と「位置」も「数字」も合っている桁の個数
- Blow 数:「位置」は合っていないが「数字」自体は正解に含まれている桁の個数
例えば、正解が 3024
で、それに対して回答された予想が 4321
の場合、2
に関しては正解と桁が合っているので Hit と判断され、さらに 3
と 4
に関しては桁は一致していないが数字自体は含まれているため Blow と判断されます。そのため、3024
を入力した場合は 1 Hit / 2 Blow と出力が得られることになります。この正解への近さという情報を基に、正解となる数字を予想していく、つまり、4 Hit を目指していくというのが Hit & Blow となります。
「数当てゲーム」を開発する場合は、もちろん Hit 数・Blow 数の算出や、正解・不正解を判断するようなロジックも重要です。ですが、“Django でウェブアプリとして” 数当てゲームを開発する場合は、それらに加えてビュー・フォーム・テンプレート等を上手く利用してゲームを実現していくという点も重要になります。また、Django で開発することで、ウェブアプリの特徴的な機能、例えばログイン機能やランキング機能を搭載するようなことも簡単に実現可能です。
ページの冒頭でも説明したように、このページでは、まずは数当てゲームとして最低限機能するウェブアプリの開発を行っていきます。そして、後編となる下記ページで、ウェブアプリに搭載することの多い「ログイン機能」や「ランキング機能」等を搭載し、よりウェブアプリらしいアプリに仕立てていく手順を解説していきます。
![Djangoでの数当てゲームの拡張の仕方・ポイントの解説ページアイキャッチ](https://daeudaeu.com/wp-content/uploads/2025/02/django-hit-blow-second-eyecatch-160x160.png)
数当てゲームの開発のポイント
まずは数当てゲームをウェブアプリとして開発するためのポイント説明していきたいと思います。
スポンサーリンク
データベースでの正解データの管理
この数当てゲームを開発する上でポイントになるのが、正解データ(正解の数字)の管理になります。
前述の通り、数当てゲームは、ユーザーが何回も試行しながら正解データを予想していくゲームになります。
ウェブアプリの場合、この試行は、ウェブアプリへの HTTP リクエストの送信によって実施されることになります。さらに、その結果(Hit 数 / Blow 数)は、ウェブアプリからの HTTP レスポンスの返却で通知されることになります。もう少し具体的に言えば、フォームから予想をボディとする HTTP リクエストを送信し、結果を記述した HTML をボディとする HTTP レスポンスが返却されることになります。
この複数回の HTTP リクエストと HTTP レスポンスの送受信の間、ウェブアプリは同じ正解データを管理し続け、その正解データを利用して結果を判断する必要があります。毎回異なる正解データに変化してしまうと、Hit 数 / Blow 数というヒントの意味が無くなり予想ができなくなってしまいますよね…。
例えば、Django で開発したウェブアプリの場合、ビューとして定義した関数は HTTP リクエストを受信するたびに実行されることになります。なので、ビューの中でローカル変数を利用して正解データを管理したりすると、HTTP リクエストを受信するたびに正解データが変化してしまうことになるので注意が必要です。
ということで、数当てゲームを開発するためには、複数の HTTP リクエストを跨いで同じデータを保持し続けることが必要となります。で、こういったデータの保持を実現するのに便利なのがデータベースとなります。データベースに保存されたデータは、複数の HTTP リクエストを跨いで保持され続けますし、ウェブアプリやサーバー等を再起動しても保持され続けます。つまり、永続的なデータの管理が可能となります。そして、これにより、同じ正解データに対して何回も予想を試行することが可能なウェブアプリを実現できます。
他にも、正解データをファイルに記録しておくような方法もありますが、Django の場合はデータベースが簡単に利用できるため、データベースで正解データを管理するようにした方が楽だと思います。
また、何回も数当てゲームをプレイできるようにするためには、ユーザーが正解したタイミングで新たな正解データを作成し、それをデータベースで管理するような処理も必要となります。ずっと同じ正解データだとゲームとして楽しくないですからね…。
ユーザー単位での正解データの管理
とりあえず、データベースで正解データを管理するようにしてウェブアプリを開発すれば、数当てゲーム自体はプレイできるようになるはずです。
ユーザー単位での正解データの管理の必要性
ただし、1つの正解データを管理するだけだとゲームが破綻する可能性があり、必要に応じてユーザー毎に正解データを管理するようにする必要があります。要はユーザーごとに独立してゲームをプレイできるようにするためには、ユーザー毎に正解データを用意し、予想した数字を送信してきたユーザーに応じて、参照する正解データを切り替えるような処理が必要となります。
簡単に、この理由について説明しておきます。
まず、ウェブアプリは、同時に複数のユーザーから利用される場合があります。むしろ、それができることがウェブアプリの1つの特徴と言って良いと思います。数当てゲームの場合であれば、同時に複数のユーザーからゲームがプレイされる可能性があるということになります。そして、ウェブアプリで1つの正解データのみを管理する場合、各ユーザーが同じ正解データを共有し、その正解データの予想を行うことになります。
この場合、特定のユーザーが正解を当てたタイミングで「正解データ」が他の正解データに切り替わることになりますので、他のユーザーが予想中の正解データが勝手にいきなり変わってしまうことになります。また、正解データを切り替えないような場合は、同じ正解データなので、正解したユーザーから正解データが漏洩してしまう可能性もあります。このようなことが起こると、ゲーム・アプリとして破綻してしまうことになります。
こういったことを避けるために、ユーザー毎に別々の正解データを管理するようにし、各ユーザーが独立してゲームをプレイできるようにする必要があります。
もちろん、早押しクイズのようなウェブアプリを開発するのであれば、複数人がゲームをプレイしていたとしても、一人が正解したらすぐに次の正解データに切り替えるような作りにする必要があります。つまり、結局はどういったウェブアプリを開発したいのかによって作り方も変わるのですが、今回はユーザーごとに独立してゲームがプレイできるようにしていきたいので、ユーザー単位で異なる正解データを用意するようにしていきたいと思います。
ユーザーの識別
で、このユーザー単位での正解データの管理を実現する上で重要になるのが「ユーザーの識別」になります。ユーザー毎に正解データを管理するようにしたとしても、予想した数字を送信してきたユーザーが識別できなければ、結果を判断するために参照すべき正解データも分かりません。
このユーザーの識別に便利な機能が「ログイン」になります。ログイン機能を搭載しておけば、リクエストを送信してきたユーザー、すなわち、ウェブアプリを利用しているユーザーを識別することが可能となります。なので、ユーザー毎に正解データを用意し、ユーザーに応じて参照する正解データを切り替えるような処理を簡単に実現することができます。
ただ、ログイン機能を搭載するのは結構大変です。そのため、今回は「セッション」を利用して簡易的なユーザーの識別を実現していきたいと思います。このセッションを利用した識別は、正確に言えばクライアント(ウェブブラウザ・デバイス)の識別となります。
セッションとは、クライアントとウェブアプリ(サーバー)との間で、ウェブアプリの利用開始から利用終了までの一連の通信を管理するための仕組みのことを言います。Django で開発したウェブアプリでは、クライアントがウェブアプリを利用開始する時にセッション ID を発行し、その ID をクライアントに対して返却することができるようになっています。そして、ウェブブラウザ等の一般的なクライアントでは、以降のウェブアプリに対する HTTP リクエスト送信時に、そのセッション ID を一緒に送信するようになっています。
このセッション ID はクライアントごとに発行されるため、このセッション ID によってクライアントを識別することができるようになります。あとは、セッション ID に紐づける形で正解データを管理するようにウェブアプリを開発すれば、クライアント単位での正解データの管理が実現できることになり、各ユーザーが独立してゲームをプレイすることができるようになります。
ただし、前述の通り、このセッションを利用した識別は、ユーザーの識別ではなくクライアント(使用しているウェブブラウザや PC 等のデバイス)の識別です。なので、同じユーザーだとしても、異なるウェブブラウザや異なる PC・スマホ等からアプリを利用した場合は、異なる利用者であると判断されてしまいます。
また、ウェブブラウザではセッション ID が保存されるようになっていますが、このセッション ID が削除されたり有効期限が切れたりすることもあります(Django の設定でセッション ID の削除・有効期限切れを防ぐことも可能ですが、セキュリティリスクやウェブアプリ側の負荷が増加する可能性があります)。そして、セッション ID が削除されたり有効期限が切れたりすると、また新たにセッション ID がウェブアプリで発行されることになり、今までとは異なる利用者と判断されることになります。なので、それまで予想していた正解データでの数当てゲームが継続できなくなります。
こういった課題は、前述でも触れたログイン機能の搭載によって解決することが可能です。ログイン機能を搭載することで、真の意味でのユーザーの識別が可能となります。ただし、今回は「数当てゲームの実現」という点に焦点を当てた解説を行いたいため、簡単に実現可能なセッションでの識別を採用したいと思います。ページの冒頭でも説明したように、このログインを数当てゲームに搭載する例は後編の下記ページで解説します。
![Djangoでの数当てゲームの拡張の仕方・ポイントの解説ページアイキャッチ](https://daeudaeu.com/wp-content/uploads/2025/02/django-hit-blow-second-eyecatch-160x160.png)
正解データのクライアントへの送信はダメ
また、「正解データはクライアントに送信しない」という点も、数当てゲームを開発する上での重要なポイントになります。
当たり前のように感じるかもしれませんが、これはウェブアプリを開発する上で非常に重要なポイントで、ここを注意しないとセキュリティリスクが生まれたりゲームとして成立しなくなったりしてしまいます。
今回の数当てゲームの場合であれば、前述で説明したような「複数の HTTP リクエストを跨いだ正解データの保持」は、サーバー側で正解データを保持・管理しなくても、クライアント側に正解データを送信するようにすることでも実現可能です。この場合、データベースに正解データを保存する必要が無くなるため、必要な記憶容量が削減可能です。また、データベースの利用が不要となるので実装も楽になります。こういったメリットが得られるとしても、正解データをクライアント側に送信することは NG です。
例えば、ウェブアプリからクライアントに送信する「回答の入力フォーム」に隠しフィールド(ページに表示されないフィールド)を設け、そのフィールドに正解データをセットするようにしておけば、回答の入力フォームを送信したときに自動的に正解データもウェブアプリに送信されるようになります。クライアントから正解データが送信されてくるため、ウェブアプリは正解データを管理する必要が無く、クライアントから送信されてきた正解データと回答データから結果(正解 or 不正解・Hit 数 / Blow 数)を計算すればよいだけになります。
また、下記ページで解説しているように、Django で開発したウェブアプリでも JavaScript を扱うことが可能で、上記のような方法で正解データをクライアント側に送信すれば、わざわざクライアントからウェブアプリに回答データを送信しなくても、ユーザーが回答フォームに値を入力したタイミングで JavaScript によって結果を判断するようなことも可能となります。
![Djangoで開発するウェブアプリでのJavaScriptの扱い方の解説ページアイキャッチ](https://daeudaeu.com/wp-content/uploads/2025/01/django-javascript-eyecatch-160x160.png)
つまり、クライアント側に正解データを送信すれば、実はウェブアプリの作りがシンプルになってウェブアプリが開発しやすくなりますし、通信の回数も減ってウェブアプリの負荷を減らすことも可能です。
なんですが、クライアント側に送信したデータは、基本的にはユーザーから閲覧することが可能です。例えば、前述のようにフォームに隠しフィールドを設けたとしても、ウェブブラウザでフォームの HTML のソースコードを表示してしまえば正解データをユーザーが確認することができてしまいます。
また、JavaScript のソースコードもウェブブラウザで確認可能で、さらにはブレークポイントを設定してスクリプトを停止し、そのタイミングの変数の中身を確認するようなこともできます。なので、JavaScript で正解データを扱うと、その正解データもユーザーにばれてしまいます。
このように、クライアントに送信したデータは基本的にはユーザーが確認可能です。なので、クライアント側でデータを管理させるようにすることでウェブアプリの開発が楽になる場合であっても、ユーザーに見られたくないデータはクライアントに送信してはダメで、機密性の高いデータはウェブアプリ側(サーバー側)のみで扱うようにウェブアプリを開発する必要があります。
今回の例では正解データが機密性の高いデータとなりますが、パスワード等も同様です。パスワードをクライアント側に送信するとパスワードが漏洩することになります。正解データの漏洩であれば笑い話で済むかもしれませんが、パスワードの漏洩は大問題となります。こういった、パスワードのような機密性の高いデータはクライアントに送信してはいけないという点は、ウェブアプリを開発する上で最重要と言っても過言ではないポイントとなりますので、是非このポイントについては覚えておいてください。
スポンサーリンク
Hit 数 / Blow 数の算出
また、今回は数当てゲームの中の Hit & Blow を開発していきますので、ユーザーからの数字の回答を受け付け、その回答と正解の数字から Hit 数や Blow 数を算出する必要があります。
ユーザーからの数字の回答の受付に関してはフォームを利用してやれば良いです。フォームに関しては下記ページで解説していますので、フォームの定義の仕方・フォームを扱うビューやテンプレートの作り方等のフォームの詳細に関しては下記ページを参考にしていただければと思います。
![Djangoのフォームの解説ページアイキャッチ](https://daeudaeu.com/wp-content/uploads/2023/04/django-form-eyecatch-160x160.png)
さらに、このフォームから送信されてきた数字と、データベースで管理している正解データを照合し、Hit 数と Blow 数を算出する必要があります。
ただ、どちらも算出方法は単純で、まず Hit 数に関しては、両方の同じ桁の数字を一つ一つ比較し、一致している桁数を Hit 数としてカウントすればよいだけです。
また、Blow 数に関しては、正解 or 回答データの各桁の数字が他方側のデータに含まれている個数をカウントし、その個数から Hit 数を減算することで求めることができます(正解データの各桁の数字が重複しないことを前提とした算出方法になります)。
具体的には、下記のようなコードで Hit 数と Blow 数は算出可能です。
# answer:正解(4桁の文字列)
# guess:ユーザーの回答(4桁の文字列)
hit = 0
for a, g in zip(answer, guess):
if a == g:
hit += 1
blow = 0
for g in guess:
if g in answer:
blow += 1
blow -= hit
また、内包表記を利用すれば下記のようなコードで算出することもできます。
# answer:正解(4桁の文字列)
# guess:ユーザーの回答(4桁の文字列)
hit = sum(1 for a, g in zip(answer, guess) if a == g)
blow = sum(1 for g in guess if g in answer) - hit
以上が、数当てゲームを Django で開発する上でのポイントの説明となります。
数当てゲームの作り方
ここからは、数当てゲームの Django での作り方について、実際に数当てゲームを開発しながら解説していきたいと思います。
プロジェクトの作成・アプリの作成
Django でウェブアプリを開発する時には、最初にプロジェクトとアプリを作成する必要があります。これらに関しては、一般的なウェブアプリを作る時と同じ手順で OK です。
今回は、プロジェクト名を number_guess
とし、アプリ名を game
としたいと思います。まずはプロジェクト number_guess
を作成するため、コンソールアプリを起動して適当なフォルダに移動後、下記のコマンドを実行してください。
% django-admin startproject number_guess
このコマンドの実行によって、コマンドを実行したフォルダに number_guess
フォルダが作成されるはずなので、この number_guess
フォルダに移動し、さらに下記のコマンドでアプリ game
を作成してください。
% python manage.py startapp game
続いて、number_guess
フォルダ内の settings.py
の INSTALLED_APPS
のリストの先頭に、下記のように 'game',
を追加してください。
INSTALLED_APPS = [
'game',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
次に、number_guess
フォルダ内の urls.py
を下記のように変更し、/game/
から始まる URL のリクエストを受け取った時に game
フォルダ内の urls.py
が参照されるようにします。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('game/', include('game.urls')),
]
スポンサーリンク
モデルクラスの定義
ここからは game
フォルダ内のファイルを変更し、アプリを作りこんでいきます。
まずはモデルクラスの定義を行っていきます。データベースでの正解データの管理 でも解説したように、ユーザーが何回も回答を試行できるようにするためには、正解データの永続的な保持が必要となります。そのため、データベースで正解データを管理できるよう、正解データを管理するフィールドを持つモデルクラスを定義する必要があります。
ということで、models.py
を下記のように変更してください。下記で定義する Game
は数当てゲームを管理するモデルクラスとなります。answer
が数当てゲームの正解を管理するフィールドとなります。
from django.db import models
class Game(models.Model):
answer = models.CharField(max_length=4) # 正解
attempts = models.IntegerField(default=0) # 予想回数
is_finished = models.BooleanField(default=False) # ゲームクリアフラグ
session_id = models.CharField(max_length=40) # セッションID
ポイントは session_id
フィールドになります。ユーザー単位での正解データの管理 で説明したように、各ユーザーが独立してゲームをプレイできるようにするためには、ユーザー(クライアント)を識別するための情報に紐づけてゲーム(正解の数字)を管理する必要があります。今回は、その識別するための情報としてセッション ID を採用し、この session_id
フィールドを設けてゲームとセッション ID を紐づけて管理することで、各ユーザーが独立してゲームをプレイできるようにしていきます。
また、他にも、attempts
でユーザーが回答した回数を管理、さらに is_finished
でユーザーが既に正解を回答済み(ゲームクリア済み)であるかどうかを管理するようにしています。
フォームの定義
また、数当てゲームでは、ユーザーから予想した数を回答してもらうために、下図のような「回答用のフォーム」が必要となります。次は、このフォームを定義していきます。
そのために game
フォルダ内に forms.py
を新規作成し、ファイルの中身を下記のように変更してください。GuessForm
が回答用のフォームであり、number
フィールドが予想した数を入力するフィールドになっています。number
フィールドでは4桁の半角数字のみを入力可能とするため、max_length
や min_length
、validators
の引数指定を行っています。
from django import forms
from django.core.validators import RegexValidator
class GuessForm(forms.Form):
number = forms.CharField(
max_length=4,
min_length=4,
validators=[
RegexValidator(r'^[0-9]{4}$', '半角数字4桁のみ入力してください。'),
],
label='予想した数字'
)
ビューの定義
次はビューを定義していきます。今回は、ビューは関数ベースで定義していきます。
models.py
で定義した Game
がゲームを管理するモデルクラスとなっていますので、この Game
のレコードを取得してゲームの情報(特に正解の数字や予想回数)を参照したり、ゲームのクリア状況等に応じて Game
のレコードを更新したりする必要があるという点がビュー定義時のポイントになります。また、クライアントを識別するためにも、Game
のレコードの session_id
フィールドを上手く利用するという点も重要なポイントになります。
今回は、下記のように views.py
を変更して数当てゲームを実現していきたいと思います。いろいろ定義していますが、ビューとして機能するのは index
関数のみで、その他は index
関数で数当てゲームを実現するために利用されるクラスや関数となっています。
from django.shortcuts import render
from .models import Game
from .forms import GuessForm
import random
class Guess:
def __init__(self):
self.game = None # プレイ中のゲーム
self.number = None # 予想した数
self.attempts = None # 予想回数
self.hit = None # Hit数
self.blow = None # Blow数
def set_hit_blow(self):
# ヒット数(桁まで一致している数字の個数)
self.hit = sum(1 for a, g in zip(self.game.answer, self.number) if a == g)
# ブロウ数(桁は一致していないが正解に含まれている数字の個数)
self.blow = sum(1 for g in self.number if g in self.game.answer) - self.hit
def create_answer():
# ランダムな4桁の数字(重複無し)の文字列を生成
return ''.join(map(str, random.sample(range(10), 4)))
def index(request):
# セッションIDに紐づくゲームの管理情報を取得
game = Game.objects.filter(session_id=request.session.session_key, is_finished=False).first()
if game is None:
# まだゲームが開始されていない場合
if request.session.session_key is None:
# セッションIDが送信されてきていない場合
# セッションIDを発行
request.session.create()
# Gameを作成(セッションIDと紐づけ)
game = Game.objects.create(
answer=create_answer(), # 正解データ
session_id=request.session.session_key # セッションID
)
guess = None
if request.method == 'POST':
# フォームからデータが送信されてきた場合
# 受信したデータからフォームを作成
form = GuessForm(request.POST)
if form.is_valid():
# 受信したデータが妥当である場合
# 予想回数をインクリメント
game.attempts += 1
# ユーザーが予想した数を取得
number = form.cleaned_data['number']
# Guessクラスのインスタンスを生成
guess = Guess()
guess.number = number
guess.game = game
guess.attempts = game.attempts
# Hit数とBlow数を計算
guess.set_hit_blow()
if guess.hit == 4:
# 予想した数が正解の場合
# ゲーム終了フラグをセット
game.is_finished = True
# レコードを更新
game.save()
else:
# フォームからデータが送信されてきていない場合
# 空のフォームを生成
form = GuessForm()
context = {
'game': game,
'guess': guess,
'form': form
}
return render(request, 'game/guess.html', context)
ゲームの管理
この views.py
における index
関数の処理の流れを確認していきましょう!
index
関数で最初に行っているのは、クライアントから送信されてきたセッション ID に紐づく Game
のレコードの取得になります。ゲームがクリアされていないレコードのみを取得するようにしています。下記の処理からも分かるように、クライアントから送信されてきたセッション ID は request.session.session_key
から取得可能です。セッション ID はクライアントごとに異なるため、Game
のレコードでゲームの状態を管理するようにし、さらにセッション ID と紐づけてレコードを管理するようにしておけば、ウェブアプリでクライアントごとに独立してゲームの状態を管理することができるようになります。
game = Game.objects.filter(session_id=request.session.session_key, is_finished=False).first()
ただし、ゲーム開始時、具体的には、次のような場合は上記の処理でレコードの取得に失敗してしまいます。
- 初めてウェブアプリを利用する(
request.session.session_key
がNone
の場合) - ゲームクリア直後(
is_finished=False
を満たすレコードが存在しない場合)
このような場合は、上記の処理において game
が None
となるため、必要に応じてセッション ID を発行したのちに、新たに Game
のレコードを作成するようにしています。で、この Game
のレコード作成時には、下記のようにセッション ID を紐づけておく必要があるところがポイントになります。また、下記で実行している create_answer
は、views.py
に定義した「正解データを生成する関数」となります。
# Gameを作成(セッションIDと紐づけ)
game = Game.objects.create(
answer=create_answer(), # 正解データ
session_id=request.session.session_key # セッションID
)
さらに、リクエストのメソッドが POST
の場合、つまりクライアントからデータが送信されてきている場合は、その送信されてきたデータからユーザーが予想した数字を取得し、Guess
の set_hit_blow
メソッドで Hit 数と Blow 数の算出を行っています。この set_hit_blow
での Hit 数と Blow 数の算出は、多少変数名等は異なりますが、基本的には Hit 数 / Blow 数の算出 で紹介したコードと同じとなります。
さらに、Hit 数が 4
の場合は、予想が的中してゲームクリアということになるので、この場合はゲームクリアフラグである game.is_finished
を True
にセットするようにしています。これにより、次回 index
関数が実行された際には、最初に実施する Game
のレコードの取得に失敗するようになり、新たな Game
のレコードが作成され、新たな正解に対してゲームが開始されることになります。
回答の管理
また、views.py
で定義している Guess
は、ユーザーの回答情報を管理するクラスになっています。
わざわざ回答情報を管理するクラスを定義している理由は2つで、1つはコンテキストを作りやすくするためです。クラスとして情報を1つに集約することで、コンテキストにキーを1つ追加するだけで、ページに表示したい「回答に関する情報」を全てテンプレートに渡すことができるようになります。
もう1つが、下記の後編でのコードの変更を楽にするためになります。下記の後編では、回答情報をデータベースに保存するように数当てゲームを拡張します。データベースに保存するので、回答情報をモデルクラスで管理することになります。回答情報をモデルクラスで管理するようにした場合でも、通常のクラスで回答情報を管理するようにしていればコードはほとんど変更が不要となるので、予め回答情報を管理するクラスを定義し、それを使ってビューを実装するようにしています。
![Djangoでの数当てゲームの拡張の仕方・ポイントの解説ページアイキャッチ](https://daeudaeu.com/wp-content/uploads/2025/02/django-hit-blow-second-eyecatch-160x160.png)
後は、基本的にはフォームを扱うビューとして典型的な流れの処理を実施しているだけになります。フォームやビューに関して詳しく知りたいという方は下記ページを参考にしていただければと思います。
![Djangoのフォームの解説ページアイキャッチ](https://daeudaeu.com/wp-content/uploads/2023/04/django-form-eyecatch-160x160.png)
![Djangoのビューの機能についての解説ページアイキャッチ](https://daeudaeu.com/wp-content/uploads/2024/09/django-view-eycatch-1-160x160.png)
スポンサーリンク
テンプレートの作成
ビューが完成したので、次はビューから利用されるテンプレートファイルを作成していきます。
index
関数の最後に実行している render
関数の第2引数に 'game/guess.html'
を指定しているため、この render
関数実行時には下記のパスのテンプレートファイルが利用されることになります。
game/templates/game/guess.html
そのため、このパスにテンプレートファイルを作成し、index
関数が実行された際に数当てゲームプレイ用のページが表示されるようにしていきます。
まずは、game
フォルダ内に templates
フォルダを作成し、さらに templates
フォルダ内に game
フォルダを作成してください。その後、最後に作成した game
フォルダ内に guess.html
を作成してください。
そして、その guess.html
に下記をコピペしてください。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>数当てゲーム</title>
</head>
<body>
<h1>数当てゲーム</h1>
{% if not game.is_finished %}
<h2>{{ game.attempts|add:1 }}回目の予想</h2>
<form method="post" action="{% url 'index' %}">
{% csrf_token %}
<table><tbody>{{ form.as_table }}</tbody></table>
<button type="submit">回答</button>
</form>
{% else %}
<p>正解です!!!</p>
<p>もう一度プレイする場合は<a href="{% url 'index' %}">ココ</a>をクリックしてください</p>
{% endif %}
{% if guess is not None %}
<h2>前回の予想結果</h2>
<table>
<thead>
<tr>
<th>予想回数</th><th>予想した数字</th><th>ヒット数</th><th>ブロウ数</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ guess.attempts }}</td>
<td>{{ guess.number }}</td>
<td>{{ guess.hit }}</td>
<td>{{ guess.blow }}</td>
</tr>
</tbody>
</table>
{% endif %}
</body>
</html>
この guess.html
で実施しているのは主に下記の2つです。
- ユーザーから予想した数字の入力受付を行うフォームの出力
- 前回ユーザーが予想した数字の Hit 数・Blow 数を表示するテーブルの出力
ただし、Django のテンプレートタグの仕組みを利用して、game
(Game
のインスタンス)や guess
(Guess
のインスタンス)に応じて表示を切り替えるようにしています。例えば、ゲームクリア時、つまり game.is_finished
が True
の場合はフォームは表示せずに正解したことを伝えるメッセージのみを表示したり、予想が送信されていない時(ゲーム開始直後や GET
メソッドの HTTP リクエストを受け取った時)、つまり guess
が None
の場合はテーブルは非表示にするようにしています。
あとは、基本的にはコンテキストとして渡されてきた各インスタンスのデータ属性を出力することで、Hit 数や Blow 数等をページに表示するようにしているだけです。このあたりの説明は不要だと思いますので省略します。
テンプレートに関して詳しく知りたいという方は、別途下記ページを参照していただければと思います。
![Djangoのテンプレートの解説ページアイキャッチ](https://daeudaeu.com/wp-content/uploads/2023/04/django-template-eyecatch-160x160.png)
また、正解データのクライアントへの送信はダメ でも解説したように、正解データをテンプレートファイルに埋め込むようなことは避けましょう。今回の場合であれば、game.answer
が正解データとなりますので、これをテンプレートファイルで出力するのは NG です。
ビューと URL とのマッピング
最後に、先ほど views.py
に定義した index
関数と URL とのマッピングを行っていきます。これにより、数当てゲームのウェブアプリが完成することになります。
まずは、game
フォルダ内に urls.py
を新規作成し、下記をコピペしてください。
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index')
]
この game/urls.py
は /game/
から始まる URL の HTTP リクエストを受け取った時に読み込まれるようになっているため(前述で変更した number_guess/urls.py
で、そうなるように設定している)、上記のように game/urls.py
を変更することで、URL が /game/
の時に index
関数が呼び出され、数当てゲームプレイ用のページが表示されることになります。
動作確認
以上の変更・実装により、とりあえず数当てゲームが完成したことになります。最後に、このアプリの動作確認を実施したいと思います。
まずは、number_guess
フォルダ内(manage.py
が存在するフォルダ内)で下記の2つのコマンドを実行してマイグレーションを実施してください。これにより、Game
のテーブルがデータベース内に作成され、この Game
のレコードで数当てゲームを管理することができるようになります。
% python manage.py makemigrations
% python manage.py migrate
続いて、下記コマンドを実行して開発用ウェブサーバーを起動してください。
% python manage.py runserver
開発用ウェブサーバーが起動できたら、次はウェブブラウザを起動して下記 URL を開いてください。
http://localhost:8000/game/
これにより、views.py
の index
関数が実行され、下記のようなページが表示されるはずです。まだ予想した数字は送信していないため、フォームのみが表示されているはずです。
続いて、このページ内の 予想した数字
フィールドに4桁の半角数字を入力し、送信
ボタンをクリックしてください。すると、下の図のように送信した数字の Hit 数や Blow 数が表示されるはずです。
また、異なる数字を入力して送信すれば、入力した数字に基づいて Hit 数や Blow 数の表示が変化するはずです。
あとは、この Hit 数や Blow 数を参考にして正解の数字を予想し、正解の数字と同じ数字を回答するまでゲームを続けていくことになります。最終的に、正解の数字を回答することができれば下の図のようなページが表示されることになります。ここで、ココ
の部分のリンクをクリックしたり、ページをリロードしたりすれば、新たなゲームが開始されることになり、先ほどと異なる正解の数字に対する数当てゲームをプレイすることができます。
もしウェブブラウザが PC 内に複数インストールされているのであれば、別々のウェブブラウザを起動してゲームをプレイした際に、それぞれが独立して異なる正解の数字に対して数当てゲームがプレイできることを確認することもできるはずです。
これは、ウェブブラウザ毎に異なるセッション ID がウェブアプリから発行されるようになっているためです。 このような動作から、セッション ID に応じてクライアントを識別し、各クライアントから独立してゲームがプレイできることを確認できたことにはなりますが、同じユーザーであってもクライアントが異なると別の利用者と判断されてしまう点は課題であり、これに関しては後編でログインを導入することで解決していきます。
スポンサーリンク
まとめ
このページでは、Django での数当てゲームの作り方について解説しました!
数当てゲーム自体はシンプルなゲームとなるのですが、ウェブアプリとして開発しようと思うと考慮すべき点も多くて結構難しいと感じた方も多いのではないでしょうか?
特に、今回開発したウェブアプリにおいては、データを永続的に管理するためにデータベースを利用するという点と、ユーザー毎に独立してゲームがプレイできるようにユーザーの識別を行うという点がポイントになると思います。後者の識別に関しては、セッション ID を利用することで簡易的に実現できることは覚えておくと良いと思います。
ただし、セッション ID を利用して識別を行うと、同じユーザーが操作したとしても異なるウェブブラウザを利用した場合に異なるユーザーと判断されてしまうことになります(異なるセッション ID が送信される)。
また、ゲームを実際にプレイしてみて、今まで回答した履歴が表示されないという点に不満を持った方も多いのではないかと思います。これだと、回答に対する Hit 数 / Blow 数を自身で覚えておく必要があって大変です。
このように、今回開発した数当てゲームには多くの課題が残っています。もしかしたら、上記以外の点を課題と感じた方もおられると思います。こういった課題を実際に解決していくことは、あなた自身の知識を増やし、さらに技術を向上させることに繋がりますので、是非課題の解決に挑戦してみていただければと思います。
下記の後編のページでは、その一例として、上記で挙げた課題を解決するために、数当てゲームに「ログイン機能」や「回答履歴の表示機能」の追加を行っていきます。興味があれば、是非、後編も読んでみてください!
![Djangoでの数当てゲームの拡張の仕方・ポイントの解説ページアイキャッチ](https://daeudaeu.com/wp-content/uploads/2025/02/django-hit-blow-second-eyecatch-160x160.png)