(uiop:define-package :sloppy-text/impl (:export #:keeppenning #:list-of-lines #:phlog #:lines) (:nicknames :sloppy-text)) #| scroll to the bottom of the file |# (in-package :sloppy-text) (defun fill-line (&optional (width 100) &key (default-char #\space)) (with-output-to-string (*standard-output*) (loop repeat width do (princ default-char)))) (defun list-of-lines (&optional (no 30) &rest for-fill-line) " The emacs paper says a list of line-strings is appropriate " (loop repeat no collect (apply #'fill-line for-fill-line))) (defun princ-lines (lines &optional (stream t)) (format stream "~{~a~^~%~}" lines)) (defun random-graphic-char () " does what it sounds like. " (let ((chars `(,@(loop for n below 128 for ch = (code-char n) for gp = (graphic-char-p ch) when gp collect ch)))) (nth (random (length chars)) chars))) (defun boundarise-linep (line x-offset &key (default-char #\space) (fun-boundary-char #'random-graphic-char)) " generalised boolean: Is there a collision coming left to x-offset? Returns the line with a modified 'line' character or else nil. fun-boundary-char should be a function with no formals that returns a single character. " (loop for x below (1+ x-offset) unless (char= (char line x) default-char) do (return-from boundarise-linep nil)) (setf (char line x-offset) (funcall fun-boundary-char)) (values line)) (defun boundarise (list x-off y-offset phase &rest boundarise-linep-args &aux (new-list (mapcar (lambda (x) (format nil "~a" x)) (nthcdr y-offset list)))) " list is a list of lines as from list-of-lines x-off and y-offset top left beginning of trace phase like #c(5 1) (5 across for 1 down) boundarise-linep-args suitable for boundarise-linep " (loop for line in new-list for n from 0 for x-offset = x-off then (if (zerop (mod n (imagpart phase))) (+ x-offset (realpart phase)) x-offset) for new-line = (apply #'boundarise-linep (format nil "~a" line) (min x-offset (1- (length line))) boundarise-linep-args) while (< (1+ x-offset) (length line)) unless new-line do (return-from boundarise nil) collect new-line into final-lines finally (return final-lines))) (defun add-boundaryp (line-list phase x-off y-off &rest linep-args) " traces a line on a new copy of line-list: phase is like #c(5 1) to mean 5 spaces across for every 1 line down x-off and y-off top left extremum of line linep-args suitable for boundarise " (loop for n from y-off to (1- (length line-list)) for new-lines = (apply #'boundarise line-list x-off n phase linep-args) for mid-lines = (append (subseq line-list 0 n) new-lines) for all-lines = (append mid-lines (last line-list (- (length line-list) (length mid-lines)))) when new-lines return all-lines)) (defun stuff-strings (things line-list &key (default-char #\space) &aux (strings (mapcar (lambda (x) (format nil "~a" x)) things))) " Listen, it's not my greatest work. I've been sick, and it was after midnight (and yet also before midnight, thank-you rat, ams and kmp) ARGS: things - a list suitable for mapcar. elements will be aesthetically printed. line-list - as from sloppy-text/impl::list-of-lines :default-char - optional, what is considered an unoccupied char. Attempts to write words that were things into each subsequent line in lines if there's space: Writes them touching whatever they're next to. Returns a (list remaining-words modified-lines-list) suitable for (apply #'stuff-strings #c(5 1) *) " (loop for line in line-list for n from 0 for string = (pop strings) then (cond ((null string) (pop strings)) (t string)) for blocked-idx = (search (format nil "~a" default-char) line :test-not 'char=) while string nconc (and blocked-idx (if (< (length string) (1+ blocked-idx)) (let* ((new-string (concatenate 'string string (subseq line blocked-idx))) (len-new (length new-string)) (dif (- (length line) (length new-string)))) (prog1 `(,(concatenate 'string (subseq line 0 dif) new-string)) (setf string nil))) (list line))) into results finally (return (list (if string (push string strings) strings) results)))) (defun keeppenning (phase words lines) " Args: phase - an integral complex number. #c(5 1) means for every 1 line down, go five more spaces indented. words - A list suitable for mapcar. What is used will be the aesthetic print of w/e you put in the list. lines - A list of string \" lines \" which could have content already. default-char seen elsewhere is left as its default, space for now. RETURNS: new-lines : freshly consed modified versions of lines, to contain words to the extent they fit. See the example at the bottom of impl.lisp " (loop for old-words = (copy-list words) for new-lines = (add-boundaryp lines phase 0 0) for offset = (or (loop for n from 0 for l in lines for k in new-lines when (not (string= l k)) return n) 0) for results = (stuff-strings words (subseq new-lines offset)) for nex-lines = (cadr results) for new-len = (length new-lines) for nex-len = (length nex-lines) for lin-len = (length lines) for joined-lines = (append (copy-list (subseq lines 0 offset)) (copy-list nex-lines) (copy-list (subseq lines (+ offset nex-len)))) when joined-lines do (setf lines joined-lines words (car results)) while (not (equal words old-words)) finally (return joined-lines))) (defvar *phlog* '(Well i cannot say it went perfectly but after seeing jns create art with the words of the epic freebsd driver phlog i decided i would give some notion of phlogging on an angle a go |.| as well as |art,| hopefully we can resist being included in LLM |data.| even though what i have done here is loosely the same as transposing a block of text i think its kind of loose hanging enough it would be hard for an insufficiently loose robot to |catch.|)) (defvar *lines* (list-of-lines 30 50)) #| ;;; e SLOPPY-TEXT/IMPL> (asdf:load-system :sloppy-text) SLOPPY-TEXT/IMPL> (use-package :sloppy-text) SLOPPY-TEXT/IMPL> (keeppenning #c(5 1) *phlog* *lines*) ("3 " " WELL8 " "8 IK " " [ CANNOTm " " SEEING1 SAY5 " " THEa JNS? IT8 " "J EPIC% CREATEN WENT, " " GIVE3 FREEBSDt ART6PERFECTLYM " "r SOME& DRIVER` WITH, BUTF " " GO< NOTION\\ PHLOG@ THEA AFTERB " " .. OFs IO WORDSA " " A ASZPHLOGGINGl DECIDED& OFX " "P RESIST1 WELLZ ONJ I' " " WHAT< BEING+ AS7 ANm WOULDu " "| IR INCLUDEDU art,% ANGLEJ " " AS< HAVE} INgHOPEFULLYk A] " " ( DONEn LLM\" WEK " "' TRANSPOSING) HERE7 data.; CAN= " " ITSR AJ ISq EVENE " "s KIND3 BLOCKq LOOSELYc THOUGH, " " HARDH OFp OFx THE4 " " FORq LOOSEk TEXTI SAME3 " " ANN HANGINGN I) " " INSUFFICIENTLYU ENOUGHq THINKN " " LOOSEp IT` " " ROBOTw WOULD( " " TON BEm " " catch.Q " " " " ") |#