4 dezembro, 2015 0 Comentários AUTOR: elemarjr CATEGORIAS: Sem categoria Tags:

Um brinde a expressividade do TypeScript!

Tempo de leitura: 2 minutos

Estou compartilhando, todos os dias, uma "brincadeira" com TypeScript. A última foi uma breve implementação do sistema de Lindenmayer.

An L-system or Lindenmayer system is a parallel rewriting system and a type of formal grammar. An L-system consists of an alphabet of symbols that can be used to make strings, a collection of production rules that expand each symbol into some larger string of symbols, an initial "axiom" string from which to begin construction, and a mechanism for translating the generated strings into geometric structures.

Eis a imagem gerada pelo meu exemplo:

2015-12-04

A especificação tinha os seguintes elementos:

  • Axioma (ou símbolo de início): F
  • Regra: F -> F+F-F-F+F
  • Onde:
    • F indica deslocamento para frente
    • - Indica rotação 90 graus
    • + Indica rotação em -90 graus

Partindo do axioma, transformo a string em iterações substituindo o símbolo mapeado na regra pelo valor relacionado.

A primeira iteração transformaria o nosso "F" em "F+F-F-F+F". A segunda em "F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F" e assim por diante. Depois de um conjunto de iterações, varro o string e executo o comando representado por cada caractere.

Onde TypeScript vem para me ajudar

A primeira coisa que gostaria de garantir é que eu tivesse uma "forma" para a minha especificação. Eis o que criei com TypeScript

interface ILSystemSpec {
    start: string;
    rules : { [symbol: string]: string };
    commands: { [symbol: string] : (turtle: Turtle) => void }
}

O que quero dizer aqui é que meu objeto precisará ter um símbolo de entrada e dois dicionários: rules e commands. Ambos com chave string. O segundo com valores do tipo "função" que recebem um objeto Turtle (minha mini implementação de logo) e devolvem void.

O que mais gosto dessa interface é que antecipo "objetos" mal formados para a edição do meu código.

Implementando o L-System (com benefício da interface)

Tendo um "contrato" de como a especificação do sistema deve funcionar, parto para a implementação.

class LSystem {
    private status: string;

    constructor(
        private turtle: Turtle,
        private spec: ILSystemSpec
    ) {
        this.status = spec.start;
    }

    public iterate() {
        var newStatus = "";
        for (var i = 0; i < this.status.length; i++)
        {
            var c = this.status.charAt(i);
            if (this.spec.rules&#91;c&#93; != undefined) {
                newStatus += this.spec.rules&#91;c&#93;;
            } else {
                newStatus += c
            }
        }
        this.status = newStatus;
    }

    public draw() {
        for (var i = 0; i < this.status.length; i++)
        {
            var c = this.status.charAt(i);
            if (this.spec.commands&#91;c&#93; != undefined) {
                this.spec.commands&#91;c&#93;(this.turtle);
            }
        }
    }
}
&#91;/code&#93;

Nada demais. A função iterate varre minha string, gerando um novo estado substituindo os caracteres por novas cadeias. A função draw, percorre os caracteres executando o comando relacionado.
<h3>Definindo a regra (com benefício da interface)</h3>
Já temos a classe que suporta L-System. Agora, é implementar o seu uso:


class App {
    private engine: RenderingEngine;
    private turtle: Turtle;
    private lsystem: LSystem;

    public init() {
        var canvas = <HTMLCanvasElement> document.getElementById('target');
        this.engine = new RenderingEngine(canvas);
        this.turtle = new Turtle(this.engine);

        var spec: ILSystemSpec = {
            start: "F",
            rules: {
                "F": "F+F-F-F+F"
            },
            commands: {
                "F": (t) => t.forward(4),
                "-": (t) => t.right(90),
                "+": (t) => t.left(90),
            }
        }

        this.lsystem = new LSystem(this.turtle, spec)

        return this;
    }

    public run() {
        this.turtle.setCursor(40, 75);
        this.lsystem.iterate();
        this.lsystem.iterate();
        this.lsystem.iterate();
        this.lsystem.iterate();
        this.lsystem.draw();
    }
}

Você não pode perceber aqui. Mas, tenho a IDE completando meu código e indicando o que está faltando.

Quem disse que tipos não são legais?! Um brinde a TypeScript!

Enviar um comentário