GithubHelp home page GithubHelp logo

gunyarakun / python-shogi Goto Github PK

View Code? Open in Web Editor NEW
175.0 13.0 42.0 220 KB

A pure Python shogi library with move generation and validation and handling of common formats.

License: GNU General Public License v3.0

Python 99.75% Makefile 0.20% Shell 0.05%

python-shogi's Introduction

python-shogi: a pure Python shogi library

Introduction

This is the module for shogi written in Pure Python. It's based on python-chess commit

This is the scholars mate in python-shogi:

>>> import shogi

>>> board = shogi.Board()

>>> board.push(shogi.Move.from_usi('7g7f'))

>>> board.push_usi('3c3d')
Move.from_usi('3c3d')
>>> board.push_usi('8h2b+')
Move.from_usi('8h2b+')
>>> board.push_usi('4a5b')
Move.from_usi('4a5b')
>>> board.push_usi('B*4b')
Move.from_usi('B*4b')
>>> board.push_usi('5a4a')
Move.from_usi('5a4a')
>>> board.push_usi('2b3a')
Move.from_usi('2b3a')
>>> board.is_checkmate()
True

Features

  • Supports Python 3.3+.

  • Supports standard shogi (hon shogi)

  • Legal move generator and move validation.

    >>> shogi.Move.from_usi("5i5a") in board.legal_moves
    False
  • Make and unmake moves.

    >>> last_move = board.pop() # Unmake last move
    >>> last_move
    Move.from_usi('2b3a')
    
    >>> board.push(last_move) # Restore
  • Show a simple ASCII board.

    >>> print(board)
     l  n  s  g  .  k +B  n  l
     .  r  .  .  g  B  .  .  .
     p  p  p  p  p  p  .  p  p
     .  .  .  .  .  .  p  .  .
     .  .  .  .  .  .  .  .  .
     .  .  P  .  .  .  .  .  .
     P  P  .  P  P  P  P  P  P
     .  .  .  .  .  .  .  R  .
     L  N  S  G  K  G  S  N  L
    <BLANKLINE>
     S*1
  • Show a KIF style board.

    >>> print(board.kif_str())
    後手の持駒:
      9 8 7 6 5 4 3 2 1
    +---------------------------+
    |v香v桂v銀v金v玉 馬v桂v香|
    |v飛 ・ ・v金  ・ ・ ・|
    |v歩v歩v歩v歩v歩v歩v歩v歩|
    | ・ ・ ・ ・ ・ ・v歩 ・ ・|
    | ・ ・ ・ ・ ・ ・ ・ ・ ・|
    | ・ ・  ・ ・ ・ ・ ・ ・|
    |       |
    | ・ ・ ・ ・ ・ ・ ・ |
    |         |
    +---------------------------+
    先手の持駒: 
  • Detects checkmates, stalemates.

    >>> board.is_stalemate()
    False
    >>> board.is_game_over()
    True
  • Detects repetitions. Has a half move clock.

    >>> board.is_fourfold_repetition()
    False
    >>> board.move_number
    8
  • Detects checks and attacks.

    >>> board.is_check()
    True
    >>> board.is_attacked_by(shogi.BLACK, shogi.A4)
    True
    >>> attackers = board.attackers(shogi.BLACK, shogi.H5)
    >>> attackers
    SquareSet(0b111000010000000000000000000000000000000000000000000000000000000000000000000000)
    >>> shogi.H2 in attackers
    True
    >>> print(attackers)
    . . . . . . . . .
    . . . . . . . . .
    . . . . . . . . .
    . . . . . . . . .
    . . . . . . . . .
    . . . . . . . . .
    . . . . . . . . .
    . . . . . . . 1 .
    . . . 1 1 1 . . .
  • Parses and creates USI representation of moves.

    >>> board = shogi.Board()
    >>> shogi.Move(shogi.E2, shogi.E4).usi()
    '2e4e'
  • Parses and creates SFENs

    >>> board.sfen()
    'lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1'
    >>> board.piece_at(shogi.I5)
    Piece.from_symbol('K')
  • Read KIFs.

    >>> import shogi.KIF
    
    >>> kif = shogi.KIF.Parser.parse_file('data/games/habu-fujii-2006.kif')[0]
    
    >>> kif['names'][shogi.BLACK]
    '羽生善治'
    >>> kif['names'][shogi.WHITE]
    '藤井猛'
    >>> kif['moves'] # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
    ['7g7f',
     '3c3d',
     ...,
     '9a9b',
     '7a7b+']
    >>> kif['win']
    'b'
  • Export to KIFs.

    >>> import shogi
    >>> import shogi.KIF
    
    >>> board = shogi.Board()
    >>> shogi.KIF.Exporter.kif_move_from('7g7f', board)
    '7六歩(77)'
    
    >>> sfen_summary = {'moves': ['7g7f', '3c3d'], 'sfen': 'lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1', 'names': ['羽生善治', '藤井猛'], 'win': 'w'}
    >>> shogi.KIF.Exporter.kif(sfen_summary)
    開始日時: \r
    終了日時: \r
    手合割平手\r
    先手羽生善治\r
    後手藤井猛\r
    手数----指手---------消費時間-- \r
    1六歩(77) \r
    2四歩(33) \r
    3 投了 \r
    まで2手で後手の勝ち\r
  • Communicate with a CSA protocol.

    Please see random_csa_tcp_match.

  • Parse professional shogi players' name

    >>> import shogi.Person
    >>> shogi.Person.Name.is_professional('羽生 善治 名人・棋聖・王位・王座')
    True

Performance

python-shogi is not intended to be used by serious shogi engines where performance is critical. The goal is rather to create a simple and relatively highlevel library.

You can install the gmpy2 or gmpy modules in order to get a slight performance boost on basic operations like bit scans and population counts.

python-shogi will only ever import very basic general (non-shogi-related) operations from native libraries. All logic is pure Python. There will always be pure Python fallbacks.

Installing

  • With pip:

    pip install python-shogi
    

How to test

> make test

If you want to print lines from the standard output, execute nosetests like following.

> poetry run nosetests -s

How to release

poetry config repositories.testpypi https://test.pypi.org/legacy/
# poetry config pypi-token.testpypi "Test PyPI API Token"
make test-upload
# poetry config pypi-token.pypi "PyPI API Token"
make upload

ToDo

  • Support board.generate_attacks() and use it in board.is_attacked_by() and board.attacker_mask().
  • Remove rotated bitboards and support Shatranj-style direct lookup like recent python-chess.
  • Support %MATTA etc. in CSA TCP Protocol.
  • Support board.is_pinned() and board.pin().

python-shogi's People

Contributors

bleu48 avatar ddugovic avatar deranderejohannes avatar enriqueav avatar gunyarakun avatar hmatsuya avatar ianfab avatar ishidakei avatar kz23szk avatar mineowl avatar sokah2412 avatar srimethan avatar st34-satoshi avatar tadaoyamaoka avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-shogi's Issues

KIF parsing of non-promotion 不成

I encountered a kifu where a silver move refraining from promotion seems to explicitly contain this information using the suffix 不成.

100 7七銀不成(68) (00:00/00:00:00)

As a quick workaround I simply normalize this suffix away. If you consider this a sufficient fix I can also raise a PR, otherwise I guess you might want to adjust the regex for parsing.

Escaped unicode string is hard to read

At first, I thought raw unicode characters must be removed from this module.

  • It can be assumed that almost all players can read Kanji characters used in shogi
  • It's hard for me to maintain the code
  • They got used to handling UTF-8 text now

So I think all the unicode escaped character are decoded into raw UTF-8 string.

Conda Support

Would it be possible to add Conda support to python-shogi? Conda is used by many data scientists, as opposed to pypi, so having this library on Conda would be helpful to many. Also any other package that depends on python-shogi would need this on Conda in order for full Conda support. The distribution process for Conda would be fairly simple, as the only two commands required are

conda skeleton pypi python-shogi

and

conda-build python-shogi

指し手生成にバグ?

偶然見つけたのですが,以下の後手番の局面のときに8筋に歩を打つ手を不正とみなすようです。

最小バグ生成コード

board = shogi.Board('lr7/3skgg1+B/2n2s1pp/p1p1ppP2/3p1np2/1PPPP4/PS1G1P2P/2GS3R1/LNK4NL w L2pb 58')

moves = []
for move in board.legal_moves:
moves.append(move.usi())

print(board.kif_str())
print(moves)

Revive doctest

Originally, README.rst is tested by doctest, but currently not.

消費時間情報のついているKIF形式のパース

手数----指手---------消費時間--
1 7六歩(77) ( 1:00/00:01:00)
このように将棋時間がついているとKIF形式ファイルのパースがうまくいかないようです。
KIF.pyにあるMOVE_RE変数の正規表現から\Zを削除すれば取りあえずはパースできるようです。

KIF parser encoding

Hello,

I'm using your kif parser for a personal project, and I saw that you read in different encodings, depending the kifu extension (e.g. if the kifu ends with .kif, it will be read in cp932 and if it ends with .kifu, it will be read in utf-8). Is there a reason to not read every kifu file in utf-8? And why choose cp932 for .kif ? I find it a little bit annoying because 81dojo export kifus in utf-8, with .kif extension, so the parser crash on them. This can be fix just by renaming the file in xxxxx.kifu (and by changing the MOVE_RE regex a little bit, as proposed in a PR).

Thank you very much :)

KIF import - ignores given board state

I'd been considering using python-shogi to automate the task of converting a few thousand tsumeshogi problems (in KIF) format to SFEN for use elsewhere (namely an Anki plugin). Each tsumeshogi problem consists of a kifu with the initial state of the problem, and the main solution line(s), though I'm currently ignoring the (much harder) problem of automatically extracting the solutions.

It seems there are some issues with my idea. After some initial problems with KIF import (renaming them to .kifu seems to have solved that issue), I find that no matter which kifu I import, via something like:

>>> import shogi.KIF
>>> kif=shogi.KIF.Parser.parse_file('010001.kifu')[0]
>>> kif['sfen']
'lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1'

I always get an SFEN corresponding to the initial game state, not of the tsumeshogi problem at all!

I asked around and so far it looks as if the following line (and the logic behind it) are responsible:

sfen = shogi.STARTING_SFEN

Essentially, it seems that python-shogi has a hardcoded assumption that a kifu will be a "full game record" and thus always initialises the board in a "game start" state, not the state explicitly given in the kifu.

Is this understanding correct; and either way, is it possible for this to be handled properly in a future release?

Content of my .kifu file:

# ----  Kifu for Windows V4.01β 棋譜ファイル  ----
# ファイル名:D:\b\temp\M2TOK141\KIFU\1t120600-1.kif
棋戦:1手詰
戦型:なし
手合割:平手  
後手の持駒:飛 角 金四 銀三 桂四 香三 歩十七 
  9 8 7 6 5 4 3 2 1
+---------------------------+
| ・ ・ ・ ・ ・ ・ ・ ・v香|一
| ・ ・ ・ ・ 飛 馬 ・ ・v玉|二
| ・ ・ ・ ・ ・ ・ ・v歩 ・|三
| ・ ・ ・ ・ ・ ・v銀 ・ ・|四
| ・ ・ ・ ・ ・ ・ ・ ・ ・|五
| ・ ・ ・ ・ ・ ・ ・ ・ ・|六
| ・ ・ ・ ・ ・ ・ ・ ・ ・|七
| ・ ・ ・ ・ ・ ・ ・ ・ ・|八
| ・ ・ ・ ・ ・ ・ ・ ・ ・|九
+---------------------------+
先手の持駒:なし
先手:大内延介
後手:最新詰将棋200選
手数----指手---------消費時間--
*作者:大内延介
*発表誌:最新詰将棋200選
   1 3一馬(42)   ( 0:00/00:00:00)
   2 中断         ( 0:00/00:00:00)
まで1手で中断

CSA parser does not support "PI" command

  File "C:\Python38\lib\site-packages\shogi\CSA.py", line 127, in parse_str
    position = Parser.parse_position(position_lines)
  File "C:\Python38\lib\site-packages\shogi\CSA.py", line 231, in parse_position
    raise ValueError('Invalid rank/piece in hand: {0}'.format(line))
ValueError: Invalid rank/piece in hand: PI

examples of files that can cause problems:
http://www2.computer-shogi.org/kifu/wcso1_kifu.zip

CSA file format spec:

http://www2.computer-shogi.org/protocol/record_v22.html

2.5 開始局面

"P"で始まる文字列(以前に決めたもの)。
(1) 平手初期配置と駒落ち
平手初期配置は、"PI"とする。駒落ちは、"PI"に続き、落とす駒の位置と種類を必要なだけ記述する。
例:二枚落ちPI82HI22KA

Board.legal_moves contains illegal moves using bishop

When programming a shogi AI, I found that board.legal_moves sometimes contains illegal moves.

This case may be because I create a board from a sfen.

The piece played in illegal moves seems to always be a bishop from my experience.

Here is an example :

import shogi
board = shogi.Board('3k4p/lg2sB1rl/npp1p1s2/p2pNpppg/P1P6/1PGPP1PRL/L8/3SG2S1/1NB1K2N1 b 3p 80')
for m in board.legal_moves :
    print(m)
print(board)

The silver on 3c is blocking the bishop's diagonal but B(4b)2d+ and B(4b)2d are listed as legal moves.

result :

9e9d
7e7d
8f8e
6f6e
5f5e
3f3e
1f1d
1f1e
9g9f
5d6b+
8i7g
2i3g
2i1g
6h7g
6h6g
6h5g
2h3g
2h2g
2h1g
2h3i
2h1i
7f8e
7f6e
7f7g
5h6g
5h5g
5h4g
5h4h
4b5a
4b5a+
4b3a
4b3a+
4b5c
4b5c+
4b3c
4b3c+
4b2d
4b2d+
4b1e
4b1e+
7i8h
2f2d
2f2e
2f2g
5i4h
5i6i
5i4i
. . . k . . . . p
l g . . s B . r l
n p p . p . s . .
p . . p N p p p g
P . P . . . . . .
. P G P P . P R L
L . . . . . . . .
. . . S G . . S .
. N B . K . . N .

p*3

edit : formatting + detailling

Null move の bool判定がTrueになる

Null moveを
return cls(0, 0, NONE)
で作っているので、
from_square とto_square が両方とも0になると思います。

そうすると、

    def __bool__(self):
        return self.to_square is not None

が、Falseにならないと思うのですが、いかがでしょうか?

この影響で、
board.push(shogi.Move.null())
としたときに、手番の変更だけでなく、9aの駒を9aの駒で取るような動作になってしまいます。

合法手の判定について

こんにちは。
合法手の判定の仕方でちょっとわからないことがあったので教えてください。
sfen文字列で局面を読み込んで、指し手を入力してみたところ、どうしても合法手の判定になりません。
sfenは lnsg1g1nl/3k3r1/pppp1s1pp/b3p1p2/2PP1p2B/P3P3P/1P3PPP1/1S3K1R1/LN1G1GSNL w - 1 で9dの地点の角が6gの地点に移動しようとすると、falseが返ってきます。王手ではないようですし、何が原因なのかわかりません。
よろしくお願いします。

board = shogi.Board("lnsg1g1nl/3k3r1/pppp1s1pp/b3p1p2/2PP1p2B/P3P3P/1P3PPP1/1S3K1R1/LN1G1GSNL w - 1")
s = shogi.Move.from_usi("9d6g") in board.legal_moves;
print(s)
False

Move.__hash__() の計算エラー

  move = shogi.Move.from_usi("9a9b")
  print move.__hash__()

で、以下のエラーが出ます。

TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'

恐らく、

    def __hash__(self):
        # 7 bit is enought to represent 81 patterns
        return self.to_square | (self.from_square or (81 + self.drop_piece_type)) << 7 | self.promotion << 14

の、self.from_square が0になっているためだと思うのですが、確認していただけますか?

Support USI protocol

In the To Do list there is this item "Support USI protocol.".
What needs to be implemented?
I see the most important part is done: board.push_usi(string)

Unfortunately the english version of the USI description is down:
http://www.glaurungchess.com/shogi/usi.html

Do you know by chance if there is a mirror in english? I could not find it.

Bug: Move Validation Not Working

Interesting...

>>> shogi.Move.from_usi('7g7f') in board.legal_moves
False
>>> print([move for move in board.legal_moves])
[Move.from_usi('9g9f'), Move.from_usi('8g8f'), Move.from_usi('7g7f'), Move.from_usi('6g6f'), Move.from_usi('5g5f'), Move.from_usi('4g4f'), Move.from_usi('3g3f'), Move.from_usi('2g2f'), Move.from_usi('1g1f'), Move.from_usi('9i9h'), Move.from_usi('1i1h'), Move.from_usi('7i7h'), Move.from_usi('7i6h'), Move.from_usi('3i4h'), Move.from_usi('3i3h'), Move.from_usi('6i7h'), Move.from_usi('6i6h'), Move.from_usi('6i5h'), Move.from_usi('4i5h'), Move.from_usi('4i4h'), Move.from_usi('4i3h'), Move.from_usi('2h7h'), Move.from_usi('2h6h'), Move.from_usi('2h5h'), Move.from_usi('2h4h'), Move.from_usi('2h3h'), Move.from_usi('2h1h'), Move.from_usi('5i6h'), Move.from_usi('5i5h'), Move.from_usi('5i4h')]

ライブラリ登録のお願い

予てよりありがたく利用させていただいております。
大変厚かましいお願いですが,コンピュータ将棋選手権使用可能ライブラリへの登録をお願いできませんでしょうか。
http://www2.computer-shogi.org/library/

昨年秋の電王トーナメントでも使用者の多いライブラリのひとつでした。
電王トーナメント主催のドワンゴ社に対しては私からの依頼でよかったのですが,
コンピュータ将棋協会主催のコンピュータ将棋選手権の規定では開発者本人の申請が必要とのことです。
お手数とは思いますが,ご登録頂ければ幸いです。
不適切でしたら削除して下さい。

nice to have svg or png support

nice to have svg or png support

when execute print(board), it will show the ASCII, like python-shogi already have
print(board)

result

 l  n  s  g  k  g  s  n  l
 .  r  .  .  .  .  .  b  .
 p  p  p  p  p  p  p  p  p
 .  .  .  .  .  .  .  .  .
 .  .  .  .  .  .  .  .  .
 .  .  .  .  .  .  .  .  .
 P  P  P  P  P  P  P  P  P
 .  B  .  .  .  .  .  R  .
 L  N  S  G  K  G  S  N  L

when execute
board

result
Board('lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1')

expected result like in python-chess,
when execute board it will get svg or png draw

best regards

legal-check bug

hello, I have a problem with move-legality check. Attached a minimal example to show the problem. The move is legal, but it is not recognized as such with move in board.legal_moves. When generating the full list of legal moves, it is recognized.
I am using python version 2.7.13 on debian with python-shogi version 1.0.7

import shogi

b = shogi.Board()
b.set_sfen('ln1g3+Rl/1ks4s1/pp1gppbpp/2p3N2/9/5P1P1/PPPP1S1bP/2K1R1G2/LNSG3NL w 4p 42')
m = shogi.Move.from_usi('2g5d+')

print(m in b.legal_moves)                   # False
print(b.legal_moves.__contains__(m))        # False
print(m in list(b.legal_moves))             # True
print(list(b.legal_moves).__contains__(m))  # True

python3でCSA.pyが動かない

python3 で random_csa_tcp_match を動かそうとすると以下のエラーが出ます。

Traceback (most recent call last):
  File "./random_csa_tcp_match", line 23, in <module>
    ct.login(sys.argv[2], sys.argv[3])
  File "......./python-shogi/shogi/CSA.py", line 377, in login
    line = self.command('LOGIN {0} {1}'.format(username, password))
  File "......./python-shogi/shogi/CSA.py", line 335, in command
    self.write(command + '\n')
  File "......./python-shogi/shogi/CSA.py", line 340, in write
    self.socket.sendall(buf)
TypeError: a bytes-like object is required, not 'str'

bufにencode(), decode()をつければpython3でも動きますがpython2と互換のコードになっているかわからずプルリクエストが出せません。

extract more info from kif header

nice to have ability to extract more info from kif header

e.g.
End date: 「終了日時」
Tournament: 「棋戦」
Opening: 「戦型」
Heading? (TN: no idea): 「表題」
Time control (initial starting time on clock): 「持ち時間」
Time expended: 「消費時間」
Location: 「場所」
Published: 「掲載」
Reference: 「備考」

or taken from 81dojo

開始日時:2016/07/27
場所:81Dojo
持ち時間:30分+60秒
手合割:平手
先手:Linkuei
後手:sirawata

ref
http://kakinoki.o.oo7.jp/kif_format.html

best regards

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.