Sokobon Game in C++
#include<iostream>
#include<conio.h>
#include<stdlib.h>
#include<windows.h>
#include<fstream>
using namespace std;
//Size of game area
const int MAX_COL = 8;
const int MAX_ROW = 7;
int count_move = 0;
struct coord
{
int x;
int y;
};
class block
{
public:
int x;
int y;
void set_coord(int x, int y){
this-> x = x;
this-> y = y;
}
//Condition to move the box from different sides.
void left_right_push(coord player, int lr){ //Left push x - 1 & right push x + 1
if( x == player.x + lr && y == player.y)
x += lr;
}
void up_down_push(coord player, int ud){ //up push y - 1 & down push y + 1
if( y == player.y + ud && x == player.x)
y += ud;
}
/////////////////////////////////////////////// METHODS FOR Resisting ///////////////////////////////////////
//Condition to resist box move when near to (another box OR a wall)
void nearby_lr(block box, coord& player, int lr){ //It has inverse sign because every action has reaction but opposite in direction
if((x+(lr)*2 == box.x+lr) && (y == box.y)){ //we have to resist the player to move the box when they align side by side
if((box.x+lr == player.x) && (box.y == player.y)){
player.x += lr; //to cancel the effect of coming decrement to remain in the same position
box.x += lr;
count_move--;
}
}
}
void nearby_ud(block box, coord& player, int ud){ //It has inverse sign because every action has reaction but opposite in direction
if((y+(ud)*2 == box.y+ud) && (x == box.x)){
if((box.y+ud == player.y) && (box.x == player.x)){
player.y += ud;
box.y += ud;
count_move--;
}
}
}
//Condition to resist player move when near to wall
void nearwall_lr(coord& player, int lr){ //It has inverse sign because every action has reaction but opposite in direction
if((x+lr == player.x) && (y == player.y)){
player.x += lr; //to cancel the effect of coming decrement to remain in the same position
count_move--;
}
}
void nearwall_ud(coord& player, int ud){ //It has inverse sign because every action has reaction but opposite in direction
if((y+ud == player.y) && (x == player.x)){
player.y += ud;
count_move--;
}
}
//Condition to resist box move at the boundary
void at_boundary_lr(coord& player, int lr, int boundary){
if(x + lr == boundary + (lr)*2 && ((player.x == x + lr)&&(player.y == y))){
player.x += lr;
x += lr;
count_move--;
}
}
void at_boundary_ud(coord& player, int ud, int boundary){
if(y + ud == boundary + (ud)*2 && ((player.y == y + ud)&&(player.x == x))){
player.y += ud;
y += ud;
count_move--;
}
}
};
int main()
{
fstream hiscore;
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
char key;
int score = 0;
string name = "";
SetConsoleTextAttribute(h, 255);
//############################################ HOME SCREEN ####################################################//
HOME_SCREEN:
coord choose={5, 1};
hiscore.open("high score.dat", ios::in);
hiscore >> score; hiscore >> name;
do{
//Condition to jump into help screen or into game screen
if(key == '\r'){
hiscore.close();
if(choose.y == 1)
goto GAME_SCREEN;
else if(choose.y == 3)
goto HELP_SCREEN;
else if(choose.y == 5)
goto ABOUT;
}
//to select to the option from the list
switch(key){
case 72: //UP KEY
if(choose.y == 1) //resist to move further up at row 1
choose.y += 2;
choose.y -= 2;
break;
case 80: //DOWN KEY
if(choose.y == 5) // resist to move further down at row 5
choose.y -= 2;
choose.y += 2;
break;
}
system("cls");
//to display the home list
SetConsoleTextAttribute(h, 251);
cout << "\n\t\x0f";
SetConsoleTextAttribute(h, 252);
cout<<" SOKOBAN GAME ";
SetConsoleTextAttribute(h, 251);
cout << "\x0f\n\n";
SetConsoleTextAttribute(h, 255);
for(int y = 1; y <= 5; y++){
for(int x = 1; x <= 6; x++){
if(choose.x == x && choose.y == y){
SetConsoleTextAttribute(h, 240);
cout << ">";
SetConsoleTextAttribute(h, 255);
}
else if(x == 6 && y == 1){
SetConsoleTextAttribute(h, 244);
cout << " START GAME";
SetConsoleTextAttribute(h, 255);
}
else if(x == 6 && y == 3){
SetConsoleTextAttribute(h, 244);
cout << " HELP";
SetConsoleTextAttribute(h, 244);
}
else if(x == 6 && y == 5){
SetConsoleTextAttribute(h, 244);
cout << " ABOUT";
SetConsoleTextAttribute(h, 255);
}
else
cout << " ";
}
cout << endl;
}
SetConsoleTextAttribute(h, 240);
cout << "\nHigh Score : ";
SetConsoleTextAttribute(h, 254);
cout << name;
SetConsoleTextAttribute(h, 240);
cout << " in ";
SetConsoleTextAttribute(h, 254);
cout << score;
SetConsoleTextAttribute(h, 240);
cout << " moves";
SetConsoleTextAttribute(h, 255);
key = getch();
}while(true);
//############################################ INTRODUCTION ####################################################//
ABOUT :
SetConsoleTextAttribute(h, 240);
system("CLS");
Sleep(500); cout << "First Year "; Sleep(500); cout << " First Semester" << endl;
Sleep(500); cout << "\nPROJECT : "; Sleep(500); cout << "SOKOBAN GAME" << endl;
Sleep(500); cout << "MADE BY : "; Sleep(1000); cout << "19SW - 05" << endl;
Sleep(1000); cout << "FARAZ AHMED"; Sleep(3000);
key = 0; //reset key
SetConsoleTextAttribute(h, 255);
goto HOME_SCREEN;
//############################################ HELP SCREEN ####################################################//
HELP_SCREEN:
do{
if(key == 8) //Backspace
goto HOME_SCREEN;
system("CLS");
SetConsoleTextAttribute(h, 240);
cout << "\t***HELP***\n";
cout << "1. Use cursor keys for movement\nof player." << endl;
cout << "2. Place all the boxes in the\nspaces shown by star * to win \nthe game." << endl;
cout << "Press 'r' to reset the box position." << endl;
cout << "Player : \x02" << endl;
cout << "Box : \xB1" << endl;
cout << "Spaces : * ";
key = getch();
SetConsoleTextAttribute(h, 255);
}while(true);
//############################################ GAME SCREEN ####################################################//
GAME_SCREEN:
const int MAX_BOX = 6;
const int MAX_WALL = 3;
block box[MAX_BOX];
block store_box[MAX_BOX];
block wall[MAX_WALL];
//initialize store block coordinates
int count_store = 0;
for(int x = 4; x <= 5; x++)
for(int y = 3; y <= 5; y++)
{
store_box[count_store].set_coord(x, y);
count_store++;
}
//initialize box coordinates
int count_box = 0;
for(int x = 3; x <= 6; x += 3)
for(int y = 3; y <= 5; y++){
if(x == 6 && y == 4)
box[count_box].set_coord(x-1, y);
else
box[count_box].set_coord(x, y);
count_box++;
}
//initialize wall coordinates
wall[0].set_coord(4,2);
wall[1].set_coord(4,6);
wall[2].set_coord(7,4);
coord player = {2, 2};
do{
//Action on cursor keys
switch(key){
/////////////////////////////////////////////// ACTION ON UP KEY /////////////////////////////////////////////
case 72: //UP KEY
//Condition to resist the movement when two box are side by side
//nested loop is used for checking which boxes are near to each other in the game area
for(int index1 = 0; index1 < MAX_BOX; index1++){
for(int index2 = 0; index2 < MAX_BOX; index2++){
if(index1 != index2){
box[index1].nearby_ud(box[index2], player, 1); //to resist the player in moving the box means
} //force should be on the player means opposite in direction.
}
}
for(int index1 = 0; index1 < MAX_WALL; index1++){ //same as above condition just difference is there is wall
for(int index2 = 0; index2 < MAX_BOX; index2++){ //in place of second box.
wall[index1].nearby_ud(box[index2], player, 1);
}
}
//Condition to resist box at boundary
for(int index = 0; index < MAX_BOX; index++){
box[index].at_boundary_ud(player, 1, 1);
}
//condition to resist the move of player at the boundary
if(player.y == 2){
player.y++;
count_move--;
}
//condition to resist the move of player near wall
for(int index = 0; index < MAX_WALL; index++){
wall[index].nearwall_ud(player,1);
}
//Condition for pushing the box
for(int index = 0; index < MAX_BOX; index++)
box[index].up_down_push(player,-1);
player.y--;
count_move++;
break;
/////////////////////////////////////////////// ACTION ON DOWN KEY /////////////////////////////////////////////
case 80: //DOWN KEY
for(int index1 = 0; index1 < MAX_BOX; index1++){
for(int index2 = 0; index2 < MAX_BOX; index2++){
if(index1 != index2){
box[index1].nearby_ud(box[index2], player, -1);
}
}
}
for(int index1 = 0; index1 < MAX_WALL; index1++){
for(int index2 = 0; index2 < MAX_BOX; index2++){
wall[index1].nearby_ud(box[index2], player, -1);
}
}
for(int index = 0; index < MAX_BOX; index++){
box[index].at_boundary_ud(player, -1, MAX_ROW);
}
if(player.y == MAX_ROW - 1){
player.y--;
count_move--;
}
for(int index = 0; index < MAX_WALL; index++){
wall[index].nearwall_ud(player,-1);
}
for(int index = 0; index < MAX_BOX; index++)
box[index].up_down_push(player, 1);
player.y++;
count_move++;
break;
/////////////////////////////////////////////// ACTION ON LEFT KEY /////////////////////////////////////////////
case 75: //LEFT KEY
for(int index1 = 0; index1 < MAX_BOX; index1++){
for(int index2 = 0; index2 < MAX_BOX; index2++){
if(index1 != index2){
box[index1].nearby_lr(box[index2], player, 1);
}
}
}
for(int index1 = 0; index1 < MAX_WALL; index1++){
for(int index2 = 0; index2 < MAX_BOX; index2++){
wall[index1].nearby_lr(box[index2], player, 1);
}
}
for(int index = 0; index < MAX_BOX; index++){
box[index].at_boundary_lr(player, 1, 1);
}
if(player.x == 2){
player.x++;
count_move--;
}
for(int index = 0; index < MAX_WALL; index++){
wall[index].nearwall_lr(player,1);
}
for(int index = 0; index < MAX_BOX; index++)
box[index].left_right_push(player, -1);
player.x--;
count_move++;
break;
/////////////////////////////////////////////// ACTION ON RIGHT KEY /////////////////////////////////////////////
case 77: //RIGHT KEY
for(int index1 = 0; index1 < MAX_BOX; index1++){
for(int index2 = 0; index2 < MAX_BOX; index2++){
if(index1 != index2){
box[index1].nearby_lr(box[index2], player, -1);
}
}
}
for(int index1 = 0; index1 < MAX_WALL; index1++){
for(int index2 = 0; index2 < MAX_BOX; index2++){
wall[index1].nearby_lr(box[index2], player, -1);
}
}
for(int index = 0; index < MAX_BOX; index++){
box[index].at_boundary_lr(player, -1, MAX_COL);
}
if(player.x == MAX_COL - 1){
player.x--;
count_move--;
}
for(int index = 0; index < MAX_WALL; index++){
wall[index].nearwall_lr(player,-1);
}
for(int index = 0; index < MAX_BOX; index++)
box[index].left_right_push(player, 1);
player.x++;
count_move++;
break;
////////////////////////// reset the game ///////////////////////////////
case 'r':
player = {2, 2};
for(int count_box = 0, x = 3; x <= 6; x += 3)
for(int y = 3; y <= 5; y++){
if(x == 6 && y == 4)
box[count_box].set_coord(x-1, y);
else
box[count_box].set_coord(x, y);
count_box++;
}
break;
}
system("CLS");
bool spc_ocupy1 = false, spc_ocupy2 = false, spc_ocupy3 = false;
bool box_change = false;
/////////////////////////////////////////// DISPLAY GAME AREA //////////////////////////////////////////
for(int y = 1; y <= MAX_ROW; y++){
for(int x = 1; x <= MAX_COL; x++){
spc_ocupy1 = false;
spc_ocupy2 = false;
spc_ocupy3 = false;
box_change = false;
for(int index = 0; index < MAX_BOX; index++){
if(box[index].x == x && box[index].y == y){
for(int index1 = 0; index1 < MAX_BOX; index1++){
if(store_box[index1].x == box[index].x && store_box[index1].y == box[index].y){
SetConsoleTextAttribute(h, 382);
cout << "\xB2";
SetConsoleTextAttribute(h, 255);
box_change = true;
spc_ocupy1 = true;
}
}
if(box_change == false){
SetConsoleTextAttribute(h, 182);
cout << "\xB1";
SetConsoleTextAttribute(h, 255);
}
spc_ocupy1 = true;
break;
}
}
if(spc_ocupy1 == false){
for(int index = 0; index < MAX_BOX; index++){
if(store_box[index].x == x && store_box[index].y == y && player.x == x && player.y == y){
SetConsoleTextAttribute(h, 253);
cout << "\x01";
SetConsoleTextAttribute(h, 255);
spc_ocupy2 = true;
break;
}
else if(store_box[index].x == x && store_box[index].y == y){
SetConsoleTextAttribute(h, 248);
cout << "*";
SetConsoleTextAttribute(h, 255);
spc_ocupy2 = true;
break;
}
}
if(spc_ocupy2 == false){
for(int index = 0; index < MAX_WALL; index++){
if(wall[index].x == x && wall[index].y == y){
SetConsoleTextAttribute(h, 177);
cout << "\xDB";
SetConsoleTextAttribute(h, 255);
spc_ocupy3 = true;
break;
}
}
if(spc_ocupy3 == false){
if(player.x == x && player.y == y){
SetConsoleTextAttribute(h, 253);
cout << "\x02";
SetConsoleTextAttribute(h, 255);
}
else if(x == 1 || x == MAX_COL || y == 1 || y == MAX_ROW){
SetConsoleTextAttribute(h, 177);
cout << "\xDB";
SetConsoleTextAttribute(h, 255);
}
else
cout << " ";
}
}
}
}
cout << endl;
}
SetConsoleTextAttribute(h, 240);
cout << "\nMOVES : " << count_move;
SetConsoleTextAttribute(h, 255);
int countbox = 0;
for(int index1 = 0; index1 < MAX_BOX; index1++){
for(int index2 = 0; index2 < MAX_BOX; index2++){
if(box[index1].x == store_box[index2].x && box[index1].y == store_box[index2].y)
countbox++;
}
}
if(countbox == MAX_BOX){
system("CLS");
SetConsoleTextAttribute(h, 240);
cout << "\nYOU WON THE GAME IN " << count_move << " moves";
hiscore.open("high score.dat", ios::in);
hiscore >> score;
hiscore.close();
if(count_move < score || score == 0){
hiscore.open("high score.dat", ios::out);
cout << "\nYou have made a high score";
cout << "\nEnter your name : ";
cin >> name;
score = count_move;
hiscore << score << " "; hiscore << name;
}
cout << "\nPress q to exit.";
SetConsoleTextAttribute(h, 255);
do{
key = getch();
}while(key != 'q');
break;
}
key = getch();
}while(key != 'q');
system("CLS");
}
Comments
Post a Comment