Эффективность сортировки массивов ... Новичку нужен совет - PullRequest
1 голос
/ 18 февраля 2011

Начну с того, что я очень начинающий программист, по сути, это мой первый настоящий проект за пределами использования учебного материала. Я делал игру в стиле «Simon Says» (игра, в которой вы повторяете шаблон, сгенерированный компьютером) с использованием C # и XNA, настоящая игра завершена и работает нормально, но, создавая ее, я также хотел создать табло лучших 10 '. На табло будут записываться имя игрока, уровень (сколько «раундов» они завершили) и комбо (сколько нажатий кнопок они получили правильно), а затем табло будет отсортировано по комбинированному баллу. Это привело меня к XML, впервые использующему его, и я в конечном итоге дошел до того, что получил XML-файл, в котором записаны 10 лучших результатов. XML-файл управляется в классе табло, который также отвечает за добавление новых баллов и сортировку баллов. Это подводит меня к делу ... Я хотел бы получить некоторые отзывы о том, как я сортировал список результатов и как я мог бы сделать это лучше, у меня нет другого способа получить обратную связь = (. Я знаю. NET имеет Array.Sort (), но я не был уверен, как его использовать, так как это не просто один массив, который нужно отсортировать. Когда нужно ввести новый счет в табло, имя и уровень игрока также должны быть добавлены. Они хранятся в «массиве массивов» (10 = для «10 лучших баллов»)

scoreboardComboData = new int[10]; // Combo

scoreboardTextData = new string[2][];
scoreboardTextData[0] = new string[10]; // Name
scoreboardTextData[1] = new string[10]; // Level as string

Класс табло работает следующим образом:

- Проверяет, существует ли «Scoreboard.xml», если нет, то создает его
- Инициализирует вышеуказанные массивы и добавляет любые данные игрока из Scoreboard.xml, из предыдущего запуска
- когда вызывается AddScore (имя, уровень, комбо), сортировка начинается
- Можно также вызвать другой метод, который заполняет файл XML данными массива выше

Сортировка проверяет, является ли новая оценка (комбинированная) меньше или равна любой записанной оценке в массиве ScoreboardComboData (если она больше оценки, она переходит к следующему элементу). Если это так, он перемещает все баллы ниже балла, на который он меньше или равен одному элементу, по существу удаляя последний балл, а затем помещает новый балл в элемент ниже балла, на который он меньше или равен. Если оценка превышает все записанные оценки, она сдвигает все оценки на единицу и вставляет новую оценку в первый элемент. Если это единственный результат, он просто добавляет его к первому элементу. Когда добавляется новый счет, данные имени и уровня также добавляются в соответствующие массивы аналогичным образом. Что за скороговорка. Ниже приведен метод AddScore, я добавил комментарии в надежде, что он прояснит ситуацию O_o. Вы можете получить фактический исходный файл ЗДЕСЬ . Ниже приведен пример самого быстрого способа добавления оценки для отладчика.

    public static void AddScore(string name, string level, int combo)
    {
        // If the scoreboard has not yet been filled, this adds another 'active'
        // array element each time a new score is added. The actual array size is
        // defined within PopulateScoreBoard() (set to 10 - for 'top 10'
        if (totalScores < scoreboardComboData.Length)
            totalScores++;

        // Does the scoreboard even need sorting?
        if (totalScores > 1)
        {
            for (int i = totalScores - 1; i > - 1; i--)
            {
                // Check to see if score (combo) is greater than score stored in 
                // array
                if (combo > scoreboardComboData[i] && i != 0)
                {
                    // If so continue to next element
                    continue;
                }

                // Check to see if score (combo) is less or equal to element 'i'
                // score && that the element is not the last in the
                // array, if so the score does not need to be added to the scoreboard
                else if (combo <= scoreboardComboData[i] && i != scoreboardComboData.Length - 1)
                {
                    // If the score is lower than element 'i' and greater than the last
                    // element within the array, it needs to be added to the scoreboard. This is achieved
                    // by moving each element under element 'i' down an element. The new score is then inserted
                    // into the array under element 'i'
                    for (int j = totalScores - 1; j > i; j--)
                    {
                        // Name and level data are moved down in their relevant arrays
                        scoreboardTextData[0][j] = scoreboardTextData[0][j - 1];
                        scoreboardTextData[1][j] = scoreboardTextData[1][j - 1];
                        // Score (combo) data is moved down in relevant array
                        scoreboardComboData[j] = scoreboardComboData[j - 1];
                    }

                    // The new Name, level and score (combo) data is inserted into the relevant array under element 'i'
                    scoreboardTextData[0][i + 1] = name;
                    scoreboardTextData[1][i + 1] = level;
                    scoreboardComboData[i + 1] = combo;
                    break;
                }

                // If the method gets the this point, it means that the score is greater than all scores within
                // the array and therefore cannot be added in the above way. As it is not less than any score within
                // the array.
                else if (i == 0)
                {
                    // All Names, levels and scores are moved down within their relevant arrays
                    for (int j = totalScores - 1; j != 0; j--)
                    {
                        scoreboardTextData[0][j] = scoreboardTextData[0][j - 1];
                        scoreboardTextData[1][j] = scoreboardTextData[1][j - 1];
                        scoreboardComboData[j] = scoreboardComboData[j - 1];
                    }

                    // The new number 1 top name, level and score, are added into the first element
                    // within each of their relevant arrays.
                    scoreboardTextData[0][0] = name;
                    scoreboardTextData[1][0] = level;
                    scoreboardComboData[0] = combo;

                    break;
                }

                // If the methods get to this point, the combo score is not high enough
                // to be on the top10 score list and therefore needs to break
                break;
            }
        }

        // As totalScores < 1, the current score is the first to be added. Therefore no checks need to be made
        // and the Name, Level and combo data can be entered directly into the first element of their relevant
        // array.
        else
        {
            scoreboardTextData[0][0] = name;
            scoreboardTextData[1][0] = level;
            scoreboardComboData[0] = combo;
        }


    }
}

Пример добавления оценки:

    private static void Initialize()
    {
        scoreboardDoc = new XmlDocument();
        if (!File.Exists("Scoreboard.xml"))
            GenerateXML("Scoreboard.xml");

        PopulateScoreBoard("Scoreboard.xml");

        // ADD TEST SCORES HERE!
        AddScore("EXAMPLE", "10", 100);
        AddScore("EXAMPLE2", "24", 999);

        PopulateXML("Scoreboard.xml");
    }

В своем текущем состоянии исходный файл используется только для тестирования, инициализация вызывается в main, а PopulateScoreBoard обрабатывает большинство других инициализаций, поэтому больше ничего не требуется, кроме добавления результатов теста.

Я благодарю вас за потраченное время!

Ответы [ 3 ]

3 голосов
/ 18 февраля 2011

В качестве подсказки по программированию вы должны заменить 3 разных массива одним массивом объектов Score, каждый из этих объектов будет иметь все 3 свойства, которые вы упомянули (Name, Level и Score).Затем вы можете создать для него функцию, подобную компаратору (на основе атрибута Score), которую можно использовать для сортировки с помощью метода Arrays.Sort().

Если вы хотите сохранить текущие 3 массива, вы можетепосмотрите алгоритмы сортировки здесь: http://en.wikipedia.org/wiki/Sorting_algorithm#Comparison_of_algorithms и просто сделайте так, чтобы любые изменения выполнялись в 3-х массивах одновременно, а не по одному (так как данные в них синхронизируются по индексу).

1 голос
/ 18 февраля 2011

Вы можете рассмотреть возможность размещения своего имени пользователя, уровня и оценки в отдельном классе (назовем его ScoreBoardEntry), который наследуется от IComparable, а затем написать компаратор.Это позволит вам использовать встроенную функцию сортировки List и станет более подходящим решением, чем просто написание собственного.

Ваш код должен выглядеть примерно так:

1) Создать / загрузитьa List со всеми предыдущими результатами

2) вставить в него новую оценку

3) Сортировать список

4) Печатать только первые 10 записей

0 голосов
/ 18 февраля 2011

Я написал код для вас. Я изучал некоторые нововведения типа C #, такие как linq, IEnumerable, и yield и вроде бы хотели собрать их вместе, так что, надеюсь, это поможет.

вам может понравиться редактор фрагментов, который я использовал - linqpad - это хорошо для обучения / экспериментов

void Main()
{
    string [] playerNames = {"Aaron", "Rick", "Josie"};
    var sim = new GameSimulator(playerNames, 1000000, 5000);
    var scores = sim.GetScores(5);
    var sorted = scores.OrderBy(c=>c.Score).Reverse();
    var top = sorted.Take(2);
    // uncomment if using linq pad
    //scores.Dump("scores");
    //sorted.Dump("sorted");
    //top.Dump("top");
}
class GameSimulator
{
    public GameSimulator(string [] playerNames, int maxScore, int maxLevel)
    {
        this.playerNames = playerNames;
        this.maxScore = maxScore;
        this.maxLevel = maxLevel;
    }
    private string [] playerNames;
    private int maxScore;
    private int maxLevel;
    public IEnumerable<ScoreBoardEntry> GetScores(int numGames)
    {
        for (int i = 0; i < numGames; i++)
        {
            string randomName = playerNames[random.Next(0, playerNames.Length-1)];
            int randomScore = random.Next(1, maxScore);
            int randomLevel = random.Next(1, maxLevel);
            yield return new ScoreBoardEntry(randomName, randomLevel, randomScore);
        }
    }
    static private Random random = new Random();
}
class ScoreBoardEntry
{
    public ScoreBoardEntry(string playerName, int levenNumber, int score)
    {
        PlayerName = playerName;
        LevelNumber = levenNumber;
        Score = score;
    }
    public string PlayerName { set; get; }
    public int LevelNumber { set; get; }
    public int Score { set; get; }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...