/// <summary> /// /// </summary> /// <param name="tiempo"></param> private void terminarUsarTerminal(Evento e) { TiempoSimulacion = e.HoraEjecucionAbsoluta; for (int i = 0; i < terminales.Count; i++) { Terminal t = terminales[i]; if (t.Estado == 1 && t.Cliente == e.Cliente) { t.Estado = 0; terminales[i] = t; if (colaTerminales.Count > 0) { Evento nextCliente = new Evento(); nextCliente.Cliente = colaTerminales[0]; colaTerminales.RemoveAt(0); nextCliente.TipoEvento = 3; nextCliente.Terminal = t; nextCliente.HoraEjecucionAbsoluta = TiempoSimulacion; comenzarAUsarTerminal(nextCliente); } break; } } insertarClienteEnColaMasChica(e); }
/// <summary> /// se ejecuta en el tipo evento 2, /// </summary> /// <param name="e"></param> private void terminarAtencCaja(Evento e) { TiempoSimulacion = e.HoraEjecucionAbsoluta; // variable para ahorrar calculos si hay o no cola bool hayCola = false; //Si hay cola en la caja if (cajas[e.IdCaja].ColaClientes.Count > 0) { //se planifica el siguiente cliente en cola planificarTiempoCaja(e.IdCaja, cajas[e.IdCaja].ColaClientes[0]); //TiempoTotalEsperaEnColaCaja += (TiempoSimulacion - e.Cliente.HoraLlegadaColaCaja); e.Cliente = cajas[e.IdCaja].ColaClientes[0]; e.TipoEvento = 4; e.Mensaje = "Evento dependiente de atender Cliente"; loguear(e); hayCola = true; cajas[e.IdCaja].Estado = 1; } else { cajas[e.IdCaja].TiempoInactivo = TiempoSimulacion; cajas[e.IdCaja].Estado = 0; } //Se contabiliza un cliente atendido (para el total) totalClientesAtendidos++; //Se suma el total del tiempo que estuvo el cliente en el banco a un totalizador de dicho tiempo :) TiempoPermanenciaCliente += (TiempoSimulacion - cajas[e.IdCaja].ClienteQueSeAtiende.HoraLlegada); //Se contabiliza un cliente atendido (para esta caja) cajas[e.IdCaja].VecesUtilizada += 1; int aux = 0; if (cajas[e.IdCaja].ClienteQueSeAtiende.HoraLlegadaColaCaja != -1) { aux = salidaClienteAnterior[e.IdCaja] - cajas[e.IdCaja].ClienteQueSeAtiende.HoraLlegadaColaCaja; //Se suma el tiempo que esperó en la cola al total de tiempo de espera en cola TiempoTotalEsperaEnColaCaja += aux; } //El cliente que se está antendiendo FINALMENTE se fue. cajas[e.IdCaja].ClienteQueSeAtiende = null; salidaClienteAnterior[e.IdCaja] = TiempoSimulacion; //clientesQueEsperaron++; if (aux > TiempoMaximoEsperaEnColaCaja) { TiempoMaximoEsperaEnColaCaja = aux; } //si hay cola se supone que atiende al siguiente if (hayCola == true) { cajas[e.IdCaja].ClienteQueSeAtiende = cajas[e.IdCaja].ColaClientes[0]; cajas[e.IdCaja].ColaClientes.RemoveAt(0); } }
private void bComenzar_Click(object sender, EventArgs e) { bDetener_Click(sender, e); bloquear(); generarLog(); //numeroEvento = -1; ultimoEventoEjecutado = 0; for (int i = 0; i < cantidadCajas.Value; i++) { cajas.Add(new Caja()); salidaClienteAnterior.Add(0); } for (int i = 0; i < cantidadTerminales.Value; i++) { terminales.Add(new Terminal()); } bool ok = true; planificarLlegadaCliente(); int minutos = Int32.Parse((horasSimulacion.Value * 60).ToString()); while (TiempoSimulacion < minutos && ok) { //Esto es para la barra de progreso int progreso = 0; progreso = 100 * TiempoSimulacion; int hs = Int32.Parse(horasSimulacion.Value.ToString()); int minutosSimulacion = hs * 60; progreso /= minutosSimulacion; progressBar1.Value = progreso; //Hasta acá es para la barra de progreso try { //La línea del mal... Evento ev = eventos[ultimoEventoEjecutado]; ev.Mensaje = "Número evento :" + ultimoEventoEjecutado + ":"; ultimoEventoEjecutado++; loguear(ev); switch (ev.TipoEvento) { case 0: llegaCliente(ev); break; case 1: terminarUsarTerminal(ev); break; case 2: terminarAtencCaja(ev); break; default: break; } calcularTiempoOcioso(); } catch (Exception exc) { /* Evento kjh = new Evento(); kjh.TipoEvento = 6; kjh.Mensaje = exc.StackTrace + " " + exc.Message; loguear(kjh); MessageBox.Show("Ud. se ha comunicado con el centro de atención al suicida.\n" + "Por favor, aguarde un momento y será atendido por uno de nuestros operadores.\n" + "No cuelgue, y no SE cuelgue.\n\n" + "Error:\n" + exc.Message); ok = false;*/ bDetener_Click(sender, e); bComenzar_Click(sender, e); } } try { int restarATotalCola = 0; foreach(Caja c in cajas) { restarATotalCola += c.ColaClientes.Count; } rColaMaximaTerminales.Text = "Tamaño máximo de la cola en terminales (minutos): " + maximaColaTerminales; rTiempoEsperaPromedioCajas.Text = "Tiempo de espera promedio en la cola de las cajas (minutos): " + (TiempoTotalEsperaEnColaCaja / (clientesQueEsperaron - restarATotalCola)); rTiempoEsperaMaximoCajas.Text = "Tiempo de espera máximo en la cola de las cajas (minutos): " + TiempoMaximoEsperaEnColaCaja; rTiempoAcumuladoOcioso.Text = "Tiempo acumulado de cajeros ociosos: " + tiempoOcioso + " minutos (~" + (tiempoOcioso / 60) + " horas)"; rTiempoTramiteCliente.Text = "Tiempo promedio para trámites de un cliente (minutos): " + (TiempoPermanenciaCliente / totalClientesAtendidos).ToString(); rTotalClientes.Text = "Total de clientes atendidos: " + totalClientesAtendidos; } catch (Exception exc) { Evento kjh = new Evento(); kjh.TipoEvento = 6; kjh.Mensaje = exc.StackTrace; loguear(kjh); MessageBox.Show("Ud. se ha comunicado con el centro de atención al suicida.\n" + "Por favor, aguarde un momento y será atendido por uno de nuestros operadores.\n" + "No cuelgue, y no SE cuelgue.\n\n" + "Error:\n" + exc.Message ); ok = false; } progressBar1.Value = 100; desbloquear(); }
/// <summary> /// Planifica cuándo termina atenderse un cliente en una caja /// </summary> private void planificarTiempoCaja(int nroCaja, Cliente c) { Evento e = new Evento(); //e.HoraEjecucionAbsoluta = TiempoSimulacion + generarXNormal(9.9, 3.56, 0.11, 1, 18); e.HoraEjecucionAbsoluta = TiempoSimulacion + generarXNormal(mediaAtencionCaja, desviacionAtencionCaja, modaAtencionCaja, limiteInferiorAtencionCaja, limiteSuperiorAtencionCaja); e.TipoEvento = 2; //salida de un cliente (terminó de usar) de la caja e.IdCaja = nroCaja; e.Cliente = c; insertarEvento(e); }
/// <summary> /// Cuándo termina de usarse una terminal /// </summary> private void planificarUsoTerminal(Terminal t) { Evento e = new Evento(); e.HoraEjecucionAbsoluta = TiempoSimulacion + generarXUniforme(modaUsoTerminal); e.TipoEvento = 1; e.Cliente = t.Cliente; insertarEvento(e); }
/// <summary> /// Agrega una entrada en el log.txt con el evento /// </summary> /// <param name="e">El evento que se desea loguear</param> private void loguear(Evento e) { string fileName = "log.txt"; //archivo log.txt //nombre del archivo, establece el cursor al final de la linea, tipo de acceso FileStream stream = new FileStream(fileName, FileMode.Append, FileAccess.Write); StreamWriter writer = new StreamWriter(stream); //crea la accion string hora = Math.Ceiling(Double.Parse((e.HoraEjecucionAbsoluta / 60).ToString())).ToString() + ":" + (e.HoraEjecucionAbsoluta % 60).ToString(); string entrada = hora + " => "; switch (e.TipoEvento) { case 0: writer.WriteLine(entrada += "Llega un cliente al sistema"); writer.WriteLine("\t\t:" + e.TipoEvento + ": => Tipo de evento"); writer.WriteLine("\t\t:" + e.Cliente.IdCliente + ": => Cliente"); writer.WriteLine("\t\t:" + e.IdCaja + ": => Caja"); writer.WriteLine("\t\t:" + e.Mensaje + ": => Mensaje"); writer.WriteLine(); break; case 1: writer.WriteLine(entrada += "Un cliente termina de usar una terminal"); writer.WriteLine("\t\t:" + e.TipoEvento + ": => Tipo de evento"); writer.WriteLine("\t\t:" + e.Cliente.IdCliente + ": => Cliente"); writer.WriteLine("\t\t:" + e.IdCaja + ": => Caja"); writer.WriteLine("\t\t:" + e.Mensaje + ": => Mensaje"); writer.WriteLine(); break; case 2: writer.WriteLine(entrada += "Un cliente termina de ser atendido por la caja (y se va)"); writer.WriteLine("\t\t:" + e.TipoEvento + ": => Tipo de evento"); writer.WriteLine("\t\t:" + e.Cliente.IdCliente + ": => Cliente"); writer.WriteLine("\t\t:" + e.IdCaja + ": => Caja"); writer.WriteLine("\t\t:" + e.Mensaje + ": => Mensaje"); writer.WriteLine(); break; case 3: writer.WriteLine(entrada += "Un cliente comienza a usar una terminal"); writer.WriteLine("\t\t:" + e.TipoEvento + ": => Tipo de evento"); writer.WriteLine("\t\t:" + e.Cliente.IdCliente + ": => Cliente"); writer.WriteLine("\t\t:" + e.IdCaja + ": => Caja"); writer.WriteLine("\t\t:" + e.Mensaje + ": => Mensaje"); writer.WriteLine(); break; case 4: writer.WriteLine(entrada += "Un cliente comienza a ser atendido"); writer.WriteLine("\t\t:" + e.TipoEvento + ": => Tipo de evento"); writer.WriteLine("\t\t:" + e.Cliente.IdCliente + ": => Cliente"); writer.WriteLine("\t\t:" + e.IdCaja + ": => Caja"); writer.WriteLine("\t\t:" + e.Mensaje + ": => Mensaje"); writer.WriteLine(); break; case 5: writer.WriteLine(entrada += "Un cliente comienza a esperar en la cola para una caja"); writer.WriteLine("\t\t:" + e.TipoEvento + ": => Tipo de evento"); writer.WriteLine("\t\t:" + e.Cliente.IdCliente + ": => Cliente"); writer.WriteLine("\t\t:" + e.IdCaja + ": => Caja"); writer.WriteLine("\t\t:" + e.Mensaje + ": => Mensaje"); writer.WriteLine(); break; case 6: writer.WriteLine("############################################################"); writer.WriteLine("Se ha producido un error. Contáctese con los desarrolladores"); writer.WriteLine("############################################################"); writer.WriteLine(); writer.WriteLine(e.Mensaje); writer.WriteLine(); break; case 7: writer.WriteLine(entrada += "Un cliente comienza a esperar en la cola para usar una terminal"); writer.WriteLine("\t\t:" + e.TipoEvento + ": => Tipo de evento"); writer.WriteLine("\t\t:" + e.Cliente.IdCliente + ": => Cliente"); writer.WriteLine("\t\t:" + e.IdCaja + ": => Caja"); writer.WriteLine("\t\t:" + e.Mensaje + ": => Mensaje"); writer.WriteLine(); break; default: writer.WriteLine(entrada += "Evento irreconocible"); writer.WriteLine("\t\t:" + e.TipoEvento + ": => Tipo de evento"); writer.WriteLine("\t\t:" + e.Cliente.IdCliente + ": => Cliente"); writer.WriteLine("\t\t:" + e.IdCaja + ": => Caja"); writer.WriteLine("\t\t:" + e.Mensaje + ": => Mensaje"); writer.WriteLine(); break; } writer.Close();//cierra la escritura del }
/// <summary> /// Agrega un evento a la lista de eventos con la hora absoluta a la que llegará el próximo cliente /// </summary> private void planificarLlegadaCliente() { Evento e = new Evento(); e.HoraEjecucionAbsoluta = TiempoSimulacion + generarXNormal(mediaLlegadaCliente, desviacionLlegadaCliente, modaLlegadaCliente, limiteInferiorLlegadaCliente, limiteSuperiorLlegadaCliente); e.TipoEvento = 0; Cliente c = new Cliente(); c.IdCliente = clientesEnBanco; clientesEnBanco++; e.Cliente = c; insertarEvento(e); }
/// <summary> /// El tiempo de ejecución es igual al evento que contiene la llegada del cliente. /// Se dispara la llegada de un cliente (se crea un cliente) y se lo agrega a una de las filas de /// las cajas o a la fila de las terminales (con una probabilidad 1/30 1/70 respectivamente. /// </summary> /// <param name="tiempo"></param> private void llegaCliente(Evento e) { TiempoSimulacion = e.HoraEjecucionAbsoluta; planificarLlegadaCliente(); e.Cliente.HoraLlegada = TiempoSimulacion; int decision = r.Next(0, 100); if (decision <= 30) //se va a la caja directamente { insertarClienteEnColaMasChica(e); } else //pasa primero por las terminales { comenzarAUsarTerminal(e); } }
/// <summary> /// Inserta un evento en una lista ordenada por la hora de ejecución absoluta del evento /// </summary> /// <param name="eNuevo">El evento que se desea insertar en la lista</param> private void insertarEvento(Evento eNuevo) { bool ok = false; int indice = eventos.Count - 1; do { if (eventos.Count > 0) { Evento e = eventos[indice]; if (eNuevo.HoraEjecucionAbsoluta > e.HoraEjecucionAbsoluta) { eventos.Insert(indice + 1, eNuevo); numeroEvento++; ok = true; } indice--; } else { eventos.Add(eNuevo); numeroEvento++; ok = true; } } while (ok == false); }
/// <summary> /// Inserta el cliente pasado por parámetro en la caja que tenga la cola más corta /// </summary> private void insertarClienteEnColaMasChica(Evento e) { int fila = 10000000; int cajaMenor = 0; for (int x = 0; x < cajas.Count; x++) { Caja c = cajas[x]; if (c.ColaClientes.Count < fila) { fila = c.ColaClientes.Count; cajaMenor = x; } } if (cajas[cajaMenor].ColaClientes.Count > 0) { e.IdCaja = cajaMenor; e.Cliente.HoraLlegadaColaCaja = TiempoSimulacion; cajas[cajaMenor].ColaClientes.Add(e.Cliente); clientesQueEsperaron++; } else { e.Cliente.HoraLlegadaColaCaja = -1; e.IdCaja = cajaMenor; comenzarAUsarCaja(e); } }
/// <summary> /// Ocupa una terminal y resta un cliente de la cola de terminales /// </summary> private void comenzarAUsarTerminal(Evento e) { bool libre = false; for(int i = 0; i < terminales.Count; i++) { Terminal t = terminales[i]; if (t.Estado == 0) { libre = true; t.Estado = 1; t.Cliente = e.Cliente; terminales[i] = t; planificarUsoTerminal(t); e.TipoEvento = 3; e.Mensaje = "Evento dependiente"; loguear(e); break; } } if (!libre) { colaTerminales.Add(e.Cliente); e.TipoEvento = 7; e.Mensaje = "Evento dependiente"; loguear(e); if (maximaColaTerminales < colaTerminales.Count) { maximaColaTerminales = colaTerminales.Count; } } }
/// <summary> /// Un cliente comenzará a ser atendido. /// </summary> /// <param name="e"></param> private void comenzarAUsarCaja(Evento e) { calcularTiempoOcioso(); if (cajas[e.IdCaja].Estado == 0) { //Ocupa la caja cajas[e.IdCaja].Estado = 1; //Se asigna el cliente a la caja cajas[e.IdCaja].ClienteQueSeAtiende = e.Cliente; //Se planifica el tiempo de uso de la caja planificarTiempoCaja(e.IdCaja, e.Cliente); e.TipoEvento = 4; e.Mensaje = "Evento dependiente"; loguear(e); } else { e.Cliente.HoraLlegadaColaCaja = TiempoSimulacion; cajas[e.IdCaja].ColaClientes.Add(e.Cliente); clientesQueEsperaron++; e.TipoEvento = 5; e.Mensaje = "Evento dependiente"; loguear(e); } //return e; }