Add extensive comments to logic.bqn

This commit is contained in:
Rampoina 2023-03-05 17:55:25 +01:00
parent a894380402
commit 37d75d3087
1 changed files with 102 additions and 43 deletions

145
logic.bqn
View File

@ -1,61 +1,123 @@
#!/usr/bin/env BQN
# SPDX-License-Identifier: AGPL-3.0-or-later
# SPDX-FileCopyrightText: 2023 Rampoina <rampoina@protonmail.com>
Game{
𝕊 levelPathcharscolors:
moves00 # list of moves, each move is a direction, we start without moving
FindIdx,SplitOnEmpty•Import "utils.bqn"
Game{ # The Game function creates a game object
𝕊 levelPathdcharscharscolors: # from parameters:
# levelPath: the path of the file containing the levels
# dchars: the characters to use for drawing
# colors: a list with colors
# Game representation:
# -------------------------------------------------------------------------------
# The game has the following objects represented as consecutive integers:
floor,player,box,machine,pmachine,wall,lmirror,rmirror,hbeam,vbeam,xbeam,llaser,rlaser,ulaser,dlaserchars
beamshbeamvbeamxbeam
mirrorslmirrorrmirror
lasersllaserrlaserulaserdlaser
mirrorslmirrorrmirror # the mirrors to reflect
beamshbeamvbeamxbeam # the laser beams
lasersllaserrlaserulaserdlaser # shot by the laser
# Each with every possible orientation
# There are *movable* objects like the following:
movablesplayerboxmirrors # player, box and mirrors
opaqueplayerboxmachinewalllasers # non laser reflecting
emptiesfloorbeams # floor and laser beams
# And *opaque* objects which don't reflect lasers:
opaqueplayerboxmachinewalllasers
# *Empty* objects can contain other ones on top:
emptiesfloorbeams
cols(chars)<(colors) # start with all glyphs being the default color
cols (1colors)˙(pmachine)
cols (2colors)¨(mirrors)
cols (3colors)¨(beams)
Colorize{𝕩˜cols˜chars𝕩} # 𝕩: character | Turn character into color+character
lTiles{𝕩movables ? 𝕩floor; 𝕩}¨chars # list of all the possible tiles as lists of numbers
# Turns the level from ascii strings into a 2d matrix of lists
Ascii2Matrix{(chars𝕩)lTiles}¨(˝·¬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)
# Move 𝕩 | 𝕩: ⟨⟨1,0⟩,⟨0⟩⟩ (2 tiles) | result: ⟨⟨0⟩,⟨1,0⟩⟩
# Move the first object in the first tile to the second tile.
# Only move Movable tile -> Empty tile
# Colors:
# The parameter 'color' is a list of colors passed to the Game function to alter the
cols(chars)<(colors) # base color,
cols (1colors)˙(pmachine) # the color for the powered machine
cols (2colors)¨(mirrors) # the color for the mirrors
cols (3colors)¨(beams) # the color for the laser beams
# We use a list of game objects (ints) to represent each tile
lTiles{𝕩movables ?
𝕩floor; # the movables are on top of the floor (list of 2 elements)
𝕩 # And the rest are a list of just that element
}¨chars
# We transform each character into its tile representation and we transform
# it into a 2d matrix
# the matrix is padded to ensure that that we can always get 3 tiles
# centered on the player and pointing to the current direction
Ascii2Matrix{(chars𝕩)lTiles}¨(˝·¬2+) # 𝕩 : Matrix of characters
# Rules:
# -------------------------------------------------------------------------------
#
# - The player can push but not pull any movable object one tile away in the
# current direction to an empty tile:
# 𝕩: ⟨⟨1,0⟩,⟨0⟩⟩ (2 tiles) | result: ⟨⟨0⟩,⟨1,0⟩⟩
# (Try to) Move the first object in the first tile to the second tile.
# Only move *movable* tile → *empty* tile
# the second tile can't be a movable object because we moved it previously
# if it is it means that the object was unmovable (next to a wall) so we do nothing
Move{ab:1a,(a)b}{´(movablesempties)<¨𝕩}
# 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
# 𝕩: ⟨⟨1,0⟩,⟨2,0⟩,⟨0,0)⟩ (3 tiles) | result: ⟨⟨0⟩,⟨1,0⟩,⟨2,0)⟩
# Given 3 tiles try to Push the second tile (possibly a movable object)
# and afterwards try to move the first one (the player) if possible
PushMove(2)Move(1)
FindIdx/()
# 𝕩: 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)
# We (try to) push the tile in front of the player
Step{Push((𝕨 Tiles player FindIdx ¨𝕩))𝕩} # 𝕨 S 𝕩 | 𝕨: direction | 𝕩:level | Step the game
# - The lasers shoot lasers that get intercepted by opaque objects and
# bounce on mirrors:
# w‿d Bounce x | x: map | w‿d: w: current position, d: direction of the laser
# Calculates the bounces of a laser beam recursively
Bounce{(wd)S x:{
opaque˜wx?(machine=wx)x,pmachine˙(w)x@; # laser hits a non-mirror
empties˜wx ? # Empty space
w+d,dS{((×d)hbeamhbeamxbeamxbeam,vbeamxbeamvbeamxbeam)˜floorhbeamvbeamxbeam𝕩}(w)x; # Draw laser and recurse
# laser hits a mirror
dd×-¬lmirror=wx # calculate the mirror bounce direction
w+d,dS x } # recurse to the next position
opaque˜wx? # When the beam touches an opaque object (not a mirror):
(machine=wx)x, # we do nothing if it doesn't touch a machine
pmachine˙(w)x # and if it does we change it to a powered machine
@;
empties˜wx ? # When the beam passes through an empty space:
# we draw the laser beam and recurse to the next:
w+d,dS{ # we choose the type of laser beam to draw
cTile(floorhbeamvbeamxbeam𝕩) # depending on the current tile:
# floor hbeam vbeam xbeam | floor hbeam vbeam xbeam
cBeam ((×d) hbeamhbeamxbeamxbeam , vbeamxbeamvbeamxbeam)
# and beam direction Horizontal | Vertical
cTilecBeam
}(w)x;
# When the beam touches a mirror:
dd×-¬lmirror=wx # calculate the mirror bounce direction
w+d,dS x # and recurse to the next position
}
}
# Shoot 𝕩 | 𝕩: map | calculates the bounces for each laser
Shoot{𝕩 {𝕨Bounce´𝕩} <0¯1,<01,<¯10,<10(˜¨+)¨ FindIdx(¨𝕩)¨ lasers}
Step{Push((𝕨 Tiles player FindIdx ¨𝕩))𝕩} # 𝕨 S 𝕩 | 𝕨: direction | 𝕩:level | Step the game
DrawLevel{´¨<˘Colorize¨chars˜+´¨Shoot 𝕨 Step´ 𝕩} # 𝕨 Draw 𝕩 | 𝕨: levels | 𝕩: moves | Draw the game in ASCII
Win{¬´˝machine=¨Shoot 𝕩}# W 𝕩 | 𝕩: level | [W]in condition, no unpowered machines after shooting laser
# - The Player wins when all machines are powered:
Win{¬´˝machine=¨Shoot 𝕩}# 𝕩: level | Win condition, no unpowered machines after shooting laser
# Drawing:
# -------------------------------------------------------------------------------
Colorize{𝕩˜cols˜dchars𝕩} # 𝕩: character | Turn character into color+character
DrawLevel{´¨<˘Colorize¨dchars˜+´¨Shoot 𝕨 Step´ 𝕩} # 𝕨 Draw 𝕩 | 𝕨: levels | 𝕩: moves | Draw the game in ASCII
# State and state mutating functions:
# -------------------------------------------------------------------------------
moves00 # list of moves, each move is a direction, we start without moving
currentLevel0
levelsAscii2Matrix¨>¨SplitOnEmpty•FLines levelPath # Load file containing levels
Next{movesmoves<𝕩}
Undo{𝕊:moves(-1<)moves}
Draw{𝕊:•Out¨ (currentLevellevels) DrawLevel moves}
@ -63,7 +125,4 @@ Game⇐{
Reset{𝕊:moves00}
NextLevel{𝕊:currentLevelcurrentLevel+1Reset @}
Over{𝕊:currentLevel<levels}
SplitOnEmpty{𝕩˜(-˜+`׬)0=¨𝕩}
levelsAscii2Matrix¨>¨SplitOnEmpty•FLines levelPath # Load file containing levels
currentLevel0
}