# Bash Shell Script: Building a Better March Madness Bracket

Last year, I wrote an article for Linux Journal titled "Building Your March Madness Bracket" My article was timely, arriving just in time for the "March Madness" college basketball series. You see, I don't follow college basketball (or really, any sports at all), but I do like to participate in office pools. And every year, it seems my office likes to fill out the March Madness brackets to see who can best predict the outcomes.

Since I don't follow college basketball, I am not a good judge of which teams might perform better than others. But fortunately, the NCAA ranks the teams for you, so I wrote a Bash script that filled out my March Madness bracket for me. Since teams were ranked 1–16, I used a "D16" method borrowed from tabletop gaming. I thought this was an elegant method to predict the outcomes.

But, there's a bug in my script. Specifically, there's an error in a key assumption for the D16 algorithm, so I'd like to correct that with an improved March Madness script here.

### Let's Review What Went Wrong

My Bash script predicted the outcome of a match by comparing the ranking of each team. So, you can throw a D16 "die" to determine if team A wins and another D16 "die" to determine if team B loses, or vice versa. If the two throws agree, you know the outcome of the game: team A wins and team B loses, or team A loses and team B wins.

I asserted that a #1 team should be a strong team, so I assumed the #1 team had 15 out of 16 "chances" to win, and one out of 16 "chances" to lose. Without any other inputs, the #1 ranked team would win if its D16 throw is two or greater, and the #1 team could lose only if the D16 value was one. With that assumption, I wrote this function:

function guesswinner {
rankA=\$1
rankB=\$2

d16A=\$(( ( \$RANDOM % 16 ) + 1 ))
d16B=\$(( ( \$RANDOM % 16 ) + 1 ))

if [ \$d16A -gt \$rankA -a \$d16B -le \$rankB ] ; then
# team A wins and team B loses
return \$rankA
elif [ \$d16A -le \$rankA -a \$d16B -gt \$rankB ] ; then
# team A loses and team B wins
return \$rankB
else
# no winner
return 0
fi
}

In the guesswinner function, each D16 roll generates a random number 1–16. If the rank of team A is "rankA" and the rank of team B is "rankB," and the D16 roll for team A is "A" and the roll for team B is "B," the function tests two D16 rolls like this:

• If A greater than rankA (team A wins) and B less than or equal to rankB (team B loses), then team A wins.

• If A less than or equal to rankA (team A loses) and B greater rankB (team B wins), then team B wins.

But look at what happens if team A is ranked #1 and team B is ranked #16. Team A will always win:

• A roll 1–16 will have a 15 out of 16 chance to be greater than 1 (team A wins), and a 1–16 roll will always be less than or equal to 16 (team B loses).

• A roll 1–16 will have a 1 out of 16 chance to be less than or equal to 1 (team A loses) but a 1–16 roll will never be greater than 16 (team B wins).

______________________

Jim Hall is an advocate for free and open-source software, best known for his work on the FreeDOS Project, and he also focuses on the usability of open-source software. Jim is the Chief Information Officer at Ramsey County, Minn.