Click here to Skip to main content
15,894,646 members
Articles / Desktop Programming / MFC

A Sudoku Teacher Using Boost Libraries

Rate me:
Please Sign up or sign in to vote.
4.73/5 (27 votes)
7 Jul 20067 min read 68.5K   1.9K   60  
A Sudoku teacher using multi_index_container, lambda, and other Boost libraries.
// SudokuEdit.cpp : implementation file
// Adapted from CodeProject work by PJ Arends

#include "stdafx.h"
#include "SudokuEdit.h"
#include "SudokuPuzzle.h"
#include <vector>
#include <sstream>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define MES_UNDO        _T("&Show &History")
#define MES_COPY         _T("Show &Answer")
#define MES_CUT         _T("&Cut")
#define MES_PASTE       _T("&Paste")
#define MES_DELETE      _T("&Delete")
#define MES_SELECTALL   _T("Select &All")
#define ME_SELECTALL    WM_USER + 0x7000

BEGIN_MESSAGE_MAP(CSudokuEdit, CEdit)
    ON_WM_CONTEXTMENU()
	ON_WM_CTLCOLOR_REFLECT()
END_MESSAGE_MAP()

CSudokuEdit::CSudokuEdit() :
	m_pPuzzle(NULL)
	, cbAnswer(NULL)
	, cbHint(NULL)
	, cbBlank(NULL)
	, cbImposs(NULL)
	, cfNormal(NULL)
	, cfAnswer(NULL)
	, cfPossibilities(NULL)
	, cfImposs(NULL)
	, crNormalText(RGB(0,0,0))
	, crAnswerText(RGB(0,0,0))
	, crHintText(RGB(0,0,0))
	, crImpossText(RGB(0,0,0))
	, m_pLB(NULL)
	, bChanged(false)
	, m_guess(0)
	, m_iCellNum(0)
	, state(CS_UNINITIALIZED)
	, prevState(CS_UNINITIALIZED)

{
	state = CS_UNINITIALIZED;
}

void CSudokuEdit::OnContextMenu(CWnd* pWnd, CPoint point)
{
    SetFocus();
    CMenu menu;
    menu.CreatePopupMenu();
    BOOL bReadOnly = GetStyle() & ES_READONLY;
    DWORD flags = CanUndo() && !bReadOnly ? 0 : MF_GRAYED;
    menu.InsertMenu(0, MF_BYPOSITION, EM_UNDO,
        MES_UNDO);

    menu.InsertMenu(1, MF_BYPOSITION | MF_SEPARATOR);

	int answer = m_pPuzzle->GetAnswer(m_iCellNum);
	if (answer == 0)
		flags = MF_GRAYED;
	else
		flags = 0;
    menu.InsertMenu(2, MF_BYPOSITION | flags, WM_COPY,
        MES_COPY);

    //flags = (flags == MF_GRAYED || bReadOnly) ? MF_GRAYED : 0;
    //menu.InsertMenu(2, MF_BYPOSITION | flags, WM_CUT,
    //    MES_CUT);
    //menu.InsertMenu(4, MF_BYPOSITION | flags, WM_CLEAR,
    //    MES_DELETE);

    //flags = IsClipboardFormatAvailable(CF_TEXT) &&
    //    !bReadOnly ? 0 : MF_GRAYED;
    //menu.InsertMenu(4, MF_BYPOSITION | flags, WM_PASTE,
    //    MES_PASTE);

    //menu.InsertMenu(6, MF_BYPOSITION | MF_SEPARATOR);

    //int len = GetWindowTextLength();
    //flags = (!len || (LOWORD(sel) == 0 && HIWORD(sel) ==
    //    len)) ? MF_GRAYED : 0;
    //menu.InsertMenu(7, MF_BYPOSITION | flags, ME_SELECTALL,
    //    MES_SELECTALL);

    menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON |
        TPM_RIGHTBUTTON, point.x, point.y, this);
}


BOOL CSudokuEdit::OnCommand(WPARAM wParam, LPARAM lParam)
{
    switch (LOWORD(wParam))
    {
    case EM_UNDO:	// hijacked - show history
		ShowReasons();
		break;
    case WM_COPY:	// hijacked - show answer
		ShowAnswer();
		break;
    case WM_CUT:
    case WM_CLEAR:
    case WM_PASTE:
        return (BOOL)SendMessage(LOWORD(wParam));
    case ME_SELECTALL:
        return (BOOL)SendMessage (EM_SETSEL, 0, -1);
    default:
        return CEdit::OnCommand(wParam, lParam);
    }
	return TRUE;
}

HBRUSH CSudokuEdit::CtlColor(CDC* pDC, UINT nCtlColor) 
{
	HBRUSH hbr;

	if (state == CS_UNINITIALIZED)
	{
		return NULL;
	}

    // Set the background mode for text to transparent 
    // so background will show thru.
    pDC->SetBkMode(TRANSPARENT);

	switch (state)
	{
		case CS_NORMAL:
		case CS_GUESS:
			hbr = *cbBlank;
			pDC->SetTextColor(crNormalText);
			pDC->SetBkColor(crNormalText);
			break;

		case CS_HINT:
			hbr = *cbHint;
			pDC->SetTextColor(crHintText);
			pDC->SetBkColor(crHintText);
			break;

		case CS_ANSWER:
			hbr = *cbAnswer;
			pDC->SetTextColor(crAnswerText);
			pDC->SetBkColor(crAnswerText);
			break;

		case CS_IMPOSSIBLE:
			hbr = *cbImposs;
			pDC->SetTextColor(crImpossText);
			pDC->SetBkColor(crImpossText);
			break;
	}

	// Changed text will always be read
	if (bChanged)
	{
		pDC->SetTextColor(RGB(255,0,0));
		pDC->SetBkColor(RGB(255,0,0));
		hbr = *cbChanged;
	}

	return hbr;
}

void CSudokuEdit::SetCellBrushes(CBrush* pbNorm, CBrush* pbAnswer, CBrush* pbPoss, CBrush* pbImposs)
{
	cbBlank = pbNorm;
	cbAnswer = pbAnswer;
	cbHint = pbPoss;
	cbImposs = pbImposs;
	cbChanged = new CBrush(RGB(225, 239, 143));
}


void CSudokuEdit::SetCellFonts(CFont* norm, CFont* answer, CFont* poss, CFont* imposs)
{
	cfNormal = norm;
	cfAnswer = answer;
	cfPossibilities = poss;
	cfImposs = imposs;
};

void CSudokuEdit::SetCellTextColors(COLORREF norm, COLORREF answer, COLORREF poss, COLORREF imposs)
{
	crNormalText = norm;
	crAnswerText = answer;
	crHintText = poss;
	crImpossText = imposs;
}

void CSudokuEdit::RefreshCell(bool hintsOn, bool showAnswers)
{
	std::string sPoss;
	char currText[16];
	std::stringstream ss;

	int answer = m_pPuzzle->GetPossibilitiesString(m_iCellNum, sPoss);

	if (showAnswers && (answer != 0))
	{
		state = CS_ANSWER;
		ss << answer;
		SetReadOnly(TRUE);
		SetFont(cfAnswer);
		SetWindowText(ss.str().c_str());
		return;
	}

	if (hintsOn && (state != CS_HINT) && (state != CS_ANSWER))
	{
		prevState = state;
		state = CS_HINT;
	}
	else if (!hintsOn && (state == CS_HINT))
	{
		state = prevState;
	}

	GetWindowText(currText, 16);
	int guess = atoi(currText);


	SetReadOnly(FALSE);

	switch (state)
	{
		case CS_ANSWER:
			ss << answer;
			SetReadOnly(TRUE);
			SetFont(cfAnswer);
			SetWindowText(ss.str().c_str());
			break;
		case CS_GUESS:
			ss << m_guess;
			SetReadOnly(FALSE);
			SetFont(cfNormal);
			SetWindowText(ss.str().c_str());
			break;
		case CS_HINT:
			SetReadOnly(TRUE);
			SetFont(cfPossibilities);
			SetWindowText(sPoss.c_str());
			break;
		case CS_NORMAL:
			SetFont(cfNormal);
			SetWindowText(ss.str().c_str());
			break;
		case CS_IMPOSSIBLE:
			SetFont(cfImposs);
			break;
		default:
			break;
	}
return;
	if (state == CS_ANSWER)
	{
		std::stringstream ss;
		ss << answer;

	}
	else if ((guess == 0) && (answer != 0))
	{
		std::stringstream ss;
		ss << answer;

		state = CS_ANSWER;
		//SetReadOnly(TRUE);
		SetFont(cfNormal);
		SetWindowText(ss.str().c_str());
	}
	else
	{
		if (hintsOn)
		{
			m_guess = guess;
			state = CS_HINT;
			SetReadOnly(TRUE);
			SetFont(cfPossibilities);
			SetWindowText(sPoss.c_str());
		}
		else
		{

			SetReadOnly(FALSE);
			if (state == CS_IMPOSSIBLE)
			{
				SetFont(cfImposs);
			}
			else
			{
				state = CS_NORMAL;
				SetFont(cfNormal);
				if (m_guess == 0)
					SetWindowText("");
				else
				{
					std::stringstream ss;
					ss << m_guess;
					SetWindowText(ss.str().c_str());
				}
			}
		}
	}
}

void CSudokuEdit::ShowReasons()
{
	if (m_pLB)
	{
		m_pLB->ResetContent();
		std::vector<std::string> sReasons;
		std::vector<std::string>::iterator reasonsIter;

		m_pPuzzle->GetReasons(m_iCellNum, sReasons);
		for (reasonsIter = sReasons.begin(); reasonsIter != sReasons.end(); ++reasonsIter)
		{
			m_pLB->AddString(reasonsIter->c_str());
		}
	}
}

void CSudokuEdit::ShowAnswer()
{
	int answer = m_pPuzzle->GetAnswer(m_iCellNum);
	if (answer != 0)
	{
		std::stringstream ss;
		ss << answer;

		state = CS_ANSWER;
		//SetReadOnly(TRUE);
		SetFont(cfAnswer);
		SetWindowText(ss.str().c_str());
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
I live in Minnesota with my wife and son, having moved here from Montana. I enjoy creating software which benefits people, and I am fortunate to have a job where I am able to do that.
I enjoy reading, hunting and fishing, any sport with a racquet or paddle, and rooting for the New England Patriots.
In addition to my full-time job, I founded Rohawk, LLC which creates software for Christian churches.

Comments and Discussions