diff --git a/Data/Data.csproj b/Data/Data.csproj new file mode 100644 index 0000000..9c5aa01 --- /dev/null +++ b/Data/Data.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + diff --git a/Data/Extentions/ServiceCollectionExtentions.cs b/Data/Extentions/ServiceCollectionExtentions.cs new file mode 100644 index 0000000..b52c22d --- /dev/null +++ b/Data/Extentions/ServiceCollectionExtentions.cs @@ -0,0 +1,13 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Services.Tickets; + +namespace Data.Extentions; + +public static class ServiceCollectionExtentions +{ + public static void TyAddFakeTicketRepository(this IServiceCollection services) + { + services.TryAddScoped(); + } +} diff --git a/Data/FakeTicketRepository.cs b/Data/FakeTicketRepository.cs new file mode 100644 index 0000000..49cee2b --- /dev/null +++ b/Data/FakeTicketRepository.cs @@ -0,0 +1,21 @@ +using Services.Tickets; +using Services.Tickets.Models; + +namespace Data; + +internal class FakeTicketRepository : ITicketRepository +{ + private readonly List _lotteryTickets = new List(); + public Task AddNewTicket(LotteryTicket ticket) + { + var id =(long)Random.Shared.Next(1, 100); + ticket.Id = id; + _lotteryTickets.Add(ticket); + return Task.FromResult(id); + } + + public Task> GetAllTickets() + { + return Task.FromResult(_lotteryTickets); + } +} diff --git a/Lottery.Tests/GlobalUsings.cs b/Lottery.Tests/GlobalUsings.cs new file mode 100644 index 0000000..cefced4 --- /dev/null +++ b/Lottery.Tests/GlobalUsings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file diff --git a/Lottery.Tests/Lottery.Tests.csproj b/Lottery.Tests/Lottery.Tests.csproj new file mode 100644 index 0000000..66239c2 --- /dev/null +++ b/Lottery.Tests/Lottery.Tests.csproj @@ -0,0 +1,24 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + diff --git a/Lottery.Tests/NumbersServiceTests.cs b/Lottery.Tests/NumbersServiceTests.cs new file mode 100644 index 0000000..6781c3e --- /dev/null +++ b/Lottery.Tests/NumbersServiceTests.cs @@ -0,0 +1,36 @@ +using Services.Numbers; +using Services.Tickets; + +namespace Lottery.Tests; + +public class NumbersServiceTests +{ + [SetUp] + public void Setup() + { + } + + [Test] + public void ShouldGenerateUniqNumbers() + { + var numbersService = new NumbersService(); + for (int i = 0; i < 1000; i++) + { + var t = numbersService.GetNumbers(35); + CollectionAssert.AllItemsAreUnique(t); + } + } + + [Test] + public void ShouldGenerateRandomNumbers() + { + var numbersService = new NumbersService(); + + List numbers = new List(); + for (int i = 0; i < 1000; i++) + { + numbers.Add(numbersService.GetNumbers(6)); + } + CollectionAssert.AllItemsAreUnique(numbers); + } +} \ No newline at end of file diff --git a/Lottery.Tickets/Class1.cs b/Lottery.Tickets/Class1.cs new file mode 100644 index 0000000..741057e --- /dev/null +++ b/Lottery.Tickets/Class1.cs @@ -0,0 +1,6 @@ +namespace Lottery.Tickets; + +public class Class1 +{ + +} diff --git a/Lottery.Tickets/Lottery.Tickets.csproj b/Lottery.Tickets/Lottery.Tickets.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/Lottery.Tickets/Lottery.Tickets.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/Lottery.sln b/Lottery.sln new file mode 100644 index 0000000..21b66c7 --- /dev/null +++ b/Lottery.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34330.188 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Services", "Services\Services.csproj", "{E53B4797-FCFE-418E-B412-E08381A144E3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Data", "Data\Data.csproj", "{1D5D5D3E-2D9A-4AAB-896E-E0957CD75E9A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkerService1", "WorkerService1\WorkerService1.csproj", "{0A24B96A-7B80-486A-9546-B82FC5F99675}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lottery.Tests", "Lottery.Tests\Lottery.Tests.csproj", "{BCBB643F-C468-4EE6-B186-6E2084B644DE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E53B4797-FCFE-418E-B412-E08381A144E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E53B4797-FCFE-418E-B412-E08381A144E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E53B4797-FCFE-418E-B412-E08381A144E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E53B4797-FCFE-418E-B412-E08381A144E3}.Release|Any CPU.Build.0 = Release|Any CPU + {1D5D5D3E-2D9A-4AAB-896E-E0957CD75E9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D5D5D3E-2D9A-4AAB-896E-E0957CD75E9A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D5D5D3E-2D9A-4AAB-896E-E0957CD75E9A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D5D5D3E-2D9A-4AAB-896E-E0957CD75E9A}.Release|Any CPU.Build.0 = Release|Any CPU + {0A24B96A-7B80-486A-9546-B82FC5F99675}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A24B96A-7B80-486A-9546-B82FC5F99675}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A24B96A-7B80-486A-9546-B82FC5F99675}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A24B96A-7B80-486A-9546-B82FC5F99675}.Release|Any CPU.Build.0 = Release|Any CPU + {BCBB643F-C468-4EE6-B186-6E2084B644DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BCBB643F-C468-4EE6-B186-6E2084B644DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BCBB643F-C468-4EE6-B186-6E2084B644DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BCBB643F-C468-4EE6-B186-6E2084B644DE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F98A62EA-62A5-4385-9709-B488076B1543} + EndGlobalSection +EndGlobal diff --git a/Services/Games/Extentions/ServiceCollectionExtentions.cs b/Services/Games/Extentions/ServiceCollectionExtentions.cs new file mode 100644 index 0000000..23f950c --- /dev/null +++ b/Services/Games/Extentions/ServiceCollectionExtentions.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Services.Tickets.Extentions; + +namespace Services.Games.Extentions; + +public static class ServiceCollectionExtentions +{ + public static void TyAddGamesService(this IServiceCollection services) + { + services.TyAddTicketService(); + services.TryAddScoped(); + } +} diff --git a/Services/Games/GameService.cs b/Services/Games/GameService.cs new file mode 100644 index 0000000..91c5c03 --- /dev/null +++ b/Services/Games/GameService.cs @@ -0,0 +1,49 @@ +using Microsoft.Extensions.Logging; +using Services.Numbers; +using Services.Tickets; +using Services.Tickets.Models; +using System.Net.Sockets; + +namespace Services.Games; +internal class GameService : IGameService +{ + private readonly INumbersService _numbersService; + private readonly ITicketService _ticketService; + + public GameService(ILogger logger, INumbersService numbersService, ITicketService ticketService) + { + _numbersService = numbersService; + _ticketService = ticketService; + } + + public async Task winTickets, int matches)>> GetWinnersTickets(byte[] winNumbers) + { + List tickets = await _ticketService.GetAllTickets(); + return CalculateWinners(tickets, winNumbers); + + } + + private List<(List winTickets,int matches)> CalculateWinners(List tickets, byte[] bytes) + { + List<(List winTickets,int matches)> results = new(); + for (int i = 0; i < bytes.Length; i++) + { + List winners = new List(); + for (int j = 0; j < tickets.Count; j++) + { + if (bytes.Except(tickets[j].Numbers!).Count() == i) + { + winners.Add(tickets[j]); + tickets.RemoveAt(j); + } + } + results.Add((winners, bytes.Length - i)); + } + return results; + } + + public byte[] GetWinNumbers() + { + return _numbersService.GetNumbers(6); + } +} diff --git a/Services/Games/IGameService.cs b/Services/Games/IGameService.cs new file mode 100644 index 0000000..1556ef6 --- /dev/null +++ b/Services/Games/IGameService.cs @@ -0,0 +1,9 @@ +using Services.Tickets.Models; + +namespace Services.Games; + +public interface IGameService +{ + byte[] GetWinNumbers(); + Task winTickets, int matches)>> GetWinnersTickets(byte[] winNumbers); +} diff --git a/Services/Numbers/Extentions/ServiceCollectionExtentions.cs b/Services/Numbers/Extentions/ServiceCollectionExtentions.cs new file mode 100644 index 0000000..0dbe501 --- /dev/null +++ b/Services/Numbers/Extentions/ServiceCollectionExtentions.cs @@ -0,0 +1,12 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace Services.Numbers.Extentions; + +public static class ServiceCollectionExtentions +{ + public static void TyAddNumbersService(this IServiceCollection services) + { + services.TryAddScoped(); + } +} diff --git a/Services/Numbers/INumbersService.cs b/Services/Numbers/INumbersService.cs new file mode 100644 index 0000000..29e5d06 --- /dev/null +++ b/Services/Numbers/INumbersService.cs @@ -0,0 +1,6 @@ +namespace Services.Numbers; + +public interface INumbersService +{ + byte[] GetNumbers(byte count); +} diff --git a/Services/Numbers/NumbersService.cs b/Services/Numbers/NumbersService.cs new file mode 100644 index 0000000..4e47909 --- /dev/null +++ b/Services/Numbers/NumbersService.cs @@ -0,0 +1,49 @@ +namespace Services.Numbers; + +internal class NumbersService : INumbersService +{ + public byte[] GetNumbers(byte count = 6) + { + byte[] init = + [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36 + ]; + Random.Shared.Shuffle(init); + return init.Take(count).ToArray(); + } +} diff --git a/Services/Services.csproj b/Services/Services.csproj new file mode 100644 index 0000000..94f6f9e --- /dev/null +++ b/Services/Services.csproj @@ -0,0 +1,20 @@ + + + + net8.0 + enable + enable + + + + + + + + + + <_Parameter1>Lottery.Tests + + + + diff --git a/Services/Tickets/Extentions/ServiceCollectionExtentions.cs b/Services/Tickets/Extentions/ServiceCollectionExtentions.cs new file mode 100644 index 0000000..7eb8fcc --- /dev/null +++ b/Services/Tickets/Extentions/ServiceCollectionExtentions.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Services.Numbers.Extentions; + +namespace Services.Tickets.Extentions; + +public static class ServiceCollectionExtentions +{ + public static void TyAddTicketService(this IServiceCollection services) + { + services.TyAddNumbersService(); + services.TryAddScoped(); + } +} diff --git a/Services/Tickets/ITicketRepository.cs b/Services/Tickets/ITicketRepository.cs new file mode 100644 index 0000000..6ac10a1 --- /dev/null +++ b/Services/Tickets/ITicketRepository.cs @@ -0,0 +1,8 @@ +using Services.Tickets.Models; + +namespace Services.Tickets; +public interface ITicketRepository +{ + Task AddNewTicket(LotteryTicket ticket); + Task> GetAllTickets(); +} diff --git a/Services/Tickets/ITicketService.cs b/Services/Tickets/ITicketService.cs new file mode 100644 index 0000000..a524460 --- /dev/null +++ b/Services/Tickets/ITicketService.cs @@ -0,0 +1,9 @@ +using Services.Tickets.Models; + +namespace Services.Tickets; + +public interface ITicketService +{ + Task> GetAllTickets(); + Task GetNewTicket(); +} diff --git a/Services/Tickets/Models/LotteryTicket.cs b/Services/Tickets/Models/LotteryTicket.cs new file mode 100644 index 0000000..eba2468 --- /dev/null +++ b/Services/Tickets/Models/LotteryTicket.cs @@ -0,0 +1,8 @@ +namespace Services.Tickets.Models; +public class LotteryTicket +{ + public long? Id { get; set; } + public byte[]? Numbers { get; set; } + public string? Owner { get; set; } + public string? PhoneNumber { get; set; } +} diff --git a/Services/Tickets/TicketService.cs b/Services/Tickets/TicketService.cs new file mode 100644 index 0000000..284ba48 --- /dev/null +++ b/Services/Tickets/TicketService.cs @@ -0,0 +1,36 @@ +using Microsoft.Extensions.Logging; +using Services.Numbers; +using Services.Tickets.Models; + +namespace Services.Tickets; + +internal class TicketService : ITicketService +{ + private readonly ILogger _logger; + private readonly ITicketRepository _ticketRepository; + private readonly INumbersService _numbersService; + + public TicketService(ILogger logger, ITicketRepository ticketRepository, INumbersService numbersService) + { + _logger = logger; + _ticketRepository = ticketRepository; + _numbersService = numbersService; + } + + public Task> GetAllTickets() + { + return _ticketRepository.GetAllTickets(); + } + + public async Task GetNewTicket() + { + LotteryTicket ticket = new() + { + Numbers = _numbersService.GetNumbers(6) + }; + var id = await _ticketRepository.AddNewTicket(ticket); + ticket.Id = id; + //_logger.LogInformation("New ticket created"); + return ticket; + } +} diff --git a/WorkerService1/Program.cs b/WorkerService1/Program.cs new file mode 100644 index 0000000..8a63434 --- /dev/null +++ b/WorkerService1/Program.cs @@ -0,0 +1,13 @@ +using WorkerService1; +using Data.Extentions; +using Services.Tickets.Extentions; +using Services.Games.Extentions; + +var builder = Host.CreateApplicationBuilder(args); +builder.Services.AddHostedService(); +builder.Services.TyAddTicketService(); +builder.Services.TyAddGamesService(); +builder.Services.TyAddFakeTicketRepository(); + +var host = builder.Build(); +host.Run(); diff --git a/WorkerService1/Properties/launchSettings.json b/WorkerService1/Properties/launchSettings.json new file mode 100644 index 0000000..e5d9dbd --- /dev/null +++ b/WorkerService1/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "WorkerService1": { + "commandName": "Project", + "dotnetRunMessages": true, + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Development" + } + } + } +} diff --git a/WorkerService1/Worker.cs b/WorkerService1/Worker.cs new file mode 100644 index 0000000..1aaf66c --- /dev/null +++ b/WorkerService1/Worker.cs @@ -0,0 +1,32 @@ +using Services.Games; +using Services.Tickets; + +namespace WorkerService1; + +public class Worker : BackgroundService +{ + private readonly ILogger _logger; + private readonly IServiceScopeFactory _serviceScopeFactory; + + public Worker(ILogger logger, IServiceScopeFactory serviceScopeFactory) + { + _logger = logger; + _serviceScopeFactory = serviceScopeFactory; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + using (var scope = _serviceScopeFactory.CreateScope()) + { + var ticketService = scope.ServiceProvider.GetRequiredService(); + for (int i = 0; i < 100000; i++) + { + var ticket = await ticketService.GetNewTicket(); + } + + var gameService = scope.ServiceProvider.GetRequiredService(); + var winNumbers = gameService.GetWinNumbers(); + var winners = await gameService.GetWinnersTickets(winNumbers); + } + } +} diff --git a/WorkerService1/WorkerService1.csproj b/WorkerService1/WorkerService1.csproj new file mode 100644 index 0000000..c9a09ad --- /dev/null +++ b/WorkerService1/WorkerService1.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + enable + enable + dotnet-WorkerService1-a5282c60-3d37-46ee-983b-990e33b39645 + + + + + + + + + + + diff --git a/WorkerService1/appsettings.Development.json b/WorkerService1/appsettings.Development.json new file mode 100644 index 0000000..b2dcdb6 --- /dev/null +++ b/WorkerService1/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/WorkerService1/appsettings.json b/WorkerService1/appsettings.json new file mode 100644 index 0000000..b2dcdb6 --- /dev/null +++ b/WorkerService1/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +}