|
|
@ -4,7 +4,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
-export([start_link/0, init/1, handle_cast/2, handle_call/3]).
|
|
|
|
-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() ->
|
|
|
|
start_link() ->
|
|
|
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
|
|
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
|
|
@ -13,12 +13,6 @@ init([]) ->
|
|
|
|
rand:seed(default),
|
|
|
|
rand:seed(default),
|
|
|
|
{ok, []}.
|
|
|
|
{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(1, Original, Constructed) -> lists:append(Original, Constructed);
|
|
|
|
duplicate(N, Original, Constructed) -> duplicate(N-1, Original, 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) ->
|
|
|
|
hash_teams_list(Teams) ->
|
|
|
|
[ Y || <<X:4>> <= crypto:hash(sha, Teams), Y <- integer_to_list(X,16)].
|
|
|
|
[ 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) ->
|
|
|
|
init_db(File) ->
|
|
|
|
IsFile = filelib:is_regular(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, 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]},
|
|
|
|
ok = sqlite3:create_table(Database, matches, [{division, integer, [not_null]},
|
|
|
|
{round, text, [not_null]},
|
|
|
|
{round, text, [not_null]},
|
|
|
|
{size, integer, [not_null]},
|
|
|
|
{size, integer, [not_null]},
|
|
|
@ -60,7 +61,12 @@ init_db(File) ->
|
|
|
|
{red_2, text, [not_null]},
|
|
|
|
{red_2, text, [not_null]},
|
|
|
|
{blue_1, text, [not_null]},
|
|
|
|
{blue_1, text, [not_null]},
|
|
|
|
{blue_2, 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]},
|
|
|
|
ok = sqlite3:create_table(Database, match_scores, [{division, integer, [not_null]},
|
|
|
|
{round, text, [not_null]},
|
|
|
|
{round, text, [not_null]},
|
|
|
|
{size, integer, [not_null]},
|
|
|
|
{size, integer, [not_null]},
|
|
|
@ -81,10 +87,19 @@ init_db(File) ->
|
|
|
|
{state, blob, [not_null]}],
|
|
|
|
{state, blob, [not_null]}],
|
|
|
|
[{primary_key, [division, round, size, teams, number, seed, time]},
|
|
|
|
[{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"}}]),
|
|
|
|
{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).
|
|
|
|
sqlite3:close(Database).
|
|
|
|
|
|
|
|
|
|
|
|
write(DatabaseFile, Division, Round, Seed, Matches, Teams) ->
|
|
|
|
write(DatabaseFile, Division, Round, Seed, Matches, Teams) ->
|
|
|
|
MatchList = generate(Seed, Matches, Teams),
|
|
|
|
MatchList = create_schedule(Seed, Matches, Teams),
|
|
|
|
Schedule = [[{division, Division},
|
|
|
|
Schedule = [[{division, Division},
|
|
|
|
{round, atom_to_list(Round)},
|
|
|
|
{round, atom_to_list(Round)},
|
|
|
|
{size, Matches},
|
|
|
|
{size, Matches},
|
|
|
@ -96,11 +111,12 @@ write(DatabaseFile, Division, Round, Seed, Matches, Teams) ->
|
|
|
|
{red_1, R1},
|
|
|
|
{red_1, R1},
|
|
|
|
{red_2, R2}] || {N, [B1, B2, R1, R2]} <- lists:enumerate(MatchList)],
|
|
|
|
{red_2, R2}] || {N, [B1, B2, R1, R2]} <- lists:enumerate(MatchList)],
|
|
|
|
{ok, Database} = sqlite3:open(anonymous, [{file, DatabaseFile}]),
|
|
|
|
{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).
|
|
|
|
ok = sqlite3:close(Database).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
generate(Seed, Matches, Teams) ->
|
|
|
|
create_schedule(Seed, Matches, Teams) ->
|
|
|
|
TeamsRepeated = duplicate(Matches, Teams),
|
|
|
|
TeamsRepeated = duplicate(Matches, Teams),
|
|
|
|
TeamsPadded = TeamsRepeated ++ lists:duplicate(padding(length(Teams)*Matches), padding),
|
|
|
|
TeamsPadded = TeamsRepeated ++ lists:duplicate(padding(length(Teams)*Matches), padding),
|
|
|
|
rand:seed(default, Seed),
|
|
|
|
rand:seed(default, Seed),
|
|
|
@ -123,5 +139,9 @@ pick_matches(Teams, Matches) ->
|
|
|
|
|
|
|
|
|
|
|
|
pick_matches(Teams) -> pick_matches(Teams, []).
|
|
|
|
pick_matches(Teams) -> pick_matches(Teams, []).
|
|
|
|
|
|
|
|
|
|
|
|
handle_call(Req, _, State) ->
|
|
|
|
handle_cast(_, State) -> {noreply, State}.
|
|
|
|
{reply, Req, 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}.
|
|
|
|