File indexing completed on 2024-05-19 04:04:52

0001 /*
0002     SPDX-FileCopyrightText: 2012 Ian Wadham <iandw.au@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef AI_BOX_H
0008 #define AI_BOX_H
0009 
0010 #include "ai_globals.h"     // Include Player enum.
0011 
0012 #include <QObject>
0013 #include <QList>
0014 
0015 /**
0016 * Class AI_Box
0017 *
0018 * @short The Box AI algorithms
0019 */
0020 
0021 // Minimum and maximum size of cube box.  Must be consistent with settings.ui.
0022 const int minSide = 3;
0023 const int maxSide = 15;
0024 
0025 class AI_Box : public QObject
0026 {
0027     Q_OBJECT
0028 public:
0029     /**
0030     * The KJumpingCube AI_Box constructor.
0031     */
0032     explicit AI_Box          (QObject * parent = nullptr, int side = 5);
0033     ~AI_Box() override;
0034 
0035     int      side() const       { return m_side; }
0036     Player   owner    (int index) const
0037                       { return (((index >= 0) && (index < m_nCubes)) ?
0038                                 m_owners [index] : Nobody); }
0039     int      value    (int index) const
0040                       { return (((index >= 0) && (index < m_nCubes)) ?
0041                                 m_values [index] : 1); }
0042     int      maxValue (int index) const
0043                       { return (((index >= 0) && (index < m_nCubes)) ?
0044                                 m_maxValues [index] : 4); }
0045 
0046     // For performance, avoid setOwner() and setValue() in the game engine (AI).
0047     // However, they are good to use when loading a saved game, for example.
0048     void     setOwner (int index, Player owner)
0049                                 { if ((index >= 0) && (index < m_nCubes) &&
0050                                       (owner >= Nobody) && (owner <= Two)) {
0051                                       if (owner != m_owners [index]) {
0052                                           m_cubesToWin [m_owners [index]] ++;
0053                                           m_cubesToWin [owner] --;
0054                                       }
0055                                       m_owners [index] = owner;
0056                                   } 
0057                                 }
0058     void     setValue (int index, int value)
0059                                 { if ((index >= 0) && (index < m_nCubes) &&
0060                                       (value >= 1)) {
0061                                       m_values [index] = value;
0062                                   } 
0063                                 }
0064 
0065     // This struct is passed to doMove() and is used to store
0066     // everything that is needed by undoMove() to actually undo it.
0067     struct MoveUndodata {
0068         Player oldPlayer;       // The player previously to move in the position
0069         int    oldCubesToWin[3];
0070         quint16 changedCubes[maxSide * maxSide]; // 8 bits index, 4 bits owner and 4 bits value
0071                                                  // end with 0xffff
0072     };
0073 
0074     bool     doMove   (Player player, int index,
0075                        MoveUndodata * undodata = nullptr, QList<int> * steps = nullptr);
0076     void     undoMove (MoveUndodata * undodata);
0077 #if AILog > 0
0078     void     printBox();
0079 #endif
0080 
0081     void     copyPosition (Player   player, bool   isAI, int index);
0082     bool     undoPosition (Player & player, bool & isAI, int & index);
0083     bool     undoPosition (Player & player);
0084     bool     redoPosition (Player & player, bool & isAI, int & index);
0085     void     initPosition (const AI_Box * box, Player player, bool isAI);
0086 
0087     void     clear();
0088 
0089 protected:
0090     int      m_side;
0091     int      m_nCubes;
0092     Player * m_owners;
0093     int *    m_values;
0094     int *    m_maxValues;
0095     int *    m_neighbors;
0096 
0097     void     resizeBox (int side);
0098 
0099 private:
0100     typedef struct {
0101         Player   player;
0102         bool     isAI;
0103         int      index;
0104         int      nCubes;
0105         Player * owners;
0106         int *    values;
0107     } Position;
0108 
0109     int      m_cubesToWin [3];
0110     int *    m_stack;
0111     int      m_stackPtr;
0112 
0113     QList<Position *> m_undoList;
0114     int      m_undoIndex;
0115     int      m_redoLimit;
0116 
0117     void     indexNeighbors();
0118 
0119     void     save    (Position * position, Player player, bool isAI);
0120     void     restore (Position * position);
0121     void     discard (Position * position);
0122     Position * emptyPosition (int nCubes);
0123     void     createBox (int side);
0124     void     destroyBox();
0125 
0126     QObject * m_parent; // IDW test.
0127 };
0128 
0129 #endif // AI_BOX_H