private static string ReadAsUtf8String(ImmutableByteWrapper bulkEdits) { byte[] asRead = new byte[bulkEdits.Length]; for (int i = 0; i < bulkEdits.Length; i++) { asRead[i] = bulkEdits.ReadAddress(new ByteAddress(i)); } return Encoding.UTF8.GetString(asRead); }
public ImmutableByteWrapper WriteToAddress(ByteAddress address, byte newValue) { ValidateAddress(address); ImmutableByteWrapper retval = new ImmutableByteWrapper(); retval.InitialState = this.InitialState; //it's immutable, so every instance can share a pointer to it. retval.edits = new Dictionary<ByteAddress, byte>(this.edits); retval.edits[address] = newValue; return retval; }
public ImmutableByteWrapper WriteMultipleAddress(IEnumerable<Tuple<ByteAddress, byte>> writes) { ImmutableByteWrapper retval = new ImmutableByteWrapper(); retval.InitialState = this.InitialState; retval.edits = new Dictionary<ByteAddress, byte>(this.edits); foreach(var toWrite in writes) { ValidateAddress(toWrite.Item1); retval.edits[toWrite.Item1] = toWrite.Item2; } return retval; }
public static GameMemory OpenFile(string filename) { byte[] file = ReadFile(filename); int length = file.Length; if(length < headerSize) { throw new ArgumentException($"{filename} is not a valid story file"); } ImmutableByteWrapper wrapper = new ImmutableByteWrapper(file); byte high = wrapper.ReadAddress(Bits.AddressOfHighByte(baseOffset)); byte low = wrapper.ReadAddress(Bits.AddressOfLowByte(baseOffset)); int dynamicSegmentLength = (256 * high) + low; if(dynamicSegmentLength > length) { throw new ArgumentException($"{filename} is not a valid story file"); } byte[] dynamicPart = new byte[dynamicSegmentLength]; Array.Copy(file, dynamicPart, dynamicSegmentLength); byte[] staticPart = new byte[length - dynamicSegmentLength]; Array.Copy(file, dynamicSegmentLength, staticPart, 0, length - dynamicSegmentLength); return new GameMemory(staticPart, new ImmutableByteWrapper(dynamicPart)); }
public void WriteByte(ByteAddress address, byte toWrite) { this.dynamicState = this.dynamicState.WriteToAddress(address, toWrite); }
public GameMemory(byte[] staticMemory, ImmutableByteWrapper dynamicState) { this.lengthOfDynamicState = dynamicState.Length; this.staticMemory = staticMemory.ToImmutableArray<byte>(); this.dynamicState = dynamicState; }
private static void TestReadingAndWritingGameState() { string storyState = "Listen to a story 'bout a guy named Al"; string interpreterState = "Who lived in the sewer with his hamster pal"; int expectedImmutableSize = Encoding.UTF8.GetByteCount(storyState); byte[] immutablePart = Encoding.UTF8.GetBytes(storyState); int expectedDynamicSize = Encoding.UTF8.GetByteCount(interpreterState); byte[] dynamicPart = Encoding.UTF8.GetBytes(interpreterState); ImmutableByteWrapper changingPart = new ImmutableByteWrapper(dynamicPart); GameMemory gameState = new GameMemory(immutablePart, changingPart); WordAddress zeroPointer = new WordAddress(0); List<WordAddress> firstFivePointers = Enumerable.Range(0, 5) .Select(el => zeroPointer + el) .ToList(); IEnumerable<ByteAddress> firstTenByteAddress = Enumerable.Range(0, 10) .Select(el => new ByteAddress(el)); byte[] firstTenBytes = firstTenByteAddress .Select(p => gameState.ReadByte(p)) .ToArray(); byte[] firstFiveWords = firstFivePointers .Select(p => gameState.ReadWord(p)) .SelectMany(word => new byte[] { (byte)(word.Value & 0xFF), (byte)((word.Value >> 8) & 0xFF) }) .ToArray(); string firstFive = new string(Encoding.UTF8.GetChars(firstFiveWords)); byte[] firstFiveTransposed = firstFivePointers .Select(p => gameState.ReadWord(p)) .SelectMany(word => new byte[] { (byte)((word.Value >> 8) & 0xFF), (byte)(word.Value & 0xFF) }) .ToArray(); string firstFiveTransposedRead = new string(Encoding.UTF8.GetChars(firstFiveTransposed)); string whatIRead = new String(Encoding.UTF8.GetChars(firstTenBytes)); //test writing to game state: //replace "Who lived " with // "zzCheese2 " byte[] toWrite = Encoding.UTF8.GetBytes("zzCheese2 "); System.Diagnostics.Debug.Assert(toWrite.Length == firstTenBytes.Length); Enumerable.Range(0, 10) .Select(el => new { address = new ByteAddress(el), val = toWrite[el] }) .ToList() .ForEach(item => gameState.WriteByte(item.address, item.val)); byte[] firstTenBytesAgain = firstTenByteAddress .Select(p => gameState.ReadByte(p)) .ToArray(); string mutated = new string(Encoding.UTF8.GetChars(firstTenBytesAgain)); //test writing Words instead of bytes to game state: byte[] toWriteWordWise = Encoding.UTF8.GetBytes("aaZZeess33"); WordAddress zero = new WordAddress(0); for(int i = 0; i < toWriteWordWise.Length - 1; i += 2) { int val = (toWriteWordWise[i] * 256 + toWriteWordWise[i + 1]); WordAddress address = zero + i / 2; gameState.WriteWord(address, new Word(val)); } byte[] firstTenBytesAgain2 = firstTenByteAddress .Select(p => gameState.ReadByte(p)) .ToArray(); string mutated2 = new string(Encoding.UTF8.GetChars(firstTenBytesAgain2)); Console.WriteLine($"{whatIRead} became {mutated} and then {mutated2}"); }
private static void TestMemoryBase() { byte[] bytes = Encoding.UTF8.GetBytes("Hello World"); ImmutableByteWrapper initialState = new ImmutableByteWrapper(bytes); ByteAddress address1 = new ByteAddress(1); ImmutableByteWrapper edited = initialState.WriteToAddress(address1, 0x00); //owerwrite "world" byte[] newBytes = Encoding.UTF8.GetBytes("woid!"); IEnumerable<int> sixThruTen = Enumerable.Range(6, 5); var multiEdits = sixThruTen.Select(val => { var address = new ByteAddress(val); var toWrite = newBytes[val - 6]; return new Tuple<ByteAddress, byte>(address, toWrite); }); ImmutableByteWrapper bulkEdits = initialState.WriteMultipleAddress(multiEdits); var toPrint = ReadAsUtf8String(bulkEdits); var oldToPrint = ReadAsUtf8String(initialState); Console.WriteLine($"Initial state has {oldToPrint} and bulk edited has {toPrint}"); int length = initialState.Length; Console.WriteLine(edited.ReadAddress(address1)); Console.WriteLine(initialState.ReadAddress(address1)); }