aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMI.cpp82
-rw-r--r--src/CMI.hpp98
2 files changed, 180 insertions, 0 deletions
diff --git a/src/CMI.cpp b/src/CMI.cpp
new file mode 100644
index 0000000..dfca22d
--- /dev/null
+++ b/src/CMI.cpp
@@ -0,0 +1,82 @@
+#include "CMI.hpp"
+
+namespace CMI{
+ void HalfMove::Promote(){
+ HalfMove *broot=GetBranchRoot();
+ if(broot!=nullptr){
+ HalfMove *parent=broot->GetParent();
+ if (parent != nullptr) {
+ if (parent->GetMainline() != broot) {
+ HalfMove *pparent=parent->GetParent();
+ // First update parent of parent:
+ if (pparent != nullptr) {
+ if (pparent->GetMainline() == parent)
+ pparent->SetMainline(broot);
+ else {
+ pparent->AddVariation(broot);
+ pparent->RemoveChild(parent);
+ }
+ }
+ // Now update parent:
+ parent->RemoveChild(broot);
+ broot->AddVariation(parent);
+ }
+ }
+ }
+ }
+
+ void HalfMove::SetAsMainline(){
+ HalfMove *broot = GetBranchRoot();
+ HalfMove *lastRoot;
+ // Just promote until we cannot anymore
+ do {
+ lastRoot = broot;
+ broot->Promote();
+ broot = GetBranchRoot();
+ } while (broot != lastRoot);
+ }
+
+ HalfMove* HalfMove::GetBranchRoot(){
+ HalfMove *m = this;
+ HalfMove *p = GetParent();
+ while (p != nullptr) {
+ if (p->GetMainline() != m) {
+ return (m);
+ }
+ m = p;
+ p = m->GetParent();
+ }
+ return m;
+ }
+
+ void HalfMove::AddVariation(HalfMove* m){
+ m->SetIsBlack(IsBlack());
+ m->SetNumber(GetNumber());
+ m->SetParent(this);
+ auto vars=GetVariations();
+ vars.push_back(m);
+ SetVariations(vars);
+ }
+
+ bool HalfMove::RemoveVariation(HalfMove* m){
+ std::vector<HalfMove*> vars;
+ bool removed=false;
+ for(HalfMove *v: GetVariations()){
+ if(m!=v)
+ vars.push_back(v);
+ else
+ removed=true;
+ }
+ if(removed)
+ SetVariations(vars);
+ return removed;
+ }
+
+ bool HalfMove::RemoveChild(HalfMove* m){
+ if(GetMainline()==m){
+ SetMainline(nullptr);
+ return true;
+ }
+ return RemoveVariation(m);
+ }
+} \ No newline at end of file
diff --git a/src/CMI.hpp b/src/CMI.hpp
new file mode 100644
index 0000000..46d8aa4
--- /dev/null
+++ b/src/CMI.hpp
@@ -0,0 +1,98 @@
+#pragma once
+
+#include <cstdint>
+#include <vector>
+#include <string>
+
+namespace CMI {
+/**
+ * @brief Chess Move Interface
+ * A standard chess half move interface for improving chess libraries
+ * interoperability.
+ * NONE OF THESE METHODS IMPLEMENTATIONS MUST DELETE A CMI::HalfMove.
+ * It is up to the user of the object instance to do it after ensuring that no references
+ * to the CMI::HalfMove remains in the move tree.
+ */
+class HalfMove {
+public:
+ /// @brief Ensure that the destructor of the child class is called
+ virtual ~HalfMove() {};
+ /**
+ * @brief Return a pointer to the next CMI::HalfMove
+ *
+ * @return HalfMove* if any and nullptr otherwise
+ */
+ virtual HalfMove* GetMainline() const = 0;
+ /**
+ * @brief Set the next CMI::HalfMove
+ * Existing main line pointer will be overriten (NOT DELETED) and the internal state (Number, IsBlack) of the new move
+ * must be ajusted in the implementation of this method.
+ */
+ virtual void SetMainline(HalfMove*) = 0;
+ /**
+ * @brief Get the previous CMI::HalfMove
+ *
+ * @return HalfMove* if any and nullptr otherwise
+ */
+ virtual HalfMove* GetParent() const = 0;
+ /**
+ * @brief Set the parent of current CMI::HalfMove
+ *
+ */
+ virtual void SetParent(HalfMove*) = 0;
+ /// @brief Return the current move using the SAN notation e.g: "Qxc5+" or "a4"
+ virtual std::string GetSAN() const = 0;
+ /// @brief Setter to replace current SAN
+ virtual void SetSAN(std::string) = 0;
+ /// @brief Return the HalfMove move number e.g 1 for the first white's and black's move
+ virtual std::uint16_t GetNumber() const = 0;
+ /// @brief Setter to replace current Number
+ virtual void SetNumber(std::uint16_t) = 0;
+ /// @brief Return the Numeric Annotation Glyphs code
+ virtual std::uint8_t GetNAG() const = 0;
+ /// @brief Setter to replace current NAG
+ virtual void SetNAG(std::uint8_t) = 0;
+ /// @brief Return the comment linked to the current move or empty string
+ virtual std::string GetComment() const = 0;
+ /// @brief Setter to replace current comment
+ virtual void SetComment(std::string) = 0;
+ /// @brief Return true if the current HalfMove was played by black
+ virtual bool IsBlack() const = 0;
+ /// @brief Setter to replace that determined the return values of HalfMove::IsBlack()
+ virtual void SetIsBlack(bool) = 0;
+ /// @brief All the variations of the current move
+ virtual std::vector<HalfMove*> GetVariations() const = 0;
+ /// @brief Setter to replace current variations
+ virtual void SetVariations(std::vector<HalfMove*>) = 0;
+
+
+ // ---------- Implementation of various common operations ----------
+
+ /// @brief Promote the current variation if any
+ void Promote();
+ /// @brief Make the current variation the main line
+ void SetAsMainline();
+ /// @brief Add a variation to the variations list
+ void AddVariation(HalfMove*);
+ /**
+ * @brief Remove the given CMI::HalfMove from the variations list
+ *
+ * @return true if found and deleted
+ * @return false otherwise
+ */
+ bool RemoveVariation(HalfMove*);
+ /**
+ * @brief Remove the given CMI::HalfMove from mainline and variations list
+ *
+ * @return true if found and deleted
+ * @return false otherwise
+ */
+ bool RemoveChild(HalfMove*);
+ /**
+ * @brief Return the CMI::HalfMove root node of the current move branch
+ *
+ * @return HalfMove* the branch root (might be nullptr)
+ */
+ HalfMove* GetBranchRoot();
+};
+} \ No newline at end of file