Proteus 8.1 51单片机仿真双人对战五子棋

2019-04-15 19:27发布

硬件需求: 内存需求较大,51单片机无法满足,因此需要扩展内存 Proteus需添加240X320的彩 {MOD}液晶
实现功能如下: 1、通过按键选择下棋位置 2、无限悔棋 3、重新开始
黑白双方循环落子,黑方先下,通过上下左右四个按键选择落子位置,按下确定按键即可将棋子放置在棋盘上。当有一方连成5子或棋盘落满棋子,游戏结束,判定双方胜负。按下悔棋按键可以悔棋,每按一次可以悔棋一步,可以无限悔棋,按下重新开始按键,游戏重新开始。
仿真效果图如下:
仿真电路图
开机初始化界面
黑棋获胜界面


源码如下:
#include "game.h" #include "malloc.h" #include "74HC165.h" //定义棋盘起始坐标 #define CHESSBOARD_START_X 47 #define CHESSBOARD_START_Y 7 #define CHESSBOARD_END_X 272 #define CHESSBOARD_END_Y 232 //棋盘大小 #define CHESSBOARD_SIZE (CHESSBOARD_END_X-CHESSBOARD_START_X) //网格大小 #define CHESSGRID_SIZE (CHESSBOARD_SIZE / 15) //棋盘颜 {MOD} #define CHESSBOARD_COLOR BROWN char (*g_Chess)[15]; //存放棋子缓存 int g_ChessNum; //棋子数量 int g_SameChessNum; //相连的相同的棋子数 //绘制棋盘 //15x15 static void DrawChessBoard(void) { int i; //填充棋盘背景 {MOD} LcdFill(CHESSBOARD_START_X-7, CHESSBOARD_START_Y-7, CHESSBOARD_END_X+7, CHESSBOARD_END_Y+7, CHESSBOARD_COLOR); LcdSetColor(BLACK); //绘制边框线 LcdDrawRect(CHESSBOARD_START_X-3, CHESSBOARD_START_Y-3, CHESSBOARD_END_X+3, CHESSBOARD_END_Y+3); LcdDrawRect(CHESSBOARD_START_X-4, CHESSBOARD_START_Y-4, CHESSBOARD_END_X+4, CHESSBOARD_END_Y+4); LcdDrawRect(CHESSBOARD_START_X, CHESSBOARD_START_Y, CHESSBOARD_END_X, CHESSBOARD_END_Y); //绘制垂直线 for (i = 1; i < 15; i++) { LcdDrawLine(CHESSBOARD_START_X, CHESSBOARD_START_Y + (CHESSGRID_SIZE*i), CHESSBOARD_END_X, CHESSBOARD_START_Y + (CHESSGRID_SIZE*i), BLACK); } //绘制水平线 for (i = 1; i < 15; i++) { LcdDrawLine(CHESSBOARD_START_X + (CHESSGRID_SIZE*i), CHESSBOARD_START_Y, CHESSBOARD_START_X + (CHESSGRID_SIZE*i), CHESSBOARD_END_Y, BLACK); } } //绘制棋子 //x,y:棋子坐标(0~14) static void DrawChess(uint8 x, uint8 y) { uint16 ChessColor; uint16 xChess; uint16 yChess; if (x>14 || x<0 || y>14 || y<0)return; //超范围了 if (g_Chess[x][y]!=0)return; //已有棋子 //判断棋子颜 {MOD} (g_ChessNum%2==0) ? (ChessColor=BLACK) : (ChessColor=WHITE); //计算棋子坐标 xChess = CHESSBOARD_START_X+(CHESSGRID_SIZE/2) + (x*CHESSGRID_SIZE); yChess = CHESSBOARD_START_Y+(CHESSGRID_SIZE/2) + (y*CHESSGRID_SIZE); LcdDrawCircleA(xChess, yChess, CHESSGRID_SIZE/2-1, ChessColor, 1); g_ChessNum++; g_Chess[x][y] = g_ChessNum; } //清除棋子 //x,y:棋子坐标(0~14) static void ClearChess(uint8 x, uint8 y) { uint16 ChessColor; uint16 xChess; uint16 yChess; if (x>14 || x<0 || y>14 || y<0)return; //超范围了 if (g_Chess[x][y]!=0)return; //已有棋子 ChessColor = CHESSBOARD_COLOR; //计算棋子坐标 xChess = CHESSBOARD_START_X+(CHESSGRID_SIZE/2) + (x*CHESSGRID_SIZE); yChess = CHESSBOARD_START_Y+(CHESSGRID_SIZE/2) + (y*CHESSGRID_SIZE); LcdDrawCircleA(xChess, yChess, CHESSGRID_SIZE/2-1, ChessColor, 1); } //绘制选择框 //x,y:选择框的坐标(0~14) static void DrawSelectBox(uint8 x, uint8 y) { uint16 xChess,yChess; //计算选择框的坐标 xChess = CHESSBOARD_START_X + (x*CHESSGRID_SIZE); yChess = CHESSBOARD_START_Y + (y*CHESSGRID_SIZE); LcdSetColor(YELLOW); LcdDrawRect(xChess, yChess, xChess+CHESSGRID_SIZE, yChess+CHESSGRID_SIZE); } //清除选择框 //x,y:选择框的坐标(0~14) static void ClearSelectBox(uint8 x, uint8 y) { uint16 xChess,yChess; //计算选择框的坐标 xChess = CHESSBOARD_START_X + (x*CHESSGRID_SIZE); yChess = CHESSBOARD_START_Y + (y*CHESSGRID_SIZE); LcdSetColor(BLACK); LcdDrawRect(xChess, yChess, xChess+CHESSGRID_SIZE, yChess+CHESSGRID_SIZE); } //获取相同棋子数 //x,y:棋子坐标(0~14) //xStep,yStep:x,y坐标移动步数 static int GetChessNum(char ChessType, int x, int y, int xStep, int yStep) { g_SameChessNum = 0; while (1) { x = x + xStep; y = y + yStep; //判断是否越界 if (x < 0 || x > 14 || y < 0 || y > 14) { return g_SameChessNum; } //没有棋子 if (g_Chess[x][y]==0) { return g_SameChessNum; } //相同的棋子 if (g_Chess[x][y] % 2 == ChessType) { if ((xStep == 1 && yStep == 0) || (xStep == -1 && yStep == 0)) { g_SameChessNum++; } else if ((xStep == 0 && yStep == 1) || (xStep == 0 && yStep == -1)) { g_SameChessNum++; } else if ((xStep == 1 && yStep == 1) || (xStep == -1 && yStep == -1)) { g_SameChessNum++; } else if ((xStep == 1 && yStep == -1) || (xStep == -1 && yStep == 1)) { g_SameChessNum++; } } else { return g_SameChessNum; } } } //判断是否五子相连 //x,y:棋子坐标(0~14) static char IsFiveChessContant(int x, int y) { int ChessType = 0; int ChessNum = 0; ChessType = g_Chess[x][y] % 2; //横向判断 ChessNum = GetChessNum(ChessType, x, y, -1, 0) + GetChessNum(ChessType, x, y, 1, 0) + 1; if (ChessNum >= 5) { return 1; } //纵向判断 ChessNum = GetChessNum(ChessType, x, y, 0, 1) + GetChessNum(ChessType, x, y, 0, -1) + 1; if (ChessNum >= 5) { return 1; } //斜向判断 ChessNum = GetChessNum(ChessType, x, y, -1, 1) + GetChessNum(ChessType, x, y, 1, -1) + 1; if (ChessNum >= 5) { return 1; } //反斜向判断 ChessNum = GetChessNum(ChessType, x, y, 1, 1) + GetChessNum(ChessType, x, y, -1, -1) + 1; if (ChessNum >= 5) { return 1; } return 0; } //游戏结束 //获胜结束 //平局结束 //x,y:棋子坐标(0~14) static uint8 IsGameOver(uint8 x, uint8 y) { //五子相连 if (IsFiveChessContant(x, y)) return 2; //平局结束 if (g_ChessNum == 225) return 1; return 0; } //悔棋 static void RetractChess(void) { int x, y; int xChess, yChess; //如果没有棋子则退出 if (g_ChessNum == 0) return; //查询最后一个棋子并记录 for (x = 0; x < 15; x++) { for (y = 0; y < 15; y++) { if (g_Chess[x][y] == g_ChessNum) { xChess = x; yChess = y; break; } } } //清除最后一个棋子 g_Chess[xChess][yChess] = 0; g_ChessNum -= 1; ClearChess(xChess, yChess); } //重新开始 static void ResStart(void) { int xChess, yChess; g_ChessNum = 0; //棋子数量 //清空棋子数据 for (xChess = 0; xChess < 15; xChess++) { for (yChess = 0; yChess < 15; yChess++) { g_Chess[xChess][yChess] = 0; } } //绘制棋盘 DrawChessBoard(); //选择框位置 DrawSelectBox(7, 7); } //游戏初始化 //初始化全局变量 //初始化棋盘 void GameInit(void) { g_ChessNum = 0; //棋子数量 g_Chess = (char (*)[15])mymalloc(SRAMEX, 15); LcdClear(BLACK); //绘制棋盘 DrawChessBoard(); //选择框位置 DrawSelectBox(7, 7); } //开始游戏 void GameStart(void) { static int xChess = 7; static int yChess = 7; uint8 key; uint8 State; //读取按键值 key = HC165_Read(); switch (key) { case KEY_UP: while(HC165_Read() == KEY_UP); ClearSelectBox(xChess, yChess); yChess -= 1; if (yChess < 0) yChess = 14; DrawSelectBox(xChess, yChess); break; case KEY_LEFT: while(HC165_Read() == KEY_LEFT); ClearSelectBox(xChess, yChess); xChess -= 1; if (xChess < 0) xChess = 14; DrawSelectBox(xChess, yChess); break; case KEY_RIGHT: while(HC165_Read() == KEY_RIGHT); ClearSelectBox(xChess, yChess); xChess += 1; if (xChess >= 15) xChess = 0; DrawSelectBox(xChess, yChess); break; case KEY_DOWN: while(HC165_Read() == KEY_DOWN); ClearSelectBox(xChess, yChess); yChess += 1; if (yChess >= 15) yChess = 0; DrawSelectBox(xChess, yChess); break; case KEY_OK: //确定 while(HC165_Read() == KEY_OK); DrawChess(xChess, yChess); State = IsGameOver(xChess, yChess); while (State) { LcdSetColor(RED); switch (State) { case 1: LcdFill(60, 90, 260, 126, WHITE); LcdDispString(100, 100, 320, 16, "Game Over!", 16, 1); State = 3; break; case 2: LcdFill(60, 90, 260, 126, WHITE); if (g_Chess[xChess][yChess] % 2) { LcdDispString(80, 100, 320, 16, "Black Chess Victory!", 16, 1); } else { LcdDispString(80, 100, 320, 16, "White Chess Victory!", 16, 1); } State = 3; break; default: break; } LcdSetColor(BLACK); //重新开始游戏 if (HC165_Read() == KEY_RESTART) { while(HC165_Read() == KEY_RESTART); ResStart(); xChess = 7; yChess = 7; break; } } break; case KEY_RESTART: //重新开始 while(HC165_Read() == KEY_RESTART); ResStart(); xChess = 7; yChess = 7; break; case KEY_RETRACT: //悔棋 while(HC165_Read() == KEY_RETRACT); RetractChess(); break; default: break; } }