/* * A Gobstones implementation of Conwey's Game of Life * that tries to use most of Gobstones syntax. * * Check out more about Gobstones at http://gobstones.org */ ----------------------------------------------------------- -- HELPERS TO MOVE AROUND ALL THE BOARD -- ----------------------------------------------------------- // This helpers allow the user to move around the board // one cell at a time procedure GoToStartOfBoard(firstDir, secondDir) { IrAlBorde(opuesto(firstDir)) IrAlBorde(opuesto(secondDir)) } function isEndOfBoard(firstDir, secondDir) { return (not puedeMover(firstDir) && not puedeMover(secondDir)) } procedure NextCellOfTheBoard(firstDir, secondDir) { if (puedeMover(firstDir)) { Mover(firstDir) } else { IrAlBorde(opuesto(firstDir)) Mover(secondDir) } } ----------------------------------------------------------- -- TYPE DECLARATIONS -- ----------------------------------------------------------- // The cell type declarations type CellStatus is variant { case Alive {} case Dead {} } type Cell is record { field status # CellStatus field color # Color } ----------------------------------------------------------- -- PROGRAM DEFINITION -- ----------------------------------------------------------- interactive program { # Map key press to actions K_UP -> { PrepareNextTick() } K_RIGHT -> { CompleteNextTick() } K_RETURN -> { SimulateNextTick() } } /* program { return ( numberOfNeighbors()) } */ ----------------------------------------------------------- -- FUNCTIONS -- ----------------------------------------------------------- function isCellAlive() { return (hayBolitas(Verde)) } function cellStatus() { return ( choose Alive when (isCellAlive()) Dead otherwise ) } function readCell() { return ( Cell(color <- Verde, status <- cellStatus()) ) } function numberOfNeighbors() { amountOfNeighbors := 0 foreach dir in [minDir() .. maxDir()] { amountOfNeighbors := amountOfNeighbors + aliveCellsAt(dir) } return (amountOfNeighbors) } function aliveCellsAt(dir) { firstCompare := puedeMover(dir) && hasAliveCellAt(dir) secondCompare := puedeMover(dir) && puedeMover(siguiente(dir)) && hasAliveCellAtD(dir) value := matching (firstCompare) select 1 on True 0 otherwise + matching (secondCompare) select 1 on True 0 otherwise return (value) } function hasAliveCellAt(dir) { Mover(dir) return (isCellAlive()) } function hasAliveCellAtD(dir) { Mover(dir) Mover(siguiente(dir)) return (isCellAlive()) } ----------------------------------------------------------- -- ROCEDURES DECLARATIONS -- ----------------------------------------------------------- procedure TagAsReanimated() { Poner(Azul) } procedure TagAsDead() { Poner(Rojo) } procedure ProcessAction() { switch (hayBolitas(Rojo)) { True -> { Sacar(Verde); Sacar(Rojo) } _ -> {} } switch (hayBolitas(Azul)) { True -> { Poner(Verde); Sacar(Azul) } _ -> {} } } procedure TagCell(numNeighbors) { if ( isCellAlive() && numNeighbors < 2) { TagAsDead() } elseif ( isCellAlive() && numNeighbors > 3) { TagAsDead() } elseif ((not isCellAlive()) && numNeighbors == 3) { TagAsReanimated() } } procedure SimulateTicks(amount) { repeat(amount) { SimulateNextTick() } } procedure SimulateNextTick() { PrepareNextTick() CompleteNextTick() } procedure PrepareNextTick() { GoToStartOfBoard(Norte, Este) while (not isEndOfBoard(Norte, Este)) { TagCell(numberOfNeighbors()) NextCellOfTheBoard(Norte, Este) } TagCell(numberOfNeighbors()) } procedure CompleteNextTick() { GoToStartOfBoard(Norte, Este) while (not isEndOfBoard(Norte, Este)) { ProcessAction() NextCellOfTheBoard(Norte, Este) } ProcessAction() }