Open4
LINEbot

おはよう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);
});

リッチメニュー
manager.line.biz/account
(3分割の場合)
1ブロック:400px × 405px

なぞなぞ
//状態管理は外で行う
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);
});

📘 なぞなぞ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 で管理