Skip to main content

A board game in MVVM Part 4: The ViewModel

This is a continuation of my experience creating a quick board game in silverlight 5
Original Post
Part 1 - The Model
Part 2 - The AI
Part 3 - The View
Part 3b - Commands and Converters
Play the Game

In MVVM the viewmodel mediates between the view and the model exposing the model or encapsulates interaction with the model that the view requires but shouldn't be performing on its own such as the user interaction.

The way I created the ViewModel here in Viking is fairly simple. It creates and exposes the main Game object to the view, and tells the game object when the user is trying to perform an action. Aside from that, it's dedicated to the user interaction. In the case of Viking, it's primary user interaction comes into play when the user:

  • Selects a piece is move (or cancels a current selection)
  • Selects a square to move an active piece to
  • Changes the player types between human and AI
  • Restarts the game

These can be seen in the following code:

  1.     public class MainViewModel : BasePropertyChanged
  2.     {
  3.         private DelegateCommand<Piece> activatePieceCommand;
  4.  
  5.         private Game game;
  6.  
  7.         private DelegateCommand<Square> makeMoveCommand;
  8.  
  9.         private DelegateCommand<object> restartGameCommand;
  10.  
  11.         private DelegateCommand<Player> togglePlayerTypeCommand;
  12.  
  13.         public MainViewModel()
  14.         {
  15.             Game = new Game();
  16.         }
  17.  
  18.         public DelegateCommand<Piece> ActivatePieceCommand
  19.         {
  20.             get
  21.             {
  22.                 if (this.activatePieceCommand == null)
  23.                 {
  24.                     this.activatePieceCommand = new DelegateCommand<Piece>(ActivatePiece);
  25.                 }
  26.  
  27.                 return this.activatePieceCommand;
  28.             }
  29.         }
  30.  
  31.         public Player AttackerPlayer
  32.         {
  33.             get
  34.             {
  35.                 return Player.Attacker;
  36.             }
  37.         }
  38.  
  39.         public Player DefenderPlayer
  40.         {
  41.             get
  42.             {
  43.                 return Player.Defender;
  44.             }
  45.         }
  46.  
  47.         public Game Game
  48.         {
  49.             get
  50.             {
  51.                 return this.game;
  52.             }
  53.  
  54.             set
  55.             {
  56.                 if (value != game)
  57.                 {
  58.                     game = value;
  59.                     RaisePropertyChanged(() => Game);
  60.                 }
  61.             }
  62.         }
  63.  
  64.         public DelegateCommand<Square> MakeMoveCommand
  65.         {
  66.             get
  67.             {
  68.                 if (this.makeMoveCommand == null)
  69.                 {
  70.                     this.makeMoveCommand = new DelegateCommand<Square>(MakeMove);
  71.                 }
  72.  
  73.                 return this.makeMoveCommand;
  74.             }
  75.         }
  76.  
  77.         public DelegateCommand<object> RestartGameCommand
  78.         {
  79.             get
  80.             {
  81.                 if (this.restartGameCommand == null)
  82.                 {
  83.                     this.restartGameCommand = new DelegateCommand<object>(RestartGame);
  84.                 }
  85.  
  86.                 return this.restartGameCommand;
  87.             }
  88.         }
  89.  
  90.         public DelegateCommand<Player> TogglePlayerTypeCommand
  91.         {
  92.             get
  93.             {
  94.                 if (this.togglePlayerTypeCommand == null)
  95.                 {
  96.                     this.togglePlayerTypeCommand = new DelegateCommand<Player>(TogglePlayerType);
  97.                 }
  98.  
  99.                 return this.togglePlayerTypeCommand;
  100.             }
  101.         }
  102.  
  103.         public void ActivatePiece(Piece targetPiece)
  104.         {
  105.             if (Game.IsActive)
  106.             {
  107.                 if (targetPiece.IsMoveable && !targetPiece.IsActive)
  108.                 {
  109.                     targetPiece.IsActive = true;
  110.                     Game.Board.ActivePiece = targetPiece;
  111.                 }
  112.                 else if (targetPiece.IsMoveable)
  113.                 {
  114.                     targetPiece.IsActive = false;
  115.                     Game.Board.ActivePiece = null;
  116.                     Game.Board.SetMoveablePieces(Game.CurrentPlayer);
  117.                 }
  118.             }
  119.         }
  120.  
  121.         public void MakeMove(Square targetSquare)
  122.         {
  123.             if (Game.IsActive)
  124.             {
  125.                 Game.MovePiece(targetSquare);
  126.             }
  127.         }
  128.  
  129.         public void RestartGame(object parameter = null)
  130.         {
  131.             Game.Restart();
  132.         }
  133.  
  134.         public void TogglePlayerType(Player playerToToggle)
  135.         {
  136.             if (playerToToggle == Player.Attacker)
  137.             {
  138.                 Game.NextAttacker = Game.NextAttacker == PlayerType.Human ? PlayerType.AI : PlayerType.Human;
  139.                 if (Game.NextAttacker == PlayerType.AI && Game.NextDefender == PlayerType.AI)
  140.                 {
  141.                     Game.NextDefender = PlayerType.Human;
  142.                 }
  143.             }
  144.             else
  145.             {
  146.                 Game.NextDefender = Game.NextDefender == PlayerType.Human ? PlayerType.AI : PlayerType.Human;
  147.                 if (Game.NextAttacker == PlayerType.AI && Game.NextDefender == PlayerType.AI)
  148.                 {
  149.                     Game.NextAttacker = PlayerType.Human;
  150.                 }
  151.             }
  152.         }
  153.     }