Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/snowse/mars_rover
Browse files Browse the repository at this point in the history
  • Loading branch information
snow-jallen committed Feb 28, 2023
2 parents 9d88585 + 6b9335d commit 6c84cd5
Show file tree
Hide file tree
Showing 22 changed files with 456 additions and 147 deletions.
File renamed without changes.
2 changes: 1 addition & 1 deletion .github/workflows/deploy-main-branch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:

- name: Run Tests
working-directory: src
run: dotnet test
run: dotnet test MarsRover.sln

- name: dotnet publish
working-directory: src/Mars.Web
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:

- name: Run Tests
working-directory: src
run: dotnet test
run: dotnet test MarsRover.sln

- name: dotnet publish
working-directory: src/Mars.Web
Expand Down
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

# 2023 Snow College Coding Competition: Mars Rover

Object: Get your rover to the destination before everyone else!
> **Next competition date:** Friday, March 31st 2023 @ 4PM
> **Final competition date:** Friday, April 21st 2023 @ 4PM
> Location: [Snow College Science Building, Room GRSC 124](https://goo.gl/maps/zKw4X9gioeNCKutZ9)
***Object: Get your rover to the destination(s) before everyone else!***

## Summary of Game Mechanics

Expand All @@ -26,6 +30,21 @@ Object: Get your rover to the destination before everyone else!
- Winners are determined by the amount of time elapsed from when the game state becomes 'Playing' to when your rover makes it to the target.
- Tip: Make sure you use the high-resolution information you get back from Perseverance and Ingenuity about their surrounding cells to help improve your planning of how you will get to the target.

## Proposed Changes for the March 2022 Competition

- Change spawning locations
- circle spawn (equidistant from target)
- fair spawn (possibly different distances but equal best-path to target)
- weighted spawn
- Edge wrapping
- Unpassable barriers / cliffs (require pathfinding)
- Weather/storms changes difficulty values (so your previous map becomes invalidated, requiring constant scanning and re-evaluation)
- closing ring, as time passes boot players outside of a certain radius
- ***Multiple waypoints***
- ***Unbounded battery (you can charge beyond your initial battery level)***
- ***Change scoring: most efficient wins (battery used / time taken), within 60 seconds of first to target***
- ***Return battery level on join***

## API Documentation

There is an [API Playground](https://snow-rover.azurewebsites.net/swagger/index.html) where you can see exactly what endpoints exist on the server, what arguments need to be passed in, and what type of data you get back. Feel free to use that to help you get familiar with how to interact with the server. While you *can* play the game using nothing more than the API Playground, or a commandline with `curl` in bash or `Invoke-RestMethod` in PowerShell (or even from a few different browser tabs), you will have the best success by writing a program to automate your server interactions.
Expand Down
12 changes: 12 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: "3.0"
services:
seq:
image: datalust/seq:latest
ports:
- "5341:5341"
- "80:80"
- "45341:45341"
volumes:
- /datadrive:/data
environment:
- ACCEPT_EULA=Y
25 changes: 25 additions & 0 deletions src/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
124 changes: 67 additions & 57 deletions src/Mars.MissionControl/Game.cs
Original file line number Diff line number Diff line change
@@ -1,41 +1,46 @@
using System.Collections.ObjectModel;
using Microsoft.Extensions.Logging;
using System.Collections.ObjectModel;

namespace Mars.MissionControl;
public class Game : IDisposable
{
public Game(GameStartOptions startOptions)
{
GameState = GameState.Joining;
Board = new Board(startOptions.Map);
Map = startOptions.Map;
TargetLocation = new Location(Map.Width / 2, Map.Height / 2);
PerseveranceVisibilityRadius = startOptions.PerseveranceVisibilityRadius;
IngenuityVisibilityRadius = startOptions.IngenuityVisibilityRadius;
StartingBatteryLevel = startOptions.StartingBatteryLevel;
IngenuityStartingBatteryLevel = Board.Width * 2 + Board.Height * 2;
}
public Game(GameStartOptions startOptions, ILogger<Game> logger)
{
GameState = GameState.Joining;
Board = new Board(startOptions.Map);
Map = startOptions.Map;
TargetLocation = new Location(Map.Width / 2, Map.Height / 2);
PerseveranceVisibilityRadius = startOptions.PerseveranceVisibilityRadius;
IngenuityVisibilityRadius = startOptions.IngenuityVisibilityRadius;
StartingBatteryLevel = startOptions.StartingBatteryLevel;
IngenuityStartingBatteryLevel = Board.Width * 2 + Board.Height * 2;
this.logger= logger;
}

public int MapNumber => Board.MapNumber;

public Location TargetLocation { get; private set; }
public int PerseveranceVisibilityRadius { get; }
public int IngenuityVisibilityRadius { get; }
public int StartingBatteryLevel { get; }
public int IngenuityStartingBatteryLevel { get; }
public Map Map { get; private set; }
private ConcurrentDictionary<PlayerToken, Player> players = new();
private ConcurrentDictionary<string, PlayerToken> playerTokenCache = new();
public bool TryTranslateToken(string tokenString, out PlayerToken? token) => playerTokenCache.TryGetValue(tokenString, out token);
private static Orientation getRandomOrientation() => (Orientation)Random.Shared.Next(0, 4);
public GamePlayOptions? GamePlayOptions { get; private set; }
public GameState GameState { get; set; }
public Board Board { get; private set; }
private Timer? rechargeTimer;
public DateTime GameStartedOn { get; private set; }
public ReadOnlyCollection<Player> Players =>
new ReadOnlyCollection<Player>(players.Values.ToList());
private ConcurrentQueue<Player> winners = new();
public IEnumerable<Player> Winners => winners.ToArray();
public int MapNumber => Board.MapNumber;

public Location TargetLocation { get; private set; }
public int PerseveranceVisibilityRadius { get; }
public int IngenuityVisibilityRadius { get; }
public int StartingBatteryLevel { get; }
public int IngenuityStartingBatteryLevel { get; }

private readonly ILogger<Game> logger;

public Map Map { get; private set; }
private ConcurrentDictionary<PlayerToken, Player> players = new();
private ConcurrentDictionary<string, PlayerToken> playerTokenCache = new();
public bool TryTranslateToken(string tokenString, out PlayerToken? token) => playerTokenCache.TryGetValue(tokenString, out token);
private static Orientation getRandomOrientation() => (Orientation)Random.Shared.Next(0, 4);
public GamePlayOptions? GamePlayOptions { get; private set; }
public GameState GameState { get; set; }
public Board Board { get; private set; }
private Timer? rechargeTimer;
public DateTime GameStartedOn { get; private set; }
public ReadOnlyCollection<Player> Players =>
new ReadOnlyCollection<Player>(players.Values.ToList());
private ConcurrentQueue<Player> winners = new();
public IEnumerable<Player> Winners => winners.ToArray();

#region State Changed
public event EventHandler? GameStateChanged;
Expand All @@ -58,21 +63,23 @@ public JoinResult Join(string playerName)
throw new InvalidGameStateException();
}

var player = new Player(playerName);
var startingLocation = Board.PlaceNewPlayer(player);
player = player with
{
BatteryLevel = StartingBatteryLevel,
PerseveranceLocation = startingLocation,
IngenuityLocation = startingLocation,
IngenuityBatteryLevel = StartingBatteryLevel,
Orientation = getRandomOrientation()
};
if (!players.TryAdd(player.Token, player) ||
!playerTokenCache.TryAdd(player.Token.Value, player.Token))
{
throw new Exception("Unable to add new player...that token already exists?!");
}
var player = new Player(playerName);
var startingLocation = Board.PlaceNewPlayer(player);
logger.LogInformation("New player came into existance and started at location ({x}, {y}) ", startingLocation.X, startingLocation.Y);
player = player with
{
BatteryLevel = StartingBatteryLevel,
PerseveranceLocation = startingLocation,
IngenuityLocation = startingLocation,
IngenuityBatteryLevel = StartingBatteryLevel,
Orientation = getRandomOrientation()
};
if (!players.TryAdd(player.Token, player) ||
!playerTokenCache.TryAdd(player.Token.Value, player.Token))
{
logger.LogError($"Player {player.Token.Value} couldn't be added");
throw new Exception("Unable to add new player...that token already exists?!");
}

raiseStateChange();

Expand Down Expand Up @@ -171,7 +178,8 @@ public IngenuityMoveResult MoveIngenuity(PlayerToken token, Location destination
message = GameMessages.IngenuityMoveOK;
}

raiseStateChange();
raiseStateChange();
logger.LogInformation("player: {name} moved helicopter correctly and moved to location: {loc}", player.Name, player.IngenuityLocation);

return new IngenuityMoveResult(
player.IngenuityLocation,
Expand Down Expand Up @@ -254,15 +262,17 @@ public MoveResult MovePerseverance(PlayerToken token, Direction direction, int u
return MovePerseverance(token, direction, updatePlayerTryAgainCount + 1);
}

if (player.PerseveranceLocation == TargetLocation)//you win!
{
players.Remove(player.Token, out _);
player = player with { WinningTime = DateTime.Now - GameStartedOn };
winners.Enqueue(player);
message = GameMessages.YouMadeItToTheTarget;
}
if (player.PerseveranceLocation == TargetLocation)//you win!
{
logger.LogInformation("Player {0} has won!", player.Name);
players.Remove(player.Token, out _);
player = player with { WinningTime = DateTime.Now - GameStartedOn };
winners.Enqueue(player);
message = GameMessages.YouMadeItToTheTarget;
}

raiseStateChange();
raiseStateChange();
logger.LogInformation("player: {0} moved rover correctly", player.Name);

return new MoveResult(
player.PerseveranceLocation,
Expand Down
12 changes: 10 additions & 2 deletions src/Mars.MissionControl/Helpers.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
namespace Mars.MissionControl;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System.Runtime.CompilerServices;

namespace Mars.MissionControl;

public static class Helpers
{
private static ILogger<Game> logger = NullLoggerFactory.Instance.CreateLogger<Game>();

public static Map CreateMap(int height, int width)
{

var cells = new List<Cell>();
for (int x = 0; x < width; x++)
{
Expand All @@ -30,11 +37,12 @@ public static Game CreateGame(int height, int width)

public static Game CreateGame(Map map)
{

var startOptions = new GameStartOptions
{
Map = map
};
var game = new Game(startOptions);
var game = new Game(startOptions, logger);
return game;
}

Expand Down
4 changes: 4 additions & 0 deletions src/Mars.MissionControl/Mars.MissionControl.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion src/Mars.Web.Tests/JoinGameTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public async Task CannotMoveWithGameInJoiningState()
var joinResponse = await client.GetFromJsonAsync<JoinResponse>($"/game/join?gameId={gameId}&name=p1");
var moveResponse = await client.GetAsync($"/game/moveperseverance?token={joinResponse.Token}&move=Forward");
var content = await moveResponse.Content.ReadAsStringAsync();
content.Should().Contain("invalid game state");
content.Should().Contain("Game not in Playing state");
}

}
Loading

0 comments on commit 6c84cd5

Please sign in to comment.