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 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 int GetEntrySizeInBytes(int n, GameMemory zorkFile)
 {
     if (IsNthEntryADictionaryWord(n))
     {
        return 4;
     }
     else
     {
         return ReadCustomSizeFromFile(zorkFile);
     }
 }
示例#5
0
 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 int CountOfSeparatorCharacters(GameMemory zorkFile)
 {
     return zorkFile.ReadByte(ptrToDictionary(zorkFile));
 }
        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 ISet<char> Separators(GameMemory zorkFile)
        {
            //TODO read separators from dictionary.
            int countSeparators = CountOfSeparatorCharacters(zorkFile);
            ByteAddress startOfDictionary = ptrToDictionary(zorkFile);

            return new HashSet<char>(new char[] { ' ' });
        }
        public DictionaryEntry ReadNthEntry(int n, GameMemory zorkFile)
        {
            WordAddress offset = GetOffSetOfNthEntry(n, zorkFile);
            Word[] entryContents = GetContentsOfNthEntry(n, zorkFile);

            List <Zchar> entryZchars = new List<Zchar>();
            foreach(Word contents in entryContents)
            {
                var zchars = Zchar.ReadWordAsZchars(contents);
                entryZchars.AddRange(zchars);
            }
            var chars = Zchar.DecodeFromZString(entryZchars, zorkFile);

            return new DictionaryEntry(
                print: new string(chars.ToArray()),
                ix: n,
                offset: offset);
        }
        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}");
        }
 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);
 }
        public static IEnumerable<char> DecodeFromZString(IEnumerable<Zchar> chars, GameMemory memory, bool permitRecurse = true)
        {
            //THIS IS the least functional-style code in here. it's so stateful. (well, it's a state machine)
            //another way would be to write a function that
            //takes a state and a zchar and decides what to do.
            const int ZCHAR_PER_ABBREV = 6;
            const int lowEntry = 6;
            Zchar? previous = null;
            state current = state.lower;
            int ixCounter = 0; //TEMP DELME
            int fivesToSkip = 0;
            foreach (Zchar ch in chars)
            {
                ixCounter++;

                bool isAbbrev = current == state.abbr || current == state.abbr32 || current == state.abbr64;
                bool isAscii = current == state.ascii || current == state.ascii2;
                if ((ch.Value >= lowEntry || ch.Value == 0)|| (isAbbrev) || (isAscii))
                {
                    switch (current)
                    {
                        case state.abbr:
                        case state.abbr32:
                        case state.abbr64:
                            AbbreviationNumber num = GetFromZcharAndState(current, ch);
                            IEnumerable<Zchar> abbrevs = ReadAbbrevTillBreak(num, memory).ToList();
                            List<char> inner = DecodeFromZString(abbrevs, memory, false).ToList();
                            fivesToSkip = ZCHAR_PER_ABBREV - inner.Count - 1;

                            foreach (char innerChar in inner)
                            {
                                yield return innerChar;
                            }
                            if(fivesToSkip > 0)
                            {
                                current = state.lower;
                                fivesToSkip--;
                                continue;
                            }

                            current = state.lower;
                            break;
                        case state.lower:
                            //Console.Write(Lower[ch.Value]);
                            yield return Lower[ch.Value];
                            break;
                        case state.upper:
                            current = state.lower;
                            //Console.Write(Upper[ch.Value]);
                            yield return Upper[ch.Value];
                            break;
                        case state.symbol:
                            if (ch.Value == 6)
                            {
                                current = state.ascii;
                                continue;
                            }
                            else
                            {
                                current = state.lower;
                                //Console.Write(Symbol[ch.Value]);
                                yield return Symbol[ch.Value];
                            }
                            break;
                        case state.ascii:
                            previous = ch;
                            current = state.ascii2;
                            continue;
                        case state.ascii2:
                            //throw new System.NotImplementedException();
                            //TODO the previous char and the current char
                            // are combined to make an ascii char
                            // not in the tables.
                            break;
                    }
                }
                else
                {
                    switch (ch.Value)
                    {
                        case 1:
                            current = state.abbr;
                            if (!permitRecurse)
                            {
                                //yield break;
                            }
                            break;
                        case 2:
                            current = state.abbr32;
                            if (!permitRecurse)
                            {
                                //yield break;
                            }
                            break;
                        case 3:
                            current = state.abbr64;
                            if (!permitRecurse)
                            {
                                //yield break;
                            }
                            break;
                        case 4:
                            current = state.upper;
                            break;
                        case 5:
                            current = state.symbol;
                            break;
                        case 0:
                            break;
                        default:
                            throw new ArgumentException("Invalid state.");
                    }
                    continue;
                }
            }
        }
        private static void ReadDictionaryTillBreak(GameMemory zorkFile)
        {
            DictionaryHelper dictionary = new DictionaryHelper();

            WordAddress startOfEntries = dictionary.GetOffSetOfNthEntry(0, zorkFile);
            WordAddress ptrFirstEntry = new WordAddress(startOfEntries.Value);

            var test = Zchar.ReadWordsTillBreak(ptrFirstEntry, zorkFile);
            char[] result = Zchar.DecodeFromZString(test, zorkFile, permitRecurse: false)
                .ToArray();

            Console.Write(new string(result));
        }
        /*
         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));
        }
 public ByteAddress ptrToDictionary(GameMemory zorkFile)
 {
     return new ByteAddress(zorkFile.ReadWord(ptrDictionaryPtr).Value);
 }