Skip to content

Instantly share code, notes, and snippets.

@eugrus
Created January 28, 2025 14:13
Show Gist options
  • Save eugrus/01217ec864e0e9dc926d298870dfe98b to your computer and use it in GitHub Desktop.
Save eugrus/01217ec864e0e9dc926d298870dfe98b to your computer and use it in GitHub Desktop.
[System.Console]::CursorVisible = $false
Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {
[System.Console]::CursorVisible = $true
} | Out-Null
$width = 10
$height = 20
$script:field = New-Object 'object[]' $height
for ($i = 0; $i -lt $height; $i++) {
$script:field[$i] = New-Object 'int[]' $width
}
$shapes = @(
@( @(1,1,1,1) ),
@( @(1,1), @(1,1) ),
@( @(0,1,0), @(1,1,1) ),
@( @(1,0), @(1,0), @(1,1) ),
@( @(0,1), @(0,1), @(1,1) ),
@( @(1,0), @(1,1), @(0,1) ),
@( @(0,1), @(1,1), @(1,0) )
)
$score = 0
$gameOver = $false
$currentShape = $null
$nextShape = $null
$lastUpdate = [DateTime]::Now
$fallInterval = 800
$previousFrame = @()
for ($i = 0; $i -lt $height; $i++) {
$previousFrame += @("")
}
function Get-NewShape {
$index = Get-Random -Minimum 0 -Maximum $shapes.Length
$shape = $shapes[$index]
return @{
Shape = $shape
X = [math]::Floor(($width - $shape[0].Length) / 2)
Y = 0
}
}
function Test-Collision {
param($shape, $x, $y)
for ($i = 0; $i -lt $shape.Shape.Length; $i++) {
for ($j = 0; $j -lt $shape.Shape[$i].Length; $j++) {
if ($shape.Shape[$i][$j] -ne 0) {
$fieldX = $x + $j
$fieldY = $y + $i
if ($fieldX -lt 0 -or $fieldX -ge $width -or $fieldY -ge $height) {
return $true
}
if ($fieldY -ge 0 -and $script:field[$fieldY][$fieldX] -ne 0) {
return $true
}
}
}
}
return $false
}
function Rotate-Shape {
param($shape)
$newShape = @()
$rows = $shape.Shape.Length
$cols = $shape.Shape[0].Length
for ($i = 0; $i -lt $cols; $i++) {
$newRow = @()
for ($j = $rows - 1; $j -ge 0; $j--) {
$newRow += $shape.Shape[$j][$i]
}
$newShape += ,$newRow
}
return @{
Shape = $newShape
X = $shape.X
Y = $shape.Y
}
}
function Draw-Field {
$output = ""
for ($y = 0; $y -lt $height; $y++) {
$line = ""
for ($x = 0; $x -lt $width; $x++) {
$cell = $script:field[$y][$x]
$isCurrent = $false
if ($currentShape) {
$sy = $y - $currentShape.Y
$sx = $x - $currentShape.X
if ($sy -ge 0 -and $sy -lt $currentShape.Shape.Length -and
$sx -ge 0 -and $sx -lt $currentShape.Shape[$sy].Length) {
$isCurrent = $currentShape.Shape[$sy][$sx] -ne 0
}
}
if ($cell -ne 0 -or $isCurrent) {
$line += "[]"
} else {
$line += " "
}
}
$output += $line + "`n"
}
[System.Console]::SetCursorPosition(0, 0)
[System.Console]::Write($output)
[System.Console]::WriteLine("Score: $score")
$remainingLines = [Console]::WindowHeight - $height - 2
if ($remainingLines -gt 0) {
[System.Console]::WriteLine((" " * [Console]::WindowWidth) * $remainingLines)
[System.Console]::SetCursorPosition(0, 0)
}
}
$currentShape = Get-NewShape
$nextShape = Get-NewShape
while (-not $gameOver) {
if ([Console]::KeyAvailable) {
$key = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
switch ($key.VirtualKeyCode) {
37 {
if (-not (Test-Collision $currentShape ($currentShape.X - 1) $currentShape.Y)) {
$currentShape.X--
}
}
39 {
if (-not (Test-Collision $currentShape ($currentShape.X + 1) $currentShape.Y)) {
$currentShape.X++
}
}
38 {
$rotated = Rotate-Shape $currentShape
if (-not (Test-Collision $rotated $rotated.X $rotated.Y)) {
$currentShape = $rotated
}
}
40 {
$fallInterval = 50
}
}
}
if (([DateTime]::Now - $lastUpdate).TotalMilliseconds -ge $fallInterval) {
if (-not (Test-Collision $currentShape $currentShape.X ($currentShape.Y + 1))) {
$currentShape.Y++
} else {
for ($i = 0; $i -lt $currentShape.Shape.Length; $i++) {
for ($j = 0; $j -lt $currentShape.Shape[$i].Length; $j++) {
if ($currentShape.Shape[$i][$j] -ne 0) {
$y = $currentShape.Y + $i
$x = $currentShape.X + $j
if ($y -lt 0) {
$gameOver = $true
break
}
$script:field[$y][$x] = 1
}
}
}
$lines = 0
$currentY = $height - 1
while ($currentY -ge 0) {
$isFull = $true
for ($xCheck = 0; $xCheck -lt $width; $xCheck++) {
if ($script:field[$currentY][$xCheck] -eq 0) {
$isFull = $false
break
}
}
if ($isFull) {
$lines++
for ($shiftY = $currentY; $shiftY -gt 0; $shiftY--) {
for ($xCopy = 0; $xCopy -lt $width; $xCopy++) {
$script:field[$shiftY][$xCopy] = $script:field[$shiftY - 1][$xCopy]
}
}
for ($xClear = 0; $xClear -lt $width; $xClear++) {
$script:field[0][$xClear] = 0
}
} else {
$currentY--
}
}
$score += switch ($lines) {
1 { 40 }
2 { 100 }
3 { 300 }
4 { 1200 }
default { 0 }
}
$currentShape = $nextShape
$nextShape = Get-NewShape
if (Test-Collision $currentShape $currentShape.X $currentShape.Y) {
$gameOver = $true
}
}
$lastUpdate = [DateTime]::Now
$fallInterval = 800
}
Draw-Field
Start-Sleep -Milliseconds 20
}
Write-Host "Game Over! Final score: $score"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment