【はじめてのKotlinプログラミング(13)】配列とシャッフルを使った簡単な四択クイズアプリ(前編)

kotlinで、一次元配列とシャッフルを使った

簡単な四択クイズアプリを作ってみたいと思います。

動画

コード

▼activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
  
  
    <TextView
        android:id="@+id/tvCount"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:layout_marginEnd="24dp"
        android:layout_marginRight="24dp"
        android:text="0問正解"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
  
    <TextView
        android:id="@+id/tvQuestion"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="番号順にタッチせよ"
        android:textSize="24sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tvCount" />
  
    <Button
        android:id="@+id/btn0"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="90dp"
        android:text="Button"
        app:layout_constraintTop_toBottomOf="@+id/tvQuestion"
        tools:layout_editor_absoluteX="187dp" />
  
    <Button
        android:id="@+id/btn1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Button"
        app:layout_constraintTop_toBottomOf="@+id/btn0"
        tools:layout_editor_absoluteX="129dp" />
  
    <Button
        android:id="@+id/btn2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Button"
        app:layout_constraintTop_toBottomOf="@+id/btn1"
        tools:layout_editor_absoluteX="160dp" />
  
    <Button
        android:id="@+id/btn3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Button"
        app:layout_constraintTop_toBottomOf="@+id/btn2"
        tools:layout_editor_absoluteX="140dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

▼MainActivity.kt

package com.example.simplequiz
 
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
 
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        //1)viewを取得(idで) + カウント用のiを用意
        val tvCount:TextView =findViewById(R.id.tvCount)
        val tvQuestion:TextView =findViewById(R.id.tvQuestion)
        val btn0:Button = findViewById(R.id.btn0)
        val btn1:Button = findViewById(R.id.btn1)
        val btn2:Button = findViewById(R.id.btn2)
        val btn3:Button = findViewById(R.id.btn3)
        var i =0
 
        //2)配列を用意
        val quizData = arrayOf("A0","A1","A2","A3")
 
        //4)0~3までのリスト用意⇒シャッフル
        val list = listOf(0,1,2,3)
        val num =list.shuffled()
 
        //3)ボタンにquizDataの0~3を表示させてみる
        //5)シャッフルされたnumの数字を入れる
        btn0.text =quizData[num[0]]
        btn1.text =quizData[num[1]]
        btn2.text =quizData[num[2]]
        btn3.text =quizData[num[3]]
 
        //6)btn0を押した時の正誤判定
        btn0.setOnClickListener {
            if(btn0.text==quizData[i]){
                //正解
                //tvQuestion.text="正解!!"
 
                //7)カウントを1増やして無効化
                i++
                btn0.isEnabled =false
                tvCount.text =i.toString() + "問正解"
                //9)i==4でGameClear
                if(i==4){
                    tvQuestion.text="全問正解!!Game Clear!!"
                }
 
            }else{
                //不正解+ボタンの無効化
                tvQuestion.text="不正解!!Game Over"
                btn0.isEnabled = false
                btn1.isEnabled = false
                btn2.isEnabled = false
                btn3.isEnabled = false
            }
        }
 
        //8)btn1~3も同じようにする
        btn1.setOnClickListener {
            if(btn1.text==quizData[i]){
                //正解
                //tvQuestion.text="正解!!"
 
                //7)カウントを1増やして無効化
                i++
                btn1.isEnabled =false
                tvCount.text =i.toString() + "問正解"
 
                if(i==4){
                    tvQuestion.text="全問正解!!Game Clear!!"
                }
 
            }else{
                //不正解+ボタンの無効化
                tvQuestion.text="不正解!!Game Over"
                btn0.isEnabled = false
                btn1.isEnabled = false
                btn2.isEnabled = false
                btn3.isEnabled = false
            }
        }
 
        btn2.setOnClickListener {
            if(btn2.text==quizData[i]){
                //正解
                //tvQuestion.text="正解!!"
 
                //7)カウントを1増やして無効化
                i++
                btn2.isEnabled =false
                tvCount.text =i.toString() + "問正解"
 
                if(i==4){
                    tvQuestion.text="全問正解!!Game Clear!!"
                }
 
            }else{
                //不正解+ボタンの無効化
                tvQuestion.text="不正解!!Game Over"
                btn0.isEnabled = false
                btn1.isEnabled = false
                btn2.isEnabled = false
                btn3.isEnabled = false
            }
        }
 
        btn3.setOnClickListener {
            if(btn3.text==quizData[i]){
                //正解
                //tvQuestion.text="正解!!"
 
                //7)カウントを1増やして無効化
                i++
                btn3.isEnabled =false
                tvCount.text =i.toString() + "問正解"
 
                if(i==4){
                    tvQuestion.text="全問正解!!Game Clear!!"
                }
 
            }else{
                //不正解+ボタンの無効化
                tvQuestion.text="不正解!!Game Over"
                btn0.isEnabled = false
                btn1.isEnabled = false
                btn2.isEnabled = false
                btn3.isEnabled = false
            }
        }
 
    }
}

テキスト

今回の主な学習のテーマは配列と、シャッフルです。

配列でいくつかの要素を用意して
それをシャッフルして、不規則に表示させる、というのをやっていきましょう。

ちなみに配列以外も色々やっていますが、それらは過去の動画の復習も兼ねています。

例えば、
正解・不正解を条件分岐するのはifですし、
正解表示はアラートダイアログです。
カウントが1ずつ増えるのは、インクリメント。
といった感じになります。

アラートダイアログだけ、次の動画の後編というか、完結編の方で解説しますが
ここでは、配列を表示して、シャッフルして並び替えて、正解・不正解の判定までやっていきます。

で、配列について、少しだけ解説しておきます。

配列について

で、配列について少しだけ解説しておきます。

配列は、このようにアレイオブとかいて、()の中に要素を格納します。

※順番は、左から、0番目、1番目、2番目、3番目、という風に0から数えるので注意が必要です。

取り出し方法ですが、
変数名に四角いカッコで繋ぎます。
これで、この名前の配列、という意味になります。

このかっこに、取り出したい数字を入力します。
例えば、

name[1]と入力したら、

この変数の、左から0番目(いぬ)⇒1番目(さる)で、「さる」、を差します。

数字の方も同じで、例えば

num[3]

と入れると、0⇒1⇒2⇒3番目の 40のことになります。

こんな感じでふんわり、配列が理解できたところで、早速はじめていきましょう

(XMLは割愛)

1.Viewの取得

それではプログラムをやっていきましょう。
ktを開いてください。

まずは、レイアウトの要素をidで取得していきます。
6つですね。

       //1)viewを取得(idで) + カウント用のiを用意
        val tvCount:TextView=findViewById(R.id.tvCount)
        val tvQuestion :TextView = findViewById(R.id.tvQuestion)
        val btn0:Button=findViewById(R.id.btn0)
        val btn1:Button=findViewById(R.id.btn1)
        val btn2:Button=findViewById(R.id.btn2)
        val btn3:Button=findViewById(R.id.btn3)
        var i = 0

それと、正解数をカウントしていくので、変数iも作っておきましょう。
ひとまず0を代入しておきますが
カウントは後で加算して変更されるのでvalではなくてvarです。

ひとまずこれで完成です。
それでは次に、今回の本題
配列を準備しましょう

2.配列の準備

それでは次に、今回の主役、配列を用意してあげましょう。

ひとまず、「1」の下に続けて表記しておきます。

        //2)配列を用意
        val quizData = arrayOf("A0","A1","A2","A3")

それでは、これで配列が用意できたので、いったん、この配列をボタンに表示させてみましょう。

3.ボタンに配列を表示させてみる

それではViewが取得できて
配列も用意できたので
ひとまず、これらのボタンに配列を表示させてみましょう。

とりあえず1個、練習がてら
btn0.text = quizData[0]

これで一旦エミュレータを起動して、確認してみましょう。

ボタンの0だけ、配列の0番目が表示されているはずです。てことで、これと同じようにして
全ての配列を表示させてみましょう。

     //3)ボタンにquizDataの0~3を表示させてみる
        btn0.text = quizData[0]
        btn1.text = quizData[1]
        btn2.text = quizData[2]
        btn3.text = quizData[3]

これで、今はButtonってなっているテキストに
arrayOf(“A0″,”A1″,”A2″,”A3”)
が表示されるようになっているはずです。

ただし、このままだと、何回起動しても、この順番ですよね。
なので、次は順番を並び替える「シャッフル」というのをしていきます。

4.シャッフル

それではですね、
このボタンの表示が毎回違う並びになるようにしたいんですが
そもそもこの並びとはなんぞやと、いうところを見ていきたいと思います。

当然、このquizData[]のならびですよねと。
今は0123,になっているので、順番に、配列の0123,と表示されています。


てことは、ここの数字が0123じゃなくて
毎回違う数字で並んでくれればいいわけです。

てことで、とりあえず説明は後にして正解だけ書いていきますね。

       //4)0~3までのリスト用意⇒シャッフル
        val list = listOf(0,1,2,3)
        val num = list.shuffled()

まず、配列と似たようなやつでlistっていうのを用意してあげます。
配列がarrayOfなのに対して
listはlistOfと書いてあげます。
中身が数字の時は、普通にコンマで区切ればOKです。
文字の時には、チョンチョンで区切ってあげるので、使い分けに注意が必要です。
で、ナンバー略してnumを用意してあげて、この中にシャッフルした数字を代入します。

***********************************
で似たようなやつでランダムっていうのもあります。
ランダムとシャッフルの違いは、同じものが重複するかどうか、みたいな感じです。
以前占いアプリを作りましたが、その時はランダムを使いました。
大吉が何度も出ることもあれば、全然でないこともあると。

一方シャッフルの場合は、順番を並べ替えるだけなので
重複はしませんし、ちゃんと1回出てきます。

という違いがあります。
***********************************

 

5.シャッフルを表示

そしたら今、numの中には「0~3」までの数字が
何かしら並べ替えられています。
ということは、ここが0123ではなくて
numの、中身はわからないけど0番目
numの、中身はわからないけど1番目
numの、中身はわからないけど2番目
numの、中身はわからないけど3番目
という風にしてあげると、
quizDataの中身が並べ替えられていると思います。

        //5)シャッフルされたnumの数字を入れる
        btn0.text = quizData[num[0]]
        btn1.text = quizData[num[1]]
        btn2.text = quizData[num[2]]
        btn3.text = quizData[num[3]]

エミュレータを起動して確認してみましょう。

こうですね。
このようになっていますし、
もう一度立ち上げてみると、
今度はこのようになっています。

で、先ほどから気になっている
listOfってなんやねんって話ですよね。

厳密にいうと、中身を書き換えできるとか、できないとか、
使い分ける違いはあるんですが
今回はとりあえずlistを使えばshuffled()が用意されるので簡単ですってだけの話です。

もちろんarrayOfでも使えますが、一手間増えてややこしいんで
せっかくなので紹介がてらlistってのを使った、くらいな感じです。
今回に関して言えば、そんな感じであまり深い理由はないです。

配列と同じ仲間でlistってのがあるので
それを使うと簡単にシャッフルできますよっていう紹介です。


それでは次に、ボタンを押した時の正解・不正解を判定してあげましょう。

6.正誤判定

それでは次に、正誤判定をしていきましょう。
ifを使います。

まずは練習で、
btn0を押して、
それがA0だったら正解
それ以外だったら不正解、としてみましょう。

        //6)btn0を押した時の正誤判定
        btn0.setOnClickListener {
            if(btn0.text==quizData[0]){
                //正解
            }else{
                //不正解
            }
        }

正解の場合は、ここのタイトルテキストに正解!と表示させて
tvQuestion.text=”正解!!”

それ以外の場合は、
tvQuestion.text=”不正解!!Game Over”
と表示させてみましょう。

       //6)btn0を押した時の正誤判定
        btn0.setOnClickListener {
            if(btn0.text==quizData[0]){
                //正解
                tvQuestion.text="正解!!"
            }else{
                //不正解
                tvQuestion.text="不正解!!Game Over"
            }
        }

はい、上手くいきました。
で、正解の場合はともかく、不正解の場合はGame Overなので、
ボタンを押せないように無効化してあげます。

        //不正解+ボタンの無効化
        tvQuestion.text="不正解!!Game Over"
        btn0.isEnabled = false
        btn1.isEnabled = false
        btn2.isEnabled = false
        btn3.isEnabled = false

それではエミュレータを起動して確認してみましょう。
はい、不正解の場合は、ゲームオーバーで、全部のボタンが無効化されました。

あとは、同じことをのこりのボタンにもやってあげるだけなので
不正解の場合は基本的にはひとまずこれで終了です。

では、
正解した場合は、カウントを増やしてあげる、という作業をしていきましょう。

7.正解した場合、カウントiを1加算

正解した場合、カウントiを1増やしてあげましょう。

                //7)カウントを1増やす
                i++

で、tvQuestionに「正解」と表示させるのをやめて
//tvQuestion.text=”正解!!”

tvCountに正解数を表示させます。

                //正解
                //tvQuestion.text="正解!!"

                //7)カウントを1増やす
                i++
                tvCount.text=i.toString() + "問正解"

そして、押されたボタンを無効化させたいので、
足した後にはEnabledをfalseにしてあげます。

                //7)カウントを1増やして無効化
                i++
                btn0.isEnabled = false
                tvCount.text=i.toString() + "問正解"

これで、ボタンの0を押した時、
クイズデータの0と等しい場合
カウントが1増えて、
ボタンが無効化されて
1問正解と表示されるようになっているはずです。

ではエミュレータを起動して確認してみましょう。


はい、このように、
ボタンが無効化されて
カウントが1増えているのがわかります。

てことはですよ。

これと同じことをしてあげればいいので、
setOnClickListenerを完全にコピーして
数字だけ変えていきましょう。

8.btn1~3も、全ボタンが押せるようにする

それでは、今ボタンの0だけ押せるようになったので
同じことを1,2,3でもやってあげましょう。

てことでbtn0.setOnClickListenerをコピーして

3つはりつけて
btn0となっているところそれぞれ3か所を
各番号に変えてあげます。

———————————
btn1.setOnClickListener {
if(btn1.text==quizData[0]){
btn1.isEnabled = false
———————————-
btn2.setOnClickListener {
if(btn2.text==quizData[0]){
btn2.isEnabled = false
———————————-
btn3.setOnClickListener {
if(btn3.text==quizData[0]){
btn3.isEnabled = false
———————————

これで今何が起きたかというと、
btn1を押した時にquizDataの0番目と等しい場合正解、
それ以外は不正解でボタンは無効化。

btn2も3も、とりあえず0番目と等しいかどうかで
正解、不正解ができるようになりました。

ではエミュレータを起動して確認してみましょう。

はい、0の番号が押されたら
カウントが1追加されて、ボタンが無効化されているのがわかります。

逆に、0以外を押した場合は、
不正解になって、全て無効化されているのがわかります。

てことで、不正解はこれで完全に終了です。

**********************************
で、今はquizDataが0の時ってことになってるんですけど
これを4つのボタン全部「i」に変えてみてください。

最初の0をクリックしたら
もちろん正解。
で、このときiが1加算されているので、
次は条件分岐みてください

quizData[i]
クイズデータの1番目と等しいならば、という風に変わってるんです。

てことはですよ。
A1をクリックすると正解
で、iが1加算されたので今、iは2になってます。

てことは
quizData[i]
クイズデータの2番目と等しいならば、という風に変わってるんです。
ではA2をクリックしてみましょう。

はい、こんな感じですね。

順番に押していくと、iが1つずつ加算されるので
全問正解することができました。

基本的にはこれで終了なんですが、
最後にもう1回if文を追加して

iが4になったら「全問正解」というのも頑張って挑戦してみましょう。

9.if文で全問正解の場合

それでは最後に、
カウントのiが4になった全問正解、と表示させる
条件分岐をしてあげましょう。

btn0のsetOnClickListenerの中で、
iが1増えた一連の流れの下に

  //9)i==4でGameClear
                if(i==4){
                    tvQuestion.text="全問正解!!Game Clear!!"
                }

これを、各ボタンの下に追加してあげます。

それでは最後にエミュレータを起動して確認してみましょう。

————————————
はい、上手くいっているのがわかります。


動作としてのプログラム解説は以上です。

 

次回は、重複しているコードを関数で一か所にまとめて、シンプルにする、というのをやって完成です。

    コメントを残す