Initial Commit

This commit is contained in:
Alexander Sigler
2022-12-08 15:39:18 -08:00
commit aa90506943
20 changed files with 969 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.4.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Models\" />
<Folder Include="_2021\" />
<Folder Include="_2022\Models\" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,15 @@
using System;
namespace AdventOfCode.Common
{
public class AOCAttribute : Attribute
{
public int Year { get; set; }
public int Day { get; set; }
public AOCAttribute(int year, int day)
{
this.Year = year;
this.Day = day;
}
}
}

View File

@@ -0,0 +1,12 @@
using System;
namespace AOC2021.Helper
{
public static class AOCExtensions
{
public static int ToInt(this string str)
{
return Convert.ToInt32(str);
}
}
}

View File

@@ -0,0 +1,35 @@
using Microsoft.AspNetCore.Mvc.Formatters;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace AOC2021.Helper
{
public class TextPlainInputFormatter : InputFormatter
{
private const string ContentType = "text/plain";
public TextPlainInputFormatter()
{
SupportedMediaTypes.Add(ContentType);
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var request = context.HttpContext.Request;
using (var reader = new StreamReader(request.Body))
{
var content = await reader.ReadToEndAsync();
return await InputFormatterResult.SuccessAsync(content);
}
}
public override bool CanRead(InputFormatterContext context)
{
var contentType = context.HttpContext.Request.ContentType;
return contentType.StartsWith(ContentType);
}
}
}

View File

@@ -0,0 +1,51 @@
using AdventOfCode.Common;
using AdventOfCode.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
namespace AdventOfCode.Controllers
{
[ApiController]
[Route("[controller]")]
public class AdventOfCodeController : ControllerBase
{
private readonly ILogger<AdventOfCodeController> _logger;
public AdventOfCodeController(ILogger<AdventOfCodeController> logger)
{
_logger = logger;
}
[HttpPost]
[Consumes("text/plain")]
public AOCResponse Day(int year, int day, AOCVersion version, [FromBody] string input, bool IgnoreLogMessages = false)
{
AOCRequest request = new AOCRequest() { Input = input, Version = version, IgnoreLogMessages = IgnoreLogMessages };
return GetAOCDay(year, day).ExecuteDay(request);
}
private AOCDay GetAOCDay(int year, int day)
{
AOCDay aocDay = null;
var type = typeof(AOCDay);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p) && !p.IsInterface && !p.IsAbstract);
foreach (var x in types)
{
var aocAttribute = (AOCAttribute) Attribute.GetCustomAttribute(x, typeof(AOCAttribute));
if (aocAttribute != null)
{
if (aocAttribute.Year == year && aocAttribute.Day == day)
{
aocDay = (AOCDay)(IAOCService)Activator.CreateInstance(x);
aocDay.SetLogger(this._logger);
}
}
}
return aocDay;
}
}
}

View File

@@ -0,0 +1,79 @@

using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace AdventOfCode.Models
{
public abstract class AOCDay : IAOCService
{
protected AOCRequest _request;
protected AOCResponse _response;
protected ILogger _logger;
private List<string> _debugMessages;
protected object Answer { set { this._response.Answer = value; } }
public AOCDay()
{
this._response = new AOCResponse()
{
Status = false
};
this._debugMessages = new List<string>();
}
public AOCResponse ExecuteDay(AOCRequest request)
{
_request = request;
var timer = new Stopwatch();
try
{
timer.Start();
switch (request.Version)
{
case AOCVersion.A:
this._response = ExecutePartA();
break;
case AOCVersion.B:
this._response = ExecutePartB();
break;
}
timer.Stop();
this._response.RunTime = timer.ElapsedTicks.ToString();
this._response.Status = true;
}
catch (Exception e)
{
this._response.Answer = e.Message;
this._response.Status = false;
this._response.StackTrace = e.StackTrace;
}
if (!request.IgnoreLogMessages)
this._response.Debug = this._debugMessages;
return this._response;
}
protected abstract AOCResponse ExecutePartA();
protected abstract AOCResponse ExecutePartB();
protected string[] GetSplitInput()
{
return this._request.Input.Trim().Replace("\r", "").Split("\n");
}
protected string[] GetSplitRowInput()
{
return this._request.Input.Trim().Replace("\r", "").Split("\n");
}
public void SetLogger(ILogger logger)
{
this._logger = logger;
}
protected void Log(object message, params object[] args)
{
if (_logger != null && !this._request.IgnoreLogMessages)
_logger.LogInformation(message.ToString(), args);
_debugMessages.Add(string.Format(message.ToString(), args));
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Runtime.Serialization;
namespace AdventOfCode.Models
{
[DataContract]
[Serializable]
public class AOCRequest
{
[DataMember]
public AOCVersion Version { get; set; }
[DataMember]
public string Input { get; set; }
[DataMember]
public bool IgnoreLogMessages { get; set; }
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace AdventOfCode.Models
{
[DataContract]
[Serializable]
public class AOCResponse
{
[DataMember]
public DateTime Date { get { return DateTime.Now; } }
[DataMember]
public object Answer { get; set; }
[DataMember]
public bool Status { get; set; }
[DataMember]
public IEnumerable<string> Debug { get; set; }
[DataMember]
public string StackTrace { get; set; }
private string timeInTicks;
[DataMember]
public string RunTime { get { return FormatRunTime(); } set { timeInTicks = value; } }
public string FormatRunTime()
{
var ts = TimeSpan.FromTicks((long)Convert.ToDouble(timeInTicks));
var microseconds = (ts.Ticks - (ts.Milliseconds * TimeSpan.TicksPerMillisecond)) / (TimeSpan.TicksPerMillisecond / 1000);
return $"Run time is {ts.Minutes}min {ts.Seconds}sec {ts.Milliseconds}ms {microseconds}µs";
}
}
}

View File

@@ -0,0 +1,15 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Runtime.Serialization;
namespace AdventOfCode.Models
{
[JsonConverter(typeof(StringEnumConverter))]
public enum AOCVersion
{
[EnumMember(Value = "A")]
A,
[EnumMember(Value = "B")]
B
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AdventOfCode.Models
{
public interface IAOCService
{
public AOCResponse ExecuteDay(AOCRequest request);
}
}

26
AdventOfCode/Program.cs Normal file
View File

@@ -0,0 +1,26 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AdventOfCode
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}

View File

@@ -0,0 +1,31 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:20379",
"sslPort": 44329
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"AdventOfCode": {
"commandName": "Project",
"dotnetRunMessages": "true",
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

70
AdventOfCode/Startup.cs Normal file
View File

@@ -0,0 +1,70 @@
using AOC2021.Helper;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AdventOfCode
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("AnyOrigin", builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod();
});
});
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "AdventofCode", Version = "v1" });
});
services.AddControllers(o => o.InputFormatters.Insert(o.InputFormatters.Count, new TextPlainInputFormatter()));
services.AddSwaggerGenNewtonsoftSupport();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "AdventOfCode v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

View File

@@ -0,0 +1,65 @@
using AdventOfCode.Common;
using AdventOfCode.Models;
using System;
using System.Collections.Generic;
using System.Linq;
namespace AdventOfCode._2022
{
[AOC(year: 2022, day: 1)]
public class Day1 : AOCDay
{
protected override AOCResponse ExecutePartA()
{
var rows = GetSplitInput();
var elves = new List<string[]>();
int elfSet = 0;
for (int i = 0; i < rows.Length; i++)
{
if (string.IsNullOrWhiteSpace(rows[i]))
{
elves.Add(rows.Skip(elfSet).Take(i - elfSet).ToArray());
elfSet = i+1;
}
if (i == rows.Length-1)
{
elves.Add(rows.Skip(elfSet).ToArray());
}
}
var highestCalories = 0;
foreach (var elf in elves)
{
highestCalories = Math.Max(highestCalories, elf.Select(x => int.Parse(x)).Sum());
}
_response.Answer = highestCalories;
return _response;
}
protected override AOCResponse ExecutePartB()
{
var rows = GetSplitInput();
var elves = new List<string[]>();
int elfSet = 0;
for (int i = 0; i < rows.Length; i++)
{
if (string.IsNullOrWhiteSpace(rows[i]))
{
elves.Add(rows.Skip(elfSet).Take(i - elfSet).ToArray());
elfSet = i + 1;
}
if (i == rows.Length - 1)
{
elves.Add(rows.Skip(elfSet).ToArray());
}
}
var highestCalories = new List<int>();
foreach (var elf in elves)
{
highestCalories.Add(elf.Select(x => int.Parse(x)).Sum());
}
_response.Answer = highestCalories.OrderByDescending(x => x).Take(3).Sum();
return _response;
}
}
}

114
AdventOfCode/_2022/Day2.cs Normal file
View File

@@ -0,0 +1,114 @@
using AdventOfCode.Common;
using AdventOfCode.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AdventOfCode._2022
{
[AOC(year: 2022, day: 2)]
public class Day2 : AOCDay
{
protected override AOCResponse ExecutePartA()
{
var rows = GetSplitInput();
var totalScore = 0;
foreach (var row in rows)
{
var opponent = row.Split(" ")[0];
var mine = row.Split(" ")[1];
var score = ScoreRound(opponent, mine);
Log(score);
totalScore += score;
}
_response.Answer = totalScore;
return _response;
}
protected override AOCResponse ExecutePartB()
{
var rows = GetSplitInput();
var totalScore = 0;
foreach (var row in rows)
{
var opponent = row.Split(" ")[0];
var mine = DeduceCorrectShape(opponent, row.Split(" ")[1]);
var score = ScoreRound(opponent, mine);
Log(score);
totalScore += score;
}
_response.Answer = totalScore;
return _response;
}
private string DeduceCorrectShape(string opponent, string mine)
{
var oppScore = GetShapeScore(opponent);
if (mine == "X") //Lose
{
if (oppScore == 1) return "C";
else if (oppScore == 2) return "A";
else if (oppScore == 3) return "B";
}else if (mine == "Y") //Draw
{
if (oppScore == 1) return "A";
else if (oppScore == 2) return "B";
else if (oppScore == 3) return "C";
}
else //Win
{
if (oppScore == 1) return "B";
else if (oppScore == 2) return "C";
else if (oppScore == 3) return "A";
}
return "";
}
private int ScoreRound(string o, string m)
{
//Its a draw
if (GetShapeScore(o) == GetShapeScore(m))
{
return 3 + GetShapeScore(m); //Tied
}else if (DidYouWin(o, m))
{
return 6 + GetShapeScore(m); //Won
}
return GetShapeScore(m); //Lost
}
private bool DidYouWin(string o, string m)
{
var opp = GetShapeScore(o);
var mine = GetShapeScore(m);
if (opp == 1 && mine == 2) return true;
if (opp == 1 && mine == 3) return false;
if (opp == 2 && mine == 1) return false;
if (opp == 2 && mine == 3) return true;
if (opp == 3 && mine == 1) return true;
if (opp == 3 && mine == 2) return false;
return false;
}
private int GetShapeScore(string s)
{
switch (s)
{
//Rock
case "A":
case "X":
return 1;
//Paper
case "B":
case "Y":
return 2;
//Scissors
case "C":
case "Z":
return 3;
}
return 0;
}
}
}

View File

@@ -0,0 +1,66 @@
using AdventOfCode.Common;
using AdventOfCode.Models;
using System;
using System.Collections.Generic;
using System.Linq;
namespace AdventOfCode._2022
{
[AOC(year: 2022, day: 3)]
public class Day3 : AOCDay
{
protected override AOCResponse ExecutePartA()
{
var rows = GetSplitInput();
int total = 0;
foreach (var row in rows)
{
var first = row.Substring(0, row.Length / 2);
var second = row.Substring((row.Length / 2));
var invalidItem = first.ToCharArray().Intersect(second.ToCharArray()).First();
total += GetPriority(invalidItem);
}
_response.Answer = total;
return _response;
}
protected override AOCResponse ExecutePartB()
{
var rows = GetSplitInput();
var elves = new List<string[]>();
int elfSet = 0;
for (int i = 0; i < rows.Length; i++)
{
if (string.IsNullOrWhiteSpace(rows[i]))
{
elves.Add(rows.Skip(elfSet).Take(i - elfSet).ToArray());
elfSet = i + 1;
}
if (i == rows.Length - 1)
{
elves.Add(rows.Skip(elfSet).ToArray());
}
}
var highestCalories = new List<int>();
foreach (var elf in elves)
{
highestCalories.Add(elf.Select(x => int.Parse(x)).Sum());
}
_response.Answer = highestCalories.OrderByDescending(x => x).Take(3).Sum();
return _response;
}
private int GetPriority(char c)
{
if (Char.IsUpper(c))
{
return (c - 'A' + 27);
}
if (Char.IsLower(c))
{
return (c - 'a' + 1);
}
return 0;
}
}
}

View File

@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}