Open4

LINEbot

phihashphihash

おはようBot

app.post('/webhook', middleware(config), (req, res) => {
   //ここに書く
   const events = req.body.events;

   // すべてのイベントを処理
   events.forEach(event => {
       if (event.type === 'message' && event.message.type === 'text') {
           // 「メッセージ」 かつ 「テキストメッセージ」 の場合
           if (event.message.text === 'おはよう') {
                メッセージの内容が 'おはよう' の場合
               client.replyMessage(event.replyToken, {
                   type: 'text',
                   text: 'おはよう!今日も頑張ろうね!'
               });
                // 第一引数に(event.replyToken)識別子
                //第二引数{ type: 'text', text: 'hogehoge' }
           }
       }
   });

   res.sendStatus(200);
});

phihashphihash

なぞなぞ

//状態管理は外で行う
let state = "waiting"; // 初期状態
let currentQuestion = null;
const userStates = new Map(); // userId → { state, currentQuestion }


const questions = [{
  question: "パンはパンでも食べられないパンってなーんだ?",
  answer: "フライパン",
  isSolved: false
},
{
  question: "食たべると勝かてそうなカレーは何なにカレーだ?",
  answer: "カツカレー",
  isSolved: false
},
{
  question: "机の上に置けて、座れないものってなーんだ?",
  answer: "座布団",
  isSolved: false
}];


//そして状態ごとに関数をまとめる(wating,quizzing)

const handleWaitingState = (text,token,userState) => {
  if(text === "なぞなぞ"){
    // 1. なぞなぞが開始されていない場合
    const unsolvedQuestions = questions.filter(
      (q) => !userState.solvedQuestions.includes(q.question)
    );

    if (unsolvedQuestions.length === 0) {
      userState.state = "finished";
      return replyMessage(token, "全問クリア!おめでとう!");
    }
    const question = unsolvedQuestions[Math.floor(Math.random() * unsolvedQuestions.length)];
    userState.currentQuestion = question;
    userState.state = "quizzing";
    replyMessage(token, question.question);
  }else{
    // 2. クイズも始まっておらず、クイズも存在せず、なぞなぞ以外のメッセージが送られた場合
    replyMessage(token, "なぞなぞを始めるには「なぞなぞ」と送信してください");
  }
}

const handleQuizzingState = (text,token ,userState) => {
  if(text === "なぞなぞ"){
    // 3. すでになぞなぞが開始されている場合
    replyMessage(token, "すでになぞなぞが開始されています");
  }else if(text === userState.currentQuestion.answer){
    // 4. クイズが解かれた場合
    replyMessage(token, "正解!");
    userState.solvedQuestions.push(userState.currentQuestion.question);
    userState.state = "waiting";
    userState.currentQuestion = null;
  }else if(text === "やめる"){
    // 5. クイズが解かれていない場合
    replyMessage(token, "クイズを終了します");
    userState.state = "waiting";
    userState.currentQuestion = null;
  }else if(text === "再送"){
    replyMessage(token, userState.currentQuestion.question);
  }else if(text !== userState.currentQuestion.answer){
    // 5. クイズが解かれていない場合
    replyMessage(token, "不正解!");
  }
}

const handleFinishedState = (text, token, userState) => {
  if (text === "リセット") {
    userState.solvedQuestions = [];
    userState.currentQuestion = null;
    userState.state = "waiting";
    replyMessage(token, "リセット完了!またなぞなぞしてね!");
  } else {
    replyMessage(token, "全問クリア済み!「リセット」と送ってもう一度遊べるよ!");
  }
};


const replyMessage = (token,text) => {
  return client.replyMessage(token, {
    type: "text",
    text: text
  })
}

const stateHandlers = {
  waiting: handleWaitingState,
  quizzing: handleQuizzingState,
  finished: handleFinishedState
};

app.post('/webhook', middleware(config), (req, res) => {
  const events = req.body.events;

  events.forEach((event)=> {
    const text = event.message.text;
    const token = event.replyToken;
    const userId = event.source.userId;
    if(event.type === "message" && event.message.type === "text"){

      if (!userStates.has(userId)) {
        userStates.set(userId, {
          state: "waiting",
          currentQuestion: null,
          solvedQuestions: []
        });
      }
      const userState = userStates.get(userId);

      const handler = stateHandlers[userState.state];

      if (handler) {
        handler(text, token,userState);
      }

    }else{
      replyMessage(token, "テキストメッセージ以外は受け付けていません");
    }
  })

  res.sendStatus(200);
});

phihashphihash

📘 なぞなぞBot:これまでの学習まとめ
✅ 基本構成
express + @line/bot-sdk

app.post('/webhook') でイベントを受信

Map<userId, { state, currentQuestion, solvedQuestions }> でユーザーごとの状態を管理

🧠 実装した状態(ステート)
状態名 説明
waiting 出題前の状態。"なぞなぞ"でクイズ開始
quizzing クイズ中。正解/不正解/再送/中断に対応
finished 全問解いた後の状態。"リセット"で再挑戦可

💬 対応した入力(text)
入力 状態 反応内容
"なぞなぞ" waiting 未出題からランダム出題、状態はquizzingに
"再送" quizzing 今の問題をもう一度送信
"やめる" quizzing クイズ中断、状態waitingに戻す
"正解" quizzing 正解!状態waitingに戻す or finishedへ
その他 quizzing 「不正解!」と返す
"リセット" finished 回答履歴を消して状態をwaitingに戻す
その他 finished 「全問クリア済み!」と案内

✨ コード構成のポイント
状態ごとに処理を分ける関数(state handler)を定義
stateHandlers[state] で状態に応じた関数を実行
Map でユーザーごとの状態を保持

問題は questions[] に入れて、question.text / question.answer で管理