/**
* Copyright Thy ( http://wonderfl.net/user/Thy )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/kxAB
*/
package
{
/**
* Jantar dos filósofos.
* @author Marcelo Bosso, thi
* Obrigado ao Juliano de Almeida Monte-Mor, na matéria de SO, na Unifei campus Itabira.
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* git https://github.com/thyfl/flash/tree/master/Jantar%20dos%20filosofos
*
* O problema
* Alguns filósofos se juntam para um brainstorm na janta, cada um leva um talher.
* Eles não conseguem pensar enquanto comem, e terão de disputar pelos talheres à sua volta!
* A comida no prato nunca acaba.
*
* Instruções
* No campo de input no topo esquerdo, é inserido a quantidade de filósofos.
* Os círculos representam os filósofos.
* Quando um círculo está com um símbolo de uma lâmpada, este filósofo está pensando.
* Quando não tem símbolo nenhum, o filósofo está com fome, e não pensa.
* Os talheres representam os recursos.
*
* Compilar
* Este programa foi feito em AS3 no FlashDevelop, compilado pelo FlexSDK 4.6.0, e não utiliza recursos externos.
*
* TODO
* Rever a questão da lista de espera
* Quando liberar que um filósofo volte a pensar. Logo depois de comer ou soltar os garfos?
* Fazer o gráfico de 'quantas idéias' estão sendo produzidas ao longo tempo?
*
* Divirta-se!
*
*/
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
public class Main extends Sprite
{
public var
tgarfo:Number = 5, // tempo para pegar, desistir e devolver o garfo TODO testar isso
fps:Number = 40;
public function Main():void
{
// setup
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.frameRate = fps;
// display
this.addChild(mesa);
this.addChild(text); // input
this.addChild(tminp);
this.addChild(tmaxp);
this.addChild(tminc);
this.addChild(tmaxc);
// event
this.addEventListener(Event.ENTER_FRAME, ef);
stage.addEventListener(Event.RESIZE, resize);
// var
ss[0] = text.tf.text;
ss[1] = tminp.tf.text;
ss[2] = tmaxp.tf.text;
ss[3] = tminc.tf.text;
ss[4] = tmaxc.tf.text;
// init
resize();
init(); // filósofos e garfos.
// text
stage.focus = text.tf;
text.tf.setSelection(0, text.tf.text.length);
text.x = text.y = 0;
//tminp.y = tmaxp.y = 25
//tminc.y = tmaxc.y = 50;
}
private var
mesa:Sprite = new Sprite(),
filosofos:Array = new Array(),
lf:int = 0, // filosofos length
lr:int = 0, // filósofos pedindo recursos
garfos:Array = new Array(),
//
ss:Array = ["", "", "", "", ""],
text:Field = new Field("quantidade de filósofos:", "10"), // input text
tminp:Field = new Field("min para pensar:", "3"), // input text
tmaxp:Field = new Field("max para pensar:", "10"), // input text
tminc:Field = new Field("min para comer:", "2"), // input text
tmaxc:Field = new Field("max para comer:", "8"), // input text
//
W:Number = 0,
H:Number = 0;
private function resize(e:Event = null):void
{
// dimensão
W = stage.stageWidth;
H = stage.stageHeight;
text.resize(); // tamanho
mesa.x = W / 2; // pos
mesa.y = H / 2 + 10;
zoom();
}
private function zoom():void
{
var r:Number = 14 * lf / 4 * Math.PI;
var zoom:Number = Math.min(W, H - 28) / (2 * r + 35);
mesa.scaleX = mesa.scaleY = zoom;
}
private function init():void {
var S:String = ".", ic:int = -1, c:String,
i:int, j:int = -1, f:Filosofo, g:Garfo;
i = -1;
while (++i < filosofos.length) {
if (filosofos[i].parent) {
mesa.removeChild(filosofos[i]);
mesa.removeChild(garfos[i]);
}
}
var s2:String = "", s3:String, n:int = Number(ss[0]);
n = n != n ? 2 : n < 2 ? 2 : n;
i = -1;
while (++i < ss.length) ss[i] = isNaN(Number(ss[i])) ? "1" : Number(ss[i]) < 1 ? "1" : ss[i];
i = -1;
var dp:int = Number(ss[2]) - Number(ss[1]);
var dc:int = Number(ss[4]) - Number(ss[3]);
dp = dp < 0 ? 0 : dp;
dc = dc < 0 ? 0 : dc;
while (++i < n) {
s2 += int(Math.random() * dp + Number(ss[1])) + " " + int(Math.random() * dc + Number(ss[3])) + ", ";
}
//trace(s2)
s3 = s;
var s:String = s2;
i = -1;
while (S) {
// pega o próximo número do input
S = "";
while (++ic < s.length) {
c = s.charAt(ic);
if (!Number(c) && c != "0") {
if (S.length > 0) break; else continue;
}
S += c;
}
switch(++i % 2) {
case 0: // primeiro input, tempo que fica pensando
if (filosofos.length <= ++j) {
filosofos.push(new Filosofo()); // cria novo filósofo
garfos.push(new Garfo( ));
}
f = filosofos[j];
f.tpensa = Number(S); // tempo que fica pensando
break;
case 1: // segundo input, tempo que fica comendo
f.tcome = Number(S);
break;
}
}
lf = j; // quantidade de filósofos. A lista em sí pode ser maior, objeto de filósfos que não são mais utilizados.
lr = 0;
s = s3;
i = -1;
while (++i < lf) {
f = filosofos[i]; // Recicla objetos
g = garfos[i];
f.pensa = f.tpensa;
f.come = NaN;
f.pensando = true;
f.comendo = false;
g.movendo = false;
g.dono = -1;
g.at = g.ai = g.ast = g.ara = g.aro = NaN;
// desenho
var r:Number = 14 * lf / 4 * Math.PI; // TODO generalizar este cálculo
f.x = r * Math.cos(i * 2 * Math.PI / lf);
f.y = -r * Math.sin(i * 2 * Math.PI / lf);
g.x = r * Math.cos((i * 2 + 1) * Math.PI / lf);
g.y = -r * Math.sin((i * 2 + 1) * Math.PI / lf);
g.rotation = - (i * 2 + 1) * 180 / lf + 90;
f.draw();
g.draw(i % 2 == 1);
mesa.addChild(f);
zoom();
}
i = -1;
while (++i < lf) mesa.addChild(garfos[i]);
}
private function ef(e:Event):void
{
// recalcular input para filósofos (e garfos)
text.resize();
tminp.x = text.x + text.width + 20;
tmaxp.x = tminp.x + tminp.width + 10;
tminc.x = tmaxp.x + tmaxp.width + 20;
tmaxc.x = tminc.x + tminc.width + 10;
var textos:Array = [text, tminp, tmaxp, tminc, tmaxc];
var k = -1;
while (++k < textos.length) {
var field:Field = textos[k];
if (ss[k] != field.tf.text && ++field.time > field.timeOut) {
var m:int = -1;
while (++m < ss.length) {
textos[m].time = 0;
ss[m] = textos[m].tf.text;
if (ss[m] == "") ss[m] = "1";
}
init();
break;
}
}
var f:Filosofo, g:Garfo, i:int = -1;
while (++i < lf) {
f = filosofos[i];
g = garfos[i];
// garfo
if (g.movendo && --g.at >= 0) {
var r:Number = 14 * lf / 4 * Math.PI;
g.x = r * Math.cos(((g.ai += g.ast) * 2) * Math.PI / lf);
g.y = -r * Math.sin((g.ai * 2) * Math.PI / lf);
if (g.at <= 0) {
g.movendo = false;
}
}
// a) se está pensando
// 1) passar o tempo
// b) se não está pensando
// b.1) se está comendo
// 1) se está satisfeito, mandar os dois recursos de volta bs juntos. TODO: juntos ou de uma vez?
// 2) esperar chegarem bs, setar que está pensando.
// b.2) se está procurando recursos
// 1) nenhum recurso
// 1.1) verifica disponibilidade global de comedores, verifica recurso livre (descartar os indo bs), muda var global e começa a pegar um.
// 2) um recurso
// 2.1) se um recurso estiver vindo, esperar ele chegar.
// 2.1.1) verifica recurso livre ou indo bs.
// 2.1.1.1) se estiver recurso indo bs, esperar.
// 2.1.1.2) se já estiver bs, começar a pegar ele.
// 2.1.2) se não tiver recurso livre, devolver o que já estava.
// 3) dois recursos
// 3.1) se um recurso estiver vindo, esperar ele chegar. setar que está comendo.
// a) se está pensando
if (f.pensando) {
// a.1) passar o tempo
if ((f.pensa -= 1.5 / fps) <= 0) {
f.pensando = false;
f.pensa = -1; // TODO verificar se precisarei fazer isso
f.come = 0; // quando fome chegar ao máximo, acabou a fome.
f.draw();
}
}
// b) se não está pensando
else {
var g1:Garfo = garfos[(i + lf - 1) % lf], g2:Garfo = garfos[(i + lf ) % lf]; //garfos que se relacionam com este filósofo.
// b.1) se está comendo
if (f.comendo) {
// b.1.1) se está satisfeito, mandar os dois recursos de volta bs juntos. TODO: juntos ou um de cada vez?
if (++f.come == f.tcome) {
g1.dono = g2.dono = -1;
g1.movendo = g2.movendo = true;
// TODO modularizar estes processos
g1.ai = i;
g1.at = fps / tgarfo;
g1.ast = -g1.ast;
g1.ara = 0;
g1.aro = 0;
g2.ai = i;
g2.at = fps / tgarfo;
g2.ast = -g2.ast;
g2.ara = 0;
g2.aro = 0;
}
// b.1.2) esperar chegarem bs, setar que está pensando.
if (g1.movendo == false && g2.movendo == false && f.come > f.tcome) {
--lr;
f.comendo = false;
f.pensando = true;
f.pensa = f.tpensa;
f.draw();
}
// b.2) se está procurando recursos
}
else {
// b.2.1) nenhum recurso
if (g1.dono != i && g2.dono != i) {
// ao menos um recurso que está livre
var livre:Garfo = g1.dono == -1 && g1.movendo == false ? g1 : g2.dono == -1 && g2.movendo == false ? g2 : null;
// b.2.1.1) verifica disponibilidade global de comedores, verifica recurso livre (descartar os indo bs), muda var global e começa a pegar um.
if (lr < lf / 2 && livre) {
++lr;
livre.dono = i;
livre.movendo = true;
var ai:Number = livre == g1 ? (i + lf - 1) % lf : (i + lf) % lf;
livre.ai = ai + .5;
livre.at = fps / tgarfo;
livre.ast = (livre == g1 ? 1 : -1 ) * .5 * tgarfo / fps;
livre.ara = 0;
livre.aro = 0;
}
} // acabou b.2.1
// b.2.2) um recurso
else if (g1.dono != g2.dono) { // g1.dono == i XOR g2.dono == i
var dono:Garfo = g1.dono == i ? g1 : g2;
var outro:Garfo = dono == g1 ? g2 : g1;
// b.2.2.1) se um recurso estiver vindo, esperar ele chegar.
if (dono.movendo) {
// esperar chegar.
continue;
}
// b.2.2.1.1) verifica recurso livre ou indo bs.
else if (outro.dono == -1) {
// b.2.2.1.1.1) se estiver recurso indo bs, esperar.
if (outro.movendo) {
// esperar
continue;
// b.2.2.1.1.2) se já estiver bs, começar a pegar ele.
} else {
outro.dono = i;
outro.movendo = true;
var ai:Number = outro == g1 ? (i + lf - 1) % lf : (i + lf) % lf;
outro.ai = ai + .5;
outro.at = fps / tgarfo;
outro.ast = (outro == g1 ? 1 : -1 ) * .5 * tgarfo / fps;
outro.ara = 0;
outro.aro = 0;
}
}
// b.2.2.1.2) se não tiver recurso livre, devolver o que já estava.
else {
--lr;
dono.dono = -1;
dono.movendo = true;
dono.ai = i;
dono.at = fps / tgarfo;
dono.ast = -g1.ast;
dono.ara = 0;
dono.aro = 0;
}
} // acabou b.2.2
// b.2.3) dois recursos
else if (g1.dono == i && g2.dono == i) {
// b.2.3.1) se um recurso estiver vindo, esperar ele chegar. setar que está comendo.
if (g1.movendo || g2.movendo) {
// o último ainda está vindo
continue;
}
else {
f.comendo = true;
}
} // acabou b.2.3
} // acabou b.2
}
}
}
}
}
import flash.display.Graphics;
import flash.display.Sprite;
/**
* ...
* @author Marcelo Bosso, thi
*/
class Garfo extends Sprite
{
public var movendo:Boolean = false;
public var dono:int = -1;
public var at:Number, // animation timer
ai:Number, // animation i (inside angle calculation)
ast:Number, // animation step (inside angle calculation)
ara:Number, // animation radius
aro:Number; // animation rotation
private var g:Graphics;
public function Garfo()
{
}
public function draw(faca:Boolean):void {
g = this.graphics;
var xi:Number = 4; // só pra dar uma desalinhada
if (faca) {
// desenha faca
g.lineStyle(0, 0, .5);
g.beginFill(0);
g.drawRect( -0.15 + xi, 5, 2, 1);
g.endFill();
g.lineStyle(1.5, 0);
g.moveTo(0 + xi, 0);
g.lineTo(0 + xi, 9);
g.lineStyle(2.8, 0);
g.moveTo(.5 + xi, 6.3);
g.lineTo(.5 + xi, 9);
} else {
// desenha garfo
g.lineStyle(1, 0);
g.drawRect(-1.8 + xi, 6.3, 3.6, 1);
g.lineStyle(1.5, 0);
g.moveTo(0 + xi, 0);
g.lineTo(0 + xi, 6.3);
g.lineStyle(.6, 0);
g.moveTo(-1.8 + xi,6.3);
g.lineTo( -1.8 + xi, 9);
g.moveTo(1.8 + xi, 6.3);
g.lineTo(1.8 + xi, 9);
g.moveTo(-.6 + xi, 6.3);
g.lineTo( -.6 + xi, 9);
g.moveTo(.6 + xi, 6.3);
g.lineTo(.6 + xi, 9);
}
this.cacheAsBitmap = true;
}
}
import flash.display.Graphics;
import flash.display.Sprite;
/**
* ...
* @author Marcelo Bosso, thi
*/
class Filosofo extends Sprite
{
public var tpensa:Number = 10, tcome:Number = 10;
public var pensando:Boolean = true, comendo:Boolean = false;
public var pensa:Number, come:Number;
private var g:Graphics;
public function Filosofo()
{
}
public function draw():void {
this.graphics.clear();
g = this.graphics;
g.lineStyle(1, 0);
g.drawCircle(0, 0, 14);
g.beginFill(0);
if (pensando) {
// está pensando
var d:Number = 3.5;
g.drawCircle(0, -9 + d, 6.7);
g.beginFill(0xFFFFFF);
g.lineStyle(0, 0, 0);
g.drawRect( -9, -5 + d, 18, 11);
g.lineStyle(1, 0);
g.beginFill(0);
g.moveTo( -3, 2 + d);
g.curveTo( -4, -3 + d, -6, -6 + d);
g.curveTo(0, -13 + d, 6, -6 + d);
g.curveTo(4, -3 + d, 3, 2 + d);
g.drawRect(-2.5, 4 + d, 5, 4);
}
this.cacheAsBitmap = true;
}
}
import flash.display.Graphics;
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
/**
* input/output textfield
* @author thi
*/
class Field extends Sprite
{
public var time:int = 0,
timeOut:int = 30,
tf:TextField,
tt:TextField;
private var g:Graphics;
public function Field(title:String = "coloque a string: ", def:String = "1")
{
var f:TextFormat = new TextFormat("Arial", 14);
tf = new TextField();
tf.defaultTextFormat = f;
tf.type = "input";
tf.text = def;
tf.textColor = 0xFFFFFF;
tf.height = 20;
tf.multiline = false;
tf.autoSize = TextFieldAutoSize.LEFT;
this.addChild(tf);
tt = new TextField();
tt.defaultTextFormat = f;
tt.selectable = false;
tt.text = title;
tt.height = 20;
tt.multiline = false;
tt.autoSize = TextFieldAutoSize.LEFT;
this.addChild(tt);
resize();
}
public function resize():void
{
tf.x = tt.width + 3;
// background
g = this.graphics;
g.clear();
g.beginFill(0, 1);
g.drawRoundRect(tf.x - 3, 0, tf.width + 3, 20, 4, 4);
g.endFill();
g.lineStyle(1, 0, .6);
//g.drawRoundRect(0, 0, tt.width + tf.width + 3, 20, 4, 4);
g.moveTo(2, 16)
g.lineTo(tt.width + tf.width + 3, 16);
}
}