/** * @fileoverview Blocos, geradores e toolbox do jogo Padrões. * * Blocos customizados expõem: leitura da ENTRADA, definição/leitura de * SAÍDA, CONTADOR e LETRA, a constante ALFABETO A-Z e as operações de * string text_charAt / text_indexOf (0-based, alinhadas ao cripto). * * @module games.padroes.blocks.blocks */ "use strict"; import * as Blockly from "blockly/core"; import "blockly/blocks"; import { javascriptGenerator } from "blockly/javascript"; import { CORES_BLOCKLY } from "@/blockly/blocklyColors"; import { configurarGerador, gerarExpressao, gerarStatementComValor, } from "@/blockly/generator"; import { gerarToolboxDeEstrutura } from "@/blockly/toolbox"; import { criarBlocoExpressaoSimples, criarBlocoStatementComValor, } from "@/blockly/blockFactory"; const C = CORES_BLOCKLY; // LOGICA:210, LOOPS:120, MATEMATICA:230, TEXTO:160, VARIAVEIS:330 // Estrutura declarativa da toolbox (cada categoria filtra por allowedBlocks). const ESTRUTURA_TOOLBOX = [ { nome: "Entrada/Saída", blocos: ["obter_entrada", "definir_saida", "obter_saida"], }, { nome: "Variáveis", blocos: [ "definir_contador", "obter_contador", "definir_letra", "obter_letra", ], }, { nome: "Repetição", blocos: ["controls_whileUntil"] }, { nome: "Lógica", blocos: ["controls_if", "logic_compare", "logic_operation"], }, { nome: "Texto", blocos: ["text", "text_charAt", "text_indexOf", "text_length", "alfabeto"], }, { nome: "Matemática", blocos: ["math_number", "math_arithmetic"] }, ]; /** * Registra todos os blocos e geradores do jogo Padrões no Blockly. * Deve ser chamado uma vez na montagem do componente. * @returns {void} */ export const registerBlocks = () => { defineBlocks(); defineGenerators(); }; /** * Gera a toolbox contendo apenas os blocos permitidos pela fase. * @param {Array} [allowedBlocks=[]] - Lista de blocos habilitados * @returns {Object} Estrutura `categoryToolbox` para o Blockly */ export const generateDynamicToolbox = (allowedBlocks = []) => { return gerarToolboxDeEstrutura(ESTRUTURA_TOOLBOX, allowedBlocks); }; // ===================== Definições de blocos ===================== const defineBlocks = () => { // Entrada (somente leitura — é pré-definida pela fase) criarBlocoExpressaoSimples( "obter_entrada", "ENTRADA", null, C.VARIAVEIS, "O texto que a fase quer analisar", ); // Saída criarBlocoStatementComValor( "definir_saida", "definir SAÍDA como", "VALUE", null, C.VARIAVEIS, ); criarBlocoExpressaoSimples( "obter_saida", "SAÍDA", null, C.VARIAVEIS, "O veredito atual", ); // Contador (índice do loop) criarBlocoStatementComValor( "definir_contador", "definir CONTADOR como", "VALUE", null, C.LOOPS, ); criarBlocoExpressaoSimples( "obter_contador", "CONTADOR", null, C.LOOPS, "Valor atual do contador", ); // Letra (caractere atual) criarBlocoStatementComValor( "definir_letra", "definir LETRA como", "VALUE", null, C.VARIAVEIS, ); criarBlocoExpressaoSimples( "obter_letra", "LETRA", null, C.VARIAVEIS, "Valor atual da letra", ); // Constante: alfabeto A-Z criarBlocoExpressaoSimples( "alfabeto", "ALFABETO A-Z", "String", C.TEXTO, "Retorna ABCDEFGHIJKLMNOPQRSTUVWXYZ", ); // text_charAt — 0-based (sobrescreve o nativo para alinhar com CONTADOR=0) Blockly.Blocks["text_charAt"] = { init: function () { this.setColour(C.TEXTO); this.setOutput(true, "String"); this.appendValueInput("VALUE") .setCheck("String") .appendField("no texto"); this.appendValueInput("AT") .setCheck("Number") .appendField("obter letra nº"); this.setInputsInline(true); this.setTooltip("Letra na posição informada (0 = primeira)."); }, }; // text_indexOf — 0-based (retorna -1 quando não encontra) Blockly.Blocks["text_indexOf"] = { init: function () { this.setColour(C.TEXTO); this.setOutput(true, "Number"); this.appendValueInput("VALUE") .setCheck("String") .appendField("no texto"); this.appendValueInput("FIND") .setCheck("String") .appendField("buscar a posição de"); this.setInputsInline(true); this.setTooltip( "Primeira posição (0-based) do trecho, ou -1 se não existir.", ); }, }; }; // ===================== Geradores de código ===================== const defineGenerators = () => { // Prefix de highlight (faz o bloco piscar na execução passo a passo) configurarGerador(); // Statements com valor gerarStatementComValor("definir_saida", "VALUE", (v) => `definirSaida(${v})`); gerarStatementComValor("definir_contador", "VALUE", (v) => `definirContador(${v})`, ); gerarStatementComValor("definir_letra", "VALUE", (v) => `var letra = ${v}`); // Expressões gerarExpressao( "obter_entrada", "obterEntrada()", javascriptGenerator.ORDER_FUNCTION_CALL, ); gerarExpressao( "obter_saida", "obterSaida()", javascriptGenerator.ORDER_FUNCTION_CALL, ); gerarExpressao( "obter_contador", "obterContador()", javascriptGenerator.ORDER_FUNCTION_CALL, ); gerarExpressao("obter_letra", "letra", javascriptGenerator.ORDER_ATOMIC); gerarExpressao( "alfabeto", '"ABCDEFGHIJKLMNOPQRSTUVWXYZ"', javascriptGenerator.ORDER_ATOMIC, ); // text_charAt — 0-based javascriptGenerator.forBlock["text_charAt"] = function (block) { const text = javascriptGenerator.valueToCode( block, "VALUE", javascriptGenerator.ORDER_MEMBER, ) || "''"; const at = javascriptGenerator.valueToCode( block, "AT", javascriptGenerator.ORDER_NONE, ) || "0"; return [`${text}.charAt(${at})`, javascriptGenerator.ORDER_MEMBER]; }; // text_indexOf — 0-based javascriptGenerator.forBlock["text_indexOf"] = function (block) { const text = javascriptGenerator.valueToCode( block, "VALUE", javascriptGenerator.ORDER_MEMBER, ) || "''"; const search = javascriptGenerator.valueToCode( block, "FIND", javascriptGenerator.ORDER_NONE, ) || "''"; return [`${text}.indexOf(${search})`, javascriptGenerator.ORDER_MEMBER]; }; };