diff --git a/voting.lua b/voting.lua index 77cf65e..e5d1cbb 100644 --- a/voting.lua +++ b/voting.lua @@ -1,3 +1,5 @@ +local categories = {"Creativity", "Appeal", "Execution", "Use of space"} + -- TODO make a "login" button for the admin screen -- TODO clear admin screen on "quit" event function show_vote_welcome() @@ -15,6 +17,7 @@ function show_vote_welcome() ) end + function show_vote_error(voter, offender) local msg = string.format("%s has tried to cast a vote instead of %s!\nThey also saw %s's votes, they're naughty!", offender, voter, voter) digiline_send("vote", @@ -33,7 +36,26 @@ function show_vote_error(voter, offender) ) end -function show_admin_main() + +function show_admin_welcome() + digiline_send("admin", + { + {command = "clear"}, + {command = "set", + width = 10.5, + height = 11, + real_coordinates = true, + locked = true, + }, + {command = "addlabel", label = "Admin only!", X = 4.4, Y = 1.7}, + {command = "addbutton", name = "edit_entries", label = "Edit entries", X = 3.7, Y = 3.3, W = 3, H = 0.8}, + {command = "addbutton", name = "view_results", label = "View results", X = 3.7, Y = 4.7, W = 3, H = 0.8} + } + ) +end + + +function show_admin_edit() local listentries = table.concat(mem.entries, ",") -- TODO sanitize :p digiline_send("admin", { @@ -48,11 +70,86 @@ function show_admin_main() {command = "addfield", name = "new_entry", label = "New entry", default = "", X = 1.2, Y = 10.4, W = 8.5, H = 0.8}, {command = "addbutton", name = "add_entry", label = "Add entry", X = 9.9, Y = 10.4, W = 1.7, H = 0.8}, {command = "addbutton", name = "delete_entry", label = "Delete selected", X = 12.2, Y = 8, W = 3, H = 0.8}, - {command = "add", element = "field_close_on_enter", name = "new_entry", close_on_enter = false} + {command = "add", element = "field_close_on_enter", name = "new_entry", close_on_enter = false}, + + {command = "addbutton", name = "edit_back", label = "Back", X = 12.2, Y = 10.4, W = 1.7, H = 0.8}, } ) end + +function show_admin_results() + + -- count the votes that we actually cast + -- local total_scores = {} + -- for _,player_votes in pairs(mem.votes) do + -- for entry, cats in pairs(player_votes) do + -- local entry_scores = total_scores[entry] or {} + -- total_scores[entry] = entry_scores + -- for cat, value in pairs(cats) do + -- local cs = (entry_scores[cat] or 0) + value + -- entry_scores[cat] = cs + -- end + -- end + -- end + + local total_scores = {} + for id, e in pairs(mem.entries) do + local entry_scores = {} + total_scores[id] = entry_scores + entry_scores.id = id + for _,player_votes in pairs(mem.votes) do + local entry_votes = player_votes[id] or {} -- nil if didn't cast any votes for this entry + for i=1,4 do + local vote = (entry_votes[i] or 1) -- 1 is the default vote + entry_scores[i] = (entry_scores[i] or 0) + vote + end + end + end + + local sorted_by_str + if mem.sort_type == "sum" then + sorted_by_str = "Sorted by sum:" + table.sort(total_scores, function(a,b) return (a[1] + a[2] + a[3] + a[4]) > (b[1] + b[2] + b[3] + b[4]) end) + elseif type(mem.sort_type) == "number" then + sorted_by_str = string.format("Sorted by '%s':", categories[mem.sort_type]) + local idx = mem.sort_type + table.sort(total_scores, function(a,b) return a[idx] > b[idx] end) + end + + local entry_list = {} + for _, s in ipairs(total_scores) do + local name = mem.entries[s.id] + table.insert(entry_list, string.format("%03d|%03d|%03d|%03d -- %s", s[1], s[2], s[3], s[4], name)) + end + entry_list = table.concat(entry_list, ",") + + + + digiline_send("debug", total_scores) + digiline_send("admin", + { + {command = "clear"}, + {command = "set", + width = 16, + height = 12, + real_coordinates = true, + locked = true, -- does not prevent someone from looking at it :( + }, + {command = "addlabel", label = sorted_by_str, X = 0.9, Y = 0.6}, + {command = "addbutton", name = "results_back", label = "Back", X = 12.7, Y = 0.3, W = 3, H = 1}, + {command = "addtextlist", name = "", listelements = entry_list, transparent = false, selected_id = 1, X = 0.3, Y = 1.5, W = 12.3, H = 9.2}, + {command = "addlabel", label = "Sort by:", X = 13.5, Y = 2.6}, + {command = "addbutton", name = "sort_sum", label = "Sum", X = 12.7, Y = 3.1, W = 3, H = 1}, + {command = "addbutton", name = "sort_1", label = categories[1], X = 12.7, Y = 4.2, W = 3, H = 1}, + {command = "addbutton", name = "sort_2", label = categories[2], X = 12.7, Y = 5.3, W = 3, H = 1}, + {command = "addbutton", name = "sort_3", label = categories[3], X = 12.7, Y = 6.4, W = 3, H = 1}, + {command = "addbutton", name = "sort_4", label = categories[4], X = 12.7, Y = 7.5, W = 3, H = 1}, + } + ) +end + + function show_vote_ballot(username) local c = { @@ -100,11 +197,13 @@ end if event.type == "program" then show_vote_welcome() - show_admin_main() + show_admin_welcome() mem.username = nil mem.entries = mem.entries or {"first"} mem.admin_entries_idx = nil mem.votes = mem.votes or {} + mem.state_admin = "welcome" + mem.sort_type = "sum" elseif event.type == "digiline" then if event.channel == "vote" then if event.msg.start then @@ -132,36 +231,71 @@ elseif event.type == "digiline" then if k:sub(1,2) == "v_" then local vote = k:sub(3) local off = vote:find("_", 1, true) - local e_id = tonumber(vote:sub(1,off-1)) - local c_id = tonumber(vote:sub(off+1)) + local e_id = tonumber(vote:sub(1,off-1)) or 0 + local c_id = tonumber(vote:sub(off+1)) or 0 local entry = votes[e_id] or {} votes[e_id] = entry - entry[c_id] = v + entry[c_id] = tonumber(v) or 0 end end digiline_send("debug", mem.votes) -- TODO remove this end elseif event.channel == "admin" then - if event.msg.entries then - -- changed selection, store index - local e = event.msg.entries - if e:sub(1,4) == "CHG:" then - mem.admin_entries_idx = tonumber(e:sub(5)) + if mem.state_admin == "welcome" then + if event.msg.edit_entries then + mem.state_admin = "edit" + show_admin_edit() + elseif event.msg.view_results then + mem.state_admin = "results" + show_admin_results() end - elseif event.msg.add_entry or (event.msg.key_enter_field == "new_entry") then - -- adding new entry - local new = event.msg.new_entry - if new ~= "" then - table.insert(mem.entries, new) + elseif mem.state_admin == "edit" then + if event.msg.entries then + -- changed selection, store index + local e = event.msg.entries + if e:sub(1,4) == "CHG:" then + mem.admin_entries_idx = tonumber(e:sub(5)) + end + show_admin_edit() + elseif event.msg.add_entry or (event.msg.key_enter_field == "new_entry") then + -- adding new entry + local new = event.msg.new_entry + if new ~= "" then + table.insert(mem.entries, new) + end + show_admin_edit() + elseif event.msg.delete_entry then + -- removing selected entry + -- TODO either re-index existing votes, or even wipe all of them + table.remove(mem.entries, mem.admin_entries_idx) + -- try to keep stored index up-to-date with what user is seeing + mem.admin_entries_idx = math.min(mem.admin_entries_idx, #mem.entries) + show_admin_edit() + elseif event.msg.edit_back then + mem.state_admin = "welcome" + show_admin_welcome() + end + elseif mem.state_admin == "results" then + if event.msg.results_back then + mem.state_admin = "welcome" + show_admin_welcome() + elseif event.msg.sort_sum then + mem.sort_type = "sum" + show_admin_results() + elseif event.msg.sort_1 then + mem.sort_type = 1 + show_admin_results() + elseif event.msg.sort_2 then + mem.sort_type = 2 + show_admin_results() + elseif event.msg.sort_3 then + mem.sort_type = 3 + show_admin_results() + elseif event.msg.sort_4 then + mem.sort_type = 4 + show_admin_results() end - elseif event.msg.delete_entry then - -- removing selected entry - -- TODO either re-index existing votes, or even wipe all of them - table.remove(mem.entries, mem.admin_entries_idx) - -- try to keep stored index up-to-date with what user is seeing - mem.admin_entries_idx = math.min(mem.admin_entries_idx, #mem.entries) end - show_admin_main() end elseif false then