我最小码解释器(又名Brainf ** K)【难度:3级】:
答案1:
using System;
using System.Collections.Generic;
using System.Linq;
public static class Kata
{
public static string BrainLuck(string code, string input)
{
return new Interpreter(code, input).Execute();
}
}
public class Interpreter
{
private Dictionary<char, Action> commands = new Dictionary<char, Action>();
private List<dataByte> data = new List<dataByte>();
private string validCode;
private int pointer;
private string output;
private string input;
private int codeLoc;
public Interpreter(string code, string input)
{
output = String.Empty;
commands.Add('<', Backward);
commands.Add('>', Forward);
commands.Add('+', Increment);
commands.Add('-', Decrement);
commands.Add('.', AddToOutput);
commands.Add(',', TakeInput);
commands.Add('[', Jump);
commands.Add(']', Jump);
this.input = input;
validCode = new string(code.Where(commands.ContainsKey).ToArray());
data.Add(new dataByte());
}
private void Forward() => MovePointerForward();
private void Backward() => pointer = pointer == 0 ? 0 : pointer -1;
private void Increment() => data.ElementAt(pointer).dataVal += 1;
private void Decrement() => data.ElementAt(pointer).dataVal -= 1;
private void TakeInput() => TakeIn();
private void AddToOutput() => output += (char)data.ElementAt(pointer).dataVal;
private void Jump() => JumpCheck(validCode[codeLoc]);
private void JumpCheck(char command)
{
if (command == '[' && data.ElementAt(pointer).dataVal == 0) jumpIndex(1, '[', ']');
if (command == ']' && data.ElementAt(pointer).dataVal != 0) jumpIndex(-1, ']', '[');
}
private void jumpIndex(int addValue, char match, char stop)
{
var count = 1;
while (count > 0)
{
codeLoc += addValue;
if (validCode[codeLoc] == match)
{
count += 1;
}
if (validCode[codeLoc] == stop)
{
count -= 1;
}
}
}
private void MovePointerForward()
{
pointer++;
if (pointer >= data.Count())
{
data.Add(new dataByte());
}
}
private void TakeIn()
{
data.ElementAt(pointer).dataVal = input[0];
input = input.Remove(0, 1);
}
public string Execute()
{
var codeBound = validCode.Length;
while (codeLoc < codeBound)
{
var act = commands[validCode[codeLoc]];
act();
codeLoc++;
}
return output;
}
}
public class dataByte
{
private int val;
public int dataVal
{
get {return val;}
set
{
val = value;
if (val > 255) val = 0;
if (val < 0) val = 255;
}
}
}
答案2:
using System;
using System.Collections.Generic;
using System.Linq;
public static class Kata
{
public static string BrainLuck(string code, string input)
{
code = string.Concat(code.Where(ch => new char[] { '>', '<', '+', '-', ',', '.', '[', ']' }.Contains(ch)));
List<byte> memory = new List<byte>();
string output = "";
int codePtr = 0;
int inputPtr = 0;
int memoryPtr = 0; memory.Add(0);
while (codePtr < code.Length)
{
switch (code[codePtr])
{
case '>':
if (++memoryPtr >= memory.Count)
memory.Add(0);
break;
case '<':
if (memoryPtr == 0)
memory.Insert(0, 0);
else
--memoryPtr;
break;
case '+':
memory[memoryPtr] = memory[memoryPtr] < 255 ? ++memory[memoryPtr] : (byte)0;
break;
case '-':
memory[memoryPtr] = memory[memoryPtr] > 0 ? --memory[memoryPtr] : (byte)255;
break;
case ',':
memory[memoryPtr] = (byte)input[inputPtr];
++inputPtr;
break;
case '.':
output += (char)memory[memoryPtr];
break;
case '[':
if (memory[memoryPtr] == 0)
{
int cnt = 1;
while (cnt != 0)
{
++codePtr;
if (code[codePtr] == '[') ++cnt;
else if (code[codePtr] == ']') --cnt;
}
}
break;
case ']':
if (memory[memoryPtr] != 0)
{
int cnt = 1;
while (cnt != 0)
{
--codePtr;
if (code[codePtr] == ']') ++cnt;
else if (code[codePtr] == '[') --cnt;
}
}
break;
}
++codePtr;
}
return output;
}
}
答案3:
using System;
using System.Collections.Generic;
using System.IO;
public static class Kata
{
public static string BrainLuck(string code, string input)
{
if (code == null)
{
throw new ArgumentNullException(nameof(code));
}
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
using (var inputStream = new MemoryStream(GetBytes(input)))
using (var outputStream = new MemoryStream())
{
var data = new List<byte>() { 0 };
var pointer = 0;
for (int pc = 0; pc < code.Length; ++pc)
{
switch (code[pc])
{
case '>':
if (++pointer == data.Count)
{
data.Add(0);
}
break;
case '<':
if (pointer == 0)
{
throw new InvalidOperationException("Can't decrement data pointer at start of data.");
}
--pointer;
break;
case '+':
++data[pointer];
break;
case '-':
--data[pointer];
break;
case '.':
outputStream.WriteByte(data[pointer]);
break;
case ',':
data[pointer] = (byte)inputStream.ReadByte();
break;
case '[':
if (data[pointer] == 0 && (pc = FindClosing(code, pc)) == -1)
{
throw new ArgumentException("Unmatched '['.", nameof(code));
}
break;
case ']':
if (data[pointer] != 0 && (pc = FindOpening(code, pc)) == -1)
{
throw new ArgumentException("Unmatched ']'.", nameof(code));
}
break;
default:
throw new ArgumentException("Unknown instruction.", nameof(code));
}
}
return GetString(outputStream.ToArray());
}
}
private static byte[] GetBytes(string s)
{
return Array.ConvertAll(s.ToCharArray(), c => (byte)c);
}
private static string GetString(byte[] bytes)
{
return new string(Array.ConvertAll(bytes, b => (char)b));
}
private static int FindClosing(string s, int startIndex)
{
int level = 1;
for (int index = startIndex + 1; index < s.Length; ++index)
{
switch (s[index])
{
case '[':
++level;
break;
case ']':
if (--level == 0)
{
return index;
}
break;
}
}
return -1;
}
private static int FindOpening(string s, int startIndex)
{
int level = 1;
for (int index = startIndex - 1; index >= 0; --index)
{
switch (s[index])
{
case ']':
++level;
break;
case '[':
if (--level == 0)
{
return index;
}
break;
}
}
return -1;
}
}
答案4:
using System.Collections.Generic;
public static class Kata {
public static string BrainLuck(string code, string input) {
var cells = new Dictionary<int, byte>() { {0,0} };
var ptr = 0;
var inputPtr = 0;
var output = "";
for (var i = 0; i < code.Length; i++) {
switch (code[i]) {
case '>': ptr++; break;
case '<': ptr--; break;
case '+': cells[ptr]++; break;
case '-': cells[ptr]--; break;
case '.': output += (char)cells[ptr]; break;
case ',': cells[ptr] = (byte)input[inputPtr]; inputPtr++; break;
case '[': if (cells[ptr] == 0) i = FindMatch(code, i); break;
case ']': if (cells[ptr] != 0) i = FindMatch(code, i); break;
default: break;
}
if (!cells.ContainsKey(ptr)) cells[ptr] = 0;
}
return output;
}
private static int FindMatch(string code, int index) {
var start = code[index];
var end = (start == '[') ? ']' : '[';
var direction = (start == '[') ? 1 : -1;
var depth = 0;
for (var i = index + direction; i >= 0 && i < code.Length; i += direction) {
if (code[i] == start) {
depth++;
} else if (code[i] == end) {
if (depth == 0) return i;
depth--;
}
}
return -1;
}
}
答案5:
using System.Collections.Generic;
public static class Kata
{
public static string BrainLuck(string code, string input, string outp = "")
{
var data = new byte[32];
for(int i = 0, inP = 0, p = 0; i < code.Length; i++)
{
if (code[i] == '>') p++;
if (code[i] == '<') p--;
if (code[i] == '+') data[p]++;
if (code[i] == '-') data[p]--;
if (code[i] == '.') outp += (char)data[p];
if (code[i] == ',') data[p] = (byte)input[inP++];
if (code[i] == '[' & data[p] == 0) i = BMatch(code, i, -1, 1,']');
if (code[i] == ']' & data[p] != 0) i = BMatch(code, i, 1, -1, '[');
}
return outp;
}
private static int BMatch(string s, int i, int b, int dir, char pair)
{
if (s[i] == pair && b == 0) return i;
if (s[i] == '[') b++;
if (s[i] == ']') b--;
return BMatch(s, i+dir, b, dir, pair);
}
}
答案6:
using System.Collections.Generic;
using System.Linq;
public static class Kata
{
public static string BrainLuck(string code, string input)
{
var outp = new List<byte>();
var data = new byte[9000];
for(int i = 0, inP = 0, p = 0; i < code.Length; i++)
{
if (code[i] == '>') p++;
if (code[i] == '<') p--;
if (code[i] == '+') data[p]++;
if (code[i] == '-') data[p]--;
if (code[i] == '.') outp.Add(data[p]);
if (code[i] == ',') data[p] = (byte)input[inP++];
if (code[i] == '[' & data[p] == 0) i = BMatch(code, i, -1, ']');
if (code[i] == ']' & data[p] != 0) i = BMatch(code, i, 1, '[');
}
return string.Concat(outp.Select(x => (char)x));
}
private static int BMatch(string s, int i, int d, char pair)
{
for (int b = d; (s[i] != pair || b != 0); i -= d)
{
if (s[i] == '[') b++;
if (s[i] == ']') b--;
}
return i;
}
}
答案7:
using System;
using System.Collections.Generic;
using System.Linq;
public static class Kata {
public static string BrainLuck(string code, string input) {
Dictionary<int, int> brackets = new Dictionary<int, int>();
Stack<int> starts = new Stack<int>();
byte[] mem = new byte[256];
string output = "";
int ptr = 0, read = 0;
for (int i = 0; i < code.Length; i++) {
if (code[i] == '[') starts.Push(i);
if (code[i] == ']') brackets.Add(starts.Pop(), i);
}
foreach (var item in brackets.ToArray()) brackets.Add(item.Value, item.Key);
for (int ip = 0; ip < code.Length; ip++) {
if (code[ip] == '[' && mem[ptr] == 0 || code[ip] == ']' && mem[ptr] != 0) ip = brackets[ip];
if (code[ip] == '>' || code[ip] == '<') ptr += code[ip] == '>' ? 1 : -1;
if (code[ip] == '+' || code[ip] == '-') mem[ptr] = (byte)(mem[ptr] + (code[ip] == '+' ? 1 : -1));
if (code[ip] == ',') mem[ptr] = (byte)input[read++];
if (code[ip] == '.') output += (char)mem[ptr];
}
return output;
}
}
答案8:
using System;
using System.Collections.Generic;
using System.Linq;
public class BrainFuckInterpreter
{
string instructions;
string inputStream;
int pntr;
List<int> mem = new List<int>() {0};
string outputString = "";
int instPointer;
private Dictionary<char, Action> ops;
public BrainFuckInterpreter(string program, string input)
{
instructions = program;
inputStream = input;
ops = new Dictionary<char, Action>()
{
{ '>',this.incPntr},
{ '<',this.decPntr},
{ '+',this.incByte},
{ '-',this.decByte},
{ '.',this.output},
{ ',',this.input},
{ '[',this.jmpIfZero},
{ ']',this.jmpIfNonZero},
};
}
public string Run()
{
char op;
while (instPointer < instructions.Length)
{
op = instructions[instPointer];
if (ops.ContainsKey(op))
ops[op]();
else
instPointer++;
}
return outputString;
}
private void incPntr()
{
pntr++;
if (pntr >= mem.Count)
{
mem.Add(0);
}
instPointer++;
}
private void decPntr()
{
pntr--;
if (pntr < 0)
{
pntr = 0;
mem.Insert(0,0);
}
instPointer++;
}
private void incByte()
{
mem[pntr] = (mem[pntr] + 1)%256;
instPointer++;
}
private void decByte()
{
mem[pntr]--;
if (mem[pntr] == -1)
{
mem[pntr] = 255;
}
instPointer++;
}
private void output()
{
outputString += (char)mem[pntr];
instPointer++;
}
private void input()
{
mem[pntr] = inputStream[0];
inputStream = inputStream.Substring(1);
instPointer++;
}
private void jmpIfZero()
{
if (mem[pntr] != 0)
{
instPointer++;
return;
}
var matches = 1;
do
{
instPointer++;
if (instructions[instPointer] == '[')
matches++;
if (instructions[instPointer] == ']')
matches--;
} while (matches != 0);
instPointer++;
}
private void jmpIfNonZero()
{
if (mem[pntr] == 0)
{
instPointer++;
return;
}
var matches = 1;
do
{
instPointer--;
if (instructions[instPointer] == '[')
matches--;
if (instructions[instPointer] == ']')
matches++;
} while (matches != 0);
instPointer++;
}
}
public static class Kata
{
public static string BrainLuck(string code, string input)
{
return new BrainFuckInterpreter(code,input).Run();
}
}
答案9:
using System;
using System.Collections.Generic;
public static class Kata
{
class Data
{
List<short> d = new List<short>();
public Data()
{
}
public short get(int index)
{
if (index < d.Count) return d[index];
else
{
d.AddRange(new short[index - d.Count + 1]);
return 0;
}
}
public void set(short val, int index)
{
if (index < d.Count) d[index] = val;
else
{
d.AddRange(new short[index - d.Count + 1]);
d[index] = val;
}
}
public int len() { return d.Count; }
}
static int findMatchFwd(string code, int start)
{
int open = 1;
for (int i = start + 1; i < code.Length; ++i)
{
if (code[i] == '[') open++;
else if (code[i] == ']') open--;
if (open == 0) return i;
}
return start + 1;
}
static int findMatchBwd(string code, int start)
{
int open = -1;
for (int i = start - 1; i >= 0; --i)
{
if (code[i] == '[') open++;
else if (code[i] == ']') open--;
if (open == 0) return i;
}
return start + 1;
}
public static string BrainLuck(string code, string input)
{
int dataPtr = 0, instrPtr = 0, inputPtr = 0;
Data d = new Data();
string res = "";
while (instrPtr < code.Length)
{
if (code[instrPtr] == ',')
{
if (inputPtr >= input.Length) break;
d.set((short)input[inputPtr++], dataPtr);
instrPtr++;
}
else if (code[instrPtr] == '.')
{
res += ((char)d.get(dataPtr)).ToString();
instrPtr++;
}
else if (code[instrPtr] == '+')
{
short old = d.get(dataPtr);
if (old == 255) old = 0;
else old += 1;
d.set(old, dataPtr);
instrPtr++;
}
else if (code[instrPtr] == '-')
{
short old = d.get(dataPtr);
if (old == 0) old = 255;
else old -= 1;
d.set(old, dataPtr);
instrPtr++;
}
else if (code[instrPtr] == '>')
{
++dataPtr;
instrPtr++;
}
else if (code[instrPtr] == '<')
{
--dataPtr;
instrPtr++;
}
else if (code[instrPtr] == '[')
{
short b = d.get(dataPtr);
if (b != 0)
instrPtr++;
else
{
instrPtr = findMatchFwd(code, instrPtr) + 1;
}
}
else if (code[instrPtr] == ']')
{
short b = d.get(dataPtr);
if (b == 0)
instrPtr++;
else
{
instrPtr = findMatchBwd(code, instrPtr) + 1;
}
}
}
return res;
}
}
答案10:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public static class Kata
{
public static string BrainLuck(string code, string input)
{
var output = new StringBuilder();
var data = new List<byte>() { 0 };
var dataPointer = 0;
var inputPointer = 0;
for(int i = 0;i < code.Length; ++i)
{
if(code[i] == '>')
{
++dataPointer;
if (dataPointer >= data.Count)
data.Add(0);
}
else if(code[i] == '<')
{
--dataPointer;
}
else if(code[i] == '+')
{
++data[dataPointer];
}
else if(code[i] == '-')
{
--data[dataPointer];
}
else if(code[i] == '.')
{
output.Append(Convert.ToChar(data[dataPointer]));
}
else if(code[i] == ',')
{
data[dataPointer] = Convert.ToByte(input[inputPointer++]);
}
else if(code[i] == '[')
{
if(data[dataPointer] == 0)
i = FindMatchingClosingBracket(code, i);
}
else if(code[i] == ']')
{
if(data[dataPointer] != 0)
i = FindMatchingOpeningBracket(code, i) - 1;
}
}
return output.ToString();
}
private static int FindMatchingClosingBracket(string code, int start)
{
var openingBracketsCount = 0;
for(int i = start + 1; i < code.Length; ++i)
{
if(code[i] == '[')
++openingBracketsCount;
else if(code[i] == ']')
{
if(openingBracketsCount == 0)
return i;
else
--openingBracketsCount;
}
}
throw new Exception();
}
private static int FindMatchingOpeningBracket(string code, int start)
{
var closingBracketsCount = 0;
for(int i = start - 1; i > -1; --i)
{
if(code[i] == ']')
++closingBracketsCount;
else if(code[i] == '[')
{
if(closingBracketsCount == 0)
return i;
else
--closingBracketsCount;
}
}
throw new Exception();
}
}