Recreating The Board Game Risk
A Project for those of us with too much time on our hands.
First Posted November 12, 2013
Last Updated February 20, 2014

February 20, 2014

Trying to close in on getting the project finished.  Currently, I am trying to get the Risk Cards  working.  While doing that, I made some changes to some of the methods in CAiThread.  In particular, the functions that send messages to the worker thread function.  The code was nearly identical so it made sense to consolidate the code into one function.  This was a correct thing to do, but boy it took me a while to fix it.  For instance, one of the functions originally looked like this:

void CAiThread::Choose(void *payload,int sz)
{
    char *pTemp = (char *)payload;
    AMSG *pMSG = CreateAMSG(sz,(char *)&pTemp,AIMSG_CHOOSE);
    pMSG->hWind = m_hWnd;
    pMSG->ReplyCmd = WM_MSGFROMAI;
    this->m_MSGQ->Insert(pMSG);
}
 
And I consolidated to something like this:

void CAiThread::Choose(int Aux, void *payload,int sz)
{
    Message(AIMSG_CHOOSE,Aux,payload,sz);
}

void CAiThread::Message(int cmd,int Aux,void *payload,int sz)
{
    AMSG *pMSG = CreateAMSG(sz,(char *)payload,cmd);
    pMSG->hWind = m_hWnd;
    pMSG->Aux = Aux;
    pMSG->ReplyCmd = WM_MSGFROMAI;
    this->m_MSGQ->Insert(pMSG);
}
 
Now, for all you experts out there, probably no reason to read further.  You see my dumb mistake.  It was a mistake made in haste.  The problem was the:

   char *pTemp = (char *)payload;

line of code.  This was something I threw in to quickly fix a problem, and then no longer paid any attention to it.  The intent I had was as it looks now.  That will teach me to code in haste, and to not put comments in the code...oh yeah, I still haven't put the comments  in.

Anyway, here is a new snapshot of the code.

Risk Game Files (Feb 20, 2014)

February 15, 2014

    Well, it has been about a month now since I last posted.  I am still working on the thing, but I am finally going to post some source code.  What you will find in the archive is both the Map Editor and the Game.  So, just what is the state of the files as of today?  Well, not great, but the game does work, although there are still some things missing.  For instance, there are no RISK cards at the moment, although you will  find some of the code in there for RISK cards.  I am sure you will find other things that are lacking as well.  The game supports up to 12 players.  The AI is, well, pathetic.  And rather than using dice, battles are determined by ROCK-PAPER-SCISSORS.  I decided on that because of the fact that any one of the three can win, so neither attacker or defender seem to have any particular advantage and who wins is determined by luck and who has the most power.  The state machine that runs the game is probably just a bit convoluted and maybe in future versions I will clean that up a bit.  So, here is the code.

Source/Binaries for Risk Game

This project is open source, you may use the files freely.
 
January 14, 2014

W
ell, I am still making progress  on the game, but you would hardly know it.  I have reorganized the program quite a bit.  I have moved a lot of the functions (Classes) into a separate DLL so that the code may be shared by not only the main program, but also the other DLLs that will be part of the game.  Speaking of which, I have actually got the AI pluggin interface working now, all I really need to do is finish up how things are going to work so I can finalize that interface.  I am also working on the graphics a bit, and have the number of armies in each territory displaying now, as well as an indicator as to which player is the current occupier.  There is one bug that occures from time to time that crashes the game, and I have been unable to track it down because when I look for it, it won't happen.  I still have no idea when I will release the first version yet.  Stay tuned.

 
December  29, 2013


I have actually got the AI's to play games and it looks like I have got a lot of the little bugs worked out of many of the classes.  Right now it takes about 50 turns for the AI's to conclude a game.  I am also cleaning up some of the code, mostly the code used to make lists.  There are lots of lists.  And the next step will be to make it so a Human player and pit them self against the AI.  Another step is also to make a mode where I can pit the AI's against each other so that I can verify many of the scoring assumptions I made.  And one last thing I need to do to make it equal to at least the original version I had as a kid is to include the Risk Cards.

December 12, 2013


I am started on the actual game app now.  So far, I have it only loading in the data and displaying the bitmap.  The only real function is the auto scrolling.  The auto scrolling is different from that in the Editor application.  To make the map scroll, right now you push down the SHIFT key and move the mouse towards the edge of the map where you want to scroll.  Eventually, soon maybe, I will have it doing an "infinite" scroll in the X direction, so that you can scroll clear around the world.  The game app is also different in that I am using just the standard CView class to display the view.

    Update at 8:36PM

Well, I just got the infinite horizontal scrolling working.  So when you scroll horizontally, it will do so continuously, in both directions.  Plus, when you click on a territory, I get the correct identification for that spot, no matter how the map is scrolled.  Pretty cool, if you ask me.  Sol, in the next couple of days, I am going to start working on the state machine that actually plays  the game, and start working on at least a crude AI that I can play against, or have it play against itself.  Wish I could have learned Windows Programming a long time ago.

December 10, 2013


I finally got the map done.  More or less that is.  I need to write some code for the map editor to check to make sure that the links between territories are in both directions.  So, I will shortly be able to move onto the more fun task of trying to actually make a playable game.  Yes, I realize that there are probably territories in the wrong place.  My geography teacher is probably spinning in her grave.  Maybe someday I will make a new map.  I am still hoping to post the editor program soon.  I still need to get the OPEN, and NEW File menu functions to stop crashing the program.

Download Current map as of 12-10-2013

December 8, 2013
One of the features I needed to add to the editor was auto scrolling.  After doing some research on the web, it seemed like a fairly simple thing to do, but I discovered that it wasn't quite that easy.  I had "moderate" success, but just could not quite get it to work anything like I have seen other programs do.  So, it was back to doing research.  I finally found a forum where the answer was "Search for CAutoScrollView".  The OP said, hey, it works great, so I decided I better try to find it.  I did.  My only problem withy the code is that there is no attribution.  I have no idea who wrote this originally.  I made some very minor modifications and here is the result.  And sure enough, it works pretty good.  I only had to make some very minor mods to my original view class to implement this.

AutoScrollView.h
#if !defined(AFX_AUTOSCROLLVIEW_H__769B5A42_3E24_47C7_956C_1121962185B1__INCLUDED_)
#define AFX_AUTOSCROLLVIEW_H__769B5A42_3E24_47C7_956C_1121962185B1__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// AutoScrollView.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CAutoScrollView view

class CAutoScrollView : public CScrollView
{
protected:
    CAutoScrollView();           // protected constructor used by dynamic creation
    DECLARE_DYNCREATE(CAutoScrollView)

   // Attributes
   public:
   BOOL        m_bAutoScroll;
   BOOL        m_bIsScrolling;

   // Operations
public:
   BOOL IsAutoScrolling(){return m_bIsScrolling;}
   void EnableAutoScrolling (BOOL bMode){m_bAutoScroll = bMode;}
protected:
   virtual void OnAutoScroll(CPoint point, BOOL bBeforeScroll);

// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CAutoScrollView)
protected:
    virtual void OnDraw(CDC* pDC);      // overridden to draw this view
    virtual void OnInitialUpdate();     // first time after construct
    //}}AFX_VIRTUAL

// Implementation
protected:
   void AutoScroll(UINT nRefMessage);
    virtual ~CAutoScrollView();
#ifdef _DEBUG
    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;
#endif

    // Generated message map functions
    //{{AFX_MSG(CAutoScrollView)
        // NOTE - the ClassWizard will add and remove member functions here.
   afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_AUTOSCROLLVIEW_H__769B5A42_3E24_47C7_956C_1121962185B1__INCLUDED_)

AutoScrollView.cpp
// AutoScrollView.cpp : implementation file
//
//
// CAutoScrollView is derived from CScrollView. It adds the AutoScroll feature
// that is needed in many applications. AutoScrolling means that the window
// begins to scroll as soon as the mouse cursor leaves the client area of the
// current View while the left mouse button is pressed. You can customize the
// button used to autoscroll using the SetAutoButton inline member function.
// SetAutoButton accepts one parameter of type _AutoButton: mbLeft, mbRight or
// mbMiddle. SetAutoButton returns the button type that was active before the
// call.
//
// The amount by which the View is scrolled depends on the distance between the
// the window border and the mouse cursor. The greater the distance, the faster
// the View scrolls.
//
// You can enable or disable the AutoScroll feature by using the
// EnableAutoScrolling() inline member function. It accepts one parameter
// of type BOOL.
//
// By default, autoscrolling is enabled with the left button.
//
// BOOL IsAutoScrolling() tells you whether autoscrolling operations are
// underway.
//
// To give your application's View a chance to properly update the screen while
// autoscrolling, CAutoScrollView calls its OnAutoScroll() virtual member
// function just before and just after scrolling. Override this function in
// your View if you want to take some action whenever autoscrolling occurs.
// By default, OnAutoScroll does nothing.
//
// OnAutoScroll accepts two parameters:
//
// virtual void OnAutoScroll(CPoint point, BOOL bBeforeScroll);
//
// point indicates the current position of the mouse cursor in client device
// coordinates. That is, the ScreenToClient() function has been applied to point
// but no DPtoLP operation has been done.
//
// bBeforeScroll is TRUE when OnAutoScroll is called before scrolling and
// FALSE otherwise.
//
// Most of the time you will not have any opportunity to initialize a
// CAutoScrollView yourself. So, member variables are initialized in the
// constructor directly.
//
// CAutoScrollView automatically adapts to the mapping mode. For example, if
// you have set a metric mapping mode, the nMapFactor will be used to
// reverse y coordinates.
//
// CAutoScrollView also corrects an annoying behavior of
// CScrollView::ScrollToPosition. This member function doesn't check whether
// the scroll limit has already been reached and always tries to scroll. This
// wouldn't be a problem if a call to ScrollWindow was not made systematically.
// This generates flicker. When AutoScrolling, this condition doesn't occur.
//

#include "stdafx.h"
#include "riskedit.h"
#include "AutoScrollView.h"

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

/////////////////////////////////////////////////////////////////////////////
// CAutoScrollView

IMPLEMENT_DYNCREATE(CAutoScrollView, CScrollView)

CAutoScrollView::CAutoScrollView()
{
   m_bAutoScroll = TRUE;
   m_bIsScrolling = FALSE;
}

CAutoScrollView::~CAutoScrollView()
{
}


BEGIN_MESSAGE_MAP(CAutoScrollView, CScrollView)
    //{{AFX_MSG_MAP(CAutoScrollView)
        // NOTE - the ClassWizard will add and remove mapping macros here.
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CAutoScrollView drawing

void CAutoScrollView::OnInitialUpdate()
{
    CScrollView::OnInitialUpdate();

    CSize sizeTotal;
    // TODO: calculate the total size of this view
    sizeTotal.cx = sizeTotal.cy = 100;
    SetScrollSizes(MM_TEXT, sizeTotal);
}

void CAutoScrollView::OnDraw(CDC* pDC)
{
    CDocument* pDoc = GetDocument();
    // TODO: add draw code here
}

/////////////////////////////////////////////////////////////////////////////
// CAutoScrollView diagnostics

#ifdef _DEBUG
void CAutoScrollView::AssertValid() const
{
    CScrollView::AssertValid();
}

void CAutoScrollView::Dump(CDumpContext& dc) const
{
    CScrollView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CAutoScrollView message handlers

void CAutoScrollView::AutoScroll(UINT nRefMessage)
{
    MSG   msg;             // dummmy message structure to process incoming
    // messages while autoscrolling.
    CPoint ptScrollPos,    // Current scroll position - logical units
    ptDevScrollPos, // Current scroll position - device units
    ptCursorPos;    // Current mouse cursor position
    CRect  rc;               // Client area
    long   dx, dy;         // Scrolling increment
    SIZE   sizeTotal,      // CScrollView scroll data
    sizePage,
    sizeLine;
    int    nMapMode,       // Mapping mode
    nMapFactor,     // Accounts for mapping mode
    xMin, xMax,
    yMin, yMax;   // Scroll range

    if (!m_bAutoScroll) return;

    msg.message = 0;   // forces at least one loop.
    SetCapture();
    GetDeviceScrollSizes(nMapMode, sizeTotal, sizePage, sizeLine);

    // We keep track of the scroll range because CScrollView::ScrollToPosition always
    // try to scroll even if the scroll limit has been reached. This results in screen
    // flickering when ScrollWindow is called.
    GetScrollRange(SB_HORZ, &xMin, &xMax);
    GetScrollRange(SB_VERT, &yMin, &yMax);

    // Process all messages until the relevant mouse button
    // has been released. nRefMessage depends on which button
    // has been used to trigger autoscrolling.
    //   while (msg.message != nRefMessage)
    BOOL bSawRefMessage = FALSE;

    while (!bSawRefMessage)
    {
        // Process incoming messages until autoscroll button is released

        // You cannot peek here because it may process an invalidate
        // due to the scrolling.

        /*
        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        */

        ptScrollPos = GetScrollPosition();
        ptDevScrollPos = GetDeviceScrollPosition();
        GetCursorPos(&ptCursorPos);
        ScreenToClient(&ptCursorPos);
        GetClientRect(&rc);
        dx = 0L;
        dy = 0L;

        if ((ptCursorPos.y < 0) && (ptDevScrollPos.y != yMin))
            // Cursor is above client area
            dy = min(-sizeLine.cy, max(-sizePage.cy, (ptCursorPos.y/10) * sizeLine.cy));
        else if ((ptCursorPos.y > rc.bottom) &&  (ptDevScrollPos.y != yMax))
            // Cursor is below client area
            dy = max(sizeLine.cy, min(sizePage.cy, ((ptCursorPos.y - rc.bottom)/10) * sizeLine.cy));
        // otherwise we can't scroll anyway

        if ((ptCursorPos.x < 0) && (ptDevScrollPos.x != xMin))
            // Cursor is on the left of the client area
            dx = min(-sizeLine.cx, max(-sizePage.cx, (ptCursorPos.x/10) * sizeLine.cx));
        else if ((ptCursorPos.x > rc.right) && (ptDevScrollPos.x != xMax))
            // Cursor is on the right of the client area
            dx = max(sizeLine.cx, min(sizePage.cx, ((ptCursorPos.x - rc.right)/10) * sizeLine.cx));
        // otherwise we can't scroll anyway

        // if mouse cursor is dragging outside the client area, scrolling occurs
        if ((dx != 0) || (dy != 0))
        {
            // Flip the Y coordinate if we're not in MM_TEXT
            nMapFactor = (nMapMode == MM_TEXT) ? 1 : -1;
            ptScrollPos.y += (int) dy * nMapFactor;
            ptScrollPos.x += (int) dx;
            m_bIsScrolling = TRUE;
            OnAutoScroll(ptCursorPos, TRUE);
            ScrollToPosition(ptScrollPos);

            while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))    //message pump 2
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);

                //            if (msg.message == nRefMessage) break;
                if (msg.message == nRefMessage) bSawRefMessage = TRUE;
            }    //end of message pump 2

            //         if (!bSawRefMessage)
            OnAutoScroll(ptCursorPos, FALSE);
        }
        else
        {
            while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))    //message pump #3
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);

                //            if (msg.message == nRefMessage) break;
                if (msg.message == nRefMessage) bSawRefMessage = TRUE;
            }    //end of message pump #3

            m_bIsScrolling = FALSE;
        }    //end of if-else
    }    //end of while loop
    ReleaseCapture();
    m_bIsScrolling = FALSE;
}

void CAutoScrollView::OnLButtonDown(UINT nFlags, CPoint point)
{
    CScrollView::OnLButtonDown(nFlags, point);
    AutoScroll(WM_LBUTTONUP);
}

void CAutoScrollView::OnAutoScroll(CPoint /*point*/, BOOL /*bBeforeScroll*/)
{
}


December 7, 2013

Well, things are progressing.  It seems that drawing the map is a lot more difficult than  writing the code to draw it with.  The  map, is, however nearly done.  I have had to fix a few bugs in the code, or changed the way the program worked to make it easier to draw with, but really most of the effort has actually been creating the map since November 12.  Right now, I have hit a minor road block in that I cannot do an operation with the program in its current state, so back to the drawing board to make a few more improvements to the code.

I am still not ready to post the code yet, as there are just a lot of things that don't work right.  But it is getting closer.  I am hoping that I will be able to get started working on the AI engine real soon.  I am going to try and make it so that it runs off of Lua Scripts.  I have downloaded the Lua DLL so that I might incorporate it into my program.

November 12, 2013

This is my most recent project.  I have always liked the game risk and have long been fascinated by it.  The version I liked the best was the one that Hasbro came out with in 1996 called Ultimate Risk.  This was of course a game that ran on a PC.  However, it was for Windows 95, and never seemed to run correctly under XP, and won't even install in windows 7.

There are lots of versions of Risk out there on the net.  The one called Domination is one of the better ones, and another one I liked was TurboRisk.  TurboRisk is interesting because it has a script engine that you can use to write your own AI players.  Domination is interesting because of the fact that you are free to make your world look any way you want.

But none of these satisfied me.  I thought it would be fun to include more aspects to the game.  Besides how many armies you have, there are economic factors, industrial, agriculture, transportation, etc.  Some territories are a boon, some are a bane.  And besides land battles, what about sea battles.

So, I embarked on this project.  First thing I needed to do was create a map editor.  This is challenging enough.  The map editor will let you draw your map using a bare minimum of painting tools, plus, it will also let you define areas with polygons that are connected to a territory so that the program will know what you are pointing at.  The program will also let you define which territories are next to which.  This is where I am at right now.  I am working on my first map, which is about 66% done.  Sure is a lot of work.  Anyway, here are some pics of what I have so far.









In the above dialog box, it is indicating that New England is adjacent to both New Youk and Oregon.  Well, the Geography might be suspect, but you get the idea.


 .





The above is a short example of what the map data format looks like.  There are some things that are not in this file, but I will update this later.