From 9d135c2f25a5ff2b724e9eb23789b72142dc457f Mon Sep 17 00:00:00 2001
From: Marc-Antoine Manningham <marc-antoine.m@outlook.com>
Date: Fri, 13 Sep 2024 22:39:16 -0400
Subject: [PATCH] feat: initial commit for an university generic engine

---
 combinatoric-solver/Cargo.lock        |  7 +++
 combinatoric-solver/Cargo.toml        |  6 +++
 combinatoric-solver/src/collection.rs | 67 +++++++++++++++++++++++++++
 combinatoric-solver/src/item.rs       |  6 +++
 combinatoric-solver/src/lib.rs        |  6 +++
 combinatoric-solver/src/score.rs      |  1 +
 combinatoric-solver/src/solver.rs     | 56 ++++++++++++++++++++++
 7 files changed, 149 insertions(+)
 create mode 100644 combinatoric-solver/Cargo.lock
 create mode 100644 combinatoric-solver/Cargo.toml
 create mode 100644 combinatoric-solver/src/collection.rs
 create mode 100644 combinatoric-solver/src/item.rs
 create mode 100644 combinatoric-solver/src/lib.rs
 create mode 100644 combinatoric-solver/src/score.rs
 create mode 100644 combinatoric-solver/src/solver.rs

diff --git a/combinatoric-solver/Cargo.lock b/combinatoric-solver/Cargo.lock
new file mode 100644
index 0000000..d5d26d1
--- /dev/null
+++ b/combinatoric-solver/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "combinatoric-solver"
+version = "0.1.0"
diff --git a/combinatoric-solver/Cargo.toml b/combinatoric-solver/Cargo.toml
new file mode 100644
index 0000000..cd0e860
--- /dev/null
+++ b/combinatoric-solver/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "combinatoric-solver"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/combinatoric-solver/src/collection.rs b/combinatoric-solver/src/collection.rs
new file mode 100644
index 0000000..f16919c
--- /dev/null
+++ b/combinatoric-solver/src/collection.rs
@@ -0,0 +1,67 @@
+use crate::score::Score;
+
+#[derive(Clone)]
+pub struct Collection<const MAX_ITEMS: usize, S, ItemVariant>
+where
+    S: Score,
+    ItemVariant: Eq,
+{
+    pub score: S,
+    pub item_quantity: usize,
+    pub item_variant: [ItemVariant; MAX_ITEMS],
+}
+
+impl<const MAX_ITEMS: usize, S: Score, ItemVariant: Eq + Default + Copy>
+    Collection<MAX_ITEMS, S, ItemVariant>
+{
+    pub fn push(&self, item_variant: ItemVariant) -> Self {
+        let mut new = self.clone();
+        new.item_variant[self.item_quantity] = item_variant;
+        new.item_quantity += 1;
+        new
+    }
+}
+
+impl<const MAX_ITEMS: usize, S: Score, ItemVariant: Eq + Default + Copy> Default
+    for Collection<MAX_ITEMS, S, ItemVariant>
+{
+    fn default() -> Self {
+        let score = S::default();
+        let item_quantity = 0;
+        let item_variant = [ItemVariant::default(); MAX_ITEMS];
+        Self {
+            score,
+            item_quantity,
+            item_variant,
+        }
+    }
+}
+
+impl<const MAX_ITEMS: usize, S: Score, ItemVariant: Eq> PartialEq
+    for Collection<MAX_ITEMS, S, ItemVariant>
+{
+    fn eq(&self, other: &Self) -> bool {
+        self.item_variant == other.item_variant
+    }
+}
+
+impl<const MAX_ITEMS: usize, S: Score, ItemVariant: Eq> PartialOrd
+    for Collection<MAX_ITEMS, S, ItemVariant>
+{
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        self.score.partial_cmp(&other.score)
+    }
+}
+
+impl<const MAX_ITEMS: usize, S: Score, ItemVariant: Eq> Eq
+    for Collection<MAX_ITEMS, S, ItemVariant>
+{
+}
+
+impl<const MAX_ITEMS: usize, S: Score, ItemVariant: Eq> Ord
+    for Collection<MAX_ITEMS, S, ItemVariant>
+{
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        self.score.cmp(&other.score)
+    }
+}
diff --git a/combinatoric-solver/src/item.rs b/combinatoric-solver/src/item.rs
new file mode 100644
index 0000000..a37121c
--- /dev/null
+++ b/combinatoric-solver/src/item.rs
@@ -0,0 +1,6 @@
+pub trait ItemVariant: Eq + Copy + Default {}
+
+pub trait CombinatoricItem {
+    type ItemVariant;
+    fn variants(&self) -> impl IntoIterator<Item = Self::ItemVariant>;
+}
diff --git a/combinatoric-solver/src/lib.rs b/combinatoric-solver/src/lib.rs
new file mode 100644
index 0000000..8d79d25
--- /dev/null
+++ b/combinatoric-solver/src/lib.rs
@@ -0,0 +1,6 @@
+pub mod collection;
+pub mod item;
+pub mod score;
+pub mod solver;
+
+pub use crate::solver::Solver;
diff --git a/combinatoric-solver/src/score.rs b/combinatoric-solver/src/score.rs
new file mode 100644
index 0000000..426175d
--- /dev/null
+++ b/combinatoric-solver/src/score.rs
@@ -0,0 +1 @@
+pub trait Score: Ord + Default + Clone {}
diff --git a/combinatoric-solver/src/solver.rs b/combinatoric-solver/src/solver.rs
new file mode 100644
index 0000000..863a287
--- /dev/null
+++ b/combinatoric-solver/src/solver.rs
@@ -0,0 +1,56 @@
+use std::{cmp::Reverse, collections::BinaryHeap};
+
+use crate::{
+    collection::Collection,
+    item::{CombinatoricItem, ItemVariant},
+    score::Score,
+};
+
+pub struct Solver<const MAX_ITEMS: usize, S, V, I, Parameters>
+where
+    S: Score,
+    V: ItemVariant,
+    I: CombinatoricItem,
+{
+    top_items: BinaryHeap<Reverse<Collection<MAX_ITEMS, S, V>>>,
+    max_capacity: usize,
+    parameters: Parameters,
+    items: Vec<I>,
+}
+
+impl<'a, const MAX_ITEMS: usize, S, V, I, Parameters> Solver<MAX_ITEMS, S, V, I, Parameters>
+where
+    S: Score,
+    V: ItemVariant,
+    I: CombinatoricItem<ItemVariant = V>,
+{
+    pub fn new(max_capacity: usize, items: Vec<I>, parameters: Parameters) -> Self {
+        let top_items = BinaryHeap::with_capacity(max_capacity);
+        Self {
+            top_items,
+            max_capacity,
+            parameters,
+            items,
+        }
+    }
+    pub fn solve(mut self) -> Vec<I> {
+        let item = &self.items;
+        Self::rec_iter(0, Collection::default(), item, &mut self.top_items);
+        vec![]
+    }
+    fn rec_iter(
+        i: usize,
+        collection: Collection<MAX_ITEMS, S, V>,
+        items: &'a [I],
+        top_items: &mut BinaryHeap<Reverse<Collection<MAX_ITEMS, S, V>>>,
+    ) {
+        if i >= items.len() {
+            return;
+        }
+
+        for variant in items[i].variants() {
+            let collections = collection.push(variant);
+            Self::rec_iter(i + 1, collections, items, top_items);
+        }
+    }
+}
-- 
GitLab