# encoding: ascii
# api: powershell
# title: TheGameOfLife
# description: This is my first attempt at simulating Conway’s ‘the game of life’ in powershell.
# version: 10.5
# type: script
# author: sqlchow
# license: CC0
# function: Initialize-Host
# x-poshcode-id: 3987
# x-archived: 2013-02-28T00:14:42
# x-published: 2013-02-23T21:05:00
#
# Save the code in a file ‘TheGameOfLife.ps1’ and start it by dot sourcing the file name ‘.\TheGameOfLife.ps1’.
# The code saves the current state of the host along with buffer contents.
# The initial state is pre-defined, if you want to change the initial state, you can do that in the main function.
# It takes about, 30secs to draw the next generation.
# To exit, just press enter.
# The code pops the original state of the host along with buffer contents on exit.
# I know, it is very slow. But, it would be nice if improvements can be suggested. I will work on them.
# Added function to put complex pattern on board. To make the function run a little longer.
# Draw-Pixel: drawn from: http://www.codeproject.com/Articles/241411/PowerShell-Falling-Blocks-Ascii-art-on-the-move written by ‘Lasse W’
#
#TheGameOfLife.ps1
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
$SCRIPT:hostProperties = @{};
$SCRIPT:hostState = $null;
$SCRIPT:BoardWidth = 50;
$SCRIPT:BoardHeight = 50;
Function Initialize-Host
{
Param(
[Parameter(Mandatory=$false)]
$wndTitle = "Game of Life...",
[Parameter(Mandatory=$false)]
[Int]$wndWidth=50,
[Parameter(Mandatory=$false)]
[Int]$wndHeight=50
)
$wndSize = $Host.UI.RawUI.WindowSize;
$wndSize.Width = $wndWidth;
$wndSize.Height = $wndHeight;
$wndBuffSize = $wndSize;
#Set Console
$Host.UI.RawUI.WindowTitle = $wndTitle;
$Host.UI.RawUI.WindowSize = $wndSize;
$Host.UI.RawUI.BufferSize = $wndBuffSize;
$Host.UI.RawUI.CursorSize = 0;
$Host.UI.RawUI.ForegroundColor = "Green";
$Host.UI.RawUI.BackgroundColor = "Black";
#get a clear the screen.
Clear-Host;
}
Function Push-Host
{
#Get the full buffer
$hostRect = "System.Management.Automation.Host.Rectangle"
$bufferObject = New-Object $hostRect 0, 0, $(($Host.UI.RawUI.BufferSize).Width), $(($Host.UI.RawUI.BufferSize).Height)
$SCRIPT:hostProperties= @{
"Title" = $Host.UI.RawUI.WindowTitle
"WindowSize" = $Host.UI.RawUI.WindowSize
"WindowPosition" = $Host.UI.RawUI.WindowPosition
"BufferSize" = $Host.UI.RawUI.BufferSize
"Buffer" = $Host.UI.RawUI.GetBufferContents($bufferObject)
"Background" = $Host.UI.RawUI.BackgroundColor
"Foreground" = $Host.UI.RawUI.ForegroundColor
"CursorSize" = $Host.UI.RawUI.CursorSize
"CursorPosition" = $Host.UI.RawUI.CursorPosition
}
$SCRIPT:hostState = New-Object -TypeName PSCustomObject -Property $SCRIPT:hostProperties
}
Function Pop-Host
{
#Restore buffer contents
$Host.UI.RawUI.BufferSize = $SCRIPT:hostState.BufferSize;
$initPosition = $Host.UI.RawUI.WindowPosition;
$initPosition.x = 0;
$initPosition.y = 0;
$Host.UI.RawUI.SetBufferContents($initPosition, $SCRIPT:hostState.Buffer)
#Start with the window
$Host.UI.RawUI.WindowTitle = $SCRIPT:hostState.Title;
$Host.UI.RawUI.WindowPosition = $SCRIPT:hostState.WindowPosition;
$Host.UI.RawUI.WindowSize = $SCRIPT:hostState.WindowSize;
#Set cursor
$Host.UI.RawUI.CursorSize = $SCRIPT:hostState.CursorSize;
$Host.UI.RawUI.CursorPosition = $SCRIPT:hostState.CursorPosition;
#set colors
$Host.UI.RawUI.ForegroundColor = $SCRIPT:hostState.Foreground;
$Host.UI.RawUI.BackgroundColor = $SCRIPT:hostState.Background;
}
Function Get-CursorPosition
{
$dY = ([System.Windows.Forms.Cursor]::Position.Y ) #read the Y coordinates
$dX = ([System.Windows.Forms.Cursor]::Position.X ) #read the X coordinates
return @($dX, $dY)
}
Function Draw-Pixel
{
param(
[Parameter(Mandatory=$true)]
[Int]$X,
[Parameter(Mandatory=$true)]
[Int]$Y,
[Parameter(Mandatory=$false)]
[String]$ForeColor = 'White',
[Parameter(Mandatory=$false)]
[String]$BackColor = 'Black',
[Parameter(Mandatory=$false)]
[String]$pixel = [Char]9608
)
$pos = $Host.UI.RawUI.WindowPosition
$pos.x = $x
$pos.y = $y
$row = $Host.UI.RawUI.NewBufferCellArray($pixel, $ForeColor, $BackColor)
$Host.UI.RawUI.SetBufferContents($pos,$row)
}
#Initialize a full board of dead cells.
Function Initialize-GameMatrix
{
param(
[Int32]$M,
[Int32]$N
)
$gameMatrix = New-Object "Int32[,]" $M, $N
for($i=0; $i -lt $M; $i++)
{
for($j=0; $j -lt $N; $j++)
{
$gameMatrix[$i, $j] = 0;
}
}
return ,$gameMatrix
}
#show the game board in 1's and 0's
Function Show-Matrix
{
param(
[Int[,]]$matrix
)
[Int]$m = $matrix.GetLength(0);
[Int]$n = $matrix.GetLength(1);
for($i=0; $i -lt $m; $i++)
{
for($j=0; $j -lt $n; $j++)
{
Write-Host("{0}" -f $matrix[$i,$j]) -NoNewLine;
}
Write-Host ""
}
}
#Currently Taking 10.5 Secs to generate next generation.
#consumes around 20-25% cpu.
#need to find a better way to do this.
Function Get-NextGeneration
{
param(
[Int[,]]$GameMatrix
)
BEGIN
{
$tmpGameMatrix = $GameMatrix;
#The game board for game of life is infinite. So, we simulate this by wrapping the
#width and height.
Function Get-WrappedWidth
{
param(
[Int]$x,
[Int]$xEdge
)
$x += $xEdge;
if($x -lt 0){
$x += $SCRIPT:BoardWidth;
}elseif($x -ge $SCRIPT:BoardWidth){
$x -= $SCRIPT:BoardWidth;
}
return $x;
}
Function Get-WrappedHeight
{
param(
[Int]$y,
[Int]$yEdge
)
$y += $yEdge;
if($y -lt 0){
$y += $SCRIPT:BoardHeight;
}elseif($y -ge $SCRIPT:BoardHeight){
$y -= $SCRIPT:BoardHeight
}
return $y;
}
Function Get-Neighbours
{
param(
[Int[,]]$ArrayMatrix,
[Int]$coordX,
[Int]$coordY
)
[Int]$nx = 0;
[Int]$ny = 0;
[Int]$count = 0;
for($nx = -1; $nx -le 1; $nx++)
{
for($ny = -1; $ny -le 1; $ny++)
{
if($nx -or $ny)
{
if($ArrayMatrix[$(Get-WrappedWidth $coordX $nx), $(Get-WrappedHeight $coordY $ny)])
{
$count += 1;
}
}
}
}
return $count;
}
}
PROCESS
{
for($x = 0; $x -lt $SCRIPT:BoardWidth; $x++)
{
for($y = 0; $y -lt $SCRIPT:BoardHeight; $y++)
{
$neighbors = Get-Neighbours $tmpGameMatrix $x $y
switch($neighbors)
{
{($neighbors -lt 2) -or ($neighbors -gt 3)}{$tmpGameMatrix[$x, $y] = 0;}
{($neighbors -eq 3)}{$tmpGameMatrix[$x, $y] = 1;}
}
}
}
}
END
{
$GameMatrix = $tmpGameMatrix;
#should we even do this? : return ,$GameMatrix
return ,$GameMatrix;
}
}
Function Draw-Board
{
param(
[Int[,]]$Board
)
for($bx = 0; $bx -lt $SCRIPT:BoardWidth; $bx++)
{
for($by = 0; $by -lt $SCRIPT:BoardHeight; $by++)
{
if($Board[$bx, $by])
{
Draw-Pixel -X $bx -Y $by -ForeColor "Green" -BackColor "Yellow"
}else{
Draw-Pixel -X $bx -Y $by -ForeColor "Black" -BackColor "Black"
}
}
}
}
#Setting a little bit of complex pattern on the board.
Function Set-SampleOnBoard
{
param(
[Int[,]]$ArrayMatrix
)
$ArrayMatrix[6,1] = 1
$ArrayMatrix[7,1] = 1
$ArrayMatrix[6,2] = 1
$ArrayMatrix[7,2] = 1
$ArrayMatrix[6,11] = 1
$ArrayMatrix[7,11] = 1
$ArrayMatrix[8,11] = 1
$ArrayMatrix[9,12] = 1
$ArrayMatrix[10,13] = 1
$ArrayMatrix[10,14] = 1
$ArrayMatrix[9,16] = 1
$ArrayMatrix[8,17] = 1
$ArrayMatrix[7,17] = 1
$ArrayMatrix[6,17] = 1
$ArrayMatrix[5,16] = 1
$ArrayMatrix[4,14] = 1
$ArrayMatrix[4,13] = 1
$ArrayMatrix[5,12] = 1
$ArrayMatrix[7,15] = 1
$ArrayMatrix[7,18] = 1
$ArrayMatrix[4,21] = 1
$ArrayMatrix[5,21] = 1
$ArrayMatrix[6,21] = 1
$ArrayMatrix[4,22] = 1
$ArrayMatrix[5,22] = 1
$ArrayMatrix[6,22] = 1
$ArrayMatrix[7,23] = 1
$ArrayMatrix[3,23] = 1
$ArrayMatrix[3,25] = 1
$ArrayMatrix[2,25] = 1
$ArrayMatrix[7,25] = 1
$ArrayMatrix[8,25] = 1
$ArrayMatrix[3,35] = 1
$ArrayMatrix[3,36] = 1
$ArrayMatrix[4,35] = 1
$ArrayMatrix[4,36] = 1
return ,$ArrayMatrix;
}
Function Main
{
Push-Host;
Initialize-Host;
$gameBoard = Initialize-GameMatrix 50 50;
#Sample filler
$gameBoard = Set-SampleOnBoard $gameBoard
Draw-Board $gameBoard
do{
$newBoard = Get-NextGeneration $gameBoard;
#Clear-Host;
Draw-Board $newBoard;
}until($Host.UI.RawUI.KeyAvailable)
Pop-Host;
}
. Main