Sunfish: A simple but strong chess engine in 111 lines of Python
github.com
github.com
http://home.hccnet.nl/h.g.muller/max-src2.html
is even shorter and stronger than Toledo's.
[1] https://github.com/vishvananda/ivory [2] https://chessprogramming.wikispaces.com/Bitboards
Whoa. I've literally never seen this idiom before.
But I immediately like it.
http://stackoverflow.com/questions/4071765/in-python-how-do-...
Still, very cool. I spent awhile trying to write my own and failed miserably. :)
Sidenote: independent from the discussions about the lines I consider it an awesome piece of work. Even in 388 lines it's still much better than what I could deliver.
wget 'https://raw.githubusercontent.com/thomasahle/sunfish/master/sunfish.py'
egrep -v '^$|^ *#' sunfish.py > sustrip.py
wc -l *py
388 sunfish.py
263 sustrip.py
(or: equivalently:) egrep -c '^$|^ *#' sunfish.py
125 #Comments, empty lines
egrep -c '^$|^ *#' sunfish.py -v
263 #Non-empty lines, non-comment lines
I believe the actual chess engine might be 111 lines, though.Having said that, the code is very neat and readable. Thank you for showing it here!
It's not like Chess is some weird, esoteric game where there is a gray area of whether or not moves are legal or not.
Maybe I'm biased. I'm currently working on a toy chess engine myself.
Actually it is exactly like that.
If you play tournament chess, like USCF tournaments, then there's no doubt what the rules are. However if you play casual chess, like with some random guy in the park, then be prepared for some misunderstandings.
Some things casual players think are rules:
Pawns move two squares only on the first move of the *game* not the first move of the pawn
You can't promote a pawn the move after it arrives on the 7th rank, you have to wait a move
Perpetual check is illegal (somewhat like the Ko rule in go)
Capturing En Passant is generally not known
So when I'm playing a stranger I always ask if they've played any tournaments, not to gauge how strong they are, but to see if they'll know the rules of chess.I actually did not know this one, and I thought I played enough Chess to know all the rules.
When I played tournaments in high school, most players knew about it, but most players were still quite amateur, so one could offer up a position in which the opponent could perform an en passant, but the en passant was actually fairly detrimental, and more often than not the opponent will take it, because "hey cool I can do that weird pawn move".
As far as I know, these rules are extremely standardized in most or all areas of the world where chess is known. I have heard about some special rules for competitions that can differ, like timing limitations and end-game rules. I'm also aware of many variations of chess, but those are always clearly discussed as variants.
Can you elaborate on this? I've never seen any claim to this effect, only that a pawn on its starting rank has the option of moving two squares (but cannot use that to jump over or capture a piece) (e.g. as stated http://en.wikipedia.org/wiki/Pawn_(chess)). Are these different claims or am I misunderstanding?
> You can't promote a pawn the move after it arrives on the 7th rank, you have to wait a move
Same here. "The new piece replaces the pawn on the same square, as part of the same move" (e.g. http://en.wikipedia.org/wiki/Promotion_(chess))
I'm only showing wikipedia cites to indicate that if these are wrong they are widely spread, and hoping that you have better cites.
K R r
_ _ _
k _ _
Can `k` move to the right? Someone who isn't familiar with this situation might think so, because `R` is pinned to `K` by `r`, but it turns out that even though `R` can't move to the square right of `k`, `R` can still give check to it, so the move would be illegal.Then you also get people who don't know about rules regarding castling through check, etc.
Basically what I'm getting at is, there are moves that even people who casually play chess might misunderstand, so OP was implying that they were not one of these people.
Edit: Thanks for the clarifications. lowercase = one color, uppercase = other color. K = king, R = rook
The question is... does the rook R still provide attack/check even though it is pinned by rook r to King K?
The answer is yes.
His situation is correct, however I don't think any experienced chess player would not know that.
If one thinks about chess as if the goal were to capture the opponent's king before one's own king is captured, this makes perfect sense. But sometimes the concept of checkmate muddles peoples' intuitions.
It's a common mistake that is likely to be made in finals from beginners.
Also, a move that would place yourself in check is never legal.
Also you never actually take the king, you just get the point where you could and it has no escape.
It would also add some credence to your argument which lacks any reproduction details.
e2e4 g8f6
e4e5 f6d5
d2d4 b8c6
f2f4 e7e6
c2c4 d8h4?
g2g3 f8b4
c1d2 -- 2 pieces en-prise at this point.
h4h6
c4d5 e6d5
d2b4 c6b4
a2a3 b4c6
b1c3 c6e7
Just a piece down with very little compensation.I think a more interesting problem now is to create computer algorithms that can be "taught" the rules of a board game --- a problem that falls squarely in the domain of supervised learning. In the studies I've found, the algorithms were provided with a lot of prior knowledge about the specific board game, so there may be a lot of room for progress.
http://en.wikipedia.org/wiki/General_game_playing
http://www.general-game-playing.de/literature.html
GGP is then about deriving knowledge about the game and its state evaluation using a) the rules directly, b) the represented state tree or c) past matches in that very game.
The other one I know of is a mechanism where you use reinforcement learning and assume one state in the beginning. With more info, you start splitting the state into several states using decision tree split criteria, such as cross entropy, and you end up obtaining a game state tree together with the knowledge to play reasonably well. Problem: I don't remember how it's called.
Since you can't use human-tuned heuristics for every game, you have to use more general meta-heuristics. There's also a lot of room for logically parsing the game, and trying to separate out individual components, obviously meaningless moves, etc.
see http://en.wikipedia.org/wiki/General_game_playing or https://www.coursera.org/course/ggp
an example game: http://ggpserver.general-game-playing.de/ggpserver/public/vi...
it basically defines an initial game state, the moves each player can make and how they alter the game state, and the end-conditions and goals of the game.
Second game I decided to avoid opening theory and head into a King's Indian Attack. Black's opening moves were sensible, knight and bishops to the right squares, pawns on e5 and d5, but it really wasn't taking my queenside pawn expansion seriously enough, giving up a knight for a pawn. But it's quite resourceful, it's managed to win an exchange, although it's in a desperate position. Currently it's hanging on this position.. oh. No, it's finally crashed. This is the position it died on:
r . . . r . . .
. . . . . . k p
. b q . . . p .
. R p . p . . .
P . Q p P . . .
B N . P . . P B
. . . . . P . P
. . . . . . K .
White's last move: f5h3. Took about 10 minutes and made the move h8g7, and then crashed with Your move: Traceback (most recent call last):
File "sunfish.py", line 388, in <module>
main()
File "sunfish.py", line 365, in main
move = parse(crdn[0:2]), parse(crdn[2:4])
File "sunfish.py", line 345, in parse
fil, rank = ord(c[0]) - ord('a'), int(c[1]) -1
ValueError: invalid literal for int() with base 10: ''
So, not strong, but surprisingly strong for the size of the code. Remarkable. Traceback (most recent call last):
File "sunfish.py", line 388, in <module>
main()
File "sunfish.py", line 365, in main
move = parse(crdn[0:2]), parse(crdn[2:4])
File "sunfish.py", line 345, in parse
fil, rank = ord(c[0]) - ord('a'), int(c[1]) - 1
IndexError: string index out of rangeThe machine had a Basic interpreter that used bytecodes (to save memory), so programmers regularly mixed adopted a mixed style : basic + asm .
Anyway, to write a chess program for that machine is however rather impressive.
It just means you are using a more abstracted version of whatever.
In reality, a 111 lines of Python program is likely thousands of lines if you were to count all of the standard Python libraries and/or any 3rd party libraries used.
What if I took this program, wrapped it in say, 5 lines of Python, then said I implemented chess in 5 lines of Python? Did I really? Of course not... but it makes for a good attention grabber.
No. It's a tradition that goes back a long way. When it started it was about making code better - more efficient; faster; smaller. Part of that was the limited hardware available.
Now, when huge computing power is available to almost anyone, it's about the fun of finding that shortcut or that weird trick to remove a few lines of code.
There's some cool techniques different people use to solve some seemingly major problems in just a few characters.
Clearly there's a line beyond which the code is no longer readable, but that is not to say that more lines is better, or that there is no elegance in implementing things more concisely.
I am proud to not contribute much to LOC counts on most of the teams I worked as I clean up a lot after my colleagues to keep code duplications low and pointless code out. Less code is normally easier to maintain as long as you follow some other coding practices and don't go and inline everything.
- Using an actual text representation of the board, rather than a binary. - Having separate functions for move generation, search and evaluation. - Using a python hashmap rather than a simple zobrist hash. - Using a direct piece square table rather than some compressed/generated nonsense.
I do however also think, that trying to shorten the move generation of some programs, which can be hundreds or thousands of lines, to something like this, is a good exercise in finding patterns, and has a certain beauty ;)