|
25 | 25 |
|
26 | 26 | #include <list> |
27 | 27 | #include <set> |
| 28 | +#include <stack> |
28 | 29 |
|
29 | 30 | #include "number.h" |
30 | 31 | #include "gameobject.h" |
@@ -118,6 +119,8 @@ template <class P, class T> class ElementCollection { |
118 | 119 | { |
119 | 120 | return m_owner == p_other.m_owner && m_container == p_other.m_container; |
120 | 121 | } |
| 122 | + |
| 123 | + bool empty() const { return m_container->empty(); } |
121 | 124 | size_t size() const { return m_container->size(); } |
122 | 125 | GameObjectPtr<T> front() const { return m_container->front(); } |
123 | 126 | GameObjectPtr<T> back() const { return m_container->back(); } |
@@ -512,6 +515,88 @@ class GameRep : public BaseGameRep { |
512 | 515 | using Players = ElementCollection<Game, GamePlayerRep>; |
513 | 516 | using Outcomes = ElementCollection<Game, GameOutcomeRep>; |
514 | 517 |
|
| 518 | + class Nodes { |
| 519 | + Game m_owner{nullptr}; |
| 520 | + |
| 521 | + public: |
| 522 | + class iterator { |
| 523 | + friend class Nodes; |
| 524 | + using ChildIterator = ElementCollection<GameNode, GameNodeRep>::iterator; |
| 525 | + |
| 526 | + Game m_owner{nullptr}; |
| 527 | + GameNode m_current_node{nullptr}; |
| 528 | + std::stack<std::pair<ChildIterator, ChildIterator>> m_stack{}; |
| 529 | + |
| 530 | + iterator(const Game &game) : m_owner(game) {} |
| 531 | + |
| 532 | + public: |
| 533 | + using iterator_category = std::forward_iterator_tag; |
| 534 | + using value_type = GameNode; |
| 535 | + using pointer = value_type *; |
| 536 | + |
| 537 | + iterator() = default; |
| 538 | + |
| 539 | + iterator(const Game &game, const GameNode &start_node) : m_owner(game), m_current_node(start_node) |
| 540 | + { |
| 541 | + if (!start_node) { |
| 542 | + return; |
| 543 | + } |
| 544 | + if (start_node->GetGame() != m_owner) { |
| 545 | + throw MismatchException(); |
| 546 | + } |
| 547 | + } |
| 548 | + |
| 549 | + value_type operator*() const |
| 550 | + { |
| 551 | + if (!m_current_node) { |
| 552 | + throw std::runtime_error("Cannot dereference an end iterator"); |
| 553 | + } |
| 554 | + return m_current_node; |
| 555 | + } |
| 556 | + |
| 557 | + iterator &operator++() |
| 558 | + { |
| 559 | + if (!m_current_node) { |
| 560 | + throw std::out_of_range("Cannot increment an end iterator"); |
| 561 | + } |
| 562 | + |
| 563 | + if (!m_current_node->IsTerminal()) { |
| 564 | + auto children = m_current_node->GetChildren(); |
| 565 | + m_stack.emplace(children.begin(), children.end()); |
| 566 | + } |
| 567 | + |
| 568 | + while (!m_stack.empty()) { |
| 569 | + auto &[current_it, end_it] = m_stack.top(); |
| 570 | + |
| 571 | + if (current_it != end_it) { |
| 572 | + m_current_node = *current_it; |
| 573 | + ++current_it; |
| 574 | + return *this; |
| 575 | + } |
| 576 | + m_stack.pop(); |
| 577 | + } |
| 578 | + |
| 579 | + m_current_node = nullptr; |
| 580 | + return *this; |
| 581 | + } |
| 582 | + |
| 583 | + bool operator==(const iterator &other) const |
| 584 | + { |
| 585 | + return m_owner == other.m_owner && m_current_node == other.m_current_node; |
| 586 | + } |
| 587 | + bool operator!=(const iterator &other) const { return !(*this == other); } |
| 588 | + }; |
| 589 | + |
| 590 | + Nodes() = default; |
| 591 | + explicit Nodes(const Game &p_owner) : m_owner(p_owner) {} |
| 592 | + |
| 593 | + iterator begin() const |
| 594 | + { |
| 595 | + return (m_owner) ? iterator{m_owner, m_owner->GetRoot()} : iterator{}; |
| 596 | + } |
| 597 | + iterator end() const { return (m_owner) ? iterator{m_owner} : iterator{}; } |
| 598 | + }; |
| 599 | + |
515 | 600 | /// @name Lifecycle |
516 | 601 | //@{ |
517 | 602 | /// Clean up the game |
@@ -724,6 +809,8 @@ class GameRep : public BaseGameRep { |
724 | 809 | //@{ |
725 | 810 | /// Returns the root node of the game |
726 | 811 | virtual GameNode GetRoot() const = 0; |
| 812 | + /// Returns a range that can be used to iterate over the nodes of the game |
| 813 | + Nodes GetNodes() const { return Nodes(this); } |
727 | 814 | /// Returns the number of nodes in the game |
728 | 815 | virtual size_t NumNodes() const = 0; |
729 | 816 | /// Returns the number of non-terminal nodes in the game |
|
0 commit comments