-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from afuersch/playerlist
Close #1 List of players. May not be the best solution, but this works for now.
- Loading branch information
Showing
8 changed files
with
309 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
using System.Linq; | ||
using Microsoft.AspNet.Mvc; | ||
using Wuzlstats.Models; | ||
using Wuzlstats.ViewModels.Players; | ||
using System; | ||
using System.Threading.Tasks; | ||
using Wuzlstats.Services; | ||
|
||
namespace Wuzlstats.Controllers | ||
{ | ||
public class PlayersController : Controller | ||
{ | ||
private readonly Db _db; | ||
private readonly AppSettings _settings; | ||
private readonly PlayersService _statisticsService; | ||
|
||
public PlayersController(Db db, AppSettings settings) | ||
{ | ||
_settings = settings; | ||
_db = db; | ||
_statisticsService = new PlayersService(_db); | ||
} | ||
|
||
[Route("~/League/{league}/Players")] | ||
public async Task<IActionResult> Index(string league, string sort, bool recent) | ||
{ | ||
var leagueEntity = _db.Leagues.FirstOrDefault(x => x.Name.ToLower() == league.ToLower()); | ||
if (leagueEntity == null) | ||
{ | ||
return RedirectToAction("Index", "Leagues"); | ||
} | ||
ViewBag.CurrentLeague = leagueEntity.Name; | ||
var players = await _statisticsService.FindPlayersOfLeague(leagueEntity.Id, recent ?_settings.DaysForStatistics : default(int?)); | ||
|
||
switch (sort) | ||
{ | ||
case "best": | ||
players = players.OrderByDescending(x => x.Rank); | ||
break; | ||
case "worst": | ||
players = players.OrderBy(x => x.Rank); | ||
break; | ||
case "activity": | ||
players = players.OrderByDescending(x => x.Wins + x.Losses); | ||
break; | ||
default: | ||
break; | ||
} | ||
|
||
return View(new IndexViewModel | ||
{ | ||
ActiveFilter = sort, | ||
Recent = recent, | ||
Players = players.Select(player => new PlayerViewModel | ||
{ | ||
PlayerId = player.Id, | ||
Name = player.Name, | ||
Image = player.Image == null || player.Image.Length <= 0 ? EmptyAvatar.Base64 : Convert.ToBase64String(player.Image), | ||
Wins = player.Wins, | ||
Losses = player.Losses, | ||
SingleGames = player.SingleGames, | ||
TeamGames = player.TeamGames, | ||
LastGamePlayedOn = player.LatestGame | ||
}) | ||
}); | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
using Microsoft.Data.Entity; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Wuzlstats.Models; | ||
|
||
namespace Wuzlstats.Services | ||
{ | ||
public class PlayersService | ||
{ | ||
private readonly Db _db; | ||
|
||
public PlayersService(Db db) | ||
{ | ||
_db = db; | ||
} | ||
|
||
public async Task<IEnumerable<PlayerDto>> FindPlayersOfLeague(int leagueId, int? daysForStatistics) | ||
{ | ||
var gamesQuery = _db.Games.AsNoTracking().Where(x => x.LeagueId == leagueId); | ||
if (daysForStatistics.HasValue) | ||
{ | ||
var date = DateTime.UtcNow.Date.AddDays(-daysForStatistics.Value); | ||
gamesQuery = gamesQuery.Where(x => x.Date >= date); | ||
} | ||
|
||
// EF7 beta4 does not support navigation properties in queries yet | ||
// this complicates the code a lot, because we need joins :( | ||
|
||
var players = new List<PlayerDto>(); | ||
|
||
foreach (var game in await gamesQuery.ToListAsync()) | ||
{ | ||
var positions = await (from position in _db.PlayerPositions.AsNoTracking() | ||
join player in _db.Players.AsNoTracking() on position.PlayerId equals player.Id | ||
where position.GameId == game.Id | ||
select new | ||
{ | ||
position.Position, | ||
Player = player | ||
}).ToListAsync(); | ||
// player stats | ||
foreach (var position in positions) | ||
{ | ||
var player = players.FirstOrDefault(x => x.Equals(position.Player)); | ||
if (player == null) | ||
{ | ||
player = PlayerDto.Create(position.Player); | ||
players.Add(player); | ||
} | ||
// calculate count of single or team games | ||
if (position.Position == PlayerPositionTypes.Blue || position.Position == PlayerPositionTypes.Red) | ||
{ | ||
player.SingleGames++; | ||
} | ||
else | ||
{ | ||
player.TeamGames++; | ||
} | ||
|
||
// don't count ties | ||
if (game.BlueWins && (position.Position == PlayerPositionTypes.Blue || position.Position == PlayerPositionTypes.BlueDefense || position.Position == PlayerPositionTypes.BlueOffense)) | ||
{ | ||
player.Wins++; | ||
} | ||
else if (game.RedWins && (position.Position == PlayerPositionTypes.Red || position.Position == PlayerPositionTypes.RedDefense || position.Position == PlayerPositionTypes.RedOffense)) | ||
{ | ||
player.Wins++; | ||
} | ||
else if (game.RedWins && | ||
(position.Position == PlayerPositionTypes.Blue || position.Position == PlayerPositionTypes.BlueDefense || position.Position == PlayerPositionTypes.BlueOffense)) | ||
{ | ||
player.Losses++; | ||
} | ||
else if (game.BlueWins && | ||
(position.Position == PlayerPositionTypes.Red || position.Position == PlayerPositionTypes.RedDefense || position.Position == PlayerPositionTypes.RedOffense)) | ||
{ | ||
player.Losses++; | ||
} | ||
if (game.Date > player.LatestGame) | ||
{ | ||
player.LatestGame = game.Date; | ||
} | ||
} | ||
} | ||
return players.OrderByDescending(x => x.LatestGame); | ||
} | ||
} | ||
|
||
public class PlayerDto | ||
{ | ||
public int Id { get; set; } | ||
public string Name { get; set; } | ||
public byte[] Image { get; set; } | ||
public int Wins { get; set; } | ||
public int Losses { get; set; } | ||
public int SingleGames { get; set; } | ||
public int TeamGames { get; set; } | ||
public DateTime LatestGame { get; set; } | ||
|
||
public double Rank => Losses == 0 ? Wins : (Wins == 0 ? 0.1d / Losses : (double)Wins / Losses); | ||
|
||
public bool Equals(Player p) | ||
{ | ||
return Id == p.Id; | ||
} | ||
|
||
public static PlayerDto Create(Player p) | ||
{ | ||
return new PlayerDto | ||
{ | ||
Id = p.Id, | ||
Name = p.Name, | ||
Image = p.Image | ||
}; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace Wuzlstats.ViewModels.Players | ||
{ | ||
public class IndexViewModel | ||
{ | ||
public string ActiveFilter { get; set; } | ||
public bool Recent { get; set; } | ||
public IEnumerable<PlayerViewModel> Players { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using System; | ||
|
||
namespace Wuzlstats.ViewModels.Players | ||
{ | ||
public class PlayerViewModel | ||
{ | ||
public int PlayerId { get; set; } | ||
public string Name { get; set; } | ||
public string Image { get; set; } | ||
public int Wins { get; set; } | ||
public int Losses { get; set; } | ||
public DateTime LastGamePlayedOn { get; set; } | ||
public int SingleGames { get; set; } | ||
public int TeamGames { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
@model Wuzlstats.ViewModels.Players.IndexViewModel | ||
|
||
<p class="help-block">These are all the players. Ever.<br />No one will be forgotten. Shame and fame will last till the very end of days, or at least until a database crash with no backups.</p> | ||
|
||
<ul class="list-unstyled list-inline filter"> | ||
<li class="@(string.IsNullOrEmpty(Model.ActiveFilter) ? "active" : "")"><a href="@Url.Action("Index", "Players", new { recent = Model.Recent })">Last played</a></li> | ||
<li class="@(Model.ActiveFilter == "best" ? "active" : "")"><a href="@Url.Action("Index", "Players", new { sort = "best", recent = Model.Recent })">Best</a></li> | ||
<li class="@(Model.ActiveFilter == "worst" ? "active" : "")"><a href="@Url.Action("Index", "Players", new { sort = "worst", recent = Model.Recent })">Worst</a></li> | ||
<li class="@(Model.ActiveFilter == "activity" ? "active" : "")"><a href="@Url.Action("Index", "Players", new { sort = "activity", recent = Model.Recent })">Most active</a></li> | ||
</ul> | ||
|
||
<table class="table table-striped ranking players"> | ||
<thead> | ||
<tr> | ||
<th></th> | ||
<th>Player</th> | ||
<th>Score</th> | ||
<th>Last game</th> | ||
<th># 1 vs. 1</th> | ||
<th># 2 vs. 2</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
@{var rank = 1; } | ||
@foreach (var player in Model.Players) | ||
{ | ||
<tr> | ||
<td> | ||
@(rank++) | ||
</td> | ||
<td> | ||
<a href="@Url.Action("Index", "Player", new { id = player.PlayerId })"> | ||
<img src="data:image/png;base64,@player.Image" alt="@player.Name" class="ranking-image" /> | ||
</a> | ||
<div class="player-name">@player.Name</div> | ||
</td> | ||
<td> | ||
<div class="player-score"> | ||
<span class="ranking-wins">@player.Wins<span class="glyphicon glyphicon-thumbs-up"></span></span> | ||
<span class="ranking-losses">@player.Losses<span class="glyphicon glyphicon-thumbs-down"></span></span> | ||
</div> | ||
</td> | ||
<td> | ||
@player.LastGamePlayedOn.ToShortDateString() | ||
</td> | ||
<td> | ||
@player.SingleGames | ||
</td> | ||
<td> | ||
@player.TeamGames | ||
</td> | ||
</tr> | ||
} | ||
</tbody> | ||
</table> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters