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)
Simple script to extract useful informations from the combo BloodHound + Neo4j

bloodhound-quickwin Simple script to extract useful informations from the combo BloodHound + Neo4j. Can help to choose a target. Prerequisites python3

140 Dec 21, 2022
Scanner and Checker for Binance Scam Contracts

Money Printer by Warranty Voider well this isnt exactly a printer, but it helps you find and check new token startups. In the end its a nice scam cont

12 Nov 24, 2022
A Simple Telegram Inline Torrent Search Bot by @infotechIT

Torrent-Search-RoBot A Simple Telegram Inline Torrent Search Bot by @infotechIT. Torrent API Using api.infotech.wtf API Host Bot Deploy to Heroku Clic

InfoTech 0 May 05, 2022
Group Chat Spammer For Discord

Group Chat Spammer For Discord Free and public gc spammer

Dreamy 20 Dec 27, 2022
A python api to get info on covid-19

A python api to get info on covid-19

roof 2 Sep 18, 2022
A tool written in Python used to instalock agents in VALORANT using the local API.

Valorant Instalock Tool v2.1.0 by Mr. SOSA A tool written in Python used to instalock agents in VALORANT using the local API. This is NOT a hotkey pro

Mr. SOSA 3 Nov 18, 2021
A simple API Wrapper for Guilded.

Guildr A simple API Wrapper for Guilded. Frequently updated! I am not a user of Guilded, meaning I do not keep track of new Guilded updates or patches

2 Mar 07, 2022
A Python wrapper around the Twitter API.

Python Twitter A Python wrapper around the Twitter API. By the Python-Twitter Developers Introduction This library provides a pure Python interface fo

Mike Taylor 3.4k Jan 01, 2023
Asynchronous Python Wrapper for the Ufile API

Ufile.io Asynchronous Python Wrapper for the Ufile API (Unofficial).

Gautam Kumar 16 Aug 31, 2022
Python interface to the LinkedIn API

Python LinkedIn Python interface to the LinkedIn API This library provides a pure Python interface to the LinkedIn Profile, Group, Company, Jobs, Sear

ozgur 844 Dec 27, 2022
Lumberjack-bot - A game bot written for Lumberjack game at Telegram platform

This is a game bot written for Lumberjack game at Telegram platform. It is devel

Uğur Uysal 6 Apr 07, 2022
API which returns cusswords , can be used to check cusswords in bots etc.

Anti-abuse-api-flask API which returns cusswords , can be used to check cusswords in bots etc. Run pip install -r requirements.txt py app.py API Endpo

8 Jan 03, 2023
Biblioteca Python que extrai dados de mercado do Bacen (Séries Temporais)

Pybacen This library was developed for economic analysis in the Brazilian scenario (Investments, micro and macroeconomic indicators) Installation Inst

42 Jan 05, 2023
Leveraged grid-trading bot using CCXT/CCXT Pro library in FTX exchange.

Leveraged-grid-trading-bot The code is designed to perform infinity grid trading strategy in FTX exchange. The basic trader named Gridtrader.py contro

Hao-Liang Wen 25 Oct 07, 2021
Widevine CDM API

wvproxy Widevine CDM API Setup Install Python 3.6 or newer and Poetry Install Python package dependencies using poetry install Activate the virtual en

24 Dec 09, 2022
Reddit cli to slack at work

Reddit CLI (v1.0) Introduction Why Reddit CLI? Coworker who sees me looking at something in a browser: "Glad you're not busy; I need you to do this, t

3 Jun 22, 2021
Telegram PHub Bot using ARQ Api and Pyrogram. This Bot can Download and Send PHub HQ videos in Telegram using ARQ API.

Tg_PHub_Bot Telegram PHub Bot using ARQ Api and Pyrogram. This Bot can Download and Send PHub HQ videos in Telegram using ARQ API. OS Support All linu

TheProgrammerCat 13 Oct 21, 2022
Requests based multi-threaded script for increasing followers on Spotify

Proxyless Spotify Follow Bot Requests based multi-threaded script for increasing followers on Spotify. Click here to report bugs. Usage Download ZIP h

397 Jan 03, 2023
OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)

OpenAPI Generator Master (5.3.1): 5.4.x (5.4.x): 6.0.x (6.0.x): ⭐ ⭐ ⭐ If you would like to contribute, please refer to guidelines and a list of open t

OpenAPI Tools 14.8k Jan 04, 2023
Cleaning Tiktok Hacks With Python

Cleaning Tiktok Hacks With Python

13 Jan 06, 2023