Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

The goal of this assignment is to refresh your programming skills and recall mat

ID: 667401 • Letter: T

Question

The goal of this assignment is to refresh your programming skills and recall material from ECE 1574. You can also use this to gauge how well you are prepared for the course and callibrate your skill level to my time estimates. If you cannot complete the program, you should probably drop.

Description

Consider an eight-tile sliding puzzle. You have probably seen these, a square array of tiles with numbers, letters, or part of an image printed on them, and one blank space. The tiles can slide left-right and up-down within the puzzle, exchanging positions with the empty location. The goal is, from a scrambled state, slide the tiles around until the tiles show a particular image or spell some text.

Consider a 3 by 3 puzzle with eight tiles, addressed by row and column with 0-based indexing, with labels 'A' through 'H' and an empty spot denoted by the label ' '(space). For example:

is empty at position (2,2), has tile 'D' in position (1,0), tile 'B' on position (0,1), etc.

Define a class Puzzle that models the above eight-tile puzzle. The class should support

Construction of a default puzzle instance with the layout in the example above,

a move method taking two position arguments from and to, throwing std::range_error if either position is invalid or the move is invalid

and a get method taking a position argument and returning the tile label at that position, throwing a std::range_error if the position is invalid.

The public portion of the class is defined in the starter code inside the file puzzle.h as:

You will need to define the internal members and methods (marked TODO) and implement all methods in the puzzle.cpp file. You will also need to write tests in the filepuzzle_test.h. These should be one test per method inside the PuzzleTest class. The included CMakeLists.txt file sets up everything for you. Just generate your build directory for your environment.

Explanation / Answer

menu.h

#pragma once

void welcomeMenu();

void mainMenu();

Game.h

#include <vector>
#include "PuzzleSearchNode.h"

class Game{

    public:
        // default & init constructor
        Game(int nrow = 4, int ncol = 4);

        // copy constructor
        Game(const Game& source);

        // destructor
        ~Game();

        // deep copy assignment operator
        Game& operator = (const Game& source);

        // get GameNumber
        int GetGameID() const;

        // get InitialPuzzle
        Puzzle* GetInitialPuzzle() const;

        // get CurrentPuzzle
        Puzzle* GetCurrentPuzzle() const;

        // get MoveHistory
        std::vector<MoveDirect> GetMoveHistory() const;

        // push to MoveHistory
        void PushToHistory(MoveDirect step);

        // get TotalNumber
        int GetTotalNumber() const;

        // get EverCreated
        int GetEverCreated() const;

        // let user play the game
        void MoveInterface();

        // decide if user wins already
        bool IsWin() const;

        // return puzzle configuration at position in history
        Puzzle Trace(int postion) const;

        // undo numStep # of steps
        void Undo(int numStep);

        // search function for IDA*
        int Search(PuzzleSearchNode& thisNode, int boundValue, PuzzleSearchNode& leafNode);

        // solve it by computer
        int SolveIt();

        // display info for the Game
        void Display() const;

       //replay through MoveHistory
       void Replay() const;


    // member fields
    private:
        int GameID;
        Puzzle* InitialPuzzle;
        Puzzle* CurrentPuzzle;
        std::vector<MoveDirect> MoveHistory;
        static int TotalNumber;
        static int EverCreated;

};

//tests.h

#pragma once

void testPuzzle();

void testGame();

//Puzzle.h

#pragma once

#include <iostream>


enum MoveDirect {BLANK_UP, BLANK_DOWN, BLANK_LEFT, BLANK_RIGHT};

// a Puzzle object stores configuration of any gem puzzle
// class Puzzle is the building block for GemPuzzle project
class Puzzle{

    public:
        // default & init constructor
        Puzzle(int nrow = 4, int ncol = 4);

        // init constructor version 2
        Puzzle(int nrow, int ncol, int* entries);

        // copy constructor
        Puzzle(const Puzzle& source);

        // destructor
        ~Puzzle();

        // deep copy assignment operator
        Puzzle& operator = (const Puzzle& source);

        // Comparison operator: Puzzles are equal when they are the same
        bool operator == (const Puzzle& compareTo) const;

        // get Nrow
        int GetNrow() const;

        // get Ncol
        int GetNcol() const;

        // get Vblank
        int GetVblank() const;

        // get Hblank
        int GetHblank() const;

        // get Entries
        int** GetEntries() const;

        // set Entries
        void SetEntries(int* entries);

        // displaying
        void Display() const;

        // swap blank space and a nearby entry
        bool Swap(MoveDirect thisDirect);

        // swap blank space and a nearby entry, no message for invalid moves
        bool Swap_NoMessage(MoveDirect thisDirect);

        // randomly permute all entries
        void RandomSet();

        // let user set the entries
        void ByUser();

        // count number of inversions
        int CountInversions(int irow, int icol) const;

        // sum number of inversions
        int SumInversions() const;

        // function to determine solvability
        bool IsSolvable() const;

        // check if Puzzle is same as default
        bool IsDefault() const;

        // manhattan distance between *this and default
        int Heuristic() const;


    private:
        // data fields
        int Nrow; // number of rows
        int Ncol; // number of columns
        int Vblank; // row index of blank space, between 0 and Nrow - 1
        int Hblank; // column index of blank space, between 0 and Ncol - 1
        int** Entries; // 2d-array for storing entries

};

Puzzle.cpp

#include <iostream>
#include <iomanip>
#include <cmath>
#include <algorithm>
#include <time.h>
#include "Puzzle.h"
#include <limits>
#include <complex>

// default & init constructor
Puzzle::Puzzle(int nrow, int ncol){
   Nrow = nrow;
   Ncol = ncol;

   Entries = new int*[Nrow];
   for(int i = 0; i < Nrow; i++){
       Entries[i] = new int[Ncol];
   }

   for(int i = 0; i< Nrow; i++){
       for(int j = 0; j < Ncol; j++){
           Entries[i][j] = i*Ncol + j + 1;
       }
   }

   Entries[Nrow-1][Ncol-1] = 0;

   Vblank = Nrow - 1;
   Hblank = Ncol - 1;

}

// init constructor version 2
Puzzle::Puzzle(int nrow, int ncol, int* entries){
   Nrow = nrow;
   Ncol = ncol;
   Entries = new int*[Nrow];
   for(int i = 0; i < Nrow; i++){
       Entries[i] = new int[Ncol];
   }

   int index = 0;
   for(int i = 0; i< Nrow; i++){
       for(int j = 0; j < Ncol; j++){
           Entries[i][j] = entries[index];
           if (Entries[i][j] == 0){
               Vblank = i;
               Hblank = j;
           }
           index++;
       }
   }

}

// copy constructor
Puzzle::Puzzle(const Puzzle& source){
   // std::cout << std::endl << "copy constructor called" << std::endl;
   Entries = NULL;
   // Calls the assignment operator
   *this = source;
}

// destructor
Puzzle::~Puzzle(){
   // std::cout << std::endl << "destructor called" << std::endl;
   for(int i = 0; i < Nrow; i++){
       delete[] Entries[i];
   }
   delete[] Entries;
   Entries = NULL;
}

// deep copy assignment operator
Puzzle& Puzzle::operator = (const Puzzle& source){
   // std::cout << std::endl << "deep copy assignment operator called" << std::endl;

   // first we have to dispose previously allocated memory
   if(Entries != NULL){
       for(int i = 0; i < Nrow; i++){
           delete[] Entries[i];
       }
       delete[] Entries;
   }

   // copy fields
   Nrow = source.GetNrow();
   Ncol = source.GetNcol();
   Vblank = source.GetVblank();
   Hblank = source.GetHblank();

   // allocate new memory
   Entries = new int*[Nrow];
   for(int i = 0; i < Nrow; i++){
       Entries[i] = new int[Ncol];
   }

   // deep copy
   for(int i = 0; i < Nrow; i++){
       for(int j = 0; j < Ncol; j++){
           Entries[i][j] = source.GetEntries()[i][j];
       }
   }

   return
       *this;

}

// Comparison operator: Puzzles are equal when their static fields are the same
// , and they dynamic fields store the same values
bool Puzzle::operator == (const Puzzle& compareTo) const{
   if(Nrow == compareTo.GetNrow() && Ncol == compareTo.GetNcol() && Vblank == compareTo.GetVblank() && Hblank == compareTo.GetHblank()){
       bool isEqual = true;
       for(int i = 0; (i < Nrow) && (isEqual == true); i++){
           for(int j = 0; (j < Ncol) && (isEqual == true); j++){
               isEqual = (Entries[i][j] == compareTo.GetEntries()[i][j]);
           }
       }
       return isEqual;
   }else{
       return false;
   }
}

// get Nrow
int Puzzle::GetNrow() const {
   return Nrow;
}

// get Ncol
int Puzzle::GetNcol() const {
   return Ncol;
}

// get Vblank
int Puzzle::GetVblank() const {
   return Vblank;
}

// get Hblank
int Puzzle::GetHblank() const {
   return Hblank;
}

// get Entries
int** Puzzle::GetEntries() const {
   return Entries;
}

// set Entries
void Puzzle::SetEntries(int* entries){
   int index = 0;
   for(int i = 0; i < Nrow; i++){
       for(int j = 0; j < Ncol; j++){
           Entries[i][j] = entries[index];
           if (Entries[i][j] == 0){
               Vblank = i;
               Hblank = j;
           }
           index++;
       }
   }
}

// randomly permute all entries
void Puzzle::RandomSet(){
   int *entries = new int[Nrow*Ncol+1];
   for(int i = 0; i < (Nrow*Ncol); i++){
       entries[i] = i + 1;
   }
   entries[Nrow*Ncol-1] = 0;
   entries[Nrow*Ncol] = 0;

   /* initialize random seed:*/
   srand(time(NULL));

   std::random_shuffle(entries, entries + Nrow*Ncol);
   int index = 0;
   for(int i = 0; i < Nrow; i++){
       for(int j = 0; j < Ncol; j++){
           Entries[i][j] = entries[index];
           if (Entries[i][j] == 0){
               Vblank = i;
               Hblank = j;
           }
           index++;
       }
   }

   if(!IsSolvable()){
       bool stop = false;
       int index_ = 0;
       int temp;
       while(!stop){
           if(entries[index_]!=0 && entries[index_+1]!=0 && index_<(Nrow*Ncol-1)){
               stop = true;

           }else{
               index_++;
           }
       }
       temp = entries[index_];
       entries[index_] = entries[index_+1];
       entries[index_+1] = temp;

       index = 0;
       for(int i = 0; i < Nrow; i++){
           for(int j = 0; j < Ncol; j++){
               Entries[i][j] = entries[index];
               if (Entries[i][j] == 0){
                   Vblank = i;
                   Hblank = j;
               }
               index++;
           }
       }
   }

   delete[] entries;
}

// let user set the entries
void Puzzle::ByUser(){
   std::cout << "Please enter the entries for this " << Nrow << " x " << Ncol << " gem puzzle. 0 represents empty space." << std::endl;
   int* tempEntries = new int[Nrow*Ncol];
   for (int i = 0; i < Nrow*Ncol; i++){
       tempEntries[i] = -1;
   }
   int tempIndex = 0;
   bool somethingWrong;
   for(int i = 0; i < Nrow; i++){
       for(int j = 0; j < Ncol; j++){
           do{
               somethingWrong = false;

               for (;;) {
                   std::cout << "[" << i << "][" << j << "]: ";
                   if (std::cin >> tempEntries[tempIndex]) {
                       break;
                   } else {
                       std::cout << std::endl << "Please enter a valid integer within [" << 0 << ", " << Nrow*Ncol-1 << "]" << std::endl;
                       std::cin.clear();
                       std::cin.ignore(std::numeric_limits<std::streamsize>::max(), ' ');
                   }
               }

               if(tempEntries[tempIndex] < 0 || tempEntries[tempIndex] >= Nrow*Ncol){
                   std::cout << std::endl << "Out of bounds!" << std::endl;
                   somethingWrong = true;
               }else{
                   for(int k = 0; k < tempIndex; k++){
                       if(tempEntries[tempIndex] == tempEntries[k]){
                           std::cout << std::endl << "Same value entered before!" << std::endl;
                           somethingWrong = true;
                           break;
                       }
                   }
               }

           }while(somethingWrong);

           Entries[i][j] = tempEntries[tempIndex];

           tempIndex++;

           if (Entries[i][j] == 0){
               Vblank = i;
               Hblank = j;
           }

           std::cout << std::endl;
       }
   }
}

// displaying
void Puzzle::Display() const {
   int width = 4 + int(std::log10(Nrow * Ncol));
   std::cout << std::endl;
   for(int i = 0; i < Nrow; i++){
       for(int j = 0; j < Ncol; j++){
           if( (i == Vblank) && (j == Hblank) ){
               std::cout << std::setw(width) << " ";
           }else{
               std::cout << std::setw(width) << Entries[i][j];
           }
       }
       std::cout << std::endl;
   }

}

// swap blank space and a nearby entry
bool Puzzle::Swap(MoveDirect thisDirect){
   int temp;
   switch(thisDirect){
   case BLANK_UP:
       if(Vblank != 0){
           temp = Entries[Vblank-1][Hblank];
           Entries[Vblank-1][Hblank] = 0;
           Entries[Vblank][Hblank] = temp;
           Vblank -= 1;
       }else{
           std::cout << std::endl << "Invalid move!" << std::endl;
           return false;
       }
       break;
   case BLANK_DOWN:
       if(Vblank != (Nrow-1)){
           temp = Entries[Vblank+1][Hblank];
           Entries[Vblank+1][Hblank] = 0;
           Entries[Vblank][Hblank] = temp;
           Vblank += 1;
       }else{
           std::cout << std::endl << "Invalid move!" << std::endl;
           return false;
       }
       break;
   case BLANK_LEFT:
       if(Hblank != 0){
           temp = Entries[Vblank][Hblank-1];
           Entries[Vblank][Hblank-1] = 0;
           Entries[Vblank][Hblank] = temp;
           Hblank -= 1;
       }else{
           std::cout << std::endl << "Invalid move!" << std::endl;
           return false;
       }
       break;
   case BLANK_RIGHT:
       if(Hblank != (Ncol-1)){
           temp = Entries[Vblank][Hblank+1];
           Entries[Vblank][Hblank+1] = 0;
           Entries[Vblank][Hblank] = temp;
           Hblank += 1;
       }else{
           std::cout << std::endl << "Invalid move!" << std::endl;
           return false;
       }
       break;
   default:;
   }
   return true;
}

// swap blank space and a nearby entry, no message for invalid moves
bool Puzzle::Swap_NoMessage(MoveDirect thisDirect){
   int temp;
   switch(thisDirect){
   case BLANK_UP:
       if(Vblank != 0){
           temp = Entries[Vblank-1][Hblank];
           Entries[Vblank-1][Hblank] = 0;
           Entries[Vblank][Hblank] = temp;
           Vblank -= 1;
       }else{
           //std::cout << std::endl << "Invalid move!" << std::endl;
           return false;
       }
       break;
   case BLANK_DOWN:
       if(Vblank != (Nrow-1)){
           temp = Entries[Vblank+1][Hblank];
           Entries[Vblank+1][Hblank] = 0;
           Entries[Vblank][Hblank] = temp;
           Vblank += 1;
       }else{
           //std::cout << std::endl << "Invalid move!" << std::endl;
           return false;
       }
       break;
   case BLANK_LEFT:
       if(Hblank != 0){
           temp = Entries[Vblank][Hblank-1];
           Entries[Vblank][Hblank-1] = 0;
           Entries[Vblank][Hblank] = temp;
           Hblank -= 1;
       }else{
           //std::cout << std::endl << "Invalid move!" << std::endl;
           return false;
       }
       break;
   case BLANK_RIGHT:
       if(Hblank != (Ncol-1)){
           temp = Entries[Vblank][Hblank+1];
           Entries[Vblank][Hblank+1] = 0;
           Entries[Vblank][Hblank] = temp;
           Hblank += 1;
       }else{
           //std::cout << std::endl << "Invalid move!" << std::endl;
           return false;
       }
       break;
   default:;
   }
   return true;
}

// count number of inversions
int Puzzle::CountInversions(int irow, int icol) const{
   int inversions = 0;
   int currentIndex = irow * Ncol + icol;
   int lastIndex = Ncol*Nrow;
   int currentValue = Entries[irow][icol];
   int jrow, jcol;
   int compValue;
   for (int i=currentIndex+1; i<lastIndex; i++) {
       jrow = floor(i / Ncol);
       jcol = i % Ncol;
       compValue = Entries[jrow][jcol];
       if (currentValue > compValue && currentIndex != (lastIndex-1) && compValue != 0) {
           inversions++;
       }
   }
   return inversions;
}

// sum number of inversions
int Puzzle::SumInversions() const{
   int inversions = 0;
   for (int irow=0; irow < Nrow; irow++) {
       for (int icol=0; icol < Ncol; icol++) {
           inversions += CountInversions(irow,icol);
       }
   }
   return inversions;
}

// function to determine solvability
bool Puzzle::IsSolvable() const{
   if (Ncol % 2 == 1) {
       return (SumInversions() % 2 == 0);
   }
   else {
       return ((SumInversions() + Nrow - Vblank - 1) % 2 == 0);
   }
}

// check if Puzzle is same as default
// chengping please check if it works
bool Puzzle::IsDefault() const{
   Puzzle tempPuzzle(Nrow, Ncol);
   return tempPuzzle == *this;
}

// manhattan distance between *this and default
int Puzzle::Heuristic() const{
   int heuristic = 0;
   int i,j, i_, j_;
   int cellValue;
   for(i = 0; i < Nrow; i++){
       for(j = 0; j < Ncol; j++){
           cellValue = Entries[i][j];
           if(cellValue != 0){
               i_ = (cellValue-1) / Ncol;
               j_ = (cellValue-1) % Ncol;
               heuristic += std::abs(i-i_) + std::abs(j-j_);
           }
       }
   }
   return heuristic;
}

tests.cpp

#include <iostream>
#include "Game.h"

void testPuzzle(){
    std::cout << "Tests for Puzzle:" << std::endl;
    // testing IsDefault()
    std::cout << "0. testing IsDefault():" << std::endl;
    Puzzle myPuzzleNeg1(3,3);
    myPuzzleNeg1.Display();
    std::cout << std::endl << myPuzzleNeg1.IsDefault() << std::endl;
    myPuzzleNeg1.RandomSet();
    myPuzzleNeg1.Display();
    std::cout << std::endl << myPuzzleNeg1.IsDefault() << std::endl;
    int resetArray[] = {1, 2, 3, 4, 5, 6, 7, 8, 0};
    myPuzzleNeg1.SetEntries(resetArray);
    myPuzzleNeg1.Display();
    std::cout << std::endl << myPuzzleNeg1.IsDefault() << std::endl;
    std::cin.ignore();

    // testing default constructor
    std::cout << "1. testing default constructor:" << std::endl;
    Puzzle myPuzzle0;
    myPuzzle0.Display();
    std::cin.ignore();

    // testing init constructor
    std::cout << "2. testing init constructor:" << std::endl;
    Puzzle myPuzzle1(3,5);
    myPuzzle1.Display();
    std::cin.ignore();

    // testing init constructor version 2
    std::cout << "3. testing init constructor versioin 2:" << std::endl;
    int thisArray[] = {2, 1, 7, 13, 12, 11, 16, 15, 3, 4, 5, 6, 8, 9, 10, 14, 17, 18, 19, 0, 20, 21, 22, 23};
    Puzzle myPuzzle2(4,6,thisArray);
    myPuzzle2.Display();
    std::cin.ignore();

    // testing copy constructor
    std::cout << "4. testing copy constructor:" << std::endl;
    Puzzle myPuzzle3 = myPuzzle2;
    myPuzzle3.Display();
    std::cin.ignore();

    // testing deep copy assignment operator and RandomSet()
    std::cout << "5. testing deep copy assignment operator:" << std::endl;
    myPuzzle3 = myPuzzle1;
    myPuzzle3.Display();
    myPuzzle3.RandomSet();
    myPuzzle3.Display();
    myPuzzle1.Display();
    std::cin.ignore();

    // testing GetNrow(), GetNcol(), GetVblank(), GetHblank()
    std::cout << "6. testing GetNrow(), GetNcol(), GetVblank(), GetHblank():" << std::endl;
    std::cout << "myPuzzle3.GetNrow() -- " << myPuzzle3.GetNrow() << std::endl;
    std::cout << "myPuzzle3.GetNcol() -- " << myPuzzle3.GetNcol() << std::endl;
    std::cout << "myPuzzle3.GetVblank() -- " << myPuzzle3.GetVblank() << std::endl;
    std::cout << "myPuzzle3.GetHblank() -- " << myPuzzle3.GetHblank() << std::endl;
    std::cin.ignore();

    // testing SetEntries()
    std::cout << "7. testing SetEntries():" << std::endl;
    Puzzle myPuzzle4(3,2);
    myPuzzle4.Display();
    int thatArray[] = {5, 0, 1, 4, 3, 2};
    myPuzzle4.SetEntries(thatArray);
    myPuzzle4.Display();
    std::cin.ignore();

    // testing Swap()
    std::cout << "8. testing Swap():" << std::endl;
    Puzzle myPuzzle6(6,6);
    myPuzzle6.RandomSet();
    myPuzzle6.Display();
    std::cin.ignore();
    myPuzzle6.Swap(BLANK_DOWN);
    myPuzzle6.Display();
    std::cin.ignore();
    myPuzzle6.Swap(BLANK_LEFT);
    myPuzzle6.Display();
    std::cin.ignore();
    myPuzzle6.Swap(BLANK_UP);
    myPuzzle6.Display();
    std::cin.ignore();
    myPuzzle6.Swap(BLANK_RIGHT);
    myPuzzle6.Display();
    std::cin.ignore();
    for(int i = 0; i < 6; i++){
        myPuzzle6.Swap(BLANK_RIGHT);
        myPuzzle6.Display();
        std::cin.ignore();
    }
    for(int i = 0; i < 6; i++){
        myPuzzle6.Swap(BLANK_DOWN);
        myPuzzle6.Display();
        std::cin.ignore();
    }
    for(int i = 0; i < 6; i++){
        myPuzzle6.Swap(BLANK_LEFT);
        myPuzzle6.Display();
        std::cin.ignore();
    }
    for(int i = 0; i < 6; i++){
        myPuzzle6.Swap(BLANK_UP);
        myPuzzle6.Display();
        std::cin.ignore();
    }

    // testing ByUser();
    std::cout << "9. testing ByUser():" << std::endl;
    Puzzle myPuzzle5;
    myPuzzle5.ByUser();
    myPuzzle5.Display();
    std::cout << std::endl;
    std::cin.ignore();
    Puzzle myPuzzle5b(3,3);
    myPuzzle5b.ByUser();
    myPuzzle5b.Display();
    std::cout << std::endl;
    std::cin.ignore();
    std::cin.get();

    // testing Puzzle::operator ==
    std::cout << "10. testing Puzzle::operator ==" << std::endl;
    Puzzle myPuzzle7(2,2);
    int tempArray1[] = {3,0,1,2};
    myPuzzle7.SetEntries(tempArray1);
    myPuzzle7.Display();

    Puzzle myPuzzle8(2,2);
    int tempArray2[] = {0,3,1,2};
    myPuzzle8.SetEntries(tempArray2);
    myPuzzle8.Display();

    std::cout << std::endl << (myPuzzle7 == myPuzzle8) << std::endl;

    myPuzzle7.Swap(BLANK_LEFT);
    std::cout << std::endl << (myPuzzle7 == myPuzzle8) << std::endl;


    // testing functions used in determining solvability
    std::cout << "11. testing functions used in determining solvability" << std::endl;
    // testing CountInversions
    Puzzle myPuzzle9(4,4);
    //int thatArray3[] = {8,13,1,4,2,14,0,5,3,12,10,7,11,6,9,15};
    //int thatArray3[] = {6,1,10,2,7,11,4,14,5,0,9,15,8,12,13,3};
    int thatArray3[] = {12,1,10,2,7,11,4,14,5,0,9,15,8,13,6,3};
    int temp;
    myPuzzle9.SetEntries(thatArray3);
    myPuzzle9.Display();
    temp = myPuzzle9.CountInversions(0, 0);
    std::cout << std::endl << temp << std::endl;
    // testing SumInversions
    temp = myPuzzle9.SumInversions();
    std::cout << std::endl << temp << std::endl;
    Puzzle myPuzzle10(4,4);
    //int thatArray4[] = {8,13,1,4,2,14,10,5,3,12,0,7,11,6,9,15};
    //int thatArray4[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,15,14,0};
    int thatArray4[] = {12,1,10,2,7,0,4,14,5,11,9,15,8,13,6,3};
    myPuzzle10.SetEntries(thatArray4);
    myPuzzle10.Display();
    temp = myPuzzle10.SumInversions();
    std::cout << std::endl << temp << std::endl;
    // testing IsSolvable
    bool temp2,temp3;
    temp2 = myPuzzle9.IsSolvable();
    std::cout << std::endl << temp2 << std::endl;
    temp3 = myPuzzle10.IsSolvable();
    std::cout << std::endl << temp3 << std::endl;
    Puzzle myPuzzle11;
    int thatArray5[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};
    myPuzzle11.SetEntries(thatArray5);
    myPuzzle11.Display();
    std::cout << std::endl << myPuzzle11.IsSolvable() << std::endl;
    int thatArray6[] = {1,2,4,3,5,0,6,7,8,10,9,11,12,13,15,14};
    myPuzzle11.SetEntries(thatArray6);
    myPuzzle11.Display();
    std::cout << std::endl << myPuzzle11.IsSolvable() << std::endl;
    int thatArray7[] = {2,10,4,8,9,6,14,12,1,5,0,15,13,7,3,11};
    myPuzzle11.SetEntries(thatArray7);
    myPuzzle11.Display();
    std::cout << std::endl << myPuzzle11.IsSolvable() << std::endl;
    int thatArray8[] = {15,12,9,14,8,2,0,4,13,1,6,11,5,10,7,3};
    myPuzzle11.SetEntries(thatArray8);
    myPuzzle11.Display();
    std::cout << std::endl << myPuzzle11.IsSolvable() << std::endl;

    // testing Huristic()
    std::cout << std::endl << "testing Huristic()" << std::endl;
    Puzzle myPuzzle12;
    int thatArray12[] = {2,10,4,8,9,6,14,12,1,0,5,15,13,7,3,11};
    myPuzzle12.SetEntries(thatArray12);
    myPuzzle12.Display();
    std::cout << std::endl << myPuzzle12.Heuristic() << std::endl;

    /*Puzzle myPuzzle13;
        int thatArray[]={14,9,4,3,10,7,15,2,1,0,13,12,5,11,8,6};
        myPuzzle13.SetEntries(thatArray);
        myPuzzle13.Display();
        PuzzleSearchNode myPuzzleSearchNode1(myPuzzle13,0);
        myPuzzleSearchNode1.PuzzleToSolve.Display();
        std::cout << std::endl << myPuzzleSearchNode1.G << " " << myPuzzleSearchNode1.H << " " << myPuzzleSearchNode1.F << std::endl;
        Game myGame1;
        myGame1.GetCurrentPuzzle() -> SetEntries(thatArray);
        myGame1.Display();
        PuzzleSearchNode Root(*(myGame1.GetCurrentPuzzle()), 0);
        std::cout << std::endl << Root.G << " " << Root.H << " " << Root.F << std::endl;
        Root.PuzzleToSolve.RandomSet();
        myGame1.Display();
        Root.PuzzleToSolve.Display();
        std::cout << std::endl << Root.G << " " << Root.H << " " << Root.F << std::endl;
        Root.CalcHF();
        std::cout << std::endl << Root.G << " " << Root.H << " " << Root.F << std::endl;*/

}


void testGame(){
    std::cout << "Tests for Game:" << std::endl;
    // testing constructors etc.
    std::cout << "0. testing constructors etc.:" << std::endl;
    Game firstGame(3,3);
    Game secondGame = firstGame;
    Game thirdGame(3,3);
    firstGame.Display();
    secondGame.Display();
    thirdGame.Display();
    Game fourthGame(3,3);
    secondGame = fourthGame;
    thirdGame = fourthGame;
    firstGame.Display();
    secondGame.Display();
    thirdGame.Display();
    thirdGame.Display();
    Game fifthGame;
    std::cout << std::endl << fifthGame.IsWin() << std::endl;

    /*Puzzle myPuzzle14(3,3);
    int thatArray14[] = {4,0,5,8,3,2,1,6,7};
    myPuzzle14.SetEntries(thatArray14);
    myPuzzle14.Display();
    std::cout << std::endl << myPuzzle14.IsSolvable() << std::endl;
    Game myGame14(3,3);
    myGame14.GetInitialPuzzle() -> SetEntries(thatArray14);
    myGame14.GetCurrentPuzzle() -> SetEntries(thatArray14);
    myGame14.Display();
    myGame14.SolveIt();
    myGame14.Display();*/

}


main.cpp

#include <iostream>
#include "Game.h"
#include "tests.h"
#include <time.h>
#include "menu.h"

using namespace std;

int main()
{
    try{

        welcomeMenu();

        mainMenu();

        /*Puzzle myPuzzle14(3,3);
    int thatArray14[] = {4,0,5,8,3,2,1,6,7};
    myPuzzle14.SetEntries(thatArray14);
    myPuzzle14.Display();
    std::cout << std::endl << myPuzzle14.IsSolvable() << std::endl;
    Game myGame14(3,3);
    myGame14.GetInitialPuzzle() -> SetEntries(thatArray14);
    myGame14.GetCurrentPuzzle() -> SetEntries(thatArray14);
    myGame14.Display();
    myGame14.SolveIt();
    myGame14.Display();*/

        //testPuzzle();

        //testGame();

    }catch(...){
        std::cout << std::endl << "Oops, program ended due to error! Plz try again!" << std::endl;
    }

    return 0;
}

menu.cpp

#include <iostream>
#include "Game.h"
#include <limits>

#define FOUND -100
#define NOTFOUND -200

void welcomeMenu(){
    std::cout << std::endl << "Welcome to GemPuzzle :)";
    std::cout << std::endl << "This program allows you to play a 3x3 GemPuzzle.";
    std::cout << std::endl << "The goal is to place the 8 tiles in order,";
    std::cout << std::endl << "by sliding tiles adjacent to the empty space.";
    std::cout << std::endl << "The program is also able to find a shortest solution." << std::endl;
    Puzzle solvedEightPuzzle(3,3);
    std::cout << std::endl << "Diagram of solved 8-Puzzle:";
    solvedEightPuzzle.Display();
}

void gameMenu(){
    Game aNewGame(3, 3);
    std::cout << std::endl << "Current Puzzle:" << std::endl;
    aNewGame.GetCurrentPuzzle() -> Display();
    bool exit = false;
    int choice;
    while(!exit){
        std::cout << std::endl << "Game Menu:";
        std::cout << std::endl << "1. Play; 2. Solve for Me; 3. Game Info; 4. Replay; 5. Main Menu." << std::endl;

        for(;;){
            if (std::cin >> choice && choice > 0 && choice < 6) {
                break;
            } else {
                std::cout << std::endl << "Please enter 1, 2, 3, 4 or 5:";
                std::cout << std::endl << "1. Play; 2. Solve for Me; 3. Game Info; 4. Replay; 5. Main Menu." << std::endl;
                std::cin.clear();
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(), ' ');
            }
        }

        switch(choice){
            case 1:
                std::cout << std::endl << "Current Puzzle:" << std::endl;
                aNewGame.GetCurrentPuzzle() -> Display();
                aNewGame.MoveInterface();
                break;

            case 2:
                if(aNewGame.SolveIt() == NOTFOUND){
                    std::cout << std::endl << "This is NOT solvable :(" << std::endl;
                }else{
                    std::cout << std::endl << "Got it :) Shortest solution found & appended to Move History. Solved game:" << std::endl;
                    aNewGame.Display();
                }
                break;

            case 3:
                std::cout << std::endl << "Game Info:" << std::endl;
                aNewGame.Display();
                break;

           case 4:
               aNewGame.Replay();
               break;

            case 5:
                exit = true;
                break;
            default:;
        }

    }

}

void mainMenu(){
    bool exit = false;
    int choice;
    while (!exit){
        std::cout << std::endl << "Main Menu:";
        std::cout << std::endl << "1. New Game; 2. Exit." << std::endl;

        for(;;){
            if (std::cin >> choice && choice > 0 && choice < 3) {
                break;
            } else {
                std::cout << std::endl << "Please enter 1 or 2:";
                std::cout << std::endl << "1. New Game; 2. Exit." << std::endl;
                std::cin.clear();
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(), ' ');
            }
        }

        switch(choice){
            case 1:
                gameMenu();
                break;
            case 2:
                exit = true;
                std::cout << std::endl << "Byebye!" << std::endl;
                break;
            default:;
        }

    }
}

PuzzleSearchNode.h

#pragma once

#include "Puzzle.h"

// a Puzzle object stores configuration of any gem puzzle
// class Puzzle is the building block for GemPuzzle project
struct PuzzleSearchNode{

    // init constructor
    PuzzleSearchNode(const Puzzle& thisPuzzle, int g){
        PuzzleToSolve = thisPuzzle;
        G = g;

        CalcHF();

        Parent = NULL;
        GetHere = BLANK_UP;

    }

    // re-calcuate H, F
    void CalcHF(){
        H = PuzzleToSolve.Heuristic();
        F = G + H;
    }

    Puzzle PuzzleToSolve;
    int G; // past path-cost
    int H; // heuristic future path-cost
    int F; // total cost
    PuzzleSearchNode* Parent;
    MoveDirect GetHere;

};

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote