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

Dev/kennyy/prequisite editing #93

Merged
merged 4 commits into from
Oct 25, 2018
Merged
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
12 changes: 11 additions & 1 deletion Data/DataModel/Prerequisites.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,20 @@ public class Prerequisites
public int ID { get; set; }

/// <summary>
/// The puzzle that depends on others.
/// The puzzle ID that depends on others to be solved before it will be unlocked.
/// </summary>
public int PuzzleID { get; set; }

/// <summary>
/// The puzzle that depends on others to be solved before it will be unlocked.
/// </summary>
public virtual Puzzle Puzzle { get; set; }

/// <summary>
/// A potential prerequisite ID of the puzzle named in Puzzle, which may need to be solved before Puzzle will be unlocked.
/// </summary>
tabascq marked this conversation as resolved.
Show resolved Hide resolved
public int PrerequisiteID { get; set; }

/// <summary>
/// A potential prerequisite of the puzzle named in Puzzle, which may need to be solved before Puzzle will be unlocked.
/// </summary>
Expand Down
32 changes: 0 additions & 32 deletions Data/DataModel/PuzzleStatePerTeam.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,38 +13,6 @@ public class PuzzleStatePerTeam
public int TeamID { get; set; }
public virtual Team Team { get; set; }

/// <summary>
/// Whether or not the puzzle has been unlocked
/// </summary>
[NotMapped]
public bool IsUnlocked
tabascq marked this conversation as resolved.
Show resolved Hide resolved
{
get { return UnlockedTime != null; }
set
{
if (IsUnlocked != value)
{
UnlockedTime = value ? (DateTime?)DateTime.UtcNow : null;
}
}
}

/// <summary>
/// Whether or not the puzzle has been solved
/// </summary>
[NotMapped]
public bool IsSolved
{
get { return SolvedTime != null; }
set
{
if (IsSolved != value)
{
SolvedTime = value ? (DateTime?)DateTime.UtcNow : null;
}
}
}

/// <summary>
/// Whether or not the puzzle has been unlocked by this team, and if so when
/// </summary>
Expand Down
32 changes: 9 additions & 23 deletions ServerCore/ModelBases/PuzzleStatePerTeamPageModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public abstract class PuzzleStatePerTeamPageModel : EventSpecificPageModel

public PuzzleStatePerTeamPageModel(PuzzleServerContext context)
{
this.Context = context;
Context = context;
}

public IList<PuzzleStatePerTeam> PuzzleStatePerTeam { get; set; }
Expand All @@ -24,10 +24,10 @@ public PuzzleStatePerTeamPageModel(PuzzleServerContext context)

public async Task InitializeModelAsync(Puzzle puzzle, Team team, SortOrder? sort)
{
IQueryable<PuzzleStatePerTeam> statesQ = PuzzleStateHelper.GetFullReadOnlyQuery(this.Context, this.Event, puzzle, team);
this.Sort = sort;
IQueryable<PuzzleStatePerTeam> statesQ = PuzzleStateHelper.GetFullReadOnlyQuery(Context, Event, puzzle, team);
Sort = sort;

switch(sort ?? this.DefaultSort)
switch(sort ?? DefaultSort)
{
case SortOrder.PuzzleAscending:
statesQ = statesQ.OrderBy(state => state.Puzzle.Name);
Expand Down Expand Up @@ -64,7 +64,7 @@ public async Task InitializeModelAsync(Puzzle puzzle, Team team, SortOrder? sort
{
SortOrder result = ascendingSort;

if (result == (this.Sort ?? DefaultSort))
if (result == (Sort ?? DefaultSort))
{
result = descendingSort;
}
Expand All @@ -77,28 +77,14 @@ public async Task InitializeModelAsync(Puzzle puzzle, Team team, SortOrder? sort
return result;
}

public async Task SetUnlockStateAsync(Puzzle puzzle, Team team, bool value)
public Task SetUnlockStateAsync(Puzzle puzzle, Team team, bool value)
{
var statesQ = await PuzzleStateHelper.GetFullReadWriteQueryAsync(this.Context, this.Event, puzzle, team);
var states = await statesQ.ToListAsync();

for (int i = 0; i < states.Count; i++)
{
states[i].IsUnlocked = value;
}
await Context.SaveChangesAsync();
return PuzzleStateHelper.SetUnlockStateAsync(Context, Event, puzzle, team, value ? (DateTime?)DateTime.UtcNow : null);
}

public async Task SetSolveStateAsync(Puzzle puzzle, Team team, bool value)
public Task SetSolveStateAsync(Puzzle puzzle, Team team, bool value)
{
var statesQ = await PuzzleStateHelper.GetFullReadWriteQueryAsync(this.Context, this.Event, puzzle, team);
var states = await statesQ.ToListAsync();

for (int i = 0; i < states.Count; i++)
{
states[i].IsSolved = value;
}
await Context.SaveChangesAsync();
return PuzzleStateHelper.SetSolveStateAsync(Context, Event, puzzle, team, value ? (DateTime?)DateTime.UtcNow : null);
}

public enum SortOrder
Expand Down
74 changes: 43 additions & 31 deletions ServerCore/Pages/Events/Map.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,20 @@ public async Task OnGetAsync()
{
// get the puzzles and teams
// TODO: Filter puzzles if an author; no need to filter teams. Revisit when authors exist.
var puzzles = await _context.Puzzles.Where(p => p.Event == this.Event).Select(p => new PuzzleStats() { Puzzle = p }).ToListAsync();
var teams = await _context.Teams.Where(t => t.Event == this.Event).Select(t => new TeamStats() { Team = t }).ToListAsync();
List<PuzzleStats> puzzles = await _context.Puzzles.Where(p => p.Event == Event).Select(p => new PuzzleStats() { Puzzle = p }).ToListAsync();
List<TeamStats> teams = await _context.Teams.Where(t => t.Event == Event).Select(t => new TeamStats() { Team = t }).ToListAsync();

// build an ID-based lookup for puzzles and teams
var puzzleLookup = new Dictionary<int, PuzzleStats>();
Dictionary<int, PuzzleStats> puzzleLookup = new Dictionary<int, PuzzleStats>();
puzzles.ForEach(p => puzzleLookup[p.Puzzle.ID] = p);

var teamLookup = new Dictionary<int, TeamStats>();
Dictionary<int, TeamStats> teamLookup = new Dictionary<int, TeamStats>();
teams.ForEach(t => teamLookup[t.Team.ID] = t);

// tabulate solve counts and team scores
var states = await PuzzleStateHelper.GetSparseQuery(_context, this.Event, null, null).ToListAsync();
var stateList = new List<StateStats>(states.Count);
foreach (var state in states)
List<PuzzleStatePerTeam> states = await PuzzleStateHelper.GetSparseQuery(_context, Event, null, null).ToListAsync();
List<StateStats> stateList = new List<StateStats>(states.Count);
foreach (PuzzleStatePerTeam state in states)
{
// TODO: Is it more performant to prefilter the states if an author, or is this sufficient?
if (!puzzleLookup.TryGetValue(state.PuzzleID, out PuzzleStats puzzle) || !teamLookup.TryGetValue(state.TeamID, out TeamStats team))
Expand All @@ -50,7 +50,7 @@ public async Task OnGetAsync()

stateList.Add(new StateStats() { Puzzle = puzzle, Team = team, UnlockedTime = state.UnlockedTime, SolvedTime = state.SolvedTime });

if (state.IsSolved)
if (state.SolvedTime != null)
{
puzzle.SolveCount++;
team.SolveCount++;
Expand Down Expand Up @@ -86,53 +86,65 @@ public async Task OnGetAsync()
var stateMap = new StateStats[puzzles.Count, teams.Count];
stateList.ForEach(state => stateMap[state.Puzzle.SortOrder, state.Team.SortOrder] = state);

this.Puzzles = puzzles;
this.Teams = teams;
this.StateMap = stateMap;
Puzzles = puzzles;
Teams = teams;
StateMap = stateMap;
}

public class PuzzleStats
{
public Puzzle Puzzle;
public int SolveCount;
public int SortOrder;
public Puzzle Puzzle { get; set; }
public int SolveCount { get; set; }
public int SortOrder { get; set; }
}

public class TeamStats
{
public Team Team;
public int SolveCount;
public int Score;
public int SortOrder;
public int? Rank;
public DateTime FinalMetaSolveTime = DateTime.MaxValue;
public Team Team { get; set; }
public int SolveCount { get; set; }
public int Score { get; set; }
public int SortOrder { get; set; }
public int? Rank { get; set; }
public DateTime FinalMetaSolveTime { get; set; } = DateTime.MaxValue;
}

public class StateStats
{
public static StateStats Default = new StateStats();
public static StateStats Default { get; } = new StateStats();

public PuzzleStats Puzzle;
public TeamStats Team;
public DateTime? UnlockedTime;
public DateTime? SolvedTime;
public PuzzleStats Puzzle { get; set; }
public TeamStats Team { get; set; }
public DateTime? UnlockedTime { get; set; }
public DateTime? SolvedTime { get; set; }

public string DisplayText => this.SolvedTime != null ? "C" : this.UnlockedTime != null ? "U" : "L";
public string DisplayText
{
get
{
return SolvedTime != null ? "C" : UnlockedTime != null ? "U" : "L";
}
}

public int DisplayHue => this.SolvedTime != null ? 120 : this.UnlockedTime != null ? 60 : 0;
public int DisplayHue
{
get
{
return SolvedTime != null ? 120 : UnlockedTime != null ? 60 : 0;
}
}

public int DisplayLightness
{
get
{
if (this.SolvedTime != null)
if (SolvedTime != null)
{
int minutes = (int)((DateTime.UtcNow - this.SolvedTime.Value).TotalMinutes);
int minutes = (int)((DateTime.UtcNow - SolvedTime.Value).TotalMinutes);
return 75 - (Math.Min(minutes, 236) >> 2);
}
else if (this.UnlockedTime != null)
else if (UnlockedTime != null)
{
int minutes = (int)((DateTime.UtcNow - this.UnlockedTime.Value).TotalMinutes);
int minutes = (int)((DateTime.UtcNow - UnlockedTime.Value).TotalMinutes);
return 75 - (Math.Min(minutes, 236) >> 2);
}
else
Expand Down
68 changes: 68 additions & 0 deletions ServerCore/Pages/Puzzles/Edit.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

<h4>Puzzle</h4>
<hr />
<h3>Properties</h3>
<div class="row">
<div class="col-md-4">
<form method="post" enctype="multipart/form-data">
Expand Down Expand Up @@ -76,6 +77,73 @@
<input type="submit" value="Save" class="btn btn-default" />
</div>
</form>
<hr />
<h3>Prerequisites</h3>
<h4>These puzzles help to unlock me:</h4>
<form method="post" enctype="multipart/form-data">
<table>
<thead>
<tr>
<th>Prerequisite</th>
<th>Action</th>
</tr>
</thead>
<tbody>
@foreach (var pre in Model.CurrentPrerequisites)
{
<tr>
<td>
<a asp-page="./Edit" asp-route-id="@(pre.ID)">@(pre.Name)</a>
</td>
<td>
<a asp-page-handler="RemovePrerequisite" asp-route-id="@Model.Puzzle.ID" asp-route-prerequisite="@(pre.ID)">Remove</a>
</td>
</tr>
}
<tr>
<td>
<select class="form-control" asp-for="NewPrerequisiteID" asp-items="@(new SelectList(Model.PotentialPrerequisites, "ID", "Name"))"></select>
</td>
<td>
<input type="submit" value="Add" asp-page-handler="AddPrerequisite" class="btn btn-default" />
</td>
</tr>
</tbody>
</table>
</form>
<br />
<h4>I help to unlock these puzzles:</h4>
<form method="post" enctype="multipart/form-data">
<table>
<thead>
<tr>
<th>Puzzle</th>
<th>Action</th>
</tr>
</thead>
<tbody>
@foreach (var p in Model.CurrentPrerequisitesOf)
{
<tr>
<td>
<a asp-page="./Edit" asp-route-id="@(p.ID)">@(p.Name)</a>
</td>
<td>
<a asp-page-handler="RemovePrerequisiteOf" asp-route-id="@Model.Puzzle.ID" asp-route-prerequisiteOf="@(p.ID)">Remove</a>
</td>
</tr>
}
<tr>
<td>
<select class="form-control" asp-for="NewPrerequisiteOfID" asp-items="@(new SelectList(Model.PotentialPrerequisitesOf, "ID", "Name"))"></select>
</td>
<td>
<input type="submit" value="Add" asp-page-handler="AddPrerequisiteOf" class="btn btn-default" />
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>

Expand Down
Loading