繁体   English   中英

计算 position 中每种类型有多少件的优雅方法

[英]Elegant way to count how many pieces of each type are present in a position

我有一个抽象的 class 有 1 个属性,如下所示:

PieceColor {
    WHITE, BLACK
}

abstract class Piece {
    PieceColor color

    abstract char getAbbr();
}

此 class 棋子已由 Bishop Knight Rook King Queen 和 Pawn 类扩展。 每个 class 都有一个名为 getAbbr() 的方法,它返回 Piece 的缩写 KQBNRP。

现在我有一个Map<Piece, Tile> piecePlacements ,它代表特定时间当前棋盘上的所有棋子。

我需要计算有多少种类型的棋子,比如白车、黑皇后等。但是这样做的正常方法太长了,而且很难看。 我就是这样做的...

//0: White pieces, 1: Black pieces; 0-5: KQRBNP
    int[][] pieceCount = new int[2][6];

    for(Piece piece : piecePlacements.keySet()) {
        switch (piece.getAbbr()) {
            case 'K' :
                if (piece.color == PieceColor.WHITE) {
                    pieceCount[0][0]++;
                } else {
                    pieceCount[1][0]++;
                }
                break;
            case 'Q' :
                if (piece.color == PieceColor.WHITE) {
                    pieceCount[0][1]++;
                } else {
                    pieceCount[1][1]++;
                }
                break;
            case 'R' :
                if (piece.color == PieceColor.WHITE) {
                    pieceCount[0][2]++;
                } else {
                    pieceCount[1][2]++;
                }
                break;
            case 'B' :
                if (piece.color == PieceColor.WHITE) {
                    pieceCount[0][3]++;
                } else {
                    pieceCount[1][3]++;
                }
                break;
            case 'N' :
                if (piece.color == PieceColor.WHITE) {
                    pieceCount[0][4]++;
                } else {
                    pieceCount[1][4]++;
                }
                break;
            case 'P' :
                if (piece.color == PieceColor.WHITE) {
                    pieceCount[0][5]++;
                } else {
                    pieceCount[1][5]++;
                }
                break;
         }
    }

必须有一种更优雅的方法,它需要更少的代码行。 我的意思是如果有超过 6 种类型的部件和 2 种类型的 colors。 我不能像这样继续在 switch 语句中添加案例吗? 但我不知道如何使它更优雅。

执行此操作的正常方法是使用 枚举器(在 Java 中称为enum )。 枚举器让您定义一组值,它们会自动完成所有 rest 的工作,例如为每个值分配一个唯一的 ID,在后台。 这是一个简单的例子:

public enum PieceType {
    KING,
    QUEEN,
    ROOK,
    BISHOP,
    KNIGHT,
    PAWN;
}

然后你可以在你的Piece class 中使用它。 我还将添加适当的封装,这是您应该遵循的。

public class Piece {
    private final PieceType type;
    private final boolean isBlack;

    public Piece(PieceType type, boolean isBlack) {
        this.type = type;
        this.isBlack = isBlack;
    }

    public PieceType getType() {
        return type;
    }

    public boolean isBlack() {
        return isBlack;
    }
}

现在我们已经完成了所有设置,编写 for 循环变得微不足道:

for (Piece piece : piecePlacements) {
    pieceCount[piece.isBlack() ? 1 : 0][piece.getType().ordinal()]++;
}

对于第一个维度的索引,我们使用三元运算符 这允许我们编写条件表达式而无需写出整个 if 语句。 在这种情况下,如果piece.isBlack()为真,则插入索引1 ,否则插入索引0

对于第二个维度的索引,我们使用ordinal()方法。 这是所有枚举器都隐含的特殊方法。 它返回给定枚举器值的唯一 ID,而且好的部分是,您不必担心它是如何得出该 ID 的。 它会自动完成这一切。

tl;博士

为每件作品的颜色和角色定义枚举。

使用错误命名的Enum#ordinal获取每个枚举对象在其定义中的 position 的索引号。 使用该数字作为 arrays 的索引。

for ( Piece piece : pieces )          // `Piece` is class with two member fields: a `Color` enum object and a `Role` enum object.
{
    pieceCount                        // Your two-dimensional array. 
        [ piece.color().ordinal() ]   // Get the `Piece` object’s `Color` enum object’s definition position.
        [ piece.role().ordinal() ]    // Get the `Piece` object’s `Role` enum object’s definition position.
        ++                            // Using those two index numbers as index into your arrays, increment the count.
    ;
}

细节

使用枚举使这项任务变得更加简单。

枚举提供了方法ordinal ,这是用词不当,因为它实际上返回了定义枚举 object 的顺序的从零开始的索引(不是从一开始的序数)。 我们可以使用这个枚举索引号作为 arrays 的索引。

让我们使用一对嵌套枚举ColorRole来定义您的Piece记录。

记录是 Java 16 中的一个新功能,用于编写 class 的简要方法,其主要目的是透明和不可变地传递数据。 编译器隐式创建构造函数、getter、 equals & hashCodetoString 此解决方案不是必需的,但非常适合您的Piece class。

package work.basil.example.chess;

public record Piece(Color color , Role role)
{
    public enum Color
    { WHITE, BLACK }

    public enum Role
    { KING, QUEEN, ROOK, BISHOP, KNIGHT, PAWN }
}

所以Piece.Color.WHITE.ordinal()返回 0,而BLACK返回 1。

我们需要一些样本数据。

List < Piece > pieces = List.of(
        new Piece( Piece.Color.BLACK , Piece.Role.QUEEN ) ,
        new Piece( Piece.Color.BLACK , Piece.Role.KNIGHT ) ,
        new Piece( Piece.Color.WHITE , Piece.Role.PAWN )
);

我们可以通过询问每个枚举的长度,以软编码方式定义您的 arrays。

int[][] pieceCount = new int[ Piece.Color.values().length ][ Piece.Role.values().length ]; // [2][6]

接下来,我们在板上循环棋子。 我们通过调用错误命名的ordinal()方法询问每个Piece对象的ColorRole枚举成员字段 object 的索引 position。

for ( Piece piece : pieces )
{
    pieceCount[ piece.color().ordinal() ][ piece.role().ordinal() ]++;
}

这是整个示例应用程序 class。

package work.basil.example.chess;

import java.util.Arrays;
import java.util.List;

public class App
{
    public static void main ( String[] args )
    {
        App app = new App();
        app.demo();
    }

    private void demo ( )
    {
        List < Piece > pieces = List.of(
                new Piece( Piece.Color.BLACK , Piece.Role.QUEEN ) ,
                new Piece( Piece.Color.BLACK , Piece.Role.KNIGHT ) ,
                new Piece( Piece.Color.WHITE , Piece.Role.PAWN )
        );
        int[][] pieceCount = new int[ Piece.Color.values().length ][ Piece.Role.values().length ]; // [2][6]
        for ( Piece piece : pieces )
        {
            pieceCount[ piece.color().ordinal() ][ piece.role().ordinal() ]++;
        }

        System.out.println( "pieces = " + pieces );
        for ( int i = 0 ; i < pieceCount.length ; i++ )
        {
            System.out.println( Arrays.toString( pieceCount[ i ] ) );
        }
    }
}

跑的时候。

pieces = [Piece[color=BLACK, role=QUEEN], Piece[color=BLACK, role=KNIGHT], Piece[color=WHITE, role=PAWN]]
[0, 0, 0, 0, 0, 1]
[0, 1, 0, 0, 1, 0]

除了巧妙地解决您的挑战之外,使用 Java 枚举还提供了另外三个重大胜利:

首先对事物进行排序通常可以加快计数速度。 如果您知道顺序,则可以减少测试次数。

另一个角度是每个项目都有一个质数。 将每个相乘成一个总数。 然后除以该素数以获得相应项目的计数。

但实际上,正确的答案可能涉及枚举。 此外,更少的代码行并不一定意味着计算更快或更有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM