File indexing completed on 2024-04-28 04:05:21

0001 /*
0002     SPDX-FileCopyrightText: 2015 Jakob Gruber <jakob.gruber@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "boardstate.h"
0008 
0009 #include <algorithm>
0010 #include <assert.h>
0011 
0012 BoardState::BoardState(int width, int height) : Board(width, height), m_box_count(0)
0013 {
0014 }
0015 
0016 void BoardState::set(int x, int y, State state) {
0017     assertInbounds(x, y);
0018 
0019     const int i = xy_to_i(x, y);
0020 
0021     if (m_state[i] == state) {
0022         return;
0023     }
0024 
0025     UndoAction undo;
0026     undo.x = x;
0027     undo.y = y;
0028     undo.state = m_state[i];
0029     m_undo_queue.push(undo);
0030     Q_EMIT undoStackSizeChanged(m_undo_queue.size());
0031 
0032     updateBoxCount(m_state[i], state);
0033     m_state[i] = state;
0034 }
0035 
0036 void BoardState::updateBoxCount(Board::State prev, Board::State next) {
0037     if (prev == Board::Box && next != Board::Box) {
0038         m_box_count--;
0039     } else if (prev != Board::Box && next == Board::Box) {
0040         m_box_count++;
0041     }
0042 }
0043 
0044 QPoint BoardState::undo() {
0045     if (m_undo_queue.empty()) {
0046         return QPoint();
0047     }
0048 
0049     UndoAction undo = m_undo_queue.pop();
0050     Q_EMIT undoStackSizeChanged(m_undo_queue.size());
0051 
0052     const int i = xy_to_i(undo.x, undo.y);
0053 
0054     updateBoxCount(m_state[i], undo.state);
0055     m_state[i] = undo.state;
0056 
0057     /* if we undo past a saved state, remove it */
0058 
0059     if (!m_saved_states.isEmpty()
0060             && m_undo_queue.size() < m_saved_states.top()) {
0061         (void)m_saved_states.pop();
0062         Q_EMIT saveStackSizeChanged(m_saved_states.size());
0063     }
0064 
0065     return QPoint(undo.x, undo.y);
0066 }
0067 
0068 void BoardState::saveState() {
0069 
0070     /* a saved state consists only of the size of
0071        the undo queue to rewind to to restore a specific state */
0072 
0073     int size = m_undo_queue.size();
0074     if (!m_saved_states.isEmpty() && m_saved_states.top() == size) {
0075         return;
0076     }
0077     m_saved_states.push(size);
0078     Q_EMIT saveStackSizeChanged(m_saved_states.size());
0079 }
0080 
0081 void BoardState::loadState() {
0082 
0083     if (m_saved_states.isEmpty()) {
0084         return;
0085     }
0086 
0087     /* rewind the undo queue until its size equals
0088        the saved queue size */
0089 
0090     int size = m_saved_states.pop();
0091     assert(size <= m_undo_queue.size());
0092     Q_EMIT saveStackSizeChanged(m_saved_states.size());
0093 
0094     while (size < m_undo_queue.size()) {
0095         (void)undo();
0096     }
0097 }
0098 
0099 int BoardState::currentStateAge() const {
0100     if (m_saved_states.isEmpty()) {
0101         return m_undo_queue.size();
0102     }
0103     return m_undo_queue.size() - m_saved_states.top();
0104 }
0105 
0106 void BoardState::replace(State prev, State next) {
0107     for (int i = 0; i < m_state.size(); i++) {
0108         if (m_state[i] == prev) {
0109             m_state[i] = next;
0110         }
0111     }
0112 }
0113 
0114 void BoardState::solve(const Board *board) {
0115     assert(board->width() == width());
0116     assert(board->height() == height());
0117 
0118     for (int y = 0; y < height(); y++) {
0119         for (int x = 0; x < width(); x++) {
0120             m_state[xy_to_i(x, y)] = board->get(x, y);
0121         }
0122     }
0123 
0124     replace(Board::Nothing, Board::Cross);
0125 }
0126 
0127 #include "moc_boardstate.cpp"