Я пытаюсь написать функцию, которая проверяет, контролирует ли черный король белая ладья. Проблема возникает, когда я пытаюсь найти, есть ли какие-нибудь фигуры между ладьей и королем.
void rook_white(piece A[]) // does WR check BK
{
cout << "Found White Rook ";
int k_x; // BK'S x coordinate
int k_y; // BK's y coordinate
bool check = false;
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
if(A[t_i].field[m_x-x][m_y] == 'k') // Moving Left
{
k_x=m_x;
k_y=m_y;
goto al_1;
}
}
}
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
if(A[t_i].field[m_x+x][m_y] == 'k') // Moving Right
{
k_x=m_x;
k_y=m_y;
goto al_2;
}
}
}
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
if(A[t_i].field[m_x][m_y-y] == 'k') // Moving Up
{
k_x=m_x;
k_y=m_y;
goto al_3;
}
}
}
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
if(A[t_i].field[m_x][m_y+y] == 'k') // Moving Down
{
k_x=m_x;
k_y=m_y;
goto al_4;
}
}
}
al_1:
for(int x=0; x<k_x; x++)
{
for(int y=0; y<k_y; y++)
{
if(!A[t_i].field[m_x-x][m_y] == '*') // Checking left
{
goto loop_exit;
}
}
}
al_2:
for(int x=0; x<k_x; x++)
{
for(int y=0; y<k_y; y++)
{
if(!A[t_i].field[m_x+x][m_y] == '*') // Checking Right
{
goto loop_exit;
}
}
}
al_3:
for(int x=0; x<k_x; x++)
{
for(int y=0; y<k_y; y++)
{
if(!A[t_i].field[m_x][m_y-y] == '*') // Checking Up
{
goto loop_exit;
}
}
}
al_4:
for(int x=0; x<k_x; x++)
{
for(int y=0; y<k_y; y++)
{
if(!A[t_i].field[m_x][m_y+y] == '*') // Checking Down
{
goto loop_exit;
}
}
}
loop_exit:
check = false;
if (check == true)
{
ofstream fr(FVR,ios::app);
fr << "Black is in check by rook " << t_i << endl;
}
}
Функция ищет, где находится король по осям x и y. Затем он переходит к определенному алгоритму (al_1, al_2, …), в котором он ищет, есть ли что-нибудь между королем и ладьей.
Входной файл является чем-то вроде этого:
********
***k****
********
***q****
********
********
***R****
********
это не должно ничего выводить, пока
********
***k****
********
********
********
********
***R****
********
должен вывести «Черные находятся под контролем ладьи». (t_i — номер доски, на которой он рассматривается)
[T_i] является массивом struct, части структуры состоят из поля char [8] [8].Я использую структуру, потому что есть неограниченное количество досок, которые я должен исследовать.
k_x и k_y — координаты короля.
m_x и m_y — это глобальные переменные, которые передаются из функции поиска, в которой найден фрагмент
вот сама программа с int main ()
#include <iostream>
#include <fstream> // chess
#include <cstdlib>
using namespace std; // PROGRAM CHECKS FOR CHESS CHEKS
const char FVD[]="5_input.txt"; // **************************************************
const char FVR[]="5_output.txt"; // P - white pawn (WP) p - black pawn (BP)
//--- // R - white rook (WR) r - black rook (BR)
//--- // B - white bishop (WB) b - black bishop (BB)
int m_i=0; // max i // N - white knight (WN) n - black knight (BN)
int m_x=0; // // Q - white queen (WQ) q - black queen (BQ)
int m_y=0; // // K - white king (WK) k - black king (BK)
int t_i=0; // // **************************************************
struct piece
{
char field[8][8];
};
void read(piece A[])
{
ifstream fd(FVD);
int i=0;
m_i=0;
while(!fd.eof())
{
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
fd >> A[i].field[x][y];
}
}
fd.ignore();
i++;
m_i=i;
}
fd.close();
}
/// ----------------------------------------------BLACK KING IS IN CHECK--------------------------------------------------------------
void rook_white(piece A[]) // does WR check BK
{
cout << "Found White Rook ";
int k_x; // BK'S x coordinate
int k_y; // BK's y coordinate
bool check = false;
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
if(A[t_i].field[m_x-x][m_y] == 'k') // Moving Left
{
k_x=m_x;
k_y=m_y;
goto al_1;
}
}
}
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
if(A[t_i].field[m_x+x][m_y] == 'k') // Moving Right
{
k_x=m_x;
k_y=m_y;
goto al_2;
}
}
}
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
if(A[t_i].field[m_x][m_y-y] == 'k') // Moving Up
{
k_x=m_x;
k_y=m_y;
goto al_3;
}
}
}
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
if(A[t_i].field[m_x][m_y+y] == 'k') // Moving Down
{
k_x=m_x;
k_y=m_y;
goto al_4;
}
}
}
al_1:
for(int x=0; x<k_x; x++)
{
for(int y=0; y<k_y; y++)
{
if(!A[t_i].field[m_x-x][m_y] == '*') // Checking left
{
goto loop_exit;
}
}
}
al_2:
for(int x=0; x<k_x; x++)
{
for(int y=0; y<k_y; y++)
{
if(!A[t_i].field[m_x+x][m_y] == '*') // Checking Right
{
goto loop_exit;
}
}
}
al_3:
for(int x=0; x<k_x; x++)
{
for(int y=0; y<k_y; y++)
{
if(!A[t_i].field[m_x][m_y-y] == '*') // Checking Up
{
goto loop_exit;
}
}
}
al_4:
for(int x=0; x<k_x; x++)
{
for(int y=0; y<k_y; y++)
{
if(!A[t_i].field[m_x][m_y+y] == '*') // Checking Down
{
goto loop_exit;
}
}
}
loop_exit:
check = false;
if (check == true)
{
ofstream fr(FVR,ios::app);
fr << "Black is in check by rook " << t_i << endl;
}
}
///-----------------------------------------SEARCHING FOR THE CHECKS // CALLING FUNCTIONS --------------------------------------------
void search(piece A[]) // searches for piece and calls a function related to it
{
for(int i=0; i<m_i-1; i++)
{
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
if (A[i].field[x][y]=='R')
{
t_i=i;
m_x=x;
m_y=y;
rook_white(A);
}
}
}
}
}
int main()
{
piece A[10];
remove(FVR); // clears the output before inputting new data because of ios::app
read(A);
search(A);
ofstream fr(FVR);
fr << "Done";
return 0;
}
Я сделаю то, что обычно не делаю — я дам вам полный круговой тур (потому что мне так хочется).
Вы начали с main()
который должен прочитать произвольное количество полей (но на самом деле происходит сбой 11-го числа), и search()
функция, которая предназначена для того, чтобы в конечном итоге перебирать все возможные шахматные фигуры … но ваша программа не проходит проверку на первую фигуру, белую ладью.
Вы также начали с C, а затем ввели гомеопатические дозы C ++, что на самом деле делает вещи более трудными, чем необходимо.
Итак, давайте урезать это. Во-первых, мы добавим «минимальный» в ваш пример кода.
Давайте использовать <vector>
вместо двумерного массива. Векторы являются одним из большинство полезных вещей в C ++, и на самом деле практически нет причин для использования массивов в стиле C (за исключением, возможно, совместимости с C API).
#include <vector>
#include <iostream>
typedef std::vector< std::vector< char > > Field;
Field
теперь псевдоним для вектора векторов char
s. Это в основном так же, как двумерный массив (включая [][]
адресации), но у него есть некоторые преимущества, как вы скоро увидите.
Ваш rook_white()
(как вы это спроектировали) необходимо один поле и координаты X и Y ладьи. Позвольте мне немного настроить прототип вашей функции — мне нравится более выразительные имена идентификаторов.
void rook_white( Field const & field, unsigned rook_x, unsigned rook_y );
Поиск и удаление A[t_i].
Пока мы работаем только над этим полем. Поиск и замены m_x
с rook_x
а также m_y
с rook_y
, Не слишком сложно. Также замените:
ofstream fr(FVR,ios::app);
fr << "Black is in check by rook " << t_i << endl;
С:
std::cout << "Black is in check by rook" endl;
На данный момент мы не беспокоимся о файловом вводе / выводе.
Теперь нам нужно настроить поле, но мы делаем не нужно прочитать его из файла на данный момент. Вы можете расширить свой код, как только вы получите действительную проверку.
int main()
{
Field field( 8, std::vector< char >( 8, '*' ) );
std::vector< char >( 8, '*' )
создает временный вектор из 8 '8'
символы. Field field( 8, /*...*/ );
создает Field
состоящий из 8 копий этого временного вектора.
Теперь давайте разместим ваши кусочки.
unsigned rook_x = 3;
unsigned rook_y = 6;
field[rook_x][rook_y] = 'R';
unsigned king_x = 3;
unsigned king_y = 1;
field[king_x][king_y] = 'k';
На данный момент я понял, ваш пример кода перепутал координаты «X» и «Y» в search()
(сообщает о ладье в X = 6, Y = 3), но не имеет значения. Это не источник ваших проблем.
Теперь у нас есть поле и координаты для вызова вашей функции.
rook_white( field, rook_x, rook_y );
return 0;
}
Этот способ написания main()
это на самом деле не отражает то, что должно делать ваше окончательное приложение, а скорее настраивает тест для определенной функциональности, называется тест-водитель. Мы только что убрали более 50 строк ненужного кода из вашего примера, устраняя все виды потенциальных проблем.
Теперь давайте посмотрим на rook_white()
, А не ___ ли нам?
Так как теперь у нас есть vector< vector< char > >
вместо «тупого» массива мы могли бы сделать что-то изящное: заменить []
доступ с .at()
, Причина? Если индекс до []
выходит за пределы допустимого, это может привести к сбою программы. Если индекс до .at()
вне границ, это будут бросить исключение.
Так что пока .at()
(немного) медленнее и обычно не используется в производственном коде, я рекомендую его для начинающих, потому что он не позволяет ошибкам «прятаться».
В этот момент вы должны изогнуть бровь и подумать про себя: «Почему он это предлагает?». Тогда вы должны посмотреть на свои петли, и …
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
if(field[rook_x-x][rook_y] == 'k')
{
k_x=rook_x;
k_y=rook_y;
goto al_1;
}
}
}
Да, точно. У тебя есть за пределами доступа на ваше поле.
rook_x
/ rook_y
где-то посреди поля, но вы настаиваете на доступе к чему-либо до [rook_x - 7][rook_y]
если вы не можете найти короля. Это был отрицательный показатель в вашем исходном коде. Так как я изменил координаты на unsigned
(который вместо этого переполняется и становится действительно большой) вместо этого вы получите аварийное завершение (если вам повезет). Это было на самом деле непреднамеренно; Я просто заявляю, что не может быть отрицательным unsigned
по привычке.
Но именно поэтому я предложил использовать vector<>
«s .at()
метод, пока вы еще учитесь: провалиться как можно раньше и как можно громче. Исключение лучше, чем неопределенное поведение.
Кроме того, вы делаете (во всех этих циклах) всегда зацикливаться x
а также y
, но только использовать один из двух переменных внутри петля. Это много потраченные впустую такты. То, что это не сломает ваш логик, это просто шанс …
На данный момент вы, вероятно, хотите полностью переработать ваш код. Но подождите, это еще не все.
Если вы «двигаетесь влево» в первом цикле и найдете там короля, вы goto al_1
, Там вы зацикливаетесь (снова используя только один из двух счетчиков циклов), чтобы проверить наличие промежуточных фрагментов.
Первый цикл x == 0
, проверка [rook_x - 0][rook_y]
… ну угадай что, Вы находите, что белая ладья вмешивается там, так как нет '*'
в этой области, так что вы переходите к loop_exit
…
И даже если бы ты не сделал эту ошибку, вы бы вышли из этого цикла и войти al_2
, проверяя все остальные направления для ладьи, а также…
И даже если бы всего этого не случилось, неважно, что произойдет, вы в конечном итоге столкнулись с этим:
loop_exit:
check = false;
if (check == true)
{
std::cout << "Black is in check by rook \n";
}
Хорошо, что check == true
никогда не случится, право?
На данный момент я цитирую один из ваших комментариев …
…Я просто не понимаю [заявления о переключении] и не могу понять, как написать их как переключатель.
Мое предложение? Я полностью понимаю, почему вы хотите написать «что-то реальное» как можно быстрее. Учебники скучные. Но ты действительно следует потратить еще немного времени на то, чтобы «обернуть голову» основными понятиями. C и C ++ — это языки, которые не очень хорошо работают с «пробной версией». & ошибка «приближается изучать их. Просто слишком много может и не получится.
У нас есть список рекомендуемых учебников, если он вам не по вкусу.
И если вы попробуете слишком большие вещи (например, шахматную программу) до того, как вы действительно освоите основы, ответ на любые ваши вопросы окажется довольно длинным, нежели удобным, и то, и другое для написания (если кто-то захочет) и для вас, чтобы переварить.
И пожалуйста:
Не использовать goto
если только вы абсолютно точно не знаете, что делаете.
Других решений пока нет …