Etapa 1 inteira (logica com 100% de cobertura, cena 3D, toque, sons, bancada de desempenho, e2e) e a base da etapa 2 (mapa novo no Tiled, texturas, imagens dos itens, sons conferidos, golpe recortado e medido). Pagina /jogo fora do menu e do sitemap ate a medicao no celular.
132 lines
4.0 KiB
TypeScript
132 lines
4.0 KiB
TypeScript
import { campoDeFluxo, direcaoNoCampo, lerMapa } from "../mapa";
|
||
import { AMBIENTES, ESCRITORIO, PORTAS } from "./escritorio";
|
||
|
||
const MAPA = lerMapa(ESCRITORIO);
|
||
const { largura, altura } = MAPA;
|
||
const andavel = (bloqueio: Uint8Array, x: number, z: number) =>
|
||
x >= 0 &&
|
||
z >= 0 &&
|
||
x < largura &&
|
||
z < altura &&
|
||
bloqueio[z * largura + x] === 0;
|
||
|
||
/** Quantas células andáveis a busca em largura alcança a partir do início. */
|
||
function alcancaveis(bloqueio: Uint8Array): number {
|
||
const inicio =
|
||
Math.floor(MAPA.inicio[1]) * largura + Math.floor(MAPA.inicio[0]);
|
||
const visto = new Uint8Array(largura * altura);
|
||
const fila = [inicio];
|
||
visto[inicio] = 1;
|
||
for (let k = 0; k < fila.length; k++) {
|
||
const x = fila[k] % largura;
|
||
const z = Math.floor(fila[k] / largura);
|
||
for (const [dx, dz] of [
|
||
[1, 0],
|
||
[-1, 0],
|
||
[0, 1],
|
||
[0, -1],
|
||
]) {
|
||
const i = (z + dz) * largura + x + dx;
|
||
if (andavel(bloqueio, x + dx, z + dz) && !visto[i]) {
|
||
visto[i] = 1;
|
||
fila.push(i);
|
||
}
|
||
}
|
||
}
|
||
return fila.length;
|
||
}
|
||
|
||
const totalAndavel = MAPA.solido.filter((c) => c === 0).length;
|
||
|
||
describe("mapa do escritório", () => {
|
||
it("tem pelo menos 40 × 28 células e é lido por lerMapa", () => {
|
||
expect(largura).toBeGreaterThanOrEqual(40);
|
||
expect(altura).toBeGreaterThanOrEqual(28);
|
||
expect(() => lerMapa(ESCRITORIO)).not.toThrow();
|
||
});
|
||
|
||
it("tem os 7 ambientes com nome", () => {
|
||
const nomes = AMBIENTES.map((a) => a.nome);
|
||
for (const nome of [
|
||
"recepção",
|
||
"área de mesas",
|
||
"sala de reunião",
|
||
"copa",
|
||
"sala do servidor",
|
||
"diretoria",
|
||
"almoxarifado",
|
||
]) {
|
||
expect(nomes).toContain(nome);
|
||
}
|
||
});
|
||
|
||
it("tem 6 ou mais nascedouros, todos a 8 m ou mais do início", () => {
|
||
expect(MAPA.nascedouros.length).toBeGreaterThanOrEqual(6);
|
||
for (const [x, z] of MAPA.nascedouros) {
|
||
expect(
|
||
Math.hypot(x - MAPA.inicio[0], z - MAPA.inicio[1]),
|
||
).toBeGreaterThanOrEqual(8);
|
||
}
|
||
});
|
||
|
||
it("alcança todo o chão a partir do início", () => {
|
||
expect(alcancaveis(MAPA.solido)).toBe(totalAndavel);
|
||
});
|
||
|
||
it("continua alcançando todo o chão sem qualquer uma das portas", () => {
|
||
expect(PORTAS.length).toBeGreaterThan(0);
|
||
for (const porta of PORTAS) {
|
||
const bloqueio = MAPA.solido.slice();
|
||
for (let z = porta.z; z < porta.z + porta.altura; z++) {
|
||
for (let x = porta.x; x < porta.x + porta.largura; x++) {
|
||
expect(andavel(bloqueio, x, z)).toBe(true);
|
||
bloqueio[z * largura + x] = 1;
|
||
}
|
||
}
|
||
expect(alcancaveis(bloqueio)).toBe(
|
||
totalAndavel - porta.largura * porta.altura,
|
||
);
|
||
}
|
||
});
|
||
|
||
it("não tem passagem com menos de 2 células: toda célula andável está num 2 × 2 andável", () => {
|
||
const livre = (x: number, z: number) => andavel(MAPA.solido, x, z);
|
||
for (let z = 0; z < altura; z++) {
|
||
for (let x = 0; x < largura; x++) {
|
||
if (!livre(x, z)) continue;
|
||
const emQuadrado = [
|
||
[-1, -1],
|
||
[-1, 0],
|
||
[0, -1],
|
||
[0, 0],
|
||
].some(
|
||
([ox, oz]) =>
|
||
livre(x + ox, z + oz) &&
|
||
livre(x + ox + 1, z + oz) &&
|
||
livre(x + ox, z + oz + 1) &&
|
||
livre(x + ox + 1, z + oz + 1),
|
||
);
|
||
expect([x, z, emQuadrado]).toEqual([x, z, true]);
|
||
}
|
||
}
|
||
});
|
||
|
||
it("o campo de fluxo leva cada nascedouro ao início em menos de 400 passos", () => {
|
||
const campo = campoDeFluxo(MAPA, MAPA.inicio[0], MAPA.inicio[1]);
|
||
const alvo = [Math.floor(MAPA.inicio[0]), Math.floor(MAPA.inicio[1])];
|
||
for (const [nx, nz] of MAPA.nascedouros) {
|
||
let x = Math.floor(nx);
|
||
let z = Math.floor(nz);
|
||
let passos = 0;
|
||
while ((x !== alvo[0] || z !== alvo[1]) && passos < 400) {
|
||
const [dx, dz] = direcaoNoCampo(MAPA, campo, x + 0.5, z + 0.5);
|
||
x += Math.round(dx);
|
||
z += Math.round(dz);
|
||
passos++;
|
||
}
|
||
expect([x, z]).toEqual(alvo);
|
||
expect(passos).toBeLessThan(400);
|
||
}
|
||
});
|
||
});
|