当前位置: 首页 > 知识库问答 >
问题:

一种优雅的方式来计算每种类型在一个位置上有多少件

段弘和
2023-03-14
PieceColor {
    WHITE, BLACK
}

abstract class Piece {
    PieceColor color

    abstract char getAbbr();
}

现在我有了一个map 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种类型的颜色。我不能一直像这样给switch语句添加大小写,对吧?但我想不出怎样才能让它更优雅。

共有1个答案

梁德馨
2023-03-14

为每一块的颜色和角色定义枚举。

使用名称错误的enum#ordinal获取每个枚举对象在其定义中位置的索引号。使用该数字作为数组的索引。

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方法,这是一个错误的名称,因为它实际上返回定义枚举对象的顺序的从零开始的索引(而不是从一开始的序数)数。我们可以使用这个枚举索引号作为数组的索引。

让我们用一对嵌套的枚举、colorrole来定义您的piece记录。

记录是Java16中的一个新特性,它是编写一个主要目的是透明和不变地通信数据的类的一种简单方法。编译器隐式创建构造函数、getter、equals&hashcodetoString。此解决方案不需要,但非常适合piece类。

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 )
);

我们可以用一种软编码的方式定义数组,通过询问每个枚举的长度。

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() ]++;
}
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枚举还提供了另外三大优势:

  • 使代码更具自文档性。
  • 提供类型安全。
  • 确保有效值。
 类似资料:
  • 问题内容: 我的孩子做了一项家庭作业,用Java编写二十一点。我为他提供了一些帮助,但大部分时间他都是自己完成的,实际上效果还不错。他甚至发现了我在计算手值时没有看到的错误。但是,他还没有解决一个难题,我能想到的每个解决方案都非常复杂,而且远远超出了他将能够利用其仍基本的Java技能轻松编写代码的范围。 王牌。实际上,不仅有一个Ace,还有四个Ace,您可能可以一手拿到所有四个Ace。当有一个或多

  • 问题内容: 一个激励人的例子: 实施各种调度“策略”,对“作业”列表进行排序。 一种非常简单的策略是首先执行最短的作业(不考虑其权重/优先级)。 嗯,这种策略只不过是对job.length进行排序,因此让我们使用sort包。定义一个自定义类型,并实现sort.Interface … 好了,现在回到我们的简单策略… 嗯… 问题答案: 首先, 即使您使用like ,也看不到任何定义 。 我认为您的意思

  • 问题内容: 在我的应用程序中,我必须实例化许多不同类型的对象。每种类型都包含一些字段,需要将其添加到包含类型中。我怎样才能优雅地做到这一点? 我当前的初始化步骤如下所示: 我真的想避免编写这样的代码,因为必须分别实例化每个对象然后在多行代码中初始化每个字段(例如,必须先调用然后再调用)有点麻烦。 我可以使用什么优雅的方法代替我现有的方法?是否可以使用任何“ ”?您有任何参考资料/示例来避免编写这样

  • 有没有一种好的方法要求类中的每个公共方法使用部分(希望不是每次都写)?

  • 我正在寻找一个更优雅的方法,将这个指令列表变成一个单一的合并指令,其中键'SKU'作为合并的键。这些列表实际上都是很容易被转化为指令的模型。我没有找到一个更优雅的解决方案使用Pydantic。 Dicts/PydanticInstances列表 所需输出: 当前解决方案:

  • 本文向大家介绍写一个方法,计算有N个数(可重复),分别放到M个位置中,有多少种排列?相关面试题,主要包含被问及写一个方法,计算有N个数(可重复),分别放到M个位置中,有多少种排列?时的应答技巧和注意事项,需要的朋友参考一下