Sokobqn/soko.bqn

77 lines
3.5 KiB
BQN
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env BQN
# SPDX-License-Identifier: AGPL-3.0-or-later
# SPDX-FileCopyrightText: 2022 Rampoina <rampoina@protonmail.com>
#
# Sokobqn
# The level is a 2d matrix of lists (tiles)
# Each list contains the objects of the game:
# 0: floor, 1: player, 2: box, 3: goal, 4: wall
# 4: player on goal, 5: box on goal
#
# Example: ASCII:
# ┌─ ┌─
# ╵ ⟨ 4 ⟩ ⟨ 4 ⟩ ⟨ 4 ⟩ ⟨ 4 ⟩ ⟨ 4 ⟩ ╵"#####
# ⟨ 4 ⟩ ⟨ 1 0 ⟩ ⟨ 2 0 ⟩ ⟨ 0 ⟩ ⟨ 4 ⟩ #@*.#
# ⟨ 4 ⟩ ⟨ 4 ⟩ ⟨ 4 ⟩ ⟨ 4 ⟩ ⟨ 4 ⟩ #####"
# ┘ ┘
moves00 # list of moves, each move is a direction, we start without moving
chars" @$.+*#" # legal characters
SplitOnEmpty{𝕩˜(-˜+`׬)0=¨𝕩}
Ascii2Matrix{(chars𝕩)0,10,20,3,13,23,6}¨(˝·¬2+)
# 𝕨 Tiles 𝕩 | 𝕩: object coordinate (3‿1) | 𝕨: direction vector (¯1‿0)
# result: ⟨ ⟨ 3 1 ⟩ ⟨ 2 1 ⟩ ⟨ 1 1 ⟩ ⟩
# returns 3 tiles in the specified direction from the
Tiles{𝕩,𝕩+𝕨,𝕩+2×𝕨} # given object (including itself)
Player{/()1¨𝕩} # Player 𝕩 | 𝕩:level | returns the coordinate of the [P]layer
# Move 𝕩 | 𝕩: ⟨⟨1,0⟩,⟨0⟩⟩ (2 tiles) | result: ⟨⟨0⟩,⟨1,0⟩⟩
# Move the first object in the first tile to the second tile.
# Only move Player/Box -> Floor/Goal
# the second tile can't be a box because we moved it previously
# if it is it means that the box was unmovable (next to a wall) so we do nothing
Move{ab:1a,(a)b}{´(1203)<¨𝕩}
# Push 𝕩 | 𝕩: ⟨⟨1,0⟩,⟨2,0⟩,⟨0,0)⟩ (3 tiles) | result: ⟨⟨0⟩,⟨1,0⟩,⟨2,0)⟩
# Given 3 tiles try to [P]ush the second tile (possible box)
# and afterwards try to move the first one (player) if possible
PushMove(2)Move(1)
S{Push((𝕨 Tiles Player 𝕩 ))𝕩} # 𝕨 S 𝕩 | 𝕨: direction | 𝕩:level | step the game
Draw{chars˜+´¨𝕨 S´ 𝕩} # Draw 𝕩 | 𝕩: moves | Draw the game in ASCII
W{(2¨¨𝕩) =(+´) (<23)¨𝕩} # W 𝕩 | 𝕩: level | [W]in condition
N{movesmoves<𝕩}
Undo{𝕊:moves(-1<)moves}
While {𝕨{𝕊𝔾𝔽𝕩}𝕩@}´
# Main loop
# Load file containing levels
levelsAscii2Matrix¨>¨SplitOnEmpty•FLines "levels"
currentLevel0
•term.RawMode 1 # set terminal to raw mode
•Out "[?25l" # Cursor to origin, hide it and clear screen
clear""
While {𝕤currentLevel<levels}{𝕤 # Loop until the user wins
•Out ""
•Out "Level: "•Repr 1+currentLevel
•Out "7"
•Out "Press key"
•Out˘ (currentLevellevels) Draw moves
key•term.CharB @
{𝕤N ("hjkl"=key)/0¯1,10,¯10,01}(key"hjkl")@
{𝕤Undo @}(key='u')@
{𝕤•Out "[?12l[?25h"•Exit 0}(key='q')@
{𝕤clear""}(((1+>(1+101))¯1+moves)key='u')@
•Out "8"
{𝕤•Out clear"Press key"}(key"hjklu")@
{𝕤•Out "Wrong key"}(¬key"hjkluq")@
•Out˘ (currentLevellevels) Draw moves
•Out "Moves: "•Repr ¯1+moves
{𝕤•Out ""currentLevelcurrentLevel+1moves00}(W (currentLevellevels) S´moves)@
}
•Out "Well played, you win!"
•Out "[?12l[?25h"