Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate Tic-Tac-Toe Unity and Azure (CSharp) Samples to dotnet-isolated, CloudScript and Azure APIs #79

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,70 +1,85 @@
// Copyright (C) Microsoft Corporation. All rights reserved.

using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using PlayFab.TicTacToeDemo.Models;
using System.Net.Http;
using PlayFab.Plugins.CloudScript;
using PlayFab.TicTacToeDemo.Util;
using PlayFab;

namespace TicTacToeFunctions.Functions
{
public static class MakeAIMove
public class MakeAIMove(ILoggerFactory loggerFactory)
{
[FunctionName("MakeRandomAIMove")]
public static async Task<TicTacToeMove> MakeRandomAIMove(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage req,
ILogger log)
[Function("MakeAIMove")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]
HttpRequestData req,
FunctionContext executionContext)
{
var context = await FunctionContext<PlayFabIdRequest>.Create(req);
return await MakeMinMaxAIMove(req, executionContext);
}

[Function("MakeRandomAIMove")]
public async Task<IActionResult> MakeRandomAIMove(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestData req,
FunctionContext executionContext)
{
var context = await PlayFabFunctionHelper.GetContext(_logger, req);
if (context is null) return new BadRequestObjectResult("Invalid context");

Settings.TrySetSecretKey(context.ApiSettings);
Settings.TrySetCloudName(context.ApiSettings);
var settings = new PlayFabApiSettings { TitleId = context.TitleAuthenticationContext.Id, };
Settings.TrySetSecretKey(settings);
Settings.TrySetCloudName(settings);

var playFabId = context.FunctionArgument.PlayFabId;
var playFabId = context.FunctionArgument.ToObject<PlayFabIdRequest>().PlayFabId;

// Attempt to load the player's game state
var state = await GameStateUtil.GetCurrentGameState(playFabId, context.ApiSettings, context.AuthenticationContext);
var state = await GameStateUtil.GetCurrentGameState(playFabId, settings);

// Look for a random AI move to make
var aiMove = TicTacToeAI.GetNextRandomMove(state);

// Store the AI move on the current game state
var oneDimMoveIndex = aiMove.row * 3 + aiMove.col;
state.Data[oneDimMoveIndex] = (int) OccupantType.AI;
await GameStateUtil.UpdateCurrentGameState(state, playFabId, context.ApiSettings, context.AuthenticationContext);
await GameStateUtil.UpdateCurrentGameState(state, playFabId, settings);

// Respond with the AI move
return aiMove;
return new OkObjectResult(aiMove);
}

[FunctionName("MakeMinimaxAIMove")]
public static async Task<TicTacToeMove> MakeMinimaxAIMove(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage req,
ILogger log)

[Function("MakeMinMaxAIMove")]
public async Task<IActionResult> MakeMinMaxAIMove(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext executionContext)
{
var context = await FunctionContext<PlayFabIdRequest>.Create(req);
var context = await PlayFabFunctionHelper.GetContext(_logger, req);
if (context is null) return new BadRequestObjectResult("Invalid context");

Settings.TrySetSecretKey(context.ApiSettings);
Settings.TrySetCloudName(context.ApiSettings);
PlayFabApiSettings settings = new() { TitleId = context.TitleAuthenticationContext.Id, };
Settings.TrySetSecretKey(settings);
Settings.TrySetCloudName(settings);

var playFabId = context.FunctionArgument.PlayFabId;
var playFabId = context.FunctionArgument.ToObject<PlayFabIdRequest>().PlayFabId;

// Attempt to load the Player's game state
var state = await GameStateUtil.GetCurrentGameState(playFabId, context.ApiSettings, context.AuthenticationContext);
var state = await GameStateUtil.GetCurrentGameState(playFabId, settings);

// Look for a minimax AI move to make
var aiMove = TicTacToeAI.GetNextMinimaxMove(state);

// Store the AI move on the current game state
var oneDimMoveIndex = aiMove.row * 3 + aiMove.col;
state.Data[oneDimMoveIndex] = (int) OccupantType.AI;
await GameStateUtil.UpdateCurrentGameState(state, playFabId, context.ApiSettings, context.AuthenticationContext);
await GameStateUtil.UpdateCurrentGameState(state, playFabId, settings);

// Respond with the AI move
return aiMove;
return new OkObjectResult(aiMove);
}

private readonly ILogger _logger = loggerFactory.CreateLogger<MakeAIMove>();
}
}
Original file line number Diff line number Diff line change
@@ -1,57 +1,48 @@
// Copyright (C) Microsoft Corporation. All rights reserved.

using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using PlayFab.TicTacToeDemo.Models;
using System.Net.Http;
using PlayFab.Plugins.CloudScript;
using PlayFab.TicTacToeDemo.Util;

namespace PlayFab.TicTacToeDemo.Functions
{
public static class MakePlayerMove
public class MakePlayerMove(ILoggerFactory loggerFactory)
{
[FunctionName("MakePlayerMove")]
public static async Task<MakePlayerMoveResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage req,
ILogger log)
[Function("MakePlayerMove")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestData req,
FunctionContext executionContext)
{
var context = await FunctionContext<MakePlayerMoveRequest>.Create(req);
var move = context.FunctionArgument.Move;
var context = await PlayFabFunctionHelper.GetContext(_logger, req);
if (context is null) return new BadRequestObjectResult("Invalid context");

Settings.TrySetSecretKey(context.ApiSettings);
Settings.TrySetCloudName(context.ApiSettings);
var settings = new PlayFabApiSettings { TitleId = context.TitleAuthenticationContext.Id, };
Settings.TrySetSecretKey(settings);
Settings.TrySetCloudName(settings);

var playFabId = context.FunctionArgument.PlayFabId;
var moveRequest = context.FunctionArgument.ToObject<MakePlayerMoveRequest>();

// Attempt to load the player's game state
var state = await GameStateUtil.GetCurrentGameState(playFabId, context.ApiSettings, context.AuthenticationContext);
var state = await GameStateUtil.GetCurrentGameState(moveRequest.PlayFabId, settings);
var move = moveRequest.Move;

var oneDimMoveIndex = move.row * 3 + move.col;
int oneDimMoveIndex = move.row * 3 + move.col;

// Move can only be made if spot was empty
if (state.Data[oneDimMoveIndex] == (int) OccupantType.NONE)
{
state.Data[oneDimMoveIndex] = (int) OccupantType.PLAYER;
await GameStateUtil.UpdateCurrentGameState(state, playFabId, context.ApiSettings, context.AuthenticationContext);
return new MakePlayerMoveResult()
{
Valid = true
};
await GameStateUtil.UpdateCurrentGameState(state, moveRequest.PlayFabId, settings);
return new OkObjectResult(new MakePlayerMoveResult { Valid = true });
}

// Move attempt was invalid
else
{
return new MakePlayerMoveResult()
{
Valid = false
};
}
return new OkObjectResult(new MakePlayerMoveResult { Valid = false });
}



private readonly ILogger _logger = loggerFactory.CreateLogger<MakePlayerMove>();
}
}
Original file line number Diff line number Diff line change
@@ -1,40 +1,49 @@
// Copyright (C) Microsoft Corporation. All rights reserved.

using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using System.Net.Http;
using PlayFab.TicTacToeDemo.Util;
using PlayFab.Plugins.CloudScript;
using PlayFab;
using PlayFab.TicTacToeDemo.Models;
using PlayFab.TicTacToeDemo.Util;

namespace TicTacToeFunctions.Functions
{
public static class ResetGameState
public class ResetGameState
{
[FunctionName("ResetGameState")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage req,
ILogger log)
[Function("ResetGameState")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestData req,
FunctionContext executionContext)
{
var context = await FunctionContext<PlayFabIdRequest>.Create(req);
var playFabId = context.FunctionArgument.PlayFabId;
var context = await PlayFabFunctionHelper.GetContext(_logger, req);
if (context is null) return new BadRequestObjectResult("Invalid context");

Settings.TrySetSecretKey(context.ApiSettings);
Settings.TrySetCloudName(context.ApiSettings);
var settings = new PlayFabApiSettings { TitleId = context.TitleAuthenticationContext.Id, };
Settings.TrySetSecretKey(settings);
Settings.TrySetCloudName(settings);

var newCurrentGameState = new TicTacToeState()
string playFabId = context.CallerEntityProfile.Lineage.MasterPlayerAccountId;

var newCurrentGameState = new TicTacToeState
{
Data = new int[9]
};

await GameStateUtil.UpdateCurrentGameState(
newCurrentGameState,
playFabId,
context.ApiSettings,
context.AuthenticationContext);
settings);

return new OkResult();
}

private readonly ILogger _logger;

public ResetGameState(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<ResetGameState>();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,52 +1,50 @@
// Copyright (C) Microsoft Corporation. All rights reserved.

using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using PlayFab;
using PlayFab.TicTacToeDemo.Models;
using System.Net.Http;
using PlayFab.Plugins.CloudScript;
using PlayFab.TicTacToeDemo.Util;

namespace PlayFab.TicTacToeDemo.Functions
namespace TicTacToeFunctions.Functions
{
public static class WinChecker
public class WinChecker
{
[FunctionName("WinCheck")]
public static async Task<WinCheckResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage entityRequest, HttpRequest httpRequest,
ILogger log)
[Function("WinCheck")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestData req,
FunctionContext executionContext)
{
// Extract the context from the incoming request
var context = await FunctionContext<PlayFabIdRequest>.Create(entityRequest);

string playFabId = context.FunctionArgument.PlayFabId;

Settings.TrySetSecretKey(context.ApiSettings);
Settings.TrySetCloudName(context.ApiSettings);
var context = await PlayFabFunctionHelper.GetContext(_logger, req);
if (context is null) return new BadRequestObjectResult("Invalid context");

// TODO: check if can be done with currentplayerid directly from context
// Extract the Player's PlayFabId from the request
string playFabId = context.FunctionArgument.ToObject<PlayFabIdRequest>().PlayFabId;

// Grab the current player's game state
var state = await GameStateUtil.GetCurrentGameState(playFabId, context.ApiSettings, context.AuthenticationContext);
PlayFabApiSettings settings = new() { TitleId = context.TitleAuthenticationContext.Id, };
Settings.TrySetSecretKey(settings);
Settings.TrySetCloudName(settings);

var winCheckResult = WinCheckUtil.Check(state);

if (winCheckResult.Winner != GameWinnerType.NONE)
{
// Update the leaderboard accordingly
await LeaderboardUtils.UpdateLeaderboard(playFabId, winCheckResult.Winner);

// Store the game history
await GameStateUtil.AddGameStateHistory(state, playFabId, context.ApiSettings, context.AuthenticationContext);

// Clear the current game state
await GameStateUtil.UpdateCurrentGameState(new TicTacToeState(), playFabId, context.ApiSettings, context.AuthenticationContext);
}
var state = await GameStateUtil.GetCurrentGameState(playFabId, settings);

// Determine the winner (if any)
var winResult = WinCheckUtil.Check(state);

// Update the leaderboard accordingly
await LeaderboardUtils.UpdateLeaderboard(playFabId, winResult.Winner);

return new OkObjectResult(winResult);
}

return winCheckResult;
private readonly ILogger _logger;

public WinChecker(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<WinChecker>();
}
}
}
Loading