using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Caisses { internal class GraphicalStore { public static readonly int[] ATTENDANCE = { 0, 0, 0, 0, 0, 0, 0, 30, 30, 40, 50, 60, 100, 80, 50, 30, 80, 100, 50, 50, 80, 0, 0, 0 }; public const int CROSSOVER_TIME = 10; private List _checkouts; private List _clients; private int _timeOfTheDayInMinuts; private Bitmap _shelvesCorner; private Bitmap _checkoutCorner; private Random rnd; /// Stats private int _AverageWaitingTime; private int _OpenCheckoutCount; private int _PlacesLeftCount; private List _NotFullCheckouts; private List _WaitingClients; public int AverageWaitingTime { get => _AverageWaitingTime; set => _AverageWaitingTime = value; } public int OpenCheckoutCount { get => _OpenCheckoutCount; set => _OpenCheckoutCount = value; } public int TotalPlacesLeftCount { get => _PlacesLeftCount; set => _PlacesLeftCount = value; } internal List NotFullCheckouts { get => _NotFullCheckouts; set => _NotFullCheckouts = value; } public List WaitingClients { get => _WaitingClients; set => _WaitingClients = value; } /// Stats public int TimeOfTheDayInMinuts { get => _timeOfTheDayInMinuts; set => _timeOfTheDayInMinuts = value; } public List Clients { get => _clients; set => _clients = value; } internal List Checkouts { get => _checkouts; set => _checkouts = value; } public Bitmap ShelvesCorner { get => _shelvesCorner; set => _shelvesCorner = value; } public Bitmap CheckoutCorner { get => _checkoutCorner; set => _checkoutCorner = value; } public int TimeOfTheDayInHours { get { return _timeOfTheDayInMinuts / 60; } } public GraphicalStore(int startingHour, int checkoutNumber, Size shelvesCornerSize, Size checkoutCornerSize) { TimeOfTheDayInMinuts = startingHour * 60; Clients = new List(); Checkouts = new List(); CheckoutCorner = new Bitmap(checkoutCornerSize.Width, checkoutCornerSize.Height); ShelvesCorner = new Bitmap(shelvesCornerSize.Width, shelvesCornerSize.Height); rnd = new Random(); FillStore(ATTENDANCE[TimeOfTheDayInHours]); populateCheckouts(checkoutNumber); Tick(); } public void populateCheckouts(int numberOfCheckouts) { int checkoutWidth = CheckoutCorner.Width / numberOfCheckouts + 1; for (int i = 0; i < numberOfCheckouts; i++) { Point position = new Point(i * checkoutWidth + checkoutWidth / numberOfCheckouts, 0); Checkouts.Add(new GraphicalCheckout(position, new Rectangle(new Point(0, 0), new Size(CheckoutCorner.Width, CheckoutCorner.Height)), numberOfCheckouts)); } } public void Tick() { TimeOfTheDayInMinuts++; if (TimeOfTheDayInMinuts % 60 == 0) { if (TimeOfTheDayInMinuts >= 24 * 60) { TimeOfTheDayInMinuts = 0; } //Its a new Hour so we can send the new clients int amountOfNewCLients = ATTENDANCE[TimeOfTheDayInHours]; FillStore(amountOfNewCLients); } int cumulatedWaitingTime = 0; int waitingClients = 0; AverageWaitingTime = 0; WaitingClients = new List(); if (NotFullCheckouts == null) NotFullCheckouts = new List(); //Clients that will leave the store List clientsToRemove = new List(); foreach (GraphicalClient client in Clients) { //Tick client.Tick(); // Calculating average waiting time if (Clients.Count == 0 || waitingClients == 0) { AverageWaitingTime = 0; } else { AverageWaitingTime = cumulatedWaitingTime / waitingClients; } //Waiting time incrementation if (Clients.Count != 0 && client.State == Client.ClientState.Waiting) { cumulatedWaitingTime += client.WaitingTime; waitingClients += 1; WaitingClients.Add(client); //Checkout process if (TotalPlacesLeftCount > 0 && NotFullCheckouts.Count > 0) { //Now we select a random one to put our waiting client int index = 0; int count = NotFullCheckouts.Count; if (count > 0) { index = rnd.Next(0, count - 1); } else { index = 0; } if (NotFullCheckouts[index].Clients.Count < Checkout.MAX_CAPACITY) { //We need to check that because a client could have been already added and so the checkout could not have any places left even tho she is listed as not full NotFullCheckouts[index].Clients.Add(client); //Clients.Remove(client); clientsToRemove.Add(client); client.State = Client.ClientState.Inline; } } } } foreach (GraphicalClient client in clientsToRemove) { Clients.Remove(client); } OpenCheckoutCount = 0; TotalPlacesLeftCount = 0; NotFullCheckouts = new List(); foreach (GraphicalCheckout checkout in Checkouts) { //Tick checkout.Tick(this); if (checkout.Open) { //Calculate amount of open Checkouts OpenCheckoutCount++; //Calculate amount of places left int CheckoutPlacesLeft = Checkout.MAX_CAPACITY - checkout.Clients.Count(); TotalPlacesLeftCount += CheckoutPlacesLeft; //Collecting every non full checkout if (CheckoutPlacesLeft > 0) { NotFullCheckouts.Add(checkout); } //Checkout behaviour if (checkout.Clients.Count > 0) { Client cClient = checkout.Clients[0]; if (cClient.State != Client.ClientState.Checkout) cClient.State = Client.ClientState.Checkout; if (cClient.CheckoutTime <= 0) { checkout.Clients.Remove(cClient); //We dont load the next because he should be loaded the next time this function is loaded } foreach (GraphicalClient ccClient in checkout.Clients) { ccClient.Tick(); } } } } } public List Draw() { ShelvesCorner = new Bitmap(ShelvesCorner.Width, ShelvesCorner.Height); CheckoutCorner = new Bitmap(CheckoutCorner.Width, CheckoutCorner.Height); foreach (GraphicalClient client in Clients) { client.Draw(ShelvesCorner); } foreach (GraphicalCheckout checkout in Checkouts) { checkout.Draw(CheckoutCorner); foreach (GraphicalClient client in checkout.Clients) { client.Draw(ShelvesCorner); } } return new List { ShelvesCorner, CheckoutCorner }; } public virtual void FillStore(int amountOfNewClients) { for (int i = 0; i < amountOfNewClients; i++) { Clients.Add(new GraphicalClient(new Point(0, 0), rnd)); } } public int GetEmptyCheckoutCount() { int result = 0; foreach (GraphicalCheckout checkout in Checkouts) { if (checkout.Open && checkout.Clients.Count == 0) { result += 1; } } return result; } } }