Using this code, I've searched up to $15×15$ and $6×65$. Improved memory management is required to go further. The only large (not $2×n$) boards on which the minimal move is winning in this range are $6×11$, $6×15$, and $6×27$.
Per my answer on the linked question, there are a finite number of boards $m×n$ for which the minimal move is winning for every $m$, so I conjecture that these are all the $6×n$ boards.
#include <iostream>
#include <unordered_map>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
#include <iterator>
std::unordered_map<std::string, bool> cache;
std::string getCacheString(std::vector<int> const &game){
std::ostringstream ss;
std::copy(game.begin(), game.end()-1, std::ostream_iterator<int>(ss, ","));
ss << game.back();
return ss.str();
}
int checkCache(std::vector<int> const &game){
std::string str = getCacheString(game);
if (cache.find(str) != cache.end()){
return cache[str];
}
return 2;
}
void addCache(std::vector<int> const &game, bool result){
std::string str = getCacheString(game);
// std::cout << "Added " << str << " to cache: " << result << std::endl;
cache[str] = result;
}
bool checkGame(std::vector<int> game);
bool checkMove(std::vector<int> game, int x, int y){
if (y == 0){
while (x < game.size()){
game.pop_back();
}
} else {
for (int i = x; i < game.size(); i++){
game[i] = y < game[i] ? y : game[i];
}
}
int prevScore = checkCache(game);
if (prevScore == 2){
return checkGame(game);
}
return prevScore;
}
bool checkGame(std::vector<int> game){
for (int i = 0; i < game.size(); i++){
for (int j = 0; j < game[i]; j++){
if (i == 0 && j == 0) continue;
if (!checkMove(game, i, j)){
addCache(game, true);
return true;
}
}
}
addCache(game, false);
return false;
}
int main(){
cache["1"] = false;
for (int i = 3; i < 1000; i++){
bool result = checkGame({i, i, i, i, i, i-1});
std::cout << i << ": " << result << std::endl;
}
}
```