Курсовая работа: Программа "Крестики-нолики 5 в ряд на неограниченном игровом поле"
ii();
//Проверяем, не закончена ли игра
if (end_analyze())
{
//Игра закончена, выводим сообщение и отрисовываем на экран
this->OnPaint();
this->Invalidate();
this->MessageBox(CA2T("Вы проиграли"),0,0);
end_game = true;//Ставим признак конца игры
return;
}
}
else
{
//Игра закончена, выводим сообщение и отрисовываем на экран
this->OnPaint();
this->Invalidate();
this->MessageBox(CA2T("Вы выиграли"),0,0);
end_game = true;//Ставим признак конца игры
return;
}
//Перерисовка окна
this->OnPaint();
this->Invalidate();
}
return;
}
//Функция вычисления, не закончена ли игра
int CChildView::end_analyze()
{
//Проход по всему полю (расчет ведется для каждой клетки)
for (int i=0;i<size_x;i++)
{
for (int j=0;j<size_y;j++)
{
//Пропускаем пустую клетку
if (fields[i][j]==0) continue;
int tek = fields[i][j];//Значение текущей клетки
int end;//Текущая длина ряда
int u;//Доп. счетчик
/////////////////////////////////////////
//Смотрим вправо от текущей клетки
end = 0;
for (int k = j;k<j+5;k++)
{
if ((k == size_y) || (fields[i][k] != tek))
{
//Нет ряда из 5
break;
}
end++;
}
if (end == 5)
{
//Есть ряд из 5 - конец игры
for (int k = j;k<j+5;k++)
{
fields[i][k]=tek+2; //Заполняем все клетки в ряду значением + 2 для отсветки красным цветом
}
return 1;
}
/////////////////////////////////////////
//Смотрим вниз и вправо от текущей клетки
end = 0;
u=i;
for (int k = j;k<j+5;k++)
{
if ((k == size_y) || (u==size_x) || (fields[u][k] != tek))
{
//Нет ряда из 5
break;
}
end++;
u++;
}
if (end == 5)
{
//Есть ряд из 5 - конец игры
u=i;
for (int k = j;k<j+5;k++)
{
fields[u][k]=tek+2; //Заполняем все клетки в ряду значением + 2 для отсветки красным цветом
u++;
}
return 1;
}
/////////////////////////////////////////
//Смотрим вниз и влево от текущей клетки
end = 0;
u=i;
for (int k = j;k>j-5;k--)
{
if ((k == -1) || (u==size_x) || (fields[u][k] != tek))
{
//Нет ряда из 5
break;
}
end++;
u++;
}
if (end == 5)
{
//Есть ряд из 5 - конец игры
u=i;
for (int k = j;k>j-5;k--)
{
fields[u][k]=tek+2; //Заполняем все клетки в ряду значением + 2 для отсветки красным цветом
u++;
}
return 1;
}
/////////////////////////////////////////
//Смотрим вниз от текущей клетки
end = 0;
for (int k = i;k<i+5;k++)
{
if ((k == size_x) || (fields[k][j] != tek))
{
//Нет ряда из 5
break;
}
end++;
}
if (end == 5)
{
//Есть ряд из 5 - конец игры
for (int k = i;k<i+5;k++)
{
fields[k][j]=tek+2; //Заполняем все клетки в ряду значением + 2 для отсветки красным цветом
}
return 1;
}
}
}
//Игра не окончена
return 0;
}
//Функция расчета действий компьютера
void CChildView::ii()
{
float max = -1;//Максимальное значение оценочной функции
int cur_x = 0,cur_y = 0;//Текущие x и у
int povtor_num = 0;//Количество повторов одинаковых значений оценочной функции
int cur_povtor = 0;//Номер текущего повтора
//Расчитываем оценочную функцию для всех клеток
for (int i=0;i<size_x;i++)
{
for (int j=0;j<size_y;j++)
{
if (fields[i][j] == 0)
{
//Расчет оценочной функции
calc_fields[i][j] = calculate(2,i,j) + calculate(1,i,j)*(float)attack_factor;
//Берем в расчет уровень (для профессионала случайности нет)
if (comp_level == 1)//Для любителя (небольшая случайность)
{
calc_fields[i][j] *= (1 + ((float)rand() / 32767)) / 2;
}
if (comp_level == 2)//Для новичка (максимальная случайность)
{
calc_fields[i][j] *= ((float)rand() / 32767);
}
if (calc_fields[i][j] == max)
{
//Еще одна клетка с максимальным значением оценочной функции
povtor_num++;
}
if (calc_fields[i][j] > max)
{
//Клетка с максимальным значением оценочной функции
max = calc_fields[i][j];
povtor_num = 0;
cur_x = i;
cur_y = j;
}
}
}
}
//Проверяем, есть ли вообще свободные клетки на поле
if (max == -1)
{
return;
}
//Выбираем куда сделать ход
if (povtor_num > 0)
{
//Выбираем куда ходить случайным образом из клеток с одинаковыми значениями оценочной функции
cur_povtor = rand() / (32767 / povtor_num);//Номер элемента, куда надо ходить
//Ищем его по полю
int buf_povtor = -1;
for (int i=0;i<size_x;i++)
{
for (int j=0;j<size_y;j++)
{
if (calc_fields[i][j] == max)
{
buf_povtor++;
if (buf_povtor == cur_povtor) //Клетка найдена
{
fields[i][j] = 2;//Ставим крестик
last_x = i;//Запоминаем координаты последнего хода
last_y = j;
return;
}
}
}
}
}
else
{
//Одна клетка с максимальным знаечением
fields[cur_x][cur_y] = 2;//Ставим крестик
last_x = cur_x;//Запоминаем координаты последнего хода
last_y = cur_y;
}
}
//Функция расчета оценочной функции
unsigned long CChildView::calculate(int id,int x,int y)
{
//Подсчет оценочной функции
//Ставим в массиве временно значение == id
fields[x][y] = id;
int series_length = 0;//Текущая длина ряда
unsigned long sum = 0;//Общее значение оценочной функции
///////////Расчет сверху вниз/////////
//Проход по каждой клетки, которая может входить в ряд
for (int i = 0;i<5;i++)
{
//Проверка, не вышли ли за границы поля
if ((x-4+i) < 0) continue;
if ((x+i) > (size_x - 1)) break;
//Проход по всем возможным рядам, отстоящим от клетки не более чем на 5
for (int j=0;j<5;j++)
{
if ((fields[x-4+i+j][y] != id) && (fields[x-4+i+j][y] != 0))
{
//Конец ряда
series_length = 0;
break;
}
if (fields[x-4+i+j][y] != 0) series_length++; //Ряд увеличивается
}
if (series_length == 1) series_length = 0;//Ряд из самой клетки не учитываем
if (series_length == 5) series_length = 100; //Выигрышная ситуация, ставим большое значение
//Плюсуем серию к общей сумме
unsigned long pow_st = valuation_factor;
if (series_length == 100)
{
if (id == 2)
pow_st = 10000;//Большое значение при своем выигрыше
else
pow_st = 1000; //Большое значение при выигрыше соперника, но меньшее, чем при своем
}
else
{
for (int i=0;i<series_length;i++)//Возводим оценочный коэффициент в степень длины серии
{
pow_st*=valuation_factor;
}
}
sum += pow_st;
series_length = 0;
}
///////////Расчет слева направо/////////
//Проход по каждой клетки, которая может входить в ряд
for (int i = 0;i<5;i++)
{
//Проверка, не вышли ли за границы поля
if ((y-4+i) < 0) continue;
if ((y+i) > (size_y - 1)) break;
//Проход по всем возможным рядам, отстоящим от клетки не более чем на 5
for (int j=0;j<5;j++)
{
if ((fields[x][y-4+i+j] != id) && (fields[x][y-4+i+j] != 0))
{
//Конец ряда
series_length = 0;
break;
}
if (fields[x][y-4+i+j] != 0) series_length++; //Ряд увеличивается
}
if (series_length == 1) series_length = 0; //Ряд из самой клетки не учитываем
if (series_length == 5) series_length = 100; //Выигрышная ситуация, ставим большое значение
//Плюсуем серию к общей сумме
unsigned long pow_st = valuation_factor;
if (series_length == 100)
{
if (id == 2)
pow_st = 10000;//Большое значение при своем выигрыше
else
pow_st = 1000; //Большое значение при выигрыше соперника, но меньшее, чем при своем
}
else
{
for (int i=0;i<series_length;i++)//Возводим оценочный коэффициент в степень длины серии
{
pow_st*=valuation_factor;
}
}
sum += pow_st;
series_length = 0;
}
///////////Расчет по диагонали с левого верхнего/////////
//Проход по каждой клетки, которая может входить в ряд
for (int i = 0;i<5;i++)
{
//Проверка, не вышли ли за границы поля
if ((y-4+i) < 0) continue;
if ((x-4+i) < 0) continue;
if ((x+i) > (size_x - 1)) break;
if ((y+i) > (size_y - 1)) break;
//Проход по всем возможным рядам, отстоящим от клетки не более чем на 5
for (int j=0;j<5;j++)
{
if ((fields[x-4+i+j][y-4+i+j] != id) && (fields[x-4+i+j][y-4+i+j] != 0))
{
//Конец ряда
series_length = 0;
break;
}
if (fields[x-4+i+j][y-4+i+j] != 0) series_length++; //Ряд увеличивается
}
if (series_length == 1) series_length = 0; //Ряд из самой клетки не учитываем