Git Product home page Git Product logo

renpy-chess's Introduction

Ren'Py Chess Engine 2.0

Play it now on itch.io or watch a YouTube demo

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 below.

Compatibility

This chess engine supports Ren'Py 8. It is not backward compatible with Ren'Py 7. See the other branches (ex. renpy-7.4, renpy-7.3.5 for older Ren'Py versions)

Gameplay Example: Fool's Mate

Gameplay Example

Differences between Ren'Py Chess 1.0 and Ren'Py Chess 2.0

Pros Cons
Ren'Py Chess 1.0
  • Has no Python package dependency hence supports any OS: Windows, Mac, Linux, Android, iOS, and even Web browser-play
  • Does not support en passant, castling, or promotion
  • Does not support claiming a draw for the threefold repetition or the fifty-move rule
  • Player can only play as White in Player vs. Computer
  • Uses a chess AI of minimal implementation with no support for customizing the strength of the AI
Ren'Py Chess 2.0 (This project)
  • Has full support for en passant and castling, plus a special UI for promotion
  • Has full support and a special UI for claiming a draw for the threefold repetition or the fifty-move rule
  • Supports flipping board view
  • Uses Stockfish and supports customization of the strength (thinking time, depth) of the chess AI
  • Only tested on Mac and Windows. Does not support iOS or Web. If you are on other OS (Linux, Android) and encounter a problem, please submit a GitHub issue

Gameplay

The game supports Player vs. Player and Player vs. Computer. In PvC, player can choose to play as either Black or White.

Click on a piece and all of its available moves will be highlighted. 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.

Feature List

  • PvP and PvC
  • Flip board view
  • Resign
  • Undo moves

Player vs. Computer (Stockfish)

Play vs Computer

Flip Board View, Undo Moves, Resign

Flip Board

Promotion UI

Promotion

Threefold Repetition: UI for Claiming a Draw

(Also shows a similar UI choice screen if the fifty-move rule is in effect) Threefold Repetition

Guide for Integrating into a Ren'Py Project

Note: This project is built on Ren'Py 7 and doesn't yet support Ren'Py 8 (which uses Python 3). If your game requires Ren'Py 8, please reach out to me.

All of the files essential to the chess engine are in game/00-chess-engine. Therefore, you only need to copy the entire 00-chess-engine into your Ren'Py game directory.

The chess game is full-screen when the screen resolution is 1280x720, but is customizable to fit any screen sizes, as described in subsequent sections.

Structure of 00-chess-engine

00-chess-engine/
    - audio                         # chess game sound effects
    - bin                           # chess AI Stockfish binaries
    - images                        # chess board and piece images
    - python-packages               # Python libraries
    - chess_displayable.rpy         # core GUI class
    - chess_subprocess.py           # core logic class

The core GUI class is a Ren'Py Creator-Defined Displayable named ChessDisplayable inside 00-chess-engine/chess_displayable.rpy. You can customize anything stylistic in chess_displayable.rpy, as described below in more details.

00-chess-engine/chess_subprocess.py is the underlying chess engine. Creating an instance of ChessDisplayable will launch chess_subprocess.py as a subprocess. You can make logical changes in chess_subprocess.py for your specific use cases if you are comfortable with subprocess programming.

In your Ren'Py script, for example, script.rpy, pass the following configuration variables for the chess engine to the chess screen defined as screen chess(fen, player_color, movetime, depth):

  • fen: the Forsyth–Edwards Notation of the board
  • player_color: None for PvP. For PvC, chess.WHITE or chess.BLACK.
  • movetime: None for PvP. For PvC, between 0 and MAX_MOVETIME = 3000 milliseconds.
  • depth: None for PvP. For PvC, between 0 and MAX_DEPTH = 20.

To call the chess displayable screen: (Also see the game/script.rpy file in this repo.)

define e = Character("Eileen")

window hide
$ quick_menu = False
# avoid rolling back and losing chess game state
$ renpy.block_rollback()

# launches an easy-level PvC where player plays as white
$ fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
call screen chess(fen=fen, player_color=WHITE, movetime=2000, depth=2)

# avoid rolling back and entering the chess game again
$ renpy.block_rollback()
# restore rollback from this point on
$ renpy.checkpoint()
$ quick_menu = True
window show

if _return == DRAW:
    e "The game ended in a draw."
else: # RESIGN or CHECKMATE
    $ winner = "White" if _return == WHITE else "Black"
    e "The winner is [winner]."
    if player_color is not None: # PvC
        if _return == player_color:
            e "Congratulations, player!"
        else:
            e "Better luck next time, player."

Customizations for Different Difficulty Levels

The strength of the compuer player can be customized by setting the depth parameter between the range of 1 and 20, with a larger number indicating more strength. See Stockfish depth to ELO conversion.

Customizations for Different Screen Sizes, Colors, Styles, and Audios

Override the defaults in chess_displayable.rpy and replace the default chess piece and chess board images, or, audio files in 00-chess-engine/images and 00-chess-engine/audio.

# directory paths
# the path of the current directory within game/
define THIS_PATH = '00-chess-engine/'
define IMAGE_PATH = 'images/'
define AUDIO_PATH = 'audio/'
define BIN_PATH = 'bin/' # stockfish binaries
define CHESSPIECES_PATH = THIS_PATH + IMAGE_PATH + 'chesspieces/'

# file paths
define IMG_CHESSBOARD = THIS_PATH + IMAGE_PATH + 'chessboard.png'
define AUDIO_MOVE = THIS_PATH + AUDIO_PATH + 'move.wav'
define AUDIO_CAPTURE = THIS_PATH + AUDIO_PATH + 'capture.wav'
define AUDIO_PROMOTION = THIS_PATH + AUDIO_PATH + 'promotion.wav'
define AUDIO_CHECK = THIS_PATH + AUDIO_PATH + 'check.wav'
define AUDIO_CHECKMATE = THIS_PATH + AUDIO_PATH + 'checkmate.wav'
define AUDIO_DRAW = THIS_PATH + AUDIO_PATH + 'draw.wav' # used for resign, stalemate, threefold, fifty-move
define AUDIO_FLIP_BOARD = THIS_PATH + AUDIO_PATH + 'flip_board.wav'

# this chess game is full-screen when the game resolution is 1280x720
define CHESS_SCREEN_WIDTH = 1280
define CHESS_SCREEN_HEIGHT = 720

# use loc to mean UI square and distinguish from logical square
define LOC_LEN = 90 # length of one side of a loc

define COLOR_HOVER = '#90ee90aa' # HTML LightGreen
define COLOR_SELECTED = '#40e0d0aa' # Turquoise
define COLOR_LEGAL_DST = '#afeeeeaa' # PaleTurquoise
define COLOR_PREV_MOVE = '#6a5acdaa' # SlateBlue
define COLOR_WHITE = '#fff'

Continuous Development

The project is under active maintenance and you can view its development status on this public Trello board. Please feel free to submit a GitHub issue for bugs and feature requests. I have helped to integrate this chess engine into an in-development kinetic novel, The Wind at Dawn.

Contribution

Please feel free to submit GitHub issues and PRs. You are also more than welcome to join the Trello board if you are interested.

Asset Credits

renpy-chess's People

Contributors

devdanzin avatar ruolinzheng08 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

renpy-chess's Issues

Allow saving and resuming a chess game

Saving board state (after every move?) and resuming from save state would avoid players losing progress on unexpected exit and crashes, as well as making it easier to stop during a long chess game, rest, and come back to finish later.

I've explored this a bit, but didn't get any positive results. My current hypothesis is that, at the same sites you add to history, it would be able to renpy.save() with something like extra_info='some_name' + self.board.fen.

Consider making chess engine plugable

Allowing alternative chess engines, like pure Python Sunfish, could make it easier to target iOS support (cf. Figure out how to add Stockfish engine for iOS since there's no download) and maybe running as HTML5.

This makes more sense if renpy-chess becomes a library (cf. [Wishlist] Separate standalone / demo and library), as users would be able to evaluate engine chess ranking, portability, completeness, etc. to suit their desired gaming experience. One example would a simple chess puzzle game where only move validation is necessary: no need to include stockfish for that (cf. Check OS compatibility and use the correct Stockfish binary.

If there's interest, I can submit an exploratory PR once we agree on a basic design.

Can't save/reload after integrating renpy-chess with renpy

I got the following error when I trie to make a save or reload the project after the chess minigame already finished and the next label is loaded. The game continues to run normaly, but seem's to be unable to save and load. I'm using the current renpy version (8.2.3.24061702). This also happens in the demo.

I'm sorry, but an uncaught exception occurred.

While running game code:
File "renpy/common/00keymap.rpy", line 487, in script
python hide:
File "renpy/common/00keymap.rpy", line 487, in
python hide:
File "renpy/common/00keymap.rpy", line 511, in _execute_python_hide
renpy.save("_reload-1", "reload save game")
TypeError: cannot pickle '_io.FileIO' object (perhaps renpy.game.log.log[107].stores['store']['STOCKFISH_ENGINE'].transport.getstate()[1]['_extra']['subprocess']._waitpid_lock = <unlocked _thread.lock object at 0x7c9125b6cf60>)

-- Full Traceback ------------------------------------------------------------

Full traceback:
File "renpy/common/00keymap.rpy", line 487, in script
python hide:
File "/home/arch/RenPy/renpy-8.2.0-sdk/renpy/ast.py", line 823, in execute
renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
File "/home/arch/RenPy/renpy-8.2.0-sdk/renpy/python.py", line 1178, in py_exec_bytecode
exec(bytecode, globals, locals)
File "renpy/common/00keymap.rpy", line 487, in
python hide:
File "renpy/common/00keymap.rpy", line 511, in _execute_python_hide
renpy.save("reload-1", "reload save game")
File "/home/arch/RenPy/renpy-8.2.0-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 "/home/arch/RenPy/renpy-8.2.0-sdk/renpy/loadsave.py", line 417, in save
dump((roots, renpy.game.log), logf)
File "/home/arch/RenPy/renpy-8.2.0-sdk/renpy/compat/pickle.py", line 103, in dump
pickle.dump(o, f, pickle.HIGHEST_PROTOCOL if highest else PROTOCOL)
TypeError: cannot pickle '_io.FileIO' object (perhaps renpy.game.log.log[107].stores['store']['STOCKFISH_ENGINE'].transport.getstate()[1]['_extra']['subprocess']._waitpid_lock = <unlocked _thread.lock object at 0x7c9125b6cf60>)

Linux-6.10.3-zen1-2-zen-x86_64-with-glibc2.40 x86_64
Ren'Py 8.2.3.24061702
Adventures 0.8
Sun Aug 11 17:54:59 2024

Unexpcted Error

When I choose Player vs. Computer -> Medium -> White, it occurred an error.

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 671, 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 "F:\renpy-8.2.3-sdk\renpy\ast.py", line 1971, in execute
    self.call("execute")
  File "F:\renpy-8.2.3-sdk\renpy\ast.py", line 1953, in call
    return renpy.statements.call(method, parsed, *args, **kwargs)
  File "F:\renpy-8.2.3-sdk\renpy\statements.py", line 349, in call
    return method(parsed, *args, **kwargs)
  File "renpy/common/000statements.rpy", line 671, in execute_call_screen
    store._return = renpy.call_screen(name, *args, **kwargs)
  File "F:\renpy-8.2.3-sdk\renpy\exports.py", line 3420, in call_screen
    rv = renpy.ui.interact(mouse="screen", type="screen", roll_forward=roll_forward)
  File "F:\renpy-8.2.3-sdk\renpy\ui.py", line 301, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
  File "F:\renpy-8.2.3-sdk\renpy\display\core.py", line 2166, 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 "F:\renpy-8.2.3-sdk\renpy\display\core.py", line 2688, in interact_core
    root_widget.visit_all(lambda d : d.per_interact())
  File "F:\renpy-8.2.3-sdk\renpy\display\displayable.py", line 431, in visit_all
    d.visit_all(callback, seen)
  File "F:\renpy-8.2.3-sdk\renpy\display\displayable.py", line 431, in visit_all
    d.visit_all(callback, seen)
  File "F:\renpy-8.2.3-sdk\renpy\display\displayable.py", line 431, in visit_all
    d.visit_all(callback, seen)
  File "F:\renpy-8.2.3-sdk\renpy\display\screen.py", line 480, in visit_all
    callback(self)
  File "F:\renpy-8.2.3-sdk\renpy\display\core.py", line 2688, in <lambda>
    root_widget.visit_all(lambda d : d.per_interact())
  File "F:\renpy-8.2.3-sdk\renpy\display\screen.py", line 491, in per_interact
    self.update()
  File "F:\renpy-8.2.3-sdk\renpy\display\screen.py", line 697, 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'

Windows-10-10.0.19041 AMD64
Ren'Py 8.2.3.24061702
chess 1.0
Thu Aug 22 19:10:12 2024

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.