《求解关灯游戏》源码分析

http://blog.163.com/prevBlogPerma.do?host=simplesource&srl=10341406200981362416959&mode=prev

 

这个代码写得相当不错。

 

这里先对蛮力搜索做个分析。

 

LightsOffAppDlg.h 添加了些调试内容。

 

// LightsOffAppDlg.h : 头文件
//

#pragma once
#include "lightsoff.h"
#include "afxwin.h"

// CLightsOffAppDlg 对话框
class CLightsOffAppDlg : public CDialog
{
// 构造
public:
	CLightsOffAppDlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_LIGHTSOFFAPP_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持

    int m_iUnitWidth;
    int m_iX0;
    int m_iY0;
    CField m_field;
    CField m_mask;
    CField m_recorder;
    bool   m_bKillMsg;
    int    m_iState;
    CMatrix m_trans;
    CMatrix m_switch;

	FILE * fp ;

    // 设置大小
    void SetSize()
    {
        int iWidth = m_cbWidth.GetCurSel() + 1;
        int iHeight = m_cbHeight.GetCurSel() + 1;
        m_field.Create(iWidth, iHeight);
        m_mask = m_field;
        m_recorder = m_field;
        int w, h;
        int fw = m_iUnitWidth * iWidth;
        int fh = m_iUnitWidth * iHeight;
        w = fw + 128;
        h = fh + 100;
        if(w < 360)
        {
            w = 360;
        }
        if(h < 200)
        {
            h = 200;
        }
        MoveWindow(
            (::GetSystemMetrics(SM_CXSCREEN) - w) / 2,
            (::GetSystemMetrics(SM_CYSCREEN) - h) / 2,
            w, h);
        CRect rect;
        GetClientRect(&rect);
        m_iX0 = 50 + (rect.Width() - fw) / 2;
        m_iY0 = 50;
        // 计算求解矩阵
        m_switch.Create(iWidth, iHeight);
        m_trans.Create(iWidth, iHeight);
        m_trans.SetAsI();
        m_switch.SetAsL(m_mask);
        m_switch.Inverse(m_trans);
        m_switch.SetAsL(m_mask);
        Invalidate();
    }
    // 执行线程
    static UINT ThreadProc(LPVOID pParm)
    {
        CLightsOffAppDlg * pClass = (CLightsOffAppDlg *)pParm;
        //pClass->m_iMode = PRO_MODE_ASYN;

        pClass->m_iState = 1;
        CField fld;
        fld.Create(pClass->m_field.Width(), pClass->m_field.Height());
        pClass->m_recorder = fld;
		
		pClass->fp = fopen("m.txt", "w");
        if(pClass->fp)
        {
            fld.Print(pClass->fp);
            pClass->m_recorder.Print(pClass->fp);
			pClass->m_mask.Print(pClass->fp);
			pClass->m_field.Print(pClass->fp);
        }

        if(pClass->FindRecord(fld, pClass->m_recorder))
        {
            pClass->Invalidate(false);
            if(pClass->m_bKillMsg == false)
            {
                pClass->MessageBox("找到解", "成功", MB_ICONINFORMATION);
            }
        }
        else
        {
            pClass->Invalidate(false);
            if(pClass->m_bKillMsg == false)
            {
                pClass->MessageBox("未找到解", "失败", MB_ICONERROR);
            }
        }
        pClass->KillTimer(0);
        pClass->m_iState = 0;
        pClass->SetDlgItemText(IDC_BT_SEARCH, "蛮力搜索");
        //pClass->m_iMode = PRO_MODE_BLOCK;

		if(pClass->fp)
		{
			fclose(pClass->fp);
		}

        return 0;
    }
    bool FindRecord(CField &fld, CField &rcd, int x = 0, int y = 0)
    {
        if(m_bKillMsg)
        {
            return false;
        }
        fld.AndNot(m_mask);
		
        if(fld == m_field)
        {
            return true;
        }
        if(x >= fld.Width())
        {
            y++;
            x = 0;
            if(y >= fld.Height())
            {
				if(fp)
				{
					fprintf(fp, "out of range. x=%d, y=%d", x, y);
					fprintf(fp, "\n");
				}

                return false;
            }
        }
        int i;

        if(fp)
        {
			fprintf(fp, "x=%d, y=%d", x, y);
			fprintf(fp, "\n");
            fld.Print(fp);
            rcd.Print(fp);
			m_mask.Print(fp);
			m_field.Print(fp);
        }


        if(m_mask.IsLightOn(x, y))
        {
			fprintf(fp, "m_mask.IsLightOn(%d, %d)", x, y);
			fprintf(fp, "\n");

            if(FindRecord(fld, rcd, x + 1, y))
            {
                return true;
            }
        }
        else
        {
			fprintf(fp, "not m_mask.IsLightOn(%d, %d)", x, y);
			fprintf(fp, "\n");
            for(i = 0; i < 2 && !m_bKillMsg; i++)
            {
                if(FindRecord(fld, rcd, x + 1, y))
                {
                    return true;
                }
								if(fp)
								{
									fprintf(fp, "x=%d, y=%d", x, y);
									fprintf(fp, "\n");
									fprintf(fp, "i=%d", i);
									fprintf(fp, "\n");
								}
                fld.LightsOff(x, y);
                rcd.SetLight(x, y);

								if(fp)
								{
									fprintf(fp, "fld.LightsOff(%d, %d);", x, y);
									fprintf(fp, "\n");
									fld.Print(fp);
									rcd.Print(fp);
									m_mask.Print(fp);
									m_field.Print(fp);
								}

            }
        }
        return false;
    }

// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnTimer(UINT nIDEvent);
    afx_msg void OnBnClickedBtCompute();
    CComboBox m_cbWidth;
    CComboBox m_cbHeight;
    afx_msg void OnBnClickedBtSearch();
    afx_msg void OnCbnSelchangeCbWidth();
    afx_msg void OnCbnSelchangeCbHeight();
    afx_msg void OnRButtonDblClk(UINT nFlags, CPoint point);
    afx_msg void OnBnClickedBtReverse();
    afx_msg void OnBnClickedBtClear();
};

 

他这解法,是从右下角开始往回开灯求解的。如果用我这个测试代码,千万别从左上角进行测试。否则,日志信息将极宠大。

 

以下列出一小段开灯的递归顺序。

 

44
44

34
 44
 44
34

24
 44
 44

 34
  44
  44
 34
24

14
 44
 44

 34
  44
  44
 34

 24
  44
  44

  34
   44
   44
  34
 24
14

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值