Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
Tags

Bruno Logerfo

1
Posts
1
Topics
A member registered Jan 15, 2016

Recent community posts

(5 edits)

Here is my solution for the self hosting problem, inspired by CakeEaterGames' version.
It takes 893 cycles and 193 bytes. His solution is faster (848 cycles), but reads more memory (206 bytes). It's probably still sub-optimal, so any improvement suggestion is welcome.
As specified, the solution can handle programs up to 21 bytes, but 40 bytes of memory are un-used, so I think it could actually handle programs up to 61 bytes if pre-allocated.
I wish I could write a test for that. Now that the game is published on Steam, having puzzles with player written test cases to publish on their community workshop would be fantastic.

; Parse a program containing .data directives and subleq
; instructions, then execute that program.
;
; All addresses used by the input program should be isolated from
; your program's address space.
;
; As in any other program, if the program writes to address 254
; (@OUT; signed value: -2), that value should be directly written out.
;
; If the program branches to address 255 (@HALT; signed value: -1),
; then the program is done. Start over from scratch with the next
; input program.
;
; The compiled size of each input program is <= 21 bytes.
;
; As in previous tasks, the .data directive will always have exactly
; 1 value and subleq instructions will specify exactly 3 addresses
; (separated by spaces only).
;
; Additionally, the input programs will not declare or use any labels
; or variables. The only built-in addresses that will be used will be
; referenced by address instead of label (e.g. "254" will be used but
; "@OUT" will not).
;
; allocate 21 bytes of memory for the program
@program:
subleq 0, 0, @start
subleq 0, 0, 0
subleq 0, 0, 0
subleq 0, 0, 0
subleq 0, 0, 0
subleq 0, 0, 0
subleq 0, 0, 0
;
@start:
subleq @input, @IN
subleq @value, @value
subleq @value, @input, @program ; execute if end of string
subleq @input, @input
subleq @value, @break, @start ; skip empty lines
subleq @number, @number
; read useless characters
subleq @IN, @IN
subleq @IN, @IN
subleq @IN, @IN
subleq @IN, @IN
subleq @input, @IN
subleq @input, @space, @next ; skip a char (subleq has one more char than data)
subleq @IN, @IN
@next:
subleq @target+2, @target+2
subleq @input, @input
subleq @input, @IN
subleq @value, @value
subleq @value, @input
; testing chars from lower to greater ascii code by their diff
subleq @value, @break, @push_line ; '\n' (10)
subleq @value, @_22, @push_space ; ' ' (22)
subleq @value, @_13, @negative ; ' '-' (45)
subleq @value, @three ; '0' (48)
; AB = 10A + B
; 'A' might be greater than 10
; it's guaranteed no out of range number will be input
subleq @input, @input
subleq @input, @number
subleq @count, @count
subleq @count, @eight
@loop:
subleq @number, @input
subleq @count, @n_one, @loop
subleq @number, @value
subleq @input, @input, @next
;
@negative:
subleq @n, @n_one
subleq @input, @input, @next
;
@push_line:
subleq @target+2, @start_address
subleq @input, @input, @push
;
@push_space:
subleq @target+2, @next_address
subleq @input, @input, @push
;
@push:
; clear the address before writing
; it's guaranteed no unallocated memory will be read or written by the input programs
subleq @program, @program
subleq @value, @value
subleq @value, @number
subleq @n, @OUT, @skip_negative ; @OUT reads as zero
; negative
subleq @n, @n
subleq @count, @count
subleq @count, @value
subleq @number, @count
subleq @number, @count
; short-circuit to @push2? faster, but costs more memory
@skip_negative:
subleq @value, @n_one, @maybe255
@push2:
subleq @program, @number
@shift:
; right shift writing addresses by one byte
subleq @push, @n_one
subleq @push+1, @n_one
subleq @push2, @n_one
@target:
; if called from @push_line, jumps to @start
; if called from @push_space, jumps to @next
subleq @number, @number, @next
;
@maybe255:
subleq @value, @n_one, @push2
subleq @number, @number
; replace @HALT (255) with address of @halt (labels are case sensitive)
; it's guaranteed 255 will only be input as subleq's arg3
; .data, arg1 and arg2 will never be 255
subleq @number, @halt_address
subleq @value, @value, @push2
;
@halt:
; resets pointers
subleq @push, @push
subleq @push+1, @push+1
subleq @push2, @push2
subleq @input, @input, @start
;
; variables
@input: .data 0
@n: .data 0
@number: .data 0
@count: .data 0
@value: .data 0
;
; constants
@halt_address: .data @halt ; positive because is higher than 127
@start_address: .data -@start
@next_address: .data -@next
@n_one: .data -1
@eight: .data 8
@three: .data 3 ; '0' (48) - '-' (45)
@break: .data '\n' ; 10
@_13: .data 13 ; '-' (45) - ' ' (32)
@_22: .data 22 ; ' ' (32) - '\n' (10)
@space: .data ' ' ; 32
;