Skip to content

Instantly share code, notes, and snippets.

@jeffhollan
Last active April 9, 2019 15:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeffhollan/8db9dde63de41a4276d4132ff0529094 to your computer and use it in GitHub Desktop.
Save jeffhollan/8db9dde63de41a4276d4132ff0529094 to your computer and use it in GitHub Desktop.
Tic Tac Toe durable sample
using System;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
namespace DurableFunctionsAlpha.TicTacToe
{
public static class GameSessionActor
{
[FunctionName("GameSessionActor")]
public static async Task RunGame(
[ActorTrigger] IDurableActorContext ctx)
{
var state = ctx.GetState<GameSessionState>();
if (ctx.IsNewlyConstructed) state.Value = new GameSessionState();
switch(ctx.OperationName.ToLowerInvariant())
{
// Operation to start a new game
case "start-game":
var startGameRequest = ctx.GetOperationContent<StartGameRequest>();
state.Value.GameBoard = new string[3, 3];
state.Value.PlayerO = startGameRequest.PlayerO;
state.Value.PlayerX = startGameRequest.PlayerX;
state.Value.NextTurn = startGameRequest.PlayerX;
break;
// Operation to add a move to the board
case "add-move":
var moveRequest = ctx.GetOperationContent<MoveRequest>();
// If the player who's turn it isn't tries to make a move
if (!state.Value.GameEnded && moveRequest.Player.ActorKey != state.Value.NextTurn.ActorKey)
throw new InvalidOperationException($"Was not player {moveRequest.Player.ActorKey} turn");
// If that turn is already taken
if (state.Value.GameBoard[moveRequest.Row, moveRequest.Column] != null)
throw new InvalidOperationException($"That move is not available: {moveRequest}");
// Update the game board
state.Value.GameBoard[moveRequest.Row, moveRequest.Column] = moveRequest.Move;
// If the game should be continued
if (!state.Value.GameEnded)
{
// Update next player and send a notification to next player
state.Value.NextTurn = moveRequest.Player.ActorKey == state.Value.PlayerX.ActorKey ? state.Value.PlayerO : state.Value.PlayerX;
await ctx.CallActivityAsync("NotifyPlayerTurnAvailable", state.Value.NextTurn);
}
// If the move resulted in the game being over (e.g. 3 in a row)
else
{
// Send a notification to the players game over
await ctx.CallActivityAsync("NotifyPlayersWinner", new
{
state.Value.PlayerX,
state.Value.PlayerO,
state.Value.Winner
});
}
break;
case "cancel-game":
ctx.DestructOnExit();
break;
default:
break;
}
}
}
}
using Microsoft.Azure.WebJobs;
namespace DurableFunctionsAlpha.TicTacToe
{
public class GameSessionState
{
public string[,] GameBoard
{
get
{
return this.GameBoard;
}
set
{
// Do some logic here to see if game still active
this.GameBoard = value;
}
}
public ActorId PlayerX { get; set; }
public ActorId PlayerO { get; set; }
public ActorId NextTurn { get; set; }
public bool GameEnded { get; }
public ActorId Winner { get; set; }
}
}
using Microsoft.Azure.WebJobs;
namespace DurableFunctionsAlpha.TicTacToe
{
public class MoveRequest
{
public ActorId Player { get; set; }
public int Row { get; set; }
public int Column { get; set; }
public string Move { get; set; }
}
}
using Microsoft.Azure.WebJobs;
namespace DurableFunctionsAlpha.TicTacToe
{
public class StartGameRequest
{
public ActorId PlayerX { get; set; }
public ActorId PlayerO { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment