Sprinkfield level difficulty
We already wrote about the difficulties of finding the best solution for a given level. When it had turned out that manually designed levels could be tested for solvability and searched for the best solution in an automated way, using a programme algorithm, our next idea was to automate the process of level creation itself. Levels are generated according to a number of parameters: size; the number of rocky fields, dry fields and fertilized fields; difficulty etc.
To tackle level difficulty, we developed a formula but, as it was found out during beta testing, it was not accurate enough. It needed to be modified. In this post we will tell you about our beta test experiences with the formula and that what changes we have applied.
What makes a level difficult?
We can only answer this rather subjective question based on our own gaming experiences. Still, let’s see the objective considerations that might be important in terms of difficulty:
- The higher the number of possible starting moves in a given level, the smaller the chance is that we actually start with the good one.
- The more moves (the higher number of sprinklers) a certain solution involves, the harder to find that solution.
- We have also noticed, that finding the solution becomes extremely tough if it does not involve the largest possible move. (Players like to fill the available space and tend to go for the largest move.)
- We also felt it was a difficulty factor that how many valid moves could lead to a given field. If there are many possible moves in a level, it results in a high number of possible variations (such representation of the levels is called a histogram).
Based on this, we wrote a formula, where a smaller calculated result meant a more difficult level. In code, it looked like this:
(4.0 * moves.size()) / (1.0 * bestKnownSolution.size() * (1 + largestPossibleMove - largestMadeMove) * histogram);
Another good indicator for difficulty is the time spent solving a givel level. The test results were as follows:
The X-axis represents the levels (free levels of the Puzzle mode from 1 to 20), the Y-axis represents the required time in seconds. Results by different testers are in different colours.
We can see that some beta testers got stuck at level 4 already, then levels 12 and 13 also caused problems, as well as the final levels. We wanted tough final levels, but this we succeded in all too well.
All in all, we gained several conclusions concerning game difficulty:
- the difficulty of a level is also relative to the player; and
- there is a random factor too when a player gets stuck with a bad start (pattern), from which it is very hard to get out.
Based on our experiences from beta testing, we decided to modify the first 20 levels.
New version with new levels
We wanted to publish an update for the game with a new „Easy“ level pack, however, our formula was not suitable for generating equally easy levels.
It was alsmost impossible to weigh the parameters and we could not extend the formula either, so we reconsidered it. We came up with a new formula where level difficulty values fell in a range of 1 to 100 (the more difficult a level was, the higher value it had). Now, this formula could be extended and it was easy to weigh the parameters.
We set a minimum and a maximum value for each parameter and thus the final calculated value could be limited to the range of 0 to 1.
We believe that the difficulty of a level depends on the following parameters:
- The number of available sprinklers (i.e. the minimal number of moves in which a level can be solved);
- The number of scarecrows on non-isolated fields, plus in how many moves we deployed all of the pigs, plus how many scarecrows have a maximum of 1 adjacent square that cannot be used (i.e. rocky field or level border);
- How large each good move is compared to the largest possible move (we calculate with the largest difference);
- The number of fields other than the basic field type (ie. usually other than crop fields). In other words, the more objects (rocky or dry fields etc.) a level has, the tougher that is;
- How many step-backs it takes the solution algorithm to find the best solution (because the solution code uses a smart algorithm and thus more step-backs suggest a more difficult level);
- The number of possible solutions for a given level (it is a key parameter above all other parameters).
Here is an excerpt from the code with the modified new formula:
final double solutionLengthScore = (Math.max(2.0, Math.min(10.0, bestKnownSolution.moves.size())) - 2) / 8.0; final double freeScarecrowScore = (Math.min(11.0, 1.0 * (scarecrows - isolatedAreas) + pigMoves + cornerScarecrows)) / 11.0; final double moveSizeDifferenceScore = (Math.min(3.0, 1.0 * largestMoveDifference)) / 3.0; final double areaScore = (Math.max(3.0, Math.min(10.0, rocks + groundArea + dryArea + pigFreeWater - Math.max(Math.max(Math.max(rocks, groundArea), dryArea), pigFreeWater))) - 3) / 7.0; final double backtrackScore = -1/(0.032 * (nodes - bestKnownSolution.moves.size()) + 1) + 1; final double solutionCountScore = 9.0 / (1.0 * numberOfSolutions + 8.0); return ( (0.3 * solutionLengthScore + 0.25 * freeScarecrowScore + 0.125 * moveSizeDifferenceScore + 0.175 * areaScore + 0.15 * backtrackScore) * Math.pow(solutionCountScore, 0.25) ) * 100.0;
Our experiences with this formula have been positive so far, we only had to finetune the weights of the parameters.