Buscar este blog

domingo, 22 de marzo de 2009

Cajero en JavaScript

Función Separa

Monto:

Esta funcion se encarga de dividir un monto dado en billetes de distintas denominaciones, las denominaciones las podemos pasar como un array, y en base a éste la función empezara a repartirlos si es posible.
Se pueden agregar la cantidad de denominaciones que se crea conveniente y priorizará conservar el "censillo", esto es, primero tratará de cubrir el monto con las denominaciones en los indices inferiores de la matriz de denominaciones.
Se pudo hacer con un doble array, o un array multidimencional, pero preferi hacerlo usando el "prototype" de los array en JavaScript, dotandole a cada item del array de propiedades, como es el caso de este, que le agregue las propiedades de "Denominacion" y "Cantidad"
function billete(denominacion,cantidad){
 this.denominacion=denominacion
 this.cantidad=cantidad
}
Como se aprecia, he creado una pseudo funcion, que me servira para pasarle este prototipo a los items del array que voy a necesitar.
La funcion "Separar" es recursiva, y requiere que se le pase como argumentos, el monto del que se va a dividir, la matriz o array que tenga el prototipo billete implementado anteriormente llenado con las denominaciones que se quiere analizar ordenadas por orden de importancia, luego explicaré a que me refiero con esto, como ultimo argumento se le debe pasar en que indice va empezar a trabajar, para el inicio se le debe de pasar -1, y se calculara automaticamente de donde debe de empezar basado en el tamaño del array, aqui el codigo:
function Separa(monto,billetes,inicio){
 if(inicio==-1){
  inicio=billetes.length-1
  if(monto%10>0)return monto
 }
 billetes[inicio].cantidad=parseInt(monto/billetes[inicio].denominacion)
 residuo=monto%billetes[inicio].denominacion
 while(residuo>0){
  ninicio=inicio
  ninicio--
  if(inicio>1){residuo=Separa(residuo,billetes,ninicio)} 
  if(residuo>0 && billetes[inicio].cantidad==0){break} 
  if(residuo>0 && billetes[inicio].cantidad>0){
   billetes[inicio].cantidad--
   residuo=monto-billetes[inicio].denominacion*billetes[inicio].cantidad
  }
 }
 return residuo
}
Lo que esta en la linea 4, es un control para que no necesite evaluar aquellos montos que de antemano no van a poder ser divididos, este valor debera ser el maximo comun divisor de todas las denominaciones, por motivos de simplicidad evite hacer este cálculo, ya que por el momento sólo estaremos teniendo denominaciones mayores a 20, tales como 20, 50, 100 y 200 soles, como se ve, 10 es el MCD de todas las denominaciones, entonces, 10 debemos de reemplazarlo con el MCD de todas las denominaciones existentes en el array. Esto tratare de hacerlo en otro post.
Como se aprecia, las lineas del 2 al 5 son para el escenario del inicio del calculo, aqui por ejemplo asigno a la variable "inicio" el valor del tamaño de la matriz billetes que vino como parametro, ademas como dije, controlar si de antemano no se va a poder hacer la repartición
Como se supone que la matriz billetes tiene el prototipo billete, entonces asumo que cada indice de la matriz tiene las propiedades Cantidad y Denominacion, e spor eso que las uso directamente.
Ahora, cómo uso esta funcion?
Primero necesitamos inicializar y asignar el prototipo billete a la matriz de denominaciones que vamos a usar
 
 billetes=new Array(4)
 billetes[1]=new billete(20,0)
 billetes[2]=new billete(50,0)
 billetes[3]=new billete(100,0)
 billetes[4]=new billete(200,0)
En la linea 1 creo el array y le doy el tamaño, mientras que en las lineas de la 2 a la 5 voy creando los items y asignandoles el prototipo que he creado, y poniendole las denominaciones, tener en cuenta que el orden en las que se pondran sera como priorizara para hacer las diviciones, cabe destacar que podemos usar las denominaciones que creamos conveniete.
Ahora necitaremos de una pequeña interface para el ingreso del monto y un botoncito para empezar el cálculo
Como se aprecia, el boton tiene asociada una llamada a una funcion "Calcula" en el evento onClick, entonces definamos esa funcion:
function Calcula(){
 for(i=1;i&ltbilletes.length;i++){billetes[i].cantidad=0} 
 monto=document.getElementById("txtMonto").value
 if(Separa(monto,billetes,-1)>0){
     document.getElementById("txtResultado").value = "No es posible descomponer S/."+monto+" en billetes de S/.200, S/.100, S/.50 o S/.20"
 }else{
  cadena="Solución:"
  for(i=1;i&ltbilletes.length;i++){
   (billetes[i].cantidad>0) ? cadena += "\n  Billetes de S/."+billetes[i].denominacion+"\t: "+billetes[i].cantidad : cadena +=""
  }
  document.getElementById("txtResultado").value = cadena;
 }
}
En la linea 2 hago la limpieza de las cantidades de mi array, ya que es posible que llamemos varias veces a la funcin, y podria quedarse "pegado" algun valor de la operación anterior, luego leo la cantidad de la caja de texto y en la linea 4 evaluo si mi funcion separa me devuelve algun residuo, si es asi, pues no se podra, y si es cero recorro todos los items de mi matriz billetes y voy viendo si tienen o no cantidades, y claro voy asiganadole a la varaible "cadena" los valores convenientes, y asi se genra adecuadamente la solucion.
El resultado de todo esto se encuentra arriba.