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;
};
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.