// HorseTransDlg.h : 头文件
//
#pragma once
#include <vector>
//typedef struct _StepState {
// POINT pos;
// //int childNum;
// std::vector<_StepState*>* pChildTree;
// //_StepState* preStep;
//} StepState;
template<class T>
class TreeNode
{
public:
TreeNode() {
parentNode = nullptr;
index = -1;
enable = 1;
childrenTree.clear();
}
~TreeNode() {}
void releaseChildren()
{
int isize = childrenTree.size();
if (isize == 0) {
return;
}
for (int ii = isize-1; ii >= 0; --ii) {
childrenTree[ii]->releaseChildren();
delete childrenTree[ii];
}
childrenTree.clear();
}
void addChild(T* pStep)
{
childrenTree.push_back(pStep);
}
T* parentNode;
int index;
int enable;
std::vector<T*> childrenTree;
};
class StepState :public TreeNode<StepState>
{
public:
StepState(POINT _pos) {
pos = _pos;
}
~StepState() {}
POINT pos;
};
// CHorseTransDlg 对话框
class CHorseTransDlg : public CDialogEx
{
// 构造
public:
CHorseTransDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_HORSETRANS_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
void paintBackground();
int countNextStepsTree(StepState& curStep);
public:
afx_msg void OnBnClickedBtnCalculate();
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
};
// HorseTransDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "HorseTrans.h"
#include "HorseTransDlg.h"
#include "afxdialogex.h"
#include <vector>
#include <list>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CHorseTransDlg 对话框
const int MARGIN_X = 10;
const int MARGIN_Y = 10;
const int FONT_MARGIN_X = 10;
const int FONT_MARGIN_Y = 10;
const int SPACE_X = 30;
const int SPACE_Y = 30;
// 这2个值可以随便改,形成不同的棋盘
const int BLOCKS_X = 16;
const int BLOCKS_Y = 10;
int g_Position[BLOCKS_Y][BLOCKS_X];
POINT g_startPos = {-1,-1};
CHorseTransDlg::CHorseTransDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_HORSETRANS_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CHorseTransDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CHorseTransDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTN_CALCULATE, &CHorseTransDlg::OnBnClickedBtnCalculate)
ON_WM_LBUTTONDBLCLK()
END_MESSAGE_MAP()
// CHorseTransDlg 消息处理程序
BOOL CHorseTransDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
//ShowWindow(SW_MINIMIZE);
// TODO: 在此添加额外的初始化代码
memset(g_Position, 0, sizeof(g_Position));
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CHorseTransDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
paintBackground();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CHorseTransDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CHorseTransDlg::paintBackground()
{
CDC* pDC = GetDC();
// 画棋盘
int ii;
for (ii = 0; ii <= BLOCKS_Y;++ii) {
pDC->MoveTo(MARGIN_X, MARGIN_Y + ii*SPACE_Y);
pDC->LineTo(MARGIN_X + BLOCKS_X*SPACE_X, MARGIN_Y + ii*SPACE_Y);
}
for (ii = 0; ii <= BLOCKS_X; ++ii) {
pDC->MoveTo(MARGIN_X + ii*SPACE_X, MARGIN_Y);
pDC->LineTo(MARGIN_X + ii*SPACE_X, MARGIN_Y + BLOCKS_Y*SPACE_Y);
}
// 画步骤号
TCHAR buf[10];
for (int ii = 0; ii < BLOCKS_Y; ii++) {
for (int jj = 0; jj < BLOCKS_X; jj++) {
if (g_Position[ii][jj] != 0) {
_itot_s(g_Position[ii][jj], buf, 10);
if (g_Position[ii][jj] == BLOCKS_X * BLOCKS_Y) {
// 结束标志
CRect rect(MARGIN_X + jj * SPACE_X,
MARGIN_Y + ii * SPACE_Y,
MARGIN_X + (jj+1) * SPACE_X,
MARGIN_Y + (ii+1) * SPACE_Y);
CBrush brush(RGB(255,0,0));
pDC->FillRect(&rect, &brush);
}
pDC->TextOut(MARGIN_X + jj * SPACE_X + FONT_MARGIN_X,
MARGIN_Y + ii * SPACE_Y + FONT_MARGIN_Y,
buf);
}
}
}
ReleaseDC(pDC);
}
void CHorseTransDlg::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (point.x < MARGIN_X || point.y < MARGIN_Y
|| point.x >= MARGIN_X + BLOCKS_X*SPACE_X || point.y >= MARGIN_Y + BLOCKS_Y*SPACE_Y)
{
CDialogEx::OnLButtonDblClk(nFlags, point);
return;
}
int iRectX = (point.x - MARGIN_X) / SPACE_X;
int iRectY = (point.y - MARGIN_Y) / SPACE_Y;
g_startPos = { iRectX, iRectY };
memset(g_Position, 0, sizeof(g_Position[0][0]) * BLOCKS_Y * BLOCKS_X);
g_Position[iRectY][iRectX] = 1;
CDialogEx::OnLButtonDblClk(nFlags, point);
Invalidate();
}
void CHorseTransDlg::OnBnClickedBtnCalculate()
{
if (g_startPos.x < 0 || g_startPos.y < 0) {
return;
}
int iStep = 1;
int iAllStep = BLOCKS_X * BLOCKS_Y;
POINT pos = g_startPos;
StepState startStep(pos);
StepState* pCurStep = &startStep;
while (iStep < iAllStep) {
while (iStep < iAllStep) {
// 获取当前节点所有下一个节点集,简称一代节点集
int iCount = countNextStepsTree(*pCurStep);
// 获取当前节点每个一代节点的下代节点集,简称二代节点
// 贪心算法,取二代节点数最小的一代节点做下一步
int iMin = -1;
for (int ii = 0; ii < iCount; ii++) {
StepState* tempStep = pCurStep->childrenTree[ii];
if (tempStep->enable == 0) {
continue;
}
int x = tempStep->pos.x;
int y = tempStep->pos.y;
g_Position[y][x] = iStep + 1;
int num = countNextStepsTree(*tempStep);
g_Position[y][x] = 0;
if (num > 0) {
if (num < iMin || iMin < 0) {
iMin = num;
pCurStep->index = ii;
}
}
}
// 选自身分支最少那个子分支
if (pCurStep->index >= 0) {
pCurStep = pCurStep->childrenTree[pCurStep->index];
int iX = pCurStep->pos.x;
int iY = pCurStep->pos.y;
g_Position[iY][iX] = ++iStep;
}else {
if (iStep + 1 >= iAllStep && pCurStep->childrenTree.size() > 0) {
// 圆满完成
pCurStep = pCurStep->childrenTree[0];
int iX = pCurStep->pos.x;
int iY = pCurStep->pos.y;
g_Position[iY][iX] = ++iStep;
}
else {
// 走到死胡同
break;
}
}
}
if (iStep < iAllStep) {
// 回溯
do {
pCurStep->enable = 0;
int iX = pCurStep->pos.x;
int iY = pCurStep->pos.y;
g_Position[iY][iX] = 0;
--iStep;
pCurStep = pCurStep->parentNode;
if (pCurStep == nullptr) {
MessageBox(_T("无解"));
break;
}
int iMin = -1;
int iCount = pCurStep->childrenTree.size();
pCurStep->index = -1;
for (int ii = 0; ii < iCount; ii++) {
StepState* pState = pCurStep->childrenTree[ii];
if (pState->enable != 1) {
continue;
}
int iNum = pState->childrenTree.size();
if (iNum < iMin || iMin < 0) {
iMin = iNum;
pCurStep->index = ii;
}
}
if (pCurStep->index != -1) {
break;
}
} while (pCurStep != nullptr);
if (pCurStep == nullptr) {
break;
}
}
}
startStep.releaseChildren();
g_startPos = {-1, -1};
Invalidate();
}
int CHorseTransDlg::countNextStepsTree(StepState& curStep)
{
if (curStep.pos.x == -1 || curStep.pos.y == -1) {
return 0;
}
int iCount = curStep.childrenTree.size();
if (iCount > 0){
return iCount;
}
int x = curStep.pos.x;
int y = curStep.pos.y;
if (x + 2 < BLOCKS_X && y + 1 < BLOCKS_Y && x + 2 >= 0 && y + 1 >= 0) {
POINT newPoint = { x + 2, y + 1 };
if (g_Position[newPoint.y][newPoint.x] == 0) {
StepState* state = new StepState(newPoint);
state->parentNode = &curStep;
curStep.childrenTree.push_back(state);
}
}
if (x + 2 < BLOCKS_X && y - 1 < BLOCKS_Y && x + 2 >= 0 && y - 1 >= 0) {
POINT newPoint = { x + 2, y - 1 };
if (g_Position[newPoint.y][newPoint.x] == 0) {
StepState* state = new StepState(newPoint);
state->parentNode = &curStep;
curStep.childrenTree.push_back(state);
}
}
if (x + 1 < BLOCKS_X && y + 2 < BLOCKS_Y && x + 1 >= 0 && y + 2 >= 0) {
POINT newPoint = { x + 1, y + 2 };
if (g_Position[newPoint.y][newPoint.x] == 0) {
StepState* state = new StepState(newPoint);
state->parentNode = &curStep;
curStep.childrenTree.push_back(state);
}
}
if (x + 1 < BLOCKS_X && y - 2 < BLOCKS_Y && x + 1 >= 0 && y - 2 >= 0) {
POINT newPoint = { x + 1, y - 2 };
if (g_Position[newPoint.y][newPoint.x] == 0) {
StepState* state = new StepState(newPoint);
state->parentNode = &curStep;
curStep.childrenTree.push_back(state);
}
}
if (x - 2 < BLOCKS_X && y + 1 < BLOCKS_Y && x - 2 >= 0 && y + 1 >= 0) {
POINT newPoint = { x - 2, y + 1 };
if (g_Position[newPoint.y][newPoint.x] == 0) {
StepState* state = new StepState(newPoint);
state->parentNode = &curStep;
curStep.childrenTree.push_back(state);
}
}
if (x - 2 < BLOCKS_X && y - 1 < BLOCKS_Y && x - 2 >= 0 && y - 1 >= 0) {
POINT newPoint = { x - 2, y - 1 };
if (g_Position[newPoint.y][newPoint.x] == 0) {
StepState* state = new StepState(newPoint);
state->parentNode = &curStep;
curStep.childrenTree.push_back(state);
}
}
if (x - 1 < BLOCKS_X && y + 2 < BLOCKS_Y && x - 1 >= 0 && y + 2 >= 0) {
POINT newPoint = { x - 1, y + 2 };
if (g_Position[newPoint.y][newPoint.x] == 0) {
StepState* state = new StepState(newPoint);
state->parentNode = &curStep;
curStep.childrenTree.push_back(state);
}
}
if (x - 1 < BLOCKS_X && y - 2 < BLOCKS_Y && x - 1 >= 0 && y - 2 >= 0) {
POINT newPoint = { x - 1, y - 2 };
if (g_Position[newPoint.y][newPoint.x] == 0) {
StepState* state = new StepState(newPoint);
state->parentNode = &curStep;
curStep.childrenTree.push_back(state);
}
}
return curStep.childrenTree.size();
}