Play-Tetris
Play Tetris
#requires -version 5.1
using Namespace System.Drawing
using Namespace System.Windows.Forms
enum ShapeTypes {
Unspecified = 0
Line = 1
T = 2
Square = 3
L = 4
LMirrored = 5
S = 6
SMirrored = 7
}
class TetrisShape {
[System.Drawing.Point]$Position
[System.Drawing.Color]$Color
[ShapeTypes]$Type = 0
[int[, ]]$Body
[PSCustomObject] $Moveset = [PSCustomObject] @{
Left = $false
Right = $false
Up = $false
Down = $false
}
[int[, ]] SetShape([ShapeTypes] $Type) {
$Coordinates = [int[, ]]::new(5, 5)
switch ([int]$Type) {
Default {
$Coordinates[2, 0] = 1
$Coordinates[2, 1] = 1
$Coordinates[2, 2] = 1
$Coordinates[2, 3] = 1
}
2 {
$Coordinates[2, 1] = 1
$Coordinates[2, 2] = 1
$Coordinates[2, 3] = 1
$Coordinates[1, 2] = 1
}
3 {
$Coordinates[2, 2] = 1
$Coordinates[2, 3] = 1
$Coordinates[3, 2] = 1
$Coordinates[3, 3] = 1
}
4 {
$Coordinates[1, 2] = 1
$Coordinates[1, 3] = 1
$Coordinates[2, 2] = 1
$Coordinates[3, 2] = 1
}
5 {
$Coordinates[1, 1] = 1
$Coordinates[1, 2] = 1
$Coordinates[2, 2] = 1
$Coordinates[3, 2] = 1
}
6 {
$Coordinates[1, 2] = 1
$Coordinates[2, 1] = 1
$Coordinates[2, 2] = 1
$Coordinates[3, 1] = 1
}
7 {
$Coordinates[1, 2] = 1
$Coordinates[2, 2] = 1
$Coordinates[2, 3] = 1
$Coordinates[3, 3] = 1
}
}
return $Coordinates
}
[bool] IsColliding([int[, ]] $Body, [int[, ]] $Table, [System.Drawing.Point] $Position) {
for ($Y = 0; $Y -le $Body.GetUpperBound(1); $Y++) {
for ($X = 0; $X -le $Body.GetUpperBound(0); $X++) {
if ($Table[($Position.X + $X), ($Position.Y + $Y)] -and $Body[$X, $Y]) {
return $true
}
}
}
return $false
}
[void] Move([System.Drawing.Point] $PositionChange, [int[, ]] $TableCoordinates) {
$PositionChange = [System.Drawing.Point]::new(
($this.Position.X + $PositionChange.X),
($this.Position.X + $PositionChange.Y)
)
if (!$this.IsColliding($this.Body, $TableCoordinates, $PositionChange)) {
$this.Position = $PositionChange
}
}
[void] Rotate([bool] $Reverse, [int[, ]] $TableCoordinates) {
if ($this.Type -ne [ShapeTypes]::Square) {
[int[, ]] $RotatedBody = [int[, ]]::new(($this.Body.GetUpperBound(1) + 1), ($this.Body.GetUpperBound(1) + 1))
for ($Y = 0; $Y -lt ($this.Body.GetUpperBound(1) + 1); ++$Y) {
for ($X = 0; $X -lt ($this.Body.GetUpperBound(1) + 1); ++$X) {
if ($Reverse) {
$RotatedBody[$Y, $X] = $this.Body[$X, (($this.Body.GetUpperBound(1) + 1) - $Y - 1)]
}
else {
$RotatedBody[$Y, $X] = $this.Body[(($this.Body.GetUpperBound(1) + 1) - $X - 1), $Y]
}
}
}
if (!$this.IsColliding($RotatedBody, $TableCoordinates, $this.Position)) {
$this.Body = $RotatedBody
}
}
}
[void] PrintBody() {
[console]::WriteLine(
('Type: {0}, Color: {1}: Left: {2}, Right: {3} Position: {4}, {5}' -f
$this.Type, $this.Color.Name,
$this.Moveset.Left, $this.Moveset.Right,
$this.Position.X, $this.Position.Y
)
)
ForEach ($Y in 0 .. $this.Body.GetUpperBound(1)) {
[console]::WriteLine(
(
(
0 .. $this.Body.GetUpperBound(0) | ForEach-Object {
$this.Body[$_, $Y]
}
) -join '-' -replace '0', '-'
)
)
}
}
TetrisShape([ShapeTypes] $ShapeName) {
$this.Color = [System.Drawing.Color]::FromArgb(255, (Get-Random (1 .. 255)), (Get-Random (1 .. 255)), (Get-Random (1 .. 255)))
$this.Type = $ShapeName
$this.Body = $this.SetShape([int]$ShapeName)
}
}
class TetrisBoard {
[bool] $Debug = $false
[int32] $BlockSize
[int32] $Width
[int32] $Height
[int[, ]] $Coordinates
[TetrisShape] $NextShape
[TetrisShape] $ActiveShape
[PSCustomObject] $Background = [PSCustomObject] @{
Burn = $false
Color = [System.Drawing.Color]::FromArgb(255, 135, 206, 235)
Min = 200
Max = 254
}
[void] Kill() {
if ($null -ne $this.ActiveShape) {
for ($Y = 0; $Y -le $this.ActiveShape.Body.GetUpperBound(1); $Y++) {
for ($X = 0; $X -le $this.ActiveShape.Body.GetUpperBound(0); $X++) {
if ($this.ActiveShape.Body[$X, $Y]) {
Try {
$this.Coordinates[($this.ActiveShape.Position.X + ($X)), ($this.ActiveShape.Position.Y + $Y)] = 1
}
Catch { }
}
}
}
$this.ActiveShape = $null
}
}
[bool] LostGame() {
# If the next shape collides with a deadblock - player lost
if ($null -ne $this.NextShape) {
return $this.NextShape.IsColliding($this.NextShape.Body, $this.Coordinates, $this.NextShape.Position)
}
else {
return $false
}
}
[void] UpdateBoard() {
# Check for any lines to be removed, or if player has fucked up enough
}
[void] UpdateMoveset() {
if ($null -ne $this.ActiveShape) {
# Enable movement to each direction
$this.ActiveShape.Moveset.Left = $true
$this.ActiveShape.Moveset.Right = $true
$this.ActiveShape.Moveset.Down = $true
for ($Y = 0; $Y -le $this.ActiveShape.Body.GetUpperBound(1); $Y++) {
for ($X = 0; $X -le $this.ActiveShape.Body.GetUpperBound(0); $X++) {
if ($this.ActiveShape.Body[$X, $Y]) {
if (
# If the left side of the block is blocked, or is out of bounds
$this.Coordinates[($this.ActiveShape.Position.X + ($X - 1)), ($this.ActiveShape.Position.Y + $Y)] -or
$this.RelativePoint($X, $Y, $this.ActiveShape).X -lt $this.BlockSize
) {
$this.ActiveShape.Moveset.Left = $false
}
if (
# If the right side of the block is blocked, or is out of bounds
$this.Coordinates[($this.ActiveShape.Position.X + ($X + 1)), ($this.ActiveShape.Position.Y + $Y)] -or
$this.RelativePoint($X, $Y, $this.ActiveShape).X -ge (($this.Width * $this.BlockSize) - $this.BlockSize)
) {
$this.ActiveShape.Moveset.Right = $false
}
if (
# If the block below is dead, or is out of bounds (Debug mode, invincible execpt oob)
(
!$this.Debug -and
$this.Coordinates[($this.ActiveShape.Position.X + $X), ($this.ActiveShape.Position.Y + ($Y + 1))]
) -or
$this.RelativePoint($X, $Y, $this.ActiveShape).Y -ge (($this.Height * $this.BlockSize) - $this.BlockSize)
) {
$this.ActiveShape.Moveset.Down = $false
}
}
}
}
}
}
[void] NewShape() {
if ($null -ne $this.NextShape) {
if ($null -eq $this.ActiveShape) {
$this.ActiveShape = $this.NextShape
$this.NextShape = [TetrisShape]::new((Get-Random (1 .. 7)))
$this.NextShape.Position = [System.Drawing.Point]::new((Get-Random (1 .. ($this.Width - ($this.NextShape.Body.GetUpperBound(0) + 1)))), 0)
}
}
else {
$this.NextShape = [TetrisShape]::new((Get-Random (1 .. 7)))
$this.NextShape.Position = [System.Drawing.Point]::new((Get-Random (1 .. ($this.Width - ($this.NextShape.Body.GetUpperBound(0) + 1)))), 0)
}
}
[System.Drawing.Point] RelativePoint([int]$X, [int]$Y, [TetrisShape] $Shape) {
return [System.Drawing.Point]::new(
(($Shape.Position.X * $this.BlockSize) + ($X * $this.BlockSize)),
(($Shape.Position.Y * $this.BlockSize) + ($Y * $this.BlockSize))
)
}
[void] AddLines([int] $Lines) {
1 .. $Lines | ForEach-Object {
#Write-Host 'Starting adding a new line'
ForEach ($Y in 1 .. $this.Coordinates.GetUpperBound(1)) {
#Write-Host ('Loop Y:{0}/{1}' -f $Y, $this.Coordinates.GetUpperBound(1))
0 .. $this.Coordinates.GetUpperBound(0) | ForEach-Object {
#Write-Host ('Column X:{0}/{1} Y:{2} = X:{3}/{4} Y:{5}' -f $_, $this.Coordinates.GetUpperBound(0), ($Y - 1), $_, $this.Coordinates.GetUpperBound(0), $Y)
$this.Coordinates[$_, ($Y - 1)] = $this.Coordinates[$_, $Y]
}
}
0 .. $this.Coordinates.GetUpperBound(0) | ForEach-Object {
#Write-Host ('Set: {0},{1} = 1' -f $_, $this.Coordinates.GetUpperBound(1))
$this.Coordinates[$_, $this.Coordinates.GetUpperBound(1)] = Get-Random (0 .. 1)
}
}
}
[void] ClearLines() {
ForEach ($Y in $this.Coordinates.GetUpperBound(1) .. 0) {
if (!( -join (0 .. $this.Coordinates.GetUpperBound(0) | ForEach-Object { $this.Coordinates[$_, $Y] })).Contains('0')) {
# Reset top row
0 .. $this.Coordinates.GetUpperBound(0) | ForEach-Object { $this.Coordinates[$_, 0] = 0 }
# Loop, from current full row -> row 1 and set currentrow to the one above
ForEach ($TempY in $Y .. 1) {
0 .. $this.Coordinates.GetUpperBound(0) | ForEach-Object {
$this.Coordinates[$_, $TempY] = $this.Coordinates[$_, ($TempY - 1)]
}
}
}
}
}
[void] PrintBoard() {
for ($Y = 0; $Y -le $this.Coordinates.GetUpperBound(1); $Y++) {
[console]::WriteLine(
(
(
0 .. $this.Coordinates.GetUpperBound(0) | ForEach-Object {
$this.Coordinates[$_, $Y]
}
) -join '-' -replace '0', '-'
)
)
}
}
[System.Drawing.Image] DrawImage() {
$Buffer = [System.Drawing.Bitmap]::new($this.Width * $this.BlockSize, $this.Height * $this.BlockSize)
$Graphics = [System.Drawing.Graphics]::FromImage($Buffer)
# Fill buffer with a white background
$Graphics.FillRectangle(
[System.Drawing.SolidBrush]::new($this.Background.Color),
[System.Drawing.Rectangle]::new(0, 0, $Buffer.Width, $Buffer.Height)
)
if (
($this.Background.Burn -and $this.Background.Color.B -ge $this.Background.Max) -or
(!$this.Background.Burn -and $this.Background.Color.B -lt $this.Background.Min)
) {
$this.Background.Burn = !$this.Background.Burn
}
if ($this.Background.Burn) {
$this.Background.Color = [System.Drawing.Color]::FromArgb(255, $this.Background.Color.R, $this.Background.Color.G, ($this.Background.Color.B + 1))
}
else {
$this.Background.Color = [System.Drawing.Color]::FromArgb(255, $this.Background.Color.R, $this.Background.Color.G, ($this.Background.Color.B - 1))
}
if ($null -ne $this.NextShape) {
# Draw NextShape
for ($Y = 0; $Y -le $this.NextShape.Body.GetUpperBound(1); $Y++) {
for ($X = 0; $X -le $this.NextShape.Body.GetUpperBound(0); $X++) {
if ($this.NextShape.Body[$X, $Y]) {
# If this part of the shape body is solid, draw it on the table
$Graphics.FillRectangle(
[System.Drawing.SolidBrush]::new([System.Drawing.Color]::FromArgb(255, ($this.Background.Color.R - 60), ($this.Background.Color.G - 60), ($this.Background.Color.B - 60))),
[System.Drawing.Rectangle]::new(
$this.RelativePoint($X, $Y, $this.NextShape).X, $this.RelativePoint($X, $Y, $this.NextShape).Y,
$this.BlockSize, $this.BlockSize
)
)
$Graphics.FillRectangle(
[System.Drawing.SolidBrush]::new([System.Drawing.Color]::FromArgb(255, ($this.Background.Color.R - 30), ($this.Background.Color.G - 30), ($this.Background.Color.B - 30))),
[System.Drawing.Rectangle]::new(
$this.RelativePoint($X, $Y, $this.NextShape).X, $this.RelativePoint($X, $Y, $this.NextShape).Y,
$this.BlockSize - 2, $this.BlockSize - 2
)
)
}
}
}
}
if ($null -ne $this.ActiveShape) {
# Draw ActiveShape
for ($Y = 0; $Y -le $this.ActiveShape.Body.GetUpperBound(1); $Y++) {
for ($X = 0; $X -le $this.ActiveShape.Body.GetUpperBound(0); $X++) {
if ($this.ActiveShape.Body[$X, $Y]) {
# If this part of the shape body is solid, draw it on the table
$Graphics.FillRectangle(
[System.Drawing.SolidBrush]::new([System.Drawing.Color]::Gray),
[System.Drawing.Rectangle]::new(
$this.RelativePoint($X, $Y, $this.ActiveShape).X, $this.RelativePoint($X, $Y, $this.ActiveShape).Y,
$this.BlockSize, $this.BlockSize
)
)
$Graphics.FillRectangle(
[System.Drawing.SolidBrush]::new($this.ActiveShape.Color),
[System.Drawing.Rectangle]::new(
$this.RelativePoint($X, $Y, $this.ActiveShape).X, $this.RelativePoint($X, $Y, $this.ActiveShape).Y,
$this.BlockSize - 2, $this.BlockSize - 2
)
)
}
}
}
}
# Draw DeadBlocks
for ($Y = 0; $Y -le $this.Coordinates.GetUpperBound(1); $Y++) {
for ($X = 0; $X -le $this.Coordinates.GetUpperBound(0); $X++) {
if ($this.Coordinates[$X, $Y]) {
# Draw a Gray outline
$Graphics.FillRectangle(
[System.Drawing.SolidBrush]::new([System.Drawing.Color]::Gray),
[System.Drawing.Rectangle]::new(
$X * $this.BlockSize, $Y * $this.BlockSize,
$this.BlockSize, $this.BlockSize
)
)
# Fill rest of the rectangle to give 3d block effect
$Graphics.FillRectangle(
[System.Drawing.SolidBrush]::new([System.Drawing.Color]::Silver),
[System.Drawing.Rectangle]::new(
$X * $this.BlockSize, $Y * $this.BlockSize,
$this.BlockSize - 2, $this.BlockSize - 2
)
)
}
}
}
if ($this.Debug) {
for ($Y = 0; $Y -le $this.Coordinates.GetUpperBound(1); $Y++) {
for ($X = 0; $X -le $this.Coordinates.GetUpperBound(0); $X++) {
if ($this.Coordinates[$X, $Y]) {
}
}
}
for ($Y = 0; $Y -le $this.ActiveShape.Body.GetUpperBound(1); $Y++) {
for ($X = 0; $X -le $this.ActiveShape.Body.GetUpperBound(0); $X++) {
if (
$this.Coordinates[($this.ActiveShape.Position.X + $X), ($this.ActiveShape.Position.Y + $Y)] -and
$this.ActiveShape.Body[$X, $Y]
) {
$Graphics.DrawString(
('{0},{1}: {2}' -f
($this.ActiveShape.Position.X + $X),
($this.ActiveShape.Position.Y + $Y),
$this.Coordinates[($this.ActiveShape.Position.X + $X), ($this.ActiveShape.Position.Y + $Y)]
),
[System.Drawing.Font]::new('Segoe UI', 8, [System.Drawing.FontStyle]::Regular),
[System.Drawing.SolidBrush]::new([System.Drawing.Color]::Red),
$this.RelativePoint($X, $Y, $this.ActiveShape).X, $this.RelativePoint($X, $Y, $this.ActiveShape).Y
)
}
}
}
# Draws the ActiveShape Body (5x5 dimensions)
$Graphics.DrawRectangle(
[System.Drawing.Pen]::new($this.ActiveShape.Color, 1),
[System.Drawing.Rectangle]::new(
($this.ActiveShape.Position.X * $this.BlockSize), ($this.ActiveShape.Position.Y * $this.BlockSize),
(($this.ActiveShape.Body.GetUpperBound(0) + 1) * $this.BlockSize) , (($this.ActiveShape.Body.GetUpperBound(1) + 1) * $this.BlockSize)
)
)
# Draws coordinate of the middle body
$Graphics.DrawString( ('Type: {0}' -f $this.ActiveShape.Type ),
[System.Drawing.Font]::new('Segoe UI', 8, [System.Drawing.FontStyle]::Regular),
[System.Drawing.SolidBrush]::new([System.Drawing.Color]::Red),
1, 0 * $this.BlockSize
)
$Graphics.DrawString( ('Color: {0}' -f $this.ActiveShape.Color.Name ),
[System.Drawing.Font]::new('Segoe UI', 8, [System.Drawing.FontStyle]::Regular),
[System.Drawing.SolidBrush]::new([System.Drawing.Color]::Red),
1, 1 * $this.BlockSize
)
$Graphics.DrawString( ('Left: {0}, Right: {1}, Down: {2}' -f $this.ActiveShape.Moveset.Left, $this.ActiveShape.Moveset.Right, $this.ActiveShape.Moveset.Down ),
[System.Drawing.Font]::new('Segoe UI', 8, [System.Drawing.FontStyle]::Regular),
[System.Drawing.SolidBrush]::new([System.Drawing.Color]::Red),
1, 2 * $this.BlockSize
)
}
$Graphics.Dispose()
return $Buffer
}
TetrisBoard($Width, $Height, $BlockSize) {
$this.Coordinates = [int[, ]]::new($Width, $Height)
$this.BlockSize = $BlockSize
$this.Width = $Width
$this.Height = $Height
# Generate random rubble at start
$this.AddLines(4)
}
}
$engine = [Hashtable]::Synchronized(@{})
$engine.Settings = @{
Block = @{
Size = 30
}
Board = @{
Width = 11
Height = 21
}
SpeedMs = 300
CurrentSpeedMs = 300
LoopTime = 100
}
$engine.TetrisBoard = [TetrisBoard]::new($engine.Settings.Board.Width, $engine.Settings.Board.Height, $engine.Settings.Block.Size)
$engine.NextFall = [Datetime]::Now.AddMilliseconds($engine.Settings.CurrentSpeedMs)
$PowerShell = [PowerShell]::Create()
$PowerShell.Runspace = [RunSpaceFactory]::CreateRunspace()
$PowerShell.Runspace.Open()
$PowerShell.Runspace.SessionStateProxy.setVariable('Engine', $engine)
$IAsyncResult = $PowerShell.AddScript( {
[void] [System.Reflection.Assembly]::LoadWithPartialName('System.Drawing')
[void] [System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
[System.Windows.Forms.Application]::EnableVisualStyles()
$engine.Form = [System.Windows.Forms.Form] @{
Text = 'PowerShell Tetris'
ClientSize = [System.Drawing.Size]::new(
($engine.Settings.Block.Size * $engine.Settings.Board.Width),
($engine.Settings.Block.Size * $engine.Settings.Board.Height)
)
Font = [System.Drawing.Font]::new('Segoe UI', 8.25, [System.Drawing.FontStyle]::Regular)
FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::Fixed3D
KeyPreview = $true
MaximizeBox = $false
}
$engine.PictureBox = [System.Windows.Forms.PictureBox] @{
Dock = [System.Windows.Forms.DockStyle]::Fill
SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::StretchImage
}
$engine.PictureBox.Add_MouseClick(
{
Param(
$Object,
[System.Windows.Forms.MouseEventArgs] $MouseEventArgs
)
$engine.InstantiateBlock = [System.Drawing.Point]::new(
($MouseEventArgs.X - ($MouseEventArgs.X % $engine.Settings.Block.Size)) / $engine.Settings.Block.Size,
($MouseEventArgs.Y - ($MouseEventArgs.Y % $engine.Settings.Block.Size)) / $engine.Settings.Block.Size
)
}
)
$engine.Form.Add_KeyUp( {
Param(
$Object,
[System.Windows.Forms.KeyEventArgs] $Key
)
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::Space) {
$engine.Settings.CurrentSpeedMs = $engine.Settings.SpeedMs
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::Enter) {
$engine.SwitchShape = $true
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::X -and $engine.TetrisBoard.Debug) {
$engine.AddLines = Get-Random (1 .. 4)
}
}
)
$engine.Form.Add_KeyDown( {
Param(
$Object,
[System.Windows.Forms.KeyEventArgs] $Key
)
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::Space) {
$engine.Settings.CurrentSpeedMs = $engine.Settings.SpeedMs / 4
}
if ($engine.TetrisBoard.Debug) {
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::K) {
$engine.TetrisBoard.Kill()
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::NumPad8) {
$engine.TetrisBoard.ActiveShape.Position = [System.Drawing.Point]::new(
$engine.TetrisBoard.ActiveShape.Position.X,
$engine.TetrisBoard.ActiveShape.Position.Y - 1
)
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::NumPad4) {
$engine.TetrisBoard.ActiveShape.Position = [System.Drawing.Point]::new(
$engine.TetrisBoard.ActiveShape.Position.X - 1,
$engine.TetrisBoard.ActiveShape.Position.Y
)
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::NumPad6) {
$engine.TetrisBoard.ActiveShape.Position = [System.Drawing.Point]::new(
$engine.TetrisBoard.ActiveShape.Position.X + 1,
$engine.TetrisBoard.ActiveShape.Position.Y
)
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::NumPad2) {
$engine.TetrisBoard.ActiveShape.Position = [System.Drawing.Point]::new(
$engine.TetrisBoard.ActiveShape.Position.X,
$engine.TetrisBoard.ActiveShape.Position.Y + 1
)
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::NumPad7) {
$engine.TetrisBoard.ActiveShape.Rotate($false)
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::NumPad9) {
$engine.TetrisBoard.ActiveShape.Rotate($true)
}
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::P) {
$engine.Debug = $true
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::Left) {
$engine.XMove = [System.Drawing.Point]::new(-1, 0)
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::Right) {
$engine.XMove = [System.Drawing.Point]::new(1, 0)
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::Up) {
$engine.Rotate = $true
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::Down) {
$engine.Rotate = $false
}
if ($Key.KeyCode -eq [System.Windows.Forms.Keys]::R) {
$engine.Renew = $true
}
}
)
$engine.Form.Controls.Add($engine.PictureBox)
$engine.Form.Add_Resize( { if ($engine.Dispose) { $engine.Form.Close() } } )
$engine.Form.Add_Load( { $engine.Form.Activate() })
$engine.Form.ShowDialog()
$engine.Form.Dispose()
}
).BeginInvoke()
while (-not $IAsyncResult.IsCompleted) {
if ($null -ne $engine.PictureBox) {
$time = Measure-Command {
if ($null -ne $engine.AddLines -and $engine.TetrisBoard.Debug) {
Write-Host ('Adding {0} lines' -f $engine.AddLines)
$engine.TetrisBoard.AddLines($engine.AddLines)
$engine.AddLines = $null
}
if ($null -ne $engine.SwitchShape -and $null -ne $engine.TetrisBoard.ActiveShape -and $null -ne $engine.TetrisBoard.NextShape) {
$TempShape = $engine.TetrisBoard.ActiveShape
$engine.TetrisBoard.ActiveShape = $engine.TetrisBoard.NextShape
$engine.TetrisBoard.NextShape = $TempShape
$TempShape = $null
$engine.SwitchShape = $null
}
if ($null -ne $engine.InstantiateBlock -and $engine.TetrisBoard.Debug) {
$engine.TetrisBoard.Coordinates[$engine.InstantiateBlock.X, $engine.InstantiateBlock.Y] = !$engine.TetrisBoard.Coordinates[$engine.InstantiateBlock.X, $engine.InstantiateBlock.Y]
$engine.InstantiateBlock = $null
}
if ($null -ne $engine.XMove) {
$engine.TetrisBoard.UpdateMoveset()
if (
($engine.XMove.X -gt 0 -and $engine.TetrisBoard.ActiveShape.Moveset.Right) -or
($engine.XMove.X -lt 0 -and $engine.TetrisBoard.ActiveShape.Moveset.Left)
) {
$engine.TetrisBoard.ActiveShape.Position = [System.Drawing.Point]::new(
($engine.TetrisBoard.ActiveShape.Position.X + $engine.XMove.X),
$engine.TetrisBoard.ActiveShape.Position.Y + $engine.XMove.Y
)
}
$engine.XMove = $null
}
if ($null -ne $engine.Debug) {
$engine.TetrisBoard.Debug = !$engine.TetrisBoard.Debug
$engine.Debug = $null
}
if ($null -ne $engine.Renew) {
$engine.TetrisBoard.ActiveShape = $null
$engine.Renew = $null
}
if ($null -ne $engine.Rotate -and $null -ne $engine.TetrisBoard.ActiveShape) {
$engine.TetrisBoard.UpdateMoveset()
$engine.TetrisBoard.ActiveShape.Rotate($engine.Rotate, $engine.TetrisBoard.Coordinates)
$engine.Rotate = $null
}
if ([Datetime]::Now -ge $engine.NextFall -and $null -ne $engine.TetrisBoard.ActiveShape) {
$engine.TetrisBoard.UpdateMoveset()
if ($engine.TetrisBoard.ActiveShape.Moveset.Down) {
$engine.TetrisBoard.ActiveShape.Position = [System.Drawing.Point]::new(
($engine.TetrisBoard.ActiveShape.Position.X),
$engine.TetrisBoard.ActiveShape.Position.Y + 1
)
}
else {
$engine.TetrisBoard.Kill()
}
$engine.NextFall = [Datetime]::Now.AddMilliseconds($engine.Settings.CurrentSpeedMs)
}
if ($engine.TetrisBoard.LostGame()) {
$engine.TetrisBoard = [TetrisBoard]::new($engine.Settings.Board.Width, $engine.Settings.Board.Height, $engine.Settings.Block.Size)
}
if ($null -eq $engine.TetrisBoard.ActiveShape) {
$engine.TetrisBoard.NewShape()
}
$engine.TetrisBoard.UpdateMoveset()
$engine.TetrisBoard.ClearLines()
$engine.PictureBox.Image = $engine.TetrisBoard.DrawImage()
}
if ($time.TotalMilliseconds -lt $engine.Settings.LoopTime) {
[System.Threading.Thread]::Sleep(($engine.Settings.LoopTime - $time.TotalMilliseconds))
}
}
}