三子棋——年轻人的第一款小游戏

简介: 主函数部分(test.c)头文件部分(game.h)1.初始化函数2.打印棋盘函数3.玩家移动函数4.电脑移动函数5.判断输赢函数6.重回game函数效果展示总结

目录


前言

正文

主函数部分(test.c)

头文件部分(game.h)

功能实现函数部分(game.c)

1.初始化函数

2.打印棋盘函数

3.玩家移动函数

4.电脑移动函数

5.判断输赢函数

6.重回game函数

效果展示

总结


前言


 经过一段时间的学习,分支与循环、数组与函数的相关知识已经足够支撑我们完成一个小游戏了,这个小游戏不需要太多的功能,也不需要太复杂的逻辑,只需要懂点循环与分支,懂点数组的使用以及函数如何传参和返值即可。作为草稿纸上常出现的小游戏,三子棋的逻辑可谓是非常简单了,只需要玩家走一步、电脑走一步,并在八种可能获胜结果中比对就行了,下面让我们一起来看看三子棋的实现。


 注意:本文为模拟游戏实现,代码量两百左右,共有两个源文件+一个头文件。


正文


本程序一共就下面三个文件


2a1badeff883a99247cd09c8b359d59.png

主函数部分(test.c)


我们直接从主函数开始

67982b96be87fd98bc966bef4d85b5d.png

下面看看game(游戏)函数的设计

4cd0898a63559533dc99c78770bf86c.png

//三子棋
#include"game.h"
void menu()
{
  printf("**************************\n");
  printf("********  1.Play  ********\n");
  printf("********  0.Exit  ********\n");
  printf("**************************\n");
}
void game()
{
  char board[ROW][COL] = { 0 };//定义
  init_board(board, ROW, COL);//初始化
  display_board(board, ROW, COL);//打印
  //下棋
  char tmp = 0;
  while (1)
  {
    player_move(board, ROW, COL);//玩家走
    display_board(board, ROW, COL);//打印
    tmp=who_win(board, ROW, COL);//判断
    if (tmp != 'C')
      break;
    computer_move(board, ROW, COL);//电脑走
    display_board(board, ROW, COL);//打印
    tmp=who_win(board, ROW, COL);//判断
    if (tmp != 'C')
      break;
  }
  if (tmp == '*')
    printf("玩家获胜\n");
  else if (tmp == '#')
    printf("电脑获胜\n");
  else
    printf("和局\n");
}
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do
  {
    menu();
    printf("请输入你的选择:>");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      game();
      break;
    case 0:
      printf("退出游戏!\n");
      break;
    default :
      printf("选择错误,重新选择!\n");
      break;
    }
  } while (input);
  return 0;
}


主函数文件(test.c就介绍完了),下面介绍game.h这个头文件

头文件部分(game.h)


这个头文件是自己建立的,目的就是在主函数源文件(test.c)和功能实现函数(game.c)中搭起一座沟通的桥梁。

80f238a7acbcb92cfd322984b2f256e.png

#pragma once
#include<stdio.h>
#include<stdlib.h>
#define ROW 3
#define COL 3
void init_board(char board[][COL],int row,int col);//初始化
void display_board(char board[][COL], int row, int col);//打印
void player_move(char board[][COL], int row, int col);//玩家走
void computer_move(char board[][COL], int row, int col);//电脑走
char who_win(char board[][COL], int row, int col);//判断

自定义头文件部分代码量最少,功能也比较简单,如果说test.c是大脑、控制中心,那么game.h就相当于神经系统的一部分,是函数间沟通的桥梁,能对函数起主导作用。


功能实现函数部分(game.c)

此部分是程序运行必不可少的部分,没有它们,程序能跑,但什么都干不了,类似于植人。


本部分函数细节较多,因此我会分开逐个讲解。

 

1.初始化函数


1b1c9bf385b4855cd7a9efdedc9ac44.png

初始函数主要就是把整个数组遍历一遍,然后将字符 空格 (' ')赋给每个数组即可


7fc84a63988cf8989654d97d4382e8e.png

void init_board(char board[][COL], int row, int col)//初始化
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    for (j = 0; j < col; j++)
    {
      board[i][j] = ' ';//初始化数组为空格' '
    }
  }
}

2.打印棋盘函数


打印棋盘函数需要思考下:什么情况打印 | 和 什么情况打印 --- ,不想清楚这些问题就无法打印出优美的棋盘。

d9c7c2fa172a9fbe2e2c652d7c78a83.png

void display_board(char board[][COL], int row, int col)//打印
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    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)//不打印第三组
    {
      for (j = 0; j < col; j++)
      {
        printf("---");
        if (j < col - 1)//不打印第三组
          printf("|");
      }
      printf("\n");
    }
  }
}

3.玩家移动函数


玩家移动就是让玩家输入坐标,输入坐标有三种情况:非法、占用、成功,依次判断即可,其次要注意不是人人都知道坐标从0开始,因此在使用x、y时要减1,确保坐标不会越界。

9168bce8663f59160b5e3053e3a5fcd.png


void player_move(char board[][COL], int row, int col)//玩家走
{
  int x = 0;
  int y = 0;
  while (1)
  {
    printf("请落子:>");
    scanf("%d %d", &x, &y);
    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");
  }
}


4.电脑移动函数


电脑移动不要太多判断,只需要给电脑一个随机值,一个判断条件。

直到电脑落子成功再跳出即可


206dbb00d0d9b8b777b802365e824b6.png

void computer_move(char board[][COL], int row, int col)//电脑走
{
  printf("轮到电脑落子:>");
  while (1)
  {
    int x = rand() % row;
    int y = rand() % col;
    if (board[x][y] == ' ')
    {
      board[x][y] = '#';
      break;
    }
  }
  printf("电脑已落子\n");
}


5.判断输赢函数


这个函数出现于玩家或电脑移动之后,目的就是判断是否已达成胜利条件(共八种),如果达成了,就能跳出game函数中的死循环,结束游戏。

6c6201dfc95fc913aaadb1f6e614012.png

0165f2d2dd5676621ad167675e3cae2.png

注意:本程序中函数就判断输赢函数和判断和局函数有返回值,一个是char,一个是int


int place(char board[][COL], int row, int col)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < row; i++)
  {
    for (j = 0; j < col; j++)
    {
      if (board[i][j] == ' ')
        return 0;//排除所有情况
    }
  }
  return 1;
}
char who_win(char board[][COL], int row, int col)//判断
{
  int i = 0;
  int j = 0;
  for (i = 0; i < row; i++)
  {
    if (board[i][0] == board[i][1] && 
      board[i][1] == board[i][2] && board[i][2] != ' ')
      return board[i][0];
  }//判断行
  for (j = 0; j < row; j++)
  {
    if (board[0][j] == board[1][j] &&
      board[1][j] == board[2][j] && board[2][j] != ' ')
      return board[0][j];
  }//判断列
  if (board[0][0] == board[1][1] && 
    board[1][1] == board[2][2] && board[2][2] != ' ')
    return board[0][0];//判断正斜
  if (board[0][2] == board[1][1] && 
    board[1][1] == board[2][0] && board[2][0] != ' ')
    return board[0][2];//判断反斜
  if (place(board, ROW, COL) == 1)
    return 'Q';//判断和局
  return 'C';//默认选项
}

6.重回game函数


经过game.c中各函数的一顿操作,最终由判断输赢函数携带返回值回到game函数进行判断

7fa423d7d3eb6619a83826f7af1bf79.png

效果展示


让我们直接来看看效果如何:

a35e863d516182aae5359561ee62d97.png

可以看到三种情况都能实现,现在只需要将代码进行优化,主要是优化输赢判断部分,使其兼容性更强,以后在玩五子棋时能沿用这套方案。

下面我将展示功能实现函数(game.c)的全部代码:

#define _CRT_SECURE_NO_WARNINGS 1 
#include"game.h"
void init_board(char board[][COL], int row, int col)//初始化
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    for (j = 0; j < col; j++)
    {
      board[i][j] = ' ';//初始化数组为空格' '
    }
  }
}
void display_board(char board[][COL], int row, int col)//打印
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    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)//不打印第三组
    {
      for (j = 0; j < col; j++)
      {
        printf("---");
        if (j < col - 1)//不打印第三组
          printf("|");
      }
      printf("\n");
    }
  }
}
void player_move(char board[][COL], int row, int col)//玩家走
{
  int x = 0;
  int y = 0;
  while (1)
  {
    printf("请落子:>");
    scanf("%d %d", &x, &y);
    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[][COL], int row, int col)//电脑走
{
  printf("轮到电脑落子:>");
  while (1)
  {
    int x = rand() % row;
    int y = rand() % col;
    if (board[x][y] == ' ')
    {
      board[x][y] = '#';
      break;
    }
  }
  printf("电脑已落子\n");
}
int place(char board[][COL], int row, int col)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < row; i++)
  {
    for (j = 0; j < col; j++)
    {
      if (board[i][j] == ' ')
        return 0;//排除所有情况
    }
  }
  return 1;
}
char who_win(char board[][COL], int row, int col)//判断
{
  int i = 0;
  int j = 0;
  for (i = 0; i < row; i++)
  {
    if (board[i][0] == board[i][1] && 
      board[i][1] == board[i][2] && board[i][2] != ' ')
      return board[i][0];
  }//判断行
  for (j = 0; j < row; j++)
  {
    if (board[0][j] == board[1][j] &&
      board[1][j] == board[2][j] && board[2][j] != ' ')
      return board[0][j];
  }//判断列
  if (board[0][0] == board[1][1] && 
    board[1][1] == board[2][2] && board[2][2] != ' ')
    return board[0][0];//判断正斜
  if (board[0][2] == board[1][1] && 
    board[1][1] == board[2][0] && board[2][0] != ' ')
    return board[0][2];//判断反斜
  if (place(board, ROW, COL) == 1)
    return 'Q';//判断和局
  return 'C';//默认选项
}

总结


 我们本次三子棋之旅到这就要结束了,说实在的,三子棋这段代码蕴含逻辑比较简单,唯一需要注意的就是棋盘打印和电脑随机值,只有理解透彻了,代码敲起来才能得心应手!


0278611b857089c68efec814ddade0d.png


目录
相关文章
|
11月前
三子棋(井字棋) 保姆级详解
三子棋(井字棋) 保姆级详解
|
2月前
|
开发者
【植物大战僵尸杂交版】致敬传奇游戏玩家——一个普通人的六年坚持
【植物大战僵尸杂交版】致敬传奇游戏玩家——一个普通人的六年坚持
|
4月前
|
人工智能 C语言
三子棋小游戏
三子棋小游戏
|
11月前
|
人工智能
多子棋游戏的玩法设计
多子棋游戏的玩法设计
|
网络架构 Python
“罚点球”小游戏
用 score_you 表示你的得分,score_com 表示电脑得分。开始都为0,每进一球就加1。
|
程序员 C语言
趣味益智小游戏 三子棋+五子棋 优化版(可任意选择棋盘大小)
趣味益智小游戏 三子棋+五子棋 优化版(可任意选择棋盘大小)
102 0
自创三子棋,拓展版
自创三子棋,拓展版
37 0
【C语言】民间传统游戏——三子棋详细教学
三子棋(介绍) 游戏分为双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子走成一条线就视为胜利,而对方就算输了,但是三子棋在很多时候会出现和棋的局面。 🌞
|
人工智能 C语言
小时候的回忆—三子棋
三子棋的实现,部分ai
小时候的回忆—三子棋