License text

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER 
 * Copyright  2008, 2010 Oracle and/or its affiliates.  All rights reserved. 
 * Use is subject to license terms.
 * 
 * This file is available and licensed under the following license:
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met: 
 * 
 *   * Redistributions of source code must retain the above copyright notice, 
 *     this list of conditions and the following disclaimer. 
 *
 *   * Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *
 *   * Neither the name of Oracle Corporation nor the names of its contributors 
 *     may be used to endorse or promote products derived from this software 
 *     without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

    

package gameoflife;

import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.Group;
import javafx.scene.paint.*;
import javafx.scene.Scene;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextOrigin;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.scene.input.MouseEvent;

/**
 * @author Jim Holmlund
 * @Modified by Vaibhav Choudhary
 */

def screenWidth: Integer = 240;
def screenHeight: Integer = 320;
def interval = .3s;
def diameter = 21;
def gap = 2;
def unitSize = diameter + gap;
def smallFont = Font { size: 15 }
def liveColor = LinearGradient {
    startX: 0.0,
    startY: 0.0,
    endX: 0.0,
    endY: 1.0
    proportional: true
    stops: [
        Stop {
            offset: 0.0
            color: Color.LIGHTGREEN
        },
        Stop {
            offset: 0.3
            color: Color.DARKGREEN
        },
        Stop {
            offset: 1.0
            color: Color.LIGHTGREEN
        }
    ]
            };
def backgroundColor = Color.BLACK;
def evenColor =  LinearGradient {
    startX: 0.0,
    startY: 0.0,
    endX: 0.0,
    endY: 1.0
    proportional: true
    stops: [
        Stop {
            offset: 0.0
            color: Color.RED
        },
        Stop {
            offset: 0.3
            color: Color.DARKRED
        },
        Stop {
            offset: 1.0
            color: Color.RED
        }
    ]
            };
def oddColor = evenColor;
def resetSize = Text {
    content: "Reset"
    font: smallFont
};
def buttonHeight:Integer = (resetSize.layoutBounds.height + 8) as Integer;
def buttonWidth:Integer = (resetSize.layoutBounds.width + 10) as Integer;
def useableHeight = screenHeight - buttonHeight - gap;
def gameSize =
if (useableHeight > screenWidth) screenWidth else useableHeight;
def buttonY = screenHeight - buttonHeight - gap;

def nCells: Integer = (gameSize - gap) / unitSize;
def lastRectIndex = nCells * nCells - 1;

class CircleGroup extends Group {
    var myColor: Paint;
        override var content =
        for (i in [0..lastRectIndex]) {
        Circle {
            translateX: gap + unitSize * (i mod nCells)
                translateY: gap + unitSize * ((
                i / nCells) as Integer)
            centerX: 15, centerY: 15
            radius: diameter/2
            fill:LinearGradient {
                startX: 0.0,
                startY: 0.0,
                endX: 0.0,
                endY: 1.0
                proportional: true
                stops: [
                    Stop {
                        offset: 0.0
                        color: Color.RED
                    },
                    Stop {
                        offset: 0.3
                        color: Color.DARKRED
                    },
                    Stop {
                        offset: 1.0
                        color: Color.RED
                    }
                ]
            }
}
        }

        override var onMousePressed = function(event: MouseEvent) {
            var xx = ((event.sceneX - gap) / (unitSize)) as Integer;
            var yy = ((event.sceneY - gap) / (unitSize)) as Integer;
            var index = yy * nCells + xx;
            def theRect = this.content[index] as Circle;
            if (theRect.fill == liveColor) {
                theRect.fill = this.myColor;
            } else {
                theRect.fill = liveColor;
            }
        }
}

def cEven = CircleGroup { myColor: evenColor };
def cOdd  = CircleGroup { myColor: oddColor };
var rectsCurr = cEven;
var count = 0;


function getLiveNeighborsCount(theCircleGroup: CircleGroup, ii: Integer): Integer {
    var retVal: Integer = 0;
    def prevRow = ii - nCells;
    def nextRow = ii + nCells;
    def left = ii mod nCells;
    def right = (ii + 1) mod nCells;
    def theSeq = theCircleGroup.content;

    if (prevRow >= 0) {
        if (left != 0) {
            if ((theSeq[
            prevRow - 1] as Circle).fill == liveColor) retVal++;
        }
        if ((theSeq[prevRow] as Circle).fill == liveColor) retVal++;
        if (right != 0) {
            if ((theSeq[
            prevRow + 1] as Circle).fill == liveColor) retVal++;
        }
    }
   if (left != 0) {
        if ((theSeq[
        ii - 1] as Circle).fill == liveColor) retVal++;
    }
    if (right != 0) {
        if ((theSeq[
        ii + 1] as Circle).fill == liveColor) retVal++;
    }
    if (nextRow < lastRectIndex) {
        if (left != 0) {
            if ((theSeq[
            nextRow - 1] as Circle).fill == liveColor) retVal++;
        }
        if ((theSeq[nextRow] as Circle).fill == liveColor) retVal++;
        if (right != 0) {
            if ((theSeq[
            nextRow + 1] as Circle).fill == liveColor) retVal++;
        }
    }
    return retVal;
}

function reset(theRect: CircleGroup) {
    for (ii in [0..lastRectIndex]) {
        (
        theRect.content[ii] as Circle).fill = theRect.myColor;
    }
}

var tt: Timeline = Timeline {
    repeatCount: Timeline.INDEFINITE
    keyFrames: [
        KeyFrame {
            canSkip: true
            time: interval
            action: function() {
                var allDead = true;
                count++;
                var nextRect: CircleGroup;
                var currRect: CircleGroup;
                if (count mod 2 == 1) {
                    nextRect = cOdd;
                    currRect = cEven;
                } else {
                    nextRect = cEven;
                    currRect = cOdd;
                }
                for (ii in [0..lastRectIndex]) {
                    def nLive = getLiveNeighborsCount(currRect, ii);
                    def curr = currRect.content[ii] as Circle;
                    def next = nextRect.content[ii] as Circle;
                    if (curr.fill == liveColor) {
                        // this cell is alive
                        if (nLive < 2 or nLive > 3) {
                            next.fill = nextRect.myColor;       // it dies
                        } else {
                            next.fill = liveColor;              // it lives
                            allDead = false;
                        }
                        continue;
                    }
                    // This cell is currently dead.
                    if (nLive == 3) {
                        next.fill = liveColor;
                        allDead = false;
                    } else {
                        next.fill = nextRect.myColor
                    }
                }
                rectsCurr = nextRect;
                if (allDead) {
                    tt.stop();
                }
            }
        }
    ]
}
var start = Group {
    content: [
        Rectangle {
            x: 2
            y: 290
            width: 75
            height: 25
            opacity: 0.6
            arcHeight:5
            arcWidth:5
            fill: LinearGradient {
                startX: 0.0
                startY: 0.0
                endX: 0.0
                endY: 1.0
                proportional: true
                stops: [
                    Stop {
                        offset: 0.0
                        color: Color.LIME
                    },
                    Stop {
                        offset: 0.5
                        color: Color.DARKGREEN
                    },
                    Stop {
                        offset: 1.0
                        color: Color.LIME
                    }
                ]
            }
            onMousePressed: function(e) {
                tt.play();
            }
        },
        Text {
            fill: Color.WHITE
            x: 27
            y: 307
            font: Font {
                size: 12
                name: "Arial Bold"
                    //letterSpacing: 0.15

            }
            content: "Start"
        },
    ]
        };

var stop = Group {
    content: [
        Rectangle {
            x: 80
            y: 290
            width: 75
            height: 25
            opacity: 0.6
            arcHeight:5
            arcWidth:5
            fill: LinearGradient {
                startX: 0.0
                startY: 0.0
                endX: 0.0
                endY: 1.0
                proportional: true
                stops: [

                    Stop {
                        offset: 0.0
                        color: Color.LIME
                    },
                    Stop {
                        offset: 0.5
                        color: Color.DARKGREEN
                    },
                    Stop {
                        offset: 1.0
                        color: Color.LIME
                    }
                ]
            }
            onMousePressed: function(e) {
                tt.stop();
            }
        },
        Text {
            fill: Color.WHITE
            x: 100
            y: 307
            font: Font {
                size: 12
                name: "Arial Bold"
                    //letterSpacing: 0.15

            }
            content: " Stop"
        },
    ]
}

var reset_b = Group {
    content: [
        Rectangle {
            x: 158
            y: 290
            width: 79
            height: 25
            opacity: 0.6
            arcHeight:5
            arcWidth:5
            fill: LinearGradient {
                startX: 0.0
                startY: 0.0
                endX: 0.0
                endY: 1.0
                proportional: true
                stops: [
                    //   Stop { offset: 0.0 color: Color.BLACK },
                    Stop {
                        offset: 0.0
                    color: Color.LIME },
                    Stop {
                        offset: 0.5
                    color: Color.DARKGREEN },
                    Stop {
                        offset: 1.0
                    color: Color.LIME }
                ]
            }
            onMousePressed: function(e) {
                tt.stop();
                reset(cOdd);
                reset(cEven);
                count = 0;
            }
        },
        Text {
            fill: Color.WHITE
            x: 175
            y: 307
            font: Font {
                size: 12
                name: "Arial Bold"
            }
            content: "  Reset"
        }
    ]
}

var ss = Stage {
    title: "Conway's Game of Life"
    style: StageStyle.TRANSPARENT
    scene: Scene {
        width: screenWidth
        height: screenHeight
        fill: Color.BLACK
        content: bind [
            start,
            stop,
            reset_b,
            rectsCurr,
            Text {
                textOrigin: TextOrigin.TOP
                font: Font {
                    size: 11
                    name: "Arial Bold"
                }
                content: "Generation = {count}, Interval = {interval}"
                translateX: 30
                translateY: buttonY - 30
                fill: Color.WHITE
            },
            Text {
                textOrigin: TextOrigin.TOP
                font: Font {
                    size: 11
                    name: "Arial Bold"
                }
                content: "Select Red Circles and Press Start"
                translateX: 25
                translateY: buttonY - 50
                fill: Color.WHITE
            }
        ]
    }
}