场景:
guess的字母,是否在hidden的单词中的正确位置。匹配正位,大写,匹配异位,小写,不匹配.
传统写法:
public record Wordle2(String hidden) {
public String guess(String guess){
StringBuilder result = new StringBuilder();
// 确保一个字母,不被重复匹配
boolean[] used = new boolean[hidden.length()];
for(int i=0;i<guess.length();i++){
// 正确位置正确字母
if(guess.codePointAt(i) == this.hidden.codePointAt(i)){
// 转成大写
result.append(Character.toString(guess.codePointAt(i)).toUpperCase(Locale.ROOT));
used[i] = true; // i位已被匹配
}else{
boolean found = false; //当前位置是否找到
for (int j = 0;j<hidden.length();j++){
if(used[j]){ // j位已被匹配,跳过当次
continue;
}
// 非正确位置
if(i != j &&
// 隐藏字母,不应与猜的字母匹配
guess.codePointAt(j) != this.hidden.codePointAt(j) &&
// 正确字母
guess.codePointAt(i) == this.hidden.codePointAt(j)){
// 小写放入结果
result.append(Character.toString(guess.codePointAt(i)));
found = true; //当前位置已找到
used[j] = true; // j位已被匹配
break; // 匹配则跳出循环
}
}
if(!found){ //当前位置未找到
result.append(".");
}
}
}
return result.toString();
}
新特性优化写法
public record Wordle(String hiddenAsString) {
record Guess(String guess){
public int length() {
// 委托模式
return this.guess.length();
}
public int codePointAt(int index) {
return this.guess.codePointAt(index);
}
// 检查这个字符和隐藏的单词
public GuessWithIndex checkCharacterAtPosition(int index) {
return new GuessWithIndex(this, index);
}
// 流
public LetterStream checkAgainst(Hidden hidden) {
return new LetterStream(IntStream.range(0, length())
//switch模式匹配,允许添加行为到一个类而不触及它,也无需修改
//添加行为有两种方式:
//1. 对非final的类扩展
//2. 组合(需创建一些新类型,以便将一些方法调用委托给组合的对象)
.mapToObj(index -> checkCharacterAtPosition(index).with(hidden)));
}
}
record LetterStream(Stream<Letter> stream){
// Function 接受 Letter 返回 String
String replaceEachLetterWith(Function<Letter, String> mapper){
return stream.map(mapper)
// 组成一个字符串
.collect(Collectors.joining());
}
}
record Hidden(String hidden, boolean[] used){
Hidden(String hidden){
this(hidden, new boolean[hidden.length()]);
}
public int codePointAt(int index) {
return this.hidden.codePointAt(index);
}
public int length() {
return this.hidden.length();
}
private boolean match(GuessWithIndex guessWithIndex, int indexGuess, int indexHidden) {
if(used[indexHidden]){
return false;
}
// 猜测的字母,与隐藏字母比较
boolean match = guessWithIndex.guess.codePointAt(indexGuess) == codePointAt(indexHidden);
if(match){
// 则表示该位置已被匹配成功,不再重复匹配
used[indexHidden] = true;
}
// 返回是否匹配
return match;
}
}
record GuessWithIndex(Guess guess, int index) {
// 匹配,正确位
public boolean thatIsWellPlacedIn(Hidden hidden){
return hidden.match(this, index, index);
}
// 匹配,非正确位
public boolean thatIsNotWellPlacedIn(Hidden hidden){
return IntStream.range(0, hidden.length()) // 整数流
.filter(i -> index != i) //过滤匹配index的索引位
.filter(i -> guess.codePointAt(i) != hidden.codePointAt(i)) //过滤出字母匹配的位置
.anyMatch(i -> hidden.match(this, index, i)); //字母匹配,但不在应有位置
}
// 返回switch中选择器变量的类型
public Letter with(Hidden hidden) {
if(thatIsWellPlacedIn(hidden)){
return new WELL_PLACED(this.guess.codePointAt(this.index));
}else if (thatIsNotWellPlacedIn(hidden)){
return new NOT_WELL_PLACED(this.guess.codePointAt(this.index));
}else {
return new ABSENT();
}
}
}
sealed interface Letter // 封闭类
permits WELL_PLACED,NOT_WELL_PLACED,ABSENT{} //只允许这些record实现
record WELL_PLACED(int codePoint) implements Letter{ }
record NOT_WELL_PLACED(int codePoint) implements Letter{}
record ABSENT() implements Letter{}
public String guess(String guessStr){
Guess guess = new Guess(guessStr);
Hidden hidden = new Hidden(hiddenAsString);
return guess.checkAgainst(hidden)
.replaceEachLetterWith(
l -> switch (l) {
case WELL_PLACED letter ->
Character.toString(letter.codePoint()).toUpperCase();
case NOT_WELL_PLACED letter ->
Character.toString(letter.codePoint());
case ABSENT ignored ->
".";
}
);
}
}
@Test
public void wordle(){
assertEquals(new Wordle2("aaaaa").guess("bbbbb"),".....");
assertEquals(new Wordle2("aaaaa").guess("bbabb"),"..A..");
assertEquals(new Wordle2("abbbb").guess("ccacc"),"..a..");
assertEquals(new Wordle2("abbbb").guess("cccca"),"....a");
assertEquals(new Wordle2("abbbb").guess("accca"),"A....");
assertEquals(new Wordle2("aaabb").guess("cccaa"),"...aa");
assertEquals(new Wordle2("aaabb").guess("aaacc"),"AAA..");
assertEquals(new Wordle2("aabbb").guess("accaa"),"A..a.");
assertEquals(new Wordle("aaaaa").guess("bbbbb"),".....");
assertEquals(new Wordle("aaaaa").guess("bbabb"),"..A..");
assertEquals(new Wordle("abbbb").guess("ccacc"),"..a..");
assertEquals(new Wordle("abbbb").guess("cccca"),"....a");
assertEquals(new Wordle("abbbb").guess("accca"),"A....");
assertEquals(new Wordle("aaabb").guess("cccaa"),"...aa");
assertEquals(new Wordle("aaabb").guess("aaacc"),"AAA..");
assertEquals(new Wordle("aabbb").guess("accaa"),"A..a.");
}