Brainhash

From Esolang
Jump to navigation Jump to search
The title of this article is not correct because of technical limitations. The correct title is actually Brain#.

Brain# is just a cool encoding of brain**** by User:Esolangist

Encoding

First, you convert BF to binary using this table:

Commands in First encoding of Brain#
First encoding of Brain# brainfuck
0 +
1 -
2 <
3 >
4 ,
5 .
6 [
7 ]


Next, convert the number to ASCII numbers (its value) and convert it back. 4 > 52 > 53 50 There, you have Brain#.

Example.

We take the cat program ,[.,] Now it's 46547. How about some 52 54 53 52 55? Now what about 53 50 53 52 53 51 53 50 53 53? (That last one was the cat in Brain#.)

Algorithm

A valorized species of formality anent the decoding algorithm shall constitute the following pseudocode's tmema's contribution:

function getFirstPassCipher (brainfuckToken)
  Input:
    brainfuckToken:  One of the eight recognized brainfuck command
                     symbols.
  
  Output:
    firstPassCipher: The first-pass cipher corresponding to the
                     BRAINFUCK_TOKEN and representing a decimal
                     digit in the closed integer interval [0, 7].
  
  Process:
    let firstPassCipher ← nil
    
    if brainfuckToken = "+" then
      firstPassCipher ← 0
    else if brainfuckToken = "-" then
      firstPassCipher ← 1
    else if brainfuckToken = "<" then
      firstPassCipher ← 2
    else if brainfuckToken = ">" then
      firstPassCipher ← 3
    else if brainfuckToken = "," then
      firstPassCipher ← 4
    else if brainfuckToken = "." then
      firstPassCipher ← 5
    else if brainfuckToken = "[" then
      firstPassCipher ← 6
    else if brainfuckToken = "]" then
      firstPassCipher ← 7
    else
      error: no brainfuck token
    end if
    
    return firstPassCipher
end function

function getASCIICode (digit)
  Input:
    digit:     The decimal digit, interpreted as a character
               rather than a numeric object, whose ASCII code
               shall be determined.
  
  Output:
    asciiCode: The ASCII code for the decimal digit considered as
               a character.
  
  Process:
    let asciiCode ← 48 + digit
    
    return asciiCode
end function

function encodeBrainfuckProgram (brainfuckProgram)
  Input:
    brainfuckProgram: The brainfuck program to encode according to
                      the Brainhash standard.
  
  Output:
    brainhashProgram: The encoded BRAINFUCK_PROGRAM as an ordered
                      list of integer number, each member an
                      incolant of the closed integral interval of
                      [48, 55].
  
  Process:
    let brainhashProgram ← empty ordered list
    
    for character bfToken in brainfuckProgram do
      let firstPassCipher  ← getFirstPassCipher(bfToken)
      let secondPassCipher ← getASCIICode(firstPassCipher)
      let secondPassDigit1 ← first  digit of secondPassCipher
      let secondPassDigit2 ← second digit of secondPassCipher
      let thirdPassCipher1 ← getASCIICode(secondPassDigit1)
      let thirdPassCipher2 ← getASCIICode(secondPassDigit2)
      
      append thirdPassCipher1 to brainhashProgram
      append thirdPassCipher2 to brainhashProgram
    end for
    
    return brainhashProgram
end function

Examples

Truth-Machine

A truth-machine equivalent to the brainfuck code ,.[-->+[>>]<[.]<<] shall be adduced below:

53 50 53 51 53 52 52 57 52 57 53 49 52 56 53 52 53 49
53 49 53 53 53 48 53 52 53 51 53 53 53 48 53 48 53 53

Hello, World!

This program, tantamount to brainfuck's +[-->-[>>+>-----<<]<--<---]>-.>>>+.>>..+++[.>]<<<<.+++.------.<<-.>>>>+., issues the message “Hello, World!” to the standard output conduit:

52 56 53 52 52 57 52 57 53 49 52 57 53 52 53 49 53 49
52 56 53 49 52 57 52 57 52 57 52 57 52 57 53 48 53 48
53 53 53 48 52 57 52 57 53 48 52 57 52 57 52 57 53 53
53 49 52 57 53 51 53 49 53 49 53 49 52 56 53 51 53 49
53 49 53 51 53 51 52 56 52 56 52 56 53 52 53 51 53 49
53 53 53 48 53 48 53 48 53 48 53 51 52 56 52 56 52 56
53 51 52 57 52 57 52 57 52 57 52 57 52 57 53 51 53 48
53 48 52 57 53 51 53 49 53 49 53 49 53 49 52 56 53 51

Decoder and Encoder Implementation

Note from User:Esolangist: This isn't official, but you can use it I guess. It looks like Common Lisp to me so run it in a Common Lisp interpreter.

The following provides a decoder from Brain# to brainfuck, and vice versa, implemented in the Common Lisp programming language. Please heed that the incorporated nimiety ensues from the verbatim replication of the transcription algorithm, rather than a simple table-based solution, which would harness the inambiguous nature of the mappings betwixt the two languages' tokens:

(deftype first-pass-cipher ()
  "The \"first-pass-cipher\" type defines the cipher associated with the
   Brain# encoding's first stage as an integral number occupying the
   closed interval [0, 7]."
  '(integer 0 7))

;;; -------------------------------------------------------

(deftype decimal-digit ()
  "A decimal digit as an integer in the range [0, 9]"
  '(integer 0 9))

;;; -------------------------------------------------------

(deftype ascii-code-of-digit ()
  "The ASCII code of a digit as an integer in the range [48, 57]."
  '(integer 48 57))

;;; -------------------------------------------------------

(deftype destination ()
  "Defines a sink for output operations."
  '(or null (eql T) stream string))

;;; -------------------------------------------------------

(defun interpret-as-a-boolean-value (object)
  "Converts the OBJECT into a \"boolean\" value."
  (declare (type T object))
  (the boolean (not (null object))))

;;; -------------------------------------------------------

(defun whitespace-character-p (candidate)
  "Determines whether the CANDIDATE represents a whitespace character."
  (declare (type character candidate))
  (the boolean
    (interpret-as-a-boolean-value
      (member candidate '(9 10 11 12 13 32)
        :key #'code-char :test #'char=))))

;;; -------------------------------------------------------

(defun locate-the-next-token (source start-index)
  "Returns the next token and its exclusive end index into the SOURCE."
  (declare (type string source))
  (declare (type fixnum start-index))
  (let* ((word-start-index
          (or (position-if-not #'whitespace-character-p source
                :start start-index)
              (length source)))
         (word-end-index
          (or (position-if #'whitespace-character-p source
                :start word-start-index)
              (length source))))
    (declare (type fixnum word-start-index word-end-index))
    (the (values string fixnum)
      (values (subseq source word-start-index word-end-index)
              word-end-index))))

;;; -------------------------------------------------------

(defmacro with-token-iterator ((driver-name source) &body body)
  "Evaluates the SOURCE, and evaluates the BODY forms, granting these
   the adit to the SOURCE's ensconced tokens by adminiculum of a local
   function of niladic signature, whose agnomination is communicated
   with the DRIVER-NAME, returning upon its invocation the next token
   as a fresh string, and finally returns the desinent BODY form's
   results."
  (let ((evaluated-source   (gensym))
        (search-start-index (gensym))
        (next-token         (gensym)))
    (declare (type symbol evaluated-source))
    (declare (type symbol search-start-index))
    (declare (type symbol next-token))
    `(let ((,evaluated-source   ,source)
           (,search-start-index 0)
           (,next-token         ""))
       (declare (type string ,evaluated-source))
       (declare (type fixnum ,search-start-index))
       (declare (type string ,next-token))
       (flet ((,driver-name ()
                "Returns the next token from the SOURCE as a string."
                (multiple-value-setq (,next-token ,search-start-index)
                  (locate-the-next-token
                    ,evaluated-source ,search-start-index))
                (the string ,next-token)))
         ,@body))))

;;; -------------------------------------------------------

(declaim (type (simple-base-string 8) +BRAINFUCK-INSTRUCTIONS+))

;;; -------------------------------------------------------

(defconstant +BRAINFUCK-INSTRUCTIONS+
  (coerce "+-<>,.[]" 'simple-base-string)
  "Maps the brainfuck instructions to their zero-based indices, which
   conincide with the first-pass cipher in the range [0, 7].")

;;; -------------------------------------------------------

(defun brainfuck-instruction-p (candidate)
  "Determines whether the CANDIDATE represents a brainfuck instruction."
  (declare (type character candidate))
  (the boolean
    (interpret-as-a-boolean-value
      (find candidate +BRAINFUCK-INSTRUCTIONS+ :test #'char=))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; -- Implementation of the brainfuck-to-Brain# encoder.           -- ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; brainfuck token to integer in [0, 7].
(defun first-pass-encode-the-instruction (brainfuck-instruction)
  "Encodes the BRAINFUCK-INSTRUCTION into the first-pass cipher as an
   integer number from the closed interval [0, 7]."
  (declare (type standard-char brainfuck-instruction))
  (the first-pass-cipher
    (or (position brainfuck-instruction +BRAINFUCK-INSTRUCTIONS+
          :test #'char=)
        (error "Cannot encode the brainfuck token \"~c\"."
          brainfuck-instruction))))

;;; -------------------------------------------------------

;; Digit in [0, 9] to ASCII code in [48, 57].
(defun second-pass-encode-the-instruction (first-pass-cipher)
  "Encodes the FIRST-PASS-CIPHER into its corresponding second-pass
   cipher tantamount, that is, its ASCII code."
  (declare (type decimal-digit first-pass-cipher))
  (the ascii-code-of-digit
    (+ 48 first-pass-cipher)))

;;; -------------------------------------------------------

;; ASCII code in [48, 57] to twissel of ASCII code in [48, 57].
(defun third-pass-encode-the-instruction (second-pass-cipher)
  "Returns the ASCII code of the SECOND-PASS-CIPHER's first digit and
   that of its second digit in this order."
  (declare (type ascii-code-of-digit second-pass-cipher))
  (multiple-value-bind (first-digit second-digit)
      (floor second-pass-cipher 10)
    (declare (type (integer 4 5) first-digit))
    (declare (type (integer 0 9) second-digit))
    (the (values ascii-code-of-digit ascii-code-of-digit)
      (values
        (second-pass-encode-the-instruction first-digit)
        (second-pass-encode-the-instruction second-digit)))))

;;; -------------------------------------------------------

(defun encode-the-brainfuck-code (code &key (destination NIL))
  "Converts the piece of brainfuck source CODE into its Brain# encoding
   and writes the resul to the DESTINATION, returning for a non-\"NIL\"
   DESTINATION the \"NIL\" value; otherwise, for a \"NIL\" DESTINATION,
   responds with a fresh string comprehending the encoded content."
  (declare (type string code) (type destination destination))
  (the (or null string)
    (if destination
      (loop
        with first-output-p of-type boolean   =      T
        for  current-token  of-type character across code
        when (brainfuck-instruction-p current-token) do
          (multiple-value-bind (left-cipher right-cipher)
              (third-pass-encode-the-instruction
                (second-pass-encode-the-instruction
                  (first-pass-encode-the-instruction current-token)))
            (declare (type ascii-code-of-digit left-cipher))
            (declare (type ascii-code-of-digit right-cipher))
            (format destination "~@[ ~*~]~d ~d"
              (not first-output-p)
              left-cipher
              right-cipher)
            (setf first-output-p NIL)))
      (with-output-to-string (encoded-program)
        (declare (type string-stream encoded-program))
        (encode-the-brainfuck-code code
          :destination encoded-program)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; -- Implementation of the Brain#-to-brainfuck decoder.           -- ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun get-the-digit-by-its-ascii-code (character-code)
  "Returns the integral value of the decimal digit represented by its
   ASCII CHARACTER-CODE."
  (declare (type ascii-code-of-digit character-code))
  (the decimal-digit (digit-char-p (code-char character-code))))

;;; -------------------------------------------------------

;; Example: (53, 50) => 52
(defun decode-the-third-pass-cipher (third-pass-cipher-1
                                     third-pass-cipher-2)
  "Decodes the third-pass cipher moeities into the second-pass cipher
   by replacing both inputs, construed as ASCII codes, by their decimal
   digits and concatenating them."
  (declare (type ascii-code-of-digit third-pass-cipher-1))
  (declare (type ascii-code-of-digit third-pass-cipher-2))
  (the ascii-code-of-digit
    (+ (* (get-the-digit-by-its-ascii-code third-pass-cipher-1) 10)
       (get-the-digit-by-its-ascii-code third-pass-cipher-2))))

;;; -------------------------------------------------------

;; Example: 52 => 4
(defun decode-the-second-pass-cipher (second-pass-cipher)
  "Decodes the SECOND-PASS-CIPHER and returns the first-pass cipher
   by interpreting the input as the ASCII code of a decimal digit from
   the range [0, 7]."
  (declare (type ascii-code-of-digit second-pass-cipher))
  (the first-pass-cipher (get-the-digit-by-its-ascii-code second-pass-cipher)))

;;; -------------------------------------------------------

;; Example: 4 => ","
(defun decode-the-first-pass-cipher (first-pass-cipher)
  "Decodes the FIRST-PASS-CIPHER into the corresponding brainfuck symbol."
  (declare (type first-pass-cipher first-pass-cipher))
  (the standard-char (schar +BRAINFUCK-INSTRUCTIONS+ first-pass-cipher)))

;;; -------------------------------------------------------

(defun parse-the-ascii-code-representing-a-digit (source)
  "Parses the SOURCE as an ASCII code in the range [48, 57]."
  (declare (type string source))
  (let ((extracted-integer (parse-integer source)))
    (declare (type integer extracted-integer))
    (the ascii-code-of-digit
      (if (<= 48 extracted-integer 57)
        extracted-integer
        (error "The number ~d does not represent a decimal digits ~
                ASCII code." extracted-integer)))))

;;; -------------------------------------------------------

(defun decode-the-brainhash-code (code &key (destination NIL))
  "Decodes the piece of Brainhash source CODE into its equivalent
   brainfuck program, writes thilk to the DESTINATION, and returns for
   a non-\"NIL\" DESTINATION the \"NIL\" value; otherwise produces a
   fresh string comprehending the output."
  (declare (type string code) (type destination destination))
  (the (or null string)
    (if destination
      (with-token-iterator (request-the-next-token code)
        (flet ((request-the-next-third-pass-cipher ()
                "Reads the next token from the CODE, and, if a digit's
                 ASCII code, returns the same; otherwise produces NIL."
                (the (or null ascii-code-of-digit)
                  (let ((next-token (request-the-next-token)))
                    (declare (type string next-token))
                    (unless (string= next-token "")
                      (parse-the-ascii-code-representing-a-digit next-token))))))
          (loop
            for third-pass-cipher-1
              of-type (or null ascii-code-of-digit)
              =       (request-the-next-third-pass-cipher)
            for third-pass-cipher-2
              of-type (or null ascii-code-of-digit)
              =       (request-the-next-third-pass-cipher)
            while third-pass-cipher-1 do
              (format destination "~c"
                (decode-the-first-pass-cipher
                  (decode-the-second-pass-cipher
                    (decode-the-third-pass-cipher
                      third-pass-cipher-1 third-pass-cipher-2)))))))
      (with-output-to-string (brainfuck-code)
        (declare (type string-stream brainfuck-code))
        (decode-the-brainhash-code code :destination brainfuck-code)))))