八数码游戏练习

八数码游戏练习

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <cstdio>
#include <set>
#include<time.h>
#include <map>
#include<conio.h>
#include<algorithm>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N = 4e5;
int d[4][2] = {{1, 0}, {0, -1}, {0, 1}, {-1, 0}};// 四个方向的偏移量
ll kt(int *s);
struct Node
{
    int a[10];// 储存状态
    int id9;// 记录每个状态中九的位置
    int num;// 记录每个状态的康托值
    int stp;// 记录每个状态的步数
};
int stp[N];// 辅助数组 用于统计每种状态的到目标状态的步数
bool check(int nx, int ny)// 判断是否越界 如果越界返回true ,否则返回false
{
    if (nx < 0 || ny < 0 || nx >= 3 || ny >= 3)
        return true;
    return false;
}
ll fact(int n)// 求阶乘辅助函数
{
    if (n == 0)
        return 1;
    return n * fact(n - 1);
}
ll kt(int *s)// 求康托展开值
{
    ll res = 0;
    for (int i = 0; i < 9; i++)
    {
        int aj = 0;
        for (int j = i + 1; j < 9; j++)
            aj += s[i] > s[j];
        res += aj * fact(8 - i);
    }
    return res;
}
bool vis[N];// 标记数组 防止搜索状态重复
void bfs(Node s)
{
    memset(stp, -1, sizeof stp);
    queue<Node> q;// 队列 存放每一个状态
    q.push(s);
    s.num = kt(s.a);
    vis[s.num] = 1;
    stp[s.num]=0;// forget init
    while (q.size())
    {
        s = q.front();
        q.pop();
        for (int i = 0; i < 4; i++)
        {
            int nx = s.id9 / 3 + d[i][0], ny = s.id9 % 3 + d[i][1];
            if (check(nx, ny))
                continue;
            Node v = s;
            v.id9 = nx * 3 + ny;
            swap(v.a[v.id9], v.a[s.id9]);
            v.num = kt(v.a);
            v.stp = s.stp + 1;
            if (vis[v.num])
                continue;
            stp[v.num] = v.stp;
            vis[v.num] = 1;
            q.push(v);
        }
    }
}
Node build()// 随机生成目标状态
{
    srand((int)time(0));// srand 随机数
    struct Node t;
    bool st[10];
    memset(st, 0, sizeof st);
    map<int, int> mp;
    int cnt = 0;
    vector<int> v;
    while (1)
    {
        int x = rand() % 10;
        if(x == 0) continue;
		if (mp[x] == 0)
            v.push_back(x), mp[x] = 1, cnt++;
        if (cnt == 9)
            break;
    }
    int i = 0;
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        if (*it == 9)
            t.id9 = i;
        t.a[i++] = *it;
    }
    t.num = kt(t.a);
    t.stp = 0;
    return t;
}
Node s;
void show(Node g)//  展示函数 表示每次状态
{
	if(stp[g.num] == 0){//  胜利图标
	cout<<endl<<endl
        <<" /$$     /$$ /$$$$$$  /$$   /$$       /$$      /$$ /$$$$$$ /$$   /$$                         /$$ /$$\n"
		<<"|  $$   /$$//$$__  $$| $$  | $$      | $$  /$ | $$|_  $$_/| $$$ | $$                        | $$| $$\n"
		<<" \  $$ /$$/| $$  \ $$| $$  | $$      | $$ /$$$| $$  | $$  | $$$$| $$                        | $$| $$\n"
		<<"  \  $$$$/ | $$  | $$| $$  | $$      | $$/$$ $$ $$  | $$  | $$ $$ $$                        | $$| $$\n"
		<<"   \  $$/  | $$  | $$| $$  | $$      | $$$$_  $$$$  | $$  | $$  $$$$                        |__/|__/\n"
		<<"    | $$   | $$  | $$| $$  | $$      | $$$/ \  $$$  | $$  | $$\  $$$                                \n"
		<<"    | $$   |  $$$$$$/|  $$$$$$/      | $$/   \  $$ /$$$$$$| $$ \  $$                         /$$ /$$\n"
		<<"    |__/    \______/  \______/       |__/     \__/|______/|__/  \__/                        |__/|__/\n";
		cout<<endl<<endl;
		getchar();
		exit(0);
	}
    cout<<"\n***DIS = "<<stp[g.num]<<"***\n";
    
    char disp[100][410];
    int B = 5;
    for(int i=0;i<3;i++)
        for(int j=B;j<B+3;j++){
            disp[i][j] = s.a[i*3+(j-B)] + '0';
            if(s.a[i*3+(j-B)] == 9)
                disp[i][j] = ' ';
        }

    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            disp[i][j] = g.a[i*3+j] + '0';
            if(disp[i][j] == '9') 
                disp[i][j] = ' ';
        }
    }
    for(int i=0;i<3;i++,puts(""))
        for(int j=0;j<B+3;j++)
            cout<<disp[i][j]<<' ';
}

Node get_start()// 生成玩家操作初始状态
{
    int id = 0 ;
    while(stp[id]==-1)id++;
    int a[9];
    for(int i=0;i<9;i++)a[i] = i+1;
    for(int i=0;i<id;i++)
        next_permutation(a,a+9);
    Node res;
    for(int i=0;i<9;i++) 
    {
        res.a[i] = a[i];
        if(a[i]==9) res.id9 = i;
    }
    res.num = kt(res.a);
    res.stp = stp[res.num];
    return res;
}

int operate(Node &st)// 操作函数
{
    char c = getch();
    if(c == 'o') return 1;
    map<char,int>mp;
    {
        mp['w'] = 0;
        mp['d'] = 1;
        mp['a'] = 2;
        mp['s'] = 3;
    }
    int nx = st.id9/3 + d[mp[c]][0];
    int ny = st.id9%3 + d[mp[c]][1];
    if(check(nx,ny)) 
    {
        cout<<"Invalid operation\n";
        return 0;
    }
    swap(st.a[st.id9],st.a[nx*3+ny]);
    st.id9 = nx * 3 + ny;
    st.num = kt(st.a);
    st.stp = stp[st.num];
    return 0;
}

void play()// 游戏运行住程序
{
    Node st = get_start();// 生成初始状态
    while(1)
    {
        show(st);// 每次循环打印状态
        if(operate(st))break;// 如果胜利,跳出循环
    }
}
void start()// 开始打印说明提示函数
{
    cout<<"----------------------------\n"
        <<"| 操作说明:w,a,s,d控制       |\n"
        <<"| 按'o' 结束游戏             |\n"
        <<"| 按 Enter 开始游戏          |\n"
        <<"----------------------------\n";
        getchar();
}   
int main()
{
    s = build();
    bfs(s);
    start();
    play();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值