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 web app via which users can buy and sell stocks using virtual money

finance Virtual Stock Trader. A web app via which users can buy and sell stocks using virtual money. All stock prices are real and provided by IEX. Fe

Kiron Deb 0 Jan 15, 2022
AWS EC2 S3 Automated With python

AWS_EC2_S3_Automated Description This programme is a Python3 script that utilizes Boto3 to automate the process of creating an AWS EC2 instance with a

niall_crowe 2 Nov 16, 2021
Feedback-TelegramBot is a resemblance bot which can be deployed on server

Feedback-TelegramBot Feedback-TelegramBot is a resemblance bot which can be deployed on server This work is based on Telegram library, thanks to their

2 Jan 03, 2022
Telegram-Discord Bridge

imperial-toilet Скрипт, пересылающий сообщения из нескольких каналов Telegram в один/несколько каналов Discord. Технически это Telegram-юзербот и Disc

1 Jan 17, 2022
Home Assistant custom integration for controlling Powered by Tuya (PBT) devices using Tuya Open API, officially maintained by the Tuya Developer Team.

Tuya Home Assistant Integration Home Assistant custom integration for controlling Powered by Tuya (PBT) devices using Tuya Open API, officially mainta

Tuya 704 Jan 03, 2023
Python based league of legends orbwalker

League of Legends Orbwalker Usage Install python3 Create a python3 venv Install the requirements pip install -r requirements.txt Get in game and run m

Inusha 43 Dec 12, 2022
Automate TikTok follower bot, like bot, share bot, view bot and more using selenium

Zefoy TikTok Automator Automate TikTok follower bot, like bot, share bot, view bot and more using selenium. Click here to report bugs. Usage Download

555 Dec 30, 2022
数字货币BTC量化交易系统-实盘行情服务器,虚拟币自动炒币-火币API-币安交易所-量化交易-网格策略。趋势跟踪策略,最简源码,可在线回测,一键部署,可定制的比特币量化交易框架,3年实盘检验!

huobi_intf 提供火币网的实时行情服务器(支持火币网所有交易对的实时行情),自带API缓存,可用于实盘交易和模拟回测。 行情数据,是一切量化交易的基础,可以获取1min、60min、4hour、1day等数据。数据能进行缓存,可以在多个币种,多个时间段查询的时候,查询速度依然很快。 服务框架

dev 258 Sep 20, 2021
NFTs Upload to OpenSea CuseEdition

NFTs-Upload-to-OpenSea-CuseEdition YOUTUBE VIDEO - Soon... Download Python and

Lil Cuse 2 Jan 04, 2022
SpamBot.py allows you, to spam other Chat Partners etc.

SpamBot -SpamBot.py allows you, to spam other Chat Partners etc. Install If you downloaded it yet, you have to install "requirements.txt" write the di

Marco 1 Jan 16, 2022
Messing around with GitHub API to look at omicron build times

gh-workflow-runs This is a very simple tool to dump out basic information about workflow runs for a GitHub repo. The structure is based on gh-subscrip

David Pacheco 1 Nov 30, 2021
a public repository helping ML/DL engineers and DS to beautify the notebook with minimal coding.

ml-helper-functions a public repository helping ML/DL engineers and DS to beautify the notebook with minimal coding.

Jesal Patel 4 Jun 24, 2021
Posts locally saved videos to the desired subreddit

redditvideoposter posts locally saved videos to the desired subreddit ================================================================= STEPS: pip ins

Kyrus 2 Dec 01, 2021
Simple stock price analytics

mune · Mune is an open source python web application built to analyze stocks, named after Homma Munehisa. Currently, the forecasting component is powe

Richard Hong 14 Aug 30, 2021
A small python script which runs a speedtest using speedtest.net and inserts it into a Google Docs Spreadsheet.

speedtest-google-sheets This is a small python script which runs a speedtest using speedtest.net and inserts it into a Google Docs Spreadsheet. Setup

marie 2 Feb 10, 2022
pymobiledevice fork with more recent coding standards and many more features

Description Features Installation Usage Sending your own messages Lockdown messages Instruments messages Example Lockdown services com.apple.instrumen

255 Dec 28, 2022
An example Music Bot written in Disnake and uses slash commands to operate.

Music Bot An example music bot that is written in Disnake [Maintained discord.py Fork] Disnake Disnake is a maintained and updated fork of discord.py.

6 Jan 08, 2022
Um script simples para consultar dados, com API's simples.

Info sobre o Script Esta é uma das mais simples ferramentas para consultar dados. Daqui um tempo eu farei um UPGRADE no painel, irei adicionar um banc

Crowley 6 Apr 11, 2022
A course on getting started with the Twitter API v2 for academic research

Getting started with the Twitter API v2 for academic research Welcome to this '101 course' on getting started with academic research using the Twitter

@TwitterDev 426 Jan 04, 2023
A Advanced Auto Filter Bot Which Can Be Used In Many Groups With Multiple Channel Support....

Adv Auto Filter Bot This Just A Simple Hand Auto Filter Bot For Searching Files From Channel... Just Sent Any Text I Will Search In All Connected Chat

Albert Einstein 33 Oct 21, 2022