俄罗斯方块(C++大作业)

源代码

效果图:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<vector>
#include<fstream>
#include <windows.h>
#include <conio.h>
#include<string>

using namespace std;

struct ColorData
{
    short color[2];
};

struct MatrixData
{
    bool data[4][4];
};

struct Block
{
    ColorData color;
    MatrixData matrix[4];
}block[7];

struct currentBlock
{
    int x, y;
    short type;
    int dir;
}curBlock, preBlock;

short  ground[10][21];
int score, line, burn, level = 6;
short nextBlocks[7], nextBlockI;
string wideNumbers[10] = { "0","1","2","3","4","5","6","7","8","9" };
short speed[20] = { 800,716,633,550,466,383,300,216,133,100,84,83,83,67,67,66,50,50,50,33 };
short linesForLevels[20] = { 0,0,0,0,0,0,5,15,15,20,20,20,20,20,20,20,25,30,35 };
//short linesForLevels[20] = {10,20,30,40,50,60,70,80,90,100,100,100,100,100,100,100,110,120,130};

//
short wallKickData[4/*四个初始方向*/][2/*两个旋转方向*/][4/*四个Test*/][2/* x,y坐标 */] =
{
        {   //0
                {{-1,0},{-1,-1},{0,2},{-1,2}},  //R
                {{1,0},{1,-1},{0,2},{1,2}}   //L
        },
        {   //R
                {{1,0},{1,1},{0,-2},{1,-2}},  //2
                {{1,0},{1,1},{0,-2},{1,-2}}   //0
        },
        {   //2
                {{1,0},{1,-1},{0,2},{1,2}},  //L
                {{-1,0},{-1,-1},{0,2},{-1,2}}   //R
        },
        {   //L
                {{-1,0},{-1,1},{0,-2},{-1,-2}},  //0
                {{-1,0},{-1,1},{0,-2},{-1,-2}}   //2
        }
};

short wallKickDataOfI[4/*四个初始方向*/][2/*两个旋转方向*/][4/*四个Test*/][2/* x,y坐标 */] =
{
        {   //0
                {{-2,0},{1,0},{-2,1},{1,-2}},  //R
                {{-1,0},{2,0},{-1,-2},{2,1}}   //L
        },
        {   //R
                {{-1,0},{2,0},{-1,-2},{2,1}},  //2
                {{2,0},{-1,0},{2,-1},{-1,2}}   //0
        },
        {   //2
                {{2,0},{-1,0},{2,-1},{-1,2}},  //L
                {{1,0},{-2,0},{1,2},{-2,-1}}   //R
        },
        {   //L
                {{1,0},{-2,0},{1,2},{-2,-1}},  //0
                {{-2,0},{1,0},{-2,1},{1,-2}}   //2
        }
};


int getRand(int mini, int maxi)
{
    return rand() % (maxi - mini + 1) + mini;
}

void go(float x, float y) //光标移动函数,x表示横坐标,y表示纵坐标。
{
    COORD coord;         //使用头文件自带的坐标结构
    coord.X = x * 2 + 2;            //这里将int类型值传给short,不过程序中涉及的坐标值均不会超过short范围
    coord.Y = y + 1;
    HANDLE a = GetStdHandle(STD_OUTPUT_HANDLE);  //获得标准输出句柄
    SetConsoleCursorPosition(a, coord);         //以标准输出的句柄为参数设置控制台光标坐标
}
void color(int a)//设定颜色的函数
{
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), a);
}//黑 深蓝 深绿 浅蓝  红  深紫  土黄 浅灰 深灰 亮蓝 亮绿  最淡的蓝 桃红 浅紫  米黄  白


void pre()
{
    score = line = burn = 0;
    level = 6;
    memset(ground, 0, sizeof(ground));

    system("mode con cols=48 lines=28");
    system("cls");
    color(15);
    CONSOLE_CURSOR_INFO cursor_info = { 1,0 };
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);//隐藏光标

    block[0].color = { 179,48 };
    block[0].matrix[0] =
    {
            0,0,0,0,
            1,1,1,1,
            0,0,0,0,
            0,0,0,0
    };
    block[0].matrix[1] =
    {
            0,0,1,0,
            0,0,1,0,
            0,0,1,0,
            0,0,1,0
    };
    block[0].matrix[2] =
    {
            0,0,0,0,
            0,0,0,0,
            1,1,1,1,
            0,0,0,0
    };
    block[0].matrix[3] =
    {
            0,1,0,0,
            0,1,0,0,
            0,1,0,0,
            0,1,0,0
    };  //I


    block[1].color = { 230,96 };
    block[1].matrix[0] =
    {
            0,1,1,0,
            0,1,1,0,
            0,0,0,0,
            0,0,0,0
    };
    block[1].matrix[1] =
    {
            0,1,1,0,
            0,1,1,0,
            0,0,0,0,
            0,0,0,0
    };
    block[1].matrix[2] =
    {
            0,1,1,0,
            0,1,1,0,
            0,0,0,0,
            0,0,0,0
    };
    block[1].matrix[3] =
    {
            0,1,1,0,
            0,1,1,0,
            0,0,0,0,
            0,0,0,0
    };  //O

    block[2].color = { 162,32 };
    block[2].matrix[0] =
    {
            0,0,1,1,
            0,1,1,0,
            0,0,0,0,
            0,0,0,0
    };
    block[2].matrix[1] =
    {
            0,0,1,0,
            0,0,1,1,
            0,0,0,1,
            0,0,0,0
    };
    block[2].matrix[2] =
    {
            0,0,0,0,
            0,0,1,1,
            0,1,1,0,
            0,0,0,0
    };
    block[2].matrix[3] =
    {
            0,1,0,0,
            0,1,1,0,
            0,0,1,0,
            0,0,0,0
    };  //S

    block[3].color = { 196,64 };
    block[3].matrix[0] =
    {
            0,1,1,0,
            0,0,1,1,
            0,0,0,0,
            0,0,0,0
    };
    block[3].matrix[1] =
    {
            0,0,0,1,
            0,0,1,1,
            0,0,1,0,
            0,0,0,0
    };
    block[3].matrix[2] =
    {
            0,0,0,0,
            0,1,1,0,
            0,0,1,1,
            0,0,0,0
    };
    block[3].matrix[3] =
    {
            0,0,1,0,
            0,1,1,0,
            0,1,0,0,
            0,0,0,0
    };  //Z

    block[4].color = { 120,128 };
    block[4].matrix[0] =
    {
            0,0,0,1,
            0,1,1,1,
            0,0,0,0,
            0,0,0,0
    };
    block[4].matrix[1] =
    {
            0,0,1,0,
            0,0,1,0,
            0,0,1,1,
            0,0,0,0
    };
    block[4].matrix[2] =
    {
            0,0,0,0,
            0,1,1,1,
            0,1,0,0,
            0,0,0,0
    };
    block[4].matrix[3] =
    {
            0,1,1,0,
            0,0,1,0,
            0,0,1,0,
            0,0,0,0
    };  //L


    block[5].color = { 49,16 };

    block[5].matrix[0] =
    {
            0,1,0,0,
            0,1,1,1,
            0,0,0,0,
            0,0,0,0
    };
    block[5].matrix[1] =
    {
            0,0,1,1,
            0,0,1,0,
            0,0,1,0,
            0,0,0,0
    };
    block[5].matrix[2] =
    {
            0,0,0,0,
            0,1,1,1,
            0,0,0,1,
            0,0,0,0
    };
    block[5].matrix[3] =
    {
            0,0,1,0,
            0,0,1,0,
            0,1,1,0,
            0,0,0,0
    };  //J

    block[6].color = { 213,80 };
    block[6].matrix[0] =
    {
            0,0,1,0,
            0,1,1,1,
            0,0,0,0,
            0,0,0,0
    };
    block[6].matrix[1] =
    {
            0,0,1,0,
            0,0,1,1,
            0,0,1,0,
            0,0,0,0
    };
    block[6].matrix[2] =
    {
            0,0,0,0,
            0,1,1,1,
            0,0,1,0,
            0,0,0,0
    };
    block[6].matrix[3] =
    {
            0,0,1,0,
            0,1,1,0,
            0,0,1,0,
            0,0,0,0
    };  //T


    unsigned seed = time(0);
    srand(seed);//设置随机数种子

    /*以下为界面打印*/

    go(0.5, 0);
    printf(" ━━━━━━━━━━━━━━━━━ \n");
    go(0.5, 1);
    printf("┃    SCORE   ┃\n");
    go(0.5, 2);
    printf("┃            ┃\n");
    go(0.5, 3);
    printf(" ━━━━━━━━━━━━━━━━━ \n");

    go(0, 4);
    printf("□□□□□□□□□□□□     ==NEXT==\n"
        "  □                    □    |        |\n"
        "  □                    □    |        |\n"
        "  □                    □     ========\n"
        "  □                    □\n"
        "  □                    □\n"
        "  □                    □  LINE\n"
        "  □                    □\n"
        "  □                    □  BURN\n"
        "  □                    □\n"
        "  □                    □  LEVEL\n"
        "  □                    □\n"
        "  □                    □  ================\n"
        "  □                    □ |[↑][X]rotate cw|\n"
        "  □                    □ |[Ctrl][Z]rot ccw|\n"
        "  □                    □ |[←][→]move L/R|\n"
        "  □                    □ |[↓]NL soft drop|\n"
        "  □                    □ |[Sp]L hard drop |\n"
        "  □                    □ |                |\n"
        "  □                    □ |按任意键开始游戏|\n"
        "  □                    □  ================\n"
        "  □□□□□□□□□□□□");
}

void clearImfBar()
{
    color(15);
    for (int i = 17; i <= 23; i++)
    {
        go(13, i);
        printf("                ");
    }
}

void printScore()
{
    color(10);
    int a = score;
    for (int i = 0; i < 6; i++)
    {
        go(7.5 - i, 2);
        cout << wideNumbers[a % 10];
        a /= 10;
    }
    color(15);
};

void printLine()
{
    color(11);
    go(18, 10);
    cout << wideNumbers[line / 100] << wideNumbers[line / 10 % 10] << wideNumbers[line % 10];
    color(15);
}

void printBurn()
{
    color(11);
    go(18, 12);
    cout << wideNumbers[burn / 100] << wideNumbers[burn / 10 % 10] << wideNumbers[burn % 10];
    color(15);
}

void printLevel()
{
    color(11);
    go(19, 14);
    cout << wideNumbers[level / 10] << wideNumbers[level % 10];
    color(15);
}
void printBlock(int mode, currentBlock block1)
{
    if (mode == 1)
        color(block[block1.type].color.color[0]);
    else if (mode == 2)
        color(block[block1.type].color.color[1]);
    else
        color(15);

    for (int i = 0; i < 4; i++)
        for (int j = 0; j < 4; j++)
            if (block[block1.type].matrix[block1.dir].data[i][j] && block1.y + i >= 0 && !ground[block1.x + j][block1.y + i])
            {
                go(j + block1.x + 1, 5 + i + block1.y);
                if (mode)
                {
                    printf("■");
                }
                else
                {
                    printf("  ");
                }
            }
    color(15);
}

bool wallHittingCheck(int x, int y, currentBlock block1)
{
    for (int i = 0; i < 4; i++)
        for (int j = 0; j < 4; j++)
            if (block[block1.type].matrix[block1.dir].data[i][j] && y + i >= 0)
                if (ground[x + j][y + i] || x + j < 0 || x + j > 9 || y + i > 19)
                    return true;
    return false;
}

void getRandomBlocks(bool itIsTheFirstBlock)
{
    for (int i = 0; i < 7; i++)
        nextBlocks[i] = i;

    int times = getRand(0, 9);
    for (int i = 0; i < times; i++)
        swap(nextBlocks[getRand(0, 6)], nextBlocks[getRand(0, 6)]);

    if (itIsTheFirstBlock && nextBlocks[0] >= 1 && nextBlocks[0] <= 3)
        getRandomBlocks(true);
}

bool land()
{
    for (int i = 3; i >= 0; i--)
        for (int j = 0; j < 4; j++)
            if (block[curBlock.type].matrix[curBlock.dir].data[i][j])
            {
                if (curBlock.y + i < 0)
                    return true;
                ground[curBlock.x + j][curBlock.y + i] = curBlock.type + 1;
            }
    return false;
}

void printTheNextBlock()
{
    int ki = 0, kj = 0;
    if (block[nextBlocks[nextBlockI]].matrix[0].data[0][0] + block[nextBlocks[nextBlockI]].matrix[0].data[1][0] + block[nextBlocks[nextBlockI]].matrix[0].data[2][0] + block[nextBlocks[nextBlockI]].matrix[0].data[3][0] == 0)
        kj++;
    if (block[nextBlocks[nextBlockI]].matrix[0].data[0][0] + block[nextBlocks[nextBlockI]].matrix[0].data[0][1] + block[nextBlocks[nextBlockI]].matrix[0].data[0][2] + block[nextBlocks[nextBlockI]].matrix[0].data[0][3] == 0)
    {
        ki++;
        if (block[nextBlocks[nextBlockI]].matrix[0].data[1][0] + block[nextBlocks[nextBlockI]].matrix[0].data[1][1] + block[nextBlocks[nextBlockI]].matrix[0].data[1][2] + block[nextBlocks[nextBlockI]].matrix[0].data[1][3] == 0)
            ki++;
    }

    color(15);
    for (int i = 0; i < 2; i++)
        for (int j = 0; j < 4; j++)
        {
            go(14.5 + j, 5 + i);
            printf("  ");
        }

    color(block[nextBlocks[nextBlockI]].color.color[0]);
    for (int i = ki; i < ki + 2; i++)
        for (int j = kj; j < 4; j++)
            if (block[nextBlocks[nextBlockI]].matrix[0].data[i][j])
            {
                go((nextBlocks[nextBlockI] == 1 ? 15 : 14.5) + j - (kj / 2.0), 5 + i - ki);
                printf("■");
            }
    color(15);
}

void preview()
{
    if (preBlock.dir != -1)
        printBlock(0, preBlock);
    preBlock = curBlock;
    while (!wallHittingCheck(preBlock.x, preBlock.y + 1, preBlock))
        preBlock.y++;
    printBlock(2, preBlock);
}

void effectiveSpin(long long& lockDelay, int x, int y, bool clockWise)
{
    curBlock.dir = (curBlock.dir + (clockWise ? 1 : 3)) % 4;
    curBlock.x += x;
    curBlock.y += y;
    preview();

    if (lockDelay != -1)
    {
        lockDelay = GetTickCount();
        while (!wallHittingCheck(curBlock.x, curBlock.y + 1, curBlock))
            curBlock.y++;
    }
}

void tryToSpin(long long& lockDelay, bool clockWise)
{
    currentBlock block1 = curBlock;
    block1.dir = (block1.dir + (clockWise ? 1 : 3)) % 4;
    if (!wallHittingCheck(block1.x, block1.y, block1))
    {
        effectiveSpin(lockDelay, 0, 0, clockWise);
    }
    else
    {
        if (block1.type != 0)
        {
            for (int i = 0; i < 4; i++)
            {
                if (!wallHittingCheck(block1.x + wallKickData[curBlock.dir][!clockWise][i][0], block1.y + wallKickData[curBlock.dir][!clockWise][i][1], block1))
                {
                    effectiveSpin(lockDelay, wallKickData[curBlock.dir][!clockWise][i][0], wallKickData[curBlock.dir][!clockWise][i][1], clockWise);
                    break;
                }
            }
        }
        else
        {
            for (int i = 0; i < 4; i++)
            {
                if (!wallHittingCheck(block1.x + wallKickDataOfI[curBlock.dir][!clockWise][i][0], block1.y + wallKickDataOfI[curBlock.dir][!clockWise][i][1], block1))
                {
                    effectiveSpin(lockDelay, wallKickDataOfI[curBlock.dir][!clockWise][i][0], wallKickDataOfI[curBlock.dir][!clockWise][i][1], clockWise);
                    break;
                }
            }
        }
    }
}

void lineCheck(int y)
{
    short linesN = 0;
    vector <int>lines;
    for (int i = y; i <= min(19, y + 3); i++)
    {
        bool flag = true;
        for (int j = 0; j < 10; j++)
            if (ground[j][i] == 0)
                flag = false;
        if (flag)
        {
            linesN++;
            lines.push_back(i);
        }
    }
    if (!linesN)
        return;

    color(15);

    string nameOfLines[4] = { "  Single! "," Double!! "," Triple!!!","Tetris!!!!" };

    go(14.5, 20);
    cout << nameOfLines[linesN - 1];

    for (int j = 0; j < 5; j++)
    {
        for (auto i = lines.begin(); i < lines.end(); i++)
        {
            go(1 + 5 + j, 5 + *i);
            printf("  ");
            go(1 + 4 - j, 5 + *i);
            printf("  ");
        }
        Sleep(100);
    }

    for (auto k = lines.begin(); k < lines.end(); k++)
    {
        for (int i = *k; i >= 0; i--)
            for (int j = 0; j < 10; j++)
                if (i)
                    ground[j][i] = ground[j][i - 1];
                else
                    ground[j][i] = 0;
    }

    if (linesN < 4)
    {
        burn += linesN;
        printBurn();
    }
    line += linesN;
    printLine();
    switch (linesN)
    {
    case 1:
        score += 40 * (level + 1);
        break;
    case 2:
        score += 100 * (level + 1);
        break;
    case 3:
        score += 300 * (level + 1);
        break;
    case 4:
        score += 1200 * (level + 1);
        break;
    }

    for (int i = 0; i < min(y + 4, 20); i++)
    {
        for (int j = 0; j < 10; j++)
        {
            go(j + 1, i + 5);
            if (ground[j][i])
            {
                color(block[ground[j][i] - 1].color.color[0]);
                printf("■");
            }
            else
            {
                color(15);
                printf("  ");
            }
        }
    }
    color(15);

    printScore();

    int l = line, i = 0;
    while (l > linesForLevels[i])
        l -= linesForLevels[i++];
    level = i;
    printLevel();

    go(14.5, 20);
    printf("游戏进行中");
}

int main();

void gaming()
{
    SetConsoleTitle("俄罗斯方块( Esc/F1/Enter暂停游戏 )");
    while (!kbhit())
        Sleep(100);
    int i = getch();

    clearImfBar();

    go(14.5, 20);
    printf("游戏进行中");

    nextBlockI = 0;
    getRandomBlocks(true);
    while (score != -1)
    {
        bool speedUp = false;

        curBlock.type = nextBlocks[nextBlockI];
        nextBlockI++;
        if (nextBlockI == 7)
        {
            getRandomBlocks(false);
            nextBlockI = 0;
        }
        printTheNextBlock();

        curBlock.x = 3;
        curBlock.y = -1;
        curBlock.dir = 0;
        if (curBlock.type == 0)
            curBlock.y--;

        if (wallHittingCheck(curBlock.x, curBlock.y + 1, curBlock))
        {
            printBlock(1, curBlock);
            break;
        }

        preview();

        long long lockDelay = -1;
        while (lockDelay == -1 || GetTickCount() - lockDelay < 500)
        {
            if (lockDelay == -1)
                curBlock.y++;
            printBlock(1, curBlock);
            if (speedUp)
            {
                speedUp = false;
                Sleep(speed[level] / 4);
            }
            else
                Sleep(speed[level]);

            printBlock(0, curBlock);
            if (kbhit())
            {
                int key = getch();
                if (key == 224)
                {
                    key = getch();
                    switch (key)
                    {
                    case 72:
                        tryToSpin(lockDelay, true);
                        break;
                    case 80:
                        speedUp = true;
                        break;
                    case 75:
                        if (!wallHittingCheck(curBlock.x - 1, curBlock.y, curBlock))
                        {
                            curBlock.x--;
                            preview();
                            if (lockDelay != -1)
                                lockDelay = GetTickCount();
                        }
                        break;
                    case 77:
                        if (!wallHittingCheck(curBlock.x + 1, curBlock.y, curBlock))
                        {
                            curBlock.x++;
                            preview();
                            if (lockDelay != -1)
                                lockDelay = GetTickCount();
                        }
                        break;
                    }
                }
                else if (key == 'X' || key == 'x')
                    tryToSpin(lockDelay, true);
                else if (key == 'Z' || key == 'z')
                    tryToSpin(lockDelay, false);
                else if (key == 27 || key == 0 || key == 13 || key == 59)
                {
                    SetConsoleTitle("暂停中……");

                    go(14.5, 20);
                    printf("暂停中……");

                    printBlock(1, curBlock);
                    while (kbhit())
                        Sleep(100);
                    while (!getch())
                        Sleep(100);

                    SetConsoleTitle("二 ……");
                    go(14.5, 20);
                    printf("    二    ");
                    Sleep(1000);

                    SetConsoleTitle("一 ……………………");
                    go(14.5, 20);
                    printf("    一    ");
                    Sleep(1000);

                    SetConsoleTitle("〓〓〓〓〓〓〓〓〓〓 游戏继续 〓〓〓〓〓〓〓〓〓〓");
                    go(14.5, 20);
                    printf("游戏继续!");
                    Sleep(1000);

                    go(14.5, 20);
                    printf("游戏进行中");
                    SetConsoleTitle("俄罗斯方块( Esc/F1/Enter暂停游戏 )");

                    lockDelay = GetTickCount();

                    printBlock(0, curBlock);
                }
                else if (key == 32)
                {
                    curBlock = preBlock;
                    break;
                }
            }
            if (GetKeyState(VK_CONTROL) < 0)
            {
                tryToSpin(lockDelay, false);
            }
            if (wallHittingCheck(curBlock.x, curBlock.y + 1, curBlock))
            {
                if (lockDelay == -1)
                    lockDelay = GetTickCount();
            }
            else
                lockDelay = -1;
        }
        printBlock(1, curBlock);
        preBlock.dir = -1;
        if (land())
            break;
        lineCheck(curBlock.y);
    }
    SetConsoleTitle("游戏结束,Esc退出");
    go(14.5, 20);
    printf("          ");
    go(15, 17);
    printf("游戏结束");
    go(13.5, 19);
    printf("得分:%d", score);

    ifstream infile("Highest.dat", ios::in);
    if (!infile)
    {
        go(13, 19);
        printf("读取最高记录失败");
    }
    int highest = -1;
    infile >> highest;
    infile.close();

    if (highest <= score)
    {
        ofstream outfile("Highest.dat", ios::out);
        if (!outfile)
        {
            go(13, 20);
            cerr << "保存最高记录失败" << endl;
        }
        outfile << score;
        highest = score;
    }

    go(13.5, 21);
    printf("最高:%d", highest);
    if (highest == score)
        printf("(当前)");

    go(13, 23);
    printf("Enter进入新游戏");

    int key = getch();
    while (key != 27 && key != 0 && key != 59)
    {
        if (key == 13)
        {
            main();
            break;
        }
        key = getch();
    }

}

int main()
{
    pre();
    printScore();
    printLine();
    printBurn();
    printLevel();

    gaming();

    return 0;
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值