C# How To Generate A Tournament Bracket Html Table
Solution 1:
Here's my attempt. I have tested the code for 2, 3, and 4 Round Tournaments. The outputs for a 2-Round and 3-Round tournament are shown here:
I have used the same model that you provided to define a Match
. I have added a Tournament
class to generate test data.
Match.cs - The class containing the models
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace tournament
{
publicclassMatch
{
public int id { get; set; }
public int teamid1 { get; set; }
public int teamid2 { get; set; }
public int roundnumber { get; set; }
public int winner { get; set; }
public Match(int id, int teamid1, int teamid2, int roundnumber, int winner)
{
this.id = id;
this.teamid1 = teamid1;
this.teamid2 = teamid2;
this.roundnumber = roundnumber;
this.winner = winner;
}
}
publicclassTournament
{
public SortedList<int, SortedList<int, Match>> TournamentRoundMatches { get; privateset; }
public Match ThirdPlaceMatch { get; privateset; }
public Tournament(int rounds)
{
this.TournamentRoundMatches = new SortedList<int, SortedList<int, Match>>();
this.GenerateTournamentResults(rounds);
if (rounds > 1)
{
this.GenerateThirdPlaceResult(rounds);
}
}
public void AddMatch(Match m)
{
if (this.TournamentRoundMatches.ContainsKey(m.roundnumber))
{
if (!this.TournamentRoundMatches[m.roundnumber].ContainsKey(m.id))
{
this.TournamentRoundMatches[m.roundnumber].Add(m.id, m);
}
}
else
{
this.TournamentRoundMatches.Add(m.roundnumber, new SortedList<int, Match>());
this.TournamentRoundMatches[m.roundnumber].Add(m.id, m);
}
}
private void GenerateTournamentResults(int rounds)
{
Random WinnerRandomizer = new Random();
for (int round = 1, match_id = 1; round <= rounds; round++)
{
int matches_in_round = 1 << (rounds - round);
for (int round_match = 1; round_match <= matches_in_round; round_match++, match_id++)
{
int team1_id;
int team2_id;
int winner;
if (round == 1)
{
team1_id = (match_id * 2) - 1;
team2_id = (match_id * 2);
}
else
{
int match1 = (match_id - (matches_in_round * 2) + (round_match - 1));
int match2 = match1 + 1;
team1_id = this.TournamentRoundMatches[round - 1][match1].winner;
team2_id = this.TournamentRoundMatches[round - 1][match2].winner;
}
winner = (WinnerRandomizer.Next(1, 3) == 1) ? team1_id : team2_id;
this.AddMatch(new Match(match_id, team1_id, team2_id, round, winner));
}
}
}
private void GenerateThirdPlaceResult(int rounds)
{
Random WinnerRandomizer = new Random();
int semifinal_matchid1 = this.TournamentRoundMatches[rounds - 1].Keys.ElementAt(0);
int semifinal_matchid2 = this.TournamentRoundMatches[rounds - 1].Keys.ElementAt(1);
Match semifinal_1 = this.TournamentRoundMatches[rounds - 1][semifinal_matchid1];
Match semifinal_2 = this.TournamentRoundMatches[rounds - 1][semifinal_matchid2];
int semifinal_loser1 = (semifinal_1.winner == semifinal_1.teamid1) ? semifinal_1.teamid2 : semifinal_1.teamid1;
int semifinal_loser2 = (semifinal_2.winner == semifinal_2.teamid1) ? semifinal_2.teamid2 : semifinal_2.teamid1;
int third_place_winner = (WinnerRandomizer.Next(1, 3) == 1) ? semifinal_loser1 : semifinal_loser2;
this.ThirdPlaceMatch = new Match((1 << rounds) + 1, semifinal_loser1, semifinal_loser2, 1, third_place_winner);
}
}
}
I have generated the raw HTML dynamically using the static method GenerateHTMLResultsTable
. This was done using only <table>
without any need for <div>
blocks.
Program.cs - The static Program class that initializes test data and generates the HTML
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace tournament
{
class Program
{
static string GenerateHTMLResultsTable(Tournament tournament)
{
int match_white_span;
int match_span;
int position_in_match_span;
int column_stagger_offset;
int effective_row;
int col_match_num;
int cumulative_matches;
int effective_match_id;
int rounds = tournament.TournamentRoundMatches.Count;
int teams = 1 << rounds;
int max_rows = teams << 1;
StringBuilder HTMLTable = new StringBuilder();
HTMLTable.AppendLine("<styletype=\"text/css\">");
HTMLTable.AppendLine(" .thd {background: rgb(220,220,220); font: bold 10pt Arial; text-align: center;}");
HTMLTable.AppendLine(" .team {color: white; background: rgb(100,100,100); font: bold 10pt Arial; border-right: solid 2px black;}");
HTMLTable.AppendLine(" .winner {color: white; background: rgb(60,60,60); font: bold 10pt Arial;}");
HTMLTable.AppendLine(" .vs {font: bold 7pt Arial; border-right: solid 2px black;}");
HTMLTable.AppendLine(" td, th {padding: 3px15px; border-right: dotted 2pxrgb(200,200,200); text-align: right;}");
HTMLTable.AppendLine(" h1 {font: bold 14pt Arial; margin-top: 24pt;}");
HTMLTable.AppendLine("</style>");
HTMLTable.AppendLine("<h1>Tournament Results</h1>");
HTMLTable.AppendLine("<tableborder=\"0\" cellspacing=\"0\">");
for (int row = 0; row <= max_rows; row++)
{
cumulative_matches = 0;
HTMLTable.AppendLine(" <tr>");
for (int col = 1; col <= rounds + 1; col++)
{
match_span = 1 << (col + 1);
match_white_span = (1 << col) - 1;
column_stagger_offset = match_white_span >> 1;
if (row == 0)
{
if (col <= rounds)
{
HTMLTable.AppendLine(" <thclass=\"thd\">Round " + col + "</th>");
}
else
{
HTMLTable.AppendLine(" <thclass=\"thd\">Winner</th>");
}
}
else if (row == 1)
{
HTMLTable.AppendLine(" <tdclass=\"white_span\" rowspan=\"" + (match_white_span-column_stagger_offset) + "\"> </td>");
}
else
{
effective_row = row + column_stagger_offset;
if (col <= rounds)
{
position_in_match_span = effective_row % match_span;
position_in_match_span = (position_in_match_span == 0) ? match_span : position_in_match_span;
col_match_num = (effective_row / match_span) + ((position_in_match_span < match_span) ? 1 : 0);
effective_match_id = cumulative_matches + col_match_num;
if ((position_in_match_span == 1) && (effective_row % match_span == position_in_match_span))
{
HTMLTable.AppendLine(" <tdclass=\"white_span\" rowspan=\"" + match_white_span + "\"> </td>");
}
else if ((position_in_match_span == (match_span >> 1)) && (effective_row % match_span == position_in_match_span))
{
HTMLTable.AppendLine(" <tdclass=\"team\">Team " + tournament.TournamentRoundMatches[col][effective_match_id].teamid1 + "</td>");
}
else if ((position_in_match_span == ((match_span >> 1) + 1)) && (effective_row % match_span == position_in_match_span))
{
HTMLTable.AppendLine(" <tdclass=\"vs\" rowspan=\"" + match_white_span + "\">VS</td>");
}
else if ((position_in_match_span == match_span) && (effective_row % match_span == 0))
{
HTMLTable.AppendLine(" <tdclass=\"team\">Team " + tournament.TournamentRoundMatches[col][effective_match_id].teamid2 + "</td>");
}
}
else
{
if (row == column_stagger_offset + 2)
{
HTMLTable.AppendLine(" <tdclass=\"winner\">Team " + tournament.TournamentRoundMatches[rounds][cumulative_matches].winner + "</td>");
}
else if (row == column_stagger_offset + 3)
{
HTMLTable.AppendLine(" <tdclass=\"white_span\" rowspan=\"" + (match_white_span-column_stagger_offset) + "\"> </td>");
}
}
}
if (col <= rounds)
{
cumulative_matches += tournament.TournamentRoundMatches[col].Count;
}
}
HTMLTable.AppendLine(" </tr>");
}
HTMLTable.AppendLine("</table>");
HTMLTable.AppendLine("<h1>Third Place Results</h1>");
HTMLTable.AppendLine("<tableborder=\"0\" cellspacing=\"0\">");
HTMLTable.AppendLine(" <tr>");
HTMLTable.AppendLine(" <thclass=\"thd\">Round 1</th>");
HTMLTable.AppendLine(" <thclass=\"thd\">Third Place</th>");
HTMLTable.AppendLine(" </tr>");
HTMLTable.AppendLine(" <tr>");
HTMLTable.AppendLine(" <tdclass=\"white_span\"> </td>");
HTMLTable.AppendLine(" <tdclass=\"white_span\" rowspan=\"2\"> </td>");
HTMLTable.AppendLine(" </tr>");
HTMLTable.AppendLine(" <tr>");
HTMLTable.AppendLine(" <tdclass=\"team\">Team " + tournament.ThirdPlaceMatch.teamid1 + "</td>");
HTMLTable.AppendLine(" </tr>");
HTMLTable.AppendLine(" <tr>");
HTMLTable.AppendLine(" <tdclass=\"vs\">VS</td>");
HTMLTable.AppendLine(" <tdclass=\"winner\">Team " + tournament.ThirdPlaceMatch.winner + "</td>");
HTMLTable.AppendLine(" </tr>");
HTMLTable.AppendLine(" <tr>");
HTMLTable.AppendLine(" <tdclass=\"team\">Team " + tournament.ThirdPlaceMatch.teamid2 + "</td>");
HTMLTable.AppendLine(" <tdclass=\"white_span\"> </td>");
HTMLTable.AppendLine(" </tr>");
HTMLTable.AppendLine("</table>");
return HTMLTable.ToString();
}
static void Main(string[] args)
{
Tournament Test3RoundTournament = new Tournament(3);
Tournament Test2RoundTournament = new Tournament(2);
File.WriteAllText(@"C:\Tournament\results.html", GenerateHTMLResultsTable(Test2RoundTournament));
File.WriteAllText(@"C:\Tournament\results.html", GenerateHTMLResultsTable(Test3RoundTournament));
Console.ReadLine();
}
}
}
UPDATE
Explanation of Parameters Used to Generate the HTML Table
As you can see, the column_stagger_offset
is the amount by which each column is shifted up to align them the way they are supposed to. The effective_row
is essentially where the particular table cell would have been had there been no vertical shift. Knowing the effective_row
and the position_in_match_span
helps determine what needs to be shown in that particuar cell (blank, team1, team2, or vs.).
As you've noticed, I am iterating over the columns one row at a time. That seems most natural considering that HTML tables are also constructed that way, i.e. create row, add cells ... create row, add cels ... and so on.
Solution 2:
We can implement this using System.Web.UI.WebControls.Table by dynamically adding table rows and table cells.
Class File
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
///<summary>/// Summary description for Matches///</summary>publicclassRounds
{
publicint RoundNumber{get;set;}
public List<Match> Matches{get;set;}
publicRounds(int number, List<Match> matches)
{
this.RoundNumber = number;
this.Matches = matches;
}
}
publicclassMatch
{
publicint MatchId{get;set;}
public Team Team1{get;set;}
public Team Team2 {get; set;}
public Team WinningTeam { get; set; }
publicMatch(int id, Team t1, Team t2) :this (id, t1, t2, null)
{
}
publicMatch(int id, Team t1, Team t2, Team t3)
{
this.MatchId = id;
this.Team1 = t1;
this.Team2 = t2;
this.WinningTeam = t3;
}
}
publicclassTeam
{
publicint TeamId {get;set;}
publicstring TeamName {get;set;}
publicTeam(int id, string name)
{
this.TeamId = id;
this.TeamName = name;
}
}
.aspx.cs file - We need to add a div control in .aspx file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial classTest : System.Web.UI.Page
{
List<Rounds> rounds = newList<Rounds>();
protectedvoidPage_Load(object sender, EventArgs e)
{
ShowRoundMatchesUsingTable();
}
private List<Rounds> GetRoundMatchesDetails()
{
List<Team> teamList = newList<Team>();
teamList.Add(newTeam(1, "Arcenal"));
teamList.Add(newTeam(2, "Barsa"));
teamList.Add(newTeam(3, "Manchester"));
teamList.Add(newTeam(4, "Black Burn"));
teamList.Add(newTeam(5, "Ferrari"));
teamList.Add(newTeam(6, "Adidas"));
teamList.Add(newTeam(7, "Reebock"));
teamList.Add(newTeam(8, "Nike"));
List<Match> matchList1 = newList<Match>();
matchList1.Add(newMatch(1, teamList.Find(lst => lst.TeamName == "Arcenal"), teamList.Find(lst => lst.TeamName == "Barsa")));
matchList1.Add(newMatch(1, teamList.Find(lst => lst.TeamName == "Manchester"), teamList.Find(lst => lst.TeamName == "Black Burn")));
matchList1.Add(newMatch(1, teamList.Find(lst => lst.TeamName == "Ferrari"), teamList.Find(lst => lst.TeamName == "Adidas")));
matchList1.Add(newMatch(1, teamList.Find(lst => lst.TeamName == "Reebock"), teamList.Find(lst => lst.TeamName == "Nike")));
List<Match> matchList2 = newList<Match>();
matchList2.Add(newMatch(2, teamList.Find(lst => lst.TeamName == "Arcenal"), teamList.Find(lst => lst.TeamName == "Manchester")));
matchList2.Add(newMatch(2, teamList.Find(lst => lst.TeamName == "Adidas"), teamList.Find(lst => lst.TeamName == "Nike")));
List<Rounds> rounds = newList<Rounds>();
rounds.Add(newRounds(1, matchList1));
rounds.Add(newRounds(2, matchList2));
return rounds;
}
privatevoidShowRoundMatchesUsingTable()
{
IEnumerable<Rounds> roundsList = GetRoundMatchesDetails();
if (roundsList == null || roundsList.Count() == 0) return;
Tabletbl=newTable();
TableRowtrHeaderRow=newTableRow();
TableRowtrDetailRow=newTableRow();
TableCelltcDetails=newTableCell();
foreach (Rounds round in roundsList)
{
TableHeaderCellth=newTableHeaderCell();
th.Text = "Round : " + round.RoundNumber ;
trHeaderRow.Cells.Add(th);
if (round.Matches != null && round.Matches.Count > 0)
{
tcDetails = newTableCell();
trDetailRow.Cells.Add(tcDetails);
}
foreach (Match m in round.Matches)
{
TabledtlTable=newTable();
tcDetails.Controls.Add(dtlTable);
TableRowtr1=newTableRow();
TableCelltc=newTableCell();
tc.Text = m.Team1.TeamName;
tr1.Cells.Add(tc);
dtlTable.Rows.Add(tr1);
tr1 = newTableRow();
tc = newTableCell();
tc.Text = "Vs";
tr1.Cells.Add(tc);
dtlTable.Rows.Add(tr1);
tr1 = newTableRow();
tc = newTableCell();
tc.Text = m.Team2.TeamName;
tr1.Cells.Add(tc);
dtlTable.Rows.Add(tr1);
}
}
tbl.Rows.Add(trHeaderRow);
tbl.Rows.Add(trDetailRow);
div.Controls.Add(tbl);
}
}
Post a Comment for "C# How To Generate A Tournament Bracket Html Table"