1212#include " core/testcase.h"
1313#include " exttestcaseupdaterdialog.h"
1414//
15+ #include < functional>
1516#include < memory>
17+ #include < optional>
18+
19+ // Remap a single test case's subtask dependencies using a mapping function.
20+ // The mapper receives 0-indexed dependency indices and returns:
21+ // - a mapped 0-indexed index, or
22+ // - std::nullopt to remove that dependency.
23+ static void remapTestCaseDeps (TestCase *testCase, const std::function<std::optional<int >(int )> &mapper) {
24+ const auto ¤tDeps = testCase->getDependenceSubtask ();
25+ QSet<int > remappedDeps;
26+
27+ for (int dep : currentDeps) {
28+ auto mapped = mapper (dep - 1 );
29+
30+ if (mapped.has_value ())
31+ remappedDeps.insert (mapped.value () + 1 );
32+ }
33+
34+ testCase->setDependenceSubtask (remappedDeps);
35+ }
1636
1737ExtTestCaseModifier::ExtTestCaseModifier (QWidget *parent) : QWidget(parent), ui(new Ui::ExtTestCaseModifier) {
1838 ui->setupUi (this );
@@ -58,11 +78,11 @@ void ExtTestCaseModifier::whenTestCaseSelectionChanged() {
5878}
5979
6080void ExtTestCaseModifier::modifySelected () {
61- auto hav = ui->testCaseTable ->getSelectedHaveSub ();
62- auto res = ui->testCaseTable ->getSelectedResSub ();
81+ auto selectedSubtasks = ui->testCaseTable ->getSelectedHaveSub ();
82+ auto partialSelections = ui->testCaseTable ->getSelectedResSub ();
6383
64- if (res .empty ()) {
65- int l = hav .front (), r = hav .back ();
84+ if (partialSelections .empty ()) {
85+ int l = selectedSubtasks .front (), r = selectedSubtasks .back ();
6686
6787 if (l != r) {
6888 auto dialog = std::make_unique<ExtTestCaseUpdaterDialog>(
@@ -98,7 +118,7 @@ void ExtTestCaseModifier::modifySelected() {
98118 }
99119 }
100120 } else {
101- int who = res .front ().first , loc = res .front ().second .first ;
121+ int who = partialSelections .front ().first , loc = partialSelections .front ().second .first ;
102122
103123 auto dialog = std::make_unique<ExtTestCaseUpdaterDialog>(this , editTask, editSettings, -1 , NO_EDIT , 1 ,
104124 NO_EDIT , NO_EDIT , NO_EDIT );
@@ -113,200 +133,167 @@ void ExtTestCaseModifier::modifySelected() {
113133}
114134
115135void ExtTestCaseModifier::moveUpSelected () {
116- auto hav = ui->testCaseTable ->getSelectedHaveSub ();
117- auto res = ui->testCaseTable ->getSelectedResSub ();
136+ auto selectedSubtasks = ui->testCaseTable ->getSelectedHaveSub ();
137+ auto partialSelections = ui->testCaseTable ->getSelectedResSub ();
118138
119- auto temp = ui->testCaseTable ->getSelectRange ();
120- int dlt = 0 ;
139+ auto selectRange = ui->testCaseTable ->getSelectRange ();
140+ int selectionDelta = 0 ;
121141
122- if (! res .empty ()) {
123- int l = res [0 ].second .first , r = res [0 ].second .second ;
124- dlt = -1 ;
142+ if (! partialSelections .empty ()) {
143+ int l = partialSelections [0 ].second .first , r = partialSelections [0 ].second .second ;
144+ selectionDelta = -1 ;
125145
126146 for (int i = l; i <= r; i++)
127- editTask->getTestCaseList ()[res [0 ].first ]->swapFiles (i - 1 , i);
147+ editTask->getTestCaseList ()[partialSelections [0 ].first ]->swapFiles (i - 1 , i);
128148 } else {
129- int l = hav .front (), r = hav .back ();
130- dlt = -editTask->getTestCase (l - 1 )->getInputFiles ().size ();
149+ int l = selectedSubtasks .front (), r = selectedSubtasks .back ();
150+ selectionDelta = -editTask->getTestCase (l - 1 )->getInputFiles ().size ();
131151
132152 for (int i = l; i <= r; i++)
133153 editTask->swapTestCase (i - 1 , i);
134154
135155 for (int i = l - 1 ; i <= r - 1 ; i++) {
136- auto nowd = editTask->getTestCase (i)->getDependenceSubtask ();
137- QSet<int > havd;
138-
139- for (auto a_ : nowd) {
140- int a = a_ - 1 ;
141-
156+ remapTestCaseDeps (editTask->getTestCase (i), [l, r](int a) -> std::optional<int > {
142157 if (a == l - 1 )
143- continue ;
158+ return std:: nullopt ;
144159
145160 if (l <= a && a <= r)
146- a-- ;
161+ return a - 1 ;
147162
148- havd.insert (a + 1 );
149- }
150-
151- editTask->getTestCase (i)->setDependenceSubtask (havd);
163+ return a;
164+ });
152165 }
153166
154- for (int i = r + 1 , ii = editTask->getTestCaseList ().size (); i < ii; i++) {
155- auto nowd = editTask->getTestCase (i)->getDependenceSubtask ();
156- QSet<int > havd;
157-
158- for (auto a_ : nowd) {
159- int a = a_ - 1 ;
167+ int totalCases = editTask->getTestCaseList ().size ();
160168
169+ for (int i = r + 1 ; i < totalCases; i++) {
170+ remapTestCaseDeps (editTask->getTestCase (i), [l, r](int a) -> std::optional<int > {
161171 if (l <= a && a <= r)
162- a--;
163- else if (a == l - 1 )
164- a = r;
172+ return a - 1 ;
165173
166- havd. insert (a + 1 );
167- }
174+ if (a == l - 1 )
175+ return r;
168176
169- editTask->getTestCase (i)->setDependenceSubtask (havd);
177+ return a;
178+ });
170179 }
171180 }
172181
173182 refresh ();
174183
175- ui->testCaseTable ->modifySelected (temp.first + dlt, temp.second + dlt);
184+ ui->testCaseTable ->modifySelected (selectRange.first + selectionDelta,
185+ selectRange.second + selectionDelta);
176186}
177187
178188void ExtTestCaseModifier::moveDownSelected () {
179- auto hav = ui->testCaseTable ->getSelectedHaveSub ();
180- auto res = ui->testCaseTable ->getSelectedResSub ();
189+ auto selectedSubtasks = ui->testCaseTable ->getSelectedHaveSub ();
190+ auto partialSelections = ui->testCaseTable ->getSelectedResSub ();
181191
182- auto temp = ui->testCaseTable ->getSelectRange ();
183- int dlt = 0 ;
192+ auto selectRange = ui->testCaseTable ->getSelectRange ();
193+ int selectionDelta = 0 ;
184194
185- if (! res .empty ()) {
186- int l = res [0 ].second .first , r = res [0 ].second .second ;
187- dlt = 1 ;
195+ if (! partialSelections .empty ()) {
196+ int l = partialSelections [0 ].second .first , r = partialSelections [0 ].second .second ;
197+ selectionDelta = 1 ;
188198
189199 for (int i = r; i >= l; i--)
190- editTask->getTestCaseList ()[res [0 ].first ]->swapFiles (i, i + 1 );
200+ editTask->getTestCaseList ()[partialSelections [0 ].first ]->swapFiles (i, i + 1 );
191201 } else {
192- int l = hav .front (), r = hav .back ();
193- dlt = editTask->getTestCase (r + 1 )->getInputFiles ().size ();
202+ int l = selectedSubtasks .front (), r = selectedSubtasks .back ();
203+ selectionDelta = editTask->getTestCase (r + 1 )->getInputFiles ().size ();
194204
195205 for (int i = r; i >= l; i--)
196206 editTask->swapTestCase (i, i + 1 );
197207
198- {
199- auto nowd = editTask->getTestCase (l)->getDependenceSubtask ();
200- QSet<int > havd;
201-
202- for (auto a_ : nowd) {
203- int a = a_ - 1 ;
204-
205- if (l <= a && a <= r)
206- continue ;
207-
208- havd.insert (a + 1 );
209- }
208+ remapTestCaseDeps (editTask->getTestCase (l), [l, r](int a) -> std::optional<int > {
209+ if (l <= a && a <= r)
210+ return std::nullopt ;
210211
211- editTask-> getTestCase (l)-> setDependenceSubtask (havd) ;
212- }
212+ return a ;
213+ });
213214
214215 for (int i = l + 1 ; i <= r + 1 ; i++) {
215- auto nowd = editTask->getTestCase (i)->getDependenceSubtask ();
216- QSet<int > havd;
217-
218- for (auto a_ : nowd) {
219- int a = a_ - 1 ;
220-
216+ remapTestCaseDeps (editTask->getTestCase (i), [l, r](int a) -> std::optional<int > {
221217 if (l <= a && a <= r)
222- a++ ;
218+ return a + 1 ;
223219
224- havd.insert (a + 1 );
225- }
226-
227- editTask->getTestCase (i)->setDependenceSubtask (havd);
220+ return a;
221+ });
228222 }
229223
230- for (int i = r + 1 , ii = editTask->getTestCaseList ().size (); i < ii; i++) {
231- auto nowd = editTask->getTestCase (i)->getDependenceSubtask ();
232- QSet<int > havd;
233-
234- for (auto a_ : nowd) {
235- int a = a_ - 1 ;
224+ int totalCases = editTask->getTestCaseList ().size ();
236225
226+ for (int i = r + 1 ; i < totalCases; i++) {
227+ remapTestCaseDeps (editTask->getTestCase (i), [l, r](int a) -> std::optional<int > {
237228 if (l <= a && a <= r)
238- a++;
239- else if (a == r + 1 )
240- a = l;
229+ return a + 1 ;
241230
242- havd. insert (a + 1 );
243- }
231+ if (a == r + 1 )
232+ return l;
244233
245- editTask->getTestCase (i)->setDependenceSubtask (havd);
234+ return a;
235+ });
246236 }
247237 }
248238
249239 refresh ();
250240
251- ui->testCaseTable ->modifySelected (temp.first + dlt, temp.second + dlt);
241+ ui->testCaseTable ->modifySelected (selectRange.first + selectionDelta,
242+ selectRange.second + selectionDelta);
252243}
253244
254245void ExtTestCaseModifier::removeSelected () {
255- auto hav = ui->testCaseTable ->getSelectedHaveSub ();
256- auto res = ui->testCaseTable ->getSelectedResSub ();
246+ auto selectedSubtasks = ui->testCaseTable ->getSelectedHaveSub ();
247+ auto partialSelections = ui->testCaseTable ->getSelectedResSub ();
257248
258- int ban1 = -1 , ban2 = -1 ;
249+ int skipSub1 = -1 , skipSub2 = -1 ;
259250
260- for (auto i : std::as_const (res )) {
261- if (ban1 < 0 )
262- ban1 = i.first ;
251+ for (auto i : std::as_const (partialSelections )) {
252+ if (skipSub1 < 0 )
253+ skipSub1 = i.first ;
263254 else
264- ban2 = i.first ;
255+ skipSub2 = i.first ;
265256
266257 int l = i.second .first , r = i.second .second ;
267258
268259 for (int j = l; j <= r; j++)
269260 editTask->getTestCaseList ()[i.first ]->deleteSingleCase (l);
270261 }
271262
272- int l = hav .front (), r = hav .back ();
263+ int l = selectedSubtasks .front (), r = selectedSubtasks .back ();
273264
274- while (l == ban1 || l == ban2 )
265+ while (l == skipSub1 || l == skipSub2 )
275266 l++;
276267
277- while (r == ban1 || r == ban2 )
268+ while (r == skipSub1 || r == skipSub2 )
278269 r--;
279270
280271 for (int i = l; i <= r; i++)
281272 editTask->deleteTestCase (l);
282273
283- for (int i = l + 1 , ii = editTask->getTestCaseList ().size (); i < ii; i++) {
284- auto nowd = editTask->getTestCase (i)->getDependenceSubtask ();
285- QSet<int > havd;
286-
287- for (auto a_ : nowd) {
288- int a = a_ - 1 ;
274+ int totalCases = editTask->getTestCaseList ().size ();
289275
276+ for (int i = l + 1 ; i < totalCases; i++) {
277+ remapTestCaseDeps (editTask->getTestCase (i), [l, r](int a) -> std::optional<int > {
290278 if (l <= a && a <= r)
291- continue ;
292- else if (a > r)
293- a -= r - l;
279+ return std::nullopt ;
294280
295- havd. insert (a + 1 );
296- }
281+ if (a > r)
282+ return a - (r - l);
297283
298- editTask->getTestCase (i)->setDependenceSubtask (havd);
284+ return a;
285+ });
299286 }
300287
301288 refresh ();
302289}
303290
304291void ExtTestCaseModifier::mergeSelected () {
305- auto hav = ui->testCaseTable ->getSelectedHaveSub ();
292+ auto selectedSubtasks = ui->testCaseTable ->getSelectedHaveSub ();
306293
307- auto temp = ui->testCaseTable ->getSelectRange ();
294+ auto selectRange = ui->testCaseTable ->getSelectRange ();
308295
309- int l = hav .front (), r = hav .back ();
296+ int l = selectedSubtasks .front (), r = selectedSubtasks .back ();
310297
311298 auto ans = *editTask->getTestCase (l);
312299
@@ -326,32 +313,35 @@ void ExtTestCaseModifier::mergeSelected() {
326313
327314 refresh ();
328315
329- ui->testCaseTable ->modifySelected (temp .first , temp .second );
316+ ui->testCaseTable ->modifySelected (selectRange .first , selectRange .second );
330317}
331318
332319void ExtTestCaseModifier::splitSelected () {
333- auto hav = ui->testCaseTable ->getSelectedHaveSub ();
320+ auto selectedSubtasks = ui->testCaseTable ->getSelectedHaveSub ();
334321
335- auto temp = ui->testCaseTable ->getSelectRange ();
322+ auto selectRange = ui->testCaseTable ->getSelectRange ();
336323
337324 QList<TestCase *> ans;
338325
339- int l = hav .front (), r = hav .back ();
326+ int l = selectedSubtasks .front (), r = selectedSubtasks .back ();
340327
341328 for (int i = l; i <= r; i++) {
342329 TestCase *now = editTask->getTestCase (i);
343330 auto in = now->getInputFiles ();
344331 auto out = now->getOutputFiles ();
345- int allScore = now->getFullScore (), gar = 0 ;
332+ int allScore = now->getFullScore ();
333+
334+ // Distribute the total score evenly across test cases.
335+ // The first baseCaseCount cases get floor(allScore / n),
336+ // the remaining cases get ceil(allScore / n).
337+ int baseCaseCount = 0 ;
346338
347339 if (! in.empty ())
348- gar = in.size () - allScore % in.size ();
349- else
350- gar = 0 ;
340+ baseCaseCount = in.size () - allScore % in.size ();
351341
352342 for (int j = 0 ; j < in.size (); j++) {
353343 auto *app = new TestCase;
354- app->setFullScore ((allScore / in.size ()) + (j >= gar ));
344+ app->setFullScore ((allScore / in.size ()) + (j >= baseCaseCount ));
355345 app->setTimeLimit (now->getTimeLimit ());
356346 app->setMemoryLimit (now->getMemoryLimit ());
357347 app->setDependenceSubtask (now->getDependenceSubtask ());
@@ -369,7 +359,7 @@ void ExtTestCaseModifier::splitSelected() {
369359
370360 refresh ();
371361
372- ui->testCaseTable ->modifySelected (temp .first , temp .second );
362+ ui->testCaseTable ->modifySelected (selectRange .first , selectRange .second );
373363}
374364
375365void ExtTestCaseModifier::appendNewSub () {
0 commit comments