Advertisement
franklinglzhou

AoPS automatic VC

May 31st, 2023 (edited)
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.52 KB | None | 0 0
  1. /* Tool for votecounts - can be used for current or retrospective votecounts
  2. * To use, load posts from start of day up until desired post (or thread end for current VCs),
  3. * and fill in the correct information below
  4. * For d2+, just load from SOD, not start of game
  5. * Votes are case-sensitive; bold and code are both counted, Vote: Unvote and Unvote are both counted
  6. */
  7.  
  8. // For each player in the game, insert into playerlist a string "<name>", without the comma for the last one.
  9. // Playerlist must be start of game
  10. var playerlist = ["Aminecraftbear", "ChrisalonaLiverspur", "Cosmosiq", "DXtreme", "Mathletesv", "NDMath", "WisteriaV", "ad333", "adrastea", "falliinqsnow-", "galaxy1220", "itsjustWanderlust", "jkittykitkat", "lovematch13", "lucaswujc", "mark888", "mathjay", "ostriches88", "saturnrocket", "scannose", "vietaformula810"];
  11. var start = 6; // SOD postnum
  12. //var start = prompt("What post did day start?"); // can use this instead if you want
  13.  
  14. /* Replacements must be in order
  15. * Each replacement: [postnum, player who replaced out, player who replaced in]
  16. * Sample:
  17. * var replacements = [
  18. * [123, "player1", "player2"],
  19. * [1610, "player3", "player4"],
  20. * ];
  21. * (Comma at end of each replacement except the last) */
  22. var replacements = [
  23. [5, "lovematch13", "dragonlouis"],
  24. [1202, "ostriches88", "Madelyn"],
  25. [1637, "galaxy1220", "hellomynameisjoe"],
  26. [2581, "dragonlouis", "lovematch13"],
  27. [2982, "adrastea", "G3don"],
  28. [3134, "lucaswujc", "sheepsaysmeep"],
  29. [3537, "G3don", "violetmx12"],
  30. [3963, "falliinqsnow-", "Scipio1"]
  31. ];
  32.  
  33. /* Fill in all deaths in order by post, similar to replacements
  34. * Sample, with two deaths in post 1236:
  35. * var deaths = [
  36. * [1234, "player1", "Town"],
  37. * [1236, "player2", "Mafia"],
  38. * [1236, "player3", "Town"]
  39. * ];
  40. * Alignment should be Town or Mafia, anything else is no alignment
  41. */
  42. var deaths = [
  43. [2575, "DXtreme", "Town"],
  44. [2582, "Aminecraftbear", "Town"],
  45. [3532, "lovematch13", "Town"],
  46. [3532, "itsjustWanderlust", "Town"],
  47. [3541, "WisteriaV", "Town"]
  48. ];
  49.  
  50. // If you want some text at the bottom of the votecount
  51. var lastline = "";
  52. var color = "[color=#00f]"; // Custom color; only for current votecounts
  53. var majOn = false; // If enabled, L-2 and L-1 will show in the votecount (untested)
  54.  
  55. /*********/
  56. /* Below options are only for a retrospective votecount */
  57.  
  58. /* For a retrospective votecount, comment out the below line and uncomment the line after, or set postNum directly
  59. A postNum of zero means a current votecount, not a retrospective one */
  60. //var postNum = 0; // post that you want a votecount for
  61. var postNum = prompt("What post do you want a votecount for?");
  62.  
  63. var day = 1; // Set to correct day if using retrospective votecount
  64. /*********/
  65.  
  66. //Turn off AoPS Enhanced if you have it before using
  67. $("div.bbcode_quote").remove();
  68. $("span.cmty-hide-heading faux-link").remove();
  69. $("div.cmty-hide-content").remove();
  70.  
  71. // End of info for user
  72. /***********************************/
  73.  
  74. function hasVoteStr(voteStr, post) {
  75. // Check whether a post contains a certain vote
  76. if ($(".cmty-post-html")[post].innerHTML.includes("<b>" + voteStr)
  77. || $(".cmty-post-html")[post].innerHTML.includes("<pre class=\"c\" style=\"font-family:monospace;background-color: #f4f6f4;padding:10px;\">" + voteStr)
  78. || $(".cmty-post-html")[post].innerHTML.includes("<code>" + voteStr)) {
  79. return true;
  80. } else if (voteStr.slice(0, 6) === "Vote: " && $(".cmty-post-html")[post].innerHTML.includes("<pre class=\"c\" style=\"font-family:monospace;background-color: #f4f6f4;padding:10px;\">Vote<span style=\"color: #339933;\">:</span> " + voteStr.slice(6))) {
  81. // Handle edge case with code tags - colon in "Vote: " is a different color
  82. return true;
  83. } else {
  84. return false;
  85. }
  86. }
  87.  
  88. function processVote(poster, target, a) {
  89. var oldVote = players[poster]["vote"];
  90. if (oldVote != target) {
  91. // Not already voting that player -> change vote
  92. if (oldVote != "None") {
  93. players[oldVote]["numVotes"]--;
  94. players[oldVote]["voters"].splice(players[oldVote]["voters"].indexOf(poster), 1);
  95. if (players[oldVote]["voters"].length > 0) {
  96. players[oldVote]["wagonTailPost"] = players[players[oldVote]["voters"][players[oldVote]["voters"].length - 1]]["votePost"];
  97. }
  98. } else {
  99. notVoting.splice(notVoting.indexOf(poster), 1);
  100. }
  101. players[target]["numVotes"] += 1;
  102. players[target]["voters"].push(poster);
  103. players[poster]["vote"] = target;
  104.  
  105. }
  106. $(".cmty-post-number")[a].click();
  107. players[target]["wagonTailPost"] = Number($(".cmty-post-number")[a].innerHTML.slice(1));
  108. players[poster]["votePost"] = players[target]["wagonTailPost"];
  109. players[poster]["voteURL"] = " ([url=" + $(".cmty-post-direct-modal > input")[0].value + "]" + $(".cmty-post-number")[a].innerHTML + "[/url])";
  110. $("a.aops-close-x").click();
  111. }
  112.  
  113. function voteCompare(a, b) {
  114. // Sort wagons in descending order
  115. if (players[a]["numVotes"] == players[b]["numVotes"]) {
  116. // Ties broken by postnum of last vote on player
  117. return players[a]["wagonTailPost"] - players[b]["wagonTailPost"];
  118. } else {
  119. return players[b]["numVotes"] - players[a]["numVotes"];
  120. }
  121. }
  122.  
  123. /* Enables loading only from SOD on D2+ rather than loading entire thread
  124. - The index of a post is based on the number of posts loaded rather than post numbers,
  125. so map postnum to index out of loaded posts */
  126. var adjusted_start = $(".cmty-post-number").index($(".cmty-post-number").filter(":contains(" + start.toString() + ")"));
  127. //var adjusted_start = $(".cmty-post-number").index(":contains(" + start.toString() + ")"); // this would be more efficient, but it doesn't work. not sure why
  128. var adjusted_end;
  129. if (postNum > 0) {
  130. adjusted_end = $(".cmty-post-number").index($(".cmty-post-number").filter(":contains(" + postNum.toString() + ")"));
  131. } else {
  132. adjusted_end = $(".cmty-post").length - 1; // Current VC
  133. }
  134.  
  135. var replaceInd = 0;
  136. var replacePost = 0;
  137. if (replacements.length !== 0) {
  138. replacePost = replacements[replaceInd][0];
  139. }
  140. while (replaceInd < replacements.length && replacePost <= start) {
  141. for (let d of deaths) {
  142. if (d[1] == replacements[replaceInd][1]) {
  143. d[1] = replacements[replaceInd][2];
  144. }
  145. }
  146. let plInd = playerlist.indexOf(replacements[replaceInd][1]);
  147. if (plInd < 0) {
  148. console.log("Warning: " + replacements[replaceInd][1] + " in replacements but not in playerlist, skipping");
  149. } else {
  150. playerlist[plInd] = replacements[replaceInd][2];
  151. console.log("Processed replacement from earlier in post " + replacePost + ": " + replacements[replaceInd][2] + " for " + replacements[replaceInd][1]);
  152. }
  153. replaceInd++;
  154. if (replaceInd < replacements.length) {
  155. replacePost = replacements[replaceInd][0];
  156. } else {
  157. // If there's no replacements left, adjust to a post we'll never hit
  158. replacePost = adjusted_end + start - adjusted_start + 1;
  159. }
  160. }
  161. var deathInd = 0;
  162. var deathPost = 0;
  163. if (deaths.length !== 0) {
  164. deathPost = deaths[deathInd][0];
  165. }
  166. while (deathInd < deaths.length && deathPost <= start) {
  167. let plInd = playerlist.indexOf(deaths[deathInd][1]);
  168. if (plInd < 0) {
  169. console.log("Warning: " + deaths[deathInd][1] + " in deaths but not in playerlist, skipping");
  170. } else {
  171. playerlist.splice(plInd, 1);
  172. console.log("Processed death from earlier in post " + deathPost + ": " + deaths[deathInd][1]);
  173. }
  174. deathInd++;
  175. if (deathInd < deaths.length) {
  176. deathPost = deaths[deathInd][0];
  177. } else {
  178. // If there's no deaths left, adjust to a post we'll never hit
  179. deathPost = adjusted_end + start - adjusted_start + 1;
  180. }
  181. }
  182.  
  183. var players = {};
  184. var notVoting = [];
  185. playerlist.push("No Hang");
  186. for (let player of playerlist) {
  187. players[player] = {};
  188. players[player]["numVotes"] = 0;
  189. players[player]["voters"] = [];
  190. players[player]["vote"] = "None";
  191. players[player]["voteURL"] = "";
  192. players[player]["wagonTailPost"] = 0;
  193. players[player]["votePost"] = 0;
  194. players[player]["alignment"] = "None";
  195. players[player]["postcount"] = 0;
  196.  
  197. if (player != "No Hang") {
  198. notVoting.push(player);
  199. }
  200. // Below is old stuff, keeping it around for reference
  201. //players[player] = [0, [], "None", "", 0, 0, "None"];
  202. /* Indices of players[player]:
  203. 0: Number of votes
  204. 1: Players voting them
  205. 2: who they're voting
  206. 3: URL of last vote
  207. 4: postnum of last vote on them
  208. 5: postnum of their last vote
  209. 6: flipped alignment
  210. */
  211. }
  212.  
  213. var voter;
  214. for (let a = adjusted_start; a <= adjusted_end; a++) {
  215. // Process replacement
  216. while (a + start - adjusted_start === replacePost) {
  217. let subOut = replacements[replaceInd][1];
  218. let subIn = replacements[replaceInd][2];
  219. let voteTarget = players[subOut]["vote"];
  220. if (!(subOut in players)) {
  221. console.log("post " + replacePost + ": " + subOut + " not currently in game, not processing replacment");
  222. } else {
  223. // Adjust for player who is voted by replacement
  224. if (voteTarget !== "None") {
  225. players[voteTarget]["voters"][players[voteTarget]["voters"].indexOf(subOut)] = subIn;
  226. }
  227.  
  228. // Adjust for players voting replacement
  229. for (let repVoter of players[subOut]["voters"]) {
  230. players[repVoter]["vote"] = subIn;
  231. }
  232.  
  233. // Adjust players, notVoting, playerlist
  234. playerlist[playerlist.indexOf(subOut)] = subIn;
  235. players[subIn] = players[subOut];
  236. delete players[subOut];
  237. let nvInd = notVoting.indexOf(subOut);
  238. if (nvInd >= 0) {
  239. notVoting[nvInd] = subIn;
  240. }
  241. for (let d of deaths) {
  242. if (d[1] == replacements[replaceInd][1]) {
  243. d[1] = replacements[replaceInd][2];
  244. }
  245. }
  246. console.log("Processed replacement in post " + (a + start - adjusted_start) + ": " + subIn + " for " + subOut);
  247. }
  248. replaceInd++;
  249. if (replaceInd < replacements.length) {
  250. replacePost = replacements[replaceInd][0];
  251. } else {
  252. // If there's no replacements left, adjust to a post we'll never hit
  253. replacePost = adjusted_end + start - adjusted_start + 1;
  254. }
  255. }
  256. // Process deaths during the day
  257. while (a + start - adjusted_start === deathPost) {
  258. let dead = deaths[deathInd][1];
  259. let voteTarget = players[dead]["vote"];
  260. if (!(dead in players)) {
  261. console.log("post " + replacePost + ": " + subOut + " not currently in game, not processing replacment");
  262. } else {
  263. if (voteTarget !== "None") {
  264. players[voteTarget]["voters"].splice(players[voteTarget]["voters"].indexOf(dead), 1);
  265. }
  266.  
  267. // Adjust for players voting dead player
  268. for (let deadVoter of players[dead]["voters"]) {
  269. players[deadVoter]["vote"] = "None";
  270. notVoting.push(voter);
  271. }
  272. // Adjust players, notVoting, playerlist
  273. playerlist.splice(playerlist.indexOf(dead), 1);
  274. delete players[dead];
  275. let nvInd = notVoting.indexOf(dead);
  276. if (nvInd >= 0) {
  277. notVoting.splice(nvInd, 1);
  278. }
  279. console.log("Processed death in post " + (a + start - adjusted_start) + ": " + dead);
  280. }
  281. deathInd++;
  282. if (deathInd < deaths.length) {
  283. deathPost = deaths[deathInd][0];
  284. } else {
  285. // If there's no deaths left, adjust to a post we'll never hit
  286. deathPost = adjusted_end + start - adjusted_start + 1;
  287. }
  288. }
  289. voter = $(".cmty-post-username > a")[a].innerHTML;
  290. if (voter in players) {
  291. players[voter]["postcount"]++;
  292. if ((hasVoteStr("Unvote", a) || hasVoteStr("Vote: Unvote", a)) && players[voter]["vote"] != "None") {
  293. // Process unvote
  294. let oldVote = players[voter]["vote"];
  295. players[oldVote]["numVotes"]--;
  296. players[oldVote]["voters"].splice(players[oldVote]["voters"].indexOf(voter), 1);
  297. if (players[oldVote]["voters"].length > 0) {
  298. // Update last vote on wagon, if the wagon still exists
  299. players[oldVote]["wagonTailPost"] = players[players[oldVote]["voters"].slice(-1)]["votePost"];
  300. }
  301. notVoting.push(voter);
  302. players[voter]["vote"] = "None";
  303. $(".cmty-post-number")[a].click();
  304. players[voter]["voteURL"] = " ([url=" + $(".cmty-post-direct-modal > input")[0].value + "]" + $(".cmty-post-number")[a].innerHTML + "[/url])";
  305. players[voter]["votePost"] = Number($(".cmty-post-number")[a].innerHTML.slice(1));
  306. $("a.aops-close-x").click();
  307. }
  308. if (hasVoteStr("Vote: ", a)) {
  309. for (var voted in players) {
  310. if (hasVoteStr("Vote: " + voted, a)) {
  311. processVote(voter, voted, a);
  312. }
  313. }
  314. }
  315. }
  316. }
  317. while (deathInd < deaths.length) {
  318. // Set alignments of players who die later for retro VC
  319. let dead = deaths[deathInd][1];
  320. if (!(dead in players)) {
  321. console.log("Warning: " + dead + " in deaths but not in playerlist, skipping");
  322. } else {
  323. players[dead]["alignment"] = deaths[deathInd][2];
  324. }
  325. deathInd++;
  326. }
  327.  
  328. var notText = "[b]Not Voting (" + notVoting.length + "):[/b] ";
  329. for (let a = 0; a < notVoting.length; a++) {
  330. if (a !== 0) {
  331. notText += ", ";
  332. }
  333. voter = notVoting[a];
  334. if (players[voter]["alignment"] == "Town") {
  335. notText += "[color=#38761D]";
  336. notText += voter;
  337. notText += "[/color]";
  338. notText += players[voter]["voteURL"];
  339. } else if (players[voter]["alignment"] == "Mafia") {
  340. notText += "[color=#f00]";
  341. notText += voter;
  342. notText += "[/color]";
  343. notText += players[voter]["voteURL"];
  344. } else {
  345. notText += voter + players[voter]["voteURL"];
  346. }
  347. }
  348.  
  349. var voteCounters = []
  350. for (let player of playerlist) {
  351. voteCounters.push(player);
  352. }
  353.  
  354. voteCounters.sort(voteCompare);
  355. var voteText = "";
  356. for (let i = 0; i < voteCounters.length; i++) {
  357. if (players[voteCounters[i]]["numVotes"] == 0) {
  358. break;
  359. }
  360. voteText += "[b]" + voteCounters[i] + " (" + players[voteCounters[i]]["numVotes"].toString();
  361. if (majOn) {
  362. // note players.length includes No Hang
  363. if (voteCounters[i] != "No Hang" && players[voteCounters[i]]["numVotes"] == Math.ceil((players.length) / 2 - 2)
  364. || voteCounters[i] == "No Hang" && players[voteCounters[i]]["numVotes"] == Math.floor((players.length) / 2 - 2)) {
  365. voteText += ", L-2";
  366. } else if (voteCounters[i] != "No Hang" && players[voteCounters[i]]["numVotes"] == Math.ceil((players.length) / 2 - 1)
  367. || voteCounters[i] == "No Hang" && players[voteCounters[i]]["numVotes"] == Math.floor((players.length) / 2 - 1)) {
  368. voteText += ", L-1";
  369. }
  370. }
  371. voteText += "):[/b] ";
  372. for (let j = 0; j < players[voteCounters[i]]["voters"].length; j++) {
  373. voter = players[voteCounters[i]]["voters"][j];
  374. if (players[voter]["alignment"] == "Town") {
  375. voteText += "[color=#38761D]";
  376. voteText += voter;
  377. voteText += "[/color]";
  378. voteText += players[voter]["voteURL"];
  379. } else if (players[voter]["alignment"] == "Mafia") {
  380. voteText += "[color=#f00]";
  381. voteText += voter;
  382. voteText += "[/color]";
  383. voteText += players[voter]["voteURL"];
  384. } else {
  385. voteText += voter + players[voter]["voteURL"];
  386. }
  387. if (j === players[voteCounters[i]]["voters"].length - 1) {
  388. voteText += "\n";
  389. } else {
  390. voteText += ", ";
  391. }
  392. }
  393. }
  394.  
  395. voteCounters.sort((a, b) => players[b]["postcount"] - players[a]["postcount"]);
  396. var postcounts = "[hide=Postcounts]";
  397. for (let player of voteCounters) {
  398. if (player != "No Hang") {
  399. postcounts += player + ": " + players[player]["postcount"] + "\n";
  400. }
  401. }
  402. postcounts += "[/hide]";
  403.  
  404. var post = "";
  405. if (postNum <= 0) {
  406. // Current VC
  407. post = color + "[b][u]Automatic Votecount " + prompt("What votecount is it?") + "[/u][/b]\n" + voteText + "\n" + notText;
  408. } else {
  409. // Retro VC
  410. post = "[b][u]Votecount for Post " + postNum + " (Day " + day + ")[/u][/b]\n" + voteText + "\n" + notText;
  411. }
  412. post += "\n" + postcounts;
  413. if (lastline.length > 0) {
  414. post += "\n\n" + lastline;
  415. }
  416. $(".cmty-topic-mini-reply").click();
  417. $(".cmty-post-textarea").val(post);
  418. console.log("Votecount added to reply box");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement