20th
I basically did the same as most others: a beam search. First at depth 8 for my opponent to estimate when the game will end. Then for myself in the remaining time.
With about 150k single simulation steps and a beam width of 1200 this gets me around 15 turns lookahead.
As you don’t want to read yet another beam search description, I’ll go with my inventory storage in a 4 byte integer.
I use 5 bit for each tier, which gives a number range from -16 to +15 each. And an extra bit as a buffer to prevent overflows. For faster access I store the total as well.
The free spots in this layout are the 0s.
Negative numbers are stored as complement. This applying a spell or brew on the inventory just becomes an addition followed by an AND operation to remove possible overflow bits.
public static int CreateInventory(int[] delta)
{
int result = 0;
for (int i = 0; i < delta.Length; i++)
result |= (1 << (6 * i)) * (delta[i] & 0x1F); // this also works for negative numbers
result |= delta.Sum() << 24;
return result;
}
public static bool IsValidInventory(int inv)
{
if ((inv & 0b010000_010000_010000_010000) > 0) return false; // negative
if (inv > (Player.INVENTORY_SIZE + 1) << 24) return false; // full
return true;
}
private void ApplyDelta(int delta)
{
Inventory += delta;
Inventory &= 0b001111_001111_001111_001111_001111;
}