Guest User

Untitled

a guest
Jun 20th, 2018
229
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.96 KB | None | 0 0
  1. %%%-------------------------------------------------------------------
  2. %%% File : bfize.erl
  3. %%% Author : Jesper Louis Andersen <jesper.louis.andersen@gmail.com>
  4. %%% Description : Brainfuckize a text message
  5. %%%
  6. %%% Created : 27 Oct 2010 by Jesper Louis Andersen <jesper.louis.andersen@gmail.com>
  7. %%%-------------------------------------------------------------------
  8. -module(bfize).
  9.  
  10. %% API, the single export from the module, taking one parameter
  11. -export([bfize/1]).
  12.  
  13. %%====================================================================
  14. %% API
  15. %%====================================================================
  16. bfize(FN) ->
  17. %% Read in the file, assume it goes well. We now have the file as a binary in memory
  18. {ok, Content} = file:read_file(FN),
  19. %% Set up an IOlist containing the initialization vector and call process with 4 counters,
  20. %% initialized by the IV at 70, 100, 30, and 10. We use multiple counters so we can choose the
  21. %% counter closest to the value we wish to output and thus get a somewhat smaller brainfuck
  22. %% program.
  23. %%
  24. %% IOlists are
  25. %% datatype iolist = L of iolist list | S of string | B of binary | C of char
  26. %% So we have O(1) concatenation. Many Erlang operations works on IOlists as well as they
  27. %% do on strings (if only ML...).
  28. Res = [initialization(), process(binary_to_list(Content),
  29. 0,
  30. [{1, 70}, {2, 100}, {3, 30}, {4, 10}])],
  31. %% Write out the resulting file.
  32. file:write_file(FN ++ ".bf", format(lists:flatten(Res))).
  33.  
  34. %%====================================================================
  35. %% Internal functions
  36. %%====================================================================
  37.  
  38. %% Simple output formatter, 40 characters per line.
  39. format(Lst) when length(Lst) < 40 -> Lst;
  40. format(Lst) ->
  41. {Front, Back} = lists:split(40, Lst),
  42. [Front, $\n, format(Back)].
  43.  
  44. %% The initialization vector. A loop of 10 sets up 4 counters at positions 1,2,3,4
  45. %% on the 0-indexed tape. Values are 7*10, 10*10,3*10 and 1*10.
  46. initialization() ->
  47. "++++++++++[>+++++++>++++++++++>+++>+<<<<-]".
  48.  
  49. %% If a counter is at Count and we want to print character Char, alter the counter so it
  50. %% can print the character on the next output value by adjusting it with either + or -.
  51. alter_counter(Char, Count) when Char == Count -> "";
  52. alter_counter(Char, Count) when Char > Count -> string:copies("+", Char - Count);
  53. alter_counter(Char, Count) when Char < Count -> string:copies("-", Count - Char).
  54.  
  55. %% Carry out move instructions on the tape to take us from an Old Position to a new one.
  56. move_tape(OldPos, NewPos) when OldPos == NewPos -> "";
  57. move_tape(OldPos, NewPos) when OldPos > NewPos -> string:copies("<", OldPos - NewPos);
  58. move_tape(OldPos, NewPos) when OldPos < NewPos -> string:copies(">", NewPos - OldPos).
  59.  
  60. %% Helper: Update a property-lists key NK with a new value NV by searching for the element
  61. %% to update.
  62. update_proplist([{K, _V} | Rest], NK, NV) when K == NK ->
  63. [{K, NV} | Rest];
  64. update_proplist([{K, V} | Rest], NK, NV) when K =/= NK ->
  65. [{K, V} | update_proplist(Rest, NK, NV)].
  66.  
  67. %% Find the nearest counter to use when you want to target output of N,
  68. %% By searching all counters and returning the one that is closest at the
  69. %% moment.
  70. find_nearest(N, Cnt) ->
  71. find_nearest(N, {0, 300}, Cnt).
  72.  
  73. find_nearest(_N, {K, V}, []) -> {K, V};
  74. find_nearest(N, {K, V}, [{NK, NV} | R]) ->
  75. case abs(N - V) < abs(N - NV) of
  76. true ->
  77. find_nearest(N, {K, V}, R);
  78. false ->
  79. find_nearest(N, {NK, NV}, R)
  80. end.
  81.  
  82. %% Finally, the meat. We want to output character N.
  83. process([], _Pos, _Counters) -> [];
  84. process([N | R], Pos, Counters) ->
  85. %% Find the nearest counter to N
  86. {NPos, V} = find_nearest(N, Counters),
  87. %% Move the tape to the counter, update the counter, print out the desired character
  88. Res = [move_tape(Pos, NPos), alter_counter(N, V), $.],
  89. %% Process next character in the input, update the counters so we keep track of them.
  90. [Res | process(R, NPos, update_proplist(Counters, NPos, N))].
Add Comment
Please, Sign In to add comment