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)
A simple Python library to integrate with the Heron Data API

Heron Python This library provides easy access to the Heron Data API from applications written in Python. Documentation No language-specific docs are

Heron Data 11 Nov 11, 2022
A beginner’s guide to train and deploy machine learning pipelines in Python using PyCaret

This model involves Insurance bill prediction, which was subsequently deployed on Heroku PaaS

1 Jan 27, 2022
Simple script to ban bots at Twitch chats using a text file as a source.

AUTOBAN 🇺🇸 English version Simple script to ban bots at Twitch chats using a text file as a source. How to use Windows Go to releases for further in

And Paiva 5 Feb 06, 2022
Manage AWS Secrets the easy way

AWStanding Easily load variables from AWS Parameter store into environment variables. Why to AWStanding? Because it handles AWS pagination so the amou

Juan Ignacio Sánchez Sampayo 13 Dec 30, 2022
Мои личные наработки по новому API Тинькофф. Не официально.

TinkoffNewAPI Мои личные наработки по новому API Тинькофф. Не официально. Официально по ссылке: https://github.com/Tinkoff/investAPI/ Выложено по прос

1 Jan 20, 2022
Fetching tweets and integrating it with Kafka and PySpark

KafkaPySpark Zookeeper bin/zookeeper-server-start.sh config/zookeeper.properties Kafka Server bin/kafka-server-start.sh config/server.properties Kafka

Priyansh 2 Dec 29, 2021
A python tool to Automate Whatsapp through Whatsapp web

This python tool is used to Automate Whatsapp through Whatsapp web. We can add number of contacts whom we want to send text messages on perticular time

5 Jul 21, 2022
Algofi Python SDK is useful for developers who want to programatically interact with the Algofi lending protocol

algofi-py-sdk Algofi Python SDK Documentation https://algofi-py-sdk.readthedocs.

Algofi 41 Dec 15, 2022
Black-hat with python

black-hat_python Advantages - More advance tool Easy to use allows updating tool update - run bash update.sh Here -: Command to install tool main- clo

Hackers Tech 2 Feb 10, 2022
A cs:go cheat/hack made in Python3.

Atomic 💖 Cheat for cs:go written in Python. Features. Glow Esp No Flash Bunny Hop Third Person To-Do. It is prefered to start the cheat when you are

Sofia 6 Feb 12, 2022
A Twitter bot written in Python using Tweepy and hosted on a server.

A Twitter bot written in Python using Tweepy. It can like and/or retweet tweets that contain single or multiple keywords and hashtags.

anniedotexe 11 Dec 15, 2022
Discord Account Generator that will create Account with hCaptcha bypass. Using socks4 proxies

Account-Generator [!] This was made for education. Please use socks4 proxies for nice experiences. [!] Please install these modules - "pip3 install ht

RyanzSantos 10 Feb 23, 2022
Sample code helps get you started with a simple Python web service using AWS Lambda and Amazon API Gateway

Welcome to the AWS CodeStar sample web service This sample code helps get you started with a simple Python web service using AWS Lambda and Amazon API

0 Jan 20, 2022
A customizable, multilanguage Telegram shop bot with Telegram Payments support

Greed A customizable, multilanguage Telegram shop bot with Telegram Payments support! Demo Send a message to @greedtestbot on Telegram to view a demo

Stefano Pigozzi 328 Dec 29, 2022
A corona statistics and information telegram bot.

A corona statistics and information telegram bot.

Fayas Noushad 15 Oct 21, 2022
𝐀 𝐦𝐨𝐝𝐮𝐥𝐚𝐫 𝐓𝐞𝐥𝐞𝐠𝐫𝐚𝐦 𝐆𝐫𝐨𝐮𝐩 𝐦𝐚𝐧𝐚𝐠𝐞𝐦𝐞𝐧𝐭 𝐛𝐨𝐭 𝐰𝐢𝐭𝐡 𝐮𝐥𝐭𝐢𝐦𝐚𝐭𝐞 𝐟𝐞𝐚𝐭𝐮𝐫𝐞𝐬 !!

𝐇𝐨𝐰 𝐓𝐨 𝐃𝐞𝐩𝐥𝐨𝐲 For easiest way to deploy this Bot click on the below button 𝐌𝐚𝐝𝐞 𝐁𝐲 𝐒𝐮𝐩𝐩𝐨𝐫𝐭 𝐆𝐫𝐨𝐮𝐩 𝐒𝐨𝐮𝐫𝐜𝐞𝐬 𝐆𝐞𝐧𝐞?

Mukesh Solanki 4 Oct 18, 2021
CloudFormation Drift Remediation - Use Cloud Control API to remediate drift that was detected on a CloudFormation stack

CloudFormation Drift Remediation - Use Cloud Control API to remediate drift that was detected on a CloudFormation stack

Cloudar 36 Dec 11, 2022
Python based Algo trading bot for Nifty / Banknifty futures and options

Fully automated Alice Blue Algo Trading with Python on NSE and MCX for Nifty / Crude / Banknifty futures and options , absolutely FREE ! This algo tra

Rajesh Sivadasan 49 Dec 31, 2022
A python package to easy the integration with Direct Online Pay (Mpesa, TigoPesa, AirtelMoney, Card Payments)

A python package to easy the integration with Direct Online Pay (DPO) which easily allow you easily integrate with payment options once without having to deal with each of them individually;

Jordan Kalebu 2 Nov 25, 2021
Opensea-upload-with-recaptcha-solution - Updated opensea uploading solution with recaptcha pass

opensea-upload-with-recaptcha-solution updated opensea uploading solution with r

byeonggeon sim 25 Nov 15, 2022