This wouldn't be too hard to implement.
Essentially you could do it something like (in C++)
using Move = std::pair<int, int>;
using Moves = std::vector<Moves>;
using Results = std::pair<int, int>; // wins, losses
using MoveMap = std::map<Move, Results>;
using MoveMaps = std::vector<MoveMap>;
using MoveProbability = std::map<Move, float>;
using MoveProbabilities = std::vector<MoveProbability>;
struct Game { Moves moves; bool iWon; };
using Games = std::vector<Game>;
MoveProbabilities calculateProbabilities(const Games& games)
{
MoveMaps moveMaps;
for(const auto& game : games)
{
moveMaps.resize(game.moves.size());
for(unsigned int i = 0; i < game.moves.size(); ++i)
{
auto& results = moveMaps[i][game.moves[i]];
if(game.iWin)
{
++results.first;
}
else
{
++results.second;
}
}
}
MoveProbabilities moveProbabilities;
moveProbabilities.resize(moveMaps.size());
for(unsigned int i = 0; i < moveMaps.size(); ++i)
{
for(const auto& move : moveMaps[i])
{
const unsigned int total = move.second.first + move.second.second;
moveProbabilities[i][move.first] = move.second.first / total;
}
}
return std::move(moveProbabilities);
}