Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifndef CHECKERS_GAME_H
- #define CHECKERS_GAME_H
- #include <windows.h>
- #include <commctrl.h>
- #include <time.h>
- #include <math.h>
- #include <errno.h>
- #include "Cell.h"
- #include "Player.h"
- #include "AiGame.h"
- #include "HumanGame.h"
- #include "Menu.h"
- extern RECT rct;
- static enum GameModes {
- HUMAN, AI
- };
- extern const int offsetX;
- extern const int offsetY;
- extern const int fieldSize;
- extern Player *player1;
- extern Player *player2;
- extern Player *currentPlayer;
- extern int humanTurn;
- extern Cell **cells;
- extern Cell *lastChosenCell;
- extern int gameStarted;
- extern int playerCanChangeSide;
- extern int gameMode;
- extern HWND hwnd;
- extern HDC dc;
- extern HDC memDC;
- extern HBITMAP memBM;
- extern HMENU hFile;
- extern HMENU hInf;
- Cell **createCells();
- void drawBorder(HDC dc);
- void drawCell(HDC dc, Cell *cell);
- void drawCells(HDC memDC, Cell **cells);
- HIMAGELIST getImg(char *path);
- void placeFigure(HDC dc, Cell *cell);
- void placeFigures(HDC dc, Cell **cells);
- Cell *findCell(int x, int y);
- void getWay(int wayType, Cell *cell);
- int countWay(Cell **way);
- void clearWay(Cell **way);
- void clearRange(Cell **way, int from, int count);
- void removeHighlight(Cell **way, int from, int count);
- void restoreHighlight();
- int getAllValidWays(Cell *cell, int humanTurn);
- void clearWays(Cell *cell);
- int getAllWays(Cell *cell, int humanTurn);
- void highlightCell(HDC dc, Cell *cell);
- void hideHighlight(Cell *cell);
- void showWays(HDC dc, Cell *cell);
- int wayContains(Cell **way, Cell *cell);
- Cell **getPath(Cell *cell);
- int wayIndexOf(Cell **way, Cell *cell);
- int indexOf(Cell **cells, Cell *cell);
- int eat(Cell *cell, Cell **way, int king);
- int canEat(Cell *cell);
- int getTurnsCount(Cell *cell);
- int haveTurns(Player *player);
- void swapProps(Cell *cell1, Cell *cell2);
- int msleep(long msec);
- void changeTurn(int ate, Cell *cell);
- void defineFiguresSide();
- void changeSide();
- void freeMem();
- void newGame(HDC dc, int mode);
- #endif
- // Game.c
- #include "Game.h"
- int getKingZone(int k) {
- int kingZone = NONE;
- if (k < 8) kingZone = BLACK; // черные ячейки от 0 индекса до 7 являются королевскими зонами
- else if (k > 55) kingZone = WHITE; // также, как и ячейки с индексом от 56 до 63
- return kingZone;
- }
- int getFigure(int k) {
- int figure = NONE;
- if (k < 24) figure = BLACK; // черные ячейки с k < 24 имеют черные фигуры
- else if (k > 39) figure = WHITE; // если k > 39, то фигуры белые
- return figure;
- }
- void createWays(Cell *cell) {
- cell->ways = malloc(4 * sizeof(Cell **));
- for (int n = 0; n < 4; n++) {
- cell->ways[n] = malloc(8 * sizeof(Cell *));
- for (int l = 0; l < 8; l++) {
- cell->ways[n][l] = NULL;
- }
- }
- }
- Cell **createCells() {
- Cell **cells = malloc(8 * sizeof(Cell *)); // выделение памяти
- int offset = fieldSize / 8; // показывает, на сколько будут сдвигатся новые ячейки
- int xOffset = 0; // отступ по оси x
- int yOffset = 0; // отступ по оси y
- COLORREF black = 0x00ba8871; // цвет, используемый как черный
- COLORREF white = 0x00e3fcff; // цвет, используемый как белый
- COLORREF lastColor = white; // последний цвет
- int k = 0; // номер создаваемой ячейки
- int pl1LastIndex = 0; // индекс последней ячейки первого игрока
- int pl2LastIndex = 0; // индекс последней ячейки второго игрока
- for (int i = 0; i < 8; i++) {
- cells[i] = malloc(8 * sizeof(Cell)); // выделение памяти
- COLORREF color;
- for (int j = 0; j < 8; j++) {
- int figure = NONE; // ячейка пуста
- int kingZone = NONE; // не является зоной, встав на которую можно превратится в дамку
- if (j % 2 == 0) { // если j четное число
- color = lastColor; // то в color записывается последний цвет
- if (lastColor != white) {
- kingZone = getKingZone(k); // установка королевской зоны
- figure = getFigure(k); // установка фигуры
- }
- } else if (lastColor == white) { // если j нечетное число и последний цвет белый
- color = black; // то цвет будет черным
- kingZone = getKingZone(k);
- figure = getFigure(k);
- } else if (lastColor == black) { // если же последний цвет черный
- color = white; // то текущий будет белым
- }
- if (color == white) kingZone = NONE; // если цвет ячейки белый, то королевская зона у такой ячейки будет отсутствовать
- Cell *cell = newCell(xOffset + 1, yOffset + 1, color, figure, kingZone); // создание ячейки
- if(color == black) createWays(cell); // инициализация массива путей, по которым фигура, сможет передвигаться
- cells[i][j] = *cell; // добавление ячейки в массив ячеек
- if (figure != NONE) {
- if (k < 24) {
- player2->cells[pl2LastIndex++] = &cells[i][j]; // добавление ячейки в массив ячеек второго игрока
- } else if (k > 39) {
- player1->cells[pl1LastIndex++] = &cells[i][j]; // добавление ячейки в массив ячеек первого игрока
- }
- }
- xOffset += offset; // увеличение отступа по x на величину offset
- k++; // увеличение индекса ячейки
- }
- yOffset += offset; // увеличение отступа по y на величину offset
- xOffset = 0; // сброс отступа по x
- lastColor = color; // установка последнего цвета
- }
- return cells; // возврат массива ячеек
- }
- void drawBorder(HDC dc) {
- SelectObject(dc, GetStockObject(DC_PEN));
- SetDCPenColor(dc, RGB(212, 162, 116));
- Rectangle(dc, 0, 0, 602, 602);
- }
- void drawCell(HDC dc, Cell *cell) {
- if (cell == NULL) return; // если ячейка
- SelectObject(dc, GetStockObject(DC_BRUSH)); // выбирается кисть
- SetDCBrushColor(dc, cell->background); // установка цвета кисти
- SelectObject(dc, GetStockObject(DC_PEN)); // выбирается перо
- SetDCPenColor(dc, cell->background); // установка цвета пера
- Rectangle(dc, cell->x, cell->y, cell->x + 75, cell->y + 75); // отрисовка прямоугольной области по заданным координатам
- }
- void drawCells(HDC memDC, Cell **cells) {
- for (int i = 0; i < 8; i++) {
- for (int j = 0; j < 8; j++) {
- Cell cell = cells[i][j]; // получение ячейки из массива
- drawCell(memDC, &cell); // вызов функции отрисовки ячейки
- }
- }
- }
- void drawLetters() {
- int offset = fieldSize / 8;
- int xOfsset = 0.8 * offset;
- int charCode = 65;
- char *letter = malloc(2);
- letter[1] = '\0';
- for(int i = 0; i < 8; i++) {
- letter[0] = (char) charCode;
- TextOut(dc, xOfsset, 5, letter, strlen(letter));
- xOfsset += offset;
- charCode++;
- }
- }
- void drawNumbers() {
- int offset = fieldSize / 8;
- int yOffset = 0.75 * offset;
- int charCode = 49;
- char *letter = malloc(2);
- letter[1] = '\0';
- for(int i = 0; i < 8; i++) {
- letter[0] = (char) charCode;
- TextOut(dc, 7, yOffset, letter, strlen(letter));
- yOffset += offset;
- charCode++;
- }
- }
- HIMAGELIST getImg(char *path) {
- InitCommonControls();
- HIMAGELIST hImagelist = ImageList_Create(60, 60, ILC_COLOR32 | ILC_MASK, 1, 0);
- HBITMAP image = LoadImage(NULL, path, IMAGE_BITMAP, 60, 60, LR_LOADFROMFILE);
- ImageList_AddMasked(hImagelist, image, RGB(0, 0, 0));
- return hImagelist;
- }
- void placeFigure(HDC dc, Cell *cell) {
- if (cell == NULL || cell->figure == NONE) return; // если указатель на ячейку = NULL или у ячейки отстутствует фигура, функция прекращает выполнение
- HIMAGELIST list = NULL; // здесь будет хранится изображение фигуры
- if (cell->figure == BLACK) {
- if (cell->figureType == KING) list = getImg("images/black_queen.bmp"); // если черная фигура является дамкой, то загружается черная фигура дамки
- else list = getImg("images/black.bmp"); // иначе просто черная фигура
- } else if (cell->figure == WHITE) {
- if (cell->figureType == KING) list = getImg("images/white_queen.bmp");// если белая фигура является дамкой, то загружается белая фигура дамки
- else list = getImg("images/white.bmp"); // иначе просто белая фигура
- }
- ImageList_Draw(list, 0, dc, cell->x + 8, cell->y + 7, ILD_NORMAL); // отрисовка изображения
- ImageList_Destroy(list); // освобождение памяти
- }
- void placeFigures(HDC dc, Cell **cells) {
- for (int i = 0; i < 8; i++) {
- for (int j = 0; j < 8; j++) {
- Cell cell = cells[i][j]; // получение ячейки из массива
- placeFigure(dc, &cell); // вызов функции размещения фигуры
- }
- }
- }
- Cell *findCell(int x, int y) {
- int i = floor((y - offsetY) / 75); // Индекс ячейки по координате Y
- int j = floor((x - offsetX) / 75); // Индекс ячейки по координате X
- if (i > -1 && i < 8 && j > -1 && j < 8) // Если индексы находятся в необходимом промежутке
- return &cells[i][j]; // То происходит возврат ссылки на ячейку
- return NULL; // Иначе возвращается NULL
- }
- void getWay(int wayType, Cell *cell) {
- if (cell == NULL) return;
- int i = floor((cell->y) / 75);
- int j = floor((cell->x) / 75);
- int k = 0;
- if (wayType == LEFT_TOP) {
- i--;
- j--;
- while (i > -1 && j > -1) { // leftTop
- cell->ways[0][k] = &cells[i][j];
- i--;
- j--;
- k++;
- }
- }
- if (wayType == RIGHT_TOP) {
- i--;
- j++;
- while (i > -1 && j < 8) {
- cell->ways[1][k] = &cells[i][j];
- i--;
- j++;
- k++;
- }
- }
- if (wayType == LEFT_BOTTOM) {
- i++;
- j--;
- while (i < 8 && j > -1) { // leftTop
- cell->ways[2][k] = &cells[i][j];
- i++;
- j--;
- k++;
- }
- }
- if (wayType == RIGHT_BOTTOM) {
- i++;
- j++;
- while (i < 8 && j < 8) { // leftTop
- cell->ways[3][k] = &cells[i][j];
- i++;
- j++;
- k++;
- }
- }
- }
- int countWay(Cell **way) {
- int count = 0;
- for (int i = 0; i < 8; i++) {
- if (way[i] != NULL) count++;
- }
- return count;
- }
- void clearWay(Cell **way) {
- for (int i = 0; i < 8; i++) {
- way[i] = NULL;
- }
- }
- void clearRange(Cell **way, int from, int count) {
- int cleared = 0;
- for (int i = from; i < 8 && cleared < count; i++) {
- if (way[i] != NULL) {
- way[i] = NULL;
- cleared++;
- }
- }
- }
- void removeHighlight(Cell **way, int from, int count) {
- for (int i = from; i < 8 && i < from + count; i++) {
- if (way[i] != NULL) way[i]->highlightPath = 0;
- }
- }
- void restoreHighlight() {
- for (int i = 0; i < 8; i++) {
- for (int j = 0; j < 8; j++) {
- cells[i][j].highlightPath = 1;
- }
- }
- }
- int getAllValidWays(Cell *cell, int humanTurn) {
- if (cell == NULL) return 0; // Если указатель на ячейку NULL, то возвращаем 0
- int eat[4] = {0, 0, 0, 0}; // Данный массив показывает, по каким направлением возможно взятие фигуры противника
- int mustEat = 0; // Должна ли фигура бить другую фигуру
- for (int i = 0; i < 4; i++) {
- Cell **way = cell->ways[i]; // Получение текущего пути
- int wayCount = countWay(way); // Количество ячеек в данном пути
- if (cell->figure != NONE && wayCount > 0) {
- if (cell->figureType == NORMAL) { // Если фигура является обычной
- if (way[0]->figure == NONE) { // То происходит проверка на соседнюю пустую ячейку
- if ((humanTurn && i > 1) || (!humanTurn && i < 2)) clearWay(way); // Если проверяются задние пути для текущего игрока, то они очищаются
- else clearRange(way, 1, wayCount - 1); // Иначе очищается все, кроме найденной соседней ячейки
- } else if (wayCount > 1 && way[0]->figure != cell->figure && way[0]->figure != NONE &&
- way[1]->figure == NONE) { // Если имеется возможность побить вражескую фигуру
- removeHighlight(way, 0, 1); // То у такой фигуры удаляется подсветка, т. к. на занимаемую такой фигурой ячейку нельзя наступить
- clearRange(way, 2, wayCount - 2); // Очищается путь
- eat[i] = 1; // На данном пути нужно есть
- mustEat = 1; // Данная ячейка должна есть
- } else {
- clearWay(way); // Если оба условия не сработали, то путь очищается
- }
- } else if (cell->figureType == KING) { // Если фигура является дамкой
- int stop = 0; // Отвечает за выход из цикла
- int j = 0;
- int rangeCleared = 0; // Показывает, был ли очищен путь
- while (!stop && j < 8) {
- if (way[j] != NULL) { // Если путь существует
- if (way[j]->figure == cell->figure) { // Если встречена своя фигура
- clearRange(way, j, wayCount - j); // То путь очищается до этой фигуры
- stop = 1; // И просиходит выход из цикла
- } else if (j + 1 < 8 && way[j + 1] != NULL && way[j]->figure != NONE && way[j + 1]->figure == NONE) { // Если есть возможность побить другие фигуры
- removeHighlight(way, j, 1); // То на данных фигурах удаляется подсветка
- if (!rangeCleared) { // Если путь не очищен
- clearRange(way, 0, j); // То он очищается
- rangeCleared = 1;
- }
- eat[i] = 1; // На данном пути нужно есть
- mustEat = 1; // Данная ячейка должна есть
- } else if (way[j]->figure != NONE) { // Если встречена любая другая фигура
- clearRange(way, j, wayCount - j); // То часть пути очищается
- stop = 1; // И происходит выход из цикла
- }
- }
- j++;
- }
- }
- }
- if (mustEat) { // Если ячейка должна есть
- for (int j = 0; j <= i; j++) {
- if (!eat[j]) clearWay(cell->ways[j]); // То очищаются все пути, где можно было не есть
- }
- }
- }
- return mustEat; // Возврат значения
- }
- void clearWays(Cell *cell) {
- for (int i = 0; i < 4; i++) {
- if (cell != NULL) clearWay(cell->ways[i]);
- }
- }
- int getAllWays(Cell *cell, int humanTurn) {
- clearWays(cell);
- getWay(LEFT_TOP, cell);
- getWay(RIGHT_TOP, cell);
- getWay(LEFT_BOTTOM, cell);
- getWay(RIGHT_BOTTOM, cell);
- return getAllValidWays(cell, humanTurn);
- }
- void highlightCell(HDC dc, Cell *cell) {
- if (cell != NULL && cell->highlightPath) { // Если указатель на ячейку не NULL и ее следует подсветить
- SelectObject(dc, GetStockObject(DC_PEN)); // То выбирается перо
- SetDCPenColor(dc, RGB(59, 221, 143)); // И устанавливается цвет пера
- SelectObject(dc, GetStockObject(DC_BRUSH)); // Затем выбирается кисть
- SetDCBrushColor(dc, RGB(59, 221, 143)); // И устанавливается увет для пера
- Rectangle(dc, cell->x, cell->y, cell->x + 75, cell->y + 75); // Далее происходит отрисовка прямоугольника по области ячейки
- placeFigure(dc, cell); // И размещается фигура
- }
- }
- void hideHighlight(Cell *cell) {
- drawCell(memDC, cell);
- placeFigure(memDC, cell);
- for (int i = 0; i < 4; i++) {
- Cell **way = cell->ways[i];
- for (int j = 0; j < 8; j++) {
- drawCell(memDC, way[j]);
- placeFigure(memDC, way[j]);
- }
- }
- }
- void showWays(HDC dc, Cell *cell) {
- for (int i = 0; i < 4; i++) {
- Cell **way = cell->ways[i];
- for (int j = 0; j < 8; j++) {
- highlightCell(dc, way[j]);
- }
- }
- }
- int wayContains(Cell **way, Cell *cell) {
- for (int i = 0; i < 8; i++) {
- if (way[i] == cell) return 1;
- }
- return 0;
- }
- Cell **getPath(Cell *cell) {
- if (lastChosenCell == NULL) return NULL;
- for (int i = 0; i < 4; i++) {
- Cell **way = lastChosenCell->ways[i];
- for (int j = 0; j < 8; j++) {
- if (wayContains(way, cell) && cell->highlightPath) return way;
- }
- }
- }
- int wayIndexOf(Cell **way, Cell *cell) {
- for (int i = 0; i < 8; i++) {
- if (way[i] == cell) return i;
- }
- return -1;
- }
- int indexOf(Cell **cells, Cell *cell) {
- for (int i = 0; i < 12; i++) {
- if (cells[i] == cell) return i;
- }
- return -1;
- }
- int eat(Cell *cell, Cell **way, int king) {
- int ate = 0;
- int destIndex = wayIndexOf(way, cell);
- for (int i = 0; i < 8; i++) {
- if (way[i] != NULL && way[i]->figure != NONE && ((king && destIndex > i) || !king)) {
- way[i]->figure = NONE;
- ate = 1;
- }
- }
- return ate;
- }
- int canEat(Cell *cell) {
- return getAllWays(cell, humanTurn);
- }
- int getTurnsCount(Cell *cell) {
- int turns = 0;
- for (int i = 0; i < 4; i++) {
- if (cell != NULL) turns += countWay(cell->ways[i]);
- }
- return turns;
- }
- int haveTurns(Player *player) {
- int humanTurn = player == player1 ? 1 : 0;
- for (int i = 0; i < 12; i++) {
- getAllWays(player->cells[i], humanTurn);
- int count = getTurnsCount(player->cells[i]);
- if (player->cells[i]->figure != NONE && player->cells[i]->figure == player->side && count > 0) {
- return 1;
- }
- }
- return 0;
- }
- void swapProps(Cell *cell1, Cell *cell2) {
- int figure = cell1->figure;
- int figureType = cell1->figureType;
- cell1->figure = cell2->figure;
- cell1->figureType = cell2->figureType;
- cell2->figure = figure;
- cell2->figureType = figureType;
- }
- int msleep(long msec) {
- struct timespec ts;
- int res;
- if (msec < 0) {
- errno = EINVAL;
- return -1;
- }
- ts.tv_sec = msec / 1000;
- ts.tv_nsec = (msec % 1000) * 1000000;
- do {
- res = nanosleep(&ts, NULL);
- } while (res && errno == EINTR);
- return res;
- }
- int isGameOver() {
- int noTurns1 = !haveTurns(player1);
- int noTurns2 = !haveTurns(player2);
- if (noTurns1 || noTurns2) {
- BitBlt(dc, 25, 25, 602, 602, memDC, 0, 0, SRCCOPY);
- if ((noTurns1 && player1->side == WHITE) || (noTurns2 && player2->side == WHITE)) {
- MessageBox(hwnd, "Победили чёрные", "Игра завершена", MB_OK | MB_ICONINFORMATION);
- } else if ((noTurns1 && player1->side == BLACK) || (noTurns2 && player2->side == BLACK)) {
- MessageBox(hwnd, "Победили белые", "Игра завершена", MB_OK | MB_ICONINFORMATION);
- }
- writeStats(humanTurn);
- ReleaseDC(hwnd, memDC);
- newGame(dc, gameMode);
- return 1;
- }
- return 0;
- }
- void changeTurn(int ate, Cell *cell) {
- if(isGameOver()) return;
- if (playerCanChangeSide) {
- playerCanChangeSide = 0;
- EnableMenuItem(hFile, 2, MF_GRAYED);
- }
- if (!ate || !canEat(cell)) { // Если в результате хода не была съедена фигура или данная ячейка не может больше есть
- humanTurn = !humanTurn; // То происходит смена хода
- currentPlayer->mustMove = NULL;
- currentPlayer = humanTurn ? player1 : player2;
- } else {
- currentPlayer->mustMove = cell; // Иначе полю mustMove будет присвоен указатель на данную ячейку
- }
- if (gameMode == AI && !humanTurn) moveFigure();
- }
- void defineFiguresSide() {
- for (int i = 0; i < 12; i++) {
- player1->cells[i]->figure = player1->side;
- player2->cells[i]->figure = player2->side;
- if (i < 8) {
- if (cells[0][i].kingZone != NONE) cells[0][i].kingZone = player2->side;
- if (cells[7][i].kingZone != NONE) cells[7][i].kingZone = player1->side;
- }
- }
- }
- void changeSide() {
- int isWhite = player1->side == WHITE;
- humanTurn = !humanTurn;
- if (isWhite) {
- player1->side = BLACK;
- player2->side = WHITE;
- currentPlayer = player2;
- } else {
- player1->side = WHITE;
- player2->side = BLACK;
- currentPlayer = player1;
- }
- defineFiguresSide();
- drawCells(memDC, cells);
- placeFigures(memDC, cells);
- if (gameMode == AI && !humanTurn) {
- moveFigure();
- playerCanChangeSide = 0;
- EnableMenuItem(hFile, 2, MF_GRAYED);
- }
- BitBlt(dc, 25, 25, 602, 602, memDC, 0, 0, SRCCOPY);
- }
- void freeMem() {
- if (gameStarted) {
- for (int i = 0; i < 8; i++) {
- for (int j = 0; j < 8; j++) {
- free(cells[i][j].ways);
- }
- free(cells[i]);
- }
- free(cells);
- free(player1);
- free(player2);
- ReleaseDC(hwnd, memDC);
- DeleteObject(memBM);
- player1 = NULL;
- player2 = NULL;
- cells = NULL;
- lastChosenCell = NULL;
- currentPlayer = NULL;
- memDC = NULL;
- memBM = NULL;
- }
- }
- void newGame(HDC dc, int mode) {
- int side1 = player1 != NULL ? player1->side : WHITE;
- int side2 = player2 != NULL ? player2->side : BLACK;
- freeMem();
- memDC = CreateCompatibleDC(dc);
- memBM = CreateCompatibleBitmap(dc, rct.right - rct.left, rct.bottom - rct.top);
- SelectObject(memDC, memBM);
- player1 = newPlayer(side1);
- player2 = newPlayer(side2);
- currentPlayer = side1 == WHITE ? player1 : player2;
- humanTurn = side1 == WHITE;
- cells = createCells();
- defineFiguresSide();
- drawBorder(memDC);
- drawCells(memDC, cells);
- placeFigures(memDC, cells);
- drawLetters();
- drawNumbers();
- gameStarted = 1;
- gameMode = mode;
- if (gameMode == AI && !humanTurn) {
- moveFigure();
- playerCanChangeSide = 0;
- } else if (!playerCanChangeSide) {
- playerCanChangeSide = 1;
- EnableMenuItem(hFile, 2, MF_ENABLED);
- }
- BitBlt(dc, 25, 25, 602, 602, memDC, 0, 0, SRCCOPY);
- }
- // Player.h
- #ifndef C_PLAYER_H
- #define C_PLAYER_H
- #include "Cell.h"
- typedef struct Player {
- int side;
- int mustEat;
- Cell **cells;
- Cell *mustMove;
- } Player;
- Player* newPlayer(int side);
- #endif
- // Player.c
- #include "Player.h"
- Player* newPlayer(int side) {
- Player *player = calloc(1, sizeof(Player));
- player->side = side;
- player->mustEat = 0;
- player->mustMove = NULL;
- player->cells = calloc(12, sizeof(Cell*));
- return player;
- }
- // Cell.h
- #ifndef C_CELL_H
- #define C_CELL_H
- #include <windows.h>
- enum Figures {
- NONE, BLACK, WHITE, NORMAL, KING
- };
- enum wayTypes {
- LEFT_TOP = 100, RIGHT_TOP, LEFT_BOTTOM, RIGHT_BOTTOM
- };
- typedef struct Cell {
- int x;
- int y;
- COLORREF background;
- int figure;
- int figureType;
- int kingZone;
- int highlightPath;
- struct Cell ***ways;
- } Cell;
- Cell* newCell(int x, int y, COLORREF background, int figure, int kingZone);
- #endif
- // Cell.c
- #include "Cell.h"
- Cell* newCell(int x, int y, COLORREF background, int figure, int kingZone) {
- Cell* cell = calloc(1, sizeof(Cell));
- cell->x = x;
- cell->y = y;
- cell->background = background;
- cell->figure = figure;
- cell->figureType = NORMAL;
- cell->kingZone = kingZone;
- cell->highlightPath = 1;
- return cell;
- }
- // HumanGame.h
- #ifndef CHECKERS_HUMANGAME_H
- #define CHECKERS_HUMANGAME_H
- #include "Player.h"
- #include "Cell.h"
- #include "Game.h"
- int canPlayerEat(Player *player);
- void onMouseDown(int x, int y);
- #endif
- // HumanGame.c
- #include "HumanGame.h"
- int canPlayerEat(Player *player) {
- for (int i = 0; i < 12; i++) {
- Cell *cell = player->cells[i];
- if (cell->figure == player->side && canEat(cell)) return 1;
- }
- return 0;
- }
- void onMouseDown(int x, int y) {
- Cell *cell = findCell(x, y);
- if (cell != NULL) {
- if (cell->figure != NONE) {
- if (cell == lastChosenCell) {
- hideHighlight(cell);
- lastChosenCell = NULL;
- } else if ((gameMode == HUMAN && ((humanTurn && cell->figure == player1->side) || (!humanTurn && cell->figure == player2->side))) || (gameMode == AI && (humanTurn && cell->figure == player1->side))) {
- if (lastChosenCell != NULL)
- hideHighlight(lastChosenCell);
- if ((currentPlayer->mustMove != NULL && currentPlayer->mustMove != cell) ||
- (canPlayerEat(currentPlayer) && !canEat(cell)))
- return;
- highlightCell(memDC, cell);
- getAllWays(cell, humanTurn);
- showWays(memDC, cell);
- lastChosenCell = cell;
- }
- } else {
- Cell **way = getPath(cell);
- if (lastChosenCell != NULL && way != NULL) {
- int ate = eat(cell, way, lastChosenCell->figureType == KING);
- swapProps(cell, lastChosenCell);
- int cellIndex = indexOf(currentPlayer->cells, lastChosenCell);
- if (cellIndex != -1) currentPlayer->cells[cellIndex] = cell;
- if (cell->kingZone != NONE && cell->kingZone != cell->figure) cell->figureType = KING;
- hideHighlight(lastChosenCell);
- drawCell(memDC, cell);
- placeFigure(memDC, cell);
- changeTurn(ate, cell);
- lastChosenCell = NULL;
- }
- }
- }
- restoreHighlight();
- BitBlt(dc, 25, 25, 602, 602, memDC, 0, 0, SRCCOPY);
- }
- // AiGame.h
- #ifndef CHECKERS_AIGAME_H
- #define CHECKERS_AIGAME_H
- #include "Player.h"
- #include "Cell.h"
- #include "Game.h"
- Cell *peekRandomCell(Cell **cells, int length);
- void moveFigure();
- #endif
- // AiGame.c
- #include "AiGame.h"
- Cell *peekRandomCell(Cell **cells, int length) {
- int index = rand() % length;
- return cells[index];
- }
- int countValidWays(Cell *cell) {
- int validWaysCount = 0;
- for (int i = 0; i < 4; i++)
- validWaysCount += countWay(cell->ways[i]);
- return validWaysCount;
- }
- Cell **getValidWaysCells(int validWaysCount, Cell *cell) {
- int k = 0;
- Cell **validWays = malloc(validWaysCount * sizeof(Cell *));
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 8; j++) {
- if (cell->ways[i][j] != NULL) {
- validWays[k] = cell->ways[i][j];
- k++;
- }
- }
- }
- return validWays;
- }
- void renderDestination(Cell *cell, Cell *destination) {
- hideHighlight(cell);
- drawCell(memDC, destination);
- placeFigure(memDC, destination);
- restoreHighlight(cell);
- }
- void moveFigure() {
- Cell *cell = peekRandomCell(player2->cells, 12); // Выбор случайной фигуры из доступных
- if(cell == NULL || cell->figure != player2->side) return moveFigure(); // Если указатель на ячейку NULL или фигура отличается, то выбирается другая фигура
- getAllWays(cell, 0); // Получение всех путей для выбранной фигуры
- int validWaysCount = countValidWays(cell); // Получение общего количества путей, по которым можно ходить
- if (validWaysCount == 0 || (player2->mustMove != NULL && player2->mustMove != cell) || (canPlayerEat(player2) && !canEat(cell))) // Если путей нет или необходимо есть, то выбирается другая фигура
- return moveFigure();
- lastChosenCell = cell;
- Cell **validWays = getValidWaysCells(validWaysCount, cell); // Одномерный массив указателей на структуру Cell, представляющий собой ячейки, на которые можно походить
- Cell *destination = peekRandomCell(validWays, validWaysCount); // Ячейка, на которую будет перемещена фигура
- Cell **way = getPath(destination); // Выбранный путь
- if (way == NULL) return moveFigure(); // Если такой путь пустой, то происходит выбор другой фигуры
- BitBlt(dc, 25, 25, 602, 602, memDC, 0, 0, SRCCOPY); // Отрисовка перед таймером
- msleep(200); // Ожидание 200 мс
- int ate = eat(destination, way, cell->figureType == KING); // Показывает, была ли съедена фигура противника
- swapProps(destination, cell); // Обмен значениями между исходной и конечной ячейками
- int cellIndex = indexOf(player2->cells, cell); // Индекс ячейки в массиве ячеек игрока
- if (cellIndex != -1) player2->cells[cellIndex] = destination; // Если ячейка в массиве игрока, то она заменяется на destination
- if (destination->kingZone != NONE && destination->kingZone != destination->figure) // Если наступили на королевскую зону противника
- destination->figureType = KING;
- renderDestination(cell, destination); // Отрисовка фигуры
- changeTurn(ate, destination); // Смена хода
- }
- // Menu.h
- #ifndef CHECKERS_MENU_H
- #define CHECKERS_MENU_H
- #include <stdio.h>
- #include <errno.h>
- #include <unistd.h>
- #include "Game.h"
- FILE *openFile(char *path);
- void showStats();
- void about();
- int *readStats(FILE *file);
- void writeStats(int win);
- void clearStats();
- void closeGame();
- void newGameWithAi();
- void newGameWithHuman();
- void confirmation(char *text, void (*callback)(void));
- #endif
- // Menu.c
- #include "Menu.h"
- FILE *openFile(char *path) {
- FILE *file;
- if (access(path, F_OK) == 0) {
- file = fopen(path, "r+");
- } else {
- file = fopen(path, "w+");
- }
- return file;
- }
- void showStats() {
- FILE *file = openFile("stats.data");
- int *stats = readStats(file);
- char *str = malloc(128);
- sprintf(str, "Победы: %d\nПоражения: %d", stats[0], stats[1]);
- MessageBox(NULL, str, "Статистика", MB_ICONINFORMATION | MB_OK);
- fclose(file);
- }
- void about() {
- MessageBox(NULL,
- "Данная программа предназначена для развлекательных целей. \n\nАвтор программы:\nКуфтырев Алексей, студент 2 курса ФКСиС.",
- "О программе", MB_ICONINFORMATION | MB_OK);
- }
- int *readStats(FILE *file) {
- rewind(file);
- int *info = malloc(2 * sizeof(int));
- info[0] = 0; // wins
- info[1] = 0; // loses
- char ch;
- int i = 0;
- while ((ch = getc(file)) != EOF) {
- info[i] = ch - '0';
- if (ch != '\n' && ch != '\r') i++;
- }
- return info;
- }
- void writeStats(int win) {
- FILE *file = openFile("stats.data");
- int *currStats = readStats(file);
- int wins = currStats[0];
- int loses = currStats[1];
- if (win)
- wins++;
- else
- loses++;
- fseek(file, 0, SEEK_SET);
- fputc(wins + '0', file);
- fputc('\n', file);
- fseek(file, 2, SEEK_SET);
- fputc(loses + '0', file);
- fclose(file);
- }
- void clearStats() {
- remove("stats.data");
- MessageBox(NULL, "Статистика сброшена", "Информация", MB_ICONINFORMATION | MB_OK);
- }
- void closeGame() {
- freeMem();
- PostQuitMessage(0);
- }
- void newGameWithAi() {
- newGame(dc, AI);
- }
- void newGameWithHuman() {
- newGame(dc, HUMAN);
- }
- void confirmation(char *text, void (*callback)(void)) {
- int msgBoxId = MessageBox(NULL, text, "Подтвердите действие", MB_ICONQUESTION | MB_YESNO);
- if (msgBoxId == IDYES) {
- callback();
- }
- }
- // main.c
- #include <math.h>
- #include <windows.h>
- #include <commctrl.h>
- #include <time.h>
- #include "modules/Game.h"
- RECT rct;
- const int offsetX = 25;
- const int offsetY = 25;
- const int fieldSize = 600;
- Player *player1 = NULL;
- Player *player2 = NULL;
- Player *currentPlayer = NULL;
- int humanTurn = 1;
- Cell **cells = NULL;
- Cell *lastChosenCell = NULL;
- int gameStarted = 0;
- int playerCanChangeSide = 1;
- int gameMode = HUMAN;
- HWND hwnd = NULL;
- HDC dc = NULL;
- HDC memDC = NULL;
- HBITMAP memBM = NULL;
- HMENU hFile = NULL;
- HMENU hInf = NULL;
- enum MenuButtons {
- AGAINST_AI, AGAINST_HUMAN, CHANGE_SIDE, CLEAR_STATS, CLOSE_GAME, ABOUT, STATS
- };
- LRESULT WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
- LRESULT WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
- if (message == WM_DESTROY) {
- freeMem();
- PostQuitMessage(0);
- } else if (message == WM_SIZE) {
- GetClientRect(hwnd, &rct);
- } else if (message == WM_LBUTTONDOWN) {
- int x = LOWORD(lparam);
- int y = HIWORD(lparam);
- onMouseDown(x, y);
- } else if (message == WM_CREATE) {
- HMENU hMenuBar = CreateMenu();
- hFile = CreateMenu();
- hInf = CreateMenu();
- AppendMenuA(hMenuBar, MF_POPUP, (UINT_PTR) hFile, "Меню");
- AppendMenuA(hMenuBar, MF_POPUP, (UINT_PTR) hInf, "Информация");
- AppendMenuA(hFile, MF_STRING, AGAINST_AI, "Новая игра с компьютером");
- AppendMenuA(hFile, MF_STRING, AGAINST_HUMAN, "Новая игра с человеком");
- AppendMenuA(hFile, MF_STRING, CHANGE_SIDE, "Сменить сторону");
- AppendMenuA(hFile, MF_SEPARATOR, NULL, NULL);
- AppendMenuA(hFile, MF_STRING, CLEAR_STATS, "Сбросить статистику");
- AppendMenuA(hFile, MF_SEPARATOR, NULL, NULL);
- AppendMenuA(hFile, MF_STRING, CLOSE_GAME, "Выход");
- AppendMenuA(hInf, MF_STRING, ABOUT, "О программе");
- AppendMenuA(hInf, MF_STRING, STATS, "Статистика");
- SetMenu(hwnd, hMenuBar);
- } else if (message == WM_COMMAND) {
- int wmId = LOWORD(wparam);
- switch (wmId) {
- case AGAINST_AI:
- confirmation("Вы уверены, что хотите начать новую игру с компьютером?", newGameWithAi);
- break;
- case AGAINST_HUMAN:
- confirmation("Вы уверены, что хотите начать новую игру с человеком?", newGameWithHuman);
- break;
- case CHANGE_SIDE:
- confirmation("Вы уверены, что хотите сменить сторону?", changeSide);
- break;
- case CLEAR_STATS:
- confirmation("Вы уверены, что хотите сбросить статистику?", clearStats);
- break;
- case CLOSE_GAME:
- confirmation("Вы уверены, что хотите выйти?", closeGame);
- case STATS:
- showStats();
- break;
- case ABOUT:
- about();
- break;
- }
- } else if (message == WM_PAINT) {
- if (gameStarted) {
- HDC dc;
- PAINTSTRUCT ps;
- RECT rc;
- dc = BeginPaint(hwnd, &ps);
- GetClientRect(hwnd, &rc);
- HDC mdc = CreateCompatibleDC(dc);
- HBITMAP mbm = CreateCompatibleBitmap(dc, rct.right - rct.left, rct.bottom - rct.top);
- SelectObject(mdc, mbm);
- drawBorder(mdc);
- drawCells(mdc, cells);
- placeFigures(mdc, cells);
- if (lastChosenCell != NULL) {
- getAllWays(lastChosenCell, humanTurn);
- highlightCell(mdc, lastChosenCell);
- showWays(mdc, lastChosenCell);
- }
- BitBlt(dc, 25, 25, 602, 602, mdc, 0, 0, SRCCOPY);
- ReleaseDC(hwnd, mdc);
- DeleteObject(mbm);
- EndPaint(hwnd, &ps);
- SelectObject(memDC, memBM);
- }
- } else
- return DefWindowProcA(hwnd, message, wparam, lparam);
- }
- void loadWindowIcon(HWND hwnd) {
- HICON icon = LoadImage(NULL, "images/icon.ico", IMAGE_ICON, 48, 48, LR_LOADFROMFILE);
- if (icon != NULL) SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) icon);
- }
- int main() {
- WNDCLASSA wcl;
- memset(&wcl, 0, sizeof(WNDCLASSA));
- wcl.lpszClassName = "my Window";
- wcl.lpfnWndProc = WndProc;
- wcl.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
- RegisterClassA(&wcl);
- int screenWidth = GetSystemMetrics(SM_CXSCREEN);
- int screenHeight = GetSystemMetrics(SM_CYSCREEN);
- int formWidth = 665;
- int formHeight = 700;
- hwnd = CreateWindow("my Window", "Шашки", WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX,
- (screenWidth - formWidth) / 2, (screenHeight - formHeight) / 2, formWidth, formHeight, NULL,
- NULL, NULL, NULL);
- dc = GetDC(hwnd);
- loadWindowIcon(hwnd);
- ShowWindow(hwnd, SW_SHOWNORMAL);
- srand(time(NULL));
- newGame(dc, HUMAN);
- InitCommonControls();
- MSG msg;
- while (GetMessage(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement