C语言实现五子棋
基本思路
1.五子棋需要棋盘并能够记录玩家落子情况,可以使用二维数来保存数据。
2.采用双人对战模式。
3.五子棋实现的主要难度是判断是否构成五子连珠,采用以下方法:
在某一点落子时,判断以该坐标为中心的八个方向,有无与所落子颜色相同的棋子,如果有则统计相同棋子数目,将相对方向的数目相加构成一组,如果哪一组有五或以上相同的棋子,这个方向就构成了五子连珠。
代码实现
多文件形式,整个程序包括一个头文件game.h,两个源文件game.c和main.c
1.game.h——宏定义和头文件包含以及函数声明等
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<windows.h>
void Game();//函数声明
#define ROW 21//棋盘大小
#define COL 21
#define PLAYER1 1
#define PLAYER2 2
#define NEXT 3
#define DRAW 4
//八个不同的方向
#define UP 10
#define RITHT_UP 11
#define RIGHT 12
#define RIGHT_DOWN 13
#define DOWN 14
#define LEFT_DOWN 15
#define LEFT 16
#define LEFT_UP 17
2.main.c——程序入口,游戏主菜单,对Game函数调用
#include"game.h"
void Menu()
{
printf("+----------------------------------+\n");
printf("+ 1.Play 2.Exit +\n");
printf("+----------------------------------+\n");
}
int main()
{
int select = 0;
int quit = 0;
//游戏为死循环模式,不选择退出则一直进行
while (!quit){
Menu();
printf("Please select:\n");
scanf("%d", &select);
switch (select)
{
case 1:
Game();
break;
case 2:
quit = 1;
break;
default:
printf("Enter error!\n");
break;
}
}
printf("Bye-bye!\n");
system("pause");
return 0;
}
3.game.c——Game函数实现
#include"game.h"
//定义两个全局变量存放落子坐标,这样做的好处是不用将\
坐标作为参数传入各个函数
int x = 0;
int y = 0;
static void ShowBoard(int ar[][COL], int row,int col)
{
system("cls");
printf(" ");
for (int i = 0; i < col; i++)
{
printf("%2d ",i);
}
printf("\n");
for (int i = 0; i < row; i++)
{
printf("%-2d", i);
for (int j = 0; j < col; j++)
{
//遍历数组,打印棋盘对应内容
if (ar[i][j] == 0){
printf(" .");
}
else if (ar[i][j] == PLAYER1){
printf(" O");
}
else if (ar[i][j] == PLAYER2){
printf(" X");
}
else{
printf("Bug");
}
}
printf("\n");
}
}
static void PlayerMove(int ar[][COL], int row, int col,int who)
{
while (1){
printf("Please enter your position Player %d<x,y>\n",who);
scanf("%d %d", &x, &y);
//判断坐标合法性
if (x<0 || x>row - 1 || y<0 || y>row - 1){
printf("Ener error!\n");
continue;
}
if (ar[x][y] == 0){
ar[x][y] = who;
break;//输入正确的坐标才能跳出循环
}
else{
printf("This position is not empty.\n");
continue;
}
}
}
static int ChessCount(int ar[][COL],int direction)
{
int count = 0;
//避免影响落子坐标x和y的值,定义两个新的变量存放
int x_ = x;
int y_ = y;
//#define UP 10
//#define RITHT_UP 11
//#define RIGHT 12
//#define RIGHT_DOWN 13
//#define DOWN 14
//#define LEFT_DOWN 15
//#define LEFT 16
//#define LEFT_UP 17
//状态机(while死循环+switch case)
while (1){
switch (direction){
case UP:
x_--;
break;
case RITHT_UP:
x_--, y_++;
break;
case RIGHT:
y_++;
break;
case RIGHT_DOWN:
x_++, y_++;
break;
case DOWN:
x_++;
break;
case LEFT_DOWN:
x_++, y_--;
break;
case LEFT:
y_--;
break;
case LEFT_UP:
x_--, y_--;
break;
default:
//BUG
break;
}
//先判断坐标合法性
if (x_<0 || x_>ROW - 1 || y_<0 || y_>COL - 1){
break;
}
//周边棋子相同时,count+1,再循环\
直到棋子不相同或者到边界位置
if (ar[x_][y_] == ar[x][y]){
count++;
}
else{
break;
}
}
return count;
}
static int Judge(int ar[][COL],int row,int col)
{
int count = 0;//相同棋子的个数
//纵向相同棋子个数
count = ChessCount(ar, UP) + ChessCount(ar, DOWN)+1;
if (count >= 5){
return ar[x][y];
}
//横向相同棋子个数
count = ChessCount(ar, LEFT) + ChessCount(ar, RIGHT)+1;
if (count >= 5){
return ar[x][y];
}
//左上到右下方向
count = ChessCount(ar, LEFT_UP) + ChessCount(ar, RIGHT_DOWN)+1;
if (count >= 5){
return ar[x][y];
}
//左下到右上方向
count = ChessCount(ar, RITHT_UP) + ChessCount(ar, LEFT_DOWN)+1;
if (count >= 5){
return ar[x][y];
}
//程序执行到这里,则说明没有五子连珠,只有平局或者继续两种情况
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (ar[i][j] != 0){
return NEXT;
}
}
}
return DRAW;
}
void Game()
{
int board[ROW][COL] = { 0 };//定义二维数组存放落子信息
int ret = 0;//存放Judge函数返回之前
while (1){
ShowBoard(board, ROW, COL);//展示棋盘
PlayerMove(board, ROW, COL,PLAYER1);//玩家落子
ret = Judge(board,ROW,COL);//判断结果
if (ret != NEXT){
//判断结果不不为NEXT则跳出循环
break;
}
ShowBoard(board, ROW, COL);
PlayerMove(board, ROW, COL,PLAYER2);
ret = Judge(board,ROW,COL);
if (ret != NEXT){
break;
}
}
//游戏结果
switch (ret){
case PLAYER1:
printf("Player1 win!\n");
break;
case PLAYER2:
printf("Player2 win!\n");
break;
case DRAW:
printf("Draw!\n");
break;
default:
printf("Bug!\n");
break;
}
}