import java.util.BitSet; import java.util.Random; import java.awt.*; import java.awt.event.*; import java.text.NumberFormat; /** Fatal gene simulation. Sloppy-ass code. @author Alan Eliasen, eliasen@mindspring.com */ public class Gene extends java.applet.Applet implements Runnable { // User-configurable parameters begin here ---------------------------- /** The initial number of individuals */ private int initPop = 1000; /** The population ceiling */ private int popCeiling = 100000; /** The average reproduction rate (children per couple), before adjustment for fatalities */ private float repAverage = 2.01f; /** The initial proportion of the population that carries one fatal gene. */ private float fatalPercent = 1.0f/2.0f; /** The probability that a someone with 2 of the recessive genes dies. */ private float dieProb = 1.0f; // User-configurable parameters end here ---------------------------- /** The current population. */ private int pop; /** The population of individuals */ private BitSet individuals1= null; /** The other population of individuals */ private BitSet individuals2 = null; /** The pointer to the active individuals and non-active. */ private BitSet individuals, altIndividuals; /** The random number generator */ private Random rand = new Random(); /** The number that died last generation */ private int died; /** The number of carriers */ private int carriers; /** The generation number */ private int generation=0; /** True if simulation is running */ private Thread runner = null; // GUI Garbage private TextField txtPop, txtPopCeiling, txtRepAverage, txtFatalPercent, txtDieProb; private Button startButton, stopButton; private TextArea outputArea; private Panel myPanel; private Frame frame = null; private Label label = null; private NumberFormat nf; /** Initialize the population and the simulation. This should be done before you call doStep() for the first time. It can be called any number of times to reset the population. */ private void initializePopulation() { nf = NumberFormat.getInstance(); nf.setMinimumFractionDigits(2); nf.setMaximumFractionDigits(2); generation = 0; carriers = 0; died = 0; pop = initPop; individuals1 = new BitSet(popCeiling*2); individuals2 = new BitSet(popCeiling*2); individuals = individuals1; altIndividuals = individuals2; for (int i=0; i popCeiling) offspring = popCeiling; int ind1, ind2; boolean b1, b2; for (int i=0; i 0) && (carriers > 0)); if (carriers == 0) outputArea.appendText("Gene exterminated after " + generation + " generations."); if (pop == 0) outputArea.appendText("So is the entire population."); stopSimulation(); } /** Output the state to the text area and the console. */ private void printState() { String output = generation + "\t" + pop + "\t" + carriers + "\t" + nf.format((100.0f * carriers) / pop) + "%\t" + died + "\t" + (100.0f * died) / (died + pop) + "%\n"; outputArea.appendText(output); // Windows automatically scrolls on append, Linux doesn't... // outputArea.setCaretPosition(outputArea.getText().length()); // System.out.print(output); } /** Stop the running of the simulation */ private void stopSimulation() { runner = null; startButton.setEnabled(true); stopButton.setEnabled(false); } /** Stop the applet */ public void stop() { stopSimulation(); } /** Detach the panel from the browser and display it in a frame. */ public void detach() { if (frame == null) { // Remove components from this applet remove(myPanel); frame = new Frame("Gene Simulator - Copyright Alan Eliasen"); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { attach(); } }); frame.setSize(getSize().width, getSize().height); frame.setLayout(new BorderLayout()); frame.add(myPanel, BorderLayout.CENTER); frame.validate(); frame.setVisible(true); if (label == null) { label = new Label("The applet has been detached.", Label.CENTER); label.setBackground(new Color(0,64,0)); label.setForeground(Color.green); } add(label, BorderLayout.CENTER); validate(); } frame.toFront(); } /** Toggle the myPanel between attached and detached states. */ public void toggleAttach() { if (frame == null) detach(); else attach(); } /** If the chat window is detached from the browser, reattach it and destroy the frame. */ public void attach() { if (frame != null) { remove(label); frame.setVisible(false); frame.remove(myPanel); frame.dispose(); frame = null; add(myPanel, BorderLayout.CENTER); validate(); } } /** Return information about the applet. */ public String getAppletInfo() { return "Fatal Gene\nby Alan Eliasen\neliasen@mindspring.com\nCopyright 2002-2003"; } /** Main for testing without a GUI. */ public static void main(String[] args) { Gene g = new Gene(); System.out.println("Gen\tPop\tCarrier\t%Carriers\tDied\t%Died"); g.initializePopulation(); do { g.doStep(); System.out.println(g.generation + "\t" + g.pop + "\t" + g.carriers + "\t" + 100.0f * g.carriers/ g.pop + "%\t" + g.died + "\t" + (100.0f * g.died) / (g.died + g.pop) + "%"); } while ((g.pop > 0) && (g.carriers > 0)); if (g.carriers == 0) System.out.println("Gene was eradicated after " + g.generation + " generations."); } }