Implementando MonteCarlo em diferentes linguagens, para aprendizado e testes.
Last active
June 10, 2023 17:21
-
-
Save yuigoto/55285ce84a7b3640757de5d6d752db1a to your computer and use it in GitHub Desktop.
Estimando o valor de PI usando Monte Carlo, em diferentes linguagens.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package; | |
// Importando packages | |
import openfl.display.Sprite; | |
import openfl.Lib; | |
import openfl.events.Event; | |
import openfl.geom.Point; | |
import openfl.text.TextField; | |
import openfl.text.TextFieldAutoSize; | |
import openfl.text.TextFormat; | |
/** | |
* ESTIMANDO PI COM MONTECARLO : Haxe + OpenFl | |
* ============================================================ | |
* | |
* Baseado no vídeo e no sketch P5.js feitos pelo Guilherme Rey | |
* (Yarquen) em https://www.youtube.com/watch?v=VQvw3u-zSZg. | |
* | |
* Assista! É importante para entender bem o que acontece aqui! | |
* | |
* Esse é o meu take usando a linguagem de programação Haxe, | |
* junto da biblioteca OpenFL. | |
* | |
* Do compilador do Haxe, é possível exportar este projeto para: | |
* - HTML5 + JavaScript; | |
* - Flash; | |
* - C++ (Windows nativo); | |
* - Neko (Neko Virtual Machine); | |
* - Android; | |
* - Tizen; | |
* - (...); | |
* - Torradeira (desde que tenha um sistema operacional | |
* compatível ;P); | |
* | |
* @author Fabio Y. Goto <lab@yuiti.com.br> | |
*/ | |
class Main extends Sprite | |
{ | |
/** | |
* Raio da circunferência. | |
*/ | |
public var radius:Int = 500; | |
/** | |
* Quantidade de pontos dentro da circunferência. | |
*/ | |
public var n_in:Int = 0; | |
/** | |
* Número máximo de pontos permitidos. | |
*/ | |
public var n_max:Int; | |
/** | |
* Array para armazenar os pontos a serem desenhados. | |
*/ | |
public var points:Array<Point>; | |
/** | |
* Campo de texto, para exibir o valor de PI. | |
*/ | |
public var text:TextField; | |
/** | |
* Construtor. | |
*/ | |
public function new() | |
{ | |
// Super construtor | |
super(); | |
// Se stage não estiver definido... | |
if (stage == null) { | |
// ...executa `init` como event listener | |
stage.addEventListener(Event.ADDED_TO_STAGE, init); | |
} else { | |
// ...caso contrário, vai direto mesmo e dane-se | |
init(null); | |
} | |
} | |
/** | |
* Event listener inicial, faz o bootstraping de variáveis. | |
* | |
* @param e Event | |
* Event handler | |
*/ | |
public function init(e:Event):Void | |
{ | |
// Remove event listener inicial | |
stage.removeEventListener(Event.ADDED_TO_STAGE, init); | |
// Definindo quantidade de partículas | |
#if (flash) | |
// Em flash, suporta bem 10000 pontos | |
n_max = 10000; | |
#elseif (cpp) | |
// Em C++, suporte bem até 20000 pontos | |
n_max = 20000; | |
#else | |
// Nas outras plataformas, meh, 5000 pontos | |
n_max = 5000; | |
#end | |
// Inicializa o array de pontos | |
points = new Array(); | |
// Cria novo campo de texto e posiciona | |
text = new TextField(); | |
text.alpha = 0.75; | |
text.background = true; | |
text.backgroundColor = 0x000000; | |
text.defaultTextFormat = new TextFormat( | |
"_sans", | |
20, | |
0xffffff, | |
false, | |
false, | |
false | |
); | |
text.x = 10; | |
text.y = 10; | |
// Define auto resizing para o campo | |
text.autoSize = TextFieldAutoSize.LEFT; | |
// Adiciona campo de texto ao stage | |
stage.addChild(text); | |
// Define event listener de frames | |
stage.addEventListener(Event.ENTER_FRAME, update); | |
} | |
/** | |
* É executado a cada frame, atualiza o status da aplicação. | |
* | |
* @param e Event | |
* Event handler | |
*/ | |
public function update(e:Event):Void | |
{ | |
if (points.length < n_max) { | |
this.graphics.clear(); | |
drawCircle(); | |
if (points.length < n_max) { | |
for (n in 0...100) { | |
// Adiciona ponto | |
addRandomPoint(); | |
} | |
} | |
for (i in 0...points.length) { | |
if (isPointIn(points[i])) { | |
this.graphics.beginFill(0xffff00, 1); | |
} else { | |
this.graphics.beginFill(0xff0000, 1); | |
} | |
this.graphics.drawCircle(points[i].x, points[i].y, 2); | |
} | |
this.graphics.endFill(); | |
text.text = "PI: " + Std.string((4 * n_in) / points.length); | |
} | |
} | |
/** | |
* Desenha o círculo base da aplicação. | |
*/ | |
public function drawCircle():Void | |
{ | |
// Desenha o círculo | |
this.graphics.beginFill(0x009900, 1); | |
this.graphics.drawCircle(0, 0, radius); | |
this.graphics.endFill(); | |
} | |
/** | |
* Adiciona um ponto aleatório. | |
*/ | |
public function addRandomPoint():Void | |
{ | |
var _x:Float = Math.random() * radius; | |
var _y:Float = Math.random() * radius; | |
var pt:Point = new Point(_x, _y); | |
n_in += (isPointIn(pt)) ? 1 : 0; | |
points.push(pt); | |
} | |
/** | |
* Verifica se o ponto está dentro, ou não, da circunferência, retornando | |
* um boolean. | |
* | |
* @param pt Point | |
* Ponto a ser verificado | |
* @return Bool | |
*/ | |
public function isPointIn(pt:Point):Bool | |
{ | |
var square_x:Float = Math.pow(pt.x, 2); | |
var square_y:Float = Math.pow(pt.y, 2); | |
return (Math.sqrt(square_x + square_y) <= radius); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
estimando pi com monte carlo | |
versao lua (pico8) | |
baseado no video e no sketch | |
de p5.js feitos pelo guilherme | |
rey em: | |
https://youtu.be/vqvw3u-zszg | |
assista! e importante para | |
entender o funcionamento. | |
esse e o meu take miniatura | |
feito em lua para o fantasy | |
console pico8. | |
super compacto, mas funciona! | |
author: fabio y. goto | |
mail: lab@yuiti.com.br | |
]]-- | |
--[[ | |
funcao da api do pico8. | |
inicializa os dados do | |
cartucho. | |
]]-- | |
function _init() | |
-- points inside | |
n_in = 0; | |
-- maximum points | |
n_mx = 5000; | |
-- radius | |
rads = 128; | |
-- point array | |
pnts = {}; | |
add_pt(); | |
end | |
--[[ | |
funcao da api do pico8. | |
atualiza a cada frame. | |
]]-- | |
function _draw() | |
-- limpa a tela | |
cls(0); | |
-- desenha circulo base | |
circfill(0, 0, rads, 6); | |
-- cria os pontos | |
if count(pnts) < n_mx then | |
add_pt(); | |
end | |
-- desenha os pontos | |
for i=1, count(pnts) do | |
if is_in(pnts[i]) then | |
circfill( | |
pnts[i].x, | |
pnts[i].y, | |
2, | |
7 | |
); | |
else | |
circfill( | |
pnts[i].x, | |
pnts[i].y, | |
2, | |
10 | |
); | |
end | |
end | |
-- desenha o texto | |
color(0); | |
pi_val = (4*n_in)/count(pnts); | |
print("pi: "..pi_val, 2, 2); | |
end | |
--[[ | |
adiciona um ponto aleatorio | |
ao array 'pnts' | |
]]-- | |
function add_pt() | |
pt = {}; | |
pt["x"] = rnd(rads); | |
pt["y"] = rnd(rads); | |
--[[ | |
se estiver na | |
circunferencia | |
incrementa n_in | |
]]-- | |
if is_in(pt) then | |
n_in += 1; | |
end | |
-- adiciona ao table | |
add(pnts,pt); | |
end | |
--[[ | |
verifica se um ponto esta | |
dentro da circunferencia | |
ou nao. | |
]]-- | |
function is_in(point) | |
_x = point.x ^ 2; | |
_y = point.y ^ 2; | |
_s = sqrt(_x + _y); | |
return _s <= rads; | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ESTIMANDO PI COM MONTECARLO | |
* ============================================================ | |
* | |
* Baseado no vídeo e no sketch P5.js feitos pelo Guilherme Rey | |
* (Yarquen) em https://www.youtube.com/watch?v=VQvw3u-zSZg. | |
* | |
* Assista! É importante para entender bem o que acontece aqui! | |
* | |
* Apesar do P5.js ser uma versão do processing, pelo fato de | |
* ser em JavaScript, algumas coisas funcionam um pouco diferente. | |
* | |
* Este é o meu take de como estimar o valor de PI, de acordo com | |
* o vídeo. Tem algumas peculiaridades do Processing que tentei | |
* explicar, mas podem estar meio mal escritas, portanto: RTFM! :P | |
* | |
* @author Fabio Y. Goto <lab@yuiti.com.br> | |
*/ | |
// GLOBAIS | |
// ============================================================ | |
/** | |
* Raio da circunferência. | |
*/ | |
int r = 500; | |
/** | |
* Total de pontos dentro da circunferência. | |
*/ | |
int n_in = 0; | |
/** | |
* Máximo de pontos a serem criados. | |
*/ | |
int n_max = 50000; | |
/** | |
* Framerate do sketch, diminua isso e a quantidade de pontos se | |
* tiver problemas de performance. | |
*/ | |
int fps = 60; | |
/** | |
* Array para armazenar pontos. | |
*/ | |
Point[] points; | |
// CLASSES | |
// ============================================================ | |
/** | |
* Um objeto de ponto. | |
* | |
* Possui apenas três atributos: x, y e is_in, que indica se | |
* o ponto está dentro, ou não, da circunferência. | |
*/ | |
class Point { | |
float x; | |
float y; | |
boolean is_in; | |
/** | |
* Construtor da classe. | |
* | |
* @var {float} x | |
* @var {float} y | |
*/ | |
Point(float x, float y) { | |
this.x = x; | |
this.y = y; | |
} | |
} | |
// FUNÇÕES AUXILIARES | |
// ============================================================ | |
/** | |
* Adiciona um ponto ao array. | |
*/ | |
void addPoint() { | |
Point coord = getRandomPoint(); | |
boolean is_in = isPointIn(coord); | |
n_in += (is_in) ? 1 : 0; | |
coord.is_in = is_in; | |
// Para adicionar itens ao array no Procesing, você precisa | |
// usar append e, ainda, indicar o tipo de dado. | |
points = (Point[]) append(points, coord); | |
} | |
/** | |
* Desenha a elipse utilizada no vídeo. | |
*/ | |
void drawEllipse() { | |
fill(#009900); | |
noStroke(); | |
ellipse(0, 0, r * 2, r * 2); | |
} | |
/** | |
* Retorna um novo ponto, com uma posição (pseudo-)aleatória. | |
* | |
* @return {Point} | |
*/ | |
Point getRandomPoint() { | |
float _x = random(0, r); | |
float _y = random(0, r); | |
return new Point(_x, _y); | |
} | |
/** | |
* Verifica se um ponto está dentro, ou fora, da circunferência. | |
* | |
* @var {Point} pt | |
* @return {boolean} | |
*/ | |
boolean isPointIn(Point pt) { | |
float square_x = pow(pt.x, 2); | |
float square_y = pow(pt.y, 2); | |
// Hipotenusa é menor ou igual ao raio? | |
return (sqrt(square_x + square_y) <= r); | |
} | |
// EXECUÇÃO | |
// ============================================================ | |
/** | |
* Setup do Processing. | |
*/ | |
void setup() { | |
/** | |
* Definimos o tamanho do canvas aqui, usando o P2D como | |
* renderer, embora seu uso seja opcional, visto que é | |
* o renderer padrão. | |
*/ | |
size(500, 500, P2D); | |
// Define framerate | |
frameRate(fps); | |
// Cria o array (importante fazer isso aqui!) | |
// O "0" é pra criar um array vazio, PRECISA ser declarado! | |
points = new Point[0]; | |
} | |
/** | |
* Update + Desenha. | |
*/ | |
void draw() { | |
// Define fundo + desenha elipse | |
background(0); | |
drawEllipse(); | |
// Vamos adicionar pontos ao array, enquanto possível | |
if (points.length < n_max) { | |
for (int a = 0; a < 100; a++) { | |
addPoint(); | |
} | |
} | |
// Adicionou o ponto? Ótimo, vamos desenhar e tirar estimativa! | |
strokeWeight(3); | |
// Vamos apenas desenhar e testar se length > 0 | |
for (int i = 0; i < points.length; i++) { | |
if (points[i].is_in) { | |
// Tá dentro? | |
stroke(255, 255, 0); | |
} else { | |
// Ou tá fora? | |
stroke(255, 0, 0); | |
} | |
point(points[i].x, points[i].y); | |
} | |
/** | |
* Note que, antes de dividir o valor pelo comprimento do array, | |
* multiplicamos o comprimento por "1.0". | |
* | |
* O motivo? É simples, se você simplesmente dividir (4 * n_in) | |
* pelo valor do comprimento do array, ele "arredonda" o resultado | |
* final para baixo (fica 3.0), visto que points.length é um int. | |
* | |
* Coisa do Processing. :P | |
*/ | |
float pi_value = (4 * n_in) / (points.length * 1.0); | |
println(pi_value); | |
// Desenhando o texto na tela com COMIC SANS, pois TODOS GOSTAM | |
PFont font = createFont("Comic Sans MS", 40, true); | |
textFont(font, 40); | |
fill(0); | |
int text_x = 30; | |
int text_y = 60; | |
// Desenhando uma borda para o texto, já que strokeWidth não funciona. | |
// Deve haver meios melhores que este. :P | |
for (int yy = -2; yy <= 2; yy++) { | |
for (int xx = -2; xx <= 2; xx++) { | |
text("PI: " + pi_value, text_x + xx, text_y + yy); | |
} | |
} | |
fill(0, 255, 255); | |
text("PI: " + pi_value, text_x, text_y); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment