我正在编写一个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)如果你想坚持掷骰子。创建一个函数,该函数获取玩家列表,在内部掷骰子并返回正确排序的骰子。每当有相等的滚动调用时,创建一个较小的列表,其中包含相等的玩家,并递归调用该函数以为您提供这些玩家的顺序。当它返回时,将其复制到结果中并继续。你可以用数学证明,这极不可能(读起来不可能)导致无限循环。
要组织内容,请尝试为您需要的每个"操作"创建一个单独的方法 - 一种用于掷骰子的方法,另一种用于查找重复项的方法,另一种用于排序的方法。 以下是步骤:
- 所有玩家掷骰子,存放在
List
- 查找重复项
- 对于所有重复项,重复步骤 1 和 2,直到找不到重复项。
- 对玩家进行排序。
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]