En las últimas semanas me ha costado bastante trabajo darme tiempo para escribir porque recién acabo de mudarme, pero espero a partir de ahora poder retomar el ritmo.
La tercera parte de programación dinámica + máscaras de bits tendrá que esperar, ya que es algo bastante pesado de escribir y quiero tomarme un descanso abordando un tema más ligero y con el que he estado trabajando mucho recientemente, así que lo tengo fresco: el patrón "estrategia".
Supongamos que queremos hacer un programa que reciba una lista de instrucciones y ejecute cada una de ellas. Cada instrucción estaría dada por un objeto en formato json, habría un campo llamado `type` especificando el tipo de instrucción y el resto de los campos dependerían del tipo.
Una posible implementación de esto sería creando un método público que reciba el objeto, y varios métodos privados para cada tipo de accion:
interface Action {
type : string;
}
const DIRECTIONS : ReadonlyArray<{x : number, y : number}> = [
{x : 1, y : 0},
{x : 0, y : 1},
{x : -1, y : 0},
{x : 0, y : -1}
];
class Karel {
position = { x : 0, y : 0};
direction = 0;
beepers_in_bag = 100;
beepers_in_world = new Map>();
performAction(action : Interface) : void {
switch(action) {
case 'putBeeper':
return this.putBeeper();
case 'pickBeeper':
return this.pickBeeper();
case 'turnLeft':
return this.turnLeft();
case 'move':
return this.move();
default:
console.error("Unknown command: ", action.type);
}
if (action === 'putBeeper') {
this.putBeeper();
}
}
private turnLeft() : void {
this.direction = (this.direction + 1) % 4;
}
private move() : void {
this.position = {
x : this.position.x + DIRECTIONS[this.direction].x,
y : this.position.y + DIRECTIONS[this.direction].y
};
}
private putBeeper() : void {
if (this.beepers_in_bag === 0) {
return;
}
this.beepers_in_bag--;
let map_x = this.beepers_in_world.get(this.position.x);
if (!map_x) {
this.beepers_in_world.set(this.position.x, new Map());
}
map_x = this.beepers_in_world.get(this.position.x);
map_x.set(this.position.y, map_x.get(this.position.x ?? 0 + 1);
}
private pickBeeper() : void {
const beepers_in_position = this.beepers_in_world.get(this.position.x)?.get(this.position.y);
if (!beepers_in_position) {
return;
}
this.beepers_in_world.get(this.position.x).set(this.position.y, beepers_in_position - 1);
this.beepers_in_bag++;
}
}
Para algo tan simple podría parecer que esta es una solución decente, pero ahora vamos a imaginar que además de las instrucciones 'putBeeper', 'pickBeeper', 'turnLeft' y 'move', se agregan 20 instrucciones más.// KarelTypes.ts
export interface KarelAction {
type : string;
}
export interface KarelContext {
position : { x : number, y : number};
direction : number;
beepers_in_bag : number;
beepers_in_world : Map>;
}
export interface KarelActionHandler {
type : string;
performAction(context : KarelContext, action: KarelAction);
}
// Karel.ts
const ACTION_HANDLERS = new Map;
export function addKarelActionHandlers(handlers : KarelActionHandlers[]) {
for (const h of handlers) {
ACTION_HANDLERS.set(h.type, h);
}
}
export class Karel {
constructor(public context : KarelContext) {}
performAction(action : Interface) : void {
const handler = ACTION_HANDLERS.get(action.type);
if (!handler) {
console.error("Unknown action:", action.type);
return;
}
handler.performAction(this.context, action);
}
}
// turnLeft.ts
export class TurnLeftHandler implements KarelActionHandler {
type = "turnLeft";
performAction(context : KarelContext/*, action: KarelAction*/) {
context.direction = (context.direction + 1) % 4;
}
}
No puse los otros handlers porque creo que con uno es suficiente para entender la idea.
No hay comentarios.:
Publicar un comentario