将经典代码更改为功能

时间:2018-04-01 20:42:01

标签: java functional-programming chess

我有以下丑陋(但正在工作)的代码,用于检查棋盘上的字段是否空置:

if (abs(xDst - xSrc) == abs(yDst - ySrc)) {
            boolean backslashMove = xSrc < xDst && ySrc > yDst || xSrc > xDst && ySrc < yDst;
            if (backslashMove) {
                int y = max(ySrc, yDst) - 1;
                for (int x = min(xSrc, xDst) + 1; x < max(xSrc, xDst); x++) {

                    if (board.getActiveChessmanAt(x, y).isAlive()) {
                        return false;
                    }
                    y--;
                }
            } else { //slash move

显然,它会在类似Bishop的移动线中检查坐标(xScr,ySrc)和(xDst,yDst)之间的字段。

我正在尝试使用IntStream转换它:

if (backslashMove) {
                final int y = max(ySrc, yDst) - 1;

                if (IntStream.range(min(xSrc, xDst) + 1, max(xSrc, xDst))
                        .anyMatch(x -> board.getActiveChessmanAt(x, y).isAlive()))
                return false;

在这种情况下,我该如何表演?如果要在'anyMatch'命令中使用它必须是最终的

3 个答案:

答案 0 :(得分:1)

如果确实需要使用流重写它,那么您可以使用xy同时递增的事实。因此,您可以构建一系列增量而不是x值范围:

final int xSrc = min(xSrc, xDst) + 1;
final int xDst = max(xSrc, xDst);
final int ySrc = max(ySrc, yDst) - 1;

if (IntStream.range(0, xDst - xSrc)
    .anyMatch(distance -> board.getActiveChessmanAt(xSrc + distance, ySrc + distance).isAlive())) {
    return false;
}

一般情况下,无法使用&#34; parent&#34;中的非最终本地变量。方法直接。 Java不支持真正的闭包。你需要一个包装器对象(AtomicInteger是一个经常被建议的候选者),或者你可以使非final变量成为一个类字段(注意潜在的线程安全问题)。就我个人而言,这两个&#34;技巧&#34;很糟糕

答案 1 :(得分:1)

您需要的不是流/折叠方面的函数式编程 而不是,你应该重构你的实际代码,使其更清晰/更短/更好。

你可以举例如:

  • 使用有意义的名称提取实际方法中分散的逻辑部分

  • 使用结构化对象而不是太精细的单一变量

  • 删除不需要的嵌套:使用提前退出并且不需要条件语句可能有帮助

它可以给:

// -> extract method + structured objects
if (!isPointsMatch(pointSrc, pointDst)) {
    return false; // -> early exit
}

// -> extract method + structured objects
if (isBackslashMove(pointSrc, pointDst)) {
     if (board.hasAnyActiveChessmanAlive(pointSrc, pointDst)) {
          return false;  
      }
}
// else slash move -> The else is useless
// ...    

答案 2 :(得分:0)

您剪切的原始代码是程序。您的功能方法效果不佳。那么面向对象的方法呢?

class Position{
  private final int x, y;
  public Position(int x, int y){
     this.x=x;
     this.y=y;
  }
  public getX(){
    return x;
  }
  public getY(){
    return y;
  }
}
interface Move {
  Position moveFrom(Position start);
}

interface Figure {
  Collection<Move> getPossibleMoves(Position start, Board board);
}
class Bishop implements Figure {
  private final Collection<Move> moves = new HashSet<>();
  public Bishop(){
      moves.add(start->new Position(start.getX()-2,start.getY()-1));
      moves.add(start->new Position(start.getX()-2,start.getY()+1));
      moves.add(start->new Position(start.getX()+2,start.getY()-1));
      moves.add(start->new Position(start.getX()+2,start.getY()+1));
      moves.add(start->new Position(start.getX()-1,start.getY()-2));
      moves.add(start->new Position(start.getX()-1,start.getY()+2));
      moves.add(start->new Position(start.getX()+1,start.getY()-2));
      moves.add(start->new Position(start.getX()+1,start.getY()+2));
  }

  @Override
  public Collection<Move> getPossibleMoves(Position start, Board board){
    return moves.stream()
                .filter({ Position end = m.moveFrom(start);
                          return board.isOnBorad(end.getX(),end.getY())
                               && board.getActiveChessmanAt(end.getX(), end.getY()).isAlive()})
                .collect(Collectors.toSet());
  }
}

Figure的另一个实现可能会为每个步骤返回一个单独的Move实例,直到达到限制为止:

class Tower implements Figure {
   enum Direction {
      NORTH(1,0),EAST(0,1),SOUTH(-1,0),WEST(0,-1);
      private final Position change;
      private Direction(int x, int y){
         change = new Position(x, y);
      }
      public Position getNextFrom(Position start){
          return new Position(start.getX()+change.getX(),start.getX()+change.getY());
      }

      @Override
      public Collection<Move> getPossibleMoves(Position start, Board board){
         Collection<Move> moves = new HashSet<>();
         for(Direction direction : Direction.values()){
           Position current = direction.getNextFrom(start);
           while( board.isOnBorad(current.getX(),current.getY())
               && board.getActiveChessmanAt(current.getX(), current.getY()).isAlive()){
             moves.add(p-> new Position(current.getX(),current.getY());
           }
        }
        return moves;
      }
}