Bot for tenhou.net riichi mahjong server written in Python

Overview

Build [Tests coverage]

Bot was tested with Python 3.7+ and PyPy3, we are not supporting Python 2.

What do we have here?

Example of bot game

Mahjong hands calculation

You can find it here: https://github.com/MahjongRepository/mahjong

Mahjong bot

For research purposes we built a simple bot to play riichi mahjong on tenhou.net server.

Here you can read about bot played games statistic: versions history

For developers

How to run it?

  1. pip install -r requirements/lint.txt
  2. Run cd project && python main.py it will connect to the tenhou.net and will play a game.

How to run bot battle with pypy

To make it easier run bot vs bot battles we prepared PyPy3 Docker container.

Run the game locally:

  1. Install Docker
  2. Run make build_docker
  3. Run make GAMES=1 run_battle it will play one game locally. Logs and replays will be stored in bots_battle folder.

Run bots with enabled decision logger (use it only for debug, since it harms performance):

  1. Run make GAMES=1 ARGS=--logs run_battle

Run multiple bots to play one game

  1. Install Docker and Install Docker Compose
  2. Run make build_docker
  3. Put bot configs to project/settings/. By default we are looking for these configs: bot_1_settings.py, bot_2_settings.py, bot_3_settings.py, bot_4_settings.py, bot_5_settings.py. Why 5 settings? Because tenhou doesn't start 2+ game in the custom lobby if you are running only 4 bots.
  4. Run make run_on_tenhou

Configuration instructions

  1. Put your own settings to the project/settings/settings_local.py file. They will override settings from default settings/base.py file.
  2. Also, you can override some default settings with command arguments. Use python main.py -h to check all available commands.

Game reproducer

It can be useful to debug bot errors or strange discards: game reproducer

Comments
  • Occassionally printing infinite empty 'GET:' after player calls Riichi

    Occassionally printing infinite empty 'GET:' after player calls Riichi

    Hi Nihisil,

    thank you so much for developing this repo, when I used it to play an online match(with my little dumb AI), it seems encountered a bug described in the title, here are some logs:

    2017-01-17 16:50:33 DEBUG: Send: <Z />
    2017-01-17 16:50:33 DEBUG: Send: <NEXTREADY />
    2017-01-17 16:50:35 DEBUG: Get: <INIT seed="3,0,0,2,5,82" ten="350,158,334,158" oya="1" hai="119,77,68,116,4,37,71,74,73,90,64,66,132"/> <U/> 
    2017-01-17 16:50:35 INFO: Round: 3, Honba: 0, Dora Indicators: [82]
    2017-01-17 16:50:35 INFO: Players: [NoName (35,000), 上野あいみ (33,400), no_D (15,800), 紅稀 (15,800)]
    2017-01-17 16:50:35 INFO: Dealer: no_D (15,800)
    2017-01-17 16:50:35 INFO: Round  wind: East
    2017-01-17 16:50:35 INFO: Player wind: North
    2017-01-17 16:50:41 DEBUG: Get: <E114/> 
    2017-01-17 16:50:42 DEBUG: Get: <N who="2" m="44139" /> 
    2017-01-17 16:50:42 INFO: Meld: pon, who 2
    2017-01-17 16:50:44 DEBUG: Get: <F3/> <W/> 
    2017-01-17 16:50:46 DEBUG: Get: <G121/> <T54/> 
    2017-01-17 16:50:47 INFO: Hand: 2m158899p1125s337z
    2017-01-17 16:50:47 DEBUG: Send: <D p="132"/>
    2017-01-17 16:50:47 INFO: Remaining tiles: 67
    2017-01-17 16:50:48 DEBUG: Send: <Z />
    2017-01-17 16:50:48 DEBUG: Get: <D132/> <U/> 
    2017-01-17 16:50:49 DEBUG: Get: <E123/> <V/> 
    2017-01-17 16:50:53 DEBUG: Get: <F60/> 
    2017-01-17 16:50:58 DEBUG: Get: <W/> 
    2017-01-17 16:50:59 DEBUG: Get: <G124/> <T63/> 
    2017-01-17 16:51:00 INFO: Hand: 2m1578899p1125s33z
    2017-01-17 16:51:00 DEBUG: Send: <D p="37"/>
    2017-01-17 16:51:00 INFO: Remaining tiles: 63
    2017-01-17 16:51:01 DEBUG: Get: <D37/> <U/> 
    2017-01-17 16:51:02 DEBUG: Get: <E34/> <V/> 
    2017-01-17 16:51:03 DEBUG: Send: <Z />
    2017-01-17 16:51:03 DEBUG: Get: <F135/> <W/> 
    2017-01-17 16:51:08 DEBUG: Get: <G133/> <T81/> 
    2017-01-17 16:51:09 INFO: Hand: 2m578899p11235s33z
    2017-01-17 16:51:09 DEBUG: Send: <D p="4"/>
    2017-01-17 16:51:09 INFO: Remaining tiles: 59
    2017-01-17 16:51:10 DEBUG: Get: <D4/> 
    2017-01-17 16:51:11 DEBUG: Get: <U/> 
    2017-01-17 16:51:12 DEBUG: Get: <E32/> <V/> 
    2017-01-17 16:51:13 DEBUG: Get: <F127/> <W/> 
    2017-01-17 16:51:16 DEBUG: Get: <G107/> <T16/> 
    2017-01-17 16:51:17 INFO: Hand: 5m578899p11235s33z
    2017-01-17 16:51:17 DEBUG: Send: <D p="16"/>
    2017-01-17 16:51:17 INFO: Remaining tiles: 55
    2017-01-17 16:51:18 DEBUG: Send: <Z />
    2017-01-17 16:51:18 DEBUG: Get: <D16/> <U/> 
    2017-01-17 16:51:20 DEBUG: Get: <E98/> <V/> 
    2017-01-17 16:51:22 DEBUG: Get: <F101/> 
    2017-01-17 16:51:23 DEBUG: Get: <W/> 
    2017-01-17 16:51:24 DEBUG: Get: <G36/> <T91/> 
    2017-01-17 16:51:25 INFO: Hand: 578899p112355s33z
    2017-01-17 16:51:25 DEBUG: Send: <D p="54"/>
    2017-01-17 16:51:25 INFO: Remaining tiles: 51
    2017-01-17 16:51:26 DEBUG: Get: <D54/> <U/> 
    2017-01-17 16:51:27 DEBUG: Get: <E131/> <V/> 
    2017-01-17 16:51:31 DEBUG: Get: <F27/> 
    2017-01-17 16:51:33 DEBUG: Send: <Z />
    2017-01-17 16:51:33 DEBUG: Get: <W/> 
    2017-01-17 16:51:34 DEBUG: Get: <g118 t="1"/> 
    2017-01-17 16:51:35 DEBUG: Send: <N />
    2017-01-17 16:51:36 DEBUG: Get: <T31/> 
    2017-01-17 16:51:37 INFO: Hand: 8m78899p112355s33z
    2017-01-17 16:51:37 DEBUG: Send: <D p="31"/>
    2017-01-17 16:51:37 INFO: Remaining tiles: 47
    2017-01-17 16:51:38 DEBUG: Get: <D31/> <U/> 
    2017-01-17 16:51:39 DEBUG: Get: <E106/> <V/> 
    2017-01-17 16:51:41 DEBUG: Get: <F129/> <W/> 
    2017-01-17 16:51:44 DEBUG: Get: <g130/> <T41/> 
    2017-01-17 16:51:45 INFO: Hand: 278899p112355s33z
    2017-01-17 16:51:45 DEBUG: Send: <D p="41"/>
    2017-01-17 16:51:45 INFO: Remaining tiles: 43
    2017-01-17 16:51:46 DEBUG: Get: <D41/> <U/> 
    2017-01-17 16:51:48 DEBUG: Send: <Z />
    2017-01-17 16:51:48 DEBUG: Get: <E0/> <V/> 
    2017-01-17 16:51:50 DEBUG: Get: <F83/> <W/> 
    2017-01-17 16:51:52 DEBUG: Get: <g109/> <T65/> 
    2017-01-17 16:51:53 INFO: Hand: 788899p112355s33z
    2017-01-17 16:51:53 DEBUG: Send: <D p="63"/>
    2017-01-17 16:51:53 INFO: Remaining tiles: 39
    2017-01-17 16:51:54 DEBUG: Get: <D63/> 
    2017-01-17 16:51:58 DEBUG: Get: <U/> 
    2017-01-17 16:51:59 DEBUG: Get: <e1/> <V/> 
    2017-01-17 16:52:00 DEBUG: Get: <f35/> 
    2017-01-17 16:52:03 DEBUG: Send: <Z />
    2017-01-17 16:52:03 DEBUG: Get: <W/> 
    2017-01-17 16:52:04 DEBUG: Get: <g96/> <T89 t="32"/> 
    2017-01-17 16:52:05 INFO: Hand: 88899p1123555s33z
    2017-01-17 16:52:05 DEBUG: Send: <REACH hai="64" />
    2017-01-17 16:52:07 DEBUG: Send: <D p="64"/>
    2017-01-17 16:52:07 INFO: Remaining tiles: 35
    2017-01-17 16:52:08 DEBUG: Get: <REACH who="0" step="1"/> 
    2017-01-17 16:52:09 DEBUG: Get: 
    2017-01-17 16:52:10 DEBUG: Get: 
    2017-01-17 16:52:11 DEBUG: Get: 
    2017-01-17 16:52:12 DEBUG: Get: 
    2017-01-17 16:52:13 DEBUG: Get: 
    2017-01-17 16:52:14 DEBUG: Get: 
    2017-01-17 16:52:15 DEBUG: Get: 
    2017-01-17 16:52:16 DEBUG: Get: 
    2017-01-17 16:52:17 DEBUG: Get: 
    2017-01-17 16:52:18 DEBUG: Send: <Z />
    2017-01-17 16:52:18 DEBUG: Get: 
    2017-01-17 16:52:19 DEBUG: Get: 
    2017-01-17 16:52:20 DEBUG: Get: 
    2017-01-17 16:52:21 DEBUG: Get: 
    2017-01-17 16:52:22 DEBUG: Get: 
    2017-01-17 16:52:23 DEBUG: Get: 
    2017-01-17 16:52:24 DEBUG: Get: 
    2017-01-17 16:52:25 DEBUG: Get: 
    2017-01-17 16:52:26 DEBUG: Get: 
    2017-01-17 16:52:27 DEBUG: Get: 
    2017-01-17 16:52:28 DEBUG: Get: 
    2017-01-17 16:52:29 DEBUG: Get: 
    2017-01-17 16:52:30 DEBUG: Get: 
    2017-01-17 16:52:31 DEBUG: Get: 
    2017-01-17 16:52:32 DEBUG: Get: 
    2017-01-17 16:52:33 DEBUG: Send: <Z />
    Exception in thread Thread-1:
    Traceback (most recent call last):
      File "/usr/lib/python3.4/threading.py", line 920, in _bootstrap_inner
        self.run()
      File "/usr/lib/python3.4/threading.py", line 868, in run
        self._target(*self._args, **self._kwargs)
      File "/home/hao/mahjong/tenhou-python-bot/project/tenhou/client.py", line 304, in send_request
        self._send_message('<Z />')
      File "/home/hao/mahjong/tenhou-python-bot/project/tenhou/client.py", line 280, in _send_message
        self.socket.sendall(message.encode())
    BrokenPipeError: [Errno 32] Broken pipe
    
    2017-01-17 16:52:33 DEBUG: Get: 
    2017-01-17 16:52:34 DEBUG: Get: 
    2017-01-17 16:52:35 DEBUG: Get: 
    2017-01-17 16:52:36 DEBUG: Get: 
    2017-01-17 16:52:37 DEBUG: Get: 
    2017-01-17 16:52:38 DEBUG: Get: 
    2017-01-17 16:52:39 DEBUG: Get: 
    2017-01-17 16:52:40 DEBUG: Get: 
    2017-01-17 16:52:41 DEBUG: Get: 
    2017-01-17 16:52:42 DEBUG: Get: 
    2017-01-17 16:52:43 DEBUG: Get: 
    2017-01-17 16:52:44 DEBUG: Get: 
    2017-01-17 16:52:45 DEBUG: Get: 
    2017-01-17 16:52:46 DEBUG: Get: 
    2017-01-17 16:52:47 DEBUG: Get: 
    2017-01-17 16:52:48 DEBUG: Get: 
    2017-01-17 16:52:49 DEBUG: Get: 
    2017-01-17 16:52:50 DEBUG: Get: 
    2017-01-17 16:52:51 DEBUG: Get: 
    2017-01-17 16:52:52 DEBUG: Get: 
    2017-01-17 16:52:53 DEBUG: Get: 
    2017-01-17 16:52:54 DEBUG: Get: 
    2017-01-17 16:52:55 DEBUG: Get: 
    2017-01-17 16:52:56 DEBUG: Get: 
    2017-01-17 16:52:57 DEBUG: Get: 
    2017-01-17 16:52:58 DEBUG: Get: 
    2017-01-17 16:52:59 DEBUG: Get: 
    2017-01-17 16:53:00 DEBUG: Get: 
    2017-01-17 16:53:01 DEBUG: Get: 
    2017-01-17 16:53:02 DEBUG: Get: 
    2017-01-17 16:53:03 DEBUG: Get: 
    2017-01-17 16:53:04 DEBUG: Get: 
    2017-01-17 16:53:05 DEBUG: Get: 
    2017-01-17 16:53:06 DEBUG: Get: 
    2017-01-17 16:53:07 DEBUG: Get: 
    2017-01-17 16:53:08 DEBUG: Get: 
    2017-01-17 16:53:09 DEBUG: Get: 
    2017-01-17 16:53:10 DEBUG: Get: 
    2017-01-17 16:53:11 DEBUG: Get: 
    2017-01-17 16:53:12 DEBUG: Get: 
    2017-01-17 16:53:13 DEBUG: Get: 
    2017-01-17 16:53:14 DEBUG: Get: 
    2017-01-17 16:53:15 DEBUG: Get: 
    2017-01-17 16:53:16 DEBUG: Get: 
    2017-01-17 16:53:17 DEBUG: Get: 
    2017-01-17 16:53:18 DEBUG: Get: 
    2017-01-17 16:53:19 DEBUG: Get: 
    2017-01-17 16:53:20 DEBUG: Get: 
    2017-01-17 16:53:21 DEBUG: Get: 
    2017-01-17 16:53:22 DEBUG: Get: 
    2017-01-17 16:53:23 DEBUG: Get: 
    2017-01-17 16:53:24 DEBUG: Get: 
    2017-01-17 16:53:25 DEBUG: Get: 
    2017-01-17 16:53:26 DEBUG: Get: 
    2017-01-17 16:53:27 DEBUG: Get: 
    2017-01-17 16:53:28 DEBUG: Get: 
    2017-01-17 16:53:29 DEBUG: Get: 
    2017-01-17 16:53:30 DEBUG: Get: 
    2017-01-17 16:53:31 DEBUG: Get: 
    2017-01-17 16:53:32 DEBUG: Get: 
    2017-01-17 16:53:33 DEBUG: Get: 
    2017-01-17 16:53:34 DEBUG: Get: 
    2017-01-17 16:53:35 DEBUG: Get: 
    2017-01-17 16:53:36 DEBUG: Get: 
    2017-01-17 16:53:37 DEBUG: Get: 
    2017-01-17 16:53:38 DEBUG: Get: 
    2017-01-17 16:53:39 DEBUG: Get: 
    2017-01-17 16:53:40 DEBUG: Get: 
    2017-01-17 16:53:41 DEBUG: Get: 
    2017-01-17 16:53:42 DEBUG: Get: 
    2017-01-17 16:53:43 DEBUG: Get: 
    2017-01-17 16:53:44 DEBUG: Get: 
    2017-01-17 16:53:45 DEBUG: Get: 
    
    opened by 0xsuu 9
  • AI crashes when calling chankan

    AI crashes when calling chankan

    2017-07-03 00:26:23 INFO: Hand: 23m55z + 8s [888s, 456m, 999s]
    2017-07-03 00:26:24 DEBUG: Send: <N type="5" hai="103" />
    2017-07-03 00:26:24 INFO: We called a kan set!
    2017-07-03 00:26:25 DEBUG: Get: <N who="0" m="38515" /> <T51/> 
    2017-07-03 00:26:25 INFO: Meld: Type: chankan, Tiles: 8888s [100, 101, 102, 103] by 0
    2017-07-03 00:26:25 INFO: Hand: 23m8s55z + 4p [888s, 456m, 999s]
    2017-07-03 00:26:26 ERROR: Unexpected exception
    Traceback (most recent call last):
      File "/mnt/d/programming/wsl/tenhou-python-bot-0.2.7/project/tenhou/main.py", line 24, in connect_and_play
        client.start_game()
      File "/mnt/d/programming/wsl/tenhou-python-bot-0.2.7/project/tenhou/client.py", line 277, in start_game
        discarded_tile = self.player.discard_tile()
      File "/mnt/d/programming/wsl/tenhou-python-bot-0.2.7/project/mahjong/player.py", line 157, in discard_tile
        tile_to_discard = self.ai.discard_tile()
      File "/mnt/d/programming/wsl/tenhou-python-bot-0.2.7/project/mahjong/ai/main.py", line 60, in discard_tile
        selected_tile = self.process_discard_options_and_select_tile_to_discard(results, shanten)
      File "/mnt/d/programming/wsl/tenhou-python-bot-0.2.7/project/mahjong/ai/main.py", line 96, in process_discard_options_and_select_tile_to_discard
        return self.chose_tile_to_discard(results)
      File "/mnt/d/programming/wsl/tenhou-python-bot-0.2.7/project/mahjong/ai/main.py", line 211, in chose_tile_to_discard
        temp_tile = results[0]
    IndexError: list index out of range
    2017-07-03 00:26:26 INFO: Ending the game...
    2017-07-03 00:26:26 ERROR: Game was ended without success
    

    Version is 0.2.7.

    Here is the link of full log file.
    https://app.box.com/s/zj8tos4qcdjcy5f3d4iolacz9dtiz88u

    bug kan 
    opened by 0xrgb 7
  • Very slow desicion

    Very slow desicion

    Бот на сервере думал 43 секунды над тем брать ли 5м в открытие. Тенха дисконектнула по таймауту из игры.

    Локально у меня это решение за 16 секунд обрабатывается, что тоже очень много и больше доступного таймера. Возможно это как-то малой кровью ускорить.

    Вопроизвести: python reproducer.py --log 2020102209gm-0009-0000-f4494785 --player Kaavi --wind 1 --honba 0 --tile 5m --action enemy_discard

    image

    performance 
    opened by Nihisil 5
  • Fail to connect if AI takes a long time to load(~3s).

    Fail to connect if AI takes a long time to load(~3s).

    In Tenhou client, if the overhead of AI takes approximately longer than 3s, then it'll show some socket timeout messages, the fix should be trivial.

    Many thanks.

    Edit: Sample output:

    2017-03-06 11:19:40 INFO: Bot AI enabled: True
    2017-03-06 11:19:52 DEBUG: Send: <HELO name="NoName" tid="f0" sx="M" />
    2017-03-06 11:19:52 DEBUG: Get: 
    2017-03-06 11:19:52 DEBUG: Send: <BYE />
    2017-03-06 11:19:52 INFO: End of the game
    
    bug 
    opened by 0xsuu 5
  • Error while run mahjong.py

    Error while run mahjong.py

    I run the mahjong.py and this came out, please help! pygame 1.9.4 Hello from the pygame community. https://www.pygame.org/contribute.html Traceback (most recent call last): File "E:/Mahjong-Dynasty-master/mahjong.py", line 12, in jeu_mahjong = mahjong_board(graphics) File "E:\Mahjong-Dynasty-master\src\game.py", line 82, in init self.refresh_mur_gfx() File "E:\Mahjong-Dynasty-master\src\game.py", line 128, in refresh_mur_gfx x, y, angle = fgx_pos_iterateur.next() AttributeError: 'generator' object has no attribute 'next'

    opened by NozomiWyane 3
  • INFO prints dan instead of score

    INFO prints dan instead of score

    2017-06-22 17:20:01 INFO: Round: 3, Honba: 1, Dora Indicators: [73]
    2017-06-22 17:20:01 INFO: Players: [isi1017 (61,400), 辺銀堂 (25,500), ToukaBot (13,100), にこぷり麻雀道. (2級)]
    2017-06-22 17:20:01 INFO: Dealer: 辺銀堂 (25,500)
    2017-06-22 17:20:01 INFO: Round  wind: East
    2017-06-22 17:20:01 INFO: Player wind: West
    

    Here is the link of full log file. https://app.box.com/s/futa0t1619l1g848trmeihzq8as0lv20

    bug 
    opened by 0xrgb 3
  • Bot crashed when calling kan set

    Bot crashed when calling kan set

    2017-06-22 13:45:12 INFO: Meld: Type: pon, Tiles: 555s [88, 90, 91] by 0
    2017-06-22 13:45:12 INFO: With hand: 34m455666p + 5s [345m, 555s]
    2017-06-22 13:45:12 INFO: Discard tile after called meld: 4p
    2017-06-22 13:45:12 DEBUG: Send: <D p="48"/>
    2017-06-22 13:45:13 DEBUG: Get: <D48/> <U/> 
    2017-06-22 13:45:16 DEBUG: Get: <e47/> <V/> 
    2017-06-22 13:45:20 DEBUG: Send: <Z />
    2017-06-22 13:45:21 DEBUG: Get: <f59 t="3"/> 
    2017-06-22 13:45:21 DEBUG: Send: <N type="2" />
    2017-06-22 13:45:21 INFO: We called a kan set!
    2017-06-22 13:45:22 DEBUG: Get: <N who="0" m="15106" /> <T45/> 
    2017-06-22 13:45:22 ERROR: Unexpected exception
    Traceback (most recent call last):
      File "/_github/tenhou-python-bot-0.2.6/project/tenhou/main.py", line 21, in connect_and_play
        client.start_game()
      File "/_github/tenhou-python-bot-0.2.6/project/tenhou/client.py", line 316, in start_game
        self.table.add_called_meld(meld.who, meld)
      File "/_github/tenhou-python-bot-0.2.6/project/mahjong/table.py", line 75, in add_called_meld
        self.get_player(player_seat).add_called_meld(meld)
      File "/_github/tenhou-python-bot-0.2.6/project/mahjong/player.py", line 214, in add_called_meld
        self.tiles.remove(meld.called_tile)
    ValueError: list.remove(x): x not in list
    2017-06-22 13:45:22 INFO: Ending the game...
    2017-06-22 13:45:22 ERROR: Game was ended without success
    

    Here is the log.

    bug kan 
    opened by 0xrgb 3
  • Not optimal discard?

    Not optimal discard?

    Возможно кинуть 9м тут является вариантом получше, но это не точно. Надо разобраться.

    Воспроизвести: python reproducer.py --log 2020102009gm-0001-7994-5e2f46c0 --player Kaavi --wind 3 --honba 1 --tile 5m --action draw

    image

    question? 
    opened by Nihisil 2
  • Change encounter and melding logic, add data analysis stuffs

    Change encounter and melding logic, add data analysis stuffs

    Hi Alex! I am really interested in this project and appreciate it a lot for works that have done. Now I have forked it, tweaked it a little bit, added some data analysis stuffs like data cleaning and visualization, and now I am running several bots to collect more data. I am looking forward to cooperate with you more.

    The changes I have made to this bot is mainly based on a book called 科学する麻雀. It's my favorite mahjong book.

    Several changes I have made to the bot are:

    • Play game according to several different states: Preparing, Proactive Goodshape, Proactive Badshape, Reactive Goodshape, Reactive Badshape, Defence.
    • Switch strategy to tanyao or yakuhai only if (dora >=1) or (shanten <= 2) or (is_dealer). I find the bot calling melds too much and several tweaks are based on this.
    • Improve tanyao condition judgement. If there are 2 or more terminal lugs(13, 12, 23 without 4, or stuffs like that), tanyao strategy won't be activated.
    • Improve yakuhai melding judgement by disallowing calling melds before yakuhai pon is called. In previous version it calls melds a lot before yakuhai pon and that's not good.

    Now the bot calls melds much less often than before and that results in better defence and more riichi.

    Now I am collecting more data to make better analysis and see where it can improve. I have collected about 100 games and 900 hands but that's not enough at all for data analysis.

    Any suggestions are appreciated.

    opened by jakehsiao 2
  • Is there a way to see whether a discarded tile from an opponent player is changed tile or not?

    Is there a way to see whether a discarded tile from an opponent player is changed tile or not?

    Hi, thanks for your effort in this project. I have a question about possibility of telling whether a tile is a changed tile or not.

    The definition of a changed tile: if the tile a player discards has existed in his hand, it is called a "changed tile"; if the tile a player discards is the one he just draws, it is NOT a "changed tile". I believe this information is important for mahjong players. When playing mahjong face to face, we always pay attention to players who changed their hands.

    In mjlog, we can easily get this information since all tiles (including those in the hands of opponent players) are visible; however, is it possible to get this information while playing real games?

    Thanks very much.

    opened by josephchenhk 2
  • [Question/Need help] How to watch a game based on python-socket communication with tenhou.net

    [Question/Need help] How to watch a game based on python-socket communication with tenhou.net

    Hi developer @Nihisil , I'm very interested in your AI developed. I'm mostly interested in the socket communication part that allows the AI to play game automatically through sending text messages. So I'm now currently learning your code and developing a program to watch a tenhou game and print out the results. But I meet some problems.

    By clicking into a tenhou game link obtained from tenhou.net/0/wg in my browser, and press F12, I saw the message sent in order to start watching a game: image So after I connected by socket and got authenticated (this part is same as your code), I sent <WG id="8DAC0C1A" tw=0 />, but I got no reply at all. At this stage if a sent a message requesting for a game (copied from your code), I could get reply and start a game. So I'm doubting whether I sent the correct message.

    Later on I compared other messages my browser sent with your code's, and I found some differences: The Login message: image image Your code has an extra tid="f0"

    The alive message when hanging around in lobby: image image The numbers within the messages are different.

    Since both messages work for sure, I wonder how you found out the correct message to send, and why you did not choose the same message as the browser version. (Note, most other messages sent are the same)

    I'm a beginner to socket, and I'm purely coding for fun and learning. I would appreciate it very much if you could give me some hints and guidance!

    opened by 17876zjc 7
  • [Question] Why and when socket connections was automatically?

    [Question] Why and when socket connections was automatically?

    Question

    I use this repository in our Mahjong AI Project and plays mahjong game (game_type is 9, hanchan ari-ari), but sometimes game was ended unsuccessfully with the log "We are getting empty messages from socket. Probably socket connection was closed". I'm not sure why and when this happened?

    opened by nara-ryoya 2
  • Crash [Live dora tiles can't be less than 0]

    Crash [Live dora tiles can't be less than 0]

    Bots played on commit: https://github.com/MahjongRepository/tenhou-python-bot/commit/1e4d477bf470c8a9024b4ad553ab47125b914903

    Seed to reproduce:

    15996451505448234089
    
    2020-11-24_03_16_38.log-Traceback (most recent call last):
    2020-11-24_03_16_38.log-  File "bots_battle.py", line 47, in main
    2020-11-24_03_16_38.log-    manager.play_game()
    2020-11-24_03_16_38.log-  File "/app/game/bots_battle/game_manager.py", line 105, in play_game
    2020-11-24_03_16_38.log-    results = self.play_round()
    2020-11-24_03_16_38.log-  File "/app/game/bots_battle/game_manager.py", line 435, in play_round
    2020-11-24_03_16_38.log-    meld, discard_option = other_client.player.try_to_call_meld(tile, is_kamicha_discard)
    2020-11-24_03_16_38.log-  File "/app/game/player.py", line 240, in try_to_call_meld
    2020-11-24_03_16_38.log-    return self.ai.try_to_call_meld(tile, is_kamicha_discard)
    2020-11-24_03_16_38.log-  File "/app/game/ai/main.py", line 126, in try_to_call_meld
    2020-11-24_03_16_38.log-    meld, discard_option = self.current_strategy.try_to_call_meld(tile_136, is_kamicha_discard, tiles_136)
    2020-11-24_03_16_38.log-  File "/app/game/ai/strategies/main.py", line 184, in try_to_call_meld
    2020-11-24_03_16_38.log-    chosen_meld_dict = self._find_best_meld_to_open(tile, possible_melds, new_tiles, closed_hand, tile)
    2020-11-24_03_16_38.log-  File "/app/game/ai/strategies/main.py", line 405, in _find_best_meld_to_open
    2020-11-24_03_16_38.log-    selected_tile = self.player.ai.hand_builder.choose_tile_to_discard(after_meld=True)
    2020-11-24_03_16_38.log-  File "/app/game/ai/hand_builder.py", line 47, in choose_tile_to_discard
    2020-11-24_03_16_38.log-    discard_options, threatening_players = self.player.ai.defence.mark_tiles_danger_for_threats(discard_options)
    2020-11-24_03_16_38.log-  File "/app/game/ai/defence/main.py", line 482, in mark_tiles_danger_for_threats
    2020-11-24_03_16_38.log-    discard_options = self.calculate_danger_borders(discard_options, threatening_player, threatening_players)
    2020-11-24_03_16_38.log-  File "/app/game/ai/defence/main.py", line 206, in calculate_danger_borders
    2020-11-24_03_16_38.log-    threatening_player_hand_cost = threatening_player.get_assumed_hand_cost(tile_136)
    2020-11-24_03_16_38.log-  File "/app/game/ai/defence/enemy_analyzer.py", line 161, in get_assumed_hand_cost
    2020-11-24_03_16_38.log-    return self._calculate_assumed_hand_cost_for_riichi(tile_136)
    2020-11-24_03_16_38.log-  File "/app/game/ai/defence/enemy_analyzer.py", line 272, in _calculate_assumed_hand_cost_for_riichi
    2020-11-24_03_16_38.log-    assert live_dora_tiles >= 0, "Live dora tiles can't be less than 0"
    2020-11-24_03_16_38.log-AssertionError: Live dora tiles can't be less than 0
    
    bug battle 
    opened by Nihisil 1
  • Don't consider suji traps when calling riichi on dora (except for 1 or 9 maybe)

    Don't consider suji traps when calling riichi on dora (except for 1 or 9 maybe)

    Боты сейчас активно ричуют в залом, но они не учитывают, что залом на дору фактически не работает. Поэтому для ожиданий на дору в логике кидать риичи или даматенить лучше не учитывать залом вообще, или учитывать его только при риичи на 1 или 9.

    enhancement 
    opened by bogachev-pa 0
  • Additional riichi/damaten rules

    Additional riichi/damaten rules

    Есть еще такая мысль, если противник ричует, то, если даматеним на тайлы, не безопасные против него, то ричуем встречку. Мб кроме случаев, когда ждем в танки на плохой вэйт. Можно будет это продумать.

    idea 
    opened by bogachev-pa 0
Releases(v0.5.1)
  • v0.5.1(Dec 16, 2020)

  • v0.5.0(Nov 29, 2020)

  • v0.4.0(Feb 26, 2019)

    For this version, we did a lot of improvements (162 commits in total) in hand building and meld calling. The bot is building hand very well now and the next step is to build a smart defence mechanism.

    Source code(tar.gz)
    Source code(zip)
  • v0.3.2(Oct 7, 2017)

  • v0.3.1(Sep 30, 2017)

    • Fix players sorting (it is sorting by first position as a second attribute now)
    • Remove " " from log name
    • Tsumogiri tile when it is possible
    • Resurrect statistics sender
    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Sep 25, 2017)

    • Hand calculations code were was to the separate project, so you had to run pip install -r requirements.txt to install this package (https://github.com/MahjongRepository/mahjong)
    • AI structure was refactored and now it is easy to implement your own AI. You can find details here: https://github.com/MahjongRepository/tenhou-python-bot#implement-your-own-ai
    Source code(tar.gz)
    Source code(zip)
  • v0.2.8(Jul 22, 2017)

  • v0.2.7(Jun 22, 2017)

    • Fix an issue with crash after called kan set (#32)
    • Fix wrong scores displaying for player with scores = 0 (#33)
    • Minor fixes in bot logger formatter
    Source code(tar.gz)
    Source code(zip)
  • v0.2.6(Jun 21, 2017)

    • Add round reproducer (check readme for details)
    • Fix an issue with crash after called kan
    • Fix an issue with called meld wrong log messages (#31)
    Source code(tar.gz)
    Source code(zip)
  • v0.2.5(Apr 15, 2017)

    Features:

    • Add logic to call closed kan, chankan and opened kan
    • Handle unexpected errors and store stack trace to the log
    • Try to push riichi (with a good wait) against threatening players
    • Remove analytics code from the project
    • Remove local game runner code from the project

    Bugs fixes:

    • Improve the way to open hand and fix different bugs related to it
    • Fix a bug related to crash when tempai without riichi
    • Improve honitsu discard detection
    • Fix a bug with overwriting safe tile danger value by more dangerous tile
    Source code(tar.gz)
    Source code(zip)
  • v0.2.4(Apr 11, 2017)

    Features:

    • Total refactoring of discards system
    • Minor improvements of rounds reproducer
    • Try to push with expensive (with 3+ doras) 1 shanten hand against threatening players
    • Try to save more valuable tiles in hand even if they have less remaining tiles
    • Try to grab as much yakuhai pons as possible
    • Correctly handle atodzuke opened yakuhai hands
    • Improve defence against multiple honitsu players
    • Improve honitsu discards detection

    Bugs fixes:

    • Don't add chankan to the players melds (because we already added a pon)
    • Fix a bug with wrong hand estimation in defence mode
    • Fix a bug with wrong detection of safe tiles
    • Fix a bug with wrong honitsu detection
    • Exclude aka dora from waiting for hand estimation, because it affected on hand cost
    Source code(tar.gz)
    Source code(zip)
  • v0.2.3(Apr 8, 2017)

    New features:

    • After started game bot will parse game rules (aka dora and open tanyao) and it will change it's play logic based on these rules
    • Discards system were refactored for better support of defence logic. It will consume more resources now, but will give more opportunity to the careful playing
    • Detect enemy's honitsu hands and fold against them
    • Parse and store to a log a message about new achieved rank
    • Add replay reproducer. We need it to be able reproduce round from the tenhou log and debug bot's decisions
    • First try to fold only with 100% safe tiles against multiple players, and if there is no 100% safe tiles try to find common suji tiles to fold
    • Mark dora as a dangerous tile to discard when defence with suji

    Bugs fixes:

    • Fix a bug when bot didn't riichi for with penchan waiting
    • Fix a bug with not counting our bot discards as safe tiles against other players in riichi
    • Fix a bug with wrong is_tempai flag after discarding tiles
    • Fix a crash after called chankan
    • Fix an issue with wrong counting of remaining tiles in the wall
    • Check should bot go to the defence mode just after called riichi, not after first draw. It will affect open hand suggestions
    Source code(tar.gz)
    Source code(zip)
  • v0.2.2(Mar 21, 2017)

    • Improve defence strategy with Kabe technique
    • Improve defence strategy with Suji technique
    • Remove beautifulsoup4 dependency. It should speed up a bot a little bit
    • Various minor fixes in local games runner
    • Fix an issue with bot discards and revealed tiles cache
    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(Mar 17, 2017)

    Bot AI improvements:

    • In defence mode try to discard not needed safe tiles first
    • If there is no not needed tiles, try to discard safe tiles that will do less harm to the hand state
    • Don't call a riichi for a pair wait (except chitoitsu). This wait can be easily improved

    Local games improvements:

    • Don't allow to call ron when furiten
    • Support multiple ron for local games
    • Support abortive retakes for local games
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Mar 16, 2017)

    • Store information about was tile discarded from hand or it was tsumogiri. It will be helpful for future discard analyzation
    • Implement simple defence mode. Discard gembutsu tiles after other player riichi if our hand is cheap or not ready
    • Heavy refactoring of Client, Table and Player classes. It will allow to build next features with less efforts :)
    Source code(tar.gz)
    Source code(zip)
  • v0.1.1(Mar 8, 2017)

    • Add the mode to detect game type dynamically based on bot rank and rate
    • Fix and issue with socket initialization and resources loading
    • Handle KeyboardInterrupt exception on Ctrl + C
    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Mar 6, 2017)

    • Was added basic support for open hands. Bot will open hand if it will improve hand shanten number. And it has different open hand strategies: Tanyao, Honitsu, Yakuhai.
    • Each discard tile has "value" from now. For example dora would be more valuable, than usual tile, or 5 is more valuable than 1. Bot will try to discard not valuable tiles first.
    • For "remaining tiles" we will not count discarded tiles or tiles from open sets. So, bot will try to avoid "dead" waits.
    • Local game runner was significantly improved. It supports more mahjong aspects and allows to save local games in tenhou.net log format. So, you can view it with standard tenhou log viewer.
    • Add analytics package. It contains scripts to download phoenix replays and load them to the memory. Later I will analyze phoenix replays for different mahjong situations (like suji traps and etc.)
    Source code(tar.gz)
    Source code(zip)
  • v0.0.5(Jun 29, 2016)

  • v0.0.4(Jun 24, 2016)

  • v0.0.3(Jun 21, 2016)

    • Allow to set settings from command arguments. Use python main.py -h for details
    • Support login to the lobby
    • Support is_tournament mode. In this mode bot will connect to the lobby and will wait while game is started.
    Source code(tar.gz)
    Source code(zip)
  • v0.0.2(May 23, 2016)

  • v0.0.1(May 23, 2016)

    Bot can only collects tiles and calls riichi. It doesn't know about dora, yaku or defence, but all main features for playing on tenhou.net were implemented. In the next release I will improve bot strategy.

    Source code(tar.gz)
    Source code(zip)
Collect links to profiles by username through search engines

Marple Summary Collect links to profiles by username through search engines (currently Google and DuckDuckGo). Quick Start ./marple.py soxoj Results:

125 Dec 19, 2022
Listen to the radio station from your favorite broadcast

Latest news Listen to the radio station from your favorite broadcast MyCroft Radio Skill for testing and copy at docker skill About Play regional radi

1 Dec 22, 2021
Async boto3 with Autogenerated Data Classes

awspydk Async boto3 with Autogenerated JIT Data Classes Motivation This library is forked from an internal project that works with a lot of backend AW

1 Dec 05, 2021
An attempt to escape the horrible JIRA editor.

An attempt to escape the horrible JIRA editor. jira_filter.py is a pandoc filter that cleans up some of JIRA's html so that it can be converted to Mar

Stefan Matting 2 Feb 10, 2022
A simple library for interacting with Amazon SQS.

qoo is a very simple Amazon SQS client, written in Python. It aims to be much more straight-forward to use than boto3, and specializes only in Amazon

Jacobi Petrucciani 2 Oct 30, 2020
A powerfull Telegram Leech Bot

owner of this repo :- Abijthkutty contact me :- Abijth Telegram Torrent and Direct links Leecher Dont Abuse The Repo ... this is intented to run in Sm

αвιנтн 9 Jun 11, 2022
Drcom-pt-client - Drcom Pt version client with refresh timer

drcom-pt-client Drcom Pt version client with refresh timer Dr.com Pt版本客户端 可用于网页认

4 Nov 16, 2022
A superb Telegram VoiceChat Player. Powered by FalconRoBo.

𝕱𝖆𝖑𝖈𝖔𝖓𝕸𝖚𝖘𝖎𝖈 A sᴜᴘᴇʀʙ Tᴇʟᴇɢʀᴀᴍ VᴏɪᴄᴇCʜᴀᴛ Pʟᴀʏᴇʀ, ᴍᴀᴅᴇ ᴜsɪɴɢ Lᴀᴛᴇsᴛ Pʏᴛʜᴏɴ ᴀɴᴅ Pʏʀᴏɢʀᴀᴍ. 𝑷𝒐𝒘𝒆𝒓𝒆𝒅 𝒃𝒚 𝑭𝒂𝒍𝒄𝒐𝒏𝑹𝒐𝑩𝒐 FalconMusic

FalconRoBo 2 Oct 21, 2022
Python functions to run WASS stereo wave processing executables, and load and post process WASS output files.

wass-pyfuns Python functions to run the WASS stereo wave processing executables, and load and post process the WASS output files. General WASS (Waves

Mika Malila 3 May 13, 2022
Scheduled Block Checker for Cardano Stakepool Operators

ScheduledBlocks Scheduled Block Checker for Cardano Stakepool Operators Lightweight and Portable Scheduled Blocks Checker for Current Epoch. No cardan

SNAKE (Cardano Stakepool) 4 Oct 18, 2022
A little proxy tool based on Tencent Cloud Function Service.

SCFProxy 一个基于腾讯云函数服务的免费代理池。 安装 python3 -m venv .venv source .venv/bin/activate pip3 install -r requirements.txt 项目配置 函数配置 开通腾讯云函数服务 在 函数服务 新建 中使用自定义

Mio 716 Dec 26, 2022
Auto file forward bot with python

Auto-File-Forward-Bot Auto file forward bot. Without Admin Permission in FROM_CHANNEL Only Give Permission In your Telegram Personal Channel Please fo

Milas 1 Oct 15, 2021
Marketplace for self published books

Nile API API for the imaginary Nile marketplace for self published books. This is a project created to try out FastAPI as the post promising ASGI serv

Matt de Young 1 Jan 31, 2022
Backend for Indipe client

Betsushi Betsu (別), the japanese word meaning "another" and Shiharai (支払い) meaning "payment". Hence the name Betsushi was derived. Introduction This i

Sudodevs 3 Feb 09, 2022
Use Node JS Keywords In Python!!!

Use Node JS Keywords In Python!!!

Sancho Godinho 1 Oct 23, 2021
🤖 The bot that runs the official Fairfield Programming Association Discord server.

🤖 The bot that runs the official Fairfield Programming Association Discord server.

Fairfield Programming Association 1 Jan 07, 2022
This is a python bot that automatically logs in, clicks the new button, and sends heroes to work in the bombcrypto game

This is a python bot that automatically logs in, clicks the new button, and sends heroes to work in the bombcrypto game. It is fully open source and free.

856 Jan 04, 2023
Attempting to create a framework for Discord Slash commands... yes

discord_slash.py Attempting to create a framework for Discord Slash commands... yes Installation pip install slashpy Documentation Coming soon™ Why is

AlexFlipnote 11 Mar 24, 2021
🎥 Stream your favorite movie from the terminal!

Stream-Cli stream-cli is a Python scrapping CLI that combine scrapy and webtorrent in one command for streaming movies from your terminal. Installatio

R E D O N E 379 Dec 24, 2022
Autodrive is designed to make it as easy as possible to interact with the Google Drive and Sheets APIs via Python

Autodrive Autodrive is designed to make it as easy as possible to interact with the Google Drive and Sheets APIs via Python. It is especially designed

Chris Larabee 1 Oct 02, 2021