棋局建模例题(1)-洛谷P1838 三子棋I

出处

洛谷-P1838 三子棋I:https://www.luogu.com.cn/problem/P1838

题目描述

小 a 和 uim 喜欢互相切磋三子棋。三子棋大家都玩过是吗?就是在九宫格里面 OOXX(别想歪了),谁连成 3 个就赢了。

由于小 a 比较愚蠢,uim 总是让他先。

我们用 9 个数字表示棋盘位置:

123
456
789

所有的棋谱都是已经结束的棋局,要么一方获胜,要么平局。

今天,他们下了一下午的棋,小 a 为了提高技术,录下了很多棋谱。他想知道,一盘棋结束时,到底是谁赢。

输入格式

一行,一串数字,表示落子的地点。小 a 总是先下。

输出格式

一行,如果小 a 赢,输出 xiaoa wins.。如果 uim 赢,输出 uim wins.。如果平局,输出 drew.

输入输出样例

输入 #1

5237649

输出 #1

xiaoa wins.

输入 #2

539128647

输出 #2

drew.

题解(模拟法)

以下使用纯模拟法,主要展示如何对棋局进行建模和判断胜负。

1. 棋盘表示和基本结构
#include <stdio.h>
#include <stdlib.h>

int board[3][3]; // 0(空),1(小 a),-1(uim)
  • 使用3×3的二维数组board表示棋盘。
  • 0表示空格,1表示小a的棋子,-1表示uim的棋子。
2. 主游戏逻辑
  • 游戏最多进行9步(棋盘填满)。
  • 从标准输入读取数字(1-9),转换为棋盘坐标。
  • 交替落子:小a(1)在偶数步,uim(-1)在奇数步。
  • 每次落子后检查是否有玩家获胜。
  • 如果9步后无人获胜,输出平局。
3. 落子函数
void move(int x, int y, int player)
{
    board[x][y] = player;
}
  • 简单地将玩家的标记(1或-1)放入指定位置。
4. 胜负判断函数
  • 检查所有行、列和对角线是否有三个相同的非0值。
  • 如果有,返回该值(1或-1)表示获胜方。
  • 否则返回0表示无人获胜。
关键点说明
  1. ​棋盘表示​​:使用简单的3×3数组,0表示空,1和-1分别表示两位玩家。
  2. ​输入处理​​:将数字1-9转换为二维坐标(x, y)。
  3. ​交替落子​​:通过步数奇偶性决定当前玩家。
  4. ​胜负判断​​:检查所有可能的连线情况(3行、3列、2对角线)。
  5. ​游戏终止​​:一旦有玩家获胜立即结束游戏,或者棋盘填满后也无玩家获胜宣布平局。

C语言实现

#include <stdio.h>
#include <stdlib.h>

int board[3][3]; // 0(空),1(小 a),-1(uim)

void move(int x, int y, int player); // 落子
int checkWin(); // 判断是否有一方胜,若有一方胜返回获胜方,否则返回 0

int main()
{
    for (int i = 0; i < 9; i++)
    {
        int n = getchar() - '0';

        // (x = (n - 1) / 3, y = (n - 1) % 3)

        int x = (n - 1) / 3;
        int y = (n - 1) % 3;

        // i 偶数是 小a 落子,奇数是 uim 落子
        int player = i % 2 ? -1 : 1;
        move(x, y, player);

        int winPlayer = checkWin();
        if (winPlayer == 1)
        {
            printf("xiaoa wins.\n");
            exit(0);
        }
        else if (winPlayer == -1)
        {
            printf("uim wins.\n");
            exit(0);
        }
    }

    printf("drew.\n");

    return 0;
}

// 落子
void move(int x, int y, int player)
{
    board[x][y] = player;
}

// 判断是否有一方胜,若有一方胜返回获胜方,否则返回 0
int checkWin()
{
    // 检查每一行
    for (int i = 0; i < 3; i++)
    {
        if (board[i][0] != 0 && board[i][0] == board[i][1] && board[i][1] == board[i][2])
            return board[i][0];
    }

    // 检查每一列
    for (int i = 0; i < 3; i++)
    {
        if (board[0][i] != 0 && board[0][i] == board[1][i] && board[1][i] == board[2][i])
            return board[0][i];
    }

    // 检查两个对角线
    if (board[1][1] != 0 && board[0][0] == board[1][1] && board[1][1] == board[2][2])
        return board[1][1];
    if (board[1][1] != 0 && board[0][2] == board[1][1] && board[1][1] == board[2][0])
        return board[1][1];

    return 0;
}

社团成员解法

直接映射+条件判断https://codecopy.cn/post/tfvbqo(作者:chuali)

#include<iostream>
#include<vector>
using namespace std;
int qipan[3][3];//这是棋盘
bool wins1();//这是判断xiaoa赢的函数
bool wins2();//这是判断uim赢的函数
int main() {
	bool fir = 0;//这个是判断谁先下棋的判断
	vector<int>num(9);
	string s;
	cin >> s;
	for (char op:s) {
		int x = op - '0';//字符串转换为int
		if (x == 1) {//接下来就是打表下琪了
			if (fir) {
				qipan[0][0] = -1;
				fir = 0;
			}
			else {
				qipan[0][0] = 1;
				fir = 1;
			}
		}
		if (x == 2) {
			if (fir) {
				qipan[0][1] = -1;
				fir = 0;
			}
			else {
				qipan[0][1] = 1;
				fir = 1;
			}
		}
		if (x == 3) {
			if (fir) {
				qipan[0][2] = -1;
				fir = 0;
			}
			else {
				qipan[0][2] = 1;
				fir = 1;
			}
		}
		if (x == 4) {
			if (fir) {
				qipan[1][0] = -1;
				fir = 0;
			}
			else {
				qipan[1][0] = 1;
				fir = 1;
			}
		}
		if (x == 5) {
			if (fir) {
				qipan[1][1] = -1;
				fir = 0;
			}
			else {
				qipan[1][1] = 1;
				fir = 1;
			}
		}
		if (x == 6) {
			if (fir) {
				qipan[1][2] = -1;
				fir = 0;
			}
			else {
				qipan[1][2] = 1;
				fir = 1;
			}
		}
		if (x == 7) {
			if (fir) {
				qipan[2][0] = -1;
				fir = 0;
			}
			else {
				qipan[2][0] = 1;
				fir = 1;
			}
		}
		if (x == 8) {
			if (fir) {
				qipan[2][1] = -1;
				fir = 0;
			}
			else {
				qipan[2][1] = 1;
				fir = 1;
			}
		}
		if (x == 9) {
			if (fir) {
				qipan[2][2] = -1;
				fir = 0;
			}
			else {
				qipan[2][2] = 1;
				fir = 1;
			}
		}
		if (wins1()) {//落完子立刻判断是否胜利
			std::cout << "xiaoa wins." << endl;
			return 0;
		}
		if (wins2()) {
			std::cout << "uim wins." << endl;
			return 0;
		}
	}
	std::cout << "drew." << endl;
	return 0;
}
bool wins1() {//纯打表判断输赢qwq
	if (qipan[0][0] == 1 && qipan[0][0] == qipan[0][1] && qipan[0][1] == qipan[0][2]) {
		return 1;
	}
	else if (qipan[1][0] == 1 && qipan[1][0] == qipan[1][1] && qipan[1][1] == qipan[1][2]) {
		return 1;
	}
	else if (qipan[2][0] == 1 && qipan[2][0] == qipan[2][1] && qipan[2][1] == qipan[2][2]) {
		return 1;
	}
	else if (qipan[0][0] == 1 && qipan[1][0] == qipan[2][0] && qipan[2][0] == qipan[0][0]) {
		return 1;
	}
	else if (qipan[0][1] == 1 && qipan[1][1] == qipan[2][1] && qipan[2][1] == qipan[0][1]) {
		return 1;
	}
	else if (qipan[0][2] == 1 && qipan[1][2] == qipan[2][2] && qipan[2][2] == qipan[0][2]) {
		return 1;
	}
	else if (qipan[0][0] == 1 && qipan[0][0] == qipan[1][1] && qipan[1][1] == qipan[2][2]) {
		return 1;
	}
	else if (qipan[0][2] == qipan[1][1] && qipan[0][2] == 1 && qipan[1][1] == qipan[2][0]) {
		return 1;
	}
	else {
		return 0;
	}
}
bool wins2() {
	if (qipan[0][0] == -1 && qipan[0][0] == qipan[0][1] && qipan[0][1] == qipan[0][2]) {
		return 1;
	}
	else if (qipan[1][0] == -1 && qipan[1][0] == qipan[1][1] && qipan[1][1] == qipan[1][2]) {
		return 1;
	}
	else if (qipan[2][0] == -1 && qipan[2][0] == qipan[2][1] && qipan[2][1] == qipan[2][2]) {
		return 1;
	}
	else if (qipan[0][0] == -1 && qipan[1][0] == qipan[2][0] && qipan[2][0] == qipan[0][0]) {
		return 1;
	}
	else if (qipan[0][1] == -1 && qipan[1][1] == qipan[2][1] && qipan[2][1] == qipan[0][1]) {
		return 1;
	}
	else if (qipan[0][2] == -1 && qipan[1][2] == qipan[2][2] && qipan[2][2] == qipan[0][2]) {
		return 1;
	}
	else if (qipan[0][0] == -1 && qipan[0][0] == qipan[1][1] && qipan[1][1] == qipan[2][2]) {
		return 1;
	}
	else if (qipan[0][2] == qipan[1][1] && qipan[0][2] == -1 && qipan[1][1] == qipan[2][0]) {
		return 1;
	}
	else {
		return 0;
	}
}

经过分析后简化的逻辑判断​​:https://www.codecopy.cn/post/vd7nj5(作者:Jason)

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=60;
signed main(){
	string n;//用字符串来存输入方便访问
    cin>>n;
	int q[10]={0};//记录下棋位置的数组(注意要开10才能存1-9)
	if(n.size()==9){
        //将小a下的棋存入数组
		for(int i=0;i<n.size();i+=2){
			q[n[i]-'0']=1;//注意字符串转整形
		}
        //判断是否满足三子连线的8个情况
		if((q[1]==q[2]&&q[2]==q[3])||(q[4]==q[5]&&q[5]==q[6])||(q[7]==q[8]&&q[8]==q[9])||(q[1]==q[4]&&q[4]==q[7])||(q[2]==q[5]&&q[5]==q[8])||(q[3]==q[6]&&q[6]==q[9])||(q[1]==q[5]&&q[5]==q[9])||(q[3]==q[5]&&q[5]==q[7])){
			cout<<"xiaoa wins."<<endl;
			return 0;
		}
		cout<<"drew."<<endl;
		return 0;
	}
    //下了奇数步(不为9)
	if(n.size()%2!=0){
		cout<<"xiaoa wins."<<endl;
		return 0;
	}
    //剩下的就是偶数步棋
	cout<<"uim wins."<<endl;
	return 0;
}

留下评论

您的邮箱地址不会被公开。 必填项已用 * 标注