File size: 3,254 Bytes
4b94493
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use serde::{Deserialize, Serialize};
use solverforge::prelude::*;

use super::RoomKind;

/// A subject meeting that the solver assigns to one timeslot and one room.
#[planning_entity]
#[derive(Serialize, Deserialize)]
pub struct Lesson {
    #[planning_id]
    pub id: String,
    /// Dense solver-facing join key rebuilt by `Plan::rebuild_derived_fields`.
    #[serde(skip)]
    pub index: usize,
    pub subject: String,
    pub group_idx: usize,
    pub student_count: usize,
    pub teacher_idx: Option<usize>,
    pub duration: u32,
    pub required_room_kind: RoomKind,
    // @solverforge:begin entity-variables
    /// Scalar planning variable pointing at `Plan.timeslots`.
    #[planning_variable(value_range_provider = "timeslots", allows_unassigned = false)]
    pub timeslot_idx: Option<usize>,
    /// Scalar planning variable pointing at `Plan.rooms`.
    #[planning_variable(value_range_provider = "rooms", allows_unassigned = false)]
    pub room_idx: Option<usize>,
    // @solverforge:end entity-variables
}

impl Lesson {
    /// Builds an unassigned lesson with the default lecture-room requirement.
    pub fn new(
        index: usize,
        subject: String,
        group_idx: usize,
        teacher_idx: Option<usize>,
        duration: u32,
    ) -> Self {
        Self::with_required_room_kind(
            index,
            subject,
            group_idx,
            teacher_idx,
            duration,
            RoomKind::Lecture,
        )
    }

    /// Builds an unassigned lesson with an explicit room-kind requirement.
    pub fn with_required_room_kind(
        index: usize,
        subject: String,
        group_idx: usize,
        teacher_idx: Option<usize>,
        duration: u32,
        required_room_kind: RoomKind,
    ) -> Self {
        Self::with_details(
            index,
            subject,
            group_idx,
            30,
            teacher_idx,
            duration,
            required_room_kind,
        )
    }

    /// Builds an unassigned lesson with every field needed by the data seed.
    pub fn with_details(
        index: usize,
        subject: String,
        group_idx: usize,
        student_count: usize,
        teacher_idx: Option<usize>,
        duration: u32,
        required_room_kind: RoomKind,
    ) -> Self {
        Self {
            id: format!("lesson-{index}"),
            index,
            subject,
            group_idx,
            student_count,
            teacher_idx,
            duration,
            required_room_kind,
            // @solverforge:begin entity-variable-init
            timeslot_idx: None,
            room_idx: None,
            // @solverforge:end entity-variable-init
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_lesson_construction() {
        let entity = Lesson::new(
            0,
            "test".to_string(),
            Default::default(),
            None,
            Default::default(),
        );
        assert_eq!(entity.id, "lesson-0");
        let _ = &entity.subject;
        let _ = &entity.group_idx;
        let _ = &entity.student_count;
        let _ = &entity.teacher_idx;
        let _ = &entity.duration;
        let _ = &entity.required_room_kind;
    }
}