diff --git a/index.html b/index.html index c366719..dc48643 100644 --- a/index.html +++ b/index.html @@ -19,6 +19,7 @@ let member = 0; const ROUND = 3; let MAX_MEMBER = 0; + const SAMPLE_ROUND = 10; const data = []; async function processForm(e) { if (e.preventDefault) e.preventDefault(); @@ -51,8 +52,6 @@ member++; } MAX_MEMBER = Math.ceil(member / GROUP); - // console.log(`${member} members`); - // console.log(data); // Insert database sheet const out_wb = xlsx.utils.book_new(); @@ -62,26 +61,12 @@ "database" ); - // Insert Group Assign Sheet - // if (!("group_assign" in workbook.Sheets)) { - // console.log("Creating group_assign sheet"); - // } else { - // xlsx.utils.book_append_sheet( - // out_wb, - // workbook.Sheets["group_assign"], - // "group_assign" - // ); - // } - const { groups, group_leaders } = random_group(); + const { groups, group_for_member, group_leaders } = random_group(); create_group_assign_sheet(out_wb); - assign_group(out_wb, groups); + insert_group_to_wb(out_wb, group_for_member); - // TODO: handle group leader sheet does not exist - // if (!("leader_group" in workbook.Sheets)) { - // console.log("Creating leader_group sheet"); - // } create_group_leader_sheet(out_wb); - assign_group_leader(out_wb, group_leaders); + insert_group_leader_to_wb(out_wb, group_leaders); // if (!("control" in workbook.Sheets)) { // console.log("Creating control sheet"); @@ -154,50 +139,87 @@ } /** - * Generate random group - * @returns {number[][]} + * Random best possible group + * @returns {{groups: number[][], group_leaders: string[][], err: number}} */ function random_group() { - const groups = Array.from({ length: member }, (_, i) => []); + const samples = []; + for (let i = 0; i < SAMPLE_ROUND || samples.length === 0; i++) { + const { groups, group_for_member, group_leaders } = sample_group(); + if (!validate_group(groups)) continue; + const err = calculate_error_score(groups); + samples.push({ groups, group_for_member, group_leaders, err }); + } + const min_err = Math.min(...samples.map((s) => s.err)); + const idx = samples.findIndex((s) => s.err === min_err); + if (idx === -1) console.warn("No valid group"); + else console.log(`Minimum error of group: ${min_err}`); + return samples[idx]; + } + + /** + * Generate random group and return 3 values + * 1. Group indexes by group number + * 2. Group indexes by member number + * 3. Group leaders by group number + * @returns {{groups: Object[][], group_for_member: number[][], group_leaders: string[][]}} + */ + function sample_group() { + const group_for_member = Array.from({ length: member }, (_, i) => []); shuffle(data); const group_leaders = Array.from({ length: GROUP }, (_, i) => Array.from({ length: DAY }, (_, i) => "") ); - const G = Array.from({ length: ROUND + 1 }, (_, i) => []); - const cat = Array.from({ length: GROUP }, (_, i) => []); + const groups = Array.from({ length: GROUP }, (_, i) => []); + const cat = Array.from({ length: ROUND + 1 }, (_, i) => []); data.forEach((d, i) => { const leader_round = d.leader_round; - if (!leader_round) G[ROUND].push(d); - else G[leader_round - 1].push(d); + if (!leader_round) cat[ROUND].push(d); + else cat[leader_round - 1].push(d); }); for (let g = 0; g < GROUP; g++) { for (let r = 0; r < ROUND; r++) { - cat[g].push(G[r][g]); for (let d = 0; d < DAY; d++) { const group_id = calculate_group_id(g, r, d); if ( - G[r][g].leader_round && - Math.floor(d / 2) === G[r][g].leader_round - 1 + cat[r][g].leader_round && + Math.floor(d / 2) === cat[r][g].leader_round - 1 ) { if (group_leaders[g][d]) console.warn("Duplicate leader"); - group_leaders[g][d] = G[r][g].names; + group_leaders[g][d] = cat[r][g].names; } - groups[G[r][g].id - 1].push(group_id); + groups[group_id - 1].push(cat[r][g]); + group_for_member[cat[r][g].id - 1].push(group_id); } } - if (g < G[ROUND].length) { - cat[g].push(G[ROUND][g]); + if (g < cat[ROUND].length) { for (let d = 0; d < DAY; d++) { - groups[G[ROUND][g].id - 1].push(calculate_group_id(g, ROUND, d)); + const group_id = calculate_group_id(g, ROUND, d); + groups[group_id - 1].push(cat[ROUND][g]); + group_for_member[cat[ROUND][g].id - 1].push(group_id); } } } return { groups, + group_for_member, group_leaders, }; } + function calculate_error_score(groups) { + return 0; + } + + /** + * Returns true if group is valid + * @param {Object[][]} groups + * @returns {boolean} + */ + function validate_group(groups) { + return true; + } + /** * Calculate group id * @param {number} g @@ -239,18 +261,10 @@ * Assign group to group assign sheet * @param {xlsx.WorkBook} wb */ - function assign_group(wb, groups) { + function insert_group_to_wb(wb, groups) { xlsx.utils.sheet_add_aoa(wb.Sheets["group_assign"], groups, { origin: "E2", }); - - // console.log(group_leaders); - // xlsx.utils.sheet_add_aoa(wb.Sheets["leader_group"], group_leaders, { - // origin: "B2", - // }); - // const group_leaders_aoa = generate_group_leader_aoa(group_leaders); - // const leader_ws = xlsx.utils.aoa_to_sheet(group_leaders_aoa); - // xlsx.utils.book_append_sheet(wb, leader_ws, "leader_group"); } /** @@ -258,8 +272,8 @@ * @param {xlsx.WorkBook} wb * @param {string[][]} group_leaders */ - function assign_group_leader(wb, group_leaders) { - xlsx.utils.sheet_add_aoa(wb.Sheets["leader_group"], group_leaders, { + function insert_group_leader_to_wb(wb, group_leaders) { + xlsx.utils.sheet_add_aoa(wb.Sheets["group_leader"], group_leaders, { origin: "B2", }); }