# Optimizing odds calculator

I am trying to setup an odds calculator for a best of 7 series, given independent odds for each event.

The following code works, but I would like to add recursion to simplify the end.

public class Game
{
public int No { get; set; }
public List<decimal> Odds;

public Game(int no, decimal odd1, decimal odd2)
{
No = no;

Odds = new List<decimal>();

}

}

void Main()
{

var games = new List<Game>();

var homeodd = .6m;
var awayodd = .4m;

var winningOdds = 0m;

//Add  7 games each with a different odd of winning game

//game one has 2 possible outcomes, 0 = win, 1 = loss =>same for all 7 games
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 2; k++)
{
for (int l = 0; l < 2; l++)
{
for (int m = 0; m < 2; m++)
{
for (int n = 0; n < 2; n++)
{
for (int o = 0; o < 2; o++)
{
if ((i+j+k+l+m+n+o)<4)  //if we have loss less than 4 games, we have won the series and we want to add the odds of that possibility to the total odds
{
winningOdds += games[0].Odds[i] * games[1].Odds[j] * games[2].Odds[k] * games[3].Odds[l] * games[4].Odds[m] * games[5].Odds[n] * games[6].Odds[o];
}
}
}
}
}
}
}
}

Console.WriteLine(winningOdds);
}

• This is messy. You have Game class defined twice and some code directly in the class definition. Write it in a way, so that people don't have to think what you meant. Oct 22, 2013 at 13:09
• good catch, stupid cut and paste screwed me first time Oct 22, 2013 at 13:16
• can you give some sample input and some expected results? there must be a better way to do this then to use all those for statements. what is inside the if statement will only run when all the variables are =0 . is that intended?
– Malachi
Oct 22, 2013 at 13:37
• for (int ii = 0; ii < Math.Pow(2, games.Count()); ii++) { var result = Convert.ToString(ii, 2); result = "00000000".Substring(0, 7-result.Length) + result; var flag = new List<int>(); for (int i2 = 0; i2 < games.Count (); i2++) { flag.Add(int.Parse(result.Substring(i2,1))); } if (flag.Sum() < 4) { winningOdds2 += games[0].Odds[flag[0]] * games[1].Odds[flag[1]] * games[2].Odds[flag[2]] * games[3].Odds[flag[3]] * games[4].Odds[flag[4]] * games[5].Odds[flag[5]] * games[6].Odds[flag[6]]; } } Oct 22, 2013 at 14:06
• All the FOR loops can be replaced with this.... I just need to linq the multiplying line now Oct 22, 2013 at 14:07

Basically, what you need is a Cartesian product of 7 sequences, each containing a 0 and a 1. Eric Lippert has an interesting article about doing just that using LINQ (note: I think you could make his code more efficient using immutable collections). If you use his method, your code could look something like:

var product = CartesianProduct(Enumerable.Repeat(new[] { 0, 1 }, games.Count));

foreach (var indexes in product)
{
if (indexes.Sum() < 4)
{
winningOdds += indexes
.Select((index, game) => games[game].Odds[index])
.Aggregate((x, y) => x * y);
}
}


This is a clean as I can make it. The last thing I could do would be to replace the hardcoded 7 by a const to make it a little easier to setup best of 5, best of 3, etc...

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication10
{
internal class Program
{
private static void Main(string[] args)
{
var games = new List<Game>();

const decimal homeodd = .6m;
const decimal awayodd = .4m;

var winningOdds2 = 0m;

for (var ii = 0; ii < Math.Pow(2, games.Count()); ii++)
{
var result = Convert.ToString(ii, 2);
result = "00000000".Substring(0, 7 - result.Length) + result;

var flag = new List<int>();

for (var i2 = 0; i2 < games.Count(); i2++)
{
}

if (flag.Sum() >= 4) continue;
var product = 1m;
for (var p = 0; p < 7; p++)
{
product = product * games[p].Odds[flag[p]];
}
winningOdds2 += product;
}

Console.WriteLine(winningOdds2);
}
}
}

public class Game
{
public int No { get; set; }

public List<decimal> Odds;

public Game(int no, decimal odd1)
{
No = no;
Odds = new List<decimal> {odd1, 1-odd1};
}
}

// Define other methods and classes here

• 1. I would be very careful about using double as the loop variable. 2. If you want to add zero padding to a string, you can use PadLeft(), it's much more readable than your solution. 3. Instead of using digits in a string, I would rather access the bits directly using % and / or bitwise operators and shifts. Oct 22, 2013 at 14:38
• I dont know how to directly access the bits, quick example please ? Oct 22, 2013 at 14:54
• If you're okay with accessing the bits from least significant to most significant (basically, right to left), then it's something like while (i != 0) { int currentBit = i % 2; ...; i /= 2; }. Oct 22, 2013 at 15:01