一个四子棋游戏

编写一个"人机对弈"的下棋程序,四个棋子连成一线即为赢。人走棋的合法输入为0-6。棋盘是垂直放置,棋子落到底部。固定为人先走,计算机后走.

首先,这里有用到枚举类型----增加程序的可读性.用来描述状态量
/*enum who { HUMAN, NEUTRAL, COMPUTER };
HUMAN=0, NEUTRAL=1,COMPUTER=2
枚举常量代表该枚举类型的变量可能取的值,编译系统为每个枚举常量指定一个整数值。
默认状态下,这个整数就是所列举元素的序号,序号从0开始。
可以在定义枚举类型时为部分或全部枚举常量指定整数值,在指定值之前的枚举常量仍按默认方式取值,
而指定值之后的枚举常量按依次加1的原则取值。 各枚举常量的值可以重复。
//枚举常量只能以标识符形式表示,而不能是整型、字符型等文字常量。
//直接输出,输出的是变量的整数值*/

定义一个who data[6][7];枚举变量数组,用于存储棋盘各位置上棋子的类型(人机无)

主要结构

class game { //这是个抽象类,抽象的是所有人走一步,计算机走一步的对弈游戏
	private:
		int move_number; //当前已走的步数
		void make_human_move( );   //调用 get_user_move( ),并用is_legal(move)判断是否合法输入,若是则调用make_move(move)
	public:
		enum who { HUMAN, NEUTRAL, COMPUTER };//枚举类型变量who(同int float样的数据类型) :有枚举元素HUMAN, NEUTRAL, COMPUTER

		game( ) {//构造函数,move_number初始值为0
			move_number = 0;
		}
		virtual ~game( ) { }//析构函数
		who play( );   //人先走,计算机后走,返回值是游戏的赢者,后面给出了此函数的定义
	protected:
		//以下虚函数可以被覆盖,也可以不被覆盖
		//virtual void display_message(const string &message)const;//在屏幕显示信息message
		virtual int get_user_move( )const;       // 输出"Your move,please:",然后接受用户输入,并将输入返回
		virtual who last_mover( ) const {
			if (move_number == 0)
				return NEUTRAL;
			else
				return (move_number % 2 == 1 ? HUMAN : COMPUTER);//人先走 必然结果
		}
		virtual int moves_completed( ) const {
			return move_number;//返回已走步数//用于将私有变量显示在棋盘上
		}
		virtual who next_mover( ) const {//表示现在的下棋者 在make_move中调用
			return (move_number % 2 == 0 ? HUMAN : COMPUTER);
		}

		//以下虚函数必须被覆盖
		virtual void make_move(const int &move) { //将棋子真正下到棋盘上,此函数被子类覆盖
			++move_number;
		}
		virtual void restart( ) {
			move_number = 0;    //开始新的棋局
		}

		//以下为纯虚函数
		virtual who winning( )const = 0;       //返回胜利者
		virtual void display_status( )  = 0;   //显示游戏棋盘的当前状态
		virtual bool is_game_over( )  = 0;     //如果游戏结束,返回真
		virtual bool is_legal(const int &move)  = 0;   //如果给定走法为合法,就返回真
		virtual void make_computer_move( ) = 0;  //计算计算机所有的可能的走法,选出一种最好的,并调用make_move(best_move)


};

class c4 : public game { //这个类是我们具体要实现的“四子棋”
	public:
		c4( ) {//构造函数
			restart( );//调用的是子类c4的restart
		}
	protected:
		virtual void make_move(const int &move);
		// 修改data[][],many_used[]和most_recent_column的值,并调用game::make_move(move)
		virtual void restart();
		//将data[6][7]各元素置为NEUTRAL,将many_used[7]各元素置为0 ,再调用game::restart();//清空棋盘以及步数
		virtual game::who winning( )const ;
		virtual void display_status( ) ;  //显示棋盘的状态
		virtual bool is_game_over( ) ;
		virtual bool is_legal(const int &move) ;
		virtual void make_computer_move( );
	private:
		who data[6][7];   //6行7列,表示棋盘
		int many_used[7]; //表示各列中已有多少个棋子
		int most_recent_column;  //最近下的棋子在哪列
		int chess_notation[30] = {0}; //定义数组存储 每步most_recent_column的位置
		int *p = chess_notation;//指针指向存储全部most_recent_column
};

game为基类,c4表示四子棋为game的派生类。

game中的纯虚函数需要在c4中再次声明,并定义新的内容 

主函数

int main() {
	cout << "Game on!" << endl;
	c4 instance;
	game::who winner;//定义一个who枚举类型的变量 winner
	winner = instance.play();//对winner进行赋元素操作,返回赢的人

	switch (winner) {
		case c4::HUMAN:
			cout << "You win!" << endl;
			break;

		case c4::COMPUTER:
			cout << "I win!" << endl;
			break;

		case c4::NEUTRAL:
			cout << "A draw" << endl;
			break;
	}

	return 0;
}

定义一个c4类结构体变量instance         定义一个枚举变量winner赢者

调用核心函数 game::play();

选择赢者——输出结果

核心函数

game::who game::play() {
	restart();//清空棋盘 开始游戏

	while (!is_game_over()) {//当游戏未结束时,显示棋盘的状态
		display_status();

		if (last_mover() == COMPUTER || last_mover() == NEUTRAL)
			make_human_move();//上一步机走,下一步人走
		else
			make_computer_move();//上一步人走,下一步机走
	}

	display_status();//走一步,显示一下棋盘状态 或游戏结束显示棋盘状态
	return winning();//返回赢者
}

以下按照核心函数的顺序 给出各个函数的定义

restart():

game中走的步数清零

c4中将棋盘上每一个都写为“无”,每一列的棋子数为0,再调用父类restart();

c4中的restart()函数覆盖了父类中函数,所以在使用restart()时调用的是子类的函数,如需要调用父类中的函数,则需要使用::

/game/
virtual void restart( ) {
	move_number = 0;    //开始新的棋局
}

void c4::restart( ) {//覆盖game类
//将data[6][7]各元素置为NEUTRAL,将many_used[7]各元素置为0 ,再调用game::restart();
	for (int i = 0; i < 6; i++) {
		for (int j = 0; j < 7; j++) {
			data[i][j] = NEUTRAL;
		}
	}

	for (int k = 0; k < 7; k++) {
		many_used[k] = 0;
	}

	game::restart( );//开始新的棋局 即move_number = 0;
}

 is_game_over():

判断是否有四子连成,如有返回真

因为使用了嵌套循环,所以只有break;只是跳出了内嵌循环。需要有一个变量来限制循环条件。

根据棋盘大小,确定ij的范围

bool c4::is_game_over( ) {
	int win = 1;//用变量作为跳出循环的条件

	if (last_mover() == NEUTRAL)//游戏开局 先手被定义为NEUTRAL 要排除这种情况
		return false;

	for (int j = 0; j < 7 && (win == 1); j++) {//win不等于1的时候 跳出循环
		for (int i = 0; i < 6; i++) {
			if (data[i][j] == HUMAN && data[i][j + 1] == HUMAN && data[i][j + 2] == HUMAN && data[i][j + 3] == HUMAN
			        || data[i][j] == HUMAN && data[i + 1][j] == HUMAN && data[i + 2][j] == HUMAN
			        && data[i + 3][j] == HUMAN) { //纵横方向上HUMAN
				win = 0;
				break;
			}

			if (data[i][j] == COMPUTER && data[i][j + 1] == COMPUTER && data[i][j + 2] == COMPUTER
			        && data[i][j + 3] == COMPUTER
			        || data[i][j] == COMPUTER && data[i + 1][j] == COMPUTER && data[i + 2][j] == COMPUTER
			        && data[i + 3][j] == COMPUTER) { //纵横方向上COMPUTER
				win = 2;
				break;
			}
		}
	}

	for (int j = 0; j < 4 && (win == 1); j++) {
		for (int i = 3; i < 6; i++) {
			if (data[i][j] == HUMAN && data[i - 1][j + 1] == HUMAN && data[i - 2][j + 2] == HUMAN
			        && data[i - 3][j + 3] == HUMAN) { //向右倾斜方向上HUMAN
				win = 0;
				break;
			}

			if (data[i][j] == COMPUTER && data[i - 1][j + 1] == COMPUTER && data[i - 2][j + 2] == COMPUTER
			        && data[i - 3][j + 3] == COMPUTER) { //向右倾斜方向上COMPUTER
				win = 2;
				break;
			}
		}
	}

	for (int j = 3; j < 7 && (win == 1); j++) {
		for (int i = 0; i < 3; i++) {
			if (data[i][j] == HUMAN && data[i + 1][j - 1] == HUMAN && data[i + 2][j - 2] == HUMAN
			        && data[i + 3][j - 3] == HUMAN) { //向左倾斜方向上HUMAN
				win = 0;
				break;
			}

			if (data[i][j] == COMPUTER && data[i + 1][j - 1] == COMPUTER && data[i + 2][j - 2] == COMPUTER
			        && data[i + 3][j - 3] == COMPUTER) { //向左倾斜方向上COMPUTER
				win = 2;
				break;
			}
		}
	}

	if (win == 0 || win == 2)
		return true;
	else
		return false;
}

i和j 的范围:由棋盘的大小决定,比如在纵横方向上,最后的一个棋在棋盘上的每一个格都可能使连成4子。而向右斜上方向,有些位置上不可能连成4子,所以,不用考虑,化简程序。

display_status():

Chess notation[30]:每步棋落在哪里,用一个数组存储。每次输出一个数组的全部元素

void c4::display_status( ) {
	//显示棋盘的状态
	for (int i = 0; i < 6; i++) {
		cout << "\t\t";

		for (int j = 0; j < 7; j++) {
			if (data[i][j] == COMPUTER)
				cout  << "@" << "  " ;
			else if (data[i][j] == HUMAN)
				cout << "$" << "  " ;
			else
				cout << "." << "  " ;
		}

		cout << endl;
	}

	cout << "\t\t" << "-------------------" << endl << "\t\t" << "0  1  2  3  4  5  6  " << endl << "\t" <<
	     "@:computer   $:human   humanfirst" << endl;
	cout << "Chess notation:";
	*p = most_recent_column;

	for (p = chess_notation; p < moves_completed( ) + chess_notation; p++) {
		cout << *p << " ";
	}

	cout << endl;
	cout << "used[i]:";

	for (int i = 0; i < 7; i++) {
		cout << many_used[i] << " ";
	}

	cout << endl;
	cout << "The number of moves have played:" << moves_completed( ) << endl << endl;
}

make_human_move( )

从键盘输入人走的列数,调用is_legal_move()判断正误,合法即调用make_move()

int game:: get_user_move( )const {
	int move;
	cout << "Your move,please:";
	cin >> move;
	return move;
}
void game::make_human_move( ) { //调用 get_user_move( ),并用is_legal(move)判断是否合法输入,若是则调用make_move(move)
	int move = get_user_move( );

	while (1) {
		if (is_legal(move)) {
			make_move(move);
			break;
		} else {
			cout << "!retry!" << endl;
			move = get_user_move( );
		}
	}
}

make_move() 

virtual void make_move(const int &move) { //将棋子真正下到棋盘上,此函数被子类覆盖
			++move_number;
		}
void c4::make_move(const int &move) {//覆盖game类
// 修改data[][],many_used[]和most_recent_column的值,并调用game::make_move(move)

	int temp = many_used[move]; //用中间变量存储 此时该列中 已有的棋子数

	if (next_mover( ) == HUMAN)
		data[5 - temp][move] = HUMAN; //人把棋子下到该列
	else
		data[5 - temp][move] = COMPUTER;//机把棋子下到该列

	many_used[move]++;//该列已有棋子+1
	most_recent_column = move;//保存最近下的棋在哪一列————————决定下一步机下在哪里
	game::make_move(move);//即 ++move_number;已走步数加1
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的三子游戏的代码,仅供参考: ```c #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define SIZE 3 void initialize_board(char board[][SIZE]); void display_board(char board[][SIZE]); bool check_win(char board[][SIZE], char player); bool check_tie(char board[][SIZE]); int main(void) { char board[SIZE][SIZE]; char player = 'X'; int row, col; bool win = false; bool tie = false; initialize_board(board); do { display_board(board); printf("Player %c's turn.\n", player); do { printf("Enter row (1-3): "); scanf("%d", &row); printf("Enter column (1-3): "); scanf("%d", &col); } while (board[row-1][col-1] != ' '); board[row-1][col-1] = player; win = check_win(board, player); tie = check_tie(board); if (win) { printf("Player %c wins!\n", player); display_board(board); break; } if (tie) { printf("It's a tie!\n"); display_board(board); break; } player = (player == 'X') ? 'O' : 'X'; } while (!win && !tie); return 0; } void initialize_board(char board[][SIZE]) { int i, j; for (i = 0; i < SIZE; i++) { for (j = 0; j < SIZE; j++) { board[i][j] = ' '; } } } void display_board(char board[][SIZE]) { int i, j; printf("\n"); for (i = 0; i < SIZE; i++) { for (j = 0; j < SIZE; j++) { printf(" %c ", board[i][j]); if (j < SIZE - 1) { printf("|"); } } printf("\n"); if (i < SIZE - 1) { printf("---+---+---\n"); } } printf("\n"); } bool check_win(char board[][SIZE], char player) { int i; // check rows for (i = 0; i < SIZE; i++) { if (board[i][0] == player && board[i][1] == player && board[i][2] == player) { return true; } } // check columns for (i = 0; i < SIZE; i++) { if (board[0][i] == player && board[1][i] == player && board[2][i] == player) { return true; } } // check diagonals if (board[0][0] == player && board[1][1] == player && board[2][2] == player) { return true; } if (board[0][2] == player && board[1][1] == player && board[2][0] == player) { return true; } return false; } bool check_tie(char board[][SIZE]) { int i, j; for (i = 0; i < SIZE; i++) { for (j = 0; j < SIZE; j++) { if (board[i][j] == ' ') { return false; } } } return true; } ``` 这个代码实现了一个简单的三子游戏,玩家可以选择行列下,程序会自动判断胜负和平局。需要注意的是,这个代码没有实现人机对战,只能让两个人玩。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值