Stuck? Need help? Ask questions on our forums.

View Battleship\src\Computer.cpp

GPL'ed Battleship clone Win32/Linux 1.2.1

Submitted By: i_like_cpp
Rating: (Not rated) (Rate It)


/*
Free Battleship clone for Win32/Linux Console.
Copyright (C) 2005  Dennis Gertitschke

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "../inc/Computer.h"
#include "../inc/Ship.h"
#include "../inc/Screen.h"
#include "../inc/Common.h"

#include <time.h>
#include <stdlib.h>

int Computer::m_iInstanceCount=0;

Computer::Computer(){

        m_iDistance=1;
        m_iDirection=0;
        m_cShotX=m_cFirstX=0;
        m_iShotY=m_iFirstY=0;
        m_iInstance=m_iInstanceCount;
        m_iInstanceCount++;
        m_iMode=GAMETYPE_PLAYER_VS_COMPUTER;
        m_pScreen->setMode(GAMETYPE_PLAYER_VS_COMPUTER);
        m_bHit=false;
        m_iHitCount=0;
        srand(static_cast<unsigned int>(time(NULL)));
}

Computer::~Computer(){
}

void Computer::registerCallback(void *pObj,F pFunc){
        m_pObj=pObj;
        m_pFunc=pFunc;
}

void Computer::setMode(int iMode){
        m_pScreen->setMode(iMode);
        m_iMode=iMode;
}

void Computer::validateCompShotCallback(void *pObj,char cX,int iY,bool& bRefHit,int& iRefHitCount){
        Computer *self=static_cast<Computer*>(pObj);
        self->validateCompShot(cX,iY,bRefHit,iRefHitCount);
}

void Computer::validateCompShot(char cX,int iY,bool& bRefHit,int& iRefHitCount){

        int iShot=transformToBoardIndex(cX,iY);
        char cTmpX=cX;
        int  iTmpY=iY;
       
        if(m_arrBoard[iShot]!=NULL){
                bRefHit=true;
                iRefHitCount++;
                m_arrBoard[iShot]->hit();
                if(m_arrBoard[iShot]->getStatus()){
                        m_iShipCount--;
                        iRefHitCount=0;
                        if(!m_iShipCount)
                                m_bDefeat=true;
                }
                transformToCompScreen(cTmpX,iTmpY);
                m_pScreen->displayHit(cTmpX,iTmpY);
                m_pScreen->printCompStatus(bRefHit,m_arrBoard[iShot]->getId(),m_arrBoard[iShot]->getStatus());
        }
        else{
                bRefHit=false;
                transformToCompScreen(cTmpX,iTmpY);
                m_pScreen->displayMiss(cTmpX,iTmpY);
                m_pScreen->printCompStatus(bRefHit,NULL,false);
        }
}

void Computer::reset(){

        m_bDefeat=false;
        m_iShipCount=4;
        for(int i=0;i<100;i++){
                m_arrBoard[i]=NULL;
                m_barrValidStart[i]=true;
                m_barrValidShot[i]=true;
        }
        m_iDistance=1;
        m_iIndex=m_iDirection=0;
        m_cShotX=m_cFirstX=0;
        m_iShotY=m_iFirstY=0;
        m_bHit=false;
        m_iHitCount=0;
        m_pFrigate->reset();
        m_pDestroyer->reset();
        m_pCruiser->reset();
        m_pBattleship->reset();
}

void Computer::shoot(){
       
        int i=0;

        if(!m_iHitCount){
                do{
                        randomCoordinate(m_cShotX,m_iShotY);
                        m_iIndex=transformToBoardIndex(m_cShotX,m_iShotY);
                        m_iDistance=1;
                }while(!m_barrValidShot[m_iIndex]);
        }
       
        if(m_iHitCount==1){
               
                if(m_bHit){
                        m_cFirstX=m_cShotX;
                        m_iFirstY=m_iShotY;
                        randomDirection();
                }
                                               
                while(i<4){
                        switch(m_iDirection){

                                case 1: if(validateCoordinate(static_cast<char>(m_cFirstX+m_iDistance),m_iFirstY)){
                                                        m_iIndex=transformToBoardIndex(static_cast<char>(m_cFirstX+m_iDistance),m_iFirstY);
                                                        if(m_barrValidShot[m_iIndex]){
                                                                m_cShotX=static_cast<char>(m_cFirstX+m_iDistance);
                                                                m_iShotY=m_iFirstY;
                                                                i=4;
                                                                break;
                                                        }
                                                        else
                                                                m_iDirection=2;
                                                }
                                                else
                                                        m_iDirection=2;
                                                break;

                                case 2: if(validateCoordinate(static_cast<char>(m_cFirstX-m_iDistance),m_iFirstY)){
                                                        m_iIndex=transformToBoardIndex(static_cast<char>(m_cFirstX-m_iDistance),m_iFirstY);
                                                        if(m_barrValidShot[m_iIndex]){
                                                                m_cShotX=static_cast<char>(m_cFirstX-m_iDistance);
                                                                m_iShotY=m_iFirstY;
                                                                i=4;
                                                                break;
                                                        }
                                                        else
                                                                m_iDirection=3;
                                                }
                                                else
                                                        m_iDirection=3;
                                                break;

                                case 3: if(validateCoordinate(m_cFirstX,m_iFirstY+m_iDistance)){
                                                        m_iIndex=transformToBoardIndex(m_cFirstX,m_iFirstY+m_iDistance);
                                                        if(m_barrValidShot[m_iIndex]){
                                                                m_cShotX=m_cFirstX;
                                                                m_iShotY=m_iFirstY+m_iDistance;
                                                                i=4;
                                                                break;
                                                        }
                                                        else
                                                                m_iDirection=4;
                                                }
                                                else
                                                        m_iDirection=4;
                                                break;

                                case 4: if(validateCoordinate(m_cFirstX,m_iFirstY-m_iDistance)){
                                                        m_iIndex=transformToBoardIndex(m_cFirstX,m_iFirstY-m_iDistance);
                                                        if(m_barrValidShot[m_iIndex]){
                                                                m_cShotX=m_cFirstX;
                                                                m_iShotY=m_iFirstY-m_iDistance;
                                                                i=4;
                                                                break;
                                                        }
                                                        else
                                                                m_iDirection=1;
                                                }
                                                else
                                                        m_iDirection=1;
                                                break;
                        }
                        i++;
                }
        }
               
        if(m_iHitCount>1){

                if(m_bHit)
                        m_iDistance++;
                else
                        m_iDistance=1;

                while(i<4){
                        switch(m_iDirection){

                                        case 1: if(validateCoordinate(static_cast<char>(m_cFirstX+m_iDistance),m_iFirstY)){
                                                                m_iIndex=transformToBoardIndex(static_cast<char>(m_cFirstX+m_iDistance),m_iFirstY);
                                                                if(m_barrValidShot[m_iIndex]){
                                                                        m_cShotX=static_cast<char>(m_cFirstX+m_iDistance);
                                                                        m_iShotY=m_iFirstY;
                                                                        i=4;
                                                                        break;
                                                                }
                                                                else{
                                                                        m_iDirection=2;
                                                                        m_iDistance=1;
                                                                }
                                                        }
                                                        else{
                                                                m_iDirection=2;
                                                                m_iDistance=1;
                                                        }
                                                        break;

                                        case 2: if(validateCoordinate(static_cast<char>(m_cFirstX-m_iDistance),m_iFirstY)){
                                                                m_iIndex=transformToBoardIndex(static_cast<char>(m_cFirstX-m_iDistance),m_iFirstY);
                                                                if(m_barrValidShot[m_iIndex]){
                                                                        m_cShotX=static_cast<char>(m_cFirstX-m_iDistance);
                                                                        m_iShotY=m_iFirstY;
                                                                        i=4;
                                                                        break;
                                                                }
                                                                else{
                                                                        m_iDirection=1;
                                                                        m_iDistance=1;
                                                                }
                                                        }
                                                        else{
                                                                m_iDirection=1;
                                                                m_iDistance=1;
                                                        break;

                                        case 3: if(validateCoordinate(m_cFirstX,m_iFirstY+m_iDistance)){
                                                                m_iIndex=transformToBoardIndex(m_cFirstX,m_iFirstY+m_iDistance);
                                                                if(m_barrValidShot[m_iIndex]){
                                                                        m_cShotX=m_cFirstX;
                                                                        m_iShotY=m_iFirstY+m_iDistance;
                                                                        i=4;
                                                                        break;
                                                                }
                                                                else{
                                                                        m_iDirection=4;
                                                                        m_iDistance=1;
                                                                }
                                                        }
                                                        else{
                                                                m_iDirection=4;
                                                                m_iDistance=1;
                                                        }
                                                        break;

                                        case 4: if(validateCoordinate(m_cFirstX,m_iFirstY-m_iDistance)){
                                                                m_iIndex=transformToBoardIndex(m_cFirstX,m_iFirstY-m_iDistance);
                                                                if(m_barrValidShot[m_iIndex]){
                                                                        m_cShotX=m_cFirstX;
                                                                        m_iShotY=m_iFirstY-m_iDistance;
                                                                        i=4;
                                                                        break;
                                                                }
                                                                else{
                                                                        m_iDirection=3;
                                                                        m_iDistance=1;
                                                                }
                                                        }
                                                        else{
                                                                m_iDirection=3;
                                                                m_iDistance=1;
                                                        }
                                                        break;
                        }
                        i++;
                }
                }
        }
        m_barrValidShot[m_iIndex]=false;
        // call back the player (or the other computer when in GAMETYPE_COMPUTER_VS_COMPUTER)
        m_pFunc(m_pObj,m_cShotX,m_iShotY,m_bHit,m_iHitCount);
}

void Computer::validateUserShotCallback(void *pObj,char cX,int iY){
        Computer *self=static_cast<Computer*>(pObj);
        self->validateUserShot(cX,iY);
}
void Computer::validateUserShot(char cX,int iY){

        int iShot=transformToBoardIndex(cX,iY);
        char cTmpX=cX;
        int  iTmpY=iY;

        if(m_arrBoard[iShot]!=NULL){
                m_arrBoard[iShot]->hit();
                if(m_arrBoard[iShot]->getStatus()){
                        m_iShipCount--;
                        if(!m_iShipCount)
                                m_bDefeat=true;
                }
                m_pScreen->printCompStatus(true,m_arrBoard[iShot]->getId(),m_arrBoard[iShot]->getStatus());
                transformToCompScreen(cTmpX,iTmpY);
                m_pScreen->displayHit(cTmpX,iTmpY);
        }
        else{
                m_pScreen->printCompStatus(false,NULL,false);
                transformToCompScreen(cTmpX,iTmpY);
                m_pScreen->displayMiss(cTmpX,iTmpY);
        }
}
void Computer::randomCoordinate(char& cRefX,int& iRefY){
        cRefX=static_cast<char>(rand()%10+65);
        iRefY=rand()%10+1;
}

void Computer::randomDirection(){
        m_iDirection=rand()%4+1;
}

void Computer::transformToCompScreen(char& cRefX,int& iRefY){

        if(m_iInstance==0){
                cRefX=static_cast<char>((cRefX-65)+2*(cRefX-40));
                iRefY=iRefY+4;
        }
        if(m_iInstance==1){
                cRefX=static_cast<char>((cRefX-65)+2*(cRefX-64));
                iRefY=iRefY+4;
        }
}

void Computer::placeShip(Ship* ship,char cStartX,int iStartY){

        int i=0;
        char cTmpX;
        int iTmpY;

        while(i<ship->getLength()){

                switch(m_iDirection){

                case 1:   
                                                if(m_iMode==GAMETYPE_COMPUTER_VS_COMPUTER){
                                                        cTmpX=cStartX;
                                                        iTmpY=iStartY;
                                                        transformToCompScreen(cTmpX,iTmpY);
                                                        m_pScreen->displayShip(cTmpX,iTmpY);
                                                }
                                                markNeighboursInvalid(cStartX,iStartY);
                                                m_iIndex=transformToBoardIndex(cStartX,iStartY);
                                                m_arrBoard[m_iIndex]=ship;
                                                m_barrValidStart[m_iIndex]=false;
                                                cStartX++;
                                                break;
                case 2:   
                                                if(m_iMode==GAMETYPE_COMPUTER_VS_COMPUTER){
                                                        cTmpX=cStartX;
                                                        iTmpY=iStartY;
                                                        transformToCompScreen(cTmpX,iTmpY);
                                                        m_pScreen->displayShip(cTmpX,iTmpY);
                                                }
                                                markNeighboursInvalid(cStartX,iStartY);
                                                m_iIndex=transformToBoardIndex(cStartX,iStartY);
                                                m_arrBoard[m_iIndex]=ship;
                                                m_barrValidStart[m_iIndex]=false;
                                                cStartX--;
                                                break;
                case 3:
                                                if(m_iMode==GAMETYPE_COMPUTER_VS_COMPUTER){
                                                        cTmpX=cStartX;
                                                        iTmpY=iStartY;
                                                        transformToCompScreen(cTmpX,iTmpY);
                                                        m_pScreen->displayShip(cTmpX,iTmpY);
                                                }
                                                markNeighboursInvalid(cStartX,iStartY);
                                                m_iIndex=transformToBoardIndex(cStartX,iStartY);
                                                m_arrBoard[m_iIndex]=ship;
                                                m_barrValidStart[m_iIndex]=false;
                                                iStartY++;
                                                break;
                                               
                case 4:   
                                                if(m_iMode==GAMETYPE_COMPUTER_VS_COMPUTER){
                                                        cTmpX=cStartX;
                                                        iTmpY=iStartY;
                                                        transformToCompScreen(cTmpX,iTmpY);
                                                        m_pScreen->displayShip(cTmpX,iTmpY);
                                                }
                                                markNeighboursInvalid(cStartX,iStartY);
                                                m_iIndex=transformToBoardIndex(cStartX,iStartY);
                                                m_arrBoard[m_iIndex]=ship;
                                                m_barrValidStart[m_iIndex]=false;
                                                iStartY--;
                                                break;
                }
                i++;
        }
}

void Computer::calculateValidStartEnd(Ship *pShip){

        int iDistance=0;
        int iStartY=0;
        char cStartX=0;
        bool bFound=false;
        int i;

        iDistance=pShip->getLength()-1;
        do{
                do{
                        randomCoordinate(cStartX,iStartY);
                        m_iIndex=transformToBoardIndex(cStartX,iStartY);
                }while(!m_barrValidStart[m_iIndex]);
                randomDirection();
                i=0;

                while(i<4){

                        switch(m_iDirection){

                        case 1:  if(validateCoordinate(static_cast<char>(cStartX+iDistance),iStartY)){
                                                        if(checkStartEnd(cStartX,iStartY,pShip->getLength())){
                                                                bFound=true;
                                                                i=4;
                                                                break;
                                                        }
                                                        else
                                                                m_iDirection=2;
                                                }
                                                else
                                                        m_iDirection=2;
                                                break;

                        case 2:  if(validateCoordinate(static_cast<char>(cStartX-iDistance),iStartY)){
                                                        if(checkStartEnd(cStartX,iStartY,pShip->getLength())){
                                                                bFound=true;
                                                                i=4;
                                                                break;
                                                        }
                                                        else
                                                                m_iDirection=3;
                                                }
                                                else
                                                        m_iDirection=3;
                                                break;

                        case 3:  if(validateCoordinate(cStartX,iStartY+iDistance)){
                                                        if(checkStartEnd(cStartX,iStartY,pShip->getLength())){
                                                                bFound=true;
                                                                i=4;
                                                                break;
                                                        }
                                                        else m_iDirection=4;
                                                }
                                                else
                                                        m_iDirection=4;
                                                break;

                        case 4:  if(validateCoordinate(cStartX,iStartY-iDistance)){
                                                        if(checkStartEnd(cStartX,iStartY,pShip->getLength())){
                                                                bFound=true;
                                                                i=4;
                                                                break;
                                                        }
                                                        else
                                                                m_iDirection=1;
                                                }
                                                else
                                                        m_iDirection=1;
                                                break;
                        }
                        i++;
                }
        }while(!bFound);

        placeShip(pShip,cStartX,iStartY);
}

void Computer::deployFleet(){
        calculateValidStartEnd(m_pFrigate);
        calculateValidStartEnd(m_pDestroyer);
        calculateValidStartEnd(m_pCruiser);
        calculateValidStartEnd(m_pBattleship);
        m_pScreen->printCompSucessfullyPlaced();
}

bool Computer::checkStartEnd(char cStartX,int iStartY,int iLength){
       
        bool bResult=true;
        int i=0;

        while(i<iLength){
                switch(m_iDirection){
                        case 1: m_iIndex=transformToBoardIndex(cStartX,iStartY);
                                        if(!m_barrValidStart[m_iIndex])
                                                return false;
                                        cStartX++;
                                        break;

                        case 2: m_iIndex=transformToBoardIndex(cStartX,iStartY);
                                        if(!m_barrValidStart[m_iIndex])
                                                return false;
                                        cStartX--;
                                        break;

                        case 3: m_iIndex=transformToBoardIndex(cStartX,iStartY);
                                        if(!m_barrValidStart[m_iIndex])
                                                return false;
                                        iStartY++;
                                        break;

                        case 4: m_iIndex=transformToBoardIndex(cStartX,iStartY);
                                        if(!m_barrValidStart[m_iIndex])
                                                return false;
                                        iStartY--;
                                        break;
                }
                i++;
        }
        return bResult;
}
 
corner