Skip to content

Commit 9b322e5

Browse files
committed
Merge branch '2025-international-rules'
2 parents 6a7038b + 07786a8 commit 9b322e5

File tree

90 files changed

+16131
-392
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+16131
-392
lines changed

bower.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,18 @@
3737
"pdfjs": "https://github.com/mozilla/pdf.js/releases/download/v4.3.136/pdfjs-4.3.136-dist.zip",
3838
"popper.js": "^1.16.0",
3939
"quill": "https://cdn.quilljs.com/1.3.7/quill.js",
40-
"quill-image-drop-and-paste": "https://github.com/chenjuneking/quill-image-drop-and-paste.git#1.2.9",
40+
"quill-image-drop-and-paste": "https://github.com/chenjuneking/quill-image-drop-and-paste.git#1.3.0",
4141
"quill-image-resize-module": "https://github.com/kensnyder/quill-image-resize-module.git",
4242
"quill.snow": "https://cdn.quilljs.com/1.3.6/quill.snow.css",
4343
"socket.io": "4.2.0",
4444
"socket.io-client": "4.2.0",
4545
"sweetalert2": "^7.28.11",
4646
"tether": "^1.4.7",
4747
"jquery-ui": "^1.12.1",
48-
"quill-image-upload": "https://github.com/fxmontigny/quill-image-upload.git#^0.1.3",
4948
"font-awesome-5": "^5.15.3",
5049
"angular-ui-select": "^0.19.8",
51-
"exceljs": "https://cdnjs.cloudflare.com/ajax/libs/exceljs/4.2.1/exceljs.min.js"
50+
"exceljs": "https://cdnjs.cloudflare.com/ajax/libs/exceljs/4.2.1/exceljs.min.js",
51+
"mutation_events.min": "https://cdn.jsdelivr.net/npm/[email protected]/src/mutation_events.min.js"
5252
},
5353
"description": "",
5454
"homepage": "https://gitlab.ida.liu.se/sebgu182",

helper/authLevels.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
const { ACCESSLEVELS } = require('../models/user');
1+
const { ACCESSLEVELS, user } = require('../models/user');
2+
3+
async function authCompetitionRole(authUser, competitionId, expectedRole) {
4+
let userObj = authUser;
5+
if (typeof(userObj) == "string" || userObj.competitions == undefined) {
6+
userObj = await user.findById(userObj).lean().exec();
7+
if (userObj == undefined) return false;
8+
}
9+
return userObj.superDuperAdmin || (userObj.competitions.length != 0 && userObj.competitions.find((c) => c.id.equals(competitionId)).role.includes(expectedRole));
10+
}
11+
module.exports.authCompetitionRole = authCompetitionRole;
212

313
function authCompetition(user, competitionId, level) {
414
if (user == null) {

helper/initRunData.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const logger = require('../config/logger').mainLogger;
22
const { lineMap } = require('../models/lineMap');
33

4-
module.exports.initLine = async function (run, scored = false) {
4+
module.exports.initLine = async function (run, rule, scored = false) {
55
if (run.started) return null;
66

77
const query = lineMap.findById(run.map);
@@ -84,17 +84,19 @@ module.exports.initLine = async function (run, scored = false) {
8484
}
8585
}
8686

87-
// Consider continued ramp tiles as a ramp
88-
let rampContinueFlag = false;
89-
for (let index = run.tiles.length - 1; index >= 0; index--) {
90-
if (run.tiles[index].scoredItems.some(item => item.item == "ramp")) {
91-
if (rampContinueFlag) {
92-
run.tiles[index].scoredItems.splice(run.tiles[index].scoredItems.findIndex(item => item.item === 'ramp'), 1);
87+
if (rule == '2024' || rule == '2024E' || rule == '2025E') {
88+
// Consider continued ramp tiles as a ramp
89+
let rampContinueFlag = false;
90+
for (let index = run.tiles.length - 1; index >= 0; index--) {
91+
if (run.tiles[index].scoredItems.some(item => item.item == "ramp")) {
92+
if (rampContinueFlag) {
93+
run.tiles[index].scoredItems.splice(run.tiles[index].scoredItems.findIndex(item => item.item === 'ramp'), 1);
94+
} else {
95+
rampContinueFlag = true;
96+
}
9397
} else {
94-
rampContinueFlag = true;
98+
rampContinueFlag = false;
9599
}
96-
} else {
97-
rampContinueFlag = false;
98100
}
99101
}
100102

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
const logger = require('../../config/logger').mainLogger;
2+
3+
/**
4+
*
5+
* @param run Must be populated with map and tiletypes!
6+
* @returns {number}
7+
*/
8+
module.exports.calculateLineScore = function (run) {
9+
try {
10+
let score = 0;
11+
let final_score;
12+
let multiplier = 1.0;
13+
14+
let lastCheckPointTile = 0;
15+
let checkPointCount = 0;
16+
17+
let total_lops = 0;
18+
for (let i = 0; i < run.LoPs.length; i++) {
19+
total_lops += run.LoPs[i];
20+
}
21+
22+
for (let i = 0; i < run.tiles.length; i++) {
23+
const tile = run.tiles[i];
24+
for (let j = 0; j < tile.scoredItems.length; j++) {
25+
switch (tile.scoredItems[j].item) {
26+
case 'checkpoint':
27+
const tileCount = i - lastCheckPointTile;
28+
score +=
29+
Math.max(tileCount * (5 - 2 * run.LoPs[checkPointCount]), 0) *
30+
tile.scoredItems[j].scored;
31+
lastCheckPointTile = i;
32+
checkPointCount++;
33+
break;
34+
case 'gap':
35+
score += 10 * tile.scoredItems[j].scored;
36+
break;
37+
case 'intersection':
38+
score += 10 * tile.scoredItems[j].scored * tile.scoredItems[j].count;
39+
break;
40+
case 'obstacle':
41+
score += 20 * tile.scoredItems[j].scored * tile.scoredItems[j].count;
42+
break;
43+
case 'speedbump':
44+
score += 10 * tile.scoredItems[j].scored;
45+
break;
46+
case 'ramp':
47+
score += 10 * tile.scoredItems[j].scored * tile.scoredItems[j].count;
48+
break;
49+
case 'seesaw':
50+
score += 20 * tile.scoredItems[j].scored * tile.scoredItems[j].count;
51+
break;
52+
}
53+
}
54+
}
55+
56+
57+
let error = 1;
58+
if (run.rescueOrder) {
59+
let liveCount = 0;
60+
for (let victim of run.rescueOrder) {
61+
if (victim.victimType == "LIVE" && victim.zoneType == "RED") continue;
62+
if (victim.victimType == "DEAD" && victim.zoneType == "GREEN") continue;
63+
if (victim.victimType == "DEAD" && liveCount != run.map.victims.live) continue;
64+
65+
multiplier *= Math.max(1400-(50*run.LoPs[run.map.EvacuationAreaLoPIndex]),1250);
66+
67+
error *= 1000;
68+
if (victim.victimType == "LIVE") liveCount ++;
69+
}
70+
multiplier /= error;
71+
}
72+
73+
if (run.exitBonus) {
74+
score += Math.max(60 - 5 * total_lops, 0);
75+
const tileCount = run.tiles.length - lastCheckPointTile - 1;
76+
score += Math.max(tileCount * (5 - 2 * run.LoPs[checkPointCount]), 0)
77+
}
78+
79+
// 5 points for placing robot on first droptile (start)
80+
// Implicit showedUp if anything else is scored
81+
if (run.showedUp || score > 0) {
82+
score += 5;
83+
}
84+
85+
final_score = Math.round(score * multiplier);
86+
87+
const ret = {};
88+
ret.raw_score = score;
89+
ret.score = final_score;
90+
ret.multiplier = multiplier;
91+
return ret;
92+
} catch (e) {
93+
console.log(e);
94+
}
95+
};
96+
97+
/**
98+
*
99+
* @param run Must be populated with map!
100+
* @returns {number}
101+
*/
102+
module.exports.calculateMazeScore = function (run) {
103+
let score = 0;
104+
105+
const mapTiles = [];
106+
for (let i = 0; i < run.map.cells.length; i++) {
107+
const cell = run.map.cells[i];
108+
if (cell.isTile) {
109+
mapTiles[`${cell.x},${cell.y},${cell.z}`] = cell;
110+
}
111+
}
112+
113+
let victims = {};
114+
let rescueKits = 0;
115+
116+
for (let i = 0; i < run.tiles.length; i++) {
117+
const tile = run.tiles[i];
118+
const coord = `${tile.x},${tile.y},${tile.z}`;
119+
120+
if (tile.scoredItems.speedbump && mapTiles[coord].tile.speedbump) {
121+
score += 5;
122+
}
123+
if (tile.scoredItems.checkpoint && mapTiles[coord].tile.checkpoint) {
124+
score += 10;
125+
}
126+
if (tile.scoredItems.ramp && mapTiles[coord].tile.ramp) {
127+
score += 10;
128+
}
129+
if (tile.scoredItems.steps && mapTiles[coord].tile.steps) {
130+
score += 10;
131+
}
132+
133+
const maxKits = {
134+
H: 2,
135+
S: 1,
136+
U: 0,
137+
Red: 2,
138+
Yellow: 1,
139+
Green: 0,
140+
};
141+
142+
if (mapTiles[coord].tile.victims.top != 'None') {
143+
if (tile.scoredItems.victims.top) {
144+
addVictimCount(victims, mapTiles[coord].tile.victims.top);
145+
if (
146+
mapTiles[coord].tile.victims.top == 'Red' ||
147+
mapTiles[coord].tile.victims.top == 'Yellow' ||
148+
mapTiles[coord].tile.victims.top == 'Green'
149+
)
150+
score += mapTiles[coord].isLinear ? 5 : 15;
151+
else score += mapTiles[coord].isLinear ? 10 : 30;
152+
153+
rescueKits += Math.min(
154+
tile.scoredItems.rescueKits.top,
155+
maxKits[mapTiles[coord].tile.victims.top]
156+
);
157+
}
158+
}
159+
if (mapTiles[coord].tile.victims.right != 'None') {
160+
if (tile.scoredItems.victims.right) {
161+
addVictimCount(victims, mapTiles[coord].tile.victims.right);
162+
if (
163+
mapTiles[coord].tile.victims.right == 'Red' ||
164+
mapTiles[coord].tile.victims.right == 'Yellow' ||
165+
mapTiles[coord].tile.victims.right == 'Green'
166+
)
167+
score += mapTiles[coord].isLinear ? 5 : 15;
168+
else score += mapTiles[coord].isLinear ? 10 : 30;
169+
170+
rescueKits += Math.min(
171+
tile.scoredItems.rescueKits.right,
172+
maxKits[mapTiles[coord].tile.victims.right]
173+
);
174+
}
175+
}
176+
if (mapTiles[coord].tile.victims.bottom != 'None') {
177+
if (tile.scoredItems.victims.bottom) {
178+
addVictimCount(victims, mapTiles[coord].tile.victims.bottom);
179+
if (
180+
mapTiles[coord].tile.victims.bottom == 'Red' ||
181+
mapTiles[coord].tile.victims.bottom == 'Yellow' ||
182+
mapTiles[coord].tile.victims.bottom == 'Green'
183+
)
184+
score += mapTiles[coord].isLinear ? 5 : 15;
185+
else score += mapTiles[coord].isLinear ? 10 : 30;
186+
187+
rescueKits += Math.min(
188+
tile.scoredItems.rescueKits.bottom,
189+
maxKits[mapTiles[coord].tile.victims.bottom]
190+
);
191+
}
192+
}
193+
if (mapTiles[coord].tile.victims.left != 'None') {
194+
if (tile.scoredItems.victims.left) {
195+
addVictimCount(victims, mapTiles[coord].tile.victims.left);
196+
if (
197+
mapTiles[coord].tile.victims.left == 'Red' ||
198+
mapTiles[coord].tile.victims.left == 'Yellow' ||
199+
mapTiles[coord].tile.victims.left == 'Green'
200+
)
201+
score += mapTiles[coord].isLinear ? 5 : 15;
202+
else score += mapTiles[coord].isLinear ? 10 : 30;
203+
204+
rescueKits += Math.min(
205+
tile.scoredItems.rescueKits.left,
206+
maxKits[mapTiles[coord].tile.victims.left]
207+
);
208+
}
209+
}
210+
}
211+
212+
let totalVictimCount = sum(Object.values(victims));
213+
214+
score += Math.min(rescueKits, 12) * 10;
215+
216+
score += Math.max((totalVictimCount + Math.min(rescueKits, 12) - run.LoPs) * 10, 0);
217+
218+
if (run.exitBonus) {
219+
score += totalVictimCount * 10;
220+
}
221+
222+
score -= Math.min(run.misidentification * 5, score);
223+
224+
return {
225+
score: score,
226+
victims: convert(victims),
227+
kits: Math.min(rescueKits, 12)
228+
}
229+
};
230+
231+
function addVictimCount(obj, type) {
232+
if (obj[type] == null) obj[type] = 0;
233+
obj[type] ++;
234+
}
235+
236+
function sum(array) {
237+
if (array.length == 0) return 0;
238+
return array.reduce(function(a,b){
239+
return a + b;
240+
});
241+
}
242+
243+
function convert(obj) {
244+
return Object.entries(obj).map(o => {
245+
return {
246+
'type': o[0],
247+
'count': o[1]
248+
}
249+
})
250+
}

0 commit comments

Comments
 (0)