Applying AI for Game Balance Testing: DNN Victory Prediction and Genetic Algorithm Optimization
This article details a practical AI-driven workflow for a turn‑based card game, covering problem background, data modeling with a DNN victory‑prediction network, reinforcement‑learning‑based data generation, and a genetic‑algorithm search to identify the strongest and weakest team compositions.
The project is a research‑stage turn‑based card game that required systematic balance testing of card line‑ups. Each line‑up consists of seven cards, each with four equipment slots and up to four attribute‑modifying sub‑entries, creating a massive combinatorial space.
To provide actionable balance insights, the team needed a method to automatically evaluate the strength of any given line‑up, generate daily reports of the strongest and weakest configurations, and do so with minimal development overhead.
Two feasible approaches were explored. The first leveraged online logs from live servers, but suffered from sparse data and limited coverage for new cards, equipment, or attributes. The second proposed a fully automated pipeline:
Use reinforcement learning to train an AI agent that plays the in‑game battles, producing large volumes of synthetic combat logs.
Train a deep neural network (DNN) on these logs to predict battle outcomes (win/loss or win probability).
Apply a genetic‑algorithm‑based search, using the DNN as a fitness evaluator, to rank line‑ups and output the top‑N strongest and weakest teams.
The DNN was implemented with Keras. An early version used an embedding layer followed by dense layers and a sigmoid output for binary classification:
model = Sequential() model.add(Embedding(max_features, 128, input_length=8)) model.add(Flatten()) model.add(Dense(128, activation='relu', name='Dense_1')) model.add(Dense(1, activation='relu', name='Dense_2')) model.add(Dense(1, activation='sigmoid')) model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])Later refinements switched to a softmax output for win‑rate prediction and replaced Adam with SGD for better convergence:
model = Sequential() model.add(Embedding(max_features, 128, input_length=14, name='embedding', embeddings_initializer='uniform')) model.add(Flatten()) model.add(Dense(256, activation='relu', name='Dense_0', kernel_initializer='random_uniform')) model.add(Dense(128, activation='relu', name='Dense_1', kernel_initializer='random_uniform')) model.add(Dense(2, activation='softmax', name='Dense_2', kernel_initializer='random_uniform')) sgd = tf.keras.optimizers.SGD(lr=0.01, decay=1e-5, momentum=0.9, nesterov=True) model.compile(loss='sparse_categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])The genetic algorithm maintains a population (e.g., 500 individuals), evaluates each individual's fitness by summing win probabilities against all other individuals (using batch predictions for efficiency), and iteratively applies mutation and limited crossover to evolve stronger line‑ups. Memory‑leak mitigation was added by reloading the model every 50 generations.
Experimental results showed that when only card IDs were used, the fitness sum stabilized around 92 after 100 generations. Including equipment attributes increased the fitness sum to around 425 after 200 generations, indicating the larger search space challenges. The best‑found line‑up achieved a 98.4% win rate against random opponents, confirming the pipeline’s practical value.
Future work includes replacing the handcrafted battle logic with a reinforcement‑learning‑trained AI, refining attribute weighting (e.g., speed may not be maximal), scaling the genetic search to explore the full 10^25‑plus space, and adding parallelism and more sophisticated crossover operators.
NetEase LeiHuo Testing Center
LeiHuo Testing Center provides high-quality, efficient QA services, striving to become a leading testing team in China.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.