Skip to content

Commit 742e2fa

Browse files
authored
Merge pull request #146 from ImogenBits/bugs
Various Bugfixes
2 parents 8736216 + b1d1793 commit 742e2fa

5 files changed

Lines changed: 74 additions & 19 deletions

File tree

algobattle/battle.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -429,39 +429,41 @@ async def run_battle(self, fight: FightHandler, config: Config, min_size: int, u
429429
"""
430430

431431
def sizes(size: int, max_size: int) -> Iterable[int]:
432+
if size > max_size:
433+
return
432434
counter = count(1)
433-
size = max(size, min_size)
434435
while size < max_size:
435436
yield size
436437
size += next(counter) ** config.exponent
437438
yield max_size
438439

439440
note = "Starting battle..."
440-
for _ in range(config.rounds):
441-
max_size = config.maximum_size
441+
for _i in range(config.rounds):
442+
lower_bound = min_size
443+
upper_bound = config.maximum_size
442444
self.results.append(0)
443445
gen_errors = 0
444-
while self.results[-1] < max_size:
445-
for size in sizes(self.results[-1] + 1, max_size):
446-
ui.update_battle_data(self.UiData(reached=self.results, cap=max_size, note=note))
446+
while lower_bound <= upper_bound:
447+
lower_bound = max(lower_bound, self.results[-1] + 1)
448+
for size in sizes(lower_bound, upper_bound):
449+
ui.update_battle_data(self.UiData(reached=self.results, cap=upper_bound, note=note))
447450
result = await fight.run(size)
448451
if result.generator.error and config.max_generator_errors != "unlimited":
449452
gen_errors += 1
450453
if gen_errors >= config.max_generator_errors:
451-
self.results[-1] = max_size
454+
self.results[-1] = upper_bound
452455
note = f"Generator failed {gen_errors} times in a row, solver wins round by default!"
453456
break
454457
else:
455458
gen_errors = 0
456459
if result.score < config.minimum_score:
457-
max_size = size - 1
460+
upper_bound = size - 1
458461
note = "Solver didn't achieve the needed score, resetting the cap"
459462
break
460463
else:
461464
note = "Solver was successful, increasing the cap"
462465
self.results[-1] = size
463-
else:
464-
note = "Cap reached, resetting instance size"
466+
note = "Cap reached, resetting instance size"
465467

466468
def score(self) -> float:
467469
"""Averages the highest instance size reached in each round."""

algobattle/match.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
ConfigDict,
1616
Field,
1717
GetCoreSchemaHandler,
18+
SerializeAsAny,
1819
ValidationInfo,
1920
field_validator,
2021
model_serializer,
@@ -67,7 +68,7 @@ class Match(BaseModel):
6768

6869
active_teams: list[str] = field(default_factory=list)
6970
excluded_teams: dict[str, ExceptionInfo] = field(default_factory=dict)
70-
battles: dict[MatchupStr, Battle] = Field(default_factory=dict)
71+
battles: dict[MatchupStr, SerializeAsAny[Battle]] = Field(default_factory=dict)
7172

7273
async def _run_battle(
7374
self,

algobattle/types.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -457,12 +457,12 @@ class EdgeLen:
457457

458458
@staticmethod
459459
def _func(v: Any, edges: list[tuple[int, int]]) -> Any:
460-
"""Validates that the collection has length `instance.size`."""
460+
"""Validates that the collection has the same length as `instance.edges`."""
461461
if len(v) != len(edges):
462-
raise ValueError("Value does not have length `instance.size`")
462+
raise ValueError("Value does not have the same length as `instance.edges`")
463463
return v
464464

465-
_validator = AttributeReferenceValidator(_func, InstanceRef.size)
465+
_validator = AttributeReferenceValidator(_func, InstanceRef.edges)
466466

467467
@classmethod
468468
def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:

docs/advanced/config.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,44 @@ one called `algobattle.toml`. Defaults to the current working directory.
260260
### config
261261

262262
Opens the CLI config file. Accepts no arguments.1
263+
264+
### package problem
265+
266+
Packages the problem in the project folder into a `.algo` file.
267+
268+
`project`
269+
: Path to the Algobattle project containing the problem. Can either point directly to a project config file, or to
270+
a folder containing one called `algobattle.toml`. Defaults to the current working directory.
271+
272+
`--description`
273+
: Path to a file containing a human-readable description of the problem. Defaults to one called `description` (with any
274+
extension) in the project's directory.
275+
276+
`--out` / `-o`
277+
: Location where the packaged `.algo` file will be placed. Defaults to a file named after the problem in the project's
278+
directory.
279+
280+
### package programs
281+
282+
Packages the programs of a particular team into `.prog` files. These files can be used to easily share programs, or
283+
upload them to the Algobattle website.
284+
285+
!!! tip "Keep program sizes down"
286+
Algobattle will package everything in the program directories into a zip file. This may include unnecessary build
287+
artefacts, logs, program output, etc. It's best to remove any superfluous files (in particular, anything in your
288+
`.gitignore`) from the directories before running this command.
289+
290+
`project`
291+
: Path to the Algobattle project containing the programs. Can either point directly to a project config file, or to
292+
a folder containing one called `algobattle.toml`. Defaults to the current working directory.
293+
294+
`--team`
295+
: Name of the team whose programs should be packaged. If there is only one team in this project, it will be selected
296+
by default.
297+
298+
`--generator` and `--solver`
299+
: Whether to package this particular program. Defaults to `#!py True`.
300+
301+
`--test` / `--no-test`
302+
: Whether to test the programs before packaging them to make sure that they are building and running correctly.
303+
Defaults to `#!py True`.

docs/tutorial/programs.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -301,12 +301,23 @@ This time it should run without any errors. If that doesn't work for you, there'
301301
## Packaging the Programs
302302

303303
You may want to share your code with e.g. your lab instructors. The best way to do that is to package them into Algobattle
304-
program files. These are files using the `.prob` file extension that are formatted in such a way that Algobattle recognises
305-
them and can use them to run matches.
304+
program files. We do this by running
305+
306+
```
307+
algobattle package programs
308+
```
309+
310+
!!! note "Using the web framework"
311+
If your lab is using the web framework, these files are what you need to upload to have your programs run in the
312+
matches.
313+
314+
!!! tip "Keep program sizes down"
315+
Algobattle will package everything in the program directories. This may include unnecessary build artefacts, logs,
316+
program output, etc. It's best to remove any superfluous files (in particular, anything in your `.gitignore`)
317+
from the directories before running this command.
306318

307319
!!! tip "A peek behind the curtain"
308320
These files again are just `zip` files containing everything in your programs' folders in a specific format.
309-
It's best to remove any unnessesary files from them before packaging to keep file sizes down.
310321

311-
!!! note "Using the web framework"
312-
If your lab is using the web framework, these files are what you need to upload to have your programs run in the matches.
322+
This will create two `.prog` files that contain all the data Algobattle needs to run our programs. We can then easily
323+
share our code using just these files, or upload them to the Algobattle website.

0 commit comments

Comments
 (0)