我正在尝试模拟一个游戏板,其中多个玩家可以提交他们的游戏分数。
POJO即。 Entry.java表示排行榜中的条目。 请注意覆盖的equals()方法。
排名是排行榜中的位置,1是用户的排名 得分最高
public class EntryTreeMapOption {
private String uid;
private int score;
private int position;
public EntryTreeMapOption(String uid, int score) {
this.uid = uid;
this.score = score;
}
public EntryTreeMapOption() {
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((uid == null) ? 0 : uid.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EntryTreeMapOption other = (EntryTreeMapOption) obj;
if (uid == null) {
if (other.uid != null)
return false;
} else if (!uid.equals(other.uid))
return false;
return true;
}
@Override
public String toString() {
return "Entry [uid=" + uid + ", score=" + score + ", position=" + position + "]";
}}
GameBoard类有几种方法:
如果用户在排行榜中,则返回最多两个条目 比用户更高的分数(直接位于用户之上的用户) 用户在排行榜中),用户自己的条目和最多两个条目 紧接在排行榜中的用户之后
e.g:
The leader board is :
Entry [uid=user1, score=14, position=1]
Entry [uid=user2, score=8, position=2]
Entry [uid=user3, score=7, position=3]
Entry [uid=user4, score=7, position=3]
Entry [uid=user5, score=4, position=4]
Entry [uid=user6, score=3, position=5]
Entry [uid=user7, score=3, position=5]
Entry [uid=user8, score=1, position=6]
For user5, entries returned should be :
Entry [uid=user3, score=7, position=3]
Entry [uid=user4, score=7, position=3]
Entry [uid=user5, score=4, position=4]
Entry [uid=user6, score=3, position=5]
Entry [uid=user7, score=3, position=5]
For user4, entries returned should be :
Entry [uid=user1, score=14, position=1]
Entry [uid=user2, score=8, position=2]
Entry [uid=user4, score=7, position=3]
Entry [uid=user5, score=4, position=4]
Entry [uid=user6, score=3, position=5]
For user6, entries returned should be :
Entry [uid=user4, score=7, position=3]
Entry [uid=user5, score=4, position=4]
Entry [uid=user6, score=3, position=5]
Entry [uid=user8, score=1, position=6]
For user7, entries returned should be :
Entry [uid=user4, score=7, position=3]
Entry [uid=user5, score=4, position=4]
Entry [uid=user7, score=3, position=5]
Entry [uid=user8, score=1, position=6]
我最初的方法是使用TreeMap,另一种方法是here。
public class GameDefault2 {
private TreeMap<EntryMapOption, String> leaderBoardEntryUserMap;
{
leaderBoardEntryUserMap = new TreeMap<>(Comparator.comparingInt(EntryTreeMapOption::getScore).reversed()
.thenComparing(EntryTreeMapOption::getUid));
}
@Override
public void submitScore(String uid, int score) {
EntryMapOption newEntry = new EntryMapOption(uid, score);
leaderBoardEntryUserMap.put(newEntry, uid);
}
@Override
public List<EntryMapOption> getLeaderBoard(String uid) {
System.out.println("---------Current leader board---------");
leaderBoardEntryUserMap.keySet().forEach(System.out::println);
List<EntryMapOption> userEntryList = leaderBoardEntryUserMap.entrySet().stream()
.filter(entry -> uid.equalsIgnoreCase(entry.getKey().getUid())).map(Map.Entry::getKey)
.collect(Collectors.toList());
if (userEntryList == null || userEntryList.isEmpty())
return Collections.emptyList();
// Incomplete and error prone
EntryMapOption userEntry = userEntryList.get(0);
List<EntryMapOption> entriesOptionTwo = new ArrayList<>();
entriesOptionTwo.add(leaderBoardEntryUserMap.higherKey(userEntry));
entriesOptionTwo.add(userEntry);
entriesOptionTwo.add(leaderBoardEntryUserMap.lowerKey(userEntry));
return entriesOptionTwo;
}
}
以上代码的问题:
*****编辑-1 ****** @ Holger的解决方案解决了以下问题
答案 0 :(得分:2)
您的equals方法基于ID,但您的比较方法基于得分,这将导致JavaDoc出现问题。
请注意,如果此有序映射要正确实现Map接口,则树映射维护的顺序(如任何有序映射)以及是否提供显式比较器必须与equals一致。 (有关与equals一致的精确定义,请参阅Comparable或Comparator。)这是因为Map接口是根据equals操作定义的,但是有序映射使用compareTo(或compare)方法执行所有键比较,因此从排序映射的角度来看,通过此方法被视为相等的键是相等的。即使排序与equals不一致,也可以很好地定义有序映射的行为。它只是没有遵守Map接口的一般合同。
问题是比较方法会在错误的方向上进行搜索,因为它在不同的属性上进行排序。
在你的情况下,这可能不是一个问题,虽然你可能有2个相同的对象没有相同的分数,导致未来的问题。
在项目位于树中时更改分数也可能会导致问题,因此您可能必须在每次分数更改时删除该项目,然后重新添加。
这个过程的一个例子是
import java.util.Comparator;
import java.util.TreeMap;
public class Test {
static class Example {
final int id;
final int score;
Example(int id, int score) {
this.id = id;
this.score = score;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Example)) {
return false;
}
final Example other = (Example) obj;
return other.id == id;
}
@Override
public int hashCode() {
return id;
}
public int getId() {
return id;
}
@Override
public String toString() {
return id + " scored " + score;
}
public int getScore() {
return score;
}
}
public static void main(final String... args) {
Example a = new Example(1, 10);
Example b = new Example(2, 30);
Example c = new Example(3, 1);
Example d = new Example(4, 10);
TreeMap<Example, Integer> x = new TreeMap<Example, Integer>(Comparator.comparingInt(Example::getScore).thenComparing(Example::getId));
x.put(a, a.getScore());
x.put(b, b.getScore());
x.put(c, c.getScore());
x.put(d, d.getScore());
final Example h2 = x.higherKey(a);
final Example h1 = h2 == null ? null : x.higherKey(h2);
final Example l1 = x.lowerKey(a);
final Example l2 = l1 == null ? null : x.lowerKey(l1);
System.out.println(h1);
System.out.println(h2);
System.out.println(a);
System.out.println(l1);
System.out.println(l2);
}
}