Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/app.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import "tailwindcss";
@plugin "@tailwindcss/typography";

@theme {
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif,
Expand Down
2 changes: 1 addition & 1 deletion app/games/Game.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export default function Game() {
});

// Game Loop
app.ticker.add(() => {
app.ticker.add((ticker) => {
Matter.Engine.update(engine, 1000 / 60);

// Sync Matter bodies to Pixi graphics
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/games/flappy-bird-js/assets/base.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/games/flappy-bird-js/assets/bird.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/games/flappy-bird-js/assets/blue-bird.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/games/flappy-bird-js/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions app/games/flappy-bird-js/componentes/Flappy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useEffect, useRef } from "react";
import { iniciar } from "../logicas/jogo";
import type { ControladorFlappy } from "../logicas/jogo";

export default function FlappyBird() {
const containerRef = useRef<HTMLDivElement>(null);
const controllerRef = useRef<ControladorFlappy | null>(null);

useEffect(() => {
// inicia o jogo quando o componente monta
controllerRef.current = iniciar(containerRef!);
return () => {
try { controllerRef.current && controllerRef.current.stop(); } catch { }
};
}, []);

function handleRestart() {
// reinicia o jogo: para e cria novamente
try { controllerRef.current && controllerRef.current.stop(); } catch { }
controllerRef.current = iniciar(containerRef!);
// reseta o contador de gerações no novo controlador, se disponível
controllerRef.current?.resetGeracao?.();
}

return (
<div className="flex mb-8 flex-col md:flex-row text-black border rounded border-black p-4 bg-white">
<div ref={containerRef} style={{ minWidth: 300, minHeight: 200 }} />
<div className="mt-3 md:mt-0 md:ml-4 flex flex-col grow">
<div>
<p className="text-md font-semibold">Distância do cano: <label id="distanciaCano" className="font-normal"></label></p>
<p className="text-md font-semibold">Altura da passagem: <label id="canoY" className="font-normal"></label></p>
<p className="text-md font-semibold">Velocidade vertical do pássaro: <label id="velocidadePassaro" className="font-normal"></label></p>
<p className="text-md font-semibold">Altura do pássaro: <label id="passaroY" className="font-normal"></label></p>
<p className="text-md font-semibold">Tempo: <label id="tempo" className="font-normal"></label></p>
<p className="text-md font-semibold">Geração: <label id="geracao" className="font-normal"></label></p>
<p className="text-md font-semibold">Pontos: <label id="pontos" className="font-bold text-green-600"></label></p>
<div className="flex flex-row justify-center">
<button onClick={handleRestart} className="cursor-pointer px-3 py-1 bg-blue-600 text-white rounded">Reiniciar</button>
</div>
</div>
</div>
</div>
);
}
37 changes: 37 additions & 0 deletions app/games/flappy-bird-js/componentes/Page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use client";
import Markdown from "marked-react";
import FlappyBird from "./Flappy";
import Lowlight from "react-lowlight";
//@ts-ignore
import typescript from 'highlight.js/lib/languages/typescript';
import 'highlight.js/styles/dark.css'
import content from "../readme.md?raw";

import logo from "../assets/logo.png"

Lowlight.registerLanguage('ts', typescript);

const renderer = {
code(snippet: string, lang: string) {
//@ts-ignore
return <Lowlight key={this.elementId} language={lang} value={snippet} markers={[]} />;
},
};

export default function Jogo() {
return (
<div className="bg-amber-50 min-h-screen py-8">
<div className="flex flex-row justify-center mb-8">
<img src={logo} alt="logo" width={300} />
</div>
<div className="flex justify-center mb-8 px-4">
<div className="w-full max-w-4xl">
<FlappyBird />
</div>
</div>
<div className="border rounded bg-white text-black mx-auto p-4 shadow prose mb-8 max-w-4xl px-4 prose-pre:bg-white">
<Markdown value={content} renderer={renderer} gfm />
</div>
</div>
);
}
25 changes: 25 additions & 0 deletions app/games/flappy-bird-js/logicas/fisica.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Matter from "matter-js";

// Módulo de física traduzido: cria engine, render e runner do Matter.js
// Exporta função que inicia o render/runner e retorna os objetos criados

const { Engine, Render, Runner } = Matter;

export function criarMotorERender(element: HTMLElement | null, largura: number, altura: number) {
if (!element) throw new Error("criarMotorERender: element é nulo");
const engine = Engine.create();
const render = Render.create({
element,
engine,
options: {
width: largura,
height: altura,
wireframes: false,
},
});
const runner = Runner.create();
// inicia render e runner
Render.run(render);
Runner.run(runner, engine);
return { engine, render, runner };
}
80 changes: 80 additions & 0 deletions app/games/flappy-bird-js/logicas/ia.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Lógica da IA: genes como bits e perceptron
// Arquivo traduzido para PT-BR com comentários explicativos

export type Genes = boolean[];

export interface EntradaRede {
distanciaCano: number;
canoY: number;
velocidadePassaro: number;
passaroY: number;
pesos: number[];
}

export const GENE_BITS = 22;
export const NUM_GENES = 4;
export const TOTAL_BITS = GENE_BITS * NUM_GENES;

// Converte 22 bits (boolean[]) para número no intervalo [-1, 1]
export function bitsParaNumero(bits: boolean[]): number {
if (bits.length !== GENE_BITS) throw new Error("bitsParaNumero: tamanho incorreto");
let val = 0;
for (let i = 0; i < GENE_BITS; i++) {
if (bits[i]) val |= (1 << (GENE_BITS - 1 - i));
}
const norm = val / ((1 << GENE_BITS) - 1);
return norm * 2 - 1;
}

// Converte número no intervalo [-1, 1] para 22 bits (boolean[])
export function numeroParaBits(num: number): boolean[] {
const clamped = Math.max(-1, Math.min(1, num));
const norm = (clamped + 1) / 2;
const val = Math.round(norm * ((1 << GENE_BITS) - 1));
const bits: boolean[] = [];
for (let i = GENE_BITS - 1; i >= 0; i--) {
bits.push(Boolean((val >> i) & 1));
}
return bits;
}

// Gera genes aleatórios (TOTAL_BITS bits)
export function criarGenesAleatorios(): Genes {
return Array.from({ length: TOTAL_BITS }, () => Math.random() < 0.5);
}

// Cruzamento/mutação bit a bit entre dois genes
export function cruzarGenes(g1: Genes, g2: Genes): Genes {
const out: Genes = [];
for (let i = 0; i < TOTAL_BITS; i++) {
const p = Math.random();
if (p < 0.45) out.push(g1[i]);
else if (p < 0.9) out.push(g2[i]);
else out.push(Math.random() < 0.5); // mutação
}
return out;
}

// Extrai os 4 pesos (números) a partir dos 88 bits
export function extrairPesos(genes: Genes): number[] {
const pesos: number[] = [];
for (let i = 0; i < NUM_GENES; i++) {
const bits = genes.slice(i * GENE_BITS, (i + 1) * GENE_BITS);
pesos.push(bitsParaNumero(bits));
}
return pesos;
}

// Calcula a decisão do perceptron a partir das entradas e dos genes
// Retorna true para pular, false caso contrário
export function calcularPuloPorGenes(distanciaCano: number, canoY: number, velocidadePassaro: number, passaroY: number, genes: Genes) {
const pesos = extrairPesos(genes);
const entradas = [distanciaCano, canoY, velocidadePassaro, passaroY];
const soma = entradas.reduce((acc, entrada, idx) => acc + entrada * pesos[idx], 0);
return soma >= 0;
}

// Cria uma população de genes (array de Genes)
export function criarPopulacaoGenes(tamanho: number): Genes[] {
return Array.from({ length: tamanho }, () => criarGenesAleatorios());
}
Loading