12th
I implemented a random search (Monte Carlo).
When starting the turn at a machine, I might use it. Then I go to another machine to use it and to a third one to use that too.
Samples: give score for having samples. Choosing sample ranks is hardcoded. I randomize how many samples I take, as I might want to get samples from the cloud as well.
Diagnosis: first diagnose undiagnosed samples. Then randomize, how many samples to move to the cloud and how many to take. Returning a sample results in a negative score, as it costs time to do so and I prefer to have a sample that I might fill later when the opponent frees molecules.
Molecules: again: random. Take any amount and type of molecules. As it is hard to fill a sample having e.g. 5A (very unlikely that I choose 5A), the probability of taking molecules is not equally distributed, but depends on my own samples, samples in the cloud and carried by the opponent.
Score is awarded for taking a molecule, when only two are left and the enemy needs both.
The available molecules are time-dependent, so that I can simulate the opponent freeing them.
Laboratory: there are only up to 3! = 6 possible combinations to use the samples (assuming that you don’t go away with a sample although you could complete it).
For each of these orders I try to complete them, add expertise if possible and add the molecules back to the molecules. So I decide here, if my random move at molecules was a good idea.
I also check if I blocked the opponent with my chain of molecules:
foreach (Sample s in enemy.Samples) {
if (s.Health == -1)
continue;
List<int> times = new List<int> ();
for (int m = 0; m < MOLECULES_COUNT; m++) {
int cost = s.Cost [m] - enemy.Expertise [m] - enemy.Storage [m];
if (cost <= 0)
continue;
int startTime = -1;
while (startTime + 1 < maxWaitTime && Machine.MOLECULES.Available [m, Math.Min (maxWaitTime - 1, startTime + cost)] >= cost)
startTime++;
for (int i = 0; i < cost; i++) {
times.Add (startTime + i);
}
}
times.Sort ();
for (int i = 0; i < times.Count; i++) {
if (times [i] < i + enemy.ETA && times[i] < 4) {
score += weightBlockChain * (s.Health + weightGainExpertise);
break;
}
}
}
some score is also given for having any molecules left (but not too many, I need free space to fill my own samples), preferably where the opponent has little expertise.
As I didn’t have time to fiddle with the parameters myself, I let the brutaltester try them out for me by randomizing my parameters and compare the results in matches against myself (fully automated).
Keeping all options open when randomizing my action and let the scoring function decide helped to make my bot do actions like collect molecules first and then go to diagnosis and get the sample for my storage or using newly gained expertise when pushing more than one sample without implementing it.
On the last day I added some basic waiting at the laboratory to block, but never found a replay where it happened before the end of the contest. But it worked, as I know now (frame 200).
I also have code to submit undiagnosed samples when I am about to lose anyway (hoping to be lucky), but didn’t get it working in time.