Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 19, средняя оценка - 4.68
joker946
0 / 0 / 0
Регистрация: 25.09.2011
Сообщений: 5
#1

Шахматы(компьютер-компьютер) - C++

25.09.2011, 16:11. Просмотров 2429. Ответов 25
Метки нет (Все метки)

Здравствуйте, задали написать шахматы, где компьютер рандомно берет фигуру и ходит ею любую возможную сторону. То есть, никакого искусственного интеллекта. Компьютер должен играть сам с собой. Подскажите, с чего начать.
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
25.09.2011, 16:11
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Шахматы(компьютер-компьютер) (C++):

Не выключается компьютер! - C++
Вот так я делаю .... ExitWindows(EWX_POWEROFF, NULL); .... так я получаю SE_SHUTDOWN_NAME(WinXP/NT/2k) ....

Класс товар-компьютер. - C++
Еще раз здравствуйте. Я понимаю, что такую задачу никто-то за спасибо делать не будет, но помогите пожалуйста, хотя бы с алгоритмом или...

Программно выключить компьютер - C++
помогите сделать програму штоб виключать компютер

Компьютер угадывает число - C++
Пользователь загадывает число от 1 до 100 и компьютер пытается угадать. На каждую попытку компьютера пользователь отвечает, больше (h)...

Cin и компьютер без MSVS - C++
Здравствуйте! Проблема возникла на компьютере, где нет ни MSVS, ни каких-либо других SDK. Суть в следующем: попросили написать простенькую...

компьютер или винда виновата! - C++
Люди, пожалуйста подскажите что делать... Врубаю комп, грузится винда, открывается раб.стол... И НИЧЕГО НЕЛЬЗЯ ОТКРЫТЬ!!!:wall: ...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
vortexx1
6 / 6 / 2
Регистрация: 06.03.2011
Сообщений: 269
25.09.2011, 16:26 #2
Я бы сначала рассказал правила игры: кто как ходит и задал условия шаха/мата.

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

В принципе, задание несложное, но повозиться придется.
0
AnyOne697
134 / 106 / 5
Регистрация: 22.05.2010
Сообщений: 533
25.09.2011, 16:30 #3
То есть - банальная математическая модель.

Делаем, имхо, просто - создаём двумерный массив (целочисленный или символьный) и как-то размечаем поле (например, 1-6 - это фигуры первого игрока, +10 - уже второго, получаем - лёгкую проверку и создание маски возможных ходов), а также битовый (вроде Си этого не умеет) или булевый массив (он нужен как раз для маски).

Теперь всё легко. Рассказывать?

Добавлено через 39 секунд
Кстати, интересная задача =) Разбираемся =)
0
vortexx1
6 / 6 / 2
Регистрация: 06.03.2011
Сообщений: 269
25.09.2011, 16:30 #4
Цитата Сообщение от AnyOne697 Посмотреть сообщение
Рассказывать?
Рассказывай, тоже будет интересно послушать )
0
joker946
0 / 0 / 0
Регистрация: 25.09.2011
Сообщений: 5
25.09.2011, 16:33  [ТС] #5
Да, хотелось бы поподробнее. Препод говорит, через ооп делать проще. Расположение фигур - как в обычных шахматах. Компьютер должен рандомно брать любую фигуру первого игрока, сходить, потом второго и т.д.
0
soon
2540 / 1305 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
25.09.2011, 16:36 #6
Как вариант.
1) Заполняете массив фигурами(можно цифрами, можно буквами, главное, чтобы можно отличить черные от белых. Можно даже так
C++
1
2
#define KING_W A
#define KING_B a //для удобства рандомизации при выборе фигуры
задефайнить все фигуры.)
2) Нужна переменная по определению очереди хода.
3) Пусть ходят белые. Рандомизируем фигуру(при использовании варанта с символами просто задаем char-переменной определенный символ), затем через case определяем, какая фигура куда должна ходить(полагаю, вы знакомы, как ходят фигуры ).
4) С пешками отдельный разговор. Для них можно завести еще одну переменную, которая определяет, какая по счету пешка будет ходить.
5) Неплохо было бы сделать вот что: добавить возможность срубить чужую фигуру, закрыться от шаха, вести запись игры. И если фигура "связана", то ей ходить нельзя. А то это уже не шахматы, а ерунда какая то получится.
6) ну и собственно, если фигурой не получилось сходить просто ищем новую.

Добавлено через 39 секунд

Не по теме:

тормоз >.<

0
AnyOne697
134 / 106 / 5
Регистрация: 22.05.2010
Сообщений: 533
25.09.2011, 22:07 #7
Раз народ просит...

Собственно, понятное дело, что через ООП будет проще. Создаём несколько классов (я не гуру ООП, поэтому возможно я вообще нифига не по парадигме ООП сделал, но самоучке, имхо, можно), а там начинаем мутить.
Я парился не особо. Получилось что-то вроде этого:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <iostream>
#include <algorithm>
#include <Windows.h>
 
using namespace std;
 
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
 
enum ConsoleColor
{Black,Blue,Green,Cyan,Red,Magenta,Brown,LightGray,DarkGray,LightBlue,LightGreen,LightCyan,LightRed,LightMagenta,Yellow,White};
 
enum Figures
{NULL1, Pawn, Rock, Knight, Bioshop, Queen, King};
 
enum Players//вроде оказалось пока не нужным... но пусть будет
{WhitePlayer, BlackPlayer};
 
 
/*
black +10
[2][3][4][5][6][4][3][2] => x
[1][1][1][1][1][1][1][1]
[ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ]
[1][1][1][1][1][1][1][1]
[2][3][4][5][6][4][3][2]
||                white
\/
y
*/
 
 
class CDesk{
public:
    int m_desk[8][8]; //m_desk[x][y]
    CDesk(){
        for(int i = 0; i < 8; i++)
            m_desk[i][1] = m_desk[i][6] = 1;//пешки
        for(int i = 0; i < 3; i++)
            m_desk[i][0] = m_desk[7-i][0] = m_desk[i][7] = m_desk[7-i][7] = i+2; //ладьи, потом кони, в конце слоны
        m_desk[4][0] = m_desk[4][7] = King; // король
        m_desk[3][0] = m_desk[3][7] = Queen; //королева
 
        for(int i = 0; i < 8; i++){ //красим фигуры в чёрный
            m_desk[i][0] += 10;
            m_desk[i][1] += 10;
        }
 
        for(int j = 2; j < 6; j++){//где-то должна быть чернота
            for(int i = 0; i < 8; i++){
                m_desk[i][j] = 0;
            }
        }
    }
 
    void Show(){
        int cell = Yellow;
        for(int j = 0; j < 8; j++){
            for(int i = 0; i < 8; i++){
                SetConsoleTextAttribute(hStdOut, cell);
                cout << '[';
                if(m_desk[i][j] > 10)   SetConsoleTextAttribute(hStdOut, DarkGray); //красим чёрных
                else                    SetConsoleTextAttribute(hStdOut, LightGray);//красим белых
                if(!m_desk[i][j])       SetConsoleTextAttribute(hStdOut, Black);//красим пустоту
                cout << m_desk[i][j]%10;
                SetConsoleTextAttribute(hStdOut, cell);
                cout << ']';
                //инверт
                if(cell == Brown)   cell = Yellow;
                else                cell = Brown;
            }
            //ещё один инверт, чтобы не инверт =)
            if(cell == Brown)   cell = Yellow;
            else                cell = Brown;
            cout << endl;
        }
    }
};
 
class CGame{
private:
    CDesk m_d;
    bool m_mask[8][8];
    bool CheckFigure(int player, int x, int y){
        if(!m_d.m_desk[x][y]) return false;
        if(m_d.m_desk[x][y] > 10) return false ^ player;
        else                      return true  ^ player;
    }
public:
    void ShowDesk(){
        m_d.Show();
    }
    void resetMask(){
        for(int i = 0; i < 8; i++)
            for(int j = 0; j < 8; j++)
                m_mask[i][j] = false;
    }
    CGame(){
        resetMask();
    }
//ОСНОВНАЯ ФУНКЦИЯ. ОСНОВНАЯ ЛОГИКА ДОЛЖНа БЫТЬ ЗДЕСЬ
    void makeMask(int x, int y){
        for(int j = 0; j < 8; j++){
            for(int i = 0; i < 8; i++){
                cerr << "WTF!!!!!!!!!!!?..\n";
                bool temp = (x == i || y == j && !(x == i && y == j));
                if(temp){
                    m_mask[i][j] == true;
                }
            }
        }
    }
//основная функция. основная логика должнА быть там
    void makeTurn(int player){
        int x = rand()%8, y = rand()%8;
        while(!CheckFigure(player, x, y)){
            x = rand()%8;
            y = rand()%8;
        }
        makeMask(x, y);
        int temp = m_d.m_desk[x][y]; //как бы поднимаем фигуру в воздух
        m_d.m_desk[x][y] = 0; //мы же уходим от туда
        do{
            x = rand()%8; y = rand()%8; //выбираем куда-бы нам поставить её
        }while(!m_mask[x][y]); //собственно, проверяем, хотим мы её поставить ПО ПРАВИЛАМ или нет
        m_d.m_desk[x][y] = temp; //а теперь мы ставим фигуру на выбранное место
    }
};
 
void main(){
    CGame game;
    for(int i = 0;;i++){//ещё надо бы сделать проверку на шах-мат. Это тоже важно! Не буду лишать удовольствия.
        game.ShowDesk();
        game.makeTurn(i%2);
        Sleep(1000);
    }
}
У меня не работает.
+ логика, конечно, не правильная. Нужно обработать правила игры, про которые вики говорит "Сложные". Ну, собственно, и почти всё. Останется за тривиальным - сделать по красивее (можно, например, юникодовые символы заюзать, думаю там есть и Unicode).

Задача решилась гениально (то есть просто).

Сначала мы делаем доску и расставляем фигуры.
Потом первый игрок (белый видимо) выбирает случайным образом фигуру, которой будет ходить.
Прим. Здесь надо бы поправить логику, чтобы если некуда ходить, выбиралась другая фигура, но это тривиал.
Теперь, надо выбрать куда ходить. Для этого я использовал булеву маску: создаём маску возможных ходов, а потом аналогичным рандомом ходим. Здесь очень хорошо реализуется "съедание" фигуры, без лишних функций.
Собственно, передаём ход другому игроку и всё повторяется.
В принципе, всё делается элементарно (так же) и без ООП: нужно два масива (целочисленный и булевый), несколько десяток функций, switch-case-технология, ну, собственно, и всё.

Ах да, проверка на шах и мат. В принципе - не сложная. Нужно пройтись по всему полю, там найти все фигуры и посмотреть, может ли он "съесть" короля. Если может, то "походить" королём - и снова проверить. Можно скопировать для этого поле.

Немного лирики про ООП.
О да, можно, конечно, создать класс фигуры, а не юзать целочисленную. Здесь, тогда, прямо в классе можно хранить правила создания маски, функцию ходя, координаты, но смысл?.. Мат. модель не Crysis и усложнять её достаточно сложным и немного не в тему ООП нет смысла. А понятный код достигается введением банального перечисления - теперь не нужно запоминать, какая цифра что означает...
Вроде всё =)

Теперь, про улучшение:
Во-первых, можно рандомить не координаты (когда фигуру выбираем), а номер клетки. Зачем? Ввести динамику - когда проходим по массиву в поиске рандомизированной фигуры, можно легко найти кол-во фигур, делать более быструю проверку шах-мата, можно ещё подумать над некоторыми пряниками. Да и выбирать будет побыстрее (если без пряников) чаще, чем рандом координатами, особенно если фигур осталось мало - здесь мы не будем часто "мазать", а просто идти по массиву с проверкой (сам рандом медленнее перехода к следующей клетке).

Но зачем?.. 64 клетки, даже если осталось два короля, то выбирать игроку фигуру рандомом будем с вероятностью 1/64. Уже на 1000-ом выборе шанс выбрать будет очень близок к 100 процентам. Так что, обойдёмся этим =)

Добавлено через 24 минуты
*facepalm*
Там где "WTF" два знака равно - этим я хотел провести операцию присваивания...
Да, всё "почти" работает... Если не брать в расчёт логику...

Добавлено через 17 минут
*facepalm*
Забыл ресетить маску.

Добавлено через 29 минут
В принципе, для ладьи можно сделать проще - случайный выбор одной из координат, для слона - выбранные координаты должны быть пропорциональны (прибавляем или вычитаем случайное число), для пешки - если ордината (y) на одну больше (меньше) или если враг рядом... В общем, можно и без маски, просто маска позволяет программировать более универсально и в switch-case'е и самое главное - проще обрабатывать дополнительные условия, вроде преград или фигур свой-чужой...

В общем, в такой задаче можно сделать и такой подход...
0
joker946
0 / 0 / 0
Регистрация: 25.09.2011
Сообщений: 5
25.09.2011, 23:16  [ТС] #8
Ого, огромное спасибо. Буду разбираться.
0
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
25.09.2011, 23:41 #9
Предлагаю такую идею:
Писать на C++, и обойтись без фигур вообще, то есть из сущностей будут только объекты класса "Клетка на доске".
У клетки будут аттрибуты, типа:

1) Сторона противника (как чёрная или белая фигура).

2) Закон передачи аттрибутов другой клетке (например, клетка, которая "Ферзь", может передавать свои аттрибуты движения по диагонали и по горизонталям-вертикалям). Для этого проверяем все клетки, которым может передать свой аттрибут клетка-ферзь,и вычитаем занятые клетки(то есть те, у которых есть аттрибуты движения). + можно брать в рассчёт клетки "под ударом".

Из этих свойств движения можно вычленить основные - движение по диагонали,движение по вертикали (горизонтали).
Ещё могут накладываться ограничения длины траектории (король и пешка). Единственная особая клетка - это та, на которой "стоит конь". Но это тоже можно сделать.
Когда фигура рубит другую, то в реализации клетка передаёт свои аттрибуты пострадавшей.

Добавлено через 16 минут
**Вот тут в принципе, возможно, целесообразно сделать нечто в виде битовых карт для каждой позиции на доске. Например, для фигуры,которая ходит по диагонали, в любой точке доски будет своя битовая карта клеток,которым можно передать аттрибуты (то есть на которые могла бы переместиться фигура). Складывая маски в более сложных случаях, можно сразу получить искомые клетки. Я не знаю, насколько валидна эта идея, но по идее должно сократить поиски и прочее.

Почему без фигур? Я не знаю, просто ради интереса . В принципе, логика шахмат от этого легче не станет.
1
AnyOne697
134 / 106 / 5
Регистрация: 22.05.2010
Сообщений: 533
26.09.2011, 00:00 #10
Цитата Сообщение от #pragma
Писать на C++, и обойтись без фигур вообще,
А разница? Принципиально, у меня реализация не то что без фигур, а без объекта клетка как такого, вместо него - два двумерных массива: целочисленный и булевый. Тем более, что здесь разницы нет, можно хранить координаты в классе (структуре) координаты (как у я, в принципе, прежложил) или хранить в классе объект (как вы предлагаете, и что у меня сделано). Что в лоб, что по лбу =) Идеология одна, а как реализовывать пусть выбирает реализующий.

Вот что до идеологии, есть идея сделать БЕЗ маски. Легко. И даже проще находить преграды. В общем - выбираем фигуру, а потом несём её всё дальше от этой клетки ПО ПРАВИЛАМ. Как бы реле такое, рельсы. Можно генерить одно случайное число - число переходов к следующей клетке. Если дальше нельзя - возврсщаемся назад, а там в другую сторону, если она одна (или они закончились), то идём заного. Так мы можем даже не считать число всех возможных ходов.
Но здесь могут быть другие подводные камни...

Добавлено через 1 минуту
И удачи в реализации!
0
joker946
0 / 0 / 0
Регистрация: 25.09.2011
Сообщений: 5
30.09.2011, 21:14  [ТС] #11
Извините, но не подскажите, что значит данная строка?

Цитата Сообщение от AnyOne697 Посмотреть сообщение
bool CheckFigure(int player, int x, int y){
* * * * * * * * if(!m_d.m_desk[x][y]) return false;
* * * * * * * * if(m_d.m_desk[x][y] > 10) return false ^ player;
* * * * * * * * else* * * * * * * * * * * * * * * * * * * return true *^ player;
А в частности знак в строке "return false ^ player;"
0
Bers
Заблокирован
30.09.2011, 22:03 #12
делет
0
AzaKendler
214 / 116 / 9
Регистрация: 30.05.2011
Сообщений: 1,772
30.09.2011, 22:09 #13
Цитата Сообщение от #pragma Посмотреть сообщение
обойтись без фигур вообще
поддерживаю. сама по себе фигура не наделена "интеллектом" так что нет смысла морочиться с каждой фигурой(этож не кол оф дьюти). пусть будут прокачанные клетки с триггерами состояния, способные содержать любую фигуру или быть пустыми
0
Bers
Заблокирован
30.09.2011, 23:13 #14
на базе вектора делается 2д контейнер (на самом деле это вектор векторов, + методы, с помощью которых можно обращаться к контейнеру, как к двухмерному массиву)

Класс шахматной доски: содержит 2д контейнер. Каждый элемент 2д контейнера - ИД_фигуры; //вместо айдишника можно впиндюрить указатель. Это не суть.

Умеет выдывать айдишник фигуры по запросу клиента. Например: Доска.КакаяФигура(координаты);
Умеет двигать фигуру по доске: Доска.ПередвинутьФигуру(ид, новые_координаты);



Класс фигур: имеет полиморфную природу. То бишь создаётся базовый класс с полями: цвет, название. И один виртуальный метод ВернутьСписокКлеток_КудаЯМогуСходить().

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

Класс игроков: Знает о существовании доски, умеет получать через её интерфейс все необходимые ему данные о расположении фигур.
Содержит вектор своих фигур. (В нем хранятся только оставшиеся в живых фигуры).

Класс игроков - полиморфный. Базовый игрок имеет виртуальный метод ТвойХод();

От базового игрока наследуются два потомка: КомпьютерныйИгрок, и ЖивойИгрок.

Задача КомпьютерногоИгрока - выбрать фигурку из списка оставшихся в живых (по смыслу задачи - рандомно).
И попросить фигурку вернуть список возможных ходов.
Из этого списка выбрать наиболее подходящий (по смыслу задачи - рандомный вариант из полученного списка) вариант. Таким образом получаем координаты, куда будит сдвинута фигурка.
Далее, игрок приказывает доске передвинуть фигурку на новую клетку.
Игрок умеет запоминать свой последний ход (какую фигурку куда сдвинул), или же все свои ходы. И выдавать эту информацию по запросу клиента.

ЖивойИгрок (его по смыслу задачи нет. Однако, если не ввести эту сущность на этапе проектирования архитектуры, потом придётся переделывать минимум весь класс игроков. Поэтому, если даже влом его изготавливать, заложить саму возможность для будущего расширения функциональности заготовки - идея правильная)

При запуске метода ТвойХод() запускает какие то свои собственные методы для общения с человеком-геймером. Но в целом процедура похожа - выбор фигурки для хода, и ход только в те клетки, которые присутствуют в списке возможных ходов данной фигурки. Ну а дальше все тоже самое - Доска.ПередвинутьФигуру(Ид, новые координаты);


Класс Игровой Логики: знает о существовании доски, и о существовании игроков.
Поочередно делает каждому игроку: Игрок.ТвойХод();
после чего, через интерфейс доски проверяет состояние фигур. И на основании этого провозглашает следующий ход, либо завершение игры.
Умеет опрашивать игрока о его последнем ходе, и на основании онного выводить данные на экран (если игра с графикой - двигать спрайты фигур, если текстовая - просто выводить данные о совершенных ходах).

Данная архитектура довольно проста, и стабильна. Она легко расширяется: ИгровуюЛогику легко научить выводить данные в виде красивой графики.
Легко можно научить Игровую логику, например, на основании расположения фигур кричать: Шах! и тп.

А Игроков легко можно изменять так, что бы они становились более умными. Ну и прикручивать удобные интерфейсы для управления живым игроков.

При данной архитектуре,из грубоватой заготовки можно будит сделать полноценную игру.
1
Deviaphan
Делаю внезапно и красиво
Эксперт C++
1287 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
01.10.2011, 09:13 #15
Скачайте книгу Евгения Корнилова "Программирование шахмат и других логических игр". Там ОЧЕНЬ подробно рассматривается реализация примитивной (тупо перебором) шахматной программы и именно на Си. И на Паскале.

Добавлено через 32 секунды
ОМГ, что я говорю. Не "скачайте", а купите, разумеется.
1
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.10.2011, 09:13
Привет! Вот еще темы с ответами:

Реализовать иерархию классов Компьютер-Ноутбук - C++
Помогите, пожалуйста. Условие задачи: частота процессора (в МГц), количество ядер, объем памяти (в МБ), объем жесткого...

Глюк компиляторов или виноват компьютер? - C++
Здравствуйте, меня мучает такой вопрос: мой ноут не может нормально скомпилировать ни одной программы, пробовала 2 компилятора под c++, а...

Программа составления спецификации на персональный компьютер - C++
Тема: Модульное программирование. Интерфейсы. Задание: Реализовать программу составления спецификации на персональный компьютер.

Вывод структуры, описывающей компьютер, из файла - C++
Привет всем, поля в структуре: 1. Тип компьютера; 2. дата выхода; 3. Цена; найти всех компьютеров, с указанним...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
01.10.2011, 09:13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru