User:Blashyrkh/A+B-brainfuck
Jump to navigation
Jump to search
My implementation of A+B Problem in Brainfuck. Stripped version is 316 bytes long. It uses decimal representation for calculations. Here's the full version with explanation (probably TOO verbose):
; Blashyrkh's elementary school of brainfuck programming ; Take your seats kids ; Let's solve more general problem: A plus B plus C plus etc until EOF ; A plus B would work as a special case ; Each input number (maybe except the last one) should be followed by LF ; Being good boys and girls we will accept both 'minus one' and 'no change' styles of EOF ; Any character other than digit or LF (ascii 10) would ruin everything ; Beware brainfuck interpreters that DO NOT replace CRLF with LF on Windows! ; == Memory layout == ; |EOF| 0 | 0 | x | | x | | x | Input buffer ; | | | | | a | | a | | Accumulator ; ; == Work cycle == ; read addendum to input buffer and reverse it in process ; if read ends with EOF then special flag is set which is analyzed after summation ; input of current addendum ends with LF or EOF ; EOF flag breaks the main loop ; add the addendum to the accumulator ; normalize accumulator digits (propagate carry bit) ; repeat ; handle special cases (leading zeroes and zero result) ; print result ; Main loop always starts at cell zero where EOF flag resides ; The flag is zero normally (and initially) and set to one if EOF is encountered during the input loop -[ ; Reset EOF flag back to its original value (zero) + ; Set position to cell number 3 ; That's where the first read symbol will be stored >>> ; Remember that we promised to be good boys and girls (ok I did not you) ; We shall accept both 'minus one' and 'no change' EOF ; It means that we have to set a cell to minus one before performing input into it -[ ; Input! ,+ ; Current input cell (let's name it 'x' for now) is: ; 0 in case of EOF ; 11 in case of LF ; 49~58 in case of digit ; Let's look at the diagram: ; | 0 | 0 | 0 | x | a | ? | (case A) ; ^ ; | 0 | 0 | 0 | 0 | a | ? | (case B) ; ^ ; Case A: subtract 11 from x ; Case B: set EOF flag and leave x=0 [-----------<<->]<+[<]> ; | 0 | 0 | 0 | x | a | ? | x=38~47 or 0 ; ^ ; | 0 | 0 | 1 | 0 | a | ? | ; ^ [-<<+>>]> ; | 0 | 0 | 0 | x | a | ? | x=38~47 ; ^ ; |EOF| 0 | 0 | 0 | a | ? | EOF or LF ; ^ ; if a digit was entered then we need to shift the whole input two cells ; rightwards to prepare place for the next input digit ; otherwise change nothing [ ; | 0 | 0 | 0 | x | a | x | a | x | x=38~47 ; ^ <++++++[->------<]>- ; | 0 | 0 | 0 | x | a | x | a | x | x=1~10 ; ^ [>>]<< ; | 0 | 0 | 0 | x | a | x | a | x | a | 0 | ; ^ [[->>+<<]<<] ; | 0 | 0 | 0 | 0 | a | x | a | x | a | x | ; ^ >+> ; | 0 | 0 | 1 | 0 | a | x | a | x | a | x | ; ^ ] ; | 0 | 0 | 1 | 0 | a | x | a | x | a | x | when we wait for next digit of current number ; ^ ; |EOF| 0 | 0 | 0 | a | x | a | x | a | x | when EOF or LF was entered ; ^ <[->-<]> ; | 0 | 0 | 0 | _1| a | x | a | x | a | x | ; ^ ; |EOF| 0 | 0 | 0 | a | x | a | x | a | x | ; ^ ; If EOF or LF was entered then we break the loop ; Otherwise we put 'minus one' input the cell and repeat input ] ; |EOF| 0 | 0 | 0 | a | x | a | x | ? ; ^ ; Addendum is stored to 'x' cells where x=1~10 ; Accumulator is in 'a' cells where a=1~10 ; But length of accumulator and of the last addendum may be different ; Let's add new addendum to accumulator and clear (reset to zero) all x cells ; Iterate over 'x' cells >>[ ; Point to corresponding 'a' cell < ; | ? | 0 | a | x | ; ^ ; | ? | 0 | 0 | x | ; ^ ; Zero 'a' cell means that this accumulator cell was not initialized yet (implicit zero) ; If 'a' is zero than we can move 'x' there ; Otherwise we add 'x' and subtract 1 since 'x' are also 1~10 [>-[-<+>]] ; | ? | 0 | a'| 0 | ; ^ ; | ? | 0 | 0 | x | ; ^ <[<]>> ; | ? | 0 | a'| 0 | ; ^ ; | ? | 0 | 0 | x | ; ^ [-<+>] ; | ? | 0 | a'| 0 | ; ^ ; | ? | 0 | x | 0 | ; ^ ; Bingo! ; Move to next 'x' cell >> ] ; Move to last guaranteed nonzero accumulator cell <<< ; Rewind [<<]>> ; Addendum is added to accumulator but its digits are not normalized ; They are 1~19 instead of 1~10 ; We need to normalize them and propagate carry bit ; |EOF| 0 | 0 | 0 | a | 0 | a | 0 | a | ; ^ [ >++++++++++ ; |EOF| 0 | 0 | 0 | a | 10| a | 0 | a | ; ^ [ <-<+>[<-]< ; |EOF| 0 | 0 | 0 | a'| ? | a | 0 | a | ; ^ ; |EOF| 0 | 0 | 1 | 0 | ? | a | 0 | a | ; ^ [->++++++++++>>>-<<<<<] ; |EOF| 0 | 0 | 0 | a'| ? | a | 0 | a | ; ^ ; |EOF| 0 | 0 | 0 | 10| ? | a | _1| a | ; ^ >>>- ] ; It worked ok for the first digit ; But we need to process the rest of accumulator ; We need space for it ; Each digit needs two zeroes to the left of it ; So we have to move already processed digits one cell left ; |EOF| 0 | 0 | 0 | a | 0 | a | c'| a | ; ^ <[-<+>]>>>+ ; |EOF| 0 | 0 | a | 0 | 0 | a | c | a | ; ^ ; Next thing to do: what is 'c'? It's carry flag which should be added to the next 'a' ; Why didn't we add it already? Because a=0 along with c=1 has special meaning: 'a' must be set to 2! ; It's because a=0 means "not yet initialized accumulator cell" and we have to perform this ; initialization (:=1) before adding carry bit [ ; |EOF| 0 | 0 | a | 0 | 0 | a | 1 | a | '*' should be incremented ; * ^ ; |EOF| 0 | 0 | a | 0 | 0 | 0 | 1 | a | '*' should be set to 2 ; * ^ -<[>]++ ; |EOF| 0 | 0 | a | 0 | 0 | a | 2 | a | ; ^ ; |EOF| 0 | 0 | a | 0 | 0 | 2 | 0 | a | ; ^ <[+>--<<]>> ; |EOF| 0 | 0 | a | 0 | 0 | a'| 0 | a | ; ^ ; |EOF| 0 | 0 | a | 0 | 0 | 2 | 0 | a | ; ^ ] ; Point to next accumulator cell and repeat the loop < ] ; Now accumulator is OK but it's shifted one cell left ; |EOF| 0 | 0 | a | 0 | a | 0 | 0 | 0 | ; ^ <<<[[->+<]<<] ; |EOF| 0 | 0 | 0 | a | 0 | a | 0 | 0 | ; ^ ; Continue if not EOF <- ] ; Now we're almost ready to print our result ; Two special cases must be handled though ; (1) leading zeroes ; (2) no digits at all >+>>>[>>]<< [ ; | 0 | 1 | 0 | 0 | a | 0 | a | 0 | 1 | leading zero looks like this ; ^ ; | 0 | 1 | 0 | 0 | a | 0 | a | 0 | a | ; ^ -[+[<<]] ; | 0 | 1 | 0 | 0 | a | 0 | a | 0 | 0 | ; ^ ; | 0 | 1 | 0 | 0 | a | 0 | a | 0 | a | ; ^ <[->>]< ; | 0 | 1 | 0 | 0 | a | 0 | a | 0 | 0 | ; ^ ; | 0 | 0 | 0 | 0 | a | 0 | a | 0 | a | ; ^ ] ; Probably no digits left at all (result was zero but all zeroes were removed) ; | 0 | 1 | 0 | 0 | 0 | ; ^ ; | 0 | 0 | 0 | 0 | a | ; ^ <[->>>+<<<] ; Now print digits from right to left ; First let's rewind and add 47 to each digit (thus convert to ascii range) >>>[->++++++[-<++++++++>]>]<< ; And print them all backwards [.<<] ; print LF ++++++++++. ; That's all folks!