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)

StatusReleased
PlatformsWindows, macOS, Linux
Rating
Rated 5.0 out of 5 stars
(5 total ratings)
Authorr3dhummingbird
GenreStrategy, Visual Novel
Made withpygame, Ren'Py
Tags2D, Chess, Open Source, Ren'Py, sourcecode, Turn-based
Code licenseMIT License
Average sessionA few minutes
InputsMouse
LinksSource code, Blog, YouTube

Download

Download
chess-1.0-linux.tar.bz2 23 MB
Download
chess-1.0-mac.zip 16 MB
Download
chess-1.0-pc.zip 43 MB

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

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!

(1 edit)

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.

Deleted 1 year ago

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!

(+1)

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,

# BEGIN STYLE
style game_status_text is text:
    font 'DejaVuSans.ttf'
    color COLOR_WHITE
    size TEXT_SIZE
style promotion_piece is button
style promotion_piece_text is text:
    font 'DejaVuSans.ttf'
    size TEXT_BUTTON_SIZE
    color '#aaaaaa' # gray
    hover_color '#555555' # darker gray
    selected_color COLOR_WHITE
style flip_board is button
style flip_board_text is text:
    font 'DejaVuSans.ttf'
    size TEXT_BUTTON_SIZE
    color '#aaaaaa' # gray
    hover_color COLOR_WHITE
# END STYLE

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 ;)

(3 edits) (+1)

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 :)

$ movetime = 2000        
$ depth = 10

Thank you. :) 

(+1)

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