【GASの永続化】モルック(アウトドアスポーツ)の進行役をLINEmessagingAPIを使って作ってみた！

# 目次
* モルックとは？
* なぜこのシステムを作ったのか
* GASの永続化について(トラブル１個目)
* ソースコードの解説等
* いきなりLINE botが動かなくなる？(トラブル２個目)
* 実際にbotを使いながらプレイしてみた！
* 最後に

とってもいい記事を書いた(と思ってる)のでぜひ最後まで読んでください！！


# 1. モルックとは？
フィンランド発祥のアウトドアスポーツです。

ルールはこんな感じです。

![スクリーンショット 2022-08-13 18.13.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/60f76a89-120d-e16f-c915-4d540658de56.png)
![スクリーンショット 2022-08-13 18.13.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/0b5e8aa1-8d77-c7e4-2eae-8ea13e4783cf.png)
![スクリーンショット 2022-08-13 18.14.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/9279e009-e221-f355-63b1-266741281642.png)





https://molkky.jp/molkky/

倒したピンを元の場所ではなく、その場で立て、１本だけ倒したなら、その倒した棒に書いてある数字、２本以上倒すと、その本数分の得点が入ります。

どちらかのチームが５０点ピッタシになれば、勝利となります。
もし、５０点を上回ってしまった場合は、得点が25まで戻ってしまいます。
また、ミスが３回続けば、負けとなってしまいます。

相手が倒したい棒を遠くへ飛ばしたり、頭を使った面白いアウトドアのスポーツです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/9b84abe5-c1bc-691e-9079-7ff7cb9d58a2.png)




# 2. なぜこのシステムを作ったのか

実際に友人とする機会があり、プレイして思ったのは、「スコアの管理めんどくさくね・・？」でした。

モルックを外でプレイしながら数字を覚えながら足していって、、、って想像以上にめんどくさいです。


当たり前ですが、得点をかなり気にしながら、作戦を決めていくので
**「今何点？」が何回も飛び交います**

ということで、LINEを使ってモルックを円滑に進めるための「モルックの支配人bot」を作って行きましょう！！レッツ作成！

LINEbotの作り方や、GASとの連携の仕方は私が前回に書いた[こちら](https://qiita.com/paupau/items/1baa0ae1a1de3b79452f)をご覧ください。


今回はGoogle App ScriptとGoogle Spreadsheetを使って行います。
(Google App Scriptを以後GASと呼びます。)



# 3. GASの永続化について(トラブル１個目)

勘の鋭い方はお分かりですが、GASを使ってゲームの進行をするには少々面倒くさいです。

:::note info
キーワードは「**GASの永続化**」です。
:::


例えば「ゲーム開始」というとゲームが始まるとします。ユーザからのメッセージをGASが取得し、
モルックを開始し、数字をどんどん入れていくとします。


そこでネックになるのはLINEから受け取る際に動く**doPost関数**です。
doPost関数は、Google Apps ScriptのページのURLに、POSTリクエストが送られたときに、関数を実行します。



**LINEが送られてくるたびに、その関数が動いてしまうため、前の点数は記憶できません。**


例で挙げると、
```javascript
if(message==(isFinite(message)==true){ //もしユーザからの送信が数値だったら
send_message('〇〇チームの合計スコアは〇〇点です')//LINEに合計スコアをpushする
}
```
こういうコードがあるとします。
この場合、二点の問題が発生します。

:::note alert
* **グループラインにbotを入れていた場合、
 モルックと関係のない会話でもdoPost関数が動いてしまう**
* **チームの合計スコアが記憶できていない**
:::

このような現象が起きてしまうと、ゲームの進行役なんてできませんよね。

そこで出てくるのが**スプレッドシート**です。

スプレッドシートで、以下の二点の管理をします。

:::note info
* **現在ゲームのどのフェーズにいるのか(コード内で、fease_sheetとして管理)**
* **スコアやチーム名の管理(コード内で、score_sheetとして管理)**
:::

このようにして、GASの永続化をし、モルックの進行役botを作ります。

以下の文献ように、永続化の方法はいくらかあると思います。
僕はスプレットシート×GASをよく使って慣れていたのでこの実装にしました。

https://qiita.com/tmokmss/items/6a15ab1a4838bd6b7f9d


# 4. ソースコードの解説等
結構分かりやすいように、コメントアウトの追加頑張りました（笑）
制作時間はざっと２０時間ほどです。


```javascript
var CHANNEL_ACCESS_TOKEN = ''; //LINE Developersで取得したアクセストークンを入れる
var url = 'https://api.line.me/v2/bot/message/push';
var groupID = ''; //グループラインのID
const OutputFolder = DriveApp.getFolderById(''); //保存するフォルダ指定
const template_sheet = DriveApp.getFileById(''); //テンプレートのスプレッドシートを指定
const fease_sheet = SpreadsheetApp.openById('').getSheetByName('');//フェーズ管理のシート




function doPost(e) { //ポストで送られてくるので、送られてきたJSONをパース
  var json = JSON.parse(e.postData.contents);


  var reply_token = json.events[0].replyToken;   //返信するためのトークン取得
  if (typeof reply_token === 'undefined') {
    return;
  }


  let message = json.events[0].message.text; //送られたメッセージ内容を取得
  
 if (message == 'モルック開始'){
  fease_sheet.clear();//フェーズシートを初期化する
  var date = new Date();//現在時刻取得
  date = Utilities.formatDate(date, "Asia/Tokyo", "モルックを開始しました    yyyy/MM/dd hh時mm分");
  send_message(date)//モルックを開始した旨を送信
  create_spreadsheet()//新しくスプレッドシートを作成
  fease_sheet.getRange("A1").setValue("0")//フェーズ０を記入
  fease_sheet.getRange('G1').setValue("0")//チーム１のミスカウントの設定
  fease_sheet.getRange('H1').setValue("0")//チーム２のミスカウントの設定
  send_message('１チーム目の名前を入力してください。')
 }

if (message == 'モルックシステム説明'){
  send_message('このモルックシステムは〇〇によって作られたものです。\n\n ゲームを開始したい際には「モルック開始」、ゲームを終了したい際には「モルック終了」と入力してください。\n\nゲームの途中であれ、誰が入力しても構いません。\n\nまた、２チームor２人で行うような設定にしています。\n\n数字の入力は必ず半角でお願いします。ミスをした場合には「ミス」と入力してください。\n\nまた、モルックのルールが知りたい場合や、並び方がわからなくなった場合には「モルックルール」と送信してください。\n\n\n\n以上、システムの説明でした。もう一度聞きたい場合には「モルックシステム説明」と入力してください。')
}

if (message == 'モルックルール'){
send_message('モルックの公式ルールは以下のサイトをご覧ください。\n\n https://molkky.jp/molkky/#id-molkky-rule')
}


var new_sheet_id = fease_sheet.getRange("A2").getValue()//フェーズシートのA2にある新規シートのIDを取得
var score_sheet = SpreadsheetApp.openById(new_sheet_id).getSheetByName('a');


if(((fease_sheet.getRange("A1").getValue()) == 0) & (message != 'モルック開始')){//フェーズ０が終わっているかつユーザからのメッセージがモルックではないか
  var date = new Date();//現在時刻取得
  date = Utilities.formatDate(date, "Asia/Tokyo", "yyyy/MM/dd hh時mm分");
  score_sheet.getRange("B2").setValue(date)//スコアシートに開始時刻を入れる
  score_sheet.getRange("B3").setValue(message)//スコアシートに１チーム目を入れる
  fease_sheet.getRange("A1").setValue("1")//フェーズ１を記入
  send_message('２チーム目の名前を入力してください。')
}


if(((fease_sheet.getRange("A1").getValue()) == 1 & (score_sheet.getRange("B3").getValue() != message))){//フェーズ１が終わっているかつ前回の入力ではないか
  score_sheet.getRange("C3").setValue(message)//スコアシートに2チーム目を入れる
  fease_sheet.getRange("A1").setValue("2")//フェーズ2を記入
  fease_sheet.getRange("B1").setValue("0")//１チーム目の得点の準備をする、B1が0なら１チーム目の入力、1なら２チーム目の入力、
  send_message('チーム名の設定が終了しました。')
  Utilities.sleep(1000)
  send_message('ゲームを開始してください')
}

let team_name_0 = score_sheet.getRange("B3").getValue()
let team_name_1 = score_sheet.getRange("C3").getValue()

 if(((fease_sheet.getRange("A1").getValue()) == 2) & (fease_sheet.getRange("B1").getValue() == 0) & ((isFinite(message) == true)　| (message == 'ミス'))　　){ //フェーズが２であり、１チーム目の入力であり、ユーザからの入力が数値であるか
  if((message > 12 | message < 1 | (Number.isInteger(Number(message)) == false)) & (message != 'ミス')){ //１３以上の数字が入力された場合、１未満の場合、小数点がついている場合
   send_message('数字は１〜１２で、自然数で入力してくださいです。')
   return
 }
  fease_sheet.getRange("B1").setValue(1)//相手チームのフェーズに設定
  game(0,team_name_0,score_sheet,new_sheet_id,message)
  return
 }


 if(((fease_sheet.getRange("A1").getValue()) == 2) & (fease_sheet.getRange("B1").getValue() == 1) & ((isFinite(message) == true)　|　(message == 'ミス'))){ //フェーズが２であり、2チーム目の入力であり、ユーザからの入力が数値であるか
 
   if((message > 12 | message < 1 | (Number.isInteger(Number(message)) == false)) & (message != 'ミス')){ //１３以上の数字が入力された場合、１未満の場合、小数点がついている場合
    send_message('数字は１〜１２で、自然数で入力してくださいです。')
   return
  }
  fease_sheet.getRange("B1").setValue(0) //相手チームのフェーズに設定
  game(1,team_name_1,score_sheet,new_sheet_id,message)
  return
 }

   if(((fease_sheet.getRange("A1").getValue()) == 2)  & (isFinite(Number(message)) == false)  & (score_sheet.getRange("C3").getValue() != message)& (message != 'モルック終了')){ //フェーズが２であり、ユーザからの入力が間違っているときであり、前回の入力ではないか、モルック終了のメッセージでないか、
send_message('入力が間違っています。半角数字でお願いします。')
 }

if (message == 'モルック終了'){
   end(new_sheet_id,'')
 }

  //return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}

function create_spreadsheet(){
  let OutputFileName;
  OutputFileName = template_sheet.getName().replace('template', '') + 'モルックスコアシート_'+Utilities.formatDate(new Date(), 'JST', 'yyyyMMddhhss') //語尾に日にち追加
  var new_sheet_id = template_sheet.makeCopy(OutputFileName, OutputFolder);//テンプレートからコピー作成
  fease_sheet.getRange("A2").setValue(new_sheet_id.getId())//フェーズシートのA2に作成したスプレッドシートIDを書いておく
}


function send_message(message){
var response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,
    },
    'method': 'POST',
    'payload': JSON.stringify({
      'to': groupID,
      'messages':[{
        'type': 'text',
        "text" : message,
      }]
     })
   })
   Logger.log(response.getResponseCode());
}

function game(team,team_name,score_sheet,new_sheet_id,message){
  if((fease_sheet.getRange('B1').getValue() == 0) | (fease_sheet.getRange('B1').getValue() == 1)){
  let team_cell
  let miss_count_cell
  let goukei_score_cell
  if(team == 0){
    team_cell = 'B'
    miss_count_cell = 'G1'
    goukei_score_cell = 'B30'
  }
 else if(team == 1){
    team_cell = 'C'
    miss_count_cell = 'H1'
    goukei_score_cell = 'C30'
  }
  for (let input_count = 4; input_count < 26; input_count++){ //空白の行を探す
    let input_cell = team_cell + input_count
    let goukei_score
    if (score_sheet.getRange(input_cell).getValue() == ''){ //空白行があったら
      score_sheet.getRange(input_cell).setValue(message) //スコアを挿入

      if(score_sheet.getRange(goukei_score_cell).getValue() == ''){//はじめての合計スコア入力なら
        if(message == 'ミス'){
        let miss_count = Number(fease_sheet.getRange(miss_count_cell).getValue()) //ミスカウントを取得
        miss_count = miss_count + 1 //ミス回数を加算
        fease_sheet.getRange(miss_count_cell).setValue(miss_count) //ミス回数を記録
        message = 0
        }
        score_sheet.getRange(goukei_score_cell).setValue(message) //スコアを合計のセルに挿入
        send_message(team_name + 'チームの合計スコアは現在' + message + '点です。')
        return
        }
      else{//はじめての合計スコアではない場合
      goukei_score = Number(score_sheet.getRange(goukei_score_cell).getValue()) + Number(message) //元々入ってる合計スコア足す今回のスコア
      if(goukei_score > 50){//モルックのルールで50を超えた場合得点が25になる処理
        send_message('得点が５０を上回ったので２５になります。')
        goukei_score = 25

        message=message + ' 半減'
        score_sheet.getRange(input_cell).setValue(message) //半減コメントの追加
      }

      if(message != 'ミス'){
      score_sheet.getRange(goukei_score_cell).setValue(goukei_score) //ミス以外の時、合計スコアを更新
      }

      if((score_sheet.getRange('B30').getValue() == 50) & team == 1 & goukei_score != 50){//１チーム目が５０点になり、２チーム目が５０点に達しなかった時
        let teki_team = score_sheet.getRange('B3').getValue()
        send_message(teki_team + 'チームの勝利です。')
        end(new_sheet_id,teki_team)
        return
      }
      if(goukei_score == 50 & team == 0){ //１チーム目の得点が50に達した時
        let teki_team = score_sheet.getRange('C3').getValue()
        send_message(teki_team + 'チームが50に達しなかった場合、' + team_name + 'チームの勝利です。')//１チーム目が上がっても２チームめのターンが残っているため
        fease_sheet.getRange(miss_count_cell).setValue(0) //ミスカウントをリセット
        return
      }
      if(goukei_score == 50 & team == 1){ //２チーム目の得点が50に達した時
      if(score_sheet.getRange('B30').getValue() == 50){
        send_message('両チーム50点に達したためこのゲームは引き分けとなります。\n\nモルックアウトをプレイして勝敗を決めてください。')
        end(new_sheet_id,'draw')
        return
      }
      else{
        send_message(team_name + 'チームの勝利です。')
        end(new_sheet_id,team_name)
        return
        }
      }

      if(message == 'ミス'){//一本も倒せなかった場合
        let miss_count = Number(fease_sheet.getRange(miss_count_cell).getValue()) //ミスカウントを取得
        miss_count = miss_count + 1 //ミス回数を加算
        fease_sheet.getRange(miss_count_cell).setValue(miss_count) //ミス回数を記録
        if (miss_count == 3){//モルックのルールで三回連続でミスしたらアウト
          let teki_team = score_sheet.getRange('B3').getValue()
          send_message(team_name + 'チームがミスを三回繰り返しました。ゲームを終了します。')
          end(new_sheet_id,teki_team) //終了への関数
          return
        }
        goukei_score = Number(score_sheet.getRange(goukei_score_cell).getValue())//合計スコアの取得
        send_message(team_name + 'チームの合計スコアは現在' + goukei_score + '点です。')
        return
      }
      
      send_message(team_name + 'チームの合計スコアは現在' + goukei_score+'点です。')
      fease_sheet.getRange(miss_count_cell).setValue(0) //ミスカウントをリセット
      return
        }
      }
    }
    end(new_sheet_id,'draw')
    return
  }
}

function end(new_sheet_id,team_name){
   send_message('お疲れ様でした。')
   Utilities.sleep(1000)
   let score_sheet = SpreadsheetApp.openById(new_sheet_id).getSheetByName('a');
   if(team_name == 'draw'){ 
     score_sheet.getRange("B31").setValue('引き分け')
     score_sheet.getRange("C31").setValue('引き分け')
   }
  if(team_name == (score_sheet.getRange("B3").getValue())){
    score_sheet.getRange("B31").setValue('勝ち')
    score_sheet.getRange("C31").setValue('負け')
  }
  if(team_name == (score_sheet.getRange("C3").getValue())){
    score_sheet.getRange("C31").setValue('勝ち')
    score_sheet.getRange("B31").setValue('負け')
  }
   const scoresheet_url = SpreadsheetApp.openById(new_sheet_id).getUrl() //スプレッドシートのURL取得
   send_message('スコアシートを送信します\n\n\n'+scoresheet_url)
   fease_sheet.clear();//フェーズシートを初期化する
   return
}


```



大まかな流れとして

```
モルック開始と入力されたらゲーム開始、テンプレートのスコアシートを複製して、そのシート名を現在時刻にする
その際、複製したスプレッドシートのIDをフェーズシートに記録しておく(そのスコアシートに記録を刻んでいくため)
　　　　　　　　　　　　　　　　　　　　↓
１チーム目の入力を促し、１チーム目の名前をスプレッドシートに挿入する
　　　　　　　　　　　　　　　　　　　　↓
２チーム目の入力を促し、フェーズ0が終わっていれば、２チーム目の名前をスプレッドシートに挿入する
　　　　　　　　　　　　　　　　　　　　↓
数字をユーザに入力してもらい、フェーズシートのB1が0なら１チーム目、1なら２チーム目のターンと判断する
　　　　　　　　　　　　　　　　　　　　↓
ゲームを進めていき、50なら終了、50を超えると25、ミスを３回すればゲーム終了となる
　　　　　　　　　　　　　　　　　　　　↓
ゲームを終了する際、スコアシートを見れるようにLINEに送信する
```


です。
以下がスコアシートのテンプレートです。
このテンプレートのシートを複製後、複製したシートの名前を変更しています。



<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/a90fbe1f-0ed7-07ba-8704-a529876174d4.png" width=75%>

以下がそのテンプレートシートを複製し、新しくスコアシートを作成しているコードです。
OutputFilenameに変更する新しいファイル名を入れます。
その後、makeCopyメソッドより、複製し、その返り値をフェーズシートに記憶させています。
　　　　　　　　　　　　　　　　　　↓

```javascript
function create_spreadsheet(){
  let OutputFileName;
  OutputFileName = template_sheet.getName().replace('template', '')+'モルックスコアシート_'+Utilities.formatDate(new Date(), 'JST', 'yyyyMMddhhss') //語尾に日にち追加
  var new_sheet_id = template_sheet.makeCopy(OutputFileName, OutputFolder);//テンプレートからコピー作成
  fease_sheet.getRange("A2").setValue(new_sheet_id.getId())//フェーズシートのA2に作成したスプレッドシートIDを書いておく
}
```

また、今回ゲームを終了する関数をend関数としています。
end関数にどちらのチームが勝ったかを引数として渡してあげることで、スプレッドシートに記録が可能です。
そして、後からどんなチーム名でどんな試合だったかを見返せるように終了の際、スプレッドシートのスコアシートをグループに送信してあげることも実装しています。
　　　　　　　　　　　　　　　↓



```javascript
function end(new_sheet_id,team_name){
   send_message('お疲れ様でした。')
   Utilities.sleep(1000)
   let score_sheet = SpreadsheetApp.openById(new_sheet_id).getSheetByName('a');
   if(team_name == 'draw'){
     score_sheet.getRange("B31").setValue('引き分け')
     score_sheet.getRange("C31").setValue('引き分け')
   }
  if(team_name  ==(score_sheet.getRange("B3").getValue())){
    score_sheet.getRange("B31").setValue('勝ち')
    score_sheet.getRange("C31").setValue('負け')
  }
  if(team_name == (score_sheet.getRange("C3").getValue())){
    score_sheet.getRange("C31").setValue('勝ち')
    score_sheet.getRange("B31").setValue('負け')
  }
   const scoresheet_url = SpreadsheetApp.openById(new_sheet_id).getUrl() //スプレッドシートのURL取得
   send_message('スコアシートを送信します\n\n\n'+scoresheet_url)
   fease_sheet.clear();//フェーズシートを初期化する
   return
}
```

モルックは、ゲームを終了する条件が多く存在し、複雑化しているため実装がやや面倒でした。

特に、前半チームが50点に達したり、ミスを３回繰り返したりなど、前半チームが終わりに差し掛かった際、後半チームはまだ最後のターンが残っていますよね。その場合の処理として、

(前半チームの合計スコアが５０点であり、前半チームのフェーズである場合　→ 後半チームに次のターンに５０点でなければ負けることを促す
　　　　　　　　　　　　　　        　↓
```javascript
  if(goukei_score == 50 & team == 0){ //１チーム目の得点が50に達した時
        let teki_team = score_sheet.getRange('C3').getValue()
        send_message(teki_team+'チームが50に達しなかった場合、' + team_name + 'チームの勝利です。')//１チーム目が上がっても２チームめのターンが残っているため
        fease_sheet.getRange(miss_count_cell).setValue(0) //ミスカウントをリセット
        return
      }
```


 


(前半チームの合計スコアが５０点であり、後半チームのフェーズであり、後半チームの合計が５０点ではない場合)　→　前半チームの勝利でend関数へ進む
end関数の引数には勝利チームの名前を渡す
　　　　　　　　　　　　　　        　↓

```javascript
 if((score_sheet.getRange('B30').getValue() == 50) & team == 1 & goukei_score != 50){//１チーム目が５０点になり、２チーム目が５０点に達しなかった時
        let teki_team = score_sheet.getRange('B3').getValue()
        send_message(teki_team+'チームの勝利です。')
        end(new_sheet_id,teki_team)
        return
      }
```

(後半チームが５０点であり、後半のチームのフェーズだった場合)　→　同点のためend関数へ進む
end関数の引数には'draw'を渡す
　　　　　　　　　　　　　　        　↓

```javascript
      if(goukei_score == 50 & team == 1){ //２チーム目の得点が50に達した時
      if(score_sheet.getRange('B30').getValue() == 50){
        send_message('両チーム50点に達したためこのゲームは引き分けとなります。\n\nモルックアウトをプレイして勝敗を決めてください。')
        end(new_sheet_id,'draw')
        return
      }
```




# 5. いきなりLINE botが動かなくなる？(トラブル２個目)
実際に使っていると、いきなりbotからの返信が来なくなりました。
既読はつくものの、何もなく。
かといって、コードはどこも間違っていない。どうしよう？

:::note alert
**doPost関数を使っていると、基本的にエラー文を見ることができません。**
:::

では、どうデバッグすれば良いのでしょうか？

結論から言うと、


:::note info
**GASをGCPと連携させることでエラー内容を把握することができます**
:::




私は以下の方のを参考にさせていただきました。


https://zenn.dev/uma1100/articles/2695d1d93e238a

GCPと連携し、ログを確認した結果が以下の通りです。


![スクリーンショット 2022-08-10 1.33.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/87eadbe9-435a-bb12-bffe-a74221305226.png)


```
'You have reached your monthly limit'
```

だそうです。
つまり、LINE Messagin APIの送信回数が上限(１０００通)にきていたわけです。
これはGCPでログを見ないと気づけませんでした。

**LINE Messaging APIを使ってグループラインにテキストをpushすると
人数分の送信回数が消費されてしまいます。**

グループラインが７人ならば、１メッセージにつき７がカウントされるという事です。
１ゲームで大体２０〜３０回メッセージが送信されるため、
１ゲームで２００近くも送信回数が消費されるわけですね〜

道理で早くbotが機能しなくなるわけですね・・・


詳細は以下のサイトをご覧ください。

https://taupe.site/entry/line-messaging-api-push-count/

# 6. 実際にbotを使いながらプレイしてみた！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/5a9a4043-8408-fc40-4031-577d428ee60b.jpeg" width=75%>



**高校の友人とレッツプレイ！！！**
ここからは上から順に時系列で書いてきます。


- - -



<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/0695ba9e-de10-7f52-64ff-045401875fdf.png" width=75%>



モルック開始とメッセージを送ることでゲームがスタートします。
その後、１チーム目の名前を理系クラスだった友人で、
２チーム目を文系クラスだった友人らです。

今回は僕は記録係です（笑）
- - -

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/b134c239-a0ce-88ad-7762-3ca48d9b382a.jpeg" width=75%>

理系チームの１発目です！

- - -

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/037e2519-81fe-e147-7670-681cfaf73569.jpeg" width=75%>

一発目の投球は３本倒れたようですね！！
この棒は倒れた場所で立て直します。


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/8739717f-e95a-deb9-19a6-21baf311b62b.png" width=90%>

このように半角数字で文字を送信すると１チーム目の得点が記録されます。
もちろん、全角の数字や、日本語文字や、１〜１２以外の数字の場合は弾かれるように設定しています。

- - -

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/d0a8f8b9-d496-d3bd-a123-a7abab38f9f9.jpeg" width=75%>

文系チームの投球はなんと０本でした・・
三回連続でミスをすると失格です。


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/7e268357-f9bb-5207-237e-f4441363aa6a.png" width=90%>


ミスの場合はミスと入力します。０点ですね、、

- - -
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/e435acaa-6309-3a16-56b3-6660be57986a.png" width=90%>

チーム理系チームもミスをしたようです。
ミスは０点なので前回のスコアが引き継がれ、合計スコアが３点です。

- - -

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/2b7938f3-7136-75da-03ab-0caa44de8c46.jpeg" width=75%>

ここで文系チームが９の棒を一本倒したようです！


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/cdd51915-7c8c-720c-91e4-e5509bfa32dd.png" width=90%>

この場合、一本のみを倒した場合はその倒した棒の点数分が加算されます。
よって９点が得点に入るので、９を送信します。

この調子でゲームを続けていきます。
- - -

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/99fc6e24-51eb-ddee-f277-4aeb8199ad63.png" width=90%>


終盤に差し掛かり、理系チームが４５点だったところ、５本を倒し、５０点になりました！！
しかし、理系チームは前半のチームのため、後半チームにはもう１回分の投球が残っています！！
そのため、文系チームが５０点に達しなかった場合、理系チームが勝利してしまうメッセージを送信しています。

- - -

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/95247b0b-78ff-0870-2248-772b2196ad66.jpeg" width=75%>



ここで、後半チームの文系チームが２点しか獲得することができず、文系チームの負けが決定しました！
ゲーム終了です！！


- - -




<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/7f5f99ff-f007-1863-cbe4-e26adc6058b4.png" width=80%>

ゲームが終了し、このように勝ったチームがメッセージとして送信され、その後にスコアシートが送信されてきます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/d2568731-b40e-69b2-5158-a289882d177e.png" width=70%>

このゲームのスコアシートはこのような感じになっています。
シンプルですが、見やすくていいですね^^


# 6. 最後に

結構時間をかけて作りましたので、いいなと思ったらいいねお願いいたします！
また、これからも面白い画期的なシステムを作れたらなと思います。
React-Nativeでアプリ作りたいと思ってます〜