出处
洛谷-P1838 三子棋I:https://www.luogu.com.cn/problem/P1838
题目描述
小 a 和 uim 喜欢互相切磋三子棋。三子棋大家都玩过是吗?就是在九宫格里面 OOXX(别想歪了),谁连成 3 个就赢了。
由于小 a 比较愚蠢,uim 总是让他先。
我们用 9 个数字表示棋盘位置:
| 1 | 2 | 3 |
| 4 | 5 | 6 |
| 7 | 8 | 9 |
所有的棋谱都是已经结束的棋局,要么一方获胜,要么平局。
今天,他们下了一下午的棋,小 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表示无人获胜。
关键点说明
- 棋盘表示:使用简单的3×3数组,0表示空,1和-1分别表示两位玩家。
- 输入处理:将数字1-9转换为二维坐标(x, y)。
- 交替落子:通过步数奇偶性决定当前玩家。
- 胜负判断:检查所有可能的连线情况(3行、3列、2对角线)。
- 游戏终止:一旦有玩家获胜立即结束游戏,或者棋盘填满后也无玩家获胜宣布平局。
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;
}
