From dd37cf7ef5e480535e4f4a5136292bcec55ecbd9 Mon Sep 17 00:00:00 2001 From: gyboth Date: Thu, 20 Nov 2008 20:20:18 +0000 Subject: [PATCH] Added joined leagues to defs system (e.g. for US conferences). --- src/fixture.c | 155 ++++++++++++++++++++++++++++++++++++-- src/fixture.h | 6 ++ src/free.c | 14 ++++ src/free.h | 3 + src/league.c | 2 +- src/league_struct.h | 18 ++++- src/misc.c | 5 +- src/table.c | 18 +++-- src/team.c | 11 ++- src/team.h | 2 +- src/xml_league.c | 22 ++++++ src/xml_loadsave_league.c | 26 +++++++ 12 files changed, 261 insertions(+), 21 deletions(-) diff --git a/src/fixture.c b/src/fixture.c index 64deef8d..56825316 100644 --- a/src/fixture.c +++ b/src/fixture.c @@ -42,21 +42,58 @@ void fixture_write_league_fixtures(League *league) { - gint round_robins = league->round_robins; - GPtrArray *teams = NULL; + gint i,j; + gint max_rr; + gint joined_clids[league->joined_leagues->len]; + gint joined_rrs[league->joined_leagues->len]; + GPtrArray *teams; + max_rr = league->round_robins; + teams = team_get_pointers_from_array(league->teams, NULL); + g_array_free(league->fixtures, TRUE); league->fixtures = g_array_new(FALSE, FALSE, sizeof(Fixture)); - while(round_robins > 0) + /** Add all teams to the same pointer array. */ + for(i = 0; i < league->joined_leagues->len; i++) { - teams = team_get_pointers_from_array(league->teams); - fixture_write_round_robin((gpointer)league, -1, teams, (round_robins == 1)); - round_robins -= (round_robins > 1) ? 2 : 1; + joined_rrs[i] = g_array_index(league->joined_leagues, JoinedLeague, i).rr; + joined_clids[i] = league_index_from_sid(g_array_index(league->joined_leagues, JoinedLeague, i).sid); + max_rr = MAX(joined_rrs[i], max_rr); + teams = team_get_pointers_from_array(lig(joined_clids[i]).teams, teams); + } + + /** Write fixtures for as many round robins as required by the maximum number of rrs given. */ + for(i = 0; i < max_rr;) + { + fixture_write_round_robin((gpointer)league, -1, misc_copy_ptr_array(teams), (i == max_rr - 1)); + i += (i < max_rr - 1) ? 2 : 1; } + g_ptr_array_free(teams, TRUE); g_array_sort_with_data(league->fixtures, fixture_compare_func, GINT_TO_POINTER(FIXTURE_COMPARE_DATE + 100)); + + if(league->joined_leagues->len > 0) + { + /** Remove fixtures involving only teams from the joined leagues and + for joined leagues with a smaller number of rrs than the maximum. */ + for(i = 0; i < league->joined_leagues->len; i++) + { + if(joined_rrs[i] < max_rr) + fixture_remove_rrs(league->fixtures, league->id, lig(joined_clids[i]).id, max_rr - joined_rrs[i]); + + for(j = i; j < league->joined_leagues->len; j++) + fixture_remove_rrs(league->fixtures, lig(joined_clids[i]).id, lig(joined_clids[j]).id, max_rr); + } + + /** Remove fixtures for reduced number of rrs. */ + if(league->round_robins < max_rr) + fixture_remove_rrs(league->fixtures, league->id, league->id, max_rr - league->round_robins); + + /** Move matches to earlier weeks if possible. */ + fixtures_condense(league->fixtures); + } } /** Write the fixtures for the given cup @@ -1419,3 +1456,109 @@ fixture_get_last_scheduled_week(void) return week_nr; } + +/** Remove a number of round robin from a fixture array. + @fixtures: The fixture array. + @clid1: The league id for one team. + @clid2: The league id for the second team. + @to_remove: How many matches to remove per pairing. */ +void +fixture_remove_rrs(GArray *fixtures, gint clid1, gint clid2, gint to_remove) +{ + gint i, j, k; + gint removed; + gint start; + League *league1, *league2; + + league1 = league_from_clid(clid1); + league2 = league_from_clid(clid2); + + for(i = 0; i < league1->teams->len; i++) + { + start = (clid1 == clid2) ? i + 1 : 0; + for(j = start; j < league2->teams->len; j++) + { + removed = 0; + for(k = fixtures->len - 1; k >= 0; k--) + if((g_array_index(fixtures, Fixture, k).teams[0]->id == g_array_index(league1->teams, Team, i).id && + g_array_index(fixtures, Fixture, k).teams[1]->id == g_array_index(league2->teams, Team, j).id) || + (g_array_index(fixtures, Fixture, k).teams[1]->id == g_array_index(league1->teams, Team, i).id && + g_array_index(fixtures, Fixture, k).teams[0]->id == g_array_index(league2->teams, Team, j).id)) + { + g_array_remove_index(fixtures, k); + removed++; + + if(removed == to_remove) + break; + } + } + } +} + +/** Move matches in the fixture array to earlier dates if possible. */ +void +fixtures_condense(GArray *fixtures) +{ + gint i, j, k, l; + GArray *matchday_teams[1000][5]; + Fixture *fix; + gboolean fix_moved; + + fix_moved = TRUE; + + while(fix_moved) + { + fix_moved = FALSE; + + for(i = 0; i < 1000; i++) + for(j = 0; j < 5; j++) + matchday_teams[i][j] = NULL; + + for(i = 0; i < ligs->len; i++) + for(j = 0; j < lig(i).fixtures->len; j++) + { + fix = &g_array_index(lig(i).fixtures, Fixture, j); + if(matchday_teams[fix->week_number - 1][fix->week_round_number - 1] == NULL) + matchday_teams[fix->week_number - 1][fix->week_round_number - 1] = g_array_new(FALSE, FALSE, sizeof(gint)); + + g_array_append_val(matchday_teams[fix->week_number - 1][fix->week_round_number - 1], fix->teams[0]->id); + g_array_append_val(matchday_teams[fix->week_number - 1][fix->week_round_number - 1], fix->teams[1]->id); + } + + + for(i = fixtures->len - 1; i >= 0; i--) + { + fix = &g_array_index(fixtures, Fixture, i); + for(j = 0; j <= fix->week_number - 2; j++) + { + for(k = 0; k < 5; k++) + { + if(matchday_teams[j][k] != NULL) + { + for(l = 0; l < matchday_teams[j][k]->len; l++) + if(g_array_index(matchday_teams[j][k], gint, l) == fix->teams[0]->id || + g_array_index(matchday_teams[j][k], gint, l) == fix->teams[1]->id) + break; + + if(l == matchday_teams[j][k]->len) + { + fix_moved = TRUE; + fix->week_number = j + 1; + fix->week_round_number = k + 1; + g_array_append_val(matchday_teams[j][k], fix->teams[0]->id); + g_array_append_val(matchday_teams[j][k], fix->teams[1]->id); + } + } + } + } + } + + for(i = 0; i < 1000; i++) + for(j = 0; j < 5; j++) + if(matchday_teams[i][j] != NULL) + g_array_free(matchday_teams[i][j], TRUE); + + g_array_sort_with_data(fixtures, fixture_compare_func, + GINT_TO_POINTER(FIXTURE_COMPARE_DATE + 100)); + } +} diff --git a/src/fixture.h b/src/fixture.h index e6e274cc..8209b0e0 100644 --- a/src/fixture.h +++ b/src/fixture.h @@ -162,4 +162,10 @@ fixture_count_matchdays(const GArray *fixtures); gint fixture_get_last_scheduled_week(void); +void +fixture_remove_rrs(GArray *fixtures, gint clid1, gint clid2, gint to_remove); + +void +fixtures_condense(GArray *fixtures); + #endif diff --git a/src/free.c b/src/free.c index b46cf83a..3684c0d4 100644 --- a/src/free.c +++ b/src/free.c @@ -335,6 +335,8 @@ free_league(League *league) if(league->teams != NULL) free_teams_array(&league->teams, FALSE); + free_joined_leagues(&league->joined_leagues); + free_g_array(&league->teams); free_g_array(&league->prom_rel.elements);; @@ -348,6 +350,18 @@ free_league(League *league) free_league_stats(&league->stats); } +/** Free the data in the joined leagues array. */ +void +free_joined_leagues(GArray **joined_leagues) +{ + gint i; + + for(i = 0; i < (*joined_leagues)->len; i++) + free_gchar_ptr(g_array_index(*joined_leagues, JoinedLeague, i).sid); + + free_g_array(joined_leagues); +} + /** Free the league stats. */ void free_league_stats(LeagueStat *stats) diff --git a/src/free.h b/src/free.h index 8ee28d95..e4f84312 100644 --- a/src/free.h +++ b/src/free.h @@ -65,6 +65,9 @@ free_leagues_array(GArray **leagues, gboolean reset); void free_league(League *league); +void +free_joined_leagues(GArray **joined_leagues); + void free_teams_array(GArray **teams, gboolean reset); diff --git a/src/league.c b/src/league.c index 7d64aec9..84c4d050 100644 --- a/src/league.c +++ b/src/league.c @@ -67,8 +67,8 @@ league_new(gboolean new_id) new.prom_rel.elements = g_array_new(FALSE, FALSE, sizeof(PromRelElement)); new.teams = g_array_new(FALSE, FALSE, sizeof(Team)); - new.fixtures = g_array_new(FALSE, FALSE, sizeof(Fixture)); + new.joined_leagues = g_array_new(FALSE, FALSE, sizeof(JoinedLeague)); new.table = table_new(); new.table.clid = new.id; diff --git a/src/league_struct.h b/src/league_struct.h index c8f5efc1..3b6d522d 100644 --- a/src/league_struct.h +++ b/src/league_struct.h @@ -77,6 +77,19 @@ typedef struct gchar *prom_games_cup_sid; } PromRel; +/** + A structure describing a different league joined to the current one + in the sense that there are matches played between teams from both leagues + like in the US conference system. +*/ +typedef struct +{ + /** Sid of the joined league. */ + gchar *sid; + /** How many round robins to schedule. */ + gint rr; +} JoinedLeague; + /** Representation of a league. @see PromRel @@ -105,7 +118,7 @@ typedef struct there should be two matches in a week instead of one. */ GArray *two_match_weeks[2]; /** How many round robins are played. Important for - small leagues with 10 teams or so. Default: 1. */ + small leagues with 10 teams or so. Default: 2. */ gint round_robins; /** Number of weeks between the parts of a round robin. */ gint rr_break; @@ -117,6 +130,9 @@ typedef struct /** Array of teams in the league. @see Team */ GArray *teams; + /** List of leagues joined fixture-wise to this one. + @see JoinedLeague */ + GArray *joined_leagues; /** League table. @see Table */ Table table; diff --git a/src/misc.c b/src/misc.c index c1af1051..d4c708d9 100644 --- a/src/misc.c +++ b/src/misc.c @@ -116,8 +116,7 @@ misc_separate_strings(gchar *string) return string_array; } -/** Write a pointer array randomly into another one and free - the original one. +/** Write a pointer array randomly into another one and free the original array. @param array The array to randomise. @return A new pointer array containing the items in random order. */ GPtrArray* @@ -512,7 +511,7 @@ misc_string_replace_expressions(gchar *string) gchar *occurrence = NULL, *occurrence2 = NULL; - if(debug > 100) + if(debug > 200) g_print("misc_string_replace_expressions: #%s#\n", string); diff --git a/src/table.c b/src/table.c index ae5c14a9..ee4fb85b 100644 --- a/src/table.c +++ b/src/table.c @@ -110,14 +110,16 @@ table_update_get_elements(TableElement **elements, const Fixture *fix) if(fix->clid < ID_CUP_START) { - table = &league_from_clid(fix->clid)->table; - for(i=0;ielements->len;i++) - { - if(g_array_index(table->elements, TableElement, i).team == fix->teams[0]) - elements[0] = &g_array_index(table->elements, TableElement, i); - else if(g_array_index(table->elements, TableElement, i).team == fix->teams[1]) - elements[1] = &g_array_index(table->elements, TableElement, i); - } + for(j = 0; j < 2; j++) + { + table = &league_from_clid(fix->teams[j]->clid)->table; + + for(i=0;ielements->len;i++) + { + if(g_array_index(table->elements, TableElement, i).team == fix->teams[j]) + elements[j] = &g_array_index(table->elements, TableElement, i); + } + } } else for(i=0;iclid)->len;i++) diff --git a/src/team.c b/src/team.c index c09508b5..2be3c9fa 100644 --- a/src/team.c +++ b/src/team.c @@ -183,9 +183,10 @@ query_team_is_in_cup(const Team *tm, const Cup *cup) /** Return a GPtrArray containing the pointers to the teams from the teams array. @param teams The teams array we use. + @param team_ptrs NULL or a pointer array we append to @return A GPtrArray containing pointers to the teams. */ GPtrArray* -team_get_pointers_from_array(const GArray *teams) +team_get_pointers_from_array(const GArray *teams, GPtrArray *team_ptrs) { gint i; GPtrArray *team_pointers = g_ptr_array_new(); @@ -193,6 +194,14 @@ team_get_pointers_from_array(const GArray *teams) for(i=0;ilen;i++) g_ptr_array_add(team_pointers, (gpointer)&g_array_index(teams, Team, i)); + if(team_ptrs != NULL) + { + for(i = 0; i < team_ptrs->len; i++) + g_ptr_array_add(team_pointers, g_ptr_array_index(team_ptrs, i)); + + g_ptr_array_free(team_ptrs, TRUE); + } + return team_pointers; } diff --git a/src/team.h b/src/team.h index ee67be14..9275befb 100644 --- a/src/team.h +++ b/src/team.h @@ -59,7 +59,7 @@ gboolean query_team_is_in_cup(const Team *tm, const Cup *cup); GPtrArray* -team_get_pointers_from_array(const GArray *teams); +team_get_pointers_from_array(const GArray *teams, GPtrArray *team_ptrs); Team* team_of_id(gint id); diff --git a/src/xml_league.c b/src/xml_league.c index b0e0122a..6b9f35b6 100644 --- a/src/xml_league.c +++ b/src/xml_league.c @@ -52,6 +52,7 @@ #define TAG_NAMES_FILE "names_file" #define TAG_ACTIVE "active" #define TAG_BREAK "break" +#define TAG_JOINED_LEAGUE "joined_league" #define TAG_PROM_REL "prom_rel" #define TAG_PROM_GAMES "prom_games" #define TAG_PROM_GAMES_DEST_SID "prom_games_dest_sid" @@ -73,6 +74,8 @@ #define TAG_TWO_MATCH_WEEK_START "two_match_week_start" #define TAG_TWO_MATCH_WEEK_END "two_match_week_end" +#define ATT_NAME_JOINED_LEAGUE_RR "rr" + /** * Enum with the states used in the XML parser functions. */ @@ -110,6 +113,7 @@ enum XmlLeagueStates STATE_TEAM_AVERAGE_TALENT, STATE_TEAM_DEF_FILE, STATE_BREAK, + STATE_JOINED_LEAGUE, STATE_TWO_MATCH_WEEK_START, STATE_TWO_MATCH_WEEK_END, STATE_END @@ -139,6 +143,7 @@ xml_league_read_start_element (GMarkupParseContext *context, { PromRelElement new_element; Team new_team; + JoinedLeague new_joined_league; if(strcmp(element_name, TAG_LEAGUE) == 0) { @@ -171,6 +176,17 @@ xml_league_read_start_element (GMarkupParseContext *context, state = STATE_ACTIVE; else if(strcmp(element_name, TAG_BREAK) == 0) state = STATE_BREAK; + else if(strcmp(element_name, TAG_JOINED_LEAGUE) == 0) + { + state = STATE_JOINED_LEAGUE; + new_joined_league.sid = NULL; + if(attribute_names[0] != NULL && strcmp(attribute_names[0], ATT_NAME_JOINED_LEAGUE_RR) == 0) + new_joined_league.rr = (gint)g_ascii_strtod(attribute_values[0], NULL); + else + new_joined_league.rr = 2; + + g_array_append_val(new_league.joined_leagues, new_joined_league); + } else if(strcmp(element_name, TAG_TWO_MATCH_WEEK_START) == 0) state = STATE_TWO_MATCH_WEEK_START; else if(strcmp(element_name, TAG_TWO_MATCH_WEEK_END) == 0) @@ -252,6 +268,7 @@ xml_league_read_end_element (GMarkupParseContext *context, strcmp(element_name, TAG_NAMES_FILE) == 0 || strcmp(element_name, TAG_ACTIVE) == 0 || strcmp(element_name, TAG_BREAK) == 0 || + strcmp(element_name, TAG_JOINED_LEAGUE) == 0 || strcmp(element_name, TAG_TWO_MATCH_WEEK_START) == 0 || strcmp(element_name, TAG_TWO_MATCH_WEEK_END) == 0 || strcmp(element_name, TAG_PROM_REL) == 0 || @@ -336,6 +353,11 @@ xml_league_read_text (GMarkupParseContext *context, new_league.active = int_value; else if(state == STATE_BREAK) new_league.rr_break = int_value; + else if(state == STATE_JOINED_LEAGUE) + misc_string_assign( + &g_array_index(new_league.joined_leagues, + JoinedLeague, + new_league.joined_leagues->len - 1).sid, buf); else if(state == STATE_TWO_MATCH_WEEK_START) g_array_append_val(new_league.two_match_weeks[0], int_value); else if(state == STATE_TWO_MATCH_WEEK_END) diff --git a/src/xml_loadsave_league.c b/src/xml_loadsave_league.c index 8556957f..03f4029b 100644 --- a/src/xml_loadsave_league.c +++ b/src/xml_loadsave_league.c @@ -54,6 +54,8 @@ enum TAG_LEAGUE_PROM_REL_ELEMENT_DEST_SID, TAG_LEAGUE_PROM_REL_ELEMENT_TYPE, TAG_LEAGUE_BREAK, + TAG_LEAGUE_JOINED_LEAGUE_SID, + TAG_LEAGUE_JOINED_LEAGUE_RR, TAG_LEAGUE_TWO_MATCH_WEEK_START, TAG_LEAGUE_TWO_MATCH_WEEK_END, TAG_END @@ -74,7 +76,10 @@ xml_loadsave_league_start_element (GMarkupParseContext *context, gint i; gint tag = xml_get_tag_from_name(element_name); gboolean valid_tag = FALSE; + JoinedLeague new_joined_league; + new_joined_league.sid = NULL; + for(i=TAG_LEAGUE;ijoined_leagues, new_joined_league); + if(!valid_tag) g_warning("xml_loadsave_league_start_element: unknown tag: %s; I'm in state %d\n", element_name, state); @@ -112,6 +120,8 @@ xml_loadsave_league_end_element (GMarkupParseContext *context, tag == TAG_LEAGUE_LAYER || tag == TAG_LEAGUE_ACTIVE || tag == TAG_LEAGUE_BREAK || + tag == TAG_LEAGUE_JOINED_LEAGUE_SID || + tag == TAG_LEAGUE_JOINED_LEAGUE_RR || tag == TAG_LEAGUE_TWO_MATCH_WEEK_START || tag == TAG_LEAGUE_TWO_MATCH_WEEK_END || tag == TAG_LEAGUE_AVERAGE_TALENT || @@ -194,6 +204,15 @@ xml_loadsave_league_text (GMarkupParseContext *context, new_league->active = int_value; else if(state == TAG_LEAGUE_BREAK) new_league->rr_break = int_value; + else if(state == TAG_LEAGUE_JOINED_LEAGUE_SID) + misc_string_assign( + &g_array_index(new_league->joined_leagues, + JoinedLeague, + new_league->joined_leagues->len - 1).sid, buf); + else if(state == TAG_LEAGUE_JOINED_LEAGUE_RR) + g_array_index(new_league->joined_leagues, + JoinedLeague, + new_league->joined_leagues->len - 1).rr = int_value; else if(state == TAG_LEAGUE_TWO_MATCH_WEEK_START) g_array_append_val(new_league->two_match_weeks[0], int_value); else if(state == TAG_LEAGUE_TWO_MATCH_WEEK_END) @@ -289,6 +308,13 @@ xml_loadsave_league_write(const gchar *prefix, const League *league) xml_write_int(fil, league->yellow_red, TAG_YELLOW_RED, I0); xml_write_int(fil, league->active, TAG_LEAGUE_ACTIVE, I0); xml_write_int(fil, league->rr_break, TAG_LEAGUE_BREAK, I0); + + for(i = 0; i < league->joined_leagues->len; i++) + { + xml_write_string(fil, g_array_index(league->joined_leagues, JoinedLeague, i).sid, TAG_LEAGUE_JOINED_LEAGUE_SID, I0); + xml_write_int(fil, g_array_index(league->joined_leagues, JoinedLeague, i).rr, TAG_LEAGUE_JOINED_LEAGUE_RR, I0); + } + xml_write_float(fil, league->average_talent, TAG_LEAGUE_AVERAGE_TALENT, I0); for(i=0;itwo_match_weeks[0]->len;i++)