Playing the Diablo1 using Deep Learning — Series 1

Dohyeong Kim
5 min readMay 25, 2022
Image From WallpaperAccess

The Diablo series is one of the most famous rogue-like games. Recently, AI development for this kind of game has begun starting from the announcement of the NetHack Learning Environment on Facebook.

Finding a platform for AI research of commercial games is not an easy task. Not only do many companies not share the code of games, but they were mostly developed for the Windows OS.

Fortunately, we can find a fully playable open-source game under the name DevilutionX for the Diablo1 game.

The DevilutionX is created using C ++ and SDL2 based on the graphic and sound assets of Diablo1. It would be convenient if there is a reference for binding that kind of game with Python. Luckily, there is already a similar project called ViZDoom that has the Python API for AI research.

The source code for this post is available from my GitHub https://github.com/kimbring2/RPG_RL/tree/main/Twini-Golf.

Structure of ViZDoom

Analysis of ViZDoom code should be done as the first step to remove many obstacles that would be appeared while writing the code for Diablo.

Code Component of ViZDoom

The most important thing about binding in C ++ and Python is to build a bridge between the C ++ SDL2 game and the program for Python binding. In the ViZDoom case, the Shared Memory method is used to exchange states such as screen frame and game status. Otherwise, the Message Queue is used to exchange actions such as character moving and menu selection.

Implementing for simple SDL2 game

Trying to implement the Python binding method for a simple game is good rather than just starting with a complex game. Therefore, ViZDoom code is first ported to the game called TwinGolf made with C ++ SDL2.

Python API demo for TwinGolf

1. Folder Structure

C ++ code needs to be built before running, unlike Python. The building option can be set via the CMakeLists.txt file commonly. Especially, this project requires multiple CMakeLists.txt files because there is C ++ code for the game, as well as for the Python binding.

First, let’s take a look at the tree of the entire project before writing the CMakeLists.txt file. The C ++ project using CMakeLists.txt has an src folder where it has C++ files to be built. Another CMakeLists.txt, src folder needs to be added under the src folder of the main project directory.

Root Folder of Main Project

In this project, two separate C++ projects are located under the src folder of the project main folder. The first one is for the golf game itself and another one is for the python binding program. The lib folder contains the libraries for other projects.

Src Folder of Main Project

The root folder of the VizGolf folder has the CMakeList.txt file and the src folder for building the game source code.

Root Folder of TwinGolf game

The root folder of another subproject, lib_python, also has a separate CMakeLists.txt and src folder to build. The res folder stores asset files for graphics and sounds of the game.

Root Folder of Python Binding

Finally, the lib folder does not have a CMakeLists.txt and src folder because it is not needed to build. However, it has the C ++ code for importing the C ++ function, struct, and enum from Python, and communicating by the shared memory and memory queue.

Lib Folder

2. Writing the CMakeLists.txt

After placing the files for each subproject, the CMakeLists.txt need to be created to build them. The first file is located under the root folder of the main project. There is no command for creating a C ++ executable or shared library file.

CMakeLists.txt of the main project

Next, the CMakeLists.txt file of the game folder needs to set the location of the C++ file for game making and the executable file to run the game program.

CMakeLists.txt for the golf game

The CMakeLists.txt file of Python binding sets the location of the C ++ file to build similar to the previous one. However, an SO file is created that can be imported from Python using the pybind11_add_module command.

CMakeLists.txt for Python binding

3. How to use the pybind11

To use the constant, enum, struct, and class of C ++ generated in Python, it should be converted using the pybind11. The ViZGolfPythonModule.cpp file of the lib_python folder contains that information.

ViZGolfPythonModule.cpp file of lib_python folder

Next, the vector data type of C ++ needs to be converted to a list, or array of Python. The ViZGolfGamePython.cpp file of the lib_python folder convert them.

ViZGolfGamePython.cpp file of lib_python folder

4. How to use the shared memory and memory queue

Game information such as a screen frame, position of the ball, reward, and score can be shared in struct format of C++ through the shared memory library of the C ++ boost. Therefore, the files related to shared memory should be included on both sides.

ViZGolfSharedMemory.h file of vizgolf folder

The memory queue of C ++ boost memory queue of the C ++ boost library is used to send and receive information such as the action information for swinging the ball or the end of the animation. Like a shared memory, the game and python binding program contain files for that. However, it can send and receive the C ++ struct as a message.

viz_message_queue.h file of vizgolf folder

5. Using bounded C++ code in Python

Every const, enum, struct, and class can be used in Python after building previous codes together. Game information, as well as control, can be sent and received through Python.

Conclusion

In this post, we see how to use the C ++ SDL2 game in Python scripts. The C ++ code of Diablo1 will be content for the next post for the final goal of this post.

--

--

Dohyeong Kim

I am a Deep Learning researcher. Currently, I am trying to make an AI agent for various situations such as MOBA, RTS, and Soccer games.