Using Xamarin to develop mobile application example -- Sudoku game to save game progress

Posted by Courbois on Sun, 30 Jan 2022 08:16:36 +0100

The project code can be downloaded from Github: https://github.com/zhenl/ZL.Shudu . The code is updated with the progress of the project.

Saving progress is the basic function of mobile applications. During the use of applications, there will be various problems that may lead to use interruption. When returning to the application again, it should be restored to the state before interruption. Previously, we have preliminarily completed the Sudoku game, but we do not have the function of state saving. Now we add this function to save the game progress to the local file.

First, determine where to save and restore the state. The ondisappealing event will be triggered when Xamarin's View exits. In this event, the progress of the game can be saved. When the View is displayed again, first judge whether there is a saved progress. If there is, restore the state, otherwise create a new game.

Then determine the content to be saved, the number and location that have been entered, the input process and the time spent.

There is also the storage location. Xamarin provides an abstract location for each application to save data. We can use environment Getfolderpath (environment. Specialfolder. Localapplicationdata) to get the path without considering the device type.

After all these are determined, the corresponding logic can be written.

The first is the method to save the status:

      private void Save(string filename)
        {
            try
            {
                var strchess = "";
                for (var i = 0; i < 9; i++)
                {
                    for (var j = 0; j < 9; j++)
                    {
                        strchess += chess[i, j].ToString();
                    }
                }
                strchess += " ";
                for (var i = 0; i < 9; i++)
                {
                    for (var j = 0; j < 9; j++)
                    {
                        strchess += string.IsNullOrEmpty(buttons[i, j].Text) ? "0" : buttons[i, j].Text;
                    }
                }
                strchess += " ";
                foreach (var str in steps)
                {
                    strchess += str + ";";
                }
                strchess += " ";
                strchess += (DateTime.Now - dtBegin).Ticks.ToString();
                string _fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), filename);
                File.WriteAllText(_fileName, strchess);
            }
            catch (Exception ex)
            {

                lbMessage.Text = ex.Message;
            }
        }

Call this method in the OnDisappearing event response:

        protected override void OnDisappearing()
        {
            Save("shudu_current.txt");
        }

The function of restoring state is as follows:

     private bool OpenCurrent()
        {
            try
            {
                string _fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "shudu_current.txt");
                if (File.Exists(_fileName))
                {
                    var strchess = File.ReadAllText(_fileName);
                    int[,] fchess = new int[9, 9];
                    var arr = strchess.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    for (var i = 0; i < 9; i++)
                    {
                        for (var j = 0; j < 9; j++)
                        {
                            chess[i, j] = int.Parse(arr[0].Substring(i * 9 + j, 1));
                            fchess[i, j] = int.Parse(arr[1].Substring(i * 9 + j, 1));
                        }
                    }
                    for (var i = 0; i < 9; i++)
                    {
                        for (var j = 0; j < 9; j++)
                        {
                            var btn = buttons[i, j];
                            if (chess[i, j] > 0)
                            {
                                btn.Text = chess[i, j].ToString();
                            }
                            else
                            {
                                btn.Text = fchess[i, j] > 0 ? fchess[i, j].ToString() : "";
                            }
                            btn.IsEnabled = chess[i, j] == 0;
                            int m = i / 3;
                            int n = j / 3;

                            var c = new Color(0.9, 0.9, 0.9);
                            if ((m + n) % 2 == 0)
                            {
                                c = new Color(0.7, 0.7, 0.7);
                            }
                            btn.BackgroundColor = c;
                        }
                    }
                    if (arr.Length > 2)
                    {
                        var steparr = arr[2].Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        steps.Clear();
                        foreach(var step in steparr) steps.Push(step);
                    }
                    if (arr.Length > 3)
                    {
                        currentDiffer = long.Parse(arr[3]);
                    }
                    dtBegin = DateTime.Now;
                    return true;
                }
            }
            catch (Exception ex)
            {

                lbMessage.Text = ex.Message;
            }
            return false;
        }

Call this function during initialization:

        public Game()
        {
            try
            {
                InitializeComponent();

                SetNumButtons();
                SetLayout();
                if (!OpenCurrent()) SetNewGame();

            }
            catch (Exception ex)
            {
                lbMessage.IsVisible = true;
                rowResult.Height = 40;
                lbMessage.Text = ex.Message;
                //throw;
            }
        }

Finally, delete the status file at the end of the game:

            if (IsFinish())
            {
                lbFinish.IsVisible = true;
                lbTime.IsVisible = true;
                rowResult.Height = 40;
                var diff = (DateTime.Now.Ticks - dtBegin.Ticks + currentDiffer) / 10000 / 1000 / 60;
                lbTime.Text = diff + "minute";
                string _fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "shudu_current.txt");
                File.Delete(_fileName);
            }

Status saving is complete. Next, we introduce the database to save the game results and add the input function of new games.

Topics: C# xamarin