5

I'm implementing a checkers-like game, and I need a sequence that enumerates all legal moves for a given configuration.

I've got the following function, directly translated from C#:

seq {
    for y1 = 0 to BOARDSIZE-1 do
        for x1 = 0 to BOARDSIZE-1 do
             for dy = -2 to 2 do
                 for dx = -2 to 2 do
                     let x2 = x1 + dx;
                     let y2 = y1 + dy;
                     let currentMove = new MoveStruct(x1, y1, x2, y2);
                     if (currentMove.SomeCondition = true) then
                             yield currentMove;
   }

It works, but it's awkward, and not quite the "F# way", let alone I have a sneaking suspicion that what I'm doing here is not performance optimal.

What I would like is to "flatten this out" into something that uses a combination of "iterate over all cells", "iterate over all valid moves from this cell".

And here are the functions I'm hoping to combine:

let AllCells =
    seq {
        for y=0 to BOARDSIZE-1 do
            for x=0 to BOARDSIZE-1 do
                yield (x,y);
    };

AND

let LegalMovesAround(x1,y1) = 
    seq {
      if board.[x1, y1] = WHITE then
        for dy = -2 to 2 do
          for dx = -2 to 2 do
                let x2 = x1 + dx;
                let y2 = y1 + dy;
                let currentMove = new MoveStruct(x1, y1, x2, y2);
                if (currentMove.DetermineMoveType <> MoveType.ILLEGAL 
                    && board.[x2, y2] = NONE) then
                        yield currentMove;
     }

I'm going to spare you the details of my various attempts to make it work, because none of them were successful. But to make the long story short, the best I could come up with is an iterator that returns a seq with each yield, instead of the flattened version I'm looking for, which would return a simple MoveStruct.

Anyone have a good idea how to combine AllCells, and LegalMovesAround(x,y)?

Regards, Aleks

user627943
  • 125
  • 4

3 Answers3

3

You could use yield! in a new sequence expression:

let allLegalMoves = seq {
  for cell in AllCells do
    yield! LegalMovesAround cell
}
Joh
  • 2,380
  • 20
  • 31
3

Are you aware of yield!?

something like

seq {
    for x,y in Allcells do
        yield! LMA(x,y)
}
Brian
  • 117,631
  • 17
  • 236
  • 300
  • This solution also works, except it returns a sequence with each yield, while I prefer it to return a MoveStruct. The caller shouldn't need to know about the details of the implementation. – user627943 Feb 22 '11 at 19:25
  • No, it yields a MoveStruct. Try it. – Brian Feb 22 '11 at 19:45
1

You should be able to combine them the way they are and then flatten, something like this:

 let validMoves = 
    AllCells 
    |> Seq.collect LegalMovesAround
    |> Seq.distinct

It may not be the best solution performance-wise though.

EDIT: Fixed sample code as per Tomas comment

Robert Jeppesen
  • 7,837
  • 3
  • 35
  • 50
  • Beware of mixing lazy sequences and side effects! If the board is mutated, it's important to have a clear understanding of when the entire sequence is evaluated. Calling Seq.distinct looks dangerous here. – Joh Feb 22 '11 at 10:30
  • Never mind my comment above, Seq.distinct would be called before going down the moves tree. – Joh Feb 22 '11 at 10:42
  • 1
    This doesn't type check. I guess `legalMovesAround` should be argument of `Seq.collect`. – Tomas Petricek Feb 22 '11 at 12:12
  • @Tomas: I should really not write answers without having FSI around. :) – Robert Jeppesen Feb 22 '11 at 15:32
  • Thanks, JUST the solution I was looking for. Short, to the point and no for loops :) – user627943 Feb 22 '11 at 19:26