• 数独小游戏


    写了个小游戏,画面非常简陋,但基本的功能实现了
    下面是学习WindowsAPI时参考的文章,虽说几乎没看懂。。。
    [https://blog.csdn.net/farmwang/article/details/50603608]

    [https://blog.csdn.net/celte/article/details/10243309]

    [https://blog.csdn.net/m0_37801033/article/details/71540942]

    单独绘制数独边框时:(我对颜色搭配实在没啥心得。。。还凑活吧)

    单独绘制数独界面时:

    main.cpp:

    #include <iostream>
    #include "soduko.h"
    using namespace std;
    int main()
    {
        system("title 数独");
        system("mode con cols=80 lines=35");
        soduko matrixone("sodukosamples");
        matrixone.play();
        return 0;
    }
    

    soduko.h:

    #ifndef SODUKO_H_INCLUDED
    #define SODUKO_H_INCLUDED
    #include <iostream>
    #include <windows.h>
    #include <cstring>
    #include <string>
    #include <fstream>
    #include <sstream>
    #include <conio.h>
    using namespace std;
    //程序中的数字如果可能造成歧义,尽可能用变量名代替
    const int line_basement=12,col_basement=30,region_intverl=2,conorcolor=7,errcolor=4,norcolor=3;
    const int ONC=800,SBC=240;
    const int HIGH_BITSIZE=16,WEIGHT_BITSIZE=8;
    class soduko
    {
    public:
        soduko(string);
        ~soduko();
        void play();//主体函数
        void finderrws(int,int);//寻找错误,并为错误设置状态
        void relieverr();//当错误被修正时,解除错误状态
        bool finderr(int [9][9],int,int);//判断是否存在错误,因为功能与性质的不同不能和finderrws函数合并,感觉有点别扭
        void show(int,int,int);//在当前所在的位置显示
        void showsame(int,int,int);//当前不是空格时,显示所有与当前数字相同的数字
        void solvanswer(int [9][9]);//计算数独答案
    private:
        int sodukodata[9][9];
        int statepara[9][9][4];//position x , position y , color , if can be changed //
    };
    
    #endif // SODUKO_H_INCLUDED
    

    soduko.cpp:

    #include "soduko.h"
    
    
    //problem : cannot use "show_same" to relieve the block with SBC//has been overcome
    
    /***********************************外部函数区(WindowsAPI)***************************************/
    HANDLE hout=GetStdHandle(STD_OUTPUT_HANDLE);//获取当前窗口句柄(也就是获取窗口状态)
    COORD position;
    void hide()//隐藏光标
    {
        CONSOLE_CURSOR_INFO cursor_info={1,0};
        SetConsoleCursorInfo(hout, &cursor_info);
    }
    void SetCurPos(const int x, const int y)//设置光标位置
    {
        position.X = x;
        position.Y = y;
        SetConsoleCursorPosition(hout, position);
    }
    void SetColor(int colorID)//设置文本颜色
    {
        SetConsoleTextAttribute(hout, colorID);
    }
    void SetBackColor()//设置文本背景色
    {
        SetConsoleTextAttribute(hout,
                                //BACKGROUND_BLUE |
                                BACKGROUND_INTENSITY|
                                BACKGROUND_GREEN |
                                BACKGROUND_RED );
    }
    //下面两个函数原谅我现学现卖,另外,它们没有也不应该出现在程序的正常线程中,因为一些问题尚未解决
    void music()
    {
        //播放音乐,需要在链接器中添加"winmm",支持wav格式,其他格式似乎不支持
        //如果文件不在工程/项目目录下,添加确切位置
        //还有,播放音乐时不能进行其他操作,所以不能加入游戏中(除非有暂停和继续播放音乐的函数。。。)
        PlaySound("Baptism.wav",NULL,SND_SYNC);
    }
    //绘制数独的边框,但是只学得懵懵懂懂,单独列出还行,作为游戏的一部分就惨不忍睹
    //另外,需要在链接器中添加"gdi32",因为调用了GDI图形接口
    //还有,我在编译这个函数时(单独的项目),发现总是画不出来,还得碰运气。。。
    //作为经验之谈,编译出现"undefined reference to ......"之类错误的,都是没有在链接器中添加相应的链接
    //最后,这个函数还没有正式移入这个程序中,所以没有优化逻辑和细节,造成数字较多,比较臃肿
    void drawframe()
    {
        HPEN hPen;//定义画笔
        HBRUSH hBrush;//定义画刷
        HWND wnd=FindWindow(NULL,"数独");//不知道获得当前窗口设备句柄的函数,还好找到了这个,获得窗口名为“数独”的窗口的设备句柄
        HDC dc=GetDC(wnd);//这个。。。真不懂,大概是获取什么东西
        POINT ipion[]={{256,192}};//起始点,不怎么懂
        int posx[]={256,256,272,272,304,304,320,320,352,352,368,368,
                    240,384,384,240,240,384,384,240,240,384,384,240};
        int posy[]={192,336,336,192,192,336,336,192,192,336,336,192,
                    208,208,224,224,256,256,272,272,304,304,320,320};
        int ppx[]={288,288,336,336,240,384,384,246};
        int ppy[]={192,336,336,192,240,240,288,288};
        //绘制矩形
        hPen = (HPEN)(GetStockObject(NULL_PEN));
        hPen = CreatePen(PS_SOLID, 5, RGB(128, 128, 128));
        SelectObject(dc, hPen);
        Rectangle(dc,237,189,388,340);
        DeleteObject(hPen);//释放画笔
        //连线(细线)//之所以没有用矩形来代替连线,是因为函数绘制的矩形实际上不是由线组成,而是一个面,所以多重矩形并不能组成网格
        hPen = CreatePen(PS_SOLID, 3, RGB(128, 128, 128));
        SelectObject(dc, hPen);
        MoveToEx(dc,ppx[0],ppy[0],ipion);
        for(int i=1;i<4;i++)
            LineTo(dc,ppx[i],ppy[i]);
        MoveToEx(dc,ppx[4],ppy[4],ipion);
        for(int i=5;i<8;i++)
            LineTo(dc,ppx[i],ppy[i]);
        DeleteObject(hPen);
        //连线(粗线)
        hPen = CreatePen(PS_DOT, 1, RGB(128, 128, 128));
        SelectObject(dc, hPen);
        hBrush = (HBRUSH)(GetStockObject(BLACK_BRUSH));
        SelectObject(dc,hBrush);
        MoveToEx(dc,posx[0],posy[0],ipion);
        for(int i=1;i<12;i++)
            LineTo(dc, posx[i], posy[i]);
        MoveToEx(dc,posx[12],posy[12],ipion);
        for(int i=13;i<24;i++)
            LineTo(dc, posx[i], posy[i]);
        DeleteObject(hPen);
    }
    /************************************************************************************/
    soduko::soduko(string textdata)
    {
        //数独的数据存储在文件中
        //格式为:文件中数据与数独的显示相似,数据为整型,用空格分开
        //数独未填写空格用0表示,其余依旧为1~9
        int a=textdata.size();
        string judgeprinciple=textdata.substr(a-4,4);
        if(judgeprinciple!=".txt")textdata+=".txt";
        ifstream input(textdata);
        if(!input)
            cout<<"Error! Cannot open the file!"<<endl;
        string s;
        for(int i=0;i<9;i++)
        {
            getline(input,s);
            istringstream scin(s);
            for(int j=0;j<9;j++)
                scin>>sodukodata[i][j];
        }
        for(int i=0;i<9;i++)
        {
            for(int j=0;j<9;j++)
            {
                //设置状态(位置,颜色,是否可变)
                statepara[i][j][0]=j*region_intverl+col_basement;//position x
                statepara[i][j][1]=i+line_basement;//position y
                if(sodukodata[i][j]==0)
                {
                    statepara[i][j][2]=norcolor;//normal color = blue
                    statepara[i][j][3]=1;//can be changed
                }
                else
                {
                    statepara[i][j][2]=conorcolor;//normal color = white
                    statepara[i][j][3]=0;//can not be changed
                }
            }
        }
    }
    soduko::~soduko(){};
    void soduko::play()
    {
        //calculate answer//采取的计算方法一点也不高明,但胜在简单(按照人的正常思路计算比较复杂)
        int answer[9][9];
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++)
                answer[i][j]=sodukodata[i][j];
        solvanswer(answer);
    
        //draw the begin view
    
        //drawframe();
        //music();
    
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++)
                show(i,j,ONC);
        //original position of choose
        show(0,0,SBC);
        showsame(0,0,SBC);
        SetCurPos(statepara[0][0][0],statepara[0][0][1]);
        hide();
        //main
        int active_x=0,active_y=0;
        char numget;
        while((numget=getch()))
        {
            showsame(active_x,active_y,ONC);
            if(numget>48&&numget<58&&statepara[active_x][active_y][3]!=0)
            {
                sodukodata[active_x][active_y]=numget-48;
                show(active_x,active_y,SBC);
            }
            else if(numget==8&&statepara[active_x][active_y][3]!=0)
            {
                sodukodata[active_x][active_y]=0;
                show(active_x,active_y,SBC);
            }
            else
            {
                show(active_x,active_y,ONC);
                switch(numget)
                {
                    case 72:
                        if(active_x>0)
                            active_x--;
                        break;//up//明明是UP为什么是x变化呢?这个问题交给读者了
                    case 75:
                        if(active_y>0)
                            active_y--;
                        break;//left
                    case 80:
                        if(active_x<8)
                            active_x++;
                        break;//down
                    case 77:
                        if(active_y<8)
                            active_y++;
                        break;//right
                    default:break;
                }
            }
            hide();
            showsame(active_x,active_y,SBC);
            relieverr();
            finderrws(active_x,active_y);
            show(active_x,active_y,SBC);
            //relocate active position
            SetColor(statepara[active_x][active_y][2]);
            SetCurPos(statepara[active_x][active_y][0],statepara[active_x][active_y][1]);
            //judge win
            int win=1;
            for(int i=0;i<9;i++)
                {
                    for(int j=0;j<9;j++)
                        if(sodukodata[i][j]!=answer[i][j])
                        {
                            win=0;
                            break;
                        }
                    if(win==0)break;
                }
            if(win==1)
            {
                SetCurPos(col_basement,3);
                SetColor(conorcolor);
                cout<<"congratulation! You win the game!"<<endl;
                break;
            }
        }
    }
    void soduko::finderrws(int line,int ver)
    {
        //find out same number and show them
        int linp=line/3*3,verp=ver/3*3;
        for(int i=0;i<9;i++)
        {
            if(i!=ver&&sodukodata[line][i]!=0)
                if(sodukodata[line][ver]==sodukodata[line][i])
                {
                    show(line,ver,errcolor);
                    show(line,i,errcolor);
                }
            if(i!=line&&sodukodata[i][ver]!=0)
                if(sodukodata[line][ver]==sodukodata[i][ver])
                {
                    show(line,ver,errcolor);
                    show(i,ver,errcolor);
                }
        }
        for(int i=linp;i<linp+3;i++)
            for(int j=verp;j<verp+3;j++)
                if((i!=line||j!=ver)&&sodukodata[i][j]!=0)
                    if(sodukodata[line][ver]==sodukodata[i][j])
                    {
                        show(line,ver,errcolor);
                        show(i,j,errcolor);
                    }
    }
    bool soduko::finderr(int data[9][9],int line,int ver)
    {
        int linp=line/3*3,verp=ver/3*3;
        for(int i=0;i<9;i++)
        {
            if(i!=ver&&data[line][i]!=0)
                if(data[line][ver]==data[line][i])
                    return false;
            if(i!=line&&data[i][ver]!=0)
                if(data[line][ver]==data[i][ver])
                    return false;
        }
        for(int i=linp;i<linp+3;i++)
            for(int j=verp;j<verp+3;j++)
                if((i!=line||j!=ver)&&sodukodata[i][j]!=0)
                    if(data[line][ver]==data[i][j])
                        return false;
        return true;
    }
    void soduko::relieverr()
    {
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++)
                if(statepara[i][j][2]==errcolor&&finderr(sodukodata,i,j))
                {
                    if(statepara[i][j][3]==1)
                        show(i,j,norcolor);
                    else
                        show(i,j,conorcolor);
                }
    }
    void soduko::show(int xt,int yt,int color)
    {
        if(color==SBC)
            SetBackColor();
        else
        {
            if(color!=ONC)
                statepara[xt][yt][2]=color;
            SetColor(statepara[xt][yt][2]);
        }
        SetCurPos(statepara[xt][yt][0],statepara[xt][yt][1]);
        if(sodukodata[xt][yt]!=0)
            cout<<sodukodata[xt][yt]<<" ";//说实话,不论加不加这个空格,都感觉有些别扭
        else
            cout<<"  ";//这是两个空格
    }
    void soduko::showsame(int x,int y,int order)
    {
        if(sodukodata[x][y]!=0)
        {
            for(int i=0;i<9;i++)
                for(int j=0;j<9;j++)
                    if(sodukodata[i][j]==sodukodata[x][y]&&i!=x&&j!=y)
                    {
                        if(order!=SBC)
                            order=statepara[i][j][2];
                        show(i,j,order);
                    }
        }
    }
    //这个函数解数独的方法是:建立指针数组,将所有空格的指针按序存入数组
    //用指针数组按序试数并记录当前所试的数,没有发现错误时试下一个
    //当所有数字填入都出现错误时,抹去当前数字的记录,返回上一个,继续从上一次记录开始试数
    //按这种方法一定能找到唯一解,只要数独有解
    void soduko::solvanswer(int soduko[9][9])
    {
        int numl=0,actnuml=0;
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++)
            if(soduko[i][j]==0)numl++;
        int *emptyspace[numl];
        int poslines[numl],posvert[numl];
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++)
                if(soduko[i][j]==0)
                {
                    poslines[actnuml]=i;
                    posvert[actnuml]=j;
                    emptyspace[actnuml++]=&soduko[i][j];
                }
        actnuml=0;
        while(actnuml<numl)
        {
            int pl=0,drt=*emptyspace[actnuml];
            for(int i=drt+1;i<=9;i++)
            {
                *emptyspace[actnuml]=i;
                if(finderr(soduko,poslines[actnuml],posvert[actnuml]))
                {
                    pl=1;
                    break;
                }
            }
            if(pl==1)
                actnuml++;
            else
            {
                *emptyspace[actnuml]=0;
                actnuml--;
            }
        }
    }
    
  • 相关阅读:
    url 编码 js url传参中文乱码解决方案
    form提交时,如果target=_blank,则会打开一个新页面,但是大小和位置无法控制,请问如何进行控制
    java日期转字符串 字符串转日期 日期转日历 日历转日期
    策略模式【设计模式学习02】
    设计模式六大原则【设计模式学习开篇】
    应用程序栏【WP7学习札记之九】
    主题样式与数据绑定【WP7学习札记之八】
    启动器与选择器常用Task【WP7学习札记之四】
    屏幕方向与常用控件【WP7学习札记之六】
    设备的开发【WP7学习札记之五】
  • 原文地址:https://www.cnblogs.com/BuluGuy/p/9221551.html
Copyright © 2020-2023  润新知