How mineqihang/codecraft2025-public works
1. Repository purpose
- This is a competition solver repository for Huawei CodeCraft 2025, organized into three independent solutions: preliminary, semifinal, and final.
- Each stage is a separate C++17 program with its own source tree, build scripts, test scripts, and challenge PDFs.
2. Top-level structure
- preliminary/, semifinal/, and final/ are the main architecture boundaries.
- docs/ under each stage stores the problem statement and sample data.
- test/ and the data-analyze.ipynb notebooks indicate offline evaluation and tuning were part of the workflow.
- images/ supports the README’s strategy explanations, not runtime behavior.
3. Execution model
- Each stage is an interactive solver: it reads judge input from stdin, maintains internal storage/request state, and prints disk operations back to stdout.
- The entry point is main.cpp in each stage, which wires the model, controller, and disk abstractions together.
- run.sh / run.py are wrapper scripts for local execution against sample or test data, while build.sh/pack.sh handle compilation and submission packaging.
4. Core runtime layers
- The codebase is split into a small set of domain objects:
- request.hpp: request parsing and request-state tracking.
- object.hpp: object metadata and placement state.
- disk.hpp: disk-level storage layout and read/write/jump behavior.
- controller.hpp: orchestration layer that decides actions each time slice.
- utils.hpp: shared constants, macros, and helper functions.
- In the final stage, these abstractions are duplicated per round where necessary.
5. Preliminary architecture
- preliminary/src/ contains a single-controller, single-disk-model solution.
- The main dependency flow is: input stream → Request/Object construction → Controller scheduling → Disk operation generation.
- The preliminary solver focuses on one round of decisions with one controller.hpp and one disk.hpp.
6. Semifinal architecture
- semifinal/src/ keeps the same overall shape as preliminary, but the solver must handle the more complex contest rules of that stage.
- The architecture is still centered on one controller and one disk model, implying the stage is handled as a single integrated strategy rather than multiple subsystems.
- The shared file layout suggests the code remains mostly rule adaptation rather than a full redesign.
7. Final architecture: two-round solver
- final/src/ is structurally different because the final has Round 1 and Round 2.
- It includes:
- controller_round1.hpp, disk_round1.hpp
- controller_round2.hpp, disk_round2.hpp
- plus shared controller.hpp, disk.hpp, object.hpp, request.hpp, utils.hpp
- This indicates a two-phase architecture: each round has its own controller/disk specialization, while the shared types provide common state and utilities.
8. Final-stage data flow
- Round 1 handles uncertain information and online inference-like behavior.
- Round 2 reuses the same data model but can exploit more complete information and more precise planning.
- The solver therefore appears to pass accumulated state from the common model into round-specific controllers, rather than treating the rounds as unrelated programs.
9. Algorithmic boundary vs. infrastructure boundary
- The repository is mostly algorithmic, not service-oriented.
- There is no sign of databases, network services, or external APIs in runtime architecture; the important boundary is between:
- judge-provided event stream
- in-memory scheduling/state
- emitted disk commands
- The PDFs in docs/ are a key input to implementation but not part of execution.
10. Build and packaging pipeline
- Each stage uses CMakeLists.txt for compilation, so the codebase is designed around standard C++ build tooling.
- build.sh likely compiles the solver locally.
- pack.sh likely prepares the final submission artifact.
- run.sh and run.py provide convenience wrappers for local replay and regression testing.
11. Testing and analysis boundary
- test.sh and the test/ directory are used to validate solver behavior on sample or custom cases.
- The notebooks under test/ are for offline data analysis and parameter tuning, which is important because the solver strategy depends heavily on empirical tuning.
- This means the repo includes both the production solver and the offline experimentation workflow.
12. What to draw in an architecture diagram
- Draw three separate stage boxes: preliminary, semifinal, final.
- Inside each, show a main.cpp entry point feeding a controller and disk model, with request and object as shared state entities.
- For the final stage, split the controller/disk into Round 1 and Round 2 branches, both using shared domain types.
- Around the solver, show build/test/pack scripts and documentation as supporting tooling, not runtime components.
Main entry points: main.cpp main.cpp · src/controller.hpp Controller · src/controller.hpp Controller · controller_round1.hpp Round 1 controller
Components 28
Preliminary
Initial contest-stage solver and its local workflow.
- main.cpp · Wires stdin parsing, state setup, and solver execution for the preliminary stage.
preliminary/src/main.cpp - Controller · Chooses actions for each decision step in the preliminary solver.
preliminary/src/controller.hpp - Disk model · Represents storage layout and emits disk operations for the preliminary solver.
preliminary/src/disk.hpp - Request · Parses judge requests and tracks per-request state.
preliminary/src/request.hpp - Object · Stores object metadata and placement information.
preliminary/src/object.hpp - Utils · Common constants, macros, and helper functions.
preliminary/src/utils.hpp
Semifinal
Mid-stage solver with the same core architecture as preliminary.
- main.cpp · Entry point for the semifinal solver and its interactive loop.
semifinal/src/main.cpp - Controller · Coordinates semifinal-stage decisions under the stage-specific rules.
semifinal/src/controller.hpp - Disk model · Maintains disk behavior and generates operations for semifinal play.
semifinal/src/disk.hpp - Request · Request parsing and tracking for the semifinal stage.
semifinal/src/request.hpp - Object · Object metadata and placement state for semifinal logic.
semifinal/src/object.hpp - Utils · Semifinal shared constants and utility helpers.
semifinal/src/utils.hpp
Final
Two-round final-stage solver with shared state and round-specific logic.
- main.cpp · Entry point that dispatches the final-stage two-round solver.
final/src/main.cpp - Round 1 controller · Round 1 decision logic for uncertain or online information.
final/src/controller_round1.hpp - Round 1 disk · Round 1 disk behavior and emitted operations.
final/src/disk_round1.hpp - Round 2 controller · Round 2 planning logic using the accumulated state and more complete information.
final/src/controller_round2.hpp - Round 2 disk · Round 2 disk behavior and emitted operations.
final/src/disk_round2.hpp - Shared controller · Shared orchestration layer and common control abstractions for the final stage.
final/src/controller.hpp - Shared disk · Shared disk abstraction reused by both final-stage rounds.
final/src/disk.hpp - Request · Common request parsing and state tracking for the final stage.
final/src/request.hpp - Object · Common object metadata and placement state for both rounds.
final/src/object.hpp - Utils · Final-stage shared constants, macros, and helper functions.
final/src/utils.hpp
Tooling
Build, run, test, and packaging support outside the runtime path.
- build.sh · Local compilation wrapper for a stage.
preliminary/build.sh - pack.sh · Creates submission artifacts for a stage.
preliminary/pack.sh - run scripts · Local replay wrappers for sample and custom runs.
preliminary/run.sh - test harness · Regression and sample validation entry point.
preliminary/test.sh - Task docs · Stage PDFs and sample data used to implement and validate the solvers.
preliminary/docs - Data analysis · Notebook-based tuning and offline evaluation workflow.
preliminary/test/data-analyze.ipynb
Connections 37
- main.cpp → Request: parse · Main reads judge input into request state.
- main.cpp → Object: build · Main initializes object metadata and placement state.
- main.cpp → Controller: run · Main drives the preliminary controller loop.
- Controller → Disk model: emit ops · Controller asks the disk model for storage actions.
- Controller → Request: consume · Controller reacts to incoming requests and their state.
- Controller → Object: update · Controller updates object placement knowledge while scheduling.
- Controller → Utils: use · Controller relies on shared helpers and constants.
- Disk model → Utils: use · Disk model uses shared helpers and constants.
- main.cpp → Request: parse · Main reads semifinal judge input into request state.
- main.cpp → Object: build · Main initializes object metadata and placement state.
- main.cpp → Controller: run · Main drives the semifinal controller loop.
- Controller → Disk model: emit ops · Controller coordinates semifinal disk operations.
- Controller → Request: consume · Controller reacts to semifinal requests and state.
- Controller → Object: update · Controller updates object placement knowledge.
- Controller → Utils: use · Controller relies on shared helpers and constants.
- Disk model → Utils: use · Disk model uses shared helpers and constants.
- main.cpp → Request: parse · Main reads judge input into the common final-stage request model.
- main.cpp → Object: build · Main initializes the common object state.
- main.cpp → Shared controller: dispatch · Main dispatches into the shared final-stage orchestration layer.
- Shared controller → Round 1 controller: round 1 · Shared orchestration hands control to the round 1 strategy.
- Shared controller → Round 2 controller: round 2 · Shared orchestration hands control to the round 2 strategy.
- Round 1 controller → Round 1 disk: emit ops · Round 1 controller produces round-specific disk actions.
- Round 2 controller → Round 2 disk: emit ops · Round 2 controller produces round-specific disk actions.
- Round 1 controller → Request: consume · Round 1 logic consumes the shared request stream.
- Round 2 controller → Request: consume · Round 2 logic consumes the shared request stream.
- Round 1 controller → Object: update · Round 1 updates shared object state.
- Round 2 controller → Object: update · Round 2 updates shared object state.
- Round 1 controller → Utils: use · Round 1 depends on shared helpers and constants.
- Round 2 controller → Utils: use · Round 2 depends on shared helpers and constants.
- Round 1 disk → Utils: use · Round 1 disk model uses shared helpers and constants.
- Round 2 disk → Utils: use · Round 2 disk model uses shared helpers and constants.
- build.sh → main.cpp: builds · Build script compiles the preliminary solver.
- pack.sh → main.cpp: packages · Packaging script prepares the preliminary submission binary.
- run scripts → main.cpp: runs · Local run wrappers execute the preliminary solver.
- test harness → main.cpp: validates · Test harness replays cases against the preliminary solver.
- Task docs → main.cpp: specifies · Problem statements and samples guide solver implementation.
- Data analysis → Controller: tunes · Notebook workflow supports strategy tuning and offline evaluation.