Jantar dos filósofos

by Thy
♥0 | Line 397 | Modified 2013-05-04 00:50:51 | MIT License
play

ActionScript3 source code

/**
 * 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);

    }

    

}

Forked