Example #1
0
        public Task <IPlayerGrain> NewPlayer(IAccountGrain account, string name)
        {
            if (_state == GameState.Unstarted)
            {
                var          accountKey = account.GetPrimaryKey();
                IPlayerGrain playerGrain;
                if (_players.TryGetValue(accountKey, out playerGrain))
                {
                    return(Task.FromResult(playerGrain));
                }

                var playerGuid = Guid.NewGuid();
                playerGrain = PlayerGrainFactory.GetGrain(playerGuid);
                playerGrain.Create(this, account, name);
                _players.Add(accountKey, playerGrain);
                account.JoinGame(this, playerGrain);

                Console.WriteLine(" -- {0,-10} -- New player joined {1}.", "Game", _name);
                return(Task.FromResult(playerGrain));
            }
            else
            {
                Console.WriteLine(" -- {0,-10} -- Cannot join a started game.", "Game");
                return(Task.FromResult <IPlayerGrain>(null));
            }
        }
Example #2
0
        public async Task <ActionResult> Join(Guid id)
        {
            var guid   = GetGuid();
            var player = PlayerGrainFactory.GetGrain(guid);
            var state  = await player.JoinGame(id);

            return(RedirectToAction("Index", id));
        }
Example #3
0
        public async Task <ActionResult> Join(Guid id)
        {
            var guid   = GetGuid();
            var player = PlayerGrainFactory.GetGrain(guid);
            var state  = await player.JoinGame(id);

            return(Json(new { GameState = state }, JsonRequestBehavior.AllowGet));
        }
Example #4
0
        public async Task <ActionResult> CreateGame()
        {
            var guid       = GetGuid();
            var player     = PlayerGrainFactory.GetGrain(guid);
            var gameIdTask = await player.CreateGame();

            return(Json(new { GameId = gameIdTask }, JsonRequestBehavior.AllowGet));
        }
Example #5
0
        public async Task <ActionResult> SetUser(string id)
        {
            var guid   = GetGuid();
            var player = PlayerGrainFactory.GetGrain(guid);
            await player.SetUsername(id);

            return(Json(new { }));
        }
Example #6
0
        public async Task <ActionResult> Index()
        {
            var guid          = GetGuid();
            var player        = PlayerGrainFactory.GetGrain(guid);
            var gamesTask     = player.GetGameSummaries();
            var availableTask = player.GetAvailableGames();
            await Task.WhenAll(gamesTask, availableTask);

            return(Json(new object[] { gamesTask.Result, availableTask.Result }, JsonRequestBehavior.AllowGet));
        }
Example #7
0
        /// <summary>
        /// Presense grain calls this method to update the game with its latest status
        /// </summary>
        public async Task UpdateGameStatus(GameStatus status)
        {
            this.status = status;

            // Check for new players that joined since last update
            foreach (Guid player in status.Players)
            {
                if (!players.Contains(player))
                {
                    try
                    {
                        // Here we call player grains serially, which is less efficient than a fan-out but simpler to express.
                        await PlayerGrainFactory.GetGrain(player).JoinGame(this);

                        players.Add(player);
                    }
                    catch (Exception)
                    {
                        // Ignore exceptions while telling player grains to join the game.
                        // Since we didn't add the player to the list, this will be tried again with next update.
                    }
                }
            }

            // Check for players that left the game since last update
            List <Task> promises = new List <Task>();

            foreach (Guid player in players)
            {
                if (!status.Players.Contains(player))
                {
                    try
                    {
                        // Here we do a fan-out with multiple calls going out in parallel. We join the promisses later.
                        // More code to write but we get lower latency when calling multiple player grains.
                        promises.Add(PlayerGrainFactory.GetGrain(player).LeaveGame(this));
                        players.Remove(player);
                    }
                    catch (Exception)
                    {
                        // Ignore exceptions while telling player grains to leave the game.
                        // Since we didn't remove the player from the list, this will be tried again with next update.
                    }
                }
            }

            // Joining promises
            await Task.WhenAll(promises);

            // Notify subsribers about the latest game score
            subscribers.Notify((s) => s.UpdateGameScore(status.Score));

            return;
        }
        async Task IPlayerRegistrationGrain.Register(IPlayerObserver playerObserver)
        {
            var playerId = this.GetPrimaryKey();

            // first have someone else to wait for future notifications from the GameServerGrain
            IPlayerGrain playerInGame = PlayerGrainFactory.GetGrain(playerId);

            // Forward subscription to the corresponding PlayerInGameGrain and trigger lobby service.
            var playerInfo = await playerInGame.Subscribe(playerObserver);

            // *then* ask to start a GameServerGrain via lobby
            await _lobby.RegisterPlayer(playerInGame, playerInfo);
        }
Example #9
0
        /// <summary>
        /// Simulates a companion application that connects to the game that a particular player is currently part of
        /// and subscribes to receive live notifications about its progress.
        /// </summary>
        static void Main(string[] args)
        {
            try
            {
                GrainClient.Initialize();

                // Hardcoded player ID
                Guid         playerId = new Guid("{2349992C-860A-4EDA-9590-000000000006}");
                IPlayerGrain player   = PlayerGrainFactory.GetGrain(playerId);
                IGameGrain   game     = null;

                while (game == null)
                {
                    Console.WriteLine("Getting current game for player {0}...", playerId);

                    try
                    {
                        game = player.GetCurrentGame().Result;
                        if (game == null) // Wait until the player joins a game
                        {
                            game = null;
                            Thread.Sleep(5000);
                        }
                    }
                    catch (Exception exc)
                    {
                        Console.WriteLine("Exception: ", exc.GetBaseException());
                    }
                }

                Console.WriteLine("Subscribing to updates for game {0}...", game.GetPrimaryKey());

                // Subscribe for updates
                var watcher = new GameObserver();
                game.SubscribeForGameUpdates(GameObserverFactory.CreateObjectReference(watcher).Result).Wait();

                // Block main thread so that the process doesn't exit. Updates arrive on thread pool threads.
                Console.WriteLine("Subscribed successfully. Press <Enter> to stop.");
                Console.ReadLine();
            }
            catch (Exception exc)
            {
                Console.WriteLine("Unexpected Error: {0}", exc.GetBaseException());
            }
        }
Example #10
0
        public async Task <GameSummary> GetSummary(Guid player)
        {
            var promises = new List <Task <string> >();

            foreach (var p in this.ListOfPlayers.Where(p => p != player))
            {
                promises.Add(PlayerGrainFactory.GetGrain(p).GetUsername());
            }
            await Task.WhenAll(promises);

            return(new GameSummary
            {
                NumMoves = this.ListOfMoves.Count,
                State = this.GameState,
                YourMove = this.GameState == GameState.InPlay && player == this.ListOfPlayers[this.indexNextPlayerToMove],
                NumPlayers = this.ListOfPlayers.Count,
                GameId = this.GetPrimaryKey(),
                Usernames = promises.Select(x => x.Result).ToArray(),
                Name = this.name,
                GameStarter = this.ListOfPlayers.FirstOrDefault() == player
            });
        }
Example #11
0
        // make a move during the game
        public async Task <GameState> MakeMove(GameMove move)
        {
            // check if its a legal move to make
            if (this.GameState != GameState.InPlay)
            {
                throw new ApplicationException("This game is not in play");
            }

            if (ListOfPlayers.IndexOf(move.PlayerId) < 0)
            {
                throw new ArgumentException("No such playerid for this game", "move");
            }
            if (move.PlayerId != ListOfPlayers[indexNextPlayerToMove])
            {
                throw new ArgumentException("The wrong player tried to make a move", "move");
            }

            if (move.X < 0 || move.X > 2 || move.Y < 0 || move.Y > 2)
            {
                throw new ArgumentException("Bad co-ordinates for a move", "move");
            }
            if (theBoard[move.X, move.Y] != -1)
            {
                throw new ArgumentException("That square is not empty", "move");
            }

            // record move
            this.ListOfMoves.Add(move);
            this.theBoard[move.X, move.Y] = indexNextPlayerToMove;

            // check for a winning move
            var win = false;

            if (!win)
            {
                for (int i = 0; i < 3 && !win; i++)
                {
                    win = isWinningLine(theBoard[i, 0], theBoard[i, 1], theBoard[i, 2]);
                }
            }
            if (!win)
            {
                for (int i = 0; i < 3 && !win; i++)
                {
                    win = isWinningLine(theBoard[0, i], theBoard[1, i], theBoard[2, i]);
                }
            }
            if (!win)
            {
                win = isWinningLine(theBoard[0, 0], theBoard[1, 1], theBoard[2, 2]);
            }
            if (!win)
            {
                win = isWinningLine(theBoard[0, 2], theBoard[1, 1], theBoard[2, 0]);
            }

            // check for draw

            var draw = false;

            if (this.ListOfMoves.Count() == 9)
            {
                draw = true;  // we could try to look for stalemate earlier, if we wanted
            }
            // handle end of game
            if (win || draw)
            {
                // game over
                this.GameState = GameState.Finished;
                if (win)
                {
                    WinnerId = ListOfPlayers[indexNextPlayerToMove];
                    LoserId  = ListOfPlayers[(indexNextPlayerToMove + 1) % 2];
                }

                // collect tasks up, so we await both notifications at the same time
                var promises = new List <Task>();
                // inform this player of outcome
                var playerGrain = PlayerGrainFactory.GetGrain(ListOfPlayers[indexNextPlayerToMove]);
                promises.Add(playerGrain.LeaveGame(this.GetPrimaryKey(), win ? GameOutcome.Win : GameOutcome.Draw));

                // inform other player of outcome
                playerGrain = PlayerGrainFactory.GetGrain(ListOfPlayers[(indexNextPlayerToMove + 1) % 2]);
                promises.Add(playerGrain.LeaveGame(this.GetPrimaryKey(), win ? GameOutcome.Lose : GameOutcome.Draw));
                await Task.WhenAll(promises);

                return(this.GameState);
            }

            // if game hasnt ended, prepare for next players move
            indexNextPlayerToMove = (indexNextPlayerToMove + 1) % 2;
            return(this.GameState);
        }