方格游戏

目录

〇,前言

一,数据建模

1,名词澄清

2,块的表示

3,块的初始化

4,玩家数据

5,玩家初始化

二,界面

1,方格输出

2,游戏界面

三,游戏规则

1,翻转和旋转

2,核心逻辑、结束控制

3,主控程序

4,玩家操作

四,完整代码

五,规则对比


〇,前言

因为是一边设计一边写代码一边写博客,所以本文的中间代码很多都不是最新版本,

代码以最终完整版为准。

一,数据建模

1,名词澄清

一个玩家有21个块,每个块由1-5个格子组成。

2,块的表示

对每个块,用最多5个点把每个格子的坐标存起来

typedef struct Point
{
    int x,y;
}Point;

typedef struct Node
{
    int num;
    Point p[5];
}Node;

那么,如何建立坐标系呢?

对每个块拓展为它的凸包,并把最左上角的快设为(0,0)那么所有格子的坐标都是2个非负整数组成。

实际上,除了十字交叉的块之外,其他20个块都可以适当的旋转和翻转,使得它的凸包的最左上角的点上有一个格子。

int num[]={5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,3,5,4,3,2,1};
int matrix[]={
        0,0,0,1,0,2,1,1,2,1,
        0,0,1,0,1,1,1,2,2,1,
        0,0,1,0,1,1,1,2,2,2,
        0,1,1,0,1,1,1,2,2,1,
        0,0,0,1,1,1,1,2,2,2,
        0,0,0,1,0,2,1,2,2,2,
        0,0,0,1,0,2,1,2,1,3,
        0,0,0,1,0,2,0,3,1,2,
        0,0,0,1,0,2,0,3,1,3,
        0,0,0,1,0,2,1,0,1,2,
        0,0,0,1,0,2,1,0,1,1,
        0,0,0,1,1,0,1,1,
        0,0,0,1,0,2,1,0,
        0,0,0,1,1,1,1,2,
        0,0,0,1,0,2,1,1,
        0,0,0,1,1,0,
        0,0,0,1,0,2,0,3,0,4,
        0,0,0,1,0,2,0,3,
        0,0,0,1,0,2,
        0,0,0,1,
        0,0,
};

对应代码,有20行都是0,0开头,只有一行不是。

3,块的初始化

void init()
{
    int p=0;
    for(int i=0;i<21;i++){
        node[i].num=num[i];
        for(int j=0;j<num[i];j++)node[i].p[j]={matrix[p],matrix[p+1]},p+=2;
    }
}

4,玩家数据

typedef struct Node
{
    int id;
    int num;
    Point p[5];
    bool flag; //=1表示手里还有,=0表示已经用掉了
}Node;

Node node[4][21]; //四个玩家

5,玩家初始化

void initNode(Node* node)
{
    int p=0;
    for(int i=0;i<21;i++){
        node[i].id=i,node[i].num=num[i],node[i].flag=1;
        for(int j=0;j<num[i];j++)node[i].p[j]={matrix[p],matrix[p+1]},p+=2;
    }
}

void init()
{
    for(int i=0;i<4;i++)initNode(node[i]);
}

二,界面

1,方格输出

只输出当前玩家的所有块,每5个一行

void outNode(int num,Node node[])
{
    int x[3][30];
    for(int j=0;j<3;j++)for(int k=0;k<30;k++)x[j][k]=0;
    for(int i=0;i<num;i++){
        for(int j=0;j<node[i].num;j++)x[node[i].p[j].x][node[i].p[j].y+i*6]=1;
    }
    for(int i=0;i<num;i++)cout<<setw(2)<<node[i].id<<"    ";
    cout<<endl;
    for(int j=0;j<3;j++) {
        for (int k = 0; k < 30; k++) {
            if (x[j][k])cout << "Y";
            else cout << " ";
        }
        cout<<endl;
    }
    cout<<endl;
}

void outNode(Node* node)
{
    int s=0;
    Node nod[5];
    for(int i=0;i<21;i++){
        if(node[i].flag==0)continue;
        nod[s++]=node[i];
        if(s==5){
            s=0;
            outNode(5,nod);
        }
    }
    if(s)outNode(s,nod);
}

运行:

2,游戏界面

复用我五子棋的界面程序 五子棋人机对战完整代码_nameofcsdn的博客-CSDN博客_五子棋代码

void out(int i, int j)
{
    if (p[i][j])cout<< col[p[i][j]];
    else if (i == 1)
    {
        if (j == 1)printf("┏");
        else if (j == N)printf("┓");
        else printf("┯");
    }
    else if (i == N)
    {
        if (j == 1)printf("┗");
        else if (j == N)printf("┛");
        else printf("┷");
    }
    else if (j == 1)printf("┠");
    else if (j == N)printf("┨");
    else printf("┼");
}

void DrawBoard(int turn)//画棋盘
{
    system("cls");
    int row = 0, col = 0;
    char alpha = 'A';
    printf("\n\n\n     ");
    for (col = 1; col <= N; col++)printf("%c ", alpha++);
    for (row = 1; row <= N; row++) {
        printf("\n   %2d", row);
        for (col = 1; col <= N; col++) {
            out(row, col);
        }
        printf("%d", row);
    }
    cout << endl;
    outNode(node[turn]);
}

三,游戏规则

1,翻转和旋转

每个块都可以翻转、旋转

void reverse(Node &node)//翻转块
{
    for(int i=0;i<node.num;i++){
        int tmp=node.p[i].x;
        node.p[i].x=node.p[i].y,node.p[i].y=tmp;
    }
}
void rotate(Node &node)//旋转块
{
    for(int i=0;i<node.num;i++){
        int tmp=4-node.p[i].x;
        node.p[i].x=node.p[i].y,node.p[i].y=tmp;
    }
}
void rotate(Node &node,int n)//旋转块
{
    if(n<=0||n>3)return;
    while(n--)rotate(node);
}

考虑到旋转之后的样子,把输出块的代码改了

void outNode(int num,Node node[])
{
    int x[5][30];
    for(int j=0;j<5;j++)for(int k=0;k<30;k++)x[j][k]=0;
    for(int i=0;i<num;i++){
        for(int j=0;j<node[i].num;j++)x[node[i].p[j].x][node[i].p[j].y+i*6]=1;
    }
    for(int i=0;i<num;i++)cout<<setw(2)<<node[i].id<<"    ";
    cout<<endl;
    for(int j=0;j<5;j++) {
        for (int k = 0; k < 30; k++) {
            if (x[j][k])cout << "Y";
            else if(k%6==5)cout<<" ";
            else cout<<".";
        }
        cout<<endl;
    }
    cout<<endl;
}

2,核心逻辑、结束控制

int isEnd[4];//=0表示还在继续,=1表示玩家已经不能再放了

bool end()
{
    return isEnd[0]+isEnd[1]+isEnd[2]+isEnd[3]==4;
}

采用简单粗暴的方式,让玩家自己上报已经不能放了这个信号。

bool play(int turn)
{
    DrawBoard();
    cout<<"输入操作类型:0结束,1翻转,2旋转,3放方格";
    int op;
    CIN(op);
    if(op<0||op>3)return false;
    //
}

3,主控程序

int main() {
    init();
    turn=-1;
    while(!end()){
        turn=(turn+1)%4;
        if(isEnd[turn])continue;
        while(!play(turn));
    }
    return 0;
}

4,玩家操作

bool op0(int turn)
{
    isEnd[turn]=0;
    return true;
}

bool op1(int turn,int id)
{
    reverse(node[turn][id]);
    return false;
}

bool op2(int turn,int id)
{
    cout<<"输入顺时针旋转次数1-3";
    int num;
    CIN(num);
    rotate(node[turn][id],num);
    return false;
}

bool check(int turn,int id,int r,int c)
{
    return true; // 待更新,不更新也能玩
}
bool op3(int turn,int id)
{
    cout<<"输入最左上角的格子放入棋盘的坐标\n";
    int r,c;
    CIN2(r,c);
    if(!check(turn,id,r,c))return false;
    Node *pn=&node[turn][id];
    for(int i=0;i<pn->num;i++){
        p[r+pn->p[i].x][c+pn->p[i].y]=turn;
    }
    return true;
}

更新play函数:

bool play(int turn)
{
    DrawBoard();
    cout << "输入操作类型:0结束,1翻转方格,2旋转方格,3放方格";
    int op, id;
    CIN(op);
    if (op < 0 || op>3)return false;
    if (op == 0)return op0(turn);
    cout << "输入要操作的方格编号";
    CIN(id);
    if (id < 0 || id >= 21)return false;
    if (op == 1)return op1(turn, id);
    if (op == 2)return op2(turn, id);
    if (op == 3)return op3(turn, id);
    return false;
}

四,完整代码


#include<iostream>
#include<iomanip>
#include<windows.h>
using namespace std;

typedef struct Point
{
    int x, y;
}Point;

typedef struct Node
{
    int id;
    int num;
    Point p[5];
    bool flag; //=1表示手里还有,=0表示已经用掉了
}Node;

Node node[4][21]; //四个玩家
int turn; //0-3,对应蓝黄红绿
string col[4] = { " B"," Y"," R"," G" }; //蓝黄红绿
char ccol[4] = { 'B','Y','R','G' };
const int N = 20;
int p[22][22];//棋盘是20*20
int isEnd[4];//=0表示还在继续,=1表示玩家已经不能再放了

int num[] = { 5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,3,5,4,3,2,1 };
int matrix[] = {
        0,0,0,1,0,2,1,1,2,1,
        0,0,1,0,1,1,1,2,2,1,
        0,0,1,0,1,1,1,2,2,2,
        0,1,1,0,1,1,1,2,2,1,
        0,0,0,1,1,1,1,2,2,2,
        0,0,0,1,0,2,1,2,2,2,
        0,0,0,1,0,2,1,2,1,3,
        0,0,0,1,0,2,0,3,1,2,
        0,0,0,1,0,2,0,3,1,3,
        0,0,0,1,0,2,1,0,1,2,
        0,0,0,1,0,2,1,0,1,1,
        0,0,0,1,1,0,1,1,
        0,0,0,1,0,2,1,0,
        0,0,0,1,1,1,1,2,
        0,0,0,1,0,2,1,1,
        0,0,0,1,1,0,
        0,0,0,1,0,2,0,3,0,4,
        0,0,0,1,0,2,0,3,
        0,0,0,1,0,2,
        0,0,0,1,
        0,0,
};

void initNode(Node* node)
{
    int p = 0;
    for (int i = 0; i < 21; i++) {
        node[i].id = i, node[i].num = num[i], node[i].flag = 1;
        for (int j = 0; j < num[i]; j++)node[i].p[j] = { matrix[p],matrix[p + 1] }, p += 2;
    }
}

void init()
{
    for (int i = 0; i < 4; i++) {
        initNode(node[i]);
        isEnd[i] = 0;
    }
}

void outNode(int num, Node node[])
{
    int x[5][66];
    for (int j = 0; j < 5; j++)for (int k = 0; k < 66; k++)x[j][k] = 0;
    for (int i = 0; i < num; i++) {
        for (int j = 0; j < node[i].num; j++)x[node[i].p[j].x][node[i].p[j].y + i * 6] = 1;
    }
    for (int i = 0; i < num; i++)cout << setw(2) << node[i].id << "    ";
    cout << endl;
    for (int j = 0; j < 5; j++) {
        for (int k = 0; k < 66; k++) {
            if (x[j][k])cout << ccol[turn];
            else if (k % 6 == 5)cout << " ";
            else cout << ".";
        }
        cout << endl;
    }
    cout << endl;
}

void outNode(Node* node)
{
    int s = 0;
    Node nod[11];
    for (int i = 0; i < 21; i++) {
        if (node[i].flag == 0)continue;
        nod[s++] = node[i];
        if (s == 11) {
            outNode(s, nod);
            s = 0;
        }
    }
    if (s)outNode(s, nod);
}

void out(int i, int j)
{
    if (p[i][j])cout<<col[p[i][j]-1];
    else if (i == 1)
    {
        if (j == 1)printf("┏");
        else if (j == N)printf("┓");
        else printf("┯");
    }
    else if (i == N)
    {
        if (j == 1)printf("┗");
        else if (j == N)printf("┛");
        else printf("┷");
    }
    else if (j == 1)printf("┠");
    else if (j == N)printf("┨");
    else printf("┼");
}

void DrawBoard()//画棋盘
{
    system("cls");
    int row = 0, col = 0;
    char alpha = 'A';
    printf("     ");
    for (col = 1; col <= N; col++)printf("%2d", col);
    for (row = 1; row <= N; row++) {
        printf("\n   %2d", row);
        for (col = 1; col <= N; col++) {
            out(row, col);
        }
        printf("%d", row);
    }
    printf("\n     ");
    for (col = 1; col <= N; col++)printf("%2d", col);
    cout << endl;
    outNode(node[turn]);
}

void reverse(Node& node)//翻转块
{
    for (int i = 0; i < node.num; i++) {
        int tmp = node.p[i].x;
        node.p[i].x = node.p[i].y, node.p[i].y = tmp;
    }
}
void rotate(Node& node)//旋转块
{
    for (int i = 0; i < node.num; i++) {
        int tmp = 4 - node.p[i].x;
        node.p[i].x = node.p[i].y, node.p[i].y = tmp;
    }
}
void rotate(Node& node, int n)//旋转块
{
    if (n <= 0 || n > 3)return;
    while (n--)rotate(node);
}


#define CIN(x) while (!(cin >> x)) { \
        cin.clear();      \
        cin.ignore();     \
    }
#define CIN2(x, y) CIN(x)CIN(y)
#define CIN3(x, y, z) CIN(x)CIN(y)CIN(z)

bool op0()
{
    isEnd[turn] = 0;
    return true;
}

bool op1(int id)
{
    reverse(node[turn][id]);
    return false;
}

bool op2(int id)
{
    cout << "输入顺时针旋转次数1-3\n";
    int num;
    CIN(num);
    rotate(node[turn][id], num);
    return false;
}

bool check(int id, int r, int c, Node* pn)
{
    //if (r < 1 || r>20 || c < 1 || c>20)return false;
    for (int i = 0; i < pn->num; i++) {
        int tr = r + pn->p[i].x,tc= c + pn->p[i].y;
        if (tr < 1 || tr>20 || tc < 1 || tc>20 || p[tr][tc])return false;
    }
    return true;
}

bool op3(int id)
{
    cout << "输入最左上角的格子放入棋盘的坐标(行,列)\n";
    int r, c;
    CIN2(r, c);
    Node* pn = &node[turn][id];
    if (!check(id, r, c, pn))return false;
    for (int i = 0; i < pn->num; i++) {
        p[r + pn->p[i].x][c + pn->p[i].y] = turn + 1;
    }
    pn->flag = 0;
    return true;
}

bool play()
{
    DrawBoard();
    cout << "输入操作类型:0结束,1翻转方格,2旋转方格,3放方格\n";
    int op, id;
    CIN(op);
    if (op < 0 || op>3)return false;
    if (op == 0)return op0();
    cout << "输入要操作的方格编号\n";
    CIN(id);
    if (id < 0 || id >= 21)return false;
    if (op == 1)return op1(id);
    if (op == 2)return op2(id);
    if (op == 3)return op3(id);
    return false;
}

bool end()
{
    return isEnd[0] + isEnd[1] + isEnd[2] + isEnd[3] == 4;
}

void p415()
{
    cout << endl;
    cout << "  .....      ..  \n"
            "    .       .  .\n"
            "    .       .  . \n"
            "    .        ..  \n";
    cout << "\n\n\n";
    cout << "    |        /  | \n"
            "  / | \\     / —|——\n"
            " /  |  \\   /——|———\n"
            "   \\|           | \n";
    Sleep(5000);
}

int main() {
    p415();
    init();
    turn = -1;
    while (!end()) {
        turn = (turn + 1) % 4;
        if (isEnd[turn])continue;
        while (!play());
    }
    return 0;
}

五,规则对比

这个程序比较简陋,对于用户输入的放方格的位置,我做的校验是保证放的格子都没有超出棋盘位置,也不会发生覆盖。

但是没有校验放的位置必须和同色格子点邻,不能边邻,第一个放的必须包含最角落的那个格子。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 舒尔特方格游戏是一款经典的记忆力训练游戏,通过展示一系列方格并要求玩家按照展示的顺序点击相应的方格,来测试玩家的记忆力。 在Java语言中,使用Android Studio开发这款游戏的实现思路如下: 1. 创建项目和界面:在Android Studio中创建一个新的Android项目,并设计游戏界面。界面中通常包含一系列方格按钮,并提供开始按钮和用户提示的文本框。 2. 生成随机序列:为了生成游戏的随机序列,可以使用Java的随机数生成方法。根据游戏难度,随机生成一定长度的序列,例如5个方格,可以用一个数组存储生成的序列。 3. 展示方格游戏开始后,根据生成的随机序列,逐个展示方格。可以使用按钮的背景色、透明度或者其他视觉效果来展示方格。展示方格时可以使用定时器等机制来延时展示每个方格。 4. 用户输入验证:用户在展示方格后可以点击方格按钮,通过监听按钮点击事件来获取用户的输入。用户输入后,需要与生成的随机序列进行比较,验证是否正确。 5. 增加游戏难度:随着游戏的进行,可以逐渐增加难度,例如增加方格的数量或者缩短方格展示的时间间隔,以增加游戏的挑战性。 6. 记录分数和排行榜:可以通过变量记录用户的分数,并与之前的最高分进行比较,将最高分存储在本地数据库中,用于排行榜的展示。 7. 重置游戏:在游戏结束后,可以提供重新开始的按钮,重置游戏状态,重新生成随机序列并开始新一轮游戏。 总之,通过设计合理的界面,利用Android Studio提供的界面绘制和事件监听功能,配合使用Java语言的随机数生成和比较功能,可以实现舒尔特方格游戏的开发。 ### 回答2: 舒尔特方格游戏的实现一般可以分为以下几个步骤: 1. 创建游戏界面:使用Android Studio创建一个Android项目,并设计游戏界面。可以使用XML布局文件创建各种游戏元素,如方格、按钮等。 2. 生成游戏区域:在游戏界面中创建一个游戏区域(格子矩阵),可以使用GridLayout或自定义View来实现。游戏区域的大小可以根据需要进行调整。 3. 随机生成数字:在游戏开始时,需要随机生成一定数量的数字(一般为2或者4)放置在游戏区域的空白格子中。可以使用随机数生成算法来实现。 4. 监听滑动事件:通过监听手势滑动事件,获取玩家的滑动方向(上、下、左、右)。可以使用GestureDetector类来监听滑动事件。 5. 移动方块:根据滑动方向,判断每行或每列中的数字方块是否可以向该方向移动,如果可以,则移动方块并合并相等的方块。移动和合并过程可以通过数组操作来实现。 6. 更新界面显示:每次移动后,需要更新界面显示,将移动后的方块位置和数字更新到游戏界面中。可以通过修改相应格子的背景颜色和数字显示来实现。 7. 判断游戏结束:在每次移动后,判断是否还有空白格子可供生成新的数字方块,如果没有,则判断是否还有相邻的方块可合并,如果没有,则判断游戏结束。可以通过遍历格子矩阵来判断。 8. 实现撤销功能:可以记录每次滑动前的游戏状态,以实现撤销功能。可以通过保存游戏状态的数组或者链表来实现。 通过以上步骤,我们可以实现一个简单的舒尔特方格游戏。当然,还可以根据实际需求进行优化和扩展,如添加动画效果、增加计分系统、设置难度级别等。 ### 回答3: 舒尔特方格游戏是一个经典的记忆力训练游戏,可以通过Java和Android Studio来实现。 首先,我们需要创建一个Android项目,在Android Studio中打开,并准备一个空白的Activity页面来容纳游戏界面。 在布局文件中,我们可以使用一个GridView来展示舒尔特方格。可以根据游戏难度设置方格的行列数,以及每个方格的宽高等。 接下来,我们需要创建一个Adapter类来管理GridView中展示的方格。Adapter类需要继承自BaseAdapter,并实现相关的方法,如getItem()、getView()等。 在Adapter类中,我们可以定义一个数据结构来保存方格的信息,例如每个方格的位置、颜色、是否被点击等。可以使用二维数组或者List来保存方格的数据。 在getView()方法中,我们可以根据方格的信息来展示对应的颜色、显示是否被点击等。 在Activity中,我们可以通过点击方格来实现游戏的交互。可以为GridView设置点击事件监听器,当方格被点击时,可以根据方格的位置来判断是否是正确的点击顺序,若是则继续游戏,否则游戏结束。 此外,我们还可以添加计时器来限制游戏时间,以及记录游戏分数等功能。 整个舒尔特方格游戏的实现主要是通过GridView展示方格,并使用Adapter来管理方格的数据和展示。通过方格的点击事件和逻辑判断来实现游戏的交互和结束判定。利用Android Studio的开发环境,我们可以轻松地进行游戏的布局、代码编写和调试。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值