|  |  |  | @ -4,7 +4,7 @@ | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | -export([start_link/0, init/1, handle_cast/2, handle_call/3]). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | -export([remove/2, generate/3, write/6, pick_teams/2, pick_matches/1, hash_teams_list/1, init_db/1]). | 
		
	
		
			
				|  |  |  |  | -export([init_db/2, generate/2]). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | start_link() -> | 
		
	
		
			
				|  |  |  |  |   gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). | 
		
	
	
		
			
				
					|  |  |  | @ -13,12 +13,6 @@ init([]) -> | 
		
	
		
			
				|  |  |  |  |   rand:seed(default), | 
		
	
		
			
				|  |  |  |  |   {ok, []}. | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | handle_cast(_, State) -> | 
		
	
		
			
				|  |  |  |  |   {noreply, State}. | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | remove(List, Index) -> | 
		
	
		
			
				|  |  |  |  |   [X || {I, X} <- lists:enumerate(0, List), I /= Index]. | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | duplicate(1, Original, Constructed) -> lists:append(Original, Constructed); | 
		
	
		
			
				|  |  |  |  | duplicate(N, Original, Constructed) -> duplicate(N-1, Original, lists:append(Original, Constructed)). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -46,10 +40,17 @@ fill_padding_schedule(Matches, Teams) -> | 
		
	
		
			
				|  |  |  |  | hash_teams_list(Teams) -> | 
		
	
		
			
				|  |  |  |  |   [ Y || <<X:4>> <= crypto:hash(sha, Teams), Y <- integer_to_list(X,16)]. | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | generate(Process, {DatabaseFile, Division, Round, Seed, Matches, Teams}) -> gen_server:call(Process, {new_schedule, DatabaseFile, Division, Round, Seed, Matches, Teams}). | 
		
	
		
			
				|  |  |  |  | init_db(Process, DatabaseFile) -> gen_server:call(Process, {init_db, DatabaseFile}). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | init_db(File) -> | 
		
	
		
			
				|  |  |  |  |   IsFile = filelib:is_regular(File), | 
		
	
		
			
				|  |  |  |  |   if IsFile -> file:delete(File) end, | 
		
	
		
			
				|  |  |  |  |   if IsFile -> file:delete(File); | 
		
	
		
			
				|  |  |  |  |      true -> true end, | 
		
	
		
			
				|  |  |  |  |   {ok, Database} = sqlite3:open(anonymous, [{file, File}]), | 
		
	
		
			
				|  |  |  |  |   ok = sqlite3:create_table(Database, teams, [{name, text, [not_null]}, | 
		
	
		
			
				|  |  |  |  |                                               {inspection, blob}], | 
		
	
		
			
				|  |  |  |  |                             [{primary_key, [name]}]), | 
		
	
		
			
				|  |  |  |  |   ok = sqlite3:create_table(Database, matches, [{division, integer, [not_null]}, | 
		
	
		
			
				|  |  |  |  |                                                 {round, text, [not_null]}, | 
		
	
		
			
				|  |  |  |  |                                                 {size, integer, [not_null]}, | 
		
	
	
		
			
				
					|  |  |  | @ -60,7 +61,12 @@ init_db(File) -> | 
		
	
		
			
				|  |  |  |  |                                                 {red_2, text, [not_null]}, | 
		
	
		
			
				|  |  |  |  |                                                 {blue_1, text, [not_null]}, | 
		
	
		
			
				|  |  |  |  |                                                 {blue_2, text, [not_null]}], | 
		
	
		
			
				|  |  |  |  |                            [{primary_key, [division, round, size, teams, number, seed]}]), | 
		
	
		
			
				|  |  |  |  |                            [{primary_key, [division, round, size, teams, number, seed]}, | 
		
	
		
			
				|  |  |  |  |                             {check, "round IN ('practice', 'qualification', 'elimination')"}, | 
		
	
		
			
				|  |  |  |  |                             {foreign_key, {[blue_1], teams, [name], "ON DELETE RESTRICT"}}, | 
		
	
		
			
				|  |  |  |  |                             {foreign_key, {[blue_2], teams, [name], "ON DELETE RESTRICT"}}, | 
		
	
		
			
				|  |  |  |  |                             {foreign_key, {[red_1], teams, [name], "ON DELETE RESTRICT"}}, | 
		
	
		
			
				|  |  |  |  |                             {foreign_key, {[red_2], teams, [name], "ON DELETE RESTRICT"}}]), | 
		
	
		
			
				|  |  |  |  |   ok = sqlite3:create_table(Database, match_scores, [{division, integer, [not_null]}, | 
		
	
		
			
				|  |  |  |  |                                               {round, text, [not_null]}, | 
		
	
		
			
				|  |  |  |  |                                               {size, integer, [not_null]}, | 
		
	
	
		
			
				
					|  |  |  | @ -81,10 +87,19 @@ init_db(File) -> | 
		
	
		
			
				|  |  |  |  |                                               {state, blob, [not_null]}], | 
		
	
		
			
				|  |  |  |  |                             [{primary_key, [division, round, size, teams, number, seed, time]}, | 
		
	
		
			
				|  |  |  |  |                              {foreign_key, {[division, round, size, teams, number, seed], matches, [division, round, size, teams, number, seed], "ON DELETE CASCADE"}}]), | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   % TODO: finals | 
		
	
		
			
				|  |  |  |  |   % ok = sqlite3:create_table(Database, finals, [], [{primary_key, []}]), | 
		
	
		
			
				|  |  |  |  |   ok = sqlite3:create_table(Database, skills_scores, [{team, text, [not_null]}, | 
		
	
		
			
				|  |  |  |  |                                                       {type, text, [not_null]}, | 
		
	
		
			
				|  |  |  |  |                                                       {attempt, integer, [not_null]}, | 
		
	
		
			
				|  |  |  |  |                                                       {score, blob, [not_null]}], | 
		
	
		
			
				|  |  |  |  |                             [{primary_key, [team, type, attempt]}, | 
		
	
		
			
				|  |  |  |  |                              {foreign_key, {[team], teams, [name], "ON DELETE CASCADE"}}]), | 
		
	
		
			
				|  |  |  |  |   sqlite3:close(Database). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | write(DatabaseFile, Division, Round, Seed, Matches, Teams) -> | 
		
	
		
			
				|  |  |  |  |   MatchList = generate(Seed, Matches, Teams), | 
		
	
		
			
				|  |  |  |  |   MatchList = create_schedule(Seed, Matches, Teams), | 
		
	
		
			
				|  |  |  |  |   Schedule = [[{division, Division}, | 
		
	
		
			
				|  |  |  |  |                {round, atom_to_list(Round)}, | 
		
	
		
			
				|  |  |  |  |                {size, Matches}, | 
		
	
	
		
			
				
					|  |  |  | @ -96,11 +111,12 @@ write(DatabaseFile, Division, Round, Seed, Matches, Teams) -> | 
		
	
		
			
				|  |  |  |  |                {red_1, R1}, | 
		
	
		
			
				|  |  |  |  |                {red_2, R2}] || {N, [B1, B2, R1, R2]} <- lists:enumerate(MatchList)], | 
		
	
		
			
				|  |  |  |  |   {ok, Database} = sqlite3:open(anonymous, [{file, DatabaseFile}]), | 
		
	
		
			
				|  |  |  |  |   [ok | _] = sqlite3:write_many(Database, matches, Schedule), | 
		
	
		
			
				|  |  |  |  |   [ok | Resp] = sqlite3:write_many(Database, matches, Schedule), | 
		
	
		
			
				|  |  |  |  |   ok = lists:last(Resp), | 
		
	
		
			
				|  |  |  |  |   ok = sqlite3:close(Database). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | generate(Seed, Matches, Teams) -> | 
		
	
		
			
				|  |  |  |  | create_schedule(Seed, Matches, Teams) -> | 
		
	
		
			
				|  |  |  |  |   TeamsRepeated = duplicate(Matches, Teams), | 
		
	
		
			
				|  |  |  |  |   TeamsPadded = TeamsRepeated ++ lists:duplicate(padding(length(Teams)*Matches), padding), | 
		
	
		
			
				|  |  |  |  |   rand:seed(default, Seed), | 
		
	
	
		
			
				
					|  |  |  | @ -123,5 +139,9 @@ pick_matches(Teams, Matches) -> | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | pick_matches(Teams) -> pick_matches(Teams, []). | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | handle_call(Req, _, State) -> | 
		
	
		
			
				|  |  |  |  |   {reply, Req, State}. | 
		
	
		
			
				|  |  |  |  | handle_cast(_, State) -> {noreply, State}. | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | handle_call({init_db, DatabaseFile}, _, State) -> | 
		
	
		
			
				|  |  |  |  |   {reply, init_db(DatabaseFile), State}; | 
		
	
		
			
				|  |  |  |  | handle_call({new_schedule, DatabaseFile, Division, Round, Seed, Matches, Teams}, _, State) -> | 
		
	
		
			
				|  |  |  |  |   {reply, write(DatabaseFile, Division, Round, Seed, Matches, Teams), State}. | 
		
	
	
		
			
				
					|  |  |  | 
 |