At the end, I have adopted MVC as my architecture of this project, the original choice is MVVM
However, I think extra C# WPF feature should be mastered before I can implemented state-of-the-art MVVM design as C# support WPF MVVM natively with different built in functions.
These are the basic game object properties that I have implemented, including:
- Push
- Control
- Kill
- Win
This is the main logic of game status, it can be initialized by reading filename
The progress of the game will be saved in a multidimensional container
List<List<Stack<string>>>
The above graph has illustrated the basic design of the grid inside model
This is the basic unit for every grid rendered, it contains self-defined height and width.
As aforementioned, each grid is implmeneted in Stack
container, my very first implementation includes only the Peek()
element, as it is easier to implement.
However, I discovered that multi-layer rendering is available in the original game, therefore, I have used DrawingGroup
to consolidate all the requried images.
Layers: Uri(@'image.path')
> BitmapImage()
> ImageDrawing()
> DrawingGroup
Using the above layer, single Image
can be added to the Children of Grid.
This is the 2D map of the TileView
, the key methods will be UpdateViews()
.
It clears all the children of the grid and re-render the whole View for every movement.
The fundentmental RuleBaseObject
is implemented here. Similar to the model, basic game properties have been added here, for instance:
- CanPush
- CanControl
- CanKill
- CanWin
- CanStop
All the above entries will be initialized to false
by default
Most of the game logics are implemented here, all rule should be recalculated for each movement of the player.
The flow of calculating the rule:
ResetRules() > RecalculateRules()
In the ResetRule
, list of prefix and suffix are defined:
_rulePrefix {
"T_BABA", "T_BLANK", "T_BALL", "T_ROCK",
"T_TREE", "T_MOUNT", "T_WATER"
};
_ruleSuffix {
"T_WIN", "T_YOU", "T_KILL",
"T_PUSH", "T_STOP"
};
Satifying any of the following structure can be considered rule
:
1. Horizontal rule (LR rule)
[prefix] [IS] [suffix]
2. Vertical rule (UD rule)
[prefix]
[IS]
[suffix]
By this setup, shape like these can be correctly executed:
[prefix]
[prefix] [IS] [suffix]
[suffix]
All the rule will be stored inside _rulesDict
, which is Dictionary<string, RuleBaseObject>
, there are two types of key, for instance:
T_BABA
: The textbox rule object of BABA
BABA
: The underlying object of BABA, i.e. the BABA
MoveSrcToDest()
contains the evaulation of movement, the priority should be:
WINNING > KILLING > PUSHING > STOPING
Once the orders have been defined, the rest of the checking should be straight forward
I actually spent most of my debugging time on the C# language itself, being partiallly spoiled by Python, I assume
too much on C# itself.
For instance, I try to keep track of every game state for the undo function, therefore, I store every game state whenever the player moves and they are stored in
Stack<List<List<Stack<string>>>>
, so that we can simply Pop()
for every undo action.
This is my original code that give me hours of debugging :
var res = _gameStateModel.GetState();
_gameHistory.Push(res);
YES ...
When looking back, the mistake is quite obvious but I actually assume it is going to work, say this is the game state changes:
stateA -> stateB -> stateC
// What I am expecting
_gameHistory.Push(stateA);
_gameHistory.Push(stateB);
_gameHistory.Push(stateC);
// So the result stack should look like
stateC (front)
stateB
stateA (back)
After hour of debugging, I discovered that this is what the stack looks ( I still have little faith in my code so I am checking other connected functions for bugs )
stateC (front)
stateC
stateC (back)
It turns out that the following line only make the _gameHistory
being refer
the object itself, it is not saving the copy
of object as I expected.
As in C++, the gameHistory should be in pointer type and more obvious and I have assumed that the language will do the deep copying for me.
_gameHistory.Push(res);
Therefore, I have implemented the GetDeepCopy()
method and copy the whole object using iterations.