はじめに
・Javaに興味がある方
・Java学んでみたけどあまりわからなかった方
・Javaでアプリ作ってみたい初学者の方
向けの内容になっています
こんにちは、チャルです!!
今回は「数字選択ゲーム」を作成してみました!!
正誤判定と解答までの時間も測れるようにしてみたので、
だれかと競い合いたいときにでも使ってみてください!!
ソースコードについても解説していきます!!
コード全文についても最後にあるので自由にお使いください!!
数字選択ゲーム
内容
ランダムな数字31個の中から
・最小
・最大
・中間
を探し出して解答フォームより答えるゲームとなります。
ランダムな数字作成
最初にランダムな数値を用意する必要があるため、
jsp(HTML)スタートではなく
サーブレット→jsp(HTML)
の順になります。
そのため今回のサーブレットはdoGetメソッドを使っています。
// 数値を作成し配列に入れる
ArrayList<Integer> numberList = new ArrayList<>();
// 計31個の数値を配列に格納する
while(numberList.size() < 31) {
// 1〜100以内の数字をランダムに作成
int num = (int)(Math.random() * 100 + 1);
// 重複チェック(すでに配列ないに存在しないか確認)
if(numberList.contains(num) == false) {
numberList.add(num);
}
}
for文だった場合、
for(int i = 0; numberList.size() < 31; i++)
と真ん中の範囲が i の値ではない、
さらにfor内で i を使う場面もないため、
whileの方がわかりやすいかなと考えてwhileにしています。
①(int)②(Math.random() ③ * 100 ④ + 1)
について解説します。
まず②のMath.random()によって
Mathクラスのrandomメソッドを呼び出しており、
0.0〜1.0未満の小数をランダムに生成します。
③の*100(×100)によって
②の数値を100倍することにより
0.0〜1.0未満 → 0.0〜100.0未満
と0〜99までの値を取得することができるようにします。
さらに今回0は不要で100は欲しいので
④で②③の数値に1を足すことで、
1.0〜101.0未満の数値を取得できるよう調整しています。
最後に①の(int)によってint型にキャスト(型変換)しています。
つまりは②③④でいろいろ手を加えましたが、
その過程によって生成された数字は小数です(12.3など)。
小数で文字の大きさ比べを行うのは
なんともややこしさが増してしまうため、
小数をなくしたい → 整数にしたい
ということでrandomによって生まれたdouble型を
int型にキャストすることで小数を切り捨てて整数にしています。
数字探しをする上で、
同じ数字が混在していると厄介だと考えました。
わざわざ合計数を奇数個にして中間が生まれるようにしたので…
(計4個: 1 3 3 5 だと中間は3になり、偶数個でも中間が生まれてしまう。
そうならないように奇数個に設計したので…)
そのためconatinsメソッド(ArrayList内に引数と同じものがあればtrueを返す)を使って、
結果がfalse(重複がない)であればArrayListにadd(追加)をしています。
このif文の処理があったこともあり、最初にwhile文を採用しています。
(if文で
if(int i = 0; i < 31; i++)
と書きたいところだけれど、重複があった場合31回繰り返しても
配列が31個になっているとは限らないので)
配列の並び替え
// 並び替え用の配列を用意する
ArrayList<Integer> sortNumberList = (ArrayList<Integer>)numberList.clone();
// 並び替える(バブルソート)
// 配列の要素数 - 1 回繰り返します(外側for文)
// 隣合う数字を比較し小さい順にします(大きいものを右に持っていく)(内側for文)
// つまり1周するごとに大きい数(右)から定まっていきます
// 周を重ねるごとに右は決まっていくのでわざわざ右端まで計算する必要はなくなります
// そのため j < sortNumberList.size() - i と記載する
for(int i = 1; i <= sortNumberList.size() - 1; i++) {
for(int j = 0; j < sortNumberList.size() - i; j++) {
int tmp1 = sortNumberList.get(j);
int tmp2 = sortNumberList.get(j+1);
if(tmp1 > tmp2) {
sortNumberList.set(j, tmp2);
sortNumberList.set(j+1, tmp1);
}
}
}
jsp(HTML)にて数字の並びに規則性を持たせないために
先ほど作成した順番がばらばらの配列と、
・最小(1番目)
・最大(31番目)
・中間(16番目)
がわかるように小さい順に並べた配列の2種を用意します。
そのため
ArrayList sortNumberList = (ArrayList)numberList.clone();
にて配列を複製しています。
隣合う数値を比較して並び替える「バブルソート」という
考え方で配列を小さい順に並び替えます。
まず考え方を下に記載します。
【イメージ例】
列名 1 2 3 4 5 6 7 8 9
数値 9 8 7 6 5 4 3 2 1
の順に並んだ9つの数値がある場合、
左の列(j)とその右の列(j+1)を比較する処理を
1列から8列まで繰り返します(9列の右はないため)。
小さい順にしたいため
左 > 右
の場合、左と右の位置を逆転させます。
この場合、
①1周目終了時
8 7 6 5 4 3 2 1 9
②2周目終了時
7 6 5 4 3 2 1 8 9
・
・
⑦7周目終了時
2 1 3 4 5 6 7 8 9
⑧8周目終了時
1 2 3 4 5 6 7 8 9
といった結果になるかとおもいます。
つまり大きい数値が右に動いていくため、
1周終えるごとに右端から確定していきます。
この結果をプログラムにしていきます。
外側のループ(上記例の①②など)は要素数の-1回必要でした
for(int i = 1; i <= sortNumberList.size() – 1; i++)
内側のループでは1周終えるごとに右側が確定していきました、
また右側の列(j+1)と比較するため要素数列まで行ってしまうと、
要素数列(j)と存在しない列(j+1)を比較してエラーが発生します。
そのため最初は1そして1周ごとに1を2,3と増やす必要があります。
そんなちょうど良い数字がないかと目を配らせると
外側ループの i がまさしくその役割を果たせそうです。
for(int j = 0; j < sortNumberList.size() – i; j++)
※そのため外側ループでは int i = 0 ではなく 1 にしています。
if(tmp1 > tmp2)
数値を比較して左の方が大きいなら
sortNumberList.set(j, tmp2)
sortNumberList.set(j+1, tmp1)
並び替えを行なっています。
Javaの主な機能はこれで終了です!!
jsp(HTML) & CSS
数値の配置はCSSで配置をすべて指定しました!!
プログラムでランダム配置できないのかな
とおもいつつもわかりませんでした( ; ; )
わかる方はぜひご教授いただけると幸いです!!
JavaScript
時間表記機能については TAG index 様のコードを使用したので、
解説含めてそちらを参照ください
アラート表記機能
<script type="text/javascript">
function submitCheck() {
var min = document.getElementById('min').value;
var max = document.getElementById('max').value;
var mid = document.getElementById('mid').value;
var minAnswer;
var maxAnswer;
var midAnswer;
if(min == <%= sortNumberList.get(0) %>) {
minAnswer = "正解⭕️";
} else {
minAnswer = "不正解(正解:<%= sortNumberList.get(0) %>)";
}
if(max == <%= sortNumberList.get(30) %>) {
maxAnswer = "正解⭕️";
} else {
maxAnswer = "不正解(正解:<%= sortNumberList.get(30) %>)";
}
if(mid == <%= sortNumberList.get(15) %>) {
midAnswer = "正解⭕️";
} else {
midAnswer = "不正解(正解:<%= sortNumberList.get(15) %>)";
}
alert(minAnswer + '\n' + maxAnswer + '\n' + midAnswer + '\n' + '時間:' + time);
}
</script>
var ◯◯ = document.getElementById(‘△△’).value
によってid = “△△”が記載された<input>タグから入力値を取得しています。
その入力値が並び替えた配列の1,15,31番目と合致するかを判定し、
正誤判定の結果を変数に入れて最後にalert表示している流れです!!
完成!!
おわりに
今回の題材はなにかを参考ではなく自分の発想で作ってみたのですが、
特段先のことを考えて作り始めたわけではないので、
「答え合わせするたびにサーブレット経由してるから、
数値が更新されちゃっていまの問題と答えを見比べられないぞ!???」
という問題に直面しました。
その結果、全然触れたことのないJavaScriptを使うことになったのですが、
無事完成できたので良い特訓になったよしよし!!という感じです。
それでは最後までお読みいただきありがとうございました!!
配布
<%@page contentType="text/html; charset=UTF-8" %>
<%@page import="java.util.ArrayList" %>
<%
ArrayList<Integer> numberList = (ArrayList<Integer>)request.getAttribute("numberList");
ArrayList<Integer> sortNumberList = (ArrayList<Integer>)request.getAttribute("sortNumberList");
%>
<html>
<head>
<title>数字探しゲーム</title>
<link rel="stylesheet" type="text/css" href="<%= request.getContextPath() %>/css/randomNumber.css">
<script type="text/javascript">
var start = new Date();
// 初期化
var hour = 0;
var min = 0;
var sec = 0;
var now = 0;
var datet = 0;
var time = 0;
function disp(){
now = new Date();
datet = parseInt((now.getTime() - start.getTime()) / 1000);
hour = parseInt(datet / 3600);
min = parseInt((datet / 60) % 60);
sec = datet % 60;
// 数値が1桁の場合、頭に0を付けて2桁で表示する指定
if(hour < 10) { hour = "0" + hour; }
if(min < 10) { min = "0" + min; }
if(sec < 10) { sec = "0" + sec; }
// フォーマットを指定(不要な行を削除する)
time = hour + ':' + min + ':' + sec; // パターン1
// テキストフィールドにデータを渡す処理(不要な行を削除する)
document.form.field.value = time; // パターン1
setTimeout("disp()", 1000);
}
</script>
</head>
<body onload="disp()">
<h2>数字を探せ31</h2>
<% if(numberList != null) { %>
<div class = "container">
<p class = "relative">下の31個の数字から最小, 最大, 中間(16番目)の<br>
数字を探して答えてください</p>
<form onsubmit = "submitCheck(); return false" name = "form">
<table>
<tr>
<th></th>
<td><input type="text" name="field"></td>
</tr>
<tr>
<th>最小</th>
<td><input id="min" type="text" name="min" required></td>
</tr>
<tr>
<th>最大</th>
<td><input id="max" type="text" name="max" required></td>
</tr>
<tr>
<th>中間</th>
<td><input id="mid" type="text" name="mid" required></td>
</tr>
<tr>
<th></th>
<td><input id="btn" type="submit" value="答える"></td>
</tr>
</table>
</form>
<button type="button" onclick="location.href='<%= request.getContextPath() %>/randomNumber'">もう一度</button>
<div class = "aa"><%= numberList.get(0) %></div>
<div class = "ab"><%= numberList.get(1) %></div>
<div class = "ac"><%= numberList.get(2) %></div>
<div class = "ad"><%= numberList.get(3) %></div>
<div class = "ae"><%= numberList.get(4) %></div>
<div class = "af"><%= numberList.get(5) %></div>
<div class = "ag"><%= numberList.get(6) %></div>
<div class = "ah"><%= numberList.get(7) %></div>
<div class = "ai"><%= numberList.get(8) %></div>
<div class = "aj"><%= numberList.get(9) %></div>
<div class = "ak"><%= numberList.get(10) %></div>
<div class = "al"><%= numberList.get(11) %></div>
<div class = "am"><%= numberList.get(12) %></div>
<div class = "an"><%= numberList.get(13) %></div>
<div class = "ao"><%= numberList.get(14) %></div>
<div class = "ap"><%= numberList.get(15) %></div>
<div class = "aq"><%= numberList.get(16) %></div>
<div class = "ar"><%= numberList.get(17) %></div>
<div class = "as"><%= numberList.get(18) %></div>
<div class = "at"><%= numberList.get(19) %></div>
<div class = "au"><%= numberList.get(20) %></div>
<div class = "av"><%= numberList.get(21) %></div>
<div class = "aw"><%= numberList.get(22) %></div>
<div class = "ax"><%= numberList.get(23) %></div>
<div class = "ay"><%= numberList.get(24) %></div>
<div class = "az"><%= numberList.get(25) %></div>
<div class = "ba"><%= numberList.get(26) %></div>
<div class = "bb"><%= numberList.get(27) %></div>
<div class = "bc"><%= numberList.get(28) %></div>
<div class = "bd"><%= numberList.get(29) %></div>
<div class = "be"><%= numberList.get(30) %></div>
</div>
<script type="text/javascript">
function submitCheck() {
var min = document.getElementById('min').value;
var max = document.getElementById('max').value;
var mid = document.getElementById('mid').value;
var minAnswer;
var maxAnswer;
var midAnswer;
if(min == <%= sortNumberList.get(0) %>) {
minAnswer = "正解⭕️";
} else {
minAnswer = "不正解(正解:<%= sortNumberList.get(0) %>)";
}
if(max == <%= sortNumberList.get(30) %>) {
maxAnswer = "正解⭕️";
} else {
maxAnswer = "不正解(正解:<%= sortNumberList.get(30) %>)";
}
if(mid == <%= sortNumberList.get(15) %>) {
midAnswer = "正解⭕️";
} else {
midAnswer = "不正解(正解:<%= sortNumberList.get(15) %>)";
}
alert(minAnswer + '\n' + maxAnswer + '\n' + midAnswer + '\n' + '時間:' + time);
}
</script>
<% } %>
</body>
</html>
@charset "UTF-8";
.relative {
position: relative;
}
.hr-top {
position: absolute;
top: 18vw;
left: 23vw;
}
.aa {
position: absolute;
top: 20vw;
left: 25vw;
}
.ab {
position: absolute;
top: 20vw;
left: 65vw;
}
.ac {
position: absolute;
top: 40vw;
left: 25vw;
}
.ad {
position: absolute;
top: 40vw;
left: 65vw;
}
.ae {
position: absolute;
top: 24vw;
left: 61vw;
}
.af {
position: absolute;
top: 24vw;
left: 43vw;
}
.ag {
position: absolute;
top: 32vw;
left: 59vw;
}
.ah {
position: absolute;
top: 21vw;
left: 41vw;
}
.ai {
position: absolute;
top: 22vw;
left: 51vw;
}
.aj {
position: absolute;
top: 28vw;
left: 46vw;
}
.ak {
position: absolute;
top: 29vw;
left: 39vw;
}
.al {
position: absolute;
top: 25vw;
left: 33vw;
}
.am {
position: absolute;
top: 27vw;
left: 38vw;
}
.an {
position: absolute;
top: 38vw;
left: 61vw;
}
.ao {
position: absolute;
top: 21vw;
left: 35vw;
}
.ap {
position: absolute;
top: 29vw;
left: 53vw;
}
.aq {
position: absolute;
top: 29vw;
left: 31vw;
}
.ar {
position: absolute;
top: 25vw;
left: 28vw;
}
.as {
position: absolute;
top: 34vw;
left: 51vw;
}
.at {
position: absolute;
top: 31vw;
left: 41vw;
}
.au {
position: absolute;
top: 37vw;
left: 38vw;
}
.av {
position: absolute;
top: 34vw;
left: 33vw;
}
.aw {
position: absolute;
top: 27vw;
left: 57vw;
}
.ax {
position: absolute;
top: 35vw;
left: 41vw;
}
.ay {
position: absolute;
top: 36vw;
left: 52vw;
}
.az {
position: absolute;
top:36vw;
left: 58vw;
}
.ba {
position: absolute;
top: 35vw;
left: 26vw;
}
.bb {
position: absolute;
top: 40vw;
left: 55vw;
}
.bc {
position: absolute;
top: 29vw;
left: 60vw;
}
.bd {
position: absolute;
top: 38vw;
left: 47vw;
}
.be {
position: absolute;
top: 38vw;
left: 31vw;
}
package servlet;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RandomNumberServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
try {
// 数値を作成し配列に入れる
ArrayList<Integer> numberList = new ArrayList<>();
// 計31個の数値を配列に格納する
while(numberList.size() < 31) {
// 1〜100以内の数字をランダムに作成
int num = (int)(Math.random() * 100 + 1);
// 重複チェック(すでに配列ないに存在しないか確認)
if(numberList.contains(num) == false) {
numberList.add(num);
}
}
// 並び替え用の配列を用意する
ArrayList<Integer> sortNumberList = (ArrayList<Integer>)numberList.clone();
// 並び替える(バブルソート)
// 配列の要素数 - 1 回繰り返します(外側for文)
// 隣合う数字を比較し小さい順にします(大きいものを右に持っていく)(内側for文)
// つまり1周するごとに大きい数(右)から定まっていきます
// 周を重ねるごとに右は決まっていくのでわざわざ右端まで計算する必要はなくなります
// そのため j < sortNumberList.size() - i と記載する
for(int i = 1; i <= sortNumberList.size() - 1; i++) {
for(int j = 0; j < sortNumberList.size() - i; j++) {
int tmp1 = sortNumberList.get(j);
int tmp2 = sortNumberList.get(j+1);
if(tmp1 > tmp2) {
sortNumberList.set(j, tmp2);
sortNumberList.set(j+1, tmp1);
}
}
}
request.setAttribute("numberList", numberList);
request.setAttribute("sortNumberList", sortNumberList);
} catch(Exception e) {
e.printStackTrace();
} finally {
request.getRequestDispatcher("/view/randomNumber.jsp").forward(request, response);
}
}
}