El siguiente es un ejercicio para codificar, refactorizar y hacer pruebas, en el cual puedes invertir de 15 a 30 minutos para resolverlo gradualmente.
- Intenta no adelantar la lectura.
- Realiza una tarea a la vez. El truco para aprender es el trabajo incremental.
- Asegurate de hacer las pruebas para las entradas correctas. No hay necesidad de probar entradas inválidas.
- De vez en cuando haz un refactor de tu código.
Vamos a resolver un problema que muy probablemente ya tiene una solución, y una muy buena (¿qué kata no la tiene?), sin embargo, el propósito es conocer y explorar alternativas en el diseño del algoritmo que despacha los billetes en un ATM.
El propósito final en el diseño de la solución es optimizar la forma en que se pueden atender la mayor cantidad de solicitantes posibles con un flujo de efectivo inicial cargado en el ATM.
Inicia un ATM con suficiente flujo de efectivo(billetes de una sola denominación) y con un método/función de la forma Collection{int denomination: int quantity} withdraw_cash(int amount)
. El ATM debería de poder despachar casos simples como los siguientes:
- Por ejemplo:
ATM([200: 10])
, significa que el cajero cuenta con $ 2,000 (en efectivo), y cuando llamamoswithdraw_cash(800)
entonces deberíamos de obtener algo como{200 => 4}
ó[200: 4]
(dependiendo el lenguaje). - Otro caso sería:
ATM([100: 1000])
, significa que el cajero cuenta con $ 100,000 (en efectivo), y cuando llamamoswithdraw_cash(4700)
entonces deberíamos de obtener algo como{100 => 47}
ó[100: 47]
.
Iniciar un ATM con suficiente flujo de efectivo, pero en esta ocasión usa dos denominaciones. Deberías de considerar ahora lo siguiente:
- Un nuevo
ATM([100: 10, 200: 10])
, quiere decir que el cajero cuenta con $3,000, y si llamaswithdraw_cash(800)
entonces deberías de obtener{200 => 4}
, llamandowithdraw_cash(900)
entonces obtendrías{200 => 4, 100 => 1}
. - Otro caso sería:
ATM([200: 300, 500: 100])
, quiere decir que el cajero cuenta con $110,000, y si llamaswithdraw_cash(4200)
entonces deberías de obtener{200 => 1, 500 => 8}
; llamandowithdraw_cash(3800)
entonces obtendrías{200 => 4, 500 => 6}
.
- Un nuevo
ATM([100: 10, 200: 10])
, quiere decir que el cajero cuenta con $3,000, y si llamaswithdraw_cash(2400)
entonces deberías de obtener{200 => 10, 100 => 4}
, llamandowithdraw_cash(2600)
entonces obtendrías{200 => 10, 100 => 6}
.
Iniciar un ATM con cierto flujo de efectivo, tal que la solicitud sobrepase lo que contiene, envíe un error indicando "ATM con fondos insuficientes".
- Un ejemplo es
ATM([100: 10, 200: 10])
, quiere decir que el cajero cuenta con $3,000, y llamandowithdraw_cash(3100)
deberíamos de obtener un error.
Iniciar un cajero con efectivo suficiente, sin embargo, las denominaciones contenidas no pueden despachar la cantidad requerida, es decir, no es que el cajero no tenga los fondos, más bien, no es capaz de atender la combinación de billetes, y por lo tanto, debe de enviar un mensaje indicando que denominaciones tiene para poder retirar.
- Un 'ATM(200: 10)' tiene $2,000 en efectivo, y al llamar
withdraw_cash(700)
debe de enviar un error indicando: "No puedo atender tu solicitud, sólo cuento con denominaciones de $200" - Un 'ATM(500: 300)' tiene 150,000 en efectivo, y al llamar
withdraw_cash(4700)
debe de enviar un error indicando: "No puedo atender tu solicitud, sólo cuento con denominaciones de $500"
- Un 'ATM(500: 300, 200:2)' tiene 150,400 en efectivo, y al llamar
withdraw_cash(4600)
debe de enviar un error indicando: "No puedo atender tu solicitud, sólo cuento con denominaciones de $500, $200"
Iniciar un cajero con efectivo suficiente, llamar múltiples veces a withdraw_cash(_)
; al final corroborar que la cantidad de billetes en el ATM ha disminuido. Para esto se puede exponer una función/método adicional get_current_state
que exponga el estado interno del ATM.
-
Por ejemplo:
ATM([200: 30, 500: 10])
, contamos inicialmente con $11,000, haciendo las siguientes llamadas:withdraw_cash(700)
, entrega 1 billete de $500 y 1 de $200withdraw_cash(3000)
, entrega 6 billetes de $500withdraw_cash(1400)
, entrega 2 billetes de $500 y 2 de $200get_current_state
, debería de indicar algo como:{200 => 27, 500 => 1}
-
Otro caso sería:
ATM([200: 30, 500: 10])
, cuenta con $11,000, y haciendo las siguientes llamadas:withdraw_cash(6000)
, entrega 10 billete de $500 y 5 de $200withdraw_cash(3000)
, entrega 15 billetes de $200withdraw_cash(1400)
, entrega 7 billetes de $200get_current_state
, debería de indicar algo como:{200 => 3, 500 => 0}