diff --git a/library/omikuji.py b/library/omikuji.py new file mode 100644 index 0000000000..8ba5583c31 --- /dev/null +++ b/library/omikuji.py @@ -0,0 +1,43 @@ +# coding: utf-8 + +""" +おみくじを返す +""" + +from typing import Tuple, TypeVar +from dataclasses import dataclass +from random import choices + + +@dataclass +class OmikujiResult(): + """ + おみくじの引いた結果を示すデータクラス + 出やすさの調整もここで行う + """ + appearance: int + message: str + + def __post_init__(self): + """ + 初期化後のアサーション + """ + assert self.appearance > 0 + assert self.message != '' + + +TOmikujiEnum = TypeVar('TOmikujiEnum') +OmikujiResults = dict[TOmikujiEnum, OmikujiResult] + + +def draw(entries: OmikujiResults) -> Tuple[TOmikujiEnum, OmikujiResult]: + """ + おみくじを引く + """ + + return choices( + population=list(entries.items()), + weights=list( + map(lambda entry: entry.appearance, entries.values())), + k=1 + )[0] diff --git a/plugins/analyze.py b/plugins/analyze.py index 614a4bb090..f6c94ca3f0 100644 --- a/plugins/analyze.py +++ b/plugins/analyze.py @@ -24,6 +24,7 @@ def analyze_message(message: str) -> Callable[[BaseClient], None]: '標高': lambda m: hato.altitude((m[len('標高'):]).strip()), 'version': lambda m: hato.version, 'にゃーん': lambda m: hato.yoshiyoshi, + 'おみくじ': lambda m: hato.omikuji, } for key, method in conditions.items(): diff --git a/plugins/hato.py b/plugins/hato.py index 67d28d052b..d6c702b2cc 100644 --- a/plugins/hato.py +++ b/plugins/hato.py @@ -6,6 +6,7 @@ import json import os import re +from enum import Enum, auto from logging import getLogger from tempfile import NamedTemporaryFile from typing import List @@ -22,6 +23,7 @@ from library.hatokaraage import hato_ha_karaage from library.clientclass import BaseClient from library.jma_amesh import jma_amesh +from library.omikuji import OmikujiResult, OmikujiResults, draw as omikuji_draw logger = getLogger(__name__) @@ -54,6 +56,7 @@ def help_message(client: BaseClient): 'text delete [int] ... 指定した番号[int]のパワーワードを削除する。 ', '>< [text] ... 文字列[text]を吹き出しで表示する。', 'にゃーん ... 「よしよし」と返す。', + 'おみくじ ... おみくじを引いて返す。', 'version ... バージョン情報を表示する。', '', '詳細はドキュメント(https://github.com/dev-hato/hato-bot/wiki)も見てくれっぽ!', @@ -273,3 +276,65 @@ def yoshiyoshi(client: BaseClient): logger.debug("%s called 'hato yoshiyoshi'", client.get_send_user()) logger.debug("%s app called 'hato yoshiyoshi'", client.get_type()) client.post('よしよし') + + +# 以下おみくじの設定 +# Refer: dev-hato/hato-bot#876 +class OmikujiEnum(Enum): + """ + おみくじの結果一覧 + """ + DAI_KICHI = auto() + CHU_KICHI = auto() + SHO_KICHI = auto() + KICHI = auto() + SUE_KICHI = auto() + AGE_KICHI = auto() + KYO = auto() + DAI_KYO = auto() + + +omikuji_results = OmikujiResults({ + OmikujiEnum.DAI_KICHI: OmikujiResult( + 12, + ":tada: 大吉 何でもうまくいく!!気がする!!" + ), + OmikujiEnum.KICHI: OmikujiResult( + 100, + ":smirk: 吉 まあうまくいくかも!?" + ), + OmikujiEnum.CHU_KICHI: OmikujiResult( + 100, + ":smile: 中吉 そこそこうまくいくかも!?" + ), + OmikujiEnum.SHO_KICHI: OmikujiResult( + 100, + ":smily: 小吉 なんとなくうまくいくかも!?" + ), + OmikujiEnum.SUE_KICHI: OmikujiResult( + 37, + ":expressionless: 末吉 まあ多分うまくいくかもね……!?" + ), + OmikujiEnum.AGE_KICHI: OmikujiResult( + 2, + ":poultry_leg: 揚げ吉 鳩を揚げると良いことあるよ!!" + ), + OmikujiEnum.KYO: OmikujiResult( + 12, + ":cry: 凶 ちょっと慎重にいったほうがいいかも……" + ), + OmikujiEnum.DAI_KYO: OmikujiResult( + 2, + ":crying_cat_face: 大凶 そういう時もあります……猫になって耐えましょう" + ), +}) + + +def omikuji(client: BaseClient): + """ + おみくじ結果を返す + """ + + logger.debug("%s called 'hato yoshiyoshi'", client.get_send_user()) + logger.debug("%s app called 'hato yoshiyoshi'", client.get_type()) + client.post(omikuji_draw(omikuji_results)[1].message) diff --git a/tests/library/test_omikuji.py b/tests/library/test_omikuji.py new file mode 100644 index 0000000000..af184b1463 --- /dev/null +++ b/tests/library/test_omikuji.py @@ -0,0 +1,35 @@ +""" +omikujiライブラリのテスト +""" + +import unittest + +from enum import Enum, auto +from library.omikuji import OmikujiResult, OmikujiResults, draw + + +class TestOmikuji(unittest.TestCase): + """ + おみくじのテスト + """ + + def test_omikuji_minimum(self): + """ + おみくじの実装が正常か + """ + class DummyOmikujiEnum(Enum): + """ + おみくじ設定(ダミー) + """ + KICHI = auto() + SUE_KICHI = auto() + + dummy_omikuji_results = OmikujiResults({ + DummyOmikujiEnum.KICHI: OmikujiResult(1, "吉"), + DummyOmikujiEnum.SUE_KICHI: OmikujiResult(1, "末吉"), + }) + + self.assertIn( + draw(dummy_omikuji_results)[0], + dummy_omikuji_results.keys() + ) diff --git a/tests/plugins/test_hato.py b/tests/plugins/test_hato.py index 1792c5e556..b13b9b58af 100644 --- a/tests/plugins/test_hato.py +++ b/tests/plugins/test_hato.py @@ -10,7 +10,7 @@ import requests_mock import slackbot_settings as conf -from plugins.hato import split_command, amesh, altitude, yoshiyoshi +from plugins.hato import split_command, amesh, altitude, yoshiyoshi, omikuji, omikuji_results from tests.library.test_geo import set_mock from tests.plugins import TestClient @@ -232,5 +232,23 @@ def test_yoshiyoshi(self): self.assertEqual(client1.get_post_message(), 'よしよし') +class TestOmikuji(unittest.TestCase): + """ + omikujiのテスト + """ + + def test_omikuji(self): + """ + 設定したおみくじ結果のうち1つが返ってくる + """ + + client1 = TestClient() + omikuji(client1) + self.assertIn( + client1.get_post_message(), + map(lambda e: e.message, omikuji_results.values()) + ) + + if __name__ == '__main__': unittest.main()