633 lines
15 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//五子棋应用
#include "stdlib.h"
#include "sys.h"
#include "systick.h"
#include "key.h"
#include "lcd.h"
#include "hc12.h"
#include "GameEngine.h"
#include "APP_Gobang.h"
/**************************************** 私有定义 ****************************************/
#define MAP_COLOR 0xdc84
#define BROADWIDTH 15
#define WIDTH (BROADWIDTH + 1)
#define BLACK_TURN 0
#define WHITE_TURN 1
#define NO_CHESS 0
#define BLACK_CHESS 1
#define WHITE_CHESS 2
#define CHECK_X 0
#define CHECK_Y 1
#define CHECK_DIAG_LEFT 2
#define CHECK_DIAG_RIGHT 3
#define CHESS_RADIUS 5
#define CONNETING_STATUS 0
#define BATTLING_STATUS 1
#define NONE_MSG 0
#define REQUEST_MSG 'R'
#define AGREE_MSG 'A'
#define REFUSE_MSG 'N'
#define CONFIRM_MSG 'X'
#define START_BYTE '#'
#define END_BYTE '&'
#define Random() rand()
/*****************************************************************************************/
/**************************************** 全局变量 ****************************************/
//棋盘交点阵
int map[WIDTH][WIDTH] = {{0, 0}};
//光标位置
int cursor_x = 7;
int cursor_y = 7;
//记录执子方
int turn = BLACK_TURN;
//棋子类型
int chess_kind = BLACK_CHESS;
//我方执子类型
int my_turn = BLACK_TURN;
//当前所处状态
int status = CONNETING_STATUS;
//联机消息
uint8_t connetion_msg = NONE_MSG;
uint8_t interval = 240 / WIDTH;
uint16_t x_start, x_end, y_start, y_end;
/*****************************************************************************************/
/**************************************** 私有函数 ****************************************/
void APP_Gobang_Init(void);
void APP_Gobang_DispGobang(void);
void APP_Gobang_DispText(void);
void APP_Gobang_DispMap(void);
void APP_Gobang_DispChess(void);
void APP_Gobang_MoveChess(void);
void APP_Gobang_DispCursor(void);
int APP_Gobang_CheckNum(int check_type);
void APP_Gobang_Msg(uint8_t *head, uint8_t *content);
void APP_Gobang_SendPosition(void);
void APP_Gobang_RevPosition(void);
uint8_t APP_Gobang_Connect(void);
uint8_t APP_Gobang_InitiateConnet(void);
uint8_t APP_Gobang_ReplyConnect(void);
void APP_Gobang_DecideMyTurn(void);
void APP_Gobang_RevMyTurn(void);
void APP_Gobang_ConfirmBeforeStart(void);
void APP_Gobang_ConnectRevHandler(uint8_t byte);
/*****************************************************************************************/
/**
* @brief 启动五子棋
*/
void APP_Gobang_Launcher(void)
{
srand(SysTick->VAL);
APP_Gobang_Init();
APP_Gobang_DispGobang();
if (APP_Gobang_Connect() == 0)
return;
status = BATTLING_STATUS;
HC12_BindReceiveHandle(NULL);
HC12_ClearReceive;
KEY_ClearKey();
while (1)
{
APP_Gobang_DispGobang();
if (turn == my_turn)
APP_Gobang_MoveChess();
else
APP_Gobang_RevPosition();
turn = !turn; //更换执子方
//判断胜负
if (
APP_Gobang_CheckNum(CHECK_X) >= 5 ||
APP_Gobang_CheckNum(CHECK_Y) >= 5 ||
APP_Gobang_CheckNum(CHECK_DIAG_LEFT) >= 5 ||
APP_Gobang_CheckNum(CHECK_DIAG_RIGHT) >= 5)
{
if ((chess_kind == BLACK_CHESS && my_turn == BLACK_TURN) || (chess_kind == WHITE_CHESS && my_turn == WHITE_TURN))
APP_Gobang_Msg("游戏结束", "恭喜您获得胜利按“L”退出游戏");
else
APP_Gobang_Msg("游戏结束", "很遗憾您输了按“L”退出游戏");
return;
}
}
}
/**
* @brief 初始化变量
*/
void APP_Gobang_Init(void)
{
ge_font_print_set.font_size = FONT_16;
for (int i = 0; i < WIDTH; i++)
for (int j = 0; j < WIDTH; j++)
map[i][j] = NO_CHESS;
cursor_x = cursor_y = 7;
turn = BLACK_TURN;
chess_kind = BLACK_CHESS;
status = CONNETING_STATUS;
connetion_msg = NONE_MSG;
x_start = (LCD_WIDTH - LCD_HEIGHT) / 2 + interval / 2;
x_end = x_start + (WIDTH - 1) * interval;
y_start = interval / 2;
y_end = y_start + (WIDTH - 1) * interval;
}
/**
* @brief 绘制游戏
*/
void APP_Gobang_DispGobang(void)
{
GE_Draw_ClrAll(MAP_COLOR);
APP_Gobang_DispMap();
APP_Gobang_DispChess();
APP_Gobang_DispCursor();
if (status == BATTLING_STATUS)
APP_Gobang_DispText();
GE_Draw_Disp();
}
/**
* @brief 绘制文字
* @param head: 标题
* @param content: 内容
*/
void APP_Gobang_DispText(void)
{
if (turn == my_turn)
GE_Font_Print_WithSet(LCD_WIDTH - FONT_16 * 2, interval / 2, BORDER_MAX, BORDER_MAX, "我方");
else
GE_Font_Print_WithSet(LCD_WIDTH - FONT_16 * 2, interval / 2, BORDER_MAX, BORDER_MAX, "对方");
GE_Font_Print_WithSet(LCD_WIDTH - FONT_16 * 2, interval / 2 + FONT_16, BORDER_MAX, BORDER_MAX, "回合");
GE_Font_Print_WithSet(LCD_WIDTH - FONT_16 * 2, LCD_HEIGHT - interval / 2 - 2 * FONT_16, BORDER_MAX, BORDER_MAX, "我方");
if (my_turn == BLACK_TURN)
GE_Font_Print_WithSet(LCD_WIDTH - FONT_16 * 2, LCD_HEIGHT - interval / 2 - FONT_16, BORDER_MAX, BORDER_MAX, "执黑");
else
GE_Font_Print_WithSet(LCD_WIDTH - FONT_16 * 2, LCD_HEIGHT - interval / 2 - FONT_16, BORDER_MAX, BORDER_MAX, "执白");
}
/**
* @brief 绘制棋盘
*/
void APP_Gobang_DispMap(void)
{
uint8_t i = 0;
for (i = 0; i < WIDTH; i++)
{
GE_Draw_Line(x_start, y_start + i * interval, x_end, y_start + i * interval, BLACK);
GE_Draw_Line(x_start + i * interval, y_start, x_start + i * interval, y_end, BLACK);
}
}
/**
* @brief 绘制棋子
*/
void APP_Gobang_DispChess(void)
{
uint8_t i, j;
for (i = 0; i < WIDTH; i++)
{
for (j = 0; j < WIDTH; j++)
{
if (map[i][j] == BLACK_CHESS)
{
GE_Draw_FillCircle(x_start + j * interval, y_start + i * interval, CHESS_RADIUS, BLACK);
}
else if (map[i][j] == WHITE_CHESS)
{
GE_Draw_FillCircle(x_start + j * interval, y_start + i * interval, CHESS_RADIUS, WHITE);
}
}
}
}
/**
* @brief 移动棋子
*/
void APP_Gobang_MoveChess(void)
{
KEY_ClearKey();
while (1)
{
switch (KEY_GetKeyWait())
{
case JOY_U_DOWN:
{
cursor_x--;
if (cursor_x < 0)
cursor_x = WIDTH - 1;
APP_Gobang_DispGobang();
}
break;
case JOY_D_DOWN:
{
cursor_x++;
if (cursor_x > WIDTH - 1)
cursor_x = 0;
APP_Gobang_DispGobang();
}
break;
case JOY_L_DOWN:
{
cursor_y--;
if (cursor_y < 0)
cursor_y = WIDTH - 1;
APP_Gobang_DispGobang();
}
break;
case JOY_R_DOWN:
{
cursor_y++;
if (cursor_y > WIDTH - 1)
cursor_y = 0;
APP_Gobang_DispGobang();
}
break;
case JOY_OK_DOWN:
{
if (map[cursor_x][cursor_y] != NO_CHESS)
break;
chess_kind = map[cursor_x][cursor_y] = turn == BLACK_TURN ? BLACK_CHESS : WHITE_CHESS;
APP_Gobang_SendPosition();
APP_Gobang_DispGobang();
return;
}
}
}
}
/**
* @brief 显示光标
*/
void APP_Gobang_DispCursor(void)
{
GE_Draw_Circle(x_start + cursor_y * interval, y_start + cursor_x * interval, CHESS_RADIUS, RED);
}
/**
* @brief 检查某个方向上的连子数
* @param check_type: 检查方向
* @retval 连子数
*/
int APP_Gobang_CheckNum(int check_type)
{
int temp_x = cursor_x, temp_y = cursor_y;
int num = 0;
while (temp_x >= 0 && temp_x < WIDTH && temp_y >= 0 && temp_y < WIDTH && map[temp_x][temp_y] == chess_kind)
{
num++;
switch (check_type)
{
case CHECK_X:
temp_x--;
break;
case CHECK_Y:
temp_y--;
break;
case CHECK_DIAG_LEFT:
temp_x--;
temp_y--;
break;
case CHECK_DIAG_RIGHT:
temp_x--;
temp_y++;
}
}
switch (check_type)
{
case CHECK_X:
temp_x = cursor_x + 1;
break;
case CHECK_Y:
temp_y = cursor_y + 1;
;
break;
case CHECK_DIAG_LEFT:
temp_x = cursor_x + 1;
temp_y = cursor_y + 1;
break;
case CHECK_DIAG_RIGHT:
temp_x = cursor_x + 1;
temp_y = cursor_y - 1;
}
while (temp_x >= 0 && temp_x < WIDTH && temp_y >= 0 && temp_y < WIDTH && map[temp_x][temp_y] == chess_kind)
{
num++;
switch (check_type)
{
case CHECK_X:
temp_x++;
break;
case CHECK_Y:
temp_y++;
break;
case CHECK_DIAG_LEFT:
temp_x++;
temp_y++;
break;
case CHECK_DIAG_RIGHT:
temp_x++;
temp_y--;
}
}
return num;
}
/**
* @brief 消息框,任意键按下后退出
* @param head: 标题
* @param content: 内容
*/
void APP_Gobang_Msg(uint8_t *head, uint8_t *content)
{
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, head, content, NULL);
KEY_WaitKey(JOY_L);
}
void APP_Gobang_SendPosition(void)
{
uint8_t position[6];
position[0] = START_BYTE;
position[1] = '0' + cursor_x / 10;
position[2] = '0' + cursor_x % 10;
position[3] = '0' + cursor_y / 10;
position[4] = '0' + cursor_y % 10;
position[5] = END_BYTE;
HC12_SendBuff(position, 6);
}
void APP_Gobang_RevPosition(void)
{
uint8_t byte;
uint8_t position[5];
while (1)
{
if (HC12_Receive(&byte) == 1)
{
if (byte == START_BYTE)
{
HC12_ReceiveBuffUntil(position, END_BYTE, 500);
cursor_x = (position[0] - '0') * 10 + position[1] - '0';
cursor_y = (position[2] - '0') * 10 + position[3] - '0';
if (map[cursor_x][cursor_y] == NO_CHESS)
{
chess_kind = map[cursor_x][cursor_y] = turn == BLACK_TURN ? BLACK_CHESS : WHITE_CHESS;
APP_Gobang_DispGobang();
break;
}
}
}
}
}
uint8_t APP_Gobang_Connect(void)
{
HC12_BindReceiveHandle(APP_Gobang_ConnectRevHandler);
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, "当前未联机", "按“OK”以发起联机", NULL);
while (1)
{
switch (KEY_GetKey())
{
case JOY_OK_DOWN:
{
if (APP_Gobang_InitiateConnet())
{
uint8_t *head = (my_turn == BLACK_TURN ? "本局我方执黑" : "本局我方执白");
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, head, "按“OK”开始游戏", NULL);
Delay_ms(500);
KEY_WaitKey(JOY_OK);
APP_Gobang_ConfirmBeforeStart();
return 1;
}
else
{
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, "当前未联机", "按“OK”以发起联机", NULL);
}
}
break;
case JOY_L_DOWN:
{
return 0;
}
break;
}
if (connetion_msg == REQUEST_MSG)
{
if (APP_Gobang_ReplyConnect())
{
uint8_t *head = (my_turn == BLACK_TURN ? "本局我方执黑" : "本局我方执白");
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, head, "按“OK”开始游戏", NULL);
Delay_ms(500);
KEY_WaitKey(JOY_OK);
APP_Gobang_ConfirmBeforeStart();
return 1;
}
else
{
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, "当前未联机", "按“OK”以发起联机", NULL);
}
}
}
}
uint8_t APP_Gobang_InitiateConnet(void)
{
int32_t start_time = SysTick_GetRunTime();
uint8_t msg[] = {START_BYTE, REQUEST_MSG};
HC12_SendBuff(msg, 2);
HC12_ClearReceive;
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, "当前未联机", "请求已发送,等待对方响应...", NULL);
while (1)
{
if (SysTick_CheckRunTime(start_time) > 10000)
{
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, "联机失败", "对方无响应,按“OK”退出", NULL);
KEY_WaitKey(JOY_OK);
connetion_msg = NONE_MSG;
return 0;
}
if (connetion_msg == AGREE_MSG)
{
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, "联机成功", "按“OK”进入游戏", NULL);
KEY_WaitKey(JOY_OK);
return 1;
}
else if (connetion_msg == REFUSE_MSG)
{
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, "联机失败", "对方拒绝联机,按“OK”退出", NULL);
KEY_WaitKey(JOY_OK);
connetion_msg = NONE_MSG;
return 0;
}
}
}
uint8_t APP_Gobang_ReplyConnect(void)
{
uint8_t content[2][GE_GUI_MENUBOX_CONTENT_LEN] = {"", ""};
GE_Draw_Fill(60, 75, 200, 90, WHITE);
switch (GE_GUI_MenuBox(60, 75, 200, 90, "对方请求联机,是否接受?", 2, content, NULL))
{
case 0:
connetion_msg = NONE_MSG;
return 0;
break;
case 1:
{
uint8_t msg[] = {START_BYTE, AGREE_MSG};
HC12_SendBuff(msg, 2);
APP_Gobang_DecideMyTurn();
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, "联机成功", "按“OK”进入游戏", NULL);
KEY_WaitKey(JOY_OK);
connetion_msg = NONE_MSG;
return 1;
}
break;
case 2:
{
uint8_t msg[] = {START_BYTE, REFUSE_MSG};
HC12_SendBuff(msg, 2);
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, "联机失败", "已拒绝联机,按“OK”退出", NULL);
KEY_WaitKey(JOY_OK);
connetion_msg = NONE_MSG;
return 0;
}
break;
}
}
void APP_Gobang_DecideMyTurn(void)
{
my_turn = Random() % 2;
uint8_t msg[] = {START_BYTE, !my_turn};
HC12_SendBuff(msg, 2);
}
void APP_Gobang_ConfirmBeforeStart(void)
{
if (my_turn == BLACK_TURN)
{
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, "游戏即将开始", "正在确认白色方设备状态...", NULL);
while (connetion_msg != CONFIRM_MSG)
{
Delay_ms(100);
}
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, "准备就绪", "按“OK”开始游戏", NULL);
Delay_ms(500);
KEY_WaitKey(JOY_OK);
}
else
{
uint8_t msg[] = {START_BYTE, CONFIRM_MSG};
HC12_SendBuff(msg, 2);
}
}
void APP_Gobang_ConnectRevHandler(uint8_t byte)
{
static uint8_t is_receiving = FALSE;
if (is_receiving == FALSE && byte == START_BYTE)
{
is_receiving = TRUE;
return;
}
if (is_receiving == TRUE)
{
if (byte == REQUEST_MSG || byte == AGREE_MSG || byte == REFUSE_MSG || byte == CONFIRM_MSG)
{
connetion_msg = byte;
is_receiving = FALSE;
}
else if (byte == BLACK_TURN || byte == WHITE_TURN)
{
my_turn = byte;
is_receiving = FALSE;
}
}
}