public static WordAddress AddressOfAbbreviationByNumber(AbbreviationNumber number, GameMemory memory)
 {
     AbbreviationTableBase basePtr = new AbbreviationTableBase(memory);
     WordAddress addressOfPtrToAbbrTable = new WordAddress(24);
     WordAddress ptrToAbbrevTable = new WordAddress(memory.ReadWord(addressOfPtrToAbbrTable).Value);
     WordAddress ptrToChosenAbbrv = ptrToAbbrevTable + (number.Value);
     WordAddress decompressedAbbrvPtr = new WordAddress(memory.ReadWord(ptrToChosenAbbrv).Value * 2);
     return decompressedAbbrvPtr;
 }
        public Word[] GetContentsOfNthEntry(int n, GameMemory zorkFile)
        {
            int entrySize =  GetEntrySizeInBytes(n, zorkFile);

            // I have been assuming that the above call will return 4, since that
            // is how many bytes are in a word entry. But it think this size
            // allows there to be arbitrary entries after all the words, and they might
            // be of up to this size.

            // Two questions:

            // 1. How do I know that we are in the size-regulated, has words-in-order
            // part of the dictionary?

            // 2. How do I know the size of the entries that are after the words,
            // in the arbitrary-sized part of the table?

            int entrySizeInWords = entrySize / 2;

            Word[] retval = new Word[entrySizeInWords];
            WordAddress ptrStartOfEntry = GetOffSetOfNthEntry(n, zorkFile);

            for(int i = 0; i < entrySizeInWords; i++)
            {
                WordAddress here = new WordAddress(ptrStartOfEntry.Value + (i * 2));
                retval[i] = zorkFile.ReadWord(here);
            }

            return retval;
        }
 public int CountOfEntries(GameMemory zorkFile)
 {
     ByteAddress startOfDictionary = ptrToDictionary(zorkFile);
     int countSepCharacters = CountOfSeparatorCharacters(zorkFile);
     WordAddress ptrToEntryCount = new WordAddress(startOfDictionary.Value + 1 + countSepCharacters + 2);
     return zorkFile.ReadWord(ptrToEntryCount).Value;
 }
 public static List<Zchar> ReadStringFromAddress(WordAddress address, GameMemory memory)
 {
     throw new System.NotImplementedException();
     List<Zchar> retval = new List<Zchar>();
     Word word = memory.ReadWord(address);
     while(!word.IsTerminal())
     {
         //Zchar char1 = new Zchar(new AbbreviationNumber(Bits.FetchBits(BitNumber.Bit14, BitSize.Size5, word)));
         //Zchar char2 = new Zchar(new AbbreviationNumber(Bits.FetchBits(BitNumber.Bit9, BitSize.Size5, word)));
         //Zchar char3 = new Zchar(new AbbreviationNumber(Bits.FetchBits(BitNumber.Bit4, BitSize.Size5, word)));
         //retval.Add(char1);
         //retval.Add(char2);
         //retval.Add(char3);
         address = address + 1;
         word = memory.ReadWord(address);
     }
     return retval;
 }
 public ByteAddress ptrToDictionary(GameMemory zorkFile)
 {
     return new ByteAddress(zorkFile.ReadWord(ptrDictionaryPtr).Value);
 }
 public AbbreviationTableBase(GameMemory memory)
 {
     WordAddress addrOfTableBasePtr = new WordAddress(24);
     WordAddress addressOfTableBase = new WordAddress(memory.ReadWord(addrOfTableBasePtr).Value);
     this.value = addressOfTableBase.Value;
 }
 public static IEnumerable<char> YieldAbbreviationFromAbbreviationNumber(AbbreviationNumber number, GameMemory memory)
 {
     WordAddress addressOfPtrToAbbrTable = new WordAddress(24);
     WordAddress ptrToAbbrevTable = new WordAddress(memory.ReadWord(addressOfPtrToAbbrTable).Value);
     WordAddress address = AbbreviationTableBase.AddressOfAbbreviationByNumber(number, memory);
     Word word = memory.ReadWord(address);
     while (true)
     {
         char[] firstThree = Zchar.PrintWordAsZchars(word).ToCharArray();
         foreach (char ch in firstThree)
         {
             yield return ch;
         }
         if (word.IsTerminal())
         {
             yield break;
         }
         address = address + 1;
         word = memory.ReadWord(address);
     }
 }
 public static IEnumerable<Zchar> ReadWordsTillBreak(WordAddress address, GameMemory memory, ISet<char> breakers = null)
 {
     while (true)
     {
         Word word = memory.ReadWord(address);
         Zchar low = new Zchar(Bits.FetchBits(BitNumber.Bit14, BitSize.Size5, word));
         Zchar mid = new Zchar(Bits.FetchBits(BitNumber.Bit9, BitSize.Size5, word));
         Zchar high = new Zchar(Bits.FetchBits(BitNumber.Bit4, BitSize.Size5, word));
         yield return low;
         yield return mid;
         yield return high;
         if (word.IsTerminal(breakers))
         {
             yield break;
         }
         address = address + 1;
     }
 }
 public static IEnumerable<Zchar> ReadAbbrevTillBreak(AbbreviationNumber num, GameMemory memory)
 {
     WordAddress addressOfPtrToAbbrTable = new WordAddress(24);
     WordAddress ptrToAbbrevTable = new WordAddress(memory.ReadWord(addressOfPtrToAbbrTable).Value);
     WordAddress ptrChosenAbbrev = AbbreviationTableBase.AddressOfAbbreviationByNumber(num, memory);
     return ReadWordsTillBreak(ptrChosenAbbrev, memory);
 }
        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}");
        }