Guest User

Numberwang (brainfuck derivative) Java Interpreter

a guest
Dec 13th, 2016
122
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 5.97 KB | None | 0 0
  1. /**
  2.  * Numberwang Interpreter -- written by JungHwan Min
  3. **/
  4.  
  5. import java.io.BufferedReader;
  6. import java.io.InputStreamReader;
  7. import java.io.IOException;
  8. import java.nio.file.Files;
  9. import java.nio.file.Path;
  10. import java.nio.file.Paths;
  11. import java.util.ArrayList;
  12. import java.util.List;
  13.  
  14. public class Numberwang {
  15.    
  16.     private static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
  17.    
  18.     public enum Error {
  19.         EMPTY_CODE(0, "Empty code."),
  20.         BRACKET_MISMATCH(1, "Brackets (4 and 7) do not match."),
  21.         INVALID_CHARACTER(2, "Invalid character in input."),
  22.         NO_CODE(3, "Usage: java Numberwang \"path/to/your/code\""),
  23.         CODE_READ_ERR(4, "Reading code failed.");
  24.        
  25.         private final int code;
  26.         private final String message;
  27.        
  28.         private Error(int code, String message) {
  29.             this.code = code;
  30.             this.message = message;
  31.         }
  32.        
  33.         private void throwError() {
  34.             System.err.println("Error: "+message);
  35.             System.exit(code);
  36.         }
  37.        
  38.     }
  39.    
  40.     public static void main(String[] args) {
  41.        
  42.         if (args.length == 0)
  43.             Error.NO_CODE.throwError();
  44.        
  45.         String code;
  46.        
  47.         try {
  48.             code = new String(Files.readAllBytes(Paths.get(args[0])));
  49.         } catch (IOException e) {
  50.             Error.CODE_READ_ERR.throwError();
  51.             code = "";
  52.         }
  53.        
  54.         List<Byte> commands = new ArrayList<Byte>();
  55.         List<Integer> coeffs = new ArrayList<Integer>();
  56.        
  57.         optimize(code, commands, coeffs);
  58.        
  59.         run(commands, coeffs);
  60.        
  61.     }
  62.    
  63.     // Delete 5, 6, and non-digit characters
  64.     private static String del56(String code) {
  65.        
  66.         // Strip non-digits
  67.         StringBuilder codeDigits = new StringBuilder();
  68.         for (int i = 0; i < code.length(); i++) {
  69.             char ch = code.charAt(i);
  70.             if (ch >= '0' && ch <= '9')
  71.                 codeDigits.append(ch);
  72.         }
  73.        
  74.         // Stop running if the code is empty.
  75.         if (codeDigits.length() == 0) {
  76.             Error.EMPTY_CODE.throwError();
  77.         }
  78.        
  79.         // Check if last char is 5 or 6 and append 0 if it is (harmless even when the code ends in 55, 56, etc.)
  80.         char last = codeDigits.charAt(codeDigits.length() - 1);
  81.         if (last == '5' || last == '6')
  82.             codeDigits.append('0');
  83.        
  84.         int bracketMatch = 0;
  85.         char[] codeArr = codeDigits.toString().toCharArray();
  86.         StringBuilder codeFinal = new StringBuilder();
  87.        
  88.         for (int i = 0; i <= codeArr.length - 1; i++) {
  89.             switch (codeArr[i]) {
  90.                 case '0' :
  91.                     codeFinal.append('0');
  92.                     break;
  93.                 case '1' :
  94.                     codeFinal.append('1');
  95.                     break;
  96.                 case '2' :
  97.                     codeFinal.append('2');
  98.                     break;
  99.                 case '3' :
  100.                     codeFinal.append('3');
  101.                     break;
  102.                 case '4' :
  103.                     codeFinal.append('4');
  104.                     bracketMatch += 1;
  105.                     break;
  106.                 case '5' :
  107.                     for(int j = 0; j < codeArr[i+1] - '0'; j++)
  108.                         codeFinal.append('2');
  109.                     i++;
  110.                     break;
  111.                 case '6' :
  112.                     for(int j = 0; j < codeArr[i+1] - '0'; j++)
  113.                         codeFinal.append('9');
  114.                     i++;
  115.                     break;
  116.                 case '7' :
  117.                     codeFinal.append('7');
  118.                     bracketMatch -= 1;
  119.                     break;
  120.                 case '8' :
  121.                     codeFinal.append('8');
  122.                     break;
  123.                 case '9' :
  124.                     codeFinal.append('9');
  125.                     break;
  126.                 default :
  127.                     break;
  128.             }
  129.            
  130.             if (bracketMatch < 0)
  131.                 Error.BRACKET_MISMATCH.throwError();
  132.            
  133.         }
  134.        
  135.         if (bracketMatch != 0)
  136.             Error.BRACKET_MISMATCH.throwError();
  137.        
  138.         return codeFinal.toString();
  139.     }
  140.    
  141.     // Optimize -- delete irrelevant characters, use byte array, run-length encode
  142.     private static void optimize(String code, List<Byte> commands, List<Integer> coeffs) {
  143.         runLengthEncode(toByteArray(del56(code)), commands, coeffs);
  144.     }
  145.    
  146.     // Convert string to byte array
  147.     private static byte[] toByteArray(String code) {
  148.         byte[] arr = code.getBytes();
  149.         for (int i = 0; i < arr.length; i++)
  150.             arr[i] -= '0';
  151.         return arr;
  152.     }
  153.    
  154.     // Run-length encode
  155.     private static void runLengthEncode(byte[] code, List<Byte> commands, List<Integer> coeffs) {
  156.        
  157.         byte[] codeNew = new byte[code.length + 1];
  158.         System.arraycopy(code, 0, codeNew, 0, code.length);
  159.         codeNew[codeNew.length - 1] = 10; // Append a 10 to make sure the run-length encoding includes the last command.
  160.        
  161.         int runLength = 1;
  162.         byte run = codeNew[0];
  163.         List<Integer> brackets = new ArrayList<Integer>();
  164.        
  165.         for (int i = 1; i < codeNew.length; i++) {
  166.             if (run == 4) {
  167.                 commands.add(run);
  168.                 coeffs.add(0); // Placeholder
  169.                 brackets.add(coeffs.size() - 1);
  170.                 run = codeNew[i];
  171.             } else if (run == 7) {
  172.                 commands.add(run);
  173.                 int lastIndex = brackets.size() - 1;
  174.                 int lBracket = brackets.get(lastIndex);
  175.                 coeffs.add(lBracket);
  176.                 coeffs.set(lBracket, coeffs.size() - 1);
  177.                 brackets.remove(lastIndex);
  178.                 run = codeNew[i];
  179.             } else if (run == 3 || run == 8) {
  180.                 commands.add(run);
  181.                 coeffs.add(0); // Placeholder
  182.                 run = codeNew[i];
  183.             } else if (run == codeNew[i]) {
  184.                 runLength++;
  185.             } else {
  186.                 commands.add(run);
  187.                 coeffs.add(runLength);
  188.                 run = codeNew[i];
  189.                 runLength = 1;
  190.             }  
  191.         }
  192.     }
  193.    
  194.     private static void run(List<Byte> commands, List<Integer> coeffs) {
  195.        
  196.         byte[] cells = new byte[65536];
  197.         short loc = 0;
  198.        
  199.         for(int i = 0; i < commands.size(); i++) {
  200.            
  201.             switch (commands.get(i)) {
  202.                 case 0: loc += coeffs.get(i);
  203.                         break;
  204.                 case 1: loc -= coeffs.get(i);
  205.                         break;
  206.                 case 9: cells[loc & 0xffff] += coeffs.get(i);
  207.                         break;
  208.                 case 2: cells[loc & 0xffff] -= coeffs.get(i);
  209.                         break;
  210.                 case 3: System.out.print((char) (cells[loc & 0xffff] & 0xff));
  211.                         break;
  212.                 case 8: cells[loc] = getInput();
  213.                         break;
  214.                 case 4: if(cells[loc & 0xffff] == 0)
  215.                             i = coeffs.get(i) - 1;
  216.                         break;
  217.                 case 7: if(cells[loc & 0xffff] != 0)
  218.                             i = coeffs.get(i) - 1;
  219.                         break;
  220.                 default: break;
  221.             }
  222.         }
  223.     }
  224.    
  225.     private static byte getInput() {
  226.        
  227.         try {
  228.             int i = in.read();
  229.            
  230.             if (i == -1)
  231.                 i = 0;
  232.             else if (i > 256)
  233.                 Error.INVALID_CHARACTER.throwError();
  234.             return (byte) i;
  235.            
  236.         } catch (IOException e) {
  237.             System.out.println("Error from user input");
  238.             Error.INVALID_CHARACTER.throwError();
  239.             return (byte) 0;
  240.         }
  241.     }
  242. }
Advertisement
Add Comment
Please, Sign In to add comment