예제 #1
0
        ///<summary>Loader of txt levelset (filename, simplified loading for fast update)</summary>
        public FunctionResult LoadTxtLevelSet(string sFileName, bool bSimplified)
        {
            System.IO.StreamReader hReader;//For reading file
            try
            {
                hReader = new System.IO.StreamReader(sFileName);//Open file
            }
            catch
            {
                return FunctionResult.FailedToOpenFile;//Unable
            }

            Reset();//Reset levelset

            string sLine, sTrim;
            string sLastNotEmpty="";
            char[] sChars;
            int i,j;
            int iPos, iEnd;
            int iCommentPhase;//Comment phase: 0 - before comments block found, 1 - inside, 2 - after
            SokoCell uNewCell;

            try
            {
                sTitle = System.IO.Path.GetFileNameWithoutExtension(sFileName);//Assing initial title (would be replaced by title from file, if specified)
            }
            catch
            {
                return FunctionResult.FileSystemError;//Something very wrong with filename
            }

            ArrayList uXSizeList = new ArrayList(20);
            ArrayList uYSizeList = new ArrayList(20);
            ArrayList uPosList = new ArrayList(20);
            ArrayList uFileLines = new ArrayList(100);

            //Stag 1. Estimate level number and their sizes

            int iPhase = 0;
            iLevelsNum = 0;
            iCommentPhase = 0;
            int iX = 0; int iY = 0;

            while (!hReader.EndOfStream)  //Read till end of file
            {
                try
                {
                    sLine = hReader.ReadLine(); //Read one line of file
                }
                catch
                {
                    return FunctionResult.ErrorOnReadingFile;//Something wrong with file
                }
                uFileLines.Add(sLine);//Store line into array
                sTrim = sLine.Trim();
                if (sTrim.StartsWith("#"))
                {//All lines, that starts with # are lines of level board
                    if (iPhase != 2)
                    {//Level was not yet started
                        iLevelsNum++;//Start level
                        uPosList.Add(uFileLines.Count-1);//Remeber line, where level starts
                        iPhase = 2;//Now we loading level
                        iX = 0;//Initial sizes
                        iY = 0;
                    }
                    iY++;//New line for level
                    if (iX < sLine.Length) iX = sLine.Length;//Update width of level, if needed
                }
                else
                {//All lines, that not starts with # are delimits levels from each other
                    if (iPhase == 0)
                    {   //Header of levelset
                        try
                        {   //Try to get values from comments (comparisons should be in increment-len order, otherwise exception may occurs earlier, than line will be found)
                            if (sTrim.Substring(0, 6) == "Name: ")
                            {
                                sTitle = sTrim.Substring(6);
                                sTrim = "";
                            }
                            else if (sTrim.Substring(0, 7) == "Title: ")
                            {
                                sTitle = sTrim.Substring(7);
                                sTrim = "";
                            }
                            else if (sTrim.Substring(0, 8) == "Author: ")
                            {
                                sAuthor = sTrim.Substring(8);
                                sTrim = "";
                            }
                            else if (sTrim.Substring(0, 8) == "Comment:")
                            {
                                sComment = "";
                                if (sTrim.Length > 8)
                                    sComment = sTrim.Substring(8).Trim();//Line contain text after "Comment:", so it is single-line comment
                                else
                                    iCommentPhase = 1;//Line do not contain other text, so it is multi-line comment
                                sTrim = "";
                            }
                            else if (sTrim.Substring(0, 11) == "Copyright: ")
                            {
                                sCopyright = sTrim.Substring(11);
                                sTrim = "";
                            }
                            else if (sTrim.Substring(0, 11) == "Comment-End")
                            {//End of multi-line comment
                                iCommentPhase = 2;
                                sTrim = "";
                            }
                        }
                        catch (ArgumentOutOfRangeException)
                        {
                            //If line is very short, substring will throw exception. We bury such exceptions here :)
                        }
                        if (iCommentPhase == 1)
                        {   //Multiline comment continuing
                            if (sComment.Length > 0)
                                sComment += "\r\n";//Not first line, add line delimiter
                            sComment += sTrim;
                            sTrim = "";
                        }
                        if (sTrim.Length > 0)
                        {   //Line is still not identified
                            if (iCommentPhase == 0)
                            {   //All lines before comment block could be comment
                                if (sComment.Length > 0)
                                    sComment += "\r\n";//Not first line, add line delimiter
                                sComment += sTrim;
                            }
                            sLastNotEmpty = sTrim;//Store line, it could be title for first level
                        }
                    }

                    if (iPhase == 2)
                    {   //Level was ended
                        uXSizeList.Add(iX);//Add sizes of level into arrays
                        uYSizeList.Add(iY);
                        iPhase = 3;//Now we waiting next level
                    }
                }
            }
            if (iPhase == 2)
            {   //Last level was not fully ended, end it here
                uXSizeList.Add(iX);
                uYSizeList.Add(iY);
            }
            hReader.Close();//Close file

            if (iLevelsNum == 0)
                return FunctionResult.NoLevelsFound;//No levels found in file

            //Stage 2. Loading all detected levels

            iLevelsAllocated = iLevelsNum;//Now we know exact number of levels
            uLevels = new SokobanLevel[iLevelsAllocated];//Allocate array of levels

            for (i = 0; i < iLevelsNum; i++) //Iterate for all levels
            {
                //Create new level with sizes, calculated in stage 1
                uLevels[i] = new SokobanLevel((int)uXSizeList[i], (int)uYSizeList[i]);

                if (bSimplified) continue;//Simplified loading - skip decoding levels (for fast updating list of levelsets, level contructor above required to load record file and calculate number of solved levels)

                //uLevels[i].sTitle = "unnamed level " + (i + 1).ToString();//Initial level title
                uLevels[i].sTitle = ""; //void level title

                iPos = (int)uPosList[i];//Restore line number, where level starts

                //Choose where we should end loading level
                if (i<(iLevelsNum-1))
                    iEnd = (int)uPosList[i + 1]; //Not last level - up to first line of previous level
                else
                    iEnd = uFileLines.Count; //Last level - up to last line of level

                iPhase = 1;//Initial phase - comment before level
                iCommentPhase = 0;
                iY = 0;
                //uNewCell = SokoCell.Background;

                while (iPos < iEnd)//Iterate thru all lines of level board
                {
                    sLine = (string)uFileLines[iPos]; iPos++;//Restore line from array
                    sTrim = sLine.Trim();//Trim whitespaces
                    if (sTrim.StartsWith("#"))
                    {   //All lines that starts with # are lines of level
                        if (iPhase == 1)
                        {   //Get title from last unidentified line
                            uLevels[i].sTitle = sLastNotEmpty;
                        }
                        if (iPhase == 3)
                        {   //Level board already was loaded, it cannot start second time
                            break;//Exit from loading this level
                        }
                        iPhase = 2;//Now we loading level
                        sChars = sLine.ToCharArray();//Get chars of string
                        iX = 0;//Start new line
                        for (j = 0; j < sChars.Length; j++)//Iterate thru all chars
                        {
                            switch (sChars[j])//Decore char into cell of level
                            {
                                case '#': uNewCell = SokoCell.Wall; break;
                                case ' ': uNewCell = SokoCell.Empty; break;
                                case '.': uNewCell = SokoCell.Target; break;
                                case '$': uNewCell = SokoCell.Box; break;
                                case '@': uNewCell = SokoCell.Player; break;
                                case '*': uNewCell = SokoCell.BoxOnTarget; break;
                                case '+': uNewCell = SokoCell.PlayerOnTarget; break;
                                default: continue;//Unknown - skipped
                            }
                            uLevels[i].SetCell(iX, iY, uNewCell);//Put cell into level
                            iX++;//Advance to next cell
                        }
                        iY++;//Advance to next line
                    }
                    else
                    {   //All lines, that not starts with # are delimits levels from each other

                        if (iPhase == 2)//If level just ends
                            sLastNotEmpty = "";//Forgot all previous unidentified lines

                        iPhase = 3;//Now we are after level board
                        try
                        {   //Try to get values from comments (comparisons should be in increment-len order, otherwise exception may occurs earlier, than line will be found)
                            if (sTrim.Substring(0, 7) == "Title: ")
                            {
                                uLevels[i].sTitle = sTrim.Substring(7);
                                sTrim = "";
                            }
                            else if (sTrim.Substring(0, 8) == "Author: ")
                            {
                                uLevels[i].sAuthor = sTrim.Substring(8);
                                sTrim = "";
                            }
                            else if (sTrim.Substring(0, 8) == "Comment:")
                            {
                                if (sTrim.Length > 8)
                                    uLevels[i].sComment = sTrim.Substring(8).Trim();//Line contain text after "Comment:", so it is single-line comment
                                else
                                    iCommentPhase = 1;//Line do not contain other text, so it is multi-line comment
                                sTrim = "";
                            }
                            else if (sTrim.Substring(0, 11) == "Comment-End")
                            {   //Multi-line comment ends
                                iCommentPhase = 0;
                                sTrim = "";
                            }
                        }
                        catch (ArgumentOutOfRangeException)
                        {
                            //If line is very short, substring will throw exception. We bury such exceptions here :)
                        }
                        if (iCommentPhase == 1)
                        {   //Multiline comment continuing
                            if (uLevels[i].sComment.Length > 0)
                                uLevels[i].sComment += "\r\n";//Not first line, add line delimiter
                            uLevels[i].sComment += sTrim;
                            sTrim = "";
                        }
                        if (sTrim.Length > 0)
                        {   //Line is still not identified
                            sLastNotEmpty = sTrim;//Store line, it could be title for next level
                        }

                    }
                }
                if (uLevels[i].sTitle.Length <= 0)
                {
                    uLevels[i].sTitle = "level " + (i+1).ToString();//Initial level title
                }
                uLevels[i].CleanUp();//Distinguish backgrounds from empty cells (both specified as spaces in file)
            }

            return FunctionResult.OK;//Level set successfully loaded
        }
예제 #2
0
        ///<summary>Copy-constructor for creating temprorary levels (source level)</summary>
        public SokobanGame(SokobanLevel uLevelToCopy)
        {
            iMovesAlloc = 0;
            iReversAlloc = 0;
            CopyFrom(uLevelToCopy);//Copy all data from source

            //Flush player and box move trees
            iMoveTreeFromX = -1; iMoveTreeFromY = -1;
            iBoxMoveTreeFromX = -1; iBoxMoveTreeFromY = -1;
        }
예제 #3
0
        ///<summary>Generate null level set - 1 random level</summary>
        public FunctionResult GenNullLevelSet()
        {
            int i, j,k;
            int iXsize, iYsize;
            Random uRandom = new Random(Environment.TickCount);
            Reset();//Reset levelset

            sAuthor = "SokobanCompact";
            sComment = "Randomly generated";
            sCopyright = "";
            sTitle = "null levelset";
            sFileName = sNullName;
            sID = sNullName;

            sRecordFile = null;

            iLevelsNum = 1;//1 level
            iLevelsAllocated = iLevelsNum;
            uLevels = new SokobanLevel[iLevelsAllocated];//Allocate array of levels
            iXsize = 10;
            iYsize = 10;
            uLevels[0] = new SokobanLevel(iXsize, iYsize);
            uLevels[0].sTitle = "null level";
            uLevels[0].sAuthor = "SokobanCompact";
            uLevels[0].sComment = "Randomly generated";
            for (i = 0; i < iXsize; i++)
                for (j = 0; j < iYsize; j++)
                {
                    if (i==0 || j==0 || i==(iXsize-1) || j==(iYsize-1))
                        uLevels[0].SetCell(i, j, SokoCell.Wall);
                    else
                        uLevels[0].SetCell(i, j, SokoCell.Empty);
                }
            uLevels[0].SetCell(1, 1, SokoCell.Player);

            k = 0;
            do
            {
                i = uRandom.Next(2, iXsize - 2);
                j = uRandom.Next(2, iYsize - 2);
                if (uLevels[0].GetCell(i, j)!=SokoCell.Empty) continue;
                uLevels[0].SetCell(i, j, SokoCell.Box);
                k++;
            } while (k < 10);

            k = 0;
            do
            {
                i = uRandom.Next(2, iXsize - 2);
                j = uRandom.Next(2, iYsize - 2);
                if (uLevels[0].GetCell(i, j)!=SokoCell.Empty) continue;
                uLevels[0].SetCell(i, j, SokoCell.Target);

                k++;
            } while (k < 10);
            return FunctionResult.OK;
        }