public byte this[ByteAddress address]
 {
     get
     {
         return this.ReadByte(address);
     }
 }
 public byte ReadAddress(ByteAddress address)
 {
     if (this.edits.ContainsKey(address))
     {
         return this.edits[address];
     }
     return this.InitialState[address.Value];
 }
        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 byte ReadByte(ByteAddress address)
 {
     if(this.dynamicState.IsInRange(address))
     {
         return this.dynamicState[address];
     }
     else
     {
         return ReadAddressFromStaticMemory(address);
     }
 }
        /*
         Structure of Dictionary Header:
         [0] => n := byte containing number of word separator characters
         [1:n] => word separator characters, I believe in ASCII
         [n+1] => size := size of each entry
         [n+2:n+3] => as word, numOfEntries := number of entries
         [n+4:n+(numOfEntires * 2 * size)] => the actual entries

            NOTE that we care about both "entry number" (index into this structure)
            AND about the entry address (offset into file of a given entry)

        */
        public WordAddress GetOffSetOfNthEntry(int n, GameMemory zorkFile)
        {
            ByteAddress startOfDictionary = ptrToDictionary(zorkFile);
            int dictionaryBaseOffset = startOfDictionary.Value;
            int sizeOfSepCountEntry = 1;
            int numberOfSeps = CountOfSeparatorCharacters(zorkFile);
            int sizeOfSizeEntry = 1;
            int sizeOfEntryCountEntry = 2;
            int offsetFirstEntry = dictionaryBaseOffset +
                                    sizeOfSepCountEntry +
                                    numberOfSeps +
                                    sizeOfSizeEntry +
                                    sizeOfEntryCountEntry;

            ByteAddress ptrSizeEntry = new ByteAddress(startOfDictionary.Value + numberOfSeps + sizeOfSepCountEntry);
            int sizeOfEntry = zorkFile.ReadByte(ptrSizeEntry);

            return new WordAddress(offsetFirstEntry + (n * sizeOfEntry));
        }
        private int ReadCustomSizeFromFile(GameMemory zorkFile)
        {
            ByteAddress startOfDictionary = ptrToDictionary(zorkFile);
            int numberOfSeps = CountOfSeparatorCharacters(zorkFile);

            ByteAddress ptrSizeEntry = new ByteAddress(startOfDictionary.Value + numberOfSeps + 1);
            int sizeOfEntry = zorkFile.ReadByte(ptrSizeEntry);
            return sizeOfEntry;
        }
 public void WriteByte(ByteAddress address, byte toWrite)
 {
     this.dynamicState = this.dynamicState.WriteToAddress(address, toWrite);
 }
 private void ValidateAddressToStatic(ByteAddress address)
 {
     if(!IsInStaticRange(address))
     {
         throw new IndexOutOfRangeException();
     }
 }
 private byte ReadAddressFromStaticMemory(ByteAddress address)
 {
     ValidateAddressToStatic(address);
     return this.staticMemory[ByteAddressToStaticIx(address)];
 }
 private bool IsInStaticRange(ByteAddress address)
 {
     return lengthOfDynamicState <= address.Value && address.Value < lengthOfDynamicState + staticMemory.Length;
 }
 private int ByteAddressToStaticIx(ByteAddress address)
 {
     return address.Value - lengthOfDynamicState;
 }
 private void ValidateAddress(ByteAddress address)
 {
     if (IsOutOfRange(address))
     {
         throw new IndexOutOfRangeException();
     }
 }
 private bool IsOutOfRange(ByteAddress address)
 {
     return !IsInRange(address);
 }
 public bool IsInRange(ByteAddress address)
 {
     return 0 <= address.Value && address.Value < InitialState.Length;
 }
 private static void TestReadVersionNumberFromFile(string pathToMiniZork)
 {
     GameMemory miniZork = GameMemory.OpenFile(pathToMiniZork);
     ByteAddress versionAddress = new ByteAddress(0);
     byte versionNumber = miniZork.ReadByte(versionAddress);
     Console.WriteLine($"Mini-Zork version {versionNumber}");
 }
        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));
        }