20.04.2011, 17:57
общий
это ответ
Здравствуйте, Иванов Иван!
Для ячейки поля будем использовать компонент, наследованный от TSpeedButton, в котором предусмотрен рисунок на кнопке. Мы будем рисовать на ней фишки заданных цветов (я поставила красный и чёрный). Нам даже не придётся перегружать никакие функции исходного класса, достаточно добавить функцию, позволяющую занять клетку (она-то и будет рисовать фишку).
Из алгоритма самое сложное - проверка на выигрыш. Но тут у нас есть преимущество перед задачей поиска пути между границами в массиве - мы можем всегда отталкиваться от последней поставленной фишки. Для этого используем рекурсивную функцию, которая осмотрит всех соседей текущей фишки. Если функция натыкается на край, то выставляет соответствующий флаг. Если после выхода из рекурсии выставлены флаги право-лево или верх-низ, то соответствующий игрок победил.
[code h=100]bool TForm1::CheckWinner (int x, int y) //проверка, победил ли игрок ходом на x,y
{
top = false;
bottom = false;
left = false;
rigth = false;
//копируем поле во временное поле
memcpy (temp[gamer], flds[gamer], MaxBlocks*MaxBlocks*sizeof(bool));
CheckPath (x, y, -2, -2); //проверяем, есть ли путь от текущей клетки до краёв
if (gamer) return left&&rigth; //определяем победителя
else return top&⊥
}
void TForm1::CheckPath (int x, int y, int fromx, int fromy)
{ //рекурсивная функция, которая осматривает ячейки вокруг x,y на занятость
if (x>=wfield || y>=wfield || x<0 || y<0) return;
if (!temp[gamer][x][y]) return; //если пуста или просмотрена - прерываем
temp[gamer][x][y] = 0; //помечаем как просмотренную
if (x==(wfield-1)) {bottom = true;} //проверяем на края
if (x==0) {top = true;}
if (y==0) {left = true;}
if (y==(wfield-1)) {rigth = true;}
if (gamer && rigth && left) return;
if (!gamer && top && bottom) return;
for (int i=-1; i<=1; i++) //просматриваем окружающие, не возвращаясь назад
for (int j=-1; j<=1; j++) {
if (!(i==0 && j==0) && !(fromx==x+i && fromy==y+j))
CheckPath (x+i, y+j, x, y);
}
}[/code]
Обратите внимание, что при ходе я проставляю единицы в матрице flds, а в рекурсивной функции работаю с её копией temp, чтобы можно было помечать просмотренные клетки (это сократит число проходов и исключит зацикление рекурсии).
Максимальное число клеток определено константой, можно менять при необходимости. Число клеток по умолчанию выставляется в конструкторе.
Проект прилагаю, в приложении код класса кнопки.
Удачи!
Приложение:
class BlockControl : public TSpeedButton
{ //кнопка, способная быть занятой фишкой заданного цвета
bool isUsed; //занятость
TColor blockColor; //цвет фона
public:
int i; //расположение на поле
int j;
__fastcall BlockControl (TComponent* owner) : TSpeedButton (owner), isUsed(false){};
void Setup (int w, int ng, int i_, int j_, TColor col);
void SetUsed (bool is, TColor col = clWhite);
bool IsUsed ();
};
void BlockControl::Setup (int w, int ng, int i_, int j_, TColor col)
{ //настроить
this->Width = w;
this->Height = w;
this->Glyph->Width = w;
this->Glyph->Height = w;
this->GroupIndex = ng;
this->AllowAllUp = true;
blockColor = col;
//this->Color = clWhite;
i = i_; j = j_;
}
void BlockControl::SetUsed (bool is, TColor col)
{ //занять или освободить
if (is!=isUsed) {
TRect r = this->ClientRect;
if (is) {
//int r = this->Glyph->Width / 2 - 2;
this->Glyph->Canvas->Brush->Color = col;
this->Glyph->Canvas->Ellipse(r);
} else {
this->Glyph->Canvas->Brush->Color = blockColor;
this->Glyph->Canvas->Ellipse(r);
}
}
isUsed = is;
}
bool BlockControl::IsUsed ()
{
return isUsed;
}