mjai.app上评估提交文件的麻将游戏模拟器
项目描述
mjai-simulator
mjai.app 是一个麻将人工智能竞赛平台。此存储库包含在mjai.app上评估提交文件的麻将游戏模拟器实现。
安装
mjai
软件包可在Python包索引(PyPI)中找到。您可以使用 pip
命令安装它。
$ pip install mjai
使用
您可以通过指定以下代码中的提交文件来模拟麻将游戏。模拟器内部运行 Docker。必须安装并可用以用户权限运行 docker
命令。
import mjai
submissions = [
"examples/shanten.zip",
"examples/tsumogiri.zip",
"examples/tsumogiri.zip",
"examples/invalidbot2.zip",
]
mjai.Simulator(submissions, logs_dir="./logs").run()
此软件包还提供了一个用于开发通过mjai协议通信的机器人的基类。
from mjai import Bot
class RulebaseBot(Bot):
def think(self) -> str:
if self.can_tsumo_agari:
return self.action_tsumo_agari()
elif self.can_ron_agari:
return self.action_ron_agari()
elif self.can_riichi:
return self.action_riichi()
...
if __name__ == "__main__":
RulebaseBot(player_id=int(sys.argv[1])).start()
Docker镜像
提交文件部署在Docker容器中,并以Docker容器的形式运行。
此存储库包含用于创建Docker容器的Dockerfile和其他资源。Docker镜像已推送到Docker Hub( docker.io/smly/mjai-client:v3
)。
提交格式
请准备一个程序,当从标准输入接收mjai协议格式的输入时,将其输出为适当的 mjai协议消息 到标准输出。将此程序命名为 "bot.py" 并将其打包到zip文件中。zip文件应包含位于根目录下的bot.py。
bot.py 必须是 Python 脚本,但也可能包含可执行的预编译库。程序将在 linux/amd64
环境中执行。提交文件大小必须小于或等于 1000 MB。bot.py 的第一个参数是玩家 ID。玩家 ID 必须是 0、1、2 或 3。玩家 ID 0 代表起家,后续数字代表下家、对面或上家。有关详细信息,请参阅 示例代码。
超时
当 mjai.Simulator
实例在 docker 中创建运行提交文件的执行环境时,它指定了 --platform linux/amd64
选项。如果您想在不同的架构上运行,您将不得不模拟并运行容器,这将非常慢。如果您在除 linux/amd64
以外的架构上调试,您可以通过放宽超时限制来避免超时错误。以下是如何指定 timeout
参数。默认情况下,timeout
设置为 2.0。
Simulator(submissions, logs_dir="./logs", timeout=10.0).run()
如果模拟被中断,docker 容器可能无法成功终止。如果以前的 docker 容器仍然存在,新的 docker 容器可能由于重复的 HTTP 端口而无法启动。您可以通过以下方式批量删除具有 smly/mjai-client
映像作为祖先的所有 docker 容器
% for cid in `docker ps -a --filter ancestor=smly/mjai-client:v3 --format "{{.ID}}"`; do docker rm -f $cid; done
Mjai 协议
我们的 Mjai 协议基本上基于Gimite 的原始 Mjai 协议,但基于Mortal 的 Mjai 引擎实现进行了定制。以下是一些定制点
- 消息通过标准输入和标准输出发送和接收。
- 游戏服务器发送消息,直到玩家可以采取行动的事件。
- 当玩家没有发送适当的事件消息时,它被视为 chombo,并支付 mangan 大小的罚款。
- 如果玩家在 2 秒内没有发送消息,它被视为 chombo,并支付 mangan 大小的罚款。
- 第一轮(局)不一定是东 1。
第一轮不一定是东 1
如果任何一位玩家出现错误,则游戏被视为中止和局(流局)。在这种情况下,所有四位玩家的容器都会终止。玩家的容器将重新启动,并从发生错误的下一轮开始继续游戏。因此,玩家收到的第一轮可能不是东 1。
以下是从玩家 0 观察到的发送和接收的消息。 <-
表示玩家的事件。 ->
表示来自玩家的事件。
# Game resumed from S1-1
0 <- [{"type":"start_game","names":["0","1","2","3"],"id":0}]
0 -> {"type":"none"}
# NOTE: No ryukyoku events are sent from the game server.
0 <- [{"type":"end_kyoku"}]
0 -> {"type":"none"}
# S2-2 first tsumo tile
0 <- [{"type":"start_kyoku","bakaze":"S","dora_marker":"1p","kyoku":2,"honba":2,"kyotaku":0,"oya":1,"scores":[800,61100,11300,26800],"tehais":[["4p","4s","P","3p","1p","5s","2m","F","1m","7s","9m","6m","9s"],["?","?","?","?","?","?","?","?","?","?","?","?","?"],["?","?","?","?","?","?","?","?","?","?","?","?","?"],["?","?","?","?","?","?","?","?","?","?","?","?","?"]]},{"type":"tsumo","actor":1,"pai":"?"},{"type":"dahai","actor":1,"pai":"F","tsumogiri":false},{"type":"tsumo","actor":2,"pai":"?"},{"type":"dahai","actor":2,"pai":"3m","tsumogiri":true},{"type":"tsumo","actor":3,"pai":"?"},{"type":"dahai","actor":3,"pai":"1m","tsumogiri":true},{"type":"tsumo","actor":0,"pai":"3s"}]
0 -> {"type":"dahai","pai":"3s","actor":0,"tsumogiri":true}
案例研究:振听(振聴)
当玩家已经做出十番,但手牌处于振听状态。由于玩家不能隆,即使对手弃掉等待的牌,也无法采取行动。例如,假设你有 2333678m 678s 678p
。等待的牌是 14m
,1m
已经被弃掉。由于手牌处于振听状态,即使其他玩家弃掉 1m
,玩家也不能隆。
3 <- [{"type":"dahai","actor":3,"pai":"P","tsumogiri":true},{"type":"tsumo","actor":0,"pai":"?"},{"type":"dahai","actor":0,"pai":"2p","tsumogiri":true},{"type":"tsumo","actor":1,"pai":"?"},{"type":"dahai","actor":1,"pai":"4m","tsumogiri":true},{"type":"tsumo","actor":2,"pai":"?"},{"type":"dahai","actor":2,"pai":"6m","tsumogiri":true}]
在这种情况下,在演员 2 弃掉 6m 后,立即为演员 3 输入。演员 3 需要决定是否对 6m 进行 chi
叫牌。
案例研究:暗杠(暗槓)
在暗杠的情况下,先出现 dora 事件,然后是摸牌事件。
3 -> {"type": "ankan", "actor": 3, "consumed": ["6s", "6s", "6s", "6s"]}
3 <- [{"type":"ankan","actor":3,"consumed":["6s","6s","6s","6s"]},{"type":"dora","dora_marker":"6p"},{"type":"tsumo","actor":3,"pai":"7p"}]
3 -> {"type":dahai","actor":3,"pai":"7p","tsumogiri":true}
对于开发者
使用交互式壳调试
Simulator 执行的进程可以逐一检查和调试,如下所示
# pull latest docker image
% docker pull docker.io/smly/mjai-client:v3
# launch
% CONTAINER_ID=`docker run -d --rm -p 28080:3000 --mount "type=bind,src=/Users/smly/gitws/mjai.app/examples/rulebase.zip,dst=/bot.zip,readonly" smly/mjai-client:v3 sleep infinity`
# install bot program
% docker exec ${CONTAINER_ID} unzip -q /bot.zip
# debug
% docker exec -it ${CONTAINER_ID} /workspace/.pyenv/shims/python -u bot.py 0
[{"type":"start_game","id":0}] <-- Input
{"type":"none"} <-- Output
[{"type":"start_kyoku","bakaze":"E","dora_marker":"2s","kyoku":1,"honba":0,"kyotaku":0,"oya":0,"scores":[25000,25000,25000,25000],"tehais":[["E","6p","9m","8m","C","2s","7m","S","6m","1m","S","3s","8m"],["?","?","?","?","?","?","?","?","?","?","?","?","?"],["?","?","?","?","?","?","?","?","?","?","?","?","?"],["?","?","?","?","?","?","?","?","?","?","?","?","?"]]},{"type":"tsumo","actor":0,"pai":"1m"}] <-- Input
{"type": "dahai", "actor": 0, "pai": "C", "tsumogiri": false} <-- Output
[{"type":"dahai","actor":0,"pai":"C","tsumogiri":false},{"type":"tsumo","actor":1,"pai":"?"},{"type":"dahai","actor":1,"pai":"3m","tsumogiri":false},{"type":"tsumo","actor":2,"pai":"?"},{"type":"dahai","actor":2,"pai":"1m","tsumogiri":false}] <-- Input
{"type": "none"} <-- Output
[{"type":"tsumo","actor":3,"pai":"?"},{"type":"dahai","actor":3,"pai":"1m","tsumogiri":false}] <-- Input
{"type": "none"} <-- Output
[{"type":"tsumo","actor":0,"pai":"C"}] <-- Input
{"type": "dahai", "actor": 0, "pai": "C", "tsumogiri": true} <-- Output
使用 http 服务器调试
# install http server interface of mjai protocol
% docker cp python/mjai/http_server/server.py ${CONTAINER_ID}:/workspace/00__server__.py
# http server mode. `0` is the player index.
% docker exec -it ${CONTAINER_ID} /workspace/.pyenv/shims/python 00__server__.py 0
% curl http://localhost:28080/
OK
% curl -X POST -d '[{"type":"start_game","id":0}]' http://localhost:28080/
{"type":"none"}
% cat > request.json
[{"type":"start_kyoku","bakaze":"E","dora_marker":"2s","kyoku":1,"honba":0,"kyotaku":0,"oya":0,"scores":[25000,25000,25000,25000],"tehais":[["E","6p","9m","8m","C","2s","7m","S","6m","1m","S","3s","8m"],["?","?","?","?","?","?","?","?","?","?","?","?","?"],["?","?","?","?","?","?","?","?","?","?","?","?","?"],["?","?","?","?","?","?","?","?","?","?","?","?","?"]]},{"type":"tsumo","actor":0,"pai":"1m"}]
% curl -X POST -d '@request.json' http://localhost:28080/
{"type":"dahai","actor":0,"pai":"6p","tsumogiri":false}
开发
已确认与 rustc 1.75.0 (82e1608df 2023-12-21) 一起工作。
$ pip install maturin # install build tool
$ maturin build --release --locked --target aarch64-apple-darwin --out dist
特别感谢
./src
目录中的代码是 Mortal 的 libriichi,仅进行了少量更新。Mortal 根据 AGPL-3.0 发布,并受 Equim 版权保护。
项目详细信息
下载文件
下载适用于您平台的应用程序。如果您不确定选择哪个,请了解有关 安装包 的更多信息。
源分发
构建分发
mjai-0.2.1.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 7678ef75265192e0bf475ffbea27129de1a4c4c496de4ce95783d9178d33fbbe |
|
MD5 | 77b196add969ebdbd057f83ebfc38ffe |
|
BLAKE2b-256 | db771298b7b1307ee150fb5f341248de517efcc48124ff8e5370c968648e1db4 |
mjai-0.2.1-cp312-none-win_amd64.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 327cdf462f20261b85be2f61bea1f1f713c10f20b037bde2e2b2e8d6e1597f12 |
|
MD5 | f81cffe38f4738689e2f683980b9c0e3 |
|
BLAKE2b-256 | 7ede77e59de167c851588d9d6c7521331b0d498ebd4db9d344e3b15456a626ea |
mjai-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 9e261bef81938fa122b79811412b770e361d00775335b00e3d55bd90a9a4fc88 |
|
MD5 | de73e14ecdcb5a323d82d33cdeebe2fb |
|
BLAKE2b-256 | 41932a0b0c1a1f02aff5ed7156c28ea21607a6c85c53ac250c2ec22cc7646706 |
mjai-0.2.1-cp312-cp312-macosx_11_0_arm64.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 14e8126a0370d74444a807ea46cb75f7b2f5e7f24124755e711c298285d82464 |
|
MD5 | 66577de64c98e4cc6f084f60020b99c4 |
|
BLAKE2b-256 | e508a19b1cc890390ec45dee2e308efec753d9beffe007def3c00b730d586d6f |
mjai-0.2.1-cp311-none-win_amd64.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 80e5f908e0a3ea86ae278d4a7d320babc7a608421f9442719f2a01e5d484ee3a |
|
MD5 | 65e60f849fcde2c05d3b2e27447b1e8a |
|
BLAKE2b-256 | 73921dee7027fc3c44473769c888b24c9b3341e1cc4f5483f7c2e3322d513f9a |
mjai-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 7e9bd89d0dfe8c00ecb1e157f889d4c2aa1098d21f3025dff5e434448e46667d |
|
MD5 | 2261d06595b956833c0d2c757e3337e4 |
|
BLAKE2b-256 | 05d53c95799b5f802a9706bb57d36fef8df1fbd67dd3ca9735136ca6e3c26aea |
mjai-0.2.1-cp311-cp311-macosx_11_0_arm64.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 31a066f250df8538b8d7f4f833e7bc0f91baef23b58899f565e4dbc5ba8ed564 |
|
MD5 | 16c7889d0c0830e2e5c1839644f4914f |
|
BLAKE2b-256 | b2997b248dba856f85aaef3301536bacd6c5046fb370ab9012530cbf0f001fb3 |
mjai-0.2.1-cp310-none-win_amd64.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 33853f451a7c5858c808f965d7180c20816a7302779f9f7331bc2f9d9e97dcd4 |
|
MD5 | 03c4f73c49c88a3fde399a229adca10e |
|
BLAKE2b-256 | 66f17880c30bf840c1b610f599d955d8c2f908445d20b5a3be738065aa4acc28 |
mjai-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 0eecddb86746eb48827f2d81f7dccd2fff28648ea9c388f8dd55ab4774e9e7f9 |
|
MD5 | 199a0a0b03d585a1f2dd45911702612e |
|
BLAKE2b-256 | 30aa704ba4c2e4e4351834ffabde39a6d046f02e3f3a37cbb8936ad9cb7f4fbd |
mjai-0.2.1-cp310-cp310-macosx_11_0_arm64.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | f5ff6a389b76fd4a3bf4aff760c19c29475074cc483c95953bcf3df001d989c7 |
|
MD5 | fbebe7a68cab234d66b5d9aa9972cef7 |
|
BLAKE2b-256 | 612b563ecdb4e9ce39de5f5933dd9e1b58e01670381102b389205d89e501b447 |