【Kotlin】初心者がJetpack Composeでチンチロゲームを作ってみる

Advent Calendar 2024, Android, Kotlin

この記事はレコチョク Advent Calendar 2024の20日目です。
株式会社レコチョクのNX開発推進部Androidアプリ開発グループの本多啓路です。

今年一番聴いていた曲はMyGO!!!!!さんが歌うノンブレス・オブリージュ(Cover)で、555分聴いていたらしいです(YouTube Music調べ)。

はじめに

自分はFY24新卒であり、10月から晴れてNX開発推進部Androidアプリ開発グループに配属になりました。
そして、OJTもいよいよ終盤となり、Eggsアプリの開発にアサインされることになった今日この頃です。

そんな時、レコチョクAdvent Calendar 2024のお話を頂きました。
学んできたことを復習できる良い機会だと考え、遊べるアプリを作成してみました。

それがこれから紹介する「チンチロアプリ」です!

チンチロについて

まず、「チンチロ」って何?という方も多いと思いますので、ざっくりと説明します。

「チンチロ」は日本の伝統的な賭博遊びの一つで、三つのサイコロを使ったゲームです。
ルールは、三つのサイコロを丼に目掛けて振り、出た数字の組み合わせによって勝敗が決まる簡単なゲームです。

使用する出目の組み合わせの役を以下に示しています。

説明
ピンゾロ 1のゾロ目 1 1 1
アラシ 1以外のゾロ目 2 2 2 , 3 3 3 , 4 4 4 , 5 5 5 , 6 6 6
シゴロ 4から6の連番 4 5 6
1〜6 2つのサイコロが同じ数字のとき、
残り1つのサイコロが示す数字
1 1 3, 2 2 6……
ヒフミ 1から3の連番 1 2 3
メナシ どれにも当てはまらない組み合わせ 2 3 5, 2 4 6……
ションベン 丼からサイコロが飛び出たとき

使用するチンチロのルールを以下に示しています。
1. ロールはCPUが「親」、プレーヤーが「子」となる
2. 子(プレイヤー)が先にサイコロを振り、その後親(CPU)がサイコロを振る
3. メナシ以外の役が出るまで最大三回サイコロを振ることができる
4. 役の強さは ピンゾロ > アラシ > シゴロ > 6 > 5 > 4 > 3 > 2 > 1 > メナシ > ヒフミ > ションベン とする
5. 実際にサイコロを投げるわけではないため、ションベンは5%の確率で起こる要素とする
6. 引き分けの場合は親(CPU)の勝ちとする

完成品

それでは作ってみましょう!

アプリ作成

環境

今回は下記環境で作成しました。

項目 詳細
PC MacBook Pro
CPU Apple M1
IDE Android Studio Koala / 2024.1.1 Patch 1
検証端末 Pixel7 / Android 13
ライブラリ Jetpack Compose

必要なデータとロジックの作成

今回はViewModelを使用して必要なデータやロジックを一元管理して作成しました。
AndroidのViewModelは、アプリケーションのUIデータを保持し、ライフサイクルを考慮して設計されたクラスになります。

実際にViewModel内で作成した主要な関数を見ていきます。

  • rollDices
    • この関数を呼ぶと、サイコロを三個分振り、出目を更新します
      ちゃんと乱数を使用しているのでイカサマはないはずです笑

  • evaluateDiceRole
    • rollDices関数での出目がどの役に当てはまるかを評価しています

ちなみにここではションベンの処理は行っていません。evaluateDiceRoleの呼び出しの前に5%の確率で発生するようにしています。

  • determineWinner
    • プレイヤーの役と、CPUの役を比較して勝敗を決定します
    • 今回作成したアプリでのプレイヤーのロールは子なので、ピンゾロを出しても負ける可能性があります

役の強さの比較はあらかじめ設定しておいたデータを使用しています。

ここまでの実装により、サイコロを振って出た目の役を比較して勝敗を決定するという最低限のロジックが作れました!

画面遷移

最低限のロジックが作れたので、次は画面遷移を作っていきます!

今回作成するアプリの画面遷移を図で表すとこのような感じになります。

画面遷移はNavControllerで作成しました。NavControllerは、アプリ内ナビゲーションを容易にするために設計されており、複数の画面(フラグメントやアクティビティ)間の遷移をスムーズに行うことを可能にしています。

画面遷移を行いたいタイミングで、たとえば navController.navigate(route = "child")を呼び出すと新しい画面で composable("child")内の処理を行ってくれる便利なシステムです。

これで画面遷移の準備もできました!
あとは、画面のUIを「Jetpack Compose」で作成していくだけです!

画面の作成

ロジックはすでに作成したので、あとは ColumnTextImageButtonSpacerを使いつつ、ViewModelで操作していたデータを組み込むだけで完成です!

汎用的に使えるコンポーズを作成

使用する頻度が多いものは予め汎用化して使いまわせるようにしました。

Top画面

サイコロを振る画面

メナシ以外の役が出るまで最大三回サイコロを振るフローを示します。

子(プレイヤー)がサイコロを振る画面

  1. childRole != RoleType.NO_ROLEで何かしら役が出ている
  2. diceRollViewModel.rollCount.value == diceRollViewModel.maxRollsで三回振ったかどうか

という条件式をボタンに仕込んでボタンを押した際の処理を分岐させています。

親(CPU)がサイコロを振る画面

こちらは LaunchedEffectで自動的に再描写を行い、画面遷移までを自動的にしてくれるようにしています。

ちなみにサイコロを振るボタンを押したときに、ViewModelの中で非同期処理を使用してアニメーションっぽい表示をしています。

勝敗結果を表示する画面

最後に

ここまでお読み頂きありがとうございました!
今回はOJTで学んだ「Jetpack Compose」を活かして「チンチロアプリ」を作成してみました!
色々と復習にもなり、良い経験ができたと思います。

明日のレコチョク Advent Calendar 2024は21日目「【Kotlin】 Jetpack Composeを使ってりんご何個分?アプリを作ろう」となります。お楽しみに!

この記事を書いた人

本多啓路
本多啓路