Ren'Py Chess Game 2.0
A downloadable game for Windows, macOS, and Linux
About
This is a chess GUI built with the Ren'Py Visual Novel Engine, python-chess, and Stockfish (for chess AI). You can use it as a standalone playable or integrate it as a minigame into a Ren'Py visual novel project. Read the guide for integration in my GitHub repo.
The source code is available both inside the game folder and on my GitHub. Please refer to GitHub for the latest updates to the source code.
This chess engine supports Ren'Py 8.
I wrote about how I developed this project in a blog post on freeCodeCamp. I've helped to integrate this chess engine into an in-development Visual Novel game, The Wind at Dawn.
~~~
The guide for integration should suffice to help you integrate this engine into your project. I also take commissions for developing custom features and helping with integration. If you have questions, feel free to comment below, email r3dhummingbird at outlook.com, or, lynn#9327 on Discord.
Gameplay
The game supports Player vs. Player and Player vs. Computer. In PvC, the player can choose to play as either Black or White.
Click on a piece and all of its available moves will be highlighted in blue. Click on any of the legal destination squares to make a move. Press Flip board view to flip the view, with White on the bottom by default.
Gameplay Example: Fool's Mate
Player vs. Computer (Stockfish)
Flip Board View, Undo Moves, Resign
Promotion UI
Stalemate
Threefold Repetition: UI for Claiming a Draw
(Also shows a similar UI choice screen if the fifty-move rule is in effect)
Status | Released |
Platforms | Windows, macOS, Linux |
Rating | Rated 5.0 out of 5 stars (5 total ratings) |
Author | r3dhummingbird |
Genre | Strategy, Visual Novel |
Made with | pygame, Ren'Py |
Tags | 2D, Chess, Open Source, Ren'Py, sourcecode, Turn-based |
Code license | MIT License |
Average session | A few minutes |
Inputs | Mouse |
Links | Source code, Blog, YouTube |
Download
Install instructions
If you are on a Mac, you may receive a warning about "unidentified developer" when you launch the game. Go to System Preferences > Security & Privacy and answer "Open anyway" to the warning.
Development log
- Add support for Ren'Py 8Jun 15, 2023
- Feature Updates: Undo Moves, ResignJan 28, 2021
- Add difficulty selectionDec 20, 2020
- Display the 5 most recent moves on the left panelOct 31, 2020
Comments
Log in with itch.io to leave a comment.
Hello, I tried to integrate your module to my project, but this error appeared. I'm using Ren'Py 8.2.1
I'm sorry, but an uncaught exception occurred.
While running game code:
File "game/00-chess-engine/chess_displayable.rpy", line 199, in script
init python:
File "game/00-chess-engine/chess_displayable.rpy", line 227, in <module>
STARTUPINFO = subprocess.STARTUPINFO()
NameError: name 'subprocess' is not defined
-- Full Traceback ------------------------------------------------------------
Full traceback:
File "game/00-chess-engine/chess_displayable.rpy", line 199, in script
init python:
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\ast.py", line 823, in execute
renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\python.py", line 1178, in py_exec_bytecode
exec(bytecode, globals, locals)
File "game/00-chess-engine/chess_displayable.rpy", line 227, in <module>
STARTUPINFO = subprocess.STARTUPINFO()
NameError: name 'subprocess' is not defined
Windows-10-10.0.19045 AMD64
Ren'Py 8.2.1.24030407
chess 1.0
Fri Mar 22 12:16:47 2024
Then I've imported subprocess library into chess_displayable.rpy after init python statement. It worked, but when the game ended and I tried to save progress, this error appeared
[code]
I'm sorry, but an uncaught exception occurred.
While running game code:
File "renpy/common/00gamemenu.rpy", line 174, in script
$ ui.interact()
File "renpy/common/00gamemenu.rpy", line 174, in <module>
$ ui.interact()
File "renpy/common/00action_file.rpy", line 414, in __call__
renpy.save(fn, extra_info=save_name)
AttributeError: Can't pickle local object 'WeakSet.__init__.<locals>._remove' (perhaps renpy.game.log.log[12].stores['store']['STOCKFISH_ENGINE'].transport.__getstate__()[1]['_extra']['subprocess']._waitpid_lock = <unlocked _thread.lock object at 0x0000000003834360>)
-- Full Traceback ------------------------------------------------------------
Full traceback:
File "renpy/common/00gamemenu.rpy", line 174, in script
$ ui.interact()
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\ast.py", line 823, in execute
renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\python.py", line 1178, in py_exec_bytecode
exec(bytecode, globals, locals)
File "renpy/common/00gamemenu.rpy", line 174, in <module>
$ ui.interact()
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\ui.py", line 301, in interact
rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\core.py", line 2165, in interact
repeat, rv = self.interact_core(preloads=preloads, trans_pause=trans_pause, pause=pause, pause_start=pause_start, pause_modal=pause_modal, **kwargs) # type: ignore
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\core.py", line 3201, in interact_core
rv = root_widget.event(ev, x, y, 0)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\layout.py", line 1202, in event
rv = i.event(ev, x - xo, y - yo, cst)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\transition.py", line 53, in event
return self.new_widget.event(ev, x, y, st) # E1101
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\layout.py", line 1202, in event
rv = i.event(ev, x - xo, y - yo, cst)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\layout.py", line 1202, in event
rv = i.event(ev, x - xo, y - yo, cst)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\screen.py", line 793, in event
rv = self.child.event(ev, x, y, st)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\layout.py", line 1202, in event
rv = i.event(ev, x - xo, y - yo, cst)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\layout.py", line 1426, in event
rv = super(Window, self).event(ev, x, y, st)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\layout.py", line 288, in event
rv = d.event(ev, x - xo, y - yo, st)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\layout.py", line 1202, in event
rv = i.event(ev, x - xo, y - yo, cst)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\layout.py", line 1426, in event
rv = super(Window, self).event(ev, x, y, st)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\layout.py", line 288, in event
rv = d.event(ev, x - xo, y - yo, st)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\layout.py", line 1202, in event
rv = i.event(ev, x - xo, y - yo, cst)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\layout.py", line 288, in event
rv = d.event(ev, x - xo, y - yo, st)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\behavior.py", line 1174, in event
return handle_click(self.clicked)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\behavior.py", line 1095, in handle_click
rv = run(action)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\display\behavior.py", line 395, in run
return action(*args, **kwargs)
File "renpy/common/00action_file.rpy", line 414, in __call__
renpy.save(fn, extra_info=save_name)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\loadsave.py", line 436, in save
reraise(t, e, tb)
File "lib/python3.9/future/utils/__init__.py", line 444, in raise_
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\loadsave.py", line 417, in save
dump((roots, renpy.game.log), logf)
File "C:\Users\Donakass\Desktop\renpy-8.2.1-sdk\renpy\compat\pickle.py", line 103, in dump
pickle.dump(o, f, pickle.HIGHEST_PROTOCOL if highest else PROTOCOL)
AttributeError: Can't pickle local object 'WeakSet.__init__.<locals>._remove' (perhaps renpy.game.log.log[12].stores['store']['STOCKFISH_ENGINE'].transport.__getstate__()[1]['_extra']['subprocess']._waitpid_lock = <unlocked _thread.lock object at 0x0000000003834360>)
Windows-10-10.0.19045 AMD64
Ren'Py 8.2.1.24030407
chess 1.0
Fri Mar 22 12:20:10 2024
[/code]
I would appreciate any help, thank you!
Fixed.
Hello, I downloaded the game file and transferred it to renpi to create my project and when I run the file, select the difficulty of the game, at that moment an error appears.
I'm sorry, but an uncaught exception occurred.
While running game code:
File "game/script.rpy", line 53, in script
call screen chess(fen, player_color, movetime, depth)
File "renpy/common/000statements.rpy", line 670, in execute_call_screen
store._return = renpy.call_screen(name, *args, **kwargs)
File "game/00-chess-engine/chess_displayable.rpy", line 108, in execute
screen chess(fen, player_color, movetime, depth):
File "game/00-chess-engine/chess_displayable.rpy", line 108, in execute
screen chess(fen, player_color, movetime, depth):
File "game/00-chess-engine/chess_displayable.rpy", line 113, in execute
default chess_displayable = ChessDisplayable(fen=fen,
File "game/00-chess-engine/chess_displayable.rpy", line 113, in <module>
default chess_displayable = ChessDisplayable(fen=fen,
File "game/00-chess-engine/chess_displayable.rpy", line 270, in __init__
self.chess_subprocess.stdin.write('#'.join(['fen', fen, '\n']))
TypeError: a bytes-like object is required, not 'str'
-- Full Traceback ------------------------------------------------------------
Full traceback:
File "game/script.rpy", line 53, in script
call screen chess(fen, player_color, movetime, depth)
File "D:\renpy-8.1.3-sdk\renpy\ast.py", line 2259, in execute
self.call("execute")
File "D:\renpy-8.1.3-sdk\renpy\ast.py", line 2241, in call
return renpy.statements.call(method, parsed, *args, **kwargs)
File "D:\renpy-8.1.3-sdk\renpy\statements.py", line 342, in call
return method(parsed, *args, **kwargs)
File "renpy/common/000statements.rpy", line 670, in execute_call_screen
store._return = renpy.call_screen(name, *args, **kwargs)
File "D:\renpy-8.1.3-sdk\renpy\exports.py", line 3347, in call_screen
rv = renpy.ui.interact(mouse="screen", type="screen", roll_forward=roll_forward)
File "D:\renpy-8.1.3-sdk\renpy\ui.py", line 299, in interact
rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
File "D:\renpy-8.1.3-sdk\renpy\display\core.py", line 3582, in interact
repeat, rv = self.interact_core(preloads=preloads, trans_pause=trans_pause, pause=pause, pause_start=pause_start, pause_modal=pause_modal, **kwargs) # type: ignore
File "D:\renpy-8.1.3-sdk\renpy\display\core.py", line 4055, in interact_core
root_widget.visit_all(lambda d : d.per_interact())
File "D:\renpy-8.1.3-sdk\renpy\display\core.py", line 684, in visit_all
d.visit_all(callback, seen)
File "D:\renpy-8.1.3-sdk\renpy\display\core.py", line 684, in visit_all
d.visit_all(callback, seen)
File "D:\renpy-8.1.3-sdk\renpy\display\core.py", line 684, in visit_all
d.visit_all(callback, seen)
File "D:\renpy-8.1.3-sdk\renpy\display\screen.py", line 476, in visit_all
callback(self)
File "D:\renpy-8.1.3-sdk\renpy\display\core.py", line 4055, in <lambda>
root_widget.visit_all(lambda d : d.per_interact())
File "D:\renpy-8.1.3-sdk\renpy\display\screen.py", line 487, in per_interact
self.update()
File "D:\renpy-8.1.3-sdk\renpy\display\screen.py", line 680, in update
self.screen.function(**self.scope)
File "game/00-chess-engine/chess_displayable.rpy", line 108, in execute
screen chess(fen, player_color, movetime, depth):
File "game/00-chess-engine/chess_displayable.rpy", line 108, in execute
screen chess(fen, player_color, movetime, depth):
File "game/00-chess-engine/chess_displayable.rpy", line 113, in execute
default chess_displayable = ChessDisplayable(fen=fen,
File "game/00-chess-engine/chess_displayable.rpy", line 113, in <module>
default chess_displayable = ChessDisplayable(fen=fen,
File "game/00-chess-engine/chess_displayable.rpy", line 270, in __init__
self.chess_subprocess.stdin.write('#'.join(['fen', fen, '\n']))
TypeError: a bytes-like object is required, not 'str'
Ren'Py 8.1.3.23091805
chess 1.0
please help me solve this problem.
Hi, please use the latest version at https://github.com/RuolinZheng08/renpy-chess
Hello! This project is very interesting and I would like to know if it is implementable in ren'py 8 visual novels?
Hi there :)
There is no scheduled upgrade for this project as I’m working on other side projects. I will give the upgrade more priority if someone is willing to commission it.
As of 8 months ago, the project has been upgraded to support Ren’Py 8.
I want to integrate it in Renpy 8, how can i do it. Can anyone send the same file comptible for renpy8.0.
As of 8 months ago, the project has been upgraded to support Ren’Py 8.
So can this game play on Android?? or in source code have distributions to Android??
Yep the source code can be compiled to run on Android.
( Ver. 2.0 is still working nicely in Ren'Py 7.4.11 )
Great to know. Thanks!
Hi Lynn, pardon my ignorance. I see that you mentioned there are codes available on Github, and we can utilize this chess game in our VN. Does that means that this game is also allowed for commercial used? Thank you.
Thanks for reaching out and for sure! Feel free to use it in commercial projects. If you use it, please credit both this itch.io page and my GitHub repo.
Thank you!
I'm Tim, director of the kinetic visual novel project The Wind at Dawn. Ren'Py Chess first caught my eye in September 2020 as an interesting addition to our game, and so we made the original commission for an update of her engine that integrates Stockfish. We also commissioned a new board displayable system that allows developers to display static board states.
Our experience working with Lynn on Ren'Py Chess (and also The Wind at Dawn) has been phenomenal. She writes code that is readable, elegant, and effective. Never one to take shortcuts in her work, she will always directly tackle the root of the problem while providing comprehensive comments along the way for posterity. Even as a student, she is producing work that one would expect of a seasoned professional.
Hopefully many more visual novel developers see the wealth of possibilities in Ren'Py Chess. The chess boom is still happening as we speak, and I'm excited to see how this ancient game can bring a new angle to more OELVNs.
(Be sure to contact and contract Lynn for both Ren'Py Chess implementation and general development support! Trust me, she's a valuable asset to any team.)
Hi! One of my teammates recently got this weird traceback when testing the engine by himself:
--------------------------------------------------------------------------------------
I'm sorry, but an uncaught exception occurred.
While running game code:
File "renpy/common/000statements.rpy", line 531, in execute_call_screen
store._return = renpy.call_screen(name, *args, **kwargs)
File "game/chess_displayable.rpy", line 75, in execute
File "game/chess_displayable.rpy", line 75, in execute
File "game/chess_displayable.rpy", line 80, in execute
File "game/chess_displayable.rpy", line 287, in __init__
WindowsError: [Error 2] The system cannot find the file specified
--------------------------------------------------------------------------------------
Could you perhaps answer this as soon as possible? I've been struggling to solve every error related to this for days, or maybe even weeks... And I seriously need help xS
Thanks in advance =)
Hi @pulpeirodasilva. Thanks for the note.
Can you confirm whether you have moved any of the files from the game I packaged? This seems like a missing file error and should not happen as long as the files are kept intact.
Please try the source code on GitHub (Ren'Py 7.3.5) without removing or changing anything. If your SDK is Ren'Py 7.4, try the GitHub prerelease.
If you have any more questions, please feel free to reach me on Discord. My handle is lynn#9327.
I already reached out to you on Discord a few days prior to my previous comment in here. I'm creating a DDLC mod in which I'm using your chess engine, Doki Doki Check Mate ^^
As for my SDK, it's actually Ren'Py 6, so I don't know if there's code for that version.
Also, I did not move any file. I placed the chess_displayable.rpy script and the folders, one by one, into their respective places, as your instructions say.
So, if you could reply to me through here or through Discord, that would be really cool ^^
Hey r3dhummingbird, thx for the updates again!
We've run into a problem implementing 2.0, as we're using fullHD resolution the buttons for a) "switch table" and b) the..pronounce - symbols of possible figures to change a pawn into on the right side.
Looking into the code a bit, were not even sure if its unicode-symbols or graphical buttons used for.. both seem kind of exist..
What we get shown are brackets like with like unicode mismatching:
D'you have ideas by chance how to solve that - or do we have to build the buttons otherwise?
Best Regards
Hi Ic4p,
Both the promotion piece buttons and the flip-board button are implemented using Unicode textbuttons. There is a flip-board button image in the asset folder but it isn't used. (See the code linked below.) If the Unicode characters aren't showing up, you would want to replace the textbuttons with image buttons and use image assets. If you have any more questions, please feel free to reach me on Discord. My handle is lynn#9327.
https://github.com/RuolinZheng08/renpy-chess/blob/bb3eeac7ec2bb5d2728d161db29388...
https://github.com/RuolinZheng08/renpy-chess/blob/bb3eeac7ec2bb5d2728d161db29388...
Hi ^^
Did you manage to use those ImageButtons? If so, please tell me how. I now need to know that myself for a project I'm working on, and I have absolutely no clue on how to do it.
Hey. No, in fact the unicode buttons work like a charm as soon as you use a standard FONT for the chess game..
And do I need to write any specific line/s of code in order to do that?
**Sorry, just kinda new to RenPy here ^^
The latest update on GitHub makes GUI display text use DejaVuSans explicitly.
Basically,
I love that this exists! Very well done.
I have already implemented the old V.1 in a renpy project still in development. Now testing V2. The sound feature alone is worth re-implementing, I think.
What I sort of missed in 1 and still V2:
For me its often not clear what the KI did as his recent move. Most "real" computer chess games ether have a kind of mark up of of the recent move - like an arrow indicating the move of the figure to current position OR even better: a notation of all recent moves on the right side.. formatwise like "E7-E5"
Perhabs you like to work on of these? Keep up the good work!
Hi @Ic4p, thanks for the comment! Having a list of the 5 most recently made moves show up on one side of the board is easy to implement. I'll make a note of this and publish a new release when it's done.
Feel free to let me know if you run into any issue integrating this into your project :)
Hi @Ic4p, I'm happy to announce that this feature has been implemented and released for download.
WHAAAAAAT!!! You are a hero! Thanks. Also, I wouldn't mind some difficulty settings being a dumb chess player that I am ;)
Hi @mif4n. Thanks for the comment!
I will consider adding that as a feature if more people express interest :D
For now, you can programmatically set the difficulty in script.rpy as follows. A shorter movetime (in milliseconds) and a smaller depth will reduce the strength of the chess AI. Read more in my GitHub README and feel free to reach out with any more questions :)
Thank you. :)
Hi mif4n. I'm happy to announce that the newest release now allows for difficulty level selection. Quote my devlog:
Easy: depth 2, < 1900 ELO.
Medium: depth 6, 1966 ELO.
Hard: depth 12, 2364 ELO.
See Stockfish depth to ELO conversion