三子棋小游戏(万字详解)可以自定义棋盘大小(下)

简介: 三子棋小游戏(万字详解)可以自定义棋盘大小(下)

在这里面,用了while循环来实现玩家对下棋坐标的多组输入!


在该段代码,用if语句嵌套if语句,实现多组判断相互交错模式,简洁易懂!


玩家下棋,输入要下棋的坐标,将输入‘*’(字符星号)


0a2653c851af460fa595bd959398a8f1.png


下面将进行电脑下棋,电脑实现下棋,也是下在了数组里面!也不能实现坐标不合法,被占用现象....


但是电脑下棋需要进行判断,如果下一步就能赢得话,将会在哪儿下棋,如果下棋赢不了的话,那就得分析别人下棋可能会赢,如果发现别人下棋马上就要赢了,那首先就得堵别人,如果别人赢不了,我有机会赢得话,就得先自己下.............所以电脑要进行一些列的分析,然后才能进行正确的下棋!


但是要是进行如此去操作,将会将电脑设置的太复杂(阿尔法狗系列),暂时不是笔者想要的程度,笔者仅仅是想实现对电脑能够随机下棋就可以,因此就借助了时间戳:rand 和srand俩个函数,来实现对电脑上面唯一时刻保持变换的东西进行改变,从而实现电脑随机下棋的目的预判!


电脑随机下棋方法,用时间戳来将电脑在棋盘上哪里空着就在那里下棋!


下面是笔者进行电脑下棋的逻辑:


//
//电脑随机下棋
//
void computer_move(char board[ROW][COL], int row, int col)
{
  printf("电脑下棋:>\n");
  //0~32726
  //%3-->0~2
  while (1)
  {
  int x = rand() % row;
  int y = rand() % col;
  if (board[x][y] == ' ')
  {
    board[x][y] = '#';
    break;
  }
  }
}

在这里面,最为重要的就是while循环里面的代码块!


下面笔者来分析一下:


while (1)
  {
  int x = rand() % row;
  int y = rand() % col;
  if (board[x][y] == ' ')
  {
    board[x][y] = '#';
    break;
  }
  }

while(1);1为非0,判断结果即为真,一直可以进行循环,    int x = rand() % row;   int y = rand() % col;    利用时间戳进行:行列坐标的输入,所输入的值一定比行列坐标小,并且还大于等于0;利用取余运算符,实现了对坐标输入是否合法性的判断;在循环中,if语句进行了判断,如果电脑随机生成的坐标为‘  ’空格,则进行输出‘#’(井号),如果不是‘  ’空格,将会再次进行循环,随机生成坐标,然后再次if语句判断.........一直进行下去,直到输入成功!!


0a2653c851af460fa595bd959398a8f1.png


在这里我们可以看出来,玩家跟电脑都已经下棋成功!


6de278e6d6694ce5bb08e7e842b7e74b.png


一直到此,棋盘已经下满,并且玩家已经赢了,第一行全部为玩家棋子,所以.......


下面将进行预判!


规则:


每一行,每一列,或者对角线都是一样的,一方将会赢!


一共四个状态:判断输赢(玩家赢,电脑赢),平局(棋盘满),游戏继续


设一个函数,来判断棋盘的情况!然后就这样..........


玩家赢输出‘*’(星号);


电脑赢输出'#'(井号);


平局了输出‘Q’;


游戏继续输出‘C’;


因此,总的方面已经概况,至于其他详细细节请参考总代码!


//如果棋盘满了,返回1
//不满,返回0
static int is_full(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
  int j = 0;
  for (j = 0; j < col; j++)
  {
    if (' ' == board[i][j])
    {
    return 0;
    }
  }
  }
  return 1;
}
char is_win(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
  if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
  {
    return board[i][0];
  }
  }
  for (i = 0; i < col; i++)
  {
  if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
  {
    return board[0][i];
  }
  }
  if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
  {
  return board[1][1];
  }
  if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
  {
  return board[1][1];
  }
  //判断平局
  if (is_full(board, row, col) == 1)
  {
  return 'Q';
  }
  //继续
  return 'C';
}


在这里面,实现了对以上情况的具体分析,因版本内容所致,笔者将不再进行过多的讲述,更多详细细节,请联系笔者!


12c3b7f3f8814309a195c64f051d4445.png


对于上述截图,我想读者都能看出来,该游戏已经能够成功的实现出来,并且符合我们的要求!


下面将是玩三子棋小游戏是整个代码,以供读者参考借鉴


test.c文档内容

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
  printf("*********************************\n");
  printf("********      1. play    ********\n");
  printf("********      0. exit    ********\n");
  printf("*********************************\n");
}
void game()
{
  char ret = 0;
  //数据的存储需要一个3*3的二维数组
  char board[ROW][COL] = { 0 };
  init_board(board, ROW, COL);
  display_board(board, ROW, COL);
  //玩游戏
  while (1)
  {
  player_move(board, ROW, COL);
  display_board(board, ROW, COL);
  ret = is_win(board, ROW, COL);
  if (ret != 'C')
    break;
  computer_move(board, ROW, COL);
  display_board(board, ROW, COL);
  ret = is_win(board, ROW, COL);
  if (ret != 'C')
    break;
  }
  if (ret == '*')
  {
  printf("玩家赢\n");
  }
  else if (ret == '#')
  {
  printf("电脑赢\n");
  }
  else if (ret == 'Q')
  {
  printf("平局\n");
  }
  display_board(board, ROW, COL);
}
//玩家赢 - '*'
//电脑赢 - '#'
//平局了 - 'Q'
//游戏继续 - 'C'
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do
  {
  menu();
  printf("请选择:>");
  scanf_s("%d", &input);
  switch (input)
  {
  case 1:
    game();
    break;
  case 0:
    printf("退出游戏\n");
    break;
  default:
    printf("选择错误,重新选择!\n");
    break;
  }
  } while (input);
  return 0;
}


game.h文档内容

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 10             //行 ,可以自定义数值的大小
#define COL 10             //列 ,可以自定义数值的大小
//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);
//打印棋盘
void display_board(char board[ROW][COL], int row, int col);
//玩家下棋
void player_move(char board[ROW][COL], int row, int col);
//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);
//判断游戏状态
char is_win(char board[ROW][COL], int row, int col);


game.c文档内容

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void init_board(char board[ROW][COL], int row, int col)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < row; i++)
  {
  for (j = 0; j < col; j++)
  {
    board[i][j] = ' ';
  }
  }
}
//void display_board(char board[ROW][COL], int row, int col)
//{
//  int i = 0;
//  for (i = 0; i < row; i++)
//  {
//  //数据
//  printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
//  //---|---|---
//  if(i<row-1)
//    printf("---|---|---\n");
//  }
//}
void display_board(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
  //数据
  //printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
  int j = 0;
  for (j = 0; j < col; j++)
  {
    printf(" %c ", board[i][j]);
    if (j < col - 1)
    printf("|");
  }
  printf("\n");
  //---|---|---
  if (i < row - 1)
  {
    //printf("---|---|---\n");
    for (j = 0; j < col; j++)
    {
    printf("---");
    if (j < col - 1)
      printf("|");
    }
    printf("\n");
  }
  }
}
void player_move(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  printf("玩家下棋:>\n");
  while (1)
  {
  printf("请输入要下棋的坐标:>");
  scanf_s("%d %d", &x, &y);
  //1.坐标的合法性
  //2.坐标是否被占用
  if (x >= 1 && x <= row && y >= 1 && y <= col)
  {
    if (board[x - 1][y - 1] == ' ')
    {
    board[x - 1][y - 1] = '*';
    break;
    }
    else
    {
    printf("该坐标被占用,请重新输入\n");
    }
  }
  else
  {
    printf("坐标非法,重新输入\n");
  }
  }
}
//
//电脑随机下棋
//
void computer_move(char board[ROW][COL], int row, int col)
{
  printf("电脑下棋:>\n");
  //0~32726
  //%3-->0~2
  while (1)
  {
  int x = rand() % row;
  int y = rand() % col;
  if (board[x][y] == ' ')
  {
    board[x][y] = '#';
    break;
  }
  }
}
//如果棋盘满了,返回1
//不满,返回0
static int is_full(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
  int j = 0;
  for (j = 0; j < col; j++)
  {
    if (' ' == board[i][j])
    {
    return 0;
    }
  }
  }
  return 1;
}
char is_win(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
  if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
  {
    return board[i][0];
  }
  }
  for (i = 0; i < col; i++)
  {
  if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
  {
    return board[0][i];
  }
  }
  if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
  {
  return board[1][1];
  }
  if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
  {
  return board[1][1];
  }
  //判断平局
  if (is_full(board, row, col) == 1)
  {
  return 'Q';
  }
  //继续
  return 'C';
}


在这里笔者用了三个文件,一个头文件game.h  ;两个源文件game.c,test.c来实现该三子棋的代码!


到此为止,该段已经结束!


相关文章
|
开发工具 git
Git - Smart Checkout、Force Checkout 区别
Git - Smart Checkout、Force Checkout 区别
1965 0
Git - Smart Checkout、Force Checkout 区别
|
JSON 数据格式 Python
Python分享之requests(1)
Python分享之requests(1)
164 0
|
9月前
|
监控 关系型数据库 MySQL
Ubuntu24.04安装Librenms
此指南介绍了在Linux系统上安装和配置LibreNMS网络监控系统的步骤。主要内容包括:安装所需软件包、创建用户、克隆LibreNMS仓库、设置文件权限、安装PHP依赖、配置时区、设置MariaDB数据库、调整PHP-FPM与Nginx配置、配置SNMP及防火墙、启用命令补全、设置Cron任务和日志配置,最后通过网页完成安装。整个过程确保LibreNMS能稳定运行并提供有效的网络监控功能。
ly~
|
11月前
|
Ubuntu Linux C语言
SDL 图形库安装常见错误及解决方法
SDL(Simple DirectMedia Layer)图形库安装过程中可能会遇到编译错误、运行时错误、依赖库缺失等问题。本文总结了在 Linux 和 Windows 系统上常见的错误及解决方法,包括检查和安装依赖库、配置 SDL 子系统、处理 X11 错误等,帮助用户顺利完成 SDL 的安装和配置。
ly~
2072 8
|
存储 缓存 Java
2022 最新 JDK 17 HashMap 源码解读 (一)
2022 最新 JDK 17 HashMap 源码解读 (一)
445 0
|
自然语言处理 JavaScript 前端开发
ECMAScript 6 新特性详解(上)
ECMAScript 6 新特性详解(上)
|
Go
Golang 004. 转换百分制分数
Golang 004. 转换百分制分数
166 0
|
消息中间件 调度 Python
【Python零基础入门篇 · 23】:进程的基础操作、进程间的通信-Queue、进程池的构建
【Python零基础入门篇 · 23】:进程的基础操作、进程间的通信-Queue、进程池的构建
168 0
【Python零基础入门篇 · 23】:进程的基础操作、进程间的通信-Queue、进程池的构建
|
存储 Java
面试题系列第6篇:JVM字符串常量池及String的intern方法详解?
面试题系列第6篇:JVM字符串常量池及String的intern方法详解?
149 0
面试题系列第6篇:JVM字符串常量池及String的intern方法详解?
|
Android开发
Android应用开发—setResult()的调用时机
本文转载自setResult()的调用时机,此处做了重新的排版,只是感觉markdown的排版比较好看些,侵删。 今天遇到这样一个问题,我在Activity-A中用startActivityForResult()方法启动了Activity-B,并且在B中通过setResult()方法给A返回值,由于某些原因不能在setResult()之后立刻调用finish()函数,只能通过用户按Back键自己退出到A。
1767 0