#include <iostream>
#include <fstream>
#include <map>
using namespace std;
const int SHIPAMOUNT = 10; // Количество кораблей
const int MAXLENGTH = 4; // Максимальная длина корабля
const int DECKMAX[MAXLENGTH+1] = {0, 4, 3, 2, 1}; // Максимум кораблей длиной i
class player
{
public:
int playernum;
map<char,bool> hit[SHIPAMOUNT]; // Поле попаданий
map<char,int> shipmap[SHIPAMOUNT]; // Поле кораблей. Если значение равно SHIPAMOUNT, то корабля нет, иначе - номер корабля.
player* enemy;
class ship
{
public:
int npos; // Числовая координата
char cpos; // Буквенная координата
int length; // Длина корабля
int health; // Оставшиеся клетки
bool hor; // Корабль расположен горизонтально
bool alive; // Корабль жив
};
ship shp[SHIPAMOUNT];
int nextship;
int deckamount[MAXLENGTH+1]; // Количество кораблей длиной i
bool ready;
int shipsleft;
// Создаёт и очищает поля, устанавливает начальные значения переменных
void preset(int a, player* b)
{
for (int num = 0; num < SHIPAMOUNT; num++)
for (char chr = 'A'; chr <= 'J'; chr++)
{
shipmap[num][chr]=SHIPAMOUNT; // Корабли игрока
hit[num][chr]=false; // Выстрелы по игроку
}
nextship=0;
shipsleft=SHIPAMOUNT;
playernum=a;
enemy=b;
ready=false;
for (int i = 0; i <= MAXLENGTH; i++) deckamount[i]=0;
}
// Попадание по координатам
void hitship(int npos, char cpos) //Аргументы - координаты
{
if ( !hit[npos][cpos] ) shp[shipmap[npos][cpos]].health--;
if ( shp[shipmap[npos][cpos]].health==0 )
{
shp[shipmap[npos][cpos]].alive=false;
cout << "Sunk!" << endl;
shipsleft--;
if ( shipsleft==0 ) cout << "You win!" << endl;
}
hit[npos][cpos]=true;
}
// Игрок стреляет. Функция возвращает номер игрока, который ходит следующим, или 0, если партия закончена.
int shoot(int pnum, player* p) // Аргументы - номер игрока, который делает ход, и указатель на другого игрока
{
showmap();
char npos,cpos;
bool correct;
do
{
cout << "Type coordinates." << endl;
cin >> npos;
cin >> cpos;
cpos=toupper(cpos);
if ( npos > '9' || npos < '0' )
{
correct = false;
cout << "Numeric coordinate incorrect.";
}
else if ( cpos > 'J' || cpos < 'A' )
{
correct = false;
cout << "Character coordinate incorrect.";
}
else correct=true;
} while (!correct);
npos-='0';
if ( (*p).shipmap[npos][cpos]<SHIPAMOUNT ) // Если на карте другого игрока в ячейке с координатами npos и cpos лежит число < SHIPAMOUNT
{
cout << "Hit!" << endl;
(*p).hitship(npos,cpos); // Запоминаем попадание
if ( (*p).shipsleft>0 ) return pnum; // Если у другого игрока остались корабли, возвращаем номер этого игрока
else return 0; // Иначе возвращаем 0 - это означает, что игра закончена
}
else
{
cout << "Miss!" << endl;
(*p).hit[npos][cpos]=true; // Запоминаем, что по этим координатам стреляли
if (pnum==1) return 2; // Возвращаем номер другого игрока
else return 1;
}
}
void recordship(int num, char chr, int length, bool hor)
{
shp[nextship].npos=num;
shp[nextship].cpos=chr;
shp[nextship].length=length;
shp[nextship].hor=hor;
shp[nextship].alive=true;
shp[nextship].health=length;
deckamount[length]++;
if (hor)
for (int j = chr; j < chr+length; j++)
shipmap[num][j]=nextship;
else
for (int i = num; i < num+length; i++)
shipmap[i][chr]=nextship;
nextship++;
}
bool shipcollision(int num, char chr, int length, bool hor)
{
if (hor)
for (int i=num-1; i <= num+1; i++)
for (int j=chr-1; j <= chr+length; j++)
if ( (i >= 0 && i < SHIPAMOUNT) && (j >= 'A' && j <= 'J') )
if (shipmap[i][j] < SHIPAMOUNT)
{
cout << "Collision detected: " << i << char(j) << endl;
return true;
}
else;
else;
else
for (int i=num-1; i <= num+length; i++)
for (int j=chr-1; j <= chr+1; j++)
if ( (i >= 0 && i < SHIPAMOUNT) && (j >= 'A' && j <= 'J') )
if (shipmap[i][j] < SHIPAMOUNT)
{
cout << "Collision detected: " << i << char(j) << endl;
return true;
}
else;
else;
return false;
}
// Добавляет корабль или выводит, что корабль не помещается
void addship(int num, char chr, int length, bool hor) // Номер клетки, буква клетки (заглавная), длина корабля, корабль горизонтальный.
{
if (deckamount[length] < DECKMAX[length])
if (hor)
if (chr-'A'+length > 10) cout << "Not enough place" << endl;
else
if (shipcollision(num, chr, length, hor)) cout << "Another ship nearby." << endl;
else recordship(num, chr, length, hor);
else
if (num+length > 10) cout << "Not enough place" << endl;
else
if (shipcollision(num, chr, length, hor)) cout << "Another ship nearby." << endl;
else recordship(num, chr, length, hor);
else cout << "Too many " << length << "-deck ships." << endl;
if (nextship==SHIPAMOUNT) ready=true;
else ready=false;
}
/*
cout << "╔═╤══════════╦═╤══════════╗" << endl;
cout << "║#│ABCDEFGHIJ║#│ABCDEFGHIJ║" << endl;
cout << "╟─┼──────────╫─┼──────────╢" << endl;
cout << "║0│ ║0│ ║" << endl;
cout << "║1│ ║1│ ║" << endl;
cout << "║2│ ║2│ ║" << endl;
cout << "║3│ ║3│ ║" << endl;
cout << "║4│ ║4│ ║" << endl;
cout << "║5│ ║5│ ║" << endl;
cout << "║6│ ║6│ ║" << endl;
cout << "║7│ ║7│ ║" << endl;
cout << "║8│ ║8│ ║" << endl;
cout << "║9│ ║9│ ║" << endl;
cout << "╚═╧══════════╩═╧══════════╝" << endl;
*/
void showmap()
{
// Right field is enemy player's field
//cout << "╔═╤══════════╦═╤══════════╗" << endl;
cout << char(201) << char(205) << char(209);
for (int i = 0; i < 10; i++) cout << char(205);
cout << char(203) << char(205) << char(209);
for (int i = 0; i < 10; i++) cout << char(205);
cout << char(187) << endl;
//cout << "║#│ABCDEFGHIJ║#│ABCDEFGHIJ║" << endl;
cout << char(186) <<'#' << char(179) << "ABCDEFGHIJ" << char(186) << '#' << char(179) << "ABCDEFGHIJ" << char(186) << endl;
//cout << "╟─┼──────────╫─┼──────────╢" << endl;
cout << char(199) << char(196) << char(197);
for (int i = 0; i < 10; i++) cout << char(196);
cout << char(215) << char(196) << char(197);
for (int i = 0; i < 10; i++) cout << char(196);
cout << char(182) << endl;
//cout << "║0│ ║0│ ║" << endl;
//cout << "║1│ ║1│ ║" << endl;
//cout << "║2│ ║2│ ║" << endl;
//cout << "║3│ ║3│ ║" << endl;
//cout << "║4│ ║4│ ║" << endl;
//cout << "║5│ ║5│ ║" << endl;
//cout << "║6│ ║6│ ║" << endl;
//cout << "║7│ ║7│ ║" << endl;
//cout << "║8│ ║8│ ║" << endl;
//cout << "║9│ ║9│ ║" << endl;
for (int i = 0; i < 10; i++)
{
cout << char(186) << i << char(179);
for (int j = 'A'; j <= 'J'; j++)
if (shipmap[i][j]<10) cout << shipmap[i][j];
else cout << ' ';
cout << char(186) << i << char(179);
for (int j = 'A'; j <= 'J'; j++)
if ((*enemy).hit[i][j]) // Если был выстрел
if ((*enemy).shipmap[i][j]<10) // Если есть корабль
if ((*enemy).shp[shipmap[i][j]].alive) cout << 'X'; // Если корабль жив - вывести 'X'
else cout << char(219); // Иначе вывести '█'
else cout << '*'; // Иначе вывести '*'
else cout << ' '; // Иначе вывести ' '
cout << char(186) << endl;
}
//cout << "╚═╧══════════╩═╧══════════╝" << endl;
cout << char(200) << char(205) << char(207) ;
for (int i = 0; i < 10; i++) cout << char(205) ;
cout << char(202) << char(205) << char(207) ;
for (int i = 0; i < 10; i++) cout << char(205) ;
cout << char(188) << endl;
}
void getships()
{
ship inship;
char c[256];
int lchar;
showmap();
do
{
cout << "Ship #" << nextship << endl;
cout << "Type ship coordinates, length, direction (H or V)." << endl;
//correct=true;
//errortype="Input correct.";
cin.getline(c,256);
lchar=0;
if (c[lchar] < '0' || c[lchar] > '9') cout << "Numeric coordinate incorrect." << endl;
else
{
inship.npos=c[lchar]-'0';
lchar++;
if (toupper(c[lchar]) < 'A' || toupper(c[lchar]) > 'J') cout << "Character coordinate incorrect." << endl;
else
{
inship.cpos=toupper(c[lchar]);
lchar+=2;
if (c[lchar] < '0' || c[lchar] > '4') cout << "Length incorrect." << endl;
else
{
inship.length=c[lchar]-'0';
lchar+=2;
if (toupper(c[lchar]) == 'H' || inship.length == 1)
{
inship.hor=true;
addship(inship.npos,inship.cpos,inship.length,inship.hor);
}
else if (toupper(c[lchar]) == 'V')
{
inship.hor=false;
addship(inship.npos,inship.cpos,inship.length,inship.hor);
}
else cout << "Direction incorrect." << endl;
}
}
}
showmap();
}
while (!ready);
}
};
int main()
{
// Объявления
player p[3];
p[1].playernum=1;
p[2].playernum=2;
bool keepplaying;
int num;
char chr;
int playerfase=1;
// Начало
cout << "Game starts now." << endl;
do
{
cout << "First player arranges ships." << endl;
p[1].preset(1,&p[2]);
p[1].getships();
cout << "Second player arranges ships." << endl;
p[2].preset(2,&p[1]);
p[2].getships();
do
{
if (playerfase==1)
{
cout << "First player shoots." << endl;
do // Передаём номер игрока и указатель на другого игрока
playerfase=p[1].shoot(1,&p[2]); // Возвращает номер игрока, который ходит после.
while (playerfase==1);
}
if (playerfase==2)
{
cout << "Second player shoots." << endl;
do playerfase=p[2].shoot(2,&p[1]);
while (playerfase==2);
}
}
while (playerfase);
cout << "Type 'Y' if you want to play again. Otherwise, type 'N'" << endl;
cin >> chr;
if (toupper(chr)=='Y') keepplaying=true;
else keepplaying=false;
}
while (keepplaying);
return 0;
}