pause for tetris ;)
This commit is contained in:
parent
f24c7d2715
commit
222a653040
@ -6,6 +6,7 @@
|
|||||||
- Use `docs/ai_stdlib_reference.md` for default runtime/module APIs and stdlib surface.
|
- Use `docs/ai_stdlib_reference.md` for default runtime/module APIs and stdlib surface.
|
||||||
- Treat `LYNG_AI_SPEC.md` and older docs as secondary if they conflict with the two files above.
|
- Treat `LYNG_AI_SPEC.md` and older docs as secondary if they conflict with the two files above.
|
||||||
- Prefer the shortest clear loop: use `for` for straightforward iteration/ranges; use `while` only when loop state/condition is irregular or changes in ways `for` cannot express cleanly.
|
- Prefer the shortest clear loop: use `for` for straightforward iteration/ranges; use `while` only when loop state/condition is irregular or changes in ways `for` cannot express cleanly.
|
||||||
|
- In Lyng code, slice strings with range indexing (`text[a..<b]`, `text[..<n]`, `text[n..]`) and avoid Java/Kotlin-style `substring(...)`.
|
||||||
|
|
||||||
## Lyng-First API Declarations
|
## Lyng-First API Declarations
|
||||||
- Use `.lyng` declarations as the single source of truth for Lyng-facing API docs and types (especially module extern declarations).
|
- Use `.lyng` declarations as the single source of truth for Lyng-facing API docs and types (especially module extern declarations).
|
||||||
|
|||||||
@ -8,7 +8,8 @@
|
|||||||
* - Up arrow or W: rotate
|
* - Up arrow or W: rotate
|
||||||
* - Down arrow or S: soft drop
|
* - Down arrow or S: soft drop
|
||||||
* - Space: hard drop
|
* - Space: hard drop
|
||||||
* - Q or Escape: quit
|
* - P or Escape: pause
|
||||||
|
* - Q: quit
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import lyng.io.console
|
import lyng.io.console
|
||||||
@ -66,6 +67,7 @@ class GameState(
|
|||||||
var level = 1
|
var level = 1
|
||||||
var running = true
|
var running = true
|
||||||
var gameOver = false
|
var gameOver = false
|
||||||
|
var paused = false
|
||||||
}
|
}
|
||||||
class LoopFrame(val resized: Bool, val originRow: Int, val originCol: Int) {}
|
class LoopFrame(val resized: Bool, val originRow: Int, val originCol: Int) {}
|
||||||
|
|
||||||
@ -286,7 +288,8 @@ fun render(
|
|||||||
panel.add("W/Up: rotate")
|
panel.add("W/Up: rotate")
|
||||||
panel.add("S/Down: drop")
|
panel.add("S/Down: drop")
|
||||||
panel.add("Space: hard drop")
|
panel.add("Space: hard drop")
|
||||||
panel.add("Q/Esc: quit")
|
panel.add("P/Esc: pause")
|
||||||
|
panel.add("Q: quit")
|
||||||
|
|
||||||
val frameLines: List<String> = []
|
val frameLines: List<String> = []
|
||||||
|
|
||||||
@ -324,6 +327,62 @@ fun render(
|
|||||||
frameLines
|
frameLines
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun fitLine(line: String, width: Int): String {
|
||||||
|
val maxLen = if (width > 0) width else 0
|
||||||
|
if (maxLen <= 0) return ""
|
||||||
|
if (line.size >= maxLen) return line[..<maxLen]
|
||||||
|
line + repeatText(" ", maxLen - line.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun renderPauseOverlay(
|
||||||
|
originRow: Int,
|
||||||
|
originCol: Int,
|
||||||
|
boardW: Int,
|
||||||
|
boardH: Int,
|
||||||
|
): Void {
|
||||||
|
val contentWidth = boardW * 2 + 2 + 3 + PANEL_WIDTH
|
||||||
|
val contentHeight = boardH + 1
|
||||||
|
|
||||||
|
val lines: List<String> = []
|
||||||
|
lines.add("PAUSED")
|
||||||
|
lines.add("")
|
||||||
|
lines.add("Any key: continue game")
|
||||||
|
lines.add("Esc: exit game")
|
||||||
|
lines.add("")
|
||||||
|
lines.add("Move: A/D or arrows")
|
||||||
|
lines.add("Rotate: W or Up")
|
||||||
|
lines.add("Drop: S/Down, Space hard drop")
|
||||||
|
|
||||||
|
var innerWidth = 0
|
||||||
|
for (line in lines) {
|
||||||
|
if (line.size > innerWidth) innerWidth = line.size
|
||||||
|
}
|
||||||
|
innerWidth += 4
|
||||||
|
val maxInner = max(12, contentWidth - 2)
|
||||||
|
if (innerWidth > maxInner) innerWidth = maxInner
|
||||||
|
if (innerWidth % 2 != 0) innerWidth--
|
||||||
|
|
||||||
|
val boxWidth = innerWidth + 2
|
||||||
|
val boxHeight = lines.size + 2
|
||||||
|
|
||||||
|
val left = originCol + max(0, (contentWidth - boxWidth) / 2)
|
||||||
|
val top = originRow + max(0, (contentHeight - boxHeight) / 2)
|
||||||
|
|
||||||
|
val topBorder = UNICODE_TOP_LEFT + repeatText(UNICODE_HORIZONTAL, innerWidth / 2) + UNICODE_TOP_RIGHT
|
||||||
|
val bottomBorder = UNICODE_BOTTOM_LEFT + repeatText(UNICODE_HORIZONTAL, innerWidth / 2) + UNICODE_BOTTOM_RIGHT
|
||||||
|
|
||||||
|
Console.moveTo(top, left)
|
||||||
|
Console.write(topBorder)
|
||||||
|
|
||||||
|
for (i in 0..<lines.size) {
|
||||||
|
Console.moveTo(top + 1 + i, left)
|
||||||
|
Console.write(UNICODE_VERTICAL + fitLine(" " + lines[i], innerWidth) + UNICODE_VERTICAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.moveTo(top + boxHeight - 1, left)
|
||||||
|
Console.write(bottomBorder)
|
||||||
|
}
|
||||||
|
|
||||||
fun waitForMinimumSize(minCols: Int, minRows: Int): Object {
|
fun waitForMinimumSize(minCols: Int, minRows: Int): Object {
|
||||||
while (true) {
|
while (true) {
|
||||||
val g = Console.geometry()
|
val g = Console.geometry()
|
||||||
@ -471,7 +530,22 @@ if (!Console.isSupported()) {
|
|||||||
|
|
||||||
fun applyKeyInput(s: GameState, key: String): Void {
|
fun applyKeyInput(s: GameState, key: String): Void {
|
||||||
try {
|
try {
|
||||||
if (key == "__CTRL_C__" || key == "q" || key == "Q" || key == "Escape") {
|
if (key == "__CTRL_C__") {
|
||||||
|
s.running = false
|
||||||
|
}
|
||||||
|
else if (s.paused) {
|
||||||
|
if (key == "Escape") {
|
||||||
|
s.running = false
|
||||||
|
} else {
|
||||||
|
s.paused = false
|
||||||
|
prevFrameLines = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (key == "p" || key == "P" || key == "Escape") {
|
||||||
|
s.paused = true
|
||||||
|
prevFrameLines = []
|
||||||
|
}
|
||||||
|
else if (key == "q" || key == "Q") {
|
||||||
s.running = false
|
s.running = false
|
||||||
}
|
}
|
||||||
else if (key == "ArrowLeft" || key == "a" || key == "A") {
|
else if (key == "ArrowLeft" || key == "a" || key == "A") {
|
||||||
@ -653,7 +727,9 @@ if (!Console.isSupported()) {
|
|||||||
}
|
}
|
||||||
prevOriginRow = frameData.originRow
|
prevOriginRow = frameData.originRow
|
||||||
prevOriginCol = frameData.originCol
|
prevOriginCol = frameData.originCol
|
||||||
frame = advanceGravity(state, frame)
|
if (!state.paused) {
|
||||||
|
frame = advanceGravity(state, frame)
|
||||||
|
}
|
||||||
prevFrameLines = render(
|
prevFrameLines = render(
|
||||||
state,
|
state,
|
||||||
board,
|
board,
|
||||||
@ -664,6 +740,9 @@ if (!Console.isSupported()) {
|
|||||||
frameData.originCol,
|
frameData.originCol,
|
||||||
useColor
|
useColor
|
||||||
)
|
)
|
||||||
|
if (state.paused) {
|
||||||
|
renderPauseOverlay(frameData.originRow, frameData.originCol, boardW, boardH)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Console.flush()
|
Console.flush()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user