努力保持算法通过掷骰子对玩家进行排序



我正在编写一个Java算法,该算法让游戏中的六个玩家中的每一个掷骰子,掷得最高的玩家掷第一回合,依此类推。我已经编写了掷骰子的方法,该方法以<String playerName, Player player>的形式接收玩家地图,并让每个玩家掷骰子,其中玩家是一个存储游戏所需的许多玩家属性的类。

我在命令玩家时难以克服的问题是,如果两个玩家掷出相同的数字,然后他们再次掷出,以查看谁领先于另一个。下面是一个示例方案:

位置:球员(滚动号码)

1: 汤姆 (5)

2: 杰瑞 (4)

=3: 杰克 (3)

=3: 吉尔 (3)

5: 哈利 (2)

6: 罗恩 (1)

于是杰克和吉尔又滚了。杰克掷出 6 分,吉尔掷出 3 分。杰克现在排在第3位,吉尔排在第4位。

我开始快速编写的任何策略都变得过于复杂,非常不整洁且难以阅读。这是因为必须检查是否有任何数量的重复卷,同时以正确的顺序存储每个卷,如果有重复的卷,则允许两个或多个位置。任何人都可以想出一个整洁的结构来确定和存储这个顺序吗?

Player的每个实例都有一个nextPlayer变量,该变量将指向玩家在他们之后的位置。最好也numberRolled存储在类中。任何掷出相同数字的玩家都可以存储在新地图中,然后再次传递到rollDice方法中。

编辑

感谢安迪·特纳,这是我的解决方案:

private Player[] playerOrder = new Player[ModelConstants.NUM_PLAYERS_PLUS_NEUTRALS];
playerOrder = getPlayerOrder();
Player[] getPlayerOrder() {
      Player[] players = ModelConstants.PLAYERS.values().toArray(new Player[ModelConstants.PLAYERS.size()]);
      String[] playerNames = ModelConstants.PLAYERS.keySet().toArray(new String[ModelConstants.PLAYERS.size()]);
      getPlayerOrder(playerNames, players,  0, players.length);
      return players;
    }
void getPlayerOrder(String[] playerNames, Player[] players, int start, int end) {
    // Get all players between players[start] (inclusive) and
    // players[end] (exclusive) to re-roll the dice.
    for (int i = start; i < end; ++i) {
        players[i].setDiceNumberRolled(rollDice(playerNames[i], players[i]));
    }
    // Sort this portion of the array according to the number rolled.
    Arrays.sort(players, start, end, new Comparator<Player>() {     
        @Override public int compare(Player a, Player b) {
            return Integer.compare(a.getDiceNumberRolled(), b.getDiceNumberRolled());
        }
    });
    for (int i = 0; i < playerNames.length; i++) {
        playerNames[i] = HashMapUtilities.getKeyFromValue(ModelConstants.PLAYERS, players[i]);
    }
    // Look for players who rolled the same number.
    int i = start;
    while (i < end) {
        // Try to find a "run" of players with the same number.
        int runStart = i;
        int diceNumberRolled = players[runStart].getDiceNumberRolled();
        i++;
        while (i < end && players[i].getDiceNumberRolled() == diceNumberRolled) {
            i++;
        }
        if (i - runStart > 1) {
            // We have found more than one player with the same dice number.
            // Get all of the players with that dice number to roll again.
            addMessageToLog(MessageType.INFO, "There has been a tie." , 2000);
            tiedPlayers = true;
            getPlayerOrder(playerNames, players, runStart, i);
            tiedPlayers = false;
        }
    }
}
private int rollDice(String playerName, Player player) {
    int numberRolled = 0;
    if (player.getPlayerType().equals(PlayerType.HUMAN)) {
        boolean diceRolled = false;
        while (!diceRolled) {
            String message = ", roll the dice";
            if (tiedPlayers == true) {
                message += " again.";
            }
            else {
                message += ".";
            }
            String userInput = getCommand(playerName +  message, "Invlaid command. Type "Roll Dice" or something similar.", 2000);
            if (userInput.equalsIgnoreCase("Roll Dice") || userInput.equalsIgnoreCase("roll the dice") || userInput.equalsIgnoreCase("Roll")) {
                numberRolled = dice.rollDice();
                diceRolled = true;
            }
            else {
                addMessageToLog(MessageType.ERROR, "Invlaid command. Type "Roll Dice" or something similar.", 0);
            }
        }
    }
    else {
        String message = " is now rolling the dice";
        if (tiedPlayers == true) {
            message += " again...";
        }
        else {
            message += "...";
        }
        addMessageToLog(MessageType.INFO, playerName + message, 2000);
        numberRolled = dice.rollDice();
    }
    player.setDiceNumberRolled(numberRolled);
    addMessageToLog(MessageType.SUCCESS, playerName + " rolled a " + numberRolled, 1000);
    addDicePanel(numberRolled);
    return numberRolled;
}
private void setPlayerOrder() {
    for (int i = 0; i < playerOrder.length; i++) {
        if (i == (playerOrder.length - 1)) {
            playerOrder[i].setNextPlayer(playerOrder[0]);
        }
        else {
            playerOrder[i].setNextPlayer(playerOrder[i + 1]);
        }
    }
    activePlayer = playerOrder[0];
}
private void changePlayer() {
    activePlayer = activePlayer.getNextPlayer();
}

有两种方法可以解决这个问题。

1)简单的事情就是忘记"掷骰子"。为每个玩家生成 32 个随机(一个整数)位,并将其用于排序。如果他们碰巧匹配,请选择您想要的任何玩家。这将是如此罕见,以至于它并不重要(40亿分之一,你得到2个数字是相同的)。

2)如果你想坚持掷骰子。创建一个函数,该函数获取玩家列表,在内部掷骰子并返回正确排序的骰子。每当有相等的滚动调用时,创建一个较小的列表,其中包含相等的玩家,并递归调用该函数以为您提供这些玩家的顺序。当它返回时,将其复制到结果中并继续。你可以用数学证明,这极不可能(读起来不可能)导致无限循环。

要组织内容,请尝试为您需要的每个"操作"创建一个单独的方法 - 一种用于掷骰子的方法,另一种用于查找重复项的方法,另一种用于排序的方法。 以下是步骤:

  1. 所有玩家掷骰子,存放在List
  2. 查找重复项
  3. 对于所有重复项,重复步骤 1 和 2,直到找不到重复项。
  4. 对玩家进行排序。

3种方法,4个步骤,逻辑执行,做你需要的。

public int rolldice(Player player);
public List<Player> findDuplicates (List<Player> players);
public void sortPlayers(List<Player> players);

您已经可以使用这 3 种方法。希望这有帮助

您可以将所有玩家放入一个数组中 - 数组中玩家的顺序可用于指示游戏顺序。

让他们都选择掷骰子;然后按他们掷出的数字对他们进行排序(使用自定义比较器)。

现在,寻找 2 个或更多掷出相同数字的玩家 - 这些玩家彼此相邻,因为数组已排序。现在,您可以递归调用相同的逻辑来让这些玩家重新掷骰子,但仅限于这些玩家掷骰子的数组部分。

例如:

Player[] getPlayerOrder() {
  Player[] players = playerMap.values().toArray(new Player[playerMap.size()]);
  getPlayerOrder(players, 0, players.length);
  return players;
}
void getPlayerOrder(Player[] players, int start, int end) {
  // Get all players between players[start] (inclusive) and
  // players[end] (exclusive) to re-roll the dice.
  for (int i = start; i < end; ++i) {
    // Logic to roll dice...
    players[i].setDiceNumberRolled(...);
  }
  // Sort this portion of the array according to the number rolled.
  Arrays.sort(players, start, end, new Comparator<Player>() {
    @Override public int compare(Player a, Player b) {
      return Integer.compare(b.getDiceNumberRolled(), a.getDiceNumberRolled());
    }
  });
  // Look for players who rolled the same number.
  int i = start;
  while (i < end) {
    // Try to find a "run" of players with the same number.
    int runStart = i;
    int diceNumberRolled = players[runStart].getDiceNumberRolled();
    ++i;
    while (i < end && players[i].getDiceNumberRolled() == diceNumberRolled) {
      ++i;
    }
    if (i - runStart > 1) {
      // We have found more than one player with the same dice number.
      // Get all of the players with that dice number to roll again.
      getPlayerOrder(players, runStart, i);
    }
  }
}

我的尝试是让每个人都掷骰子,然后存储它而不进行任何排序。然后检查重复项,让获得相同号码的玩家再次滚动。之后,当每个玩家滚动并且不再重复时,只需使用某种排序算法即可。最简单的方法是BubbleSort,因为排序时没有时间问题。在此处查看此输入链接说明

迭代解决方案并不像我最初想象的那么简单!

我最初发布了一个使用原始 int 数组为玩家和骰子的解决方案。但这对编码来说是不必要的复杂。到目前为止,更容易使用复合类,PlayerDice。可以使用 Arrays.sort(...) 方法对数组的所需范围进行排序,根据为 PlayerDice 定义的 compareTo(.) 方法。

当一组玩家中的一些人在掷出后再次平局时,您必须小心存储结束索引。这些我放进了一堆 - 除非整组平局的玩家在掷出时掷出相同的骰子。

总体完成条件是当没有平局且起始索引大于结束索引时。

package snakesAndLadders;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Stack;
public class PlayOrderTest6
{
    private final static int numPlayers = 16;
    private PlayerDice[] playersDice = new PlayerDice[numPlayers];
    /** Composite class to enable sorting of players according to dice they throw.*/
    public static class PlayerDice implements Comparable<PlayerDice>
    {
        private int player;
        private int dice;
        public PlayerDice(int player, int dice)
        {
            this.player = player;
            this.dice = dice;
        }
        public int getPlayer()
        {
            return player;
        }
        public void setPlayer(int player)
        {
            this.player = player;
        }
        public int getDice()
        {
            return dice;
        }
        public void setDice(int dice)
        {
            this.dice = dice;
        }
        public String toString()
        {
            return "Player# " + player + " | Dice: " + dice;
        }

        @Override
        public int compareTo(PlayerDice pd)
        {
            // Default comparison is on basis of dice value descending:
            return pd.getDice() - this.dice;
        }   
}
    /** Main method basically runs the getPlayOrder(.) method for the number of 
    players involved in this game, i.e. the attribute players.                 */
    public static void main(String[] args)
    {
        int[] playOrder = new int[numPlayers];  // Holds final play order
        // Initialize playerDice array and give each player a number between 1 .. players :
        for(int i = 0; i < numPlayers; i++)
        {
            playersDice[i] = new PlayerDice(i + 1, 1);
            playOrder[i] = i + 1;
        }
        // Generate the order of play by rolling dice & re-rolling for tied players :
        getPlayOrder(playersDice);
        // Extract play order :
        for(int i = 0; i < numPlayers; i++)
            playOrder[i] = playersDice[i].getPlayer();
        System.out.println("nnFinal Player Order is : " + Arrays.toString(playOrder));
    }

    public static void getPlayOrder(PlayerDice[] p)
    {
        int start = 0,                                  // Start index of unsorted PlayerDice array
            end = numPlayers - 1;                       // End index of unsorted PlayerDice array
        Integer[] sdInds = new Integer[2];              // For start & end indices of first group of tied players.
        Stack<Integer> endStack = new Stack<Integer>(); // Holds end index when a dice-roll to sort a tie produces another tie.
        while (start < numPlayers && end > start)
        {   
            // Roll dice for players in index range between start & end :
            for(int i = start; i < end + 1; i++)
                p[i].setDice( (int) (6 * Math.random() + 1));
            // Output player/dice values :
            System.out.print("nnPlayer Order:tt");
            for(int i = 0; i < numPlayers; i++)
                System.out.print(p[i].getPlayer() + "t");
            System.out.print("nDice Rolled:tt");
            for(int i = 0; i < numPlayers; i++)
                System.out.print(p[i].getDice() + "t");
            // Sort players between start & end indices by their dice number descending :
            Arrays.sort(p, start, end + 1); // Uses PlayerDice compareTo(.) method, i.e. by dice value descending.
            // Output player/dice values :
            System.out.print("nnSorted Player Order:t");
            for(int i = 0; i < numPlayers; i++)
                System.out.print(p[i].getPlayer() + "t");
            System.out.print("nSorted Dice Rolled:t");
            for(int i = 0; i < numPlayers; i++)
                System.out.print(p[i].getDice() + "t");
            // Find first group of players (from leftmost element of p) on the same dice :
            sdInds[0] = -1;
            sdInds[1] = -1;
            findTiedPlayers(p, start, end, sdInds);
            System.out.print("nsdInds[0]: " + sdInds[0]);
            System.out.print("nsdInds[1]: " + sdInds[1]);
            // Where tied players are found ...
            if (sdInds[0] != -1)
            {   // Re-set start and end indices and re-roll dice to sort the tied group :
                start = sdInds[0];
                if (sdInds[1] != end)
                {
                    endStack.push(end); // Keeps priority of tied players over those on lower first dice roll
                    end = sdInds[1];
                }
            }
            else // Where no ties, reset start & end indices till ties found or all players sorted.
                while (sdInds[0] == -1 && end >= start) 
                {
                    start = end + 1;
                    if(!endStack.isEmpty())
                        end = endStack.pop();
                    else 
                        break;      // When no more players to be checked !
                    // Get indices of first tied group in remaining players :
                    sdInds[0] = -1; // Initializing start- ...
                    sdInds[1] = -1; // ... and end-indices before tie search.
                    findTiedPlayers(p, start, end, sdInds); 
                    if (sdInds[0]!= -1) // If ties found, adjust start & end indices before tie-breaker roll
                    {
                        start = sdInds[0];
                        endStack.push(end); // Store old end index
                        end = sdInds[1];
                    }
                }
            System.out.print("nstart: " + start);
            System.out.print("nend: " + end);
        }
    }
    /** Method to find first group of tied players in an array holding player & dice data. 
     * @param pt - a PlayerDice array;
     * @param st - an int holding the start index of the range of pt being examined;
     * @param en - an int holding the end index of the range of pt being examined;
     * @param tInds - an int array holding the start & end index of the 
first group of tied players.
This parameter also acts as a return parameter since it's a reference type, 
tInds[0] holding the index of the first tied player and tInds[1] the index of
 the last.  Where no ties are found, both tInds elements retain their received 
values of -1 which signifies no ties.   */
    public static void findTiedPlayers(PlayerDice[] pt, int st, int en, Integer[] tInds)
    {
        for(int i = st; i < en; i++)
        {
            for(int j = i + 1; j < en + 1; j++)
                if (pt[i].getDice() == pt[j].getDice())
                {
                    tInds[0] = i;
                    tInds[1] = j;
                }
            if (tInds[0] != -1)     // First group of tied players found ...
                break;              // ... finish search !
        }
    }
}

输出:

Player Order:       1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  
Dice Rolled:        4   4   6   5   2   1   3   6   1   3   4   4   1   2   1   3   
Sorted Player Order:    3   8   4   1   2   11  12  7   10  16  5   14  6   9   13  15  
Sorted Dice Rolled: 6   6   5   4   4   4   4   3   3   3   2   2   1   1   1   1   
sdInds[0]: 0
sdInds[1]: 1
start: 0
end: 1
Player Order:       3   8   4   1   2   11  12  7   10  16  5   14  6   9   13  15  
Dice Rolled:        5   6   5   4   4   4   4   3   3   3   2   2   1   1   1   1   
Sorted Player Order:    8   3   4   1   2   11  12  7   10  16  5   14  6   9   13  15  
Sorted Dice Rolled: 6   5   5   4   4   4   4   3   3   3   2   2   1   1   1   1   
sdInds[0]: -1
sdInds[1]: -1
start: 3
end: 6
Player Order:       8   3   4   1   2   11  12  7   10  16  5   14  6   9   13  15  
Dice Rolled:        6   5   5   2   6   1   1   3   3   3   2   2   1   1   1   1   
Sorted Player Order:    8   3   4   2   1   11  12  7   10  16  5   14  6   9   13  15  
Sorted Dice Rolled: 6   5   5   6   2   1   1   3   3   3   2   2   1   1   1   1   
sdInds[0]: 5
sdInds[1]: 6
start: 5
end: 6
Player Order:       8   3   4   2   1   11  12  7   10  16  5   14  6   9   13  15  
Dice Rolled:        6   5   5   6   2   4   4   3   3   3   2   2   1   1   1   1   
Sorted Player Order:    8   3   4   2   1   11  12  7   10  16  5   14  6   9   13  15  
Sorted Dice Rolled: 6   5   5   6   2   4   4   3   3   3   2   2   1   1   1   1   
sdInds[0]: 5
sdInds[1]: 6
start: 5
end: 6
Player Order:       8   3   4   2   1   11  12  7   10  16  5   14  6   9   13  15  
Dice Rolled:        6   5   5   6   2   5   1   3   3   3   2   2   1   1   1   1   
Sorted Player Order:    8   3   4   2   1   11  12  7   10  16  5   14  6   9   13  15  
Sorted Dice Rolled: 6   5   5   6   2   5   1   3   3   3   2   2   1   1   1   1   
sdInds[0]: -1
sdInds[1]: -1
start: 7
end: 9
Player Order:       8   3   4   2   1   11  12  7   10  16  5   14  6   9   13  15  
Dice Rolled:        6   5   5   6   2   5   1   2   6   3   2   2   1   1   1   1   
Sorted Player Order:    8   3   4   2   1   11  12  10  16  7   5   14  6   9   13  15  
Sorted Dice Rolled: 6   5   5   6   2   5   1   6   3   2   2   2   1   1   1   1   
sdInds[0]: -1
sdInds[1]: -1
start: 10
end: 11
Player Order:       8   3   4   2   1   11  12  10  16  7   5   14  6   9   13  15  
Dice Rolled:        6   5   5   6   2   5   1   6   3   2   4   6   1   1   1   1   
Sorted Player Order:    8   3   4   2   1   11  12  10  16  7   14  5   6   9   13  15  
Sorted Dice Rolled: 6   5   5   6   2   5   1   6   3   2   6   4   1   1   1   1   
sdInds[0]: -1
sdInds[1]: -1
start: 12
end: 15
Player Order:       8   3   4   2   1   11  12  10  16  7   14  5   6   9   13  15  
Dice Rolled:        6   5   5   6   2   5   1   6   3   2   6   4   5   4   5   5   
Sorted Player Order:    8   3   4   2   1   11  12  10  16  7   14  5   6   13  15  9   
Sorted Dice Rolled: 6   5   5   6   2   5   1   6   3   2   6   4   5   5   5   4   
sdInds[0]: 12
sdInds[1]: 14
start: 12
end: 14
Player Order:       8   3   4   2   1   11  12  10  16  7   14  5   6   13  15  9   
Dice Rolled:        6   5   5   6   2   5   1   6   3   2   6   4   6   2   5   4   
Sorted Player Order:    8   3   4   2   1   11  12  10  16  7   14  5   6   15  13  9   
Sorted Dice Rolled: 6   5   5   6   2   5   1   6   3   2   6   4   6   5   2   4   
sdInds[0]: -1
sdInds[1]: -1
start: 16
end: 15
Final Player Order is : [8, 3, 4, 2, 1, 11, 12, 10, 16, 7, 14, 5, 6, 15, 13, 9]

最新更新