//
// Created by WAHAHA
//
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
char BoardRecord[4][4];
char drawPieceCoord[9][2] = {
{1, 0},
{5, 0},
{9, 0},
{1, 2},
{5, 2},
{9, 2},
{1, 4},
{5, 4},
{9, 4},
};
int check[8][3][2] = {
{{1, 1}, {2, 2}, {3, 3}},
{{1, 3}, {2, 2}, {3, 1}},
{{1, 1}, {1, 2}, {1, 3}},
{{2, 1}, {2, 2}, {2, 3}},
{{3, 1}, {3, 2}, {3, 3}},
{{1, 1}, {2, 1}, {3, 1}},
{{1, 2}, {2, 2}, {3, 2}},
{{1, 3}, {2, 3}, {3, 3}},
};
//menu
void menu();
void initmenu();
void wrongInput();
//game begin
void start();
void printBoard();
void computerPlay(char);
int select_mode();
void userPlay(char);
int checkGameover(char);
void gameover(int, int);
//system
void gotoxy(int, int);
//menu
void menu() {
char c;
initmenu();
while (1) {
gotoxy(37, 8);//定位到输入栏
c = _getch();//vs2022要求将getch()更换为_getch()---标准c编译器换回getch()(?)
if (c == '1') {
start();
system("cls");
initmenu();
} else if (c == '2') {
break;
} else wrongInput();
}
}
void initmenu() {
gotoxy(28, 0);
printf("三子棋\n");
const char *select[8] = {
" _______________________________________________\n",
" | |\n",
" | 请输入编号: |\n",
" | 1.开始游戏 2.退出游戏 |\n",
" | |\n",
" | |\n",
" -----------------------------------------------\n",
" 请输入编号[1/2]:[ ]"
};
for (int i = 0; i < 8; ++i) {//打印菜单
printf("%s", select[i]);
}
}
void wrongInput() {
gotoxy(39, 8);
printf("输入错误!");
Sleep(1000);
gotoxy(39, 8);
printf(" ");
return;
}
//game bigin
void start() {
memset(BoardRecord, '0', sizeof(BoardRecord));
srand((unsigned int) time(NULL));
int flag, mode, hand = rand() % 2;
mode = select_mode();
system("cls");
printBoard();
if (mode == 1) {//先后手的分配要考虑人机对战
if (hand == 0) {
printf("\n这局你为先手!\n");
} else {
printf("\n这局你为后手!\n");
computerPlay('x');
}
} else {
if (hand == 0) {
printf("\n这局玩家'o'为先手!\n");
} else {
printf("\n这局玩家'x'为先手!\n");
userPlay('x');
}
}
while (1) {
if (mode == 1) {//人机对战
userPlay('o');
if ((flag = checkGameover('x')) != 0) {
gameover(flag, mode);
return;
}
computerPlay('x');
if ((flag = checkGameover('o')) != 0) {
gameover(flag, mode);
return;
}
} else {//双人对战
userPlay('o');
if ((flag = checkGameover('x')) != 0) {
gameover(flag, mode);
return;
}
userPlay('x');
if ((flag = checkGameover('o')) != 0) {
gameover(flag, mode);
return;
}
}
}
}
void printBoard() {
const char *board[5] = {
" | | \n",
"---+---+---\n",
" | | \n",
"---+---+---\n",
" | | "
};
gotoxy(0, 0);
for (int i = 0; i < 5; ++i) {
printf("%s", board[i]);
}
}
int checkGameover(char next_player) {//0为继续,1为(玩家o)(电脑或玩家2)赢,2为(玩家x)赢,3为平局
//为了实现提前预测胜负,每次落子判断胜负的函数传入下一个玩家的身份(字符)
int num = 0, *a, *b, *c;
//先判断玩家o赢---每次玩家o先下棋(?)---在人机对战时
for (int i = 0; i < 8; ++i) {
a = check[i][0];
b = check[i][1];
c = check[i][2];
if (BoardRecord[a[0]][a[1]] == 'o' &&
BoardRecord[b[0]][b[1]] == 'o' &&
BoardRecord[c[0]][c[1]] == 'o') {
return 2;
} else if (BoardRecord[a[0]][a[1]] == 'x' &&
BoardRecord[b[0]][b[1]] == 'x' &&
BoardRecord[c[0]][c[1]] == 'x') {
return 1;
}
}
if (next_player == '#') //递归出口
return 3;
int last_i, last_j;
for (int i = 1; i <= 3; ++i)
for (int j = 1; j <= 3; ++j)
if (BoardRecord[i][j] == '0') {
last_i = i;
last_j = j;
++num;
}
if (num == 1) {
BoardRecord[last_i][last_j] = next_player;
if (checkGameover('#') == 3)//此处以'#'作为递归出口
return 3;
BoardRecord[last_i][last_j] = '0';
}
return 0;
}
void gameover(int flag, int mode) {
const char *gameoverTips_mode1[4] = {
"\0",
"You lose!",
"You win!",
"Draw!"
};
const char *gameoverTips_mode2[4] = {//认为玩家o为优先
"\0",
"玩家'x' win!",
"玩家'o' win!",
"Draw!"
};
gotoxy(0, 7);
if (mode == 1)
printf("%s\n", gameoverTips_mode1[flag]);
else
printf("%s\n", gameoverTips_mode2[flag]);
printf("按空格键确认:[ ]");
gotoxy(14, 8);
char c;
while ((c = _getch()) != ' ');
}
void computerPlay(char c) {
srand((unsigned int) time(NULL));
int x, y;
x = (rand() % 3) + 1;
y = (rand() % 3) + 1;
while (BoardRecord[x][y] != '0') {
x = (rand() % 3) + 1;
y = (rand() % 3) + 1;
}
BoardRecord[x][y] = c;
gotoxy(drawPieceCoord[3 * (x - 1) + y - 1][0], drawPieceCoord[3 * (x - 1) + y - 1][1]);
putchar(c);
return;
}
void userPlay(char c) {
int x, y;
gotoxy(12, 2);
printf("轮到玩家'%c'落子", c);
while (1) {
gotoxy(0, 6);
printf("请输入你要落子的坐标(例如:左上为1 1;左下为3 1):");
scanf("%d%d", &x, &y);
while (getchar() != '\n');
if (x >= 1 && x <= 3 && y >= 1 && y <= 3 && BoardRecord[x][y] == '0') {
BoardRecord[x][y] = c;
gotoxy(47, 6);
printf(" ");
break;
} else {
printf("error!");
gotoxy(47, 6);
printf(" ");
Sleep(1000);
gotoxy(0, 7);
printf(" ");
}
}
gotoxy(drawPieceCoord[3 * (x - 1) + y - 1][0], drawPieceCoord[3 * (x - 1) + y - 1][1]);
putchar(c);
return;
}
int select_mode() {
system("cls");
gotoxy(28, 0);
printf("选择模式\n");
const char *select[8] = {
" _______________________________________________\n",
" | |\n",
" | 请输入编号: |\n",
" | 1.人机对战 2.双人对战 |\n",
" | |\n",
" | |\n",
" -----------------------------------------------\n",
" 请输入编号[1/2]:[ ]"
};
for (int i = 0; i < 8; ++i) {//打印菜单
printf("%s", select[i]);
}
char c;
while (1) {
gotoxy(37, 8);//定位到输入栏
c = _getch();//vs2022要求将getch()更换为_getch()---标准c编译器换回getch()(?)
if (c == '1') {
return 1;
} else if (c == '2') {
return 2;
} else wrongInput();
}
}
//system
void gotoxy(int x, int y) {
COORD c;
static HANDLE h;
h = GetStdHandle(STD_OUTPUT_HANDLE);
c.X = x;
c.Y = y;
SetConsoleCursorPosition(h, c);
}
int main() {
menu();
return 0;
}