Функция движения ладьи не находит прерываний

Я пытаюсь написать функцию, которая проверяет, находится ли черный король под шахом белой ладьей. Проблема возникает, когда я пытаюсь найти фигуры между ладьей и королем.

    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 — номер доски, на которой он проверяется)

A[t_i] представляет собой массив структур, части структуры состоят из char field[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;
}

person Community    schedule 22.10.2015    source источник
comment
goto... почему? Кроме того, эта функция не компилируется (не объявлены t_i, m_x, m_y и, возможно, больше), и в ней отсутствует main(), поэтому мы не можем воспроизвести проблему. Вы даже не сказали нам, что такое наблюдаемый результат, только ожидаемый результат. Я не вижу там никакого отладочного вывода, который мог бы помочь вам определить, где фактическая обработка отличается от того, что вы ожидаете.   -  person DevSolar    schedule 22.10.2015
comment
@DevSolar, потому что я не могу придумать что-то еще, мне нужны разные циклы для вызова других циклов, чтобы завершить проверку, int main - это просто вызовы функции, в которой он ищет. вся программа уже состоит из 300+ строк, я не хочу группировать все, наблюдаемый вывод - ничего. Он ничего не выводит, как будто между кусочками что-то есть. Но если вы удалите кусок, он все равно ничего не выводит.   -  person    schedule 22.10.2015
comment
Что ж, сейчас я пишу int main(), пытаясь понять, как заполнить piece A[], чтобы посмотреть, что происходит. Если вы разместили минимальный, полный, проверяемый пример (который является проверенным временем методом отладки при попытке самостоятельно выяснить проблему ), я бы, наверное, уже написал ответ...   -  person DevSolar    schedule 22.10.2015
comment
При проверке пустых полей ладья движется только в одном измерении. Таким образом, меняется либо x, либо y, либо вверх, либо вниз в зависимости от направления.   -  person Bo Persson    schedule 22.10.2015
comment
@BoPersson ну да. Я пытаюсь выяснить, в каком направлении (L, R, U, D) находится король, расположенный от ладьи, поэтому я иду по одному измерению через все из них, чтобы найти само направление. @DevSolar Я включил int main() как вы запросили   -  person    schedule 22.10.2015
comment
Хорошо, теперь видите, что направление может быть задано вами с помощью +x или -x в индексе. Однако, если вы не найдете кусок в этом направлении (поэтому нет перехода к loop_exit), вы провалитесь до следующего теста.   -  person Bo Persson    schedule 22.10.2015
comment
Дубликат: stackoverflow.com/questions /33268987/   -  person Tas    schedule 22.10.2015
comment
@BoPersson, это то, что я хочу сделать, чтобы проверить все 4 направления и посмотреть, проходят ли они к королю.   -  person    schedule 22.10.2015
comment
Действительно ли у каждой фигуры есть копия шахматной доски? Я бы ожидал, что будет отдельная доска 8x8, и каждая часть будет хранить свою собственную позицию x, y.   -  person Galik    schedule 22.10.2015
comment
@iamtco - Извините, я говорил о коде после того, как вы нашли короля. Начиная с al_1: и ниже это похоже на switch-оператор без break.   -  person Bo Persson    schedule 22.10.2015
comment
@BoPersson хорошо. Я не совсем понимаю, о чем вы спрашиваете. Да, я думаю, они похожи на операторы switch, но я просто не понимаю их и не могу понять, как написать их как switch . Что касается копий шахматной доски, я думаю, что да - доска не меняется между функциями при поиске K. Поэтому я использую глобальные переменные m_x, k_x, ...   -  person    schedule 22.10.2015
comment
@iamtco - В switch-операторе вы используете break для выхода, чтобы он не переходил к следующей альтернативе. Для вас это означает, что если al_1: ничего не находит, он продолжает с al_2, al_3 и al_4. Может быть, не то, что вы хотели? Еще одна важная вещь, которую я вижу сейчас, это то, что сразу после loop_exit: вы всегда устанавливаете check = false.   -  person Bo Persson    schedule 22.10.2015
comment
@BoPersson о, я думал, что это не пройдет через al_1, al_2 и так далее. Итак, как мне обойти loop_exit: ? Мне все еще нужно проверить, является ли check true или false, а затем вывести его. Прямо сейчас это даже ничего не значит, я думаю, учитывая, что оно всегда устанавливает check = false ... как я могу обойти эту проблему?   -  person    schedule 22.10.2015
comment
@BoPersson Я имею в виду, что это пройдет только при вызове goto al_ ...   -  person    schedule 22.10.2015
comment
@DevSolar это похоже на современное использование goto. Это вещь? (Кстати, я не уверен, какой вопрос закрыть как обман.)   -  person Andras Deak    schedule 22.10.2015
comment
@AndrasDeak: я думаю, что я справился с этим. Возможно, ответ ниже поможет ОП. ;-)   -  person DevSolar    schedule 22.10.2015
comment
@AndrasDeak: я категорически не согласен с любым использованием goto в C++. (continue попадает в ту же категорию, а break не входит в case.) Если вы когда-либо делали NSD-диаграммы потока управления функцией, вы знаете почему. Я знаю, что есть и другие мнения, и я соглашусь с goto в руках настоящего эксперта, рассматривающего довольно частный случай, но обычно люди, использующие goto, не являются ни тем, ни другим (экспертами или рассматривающими особый случай). ;-)   -  person DevSolar    schedule 22.10.2015


Ответы (1)


Я сделаю то, что я обычно не делаю - я дам вам полное путешествие туда и обратно (потому что мне так хочется).


Вы начали с main(), которая должна считывать произвольное количество полей (но на самом деле падает 11-го числа), и функции search(), которая предназначена для перебора всех возможных шахматных фигур... но ваша программа не проходит проверку на самое первая фигура, белая ладья.

Вы также начали с C, а затем ввели гомеопатические дозы C++, фактически усложнив задачу.

Итак, давайте урежем это. Сначала мы добавим "минимум" в код вашего примера.


Давайте использовать <vector> вместо двумерного массива. Векторы — одна из самых полезных вещей в C++, и на самом деле почти нет причин использовать массивы в стиле C (за исключением, возможно, совместимости с C API).

#include <vector>
#include <iostream>

typedef std::vector< std::vector< char > > Field;

Field теперь является псевдонимом вектора векторов chars. Это в основном то же самое, что и двумерный массив (включая адресацию [][]), но у него есть некоторые преимущества, как вы скоро увидите.


Для вашего 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 по привычке.

Но именно поэтому я предложил использовать метод .at() vector<>, пока вы еще учитесь: терпеть неудачу как можно раньше и как можно громче. Исключение лучше, чем неопределенное поведение.


Кроме того, вы (во всех этих циклах) всегда перебираете 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, если вы абсолютно точно не знаете, что делаете.

person DevSolar    schedule 22.10.2015