Loading ...
Sorry, an error occurred while loading the content.

Re: When can I play the six of clubs? Observations on the autoplay controversy

Expand Messages
  • dannyjones183
    ... (foundations), I believe, when any possible card that could be played onto it in a tableau column is either already home or can immediately be played home.
    Message 1 of 10 , Nov 29, 2012
    View Source
    • 0 Attachment
      --- In fc-solve-discuss@yahoogroups.com, "MichaelK" <wgreview@...> wrote:
      >
      > Here are my observations and opinions on the autoplay controversy:
      >
      > It is always completely safe to play a card to the homecells (foundations), I believe, when any possible card that could be played onto it in a tableau column is either already home or can immediately be played home. So we can play the six of clubs to its foundation pile if the five of clubs, three of spades, and both red fours are already there. This is true because 6C could only hold red fives and the 4S (of the cards not already home). This is, I hope, a clear and obvious rule, and was implemented in some of the earliest FreeCell
      > programs (it is currently implemented by NetCELL among others).
      >
      > Are there any such plays which a solver would not want to make? I am not aware of any, but I haven't ever designed a solver.
      >
      > Microsoft FreeCell does not fully implement this rule: it requires that both red fives be home already before it plays the six of clubs. (It does apply the rule in the case of twos.) MS FC plays the six of clubs in this case, however, regardless of how many cards are on the spade foundation. I would argue that this is an extension of the rule described above, not the other way around. It is safe to play 6C to the foundations 5C AS 5H 5D under the standard rules, since the six of clubs in a tableau column cannot hold 4S or 2S (the necessary intervening red cards being missing). But the play of 6C to 5C AS 5H 5D is *not* always a safe play in the variant of FreeCell where worrying back (playing cards from foundations back to tableau columns or freecells) is permitted. (This variant has been examined for its effect on the winnability of a few rare deals). In that variant, you might conceivably need to extract 4S from some remote spot (or perhaps to unblock a freecell) by playing a red five back from its foundation onto the 6C, and putting 4S on the red five. So if worrying back is allowed, the extra plays that MS FC makes beyond the rule I mentioned first are not automatically safe.
      >
      > Microsoft FC is not the definitive version of FreeCell, though Wilson Callan and Adrian Ettlinger considered it so and tried to make FreeCell Pro (to its detriment) behave exactly like MS FC as far as autoplay and supermoves were concerned, in order to make playback of recorded solutions compatible. This was misguided, in my view, because (1) MS FC has no automatic playback capability anyway, (2) it turned some supermoves into monstrosities, and (3) Microsoft FreeCell later changed its supermove rules, so that some recorded solutions no longer play back correctly in MS FC anyway.
      >
      > Since it's my intention to eventually replace FreeCell Pro, I think that FC solver designers (Danny, Shlomi, and Gary in particular) should work out standards for what autoplays are recorded in solutions (and how supermoves are recorded) without any reference at all to how Microsoft FreeCell or FreeCell Pro did things. What works best for your solvers? I would be happy to make whatever you three can agree on the standard in both the FAQ and the eventual replacement program, FreeCell Virtuoso.
      >
      > As far as counting moves (for finding minimal solutions), I'll suggest something which might simplify the uncertainty there too. I think that no plays to the foundations should count towards the total -- only plays to and from the columns and freecells. That way a particular solution will be designated as having the same number of moves regardless of what autoplay rule you are using (even AutoPlayAll or AutoPlayNone).
      >
      > Comments are welcome.
      >

      Automove logic for Keith's first scenario. Braces contain actual values assigned.


      /* Foundation:        5C 4D 3S 4H */
      /* Card in Question:  6C          */

      int   Test_1, Test_2, Test_3, Test_4, val_1[4], val_2[4];

      val_1[C] = {6} = RANK( 5C ) + 1;
      val_1[D] = {5} = RANK( 4D ) + 1;
      val_1[S] = {4} = RANK( 3S ) + 1;
      val_1[H] = {5} = RANK( 4H ) + 1;

      val_2[C] = val_2[S] = {6} = MIN( val_1[D] , val_1[H] ) + 1;
      val_2[D] = val_2[H] = {5} = MIN( val_1[C] , val_1[S] ) + 1;

      Test_1   = {T} =   ( RANK( 6C ) == val_1[C] );
      Test_2   = {F} =   ( RANK( 6C ) <  val_2[C] );
      Test_3   = {T} = ( ( RANK( 6C ) == val_2[C] ) && ( RANK( 6C ) <= ( val_1[S] + 2 ) ) );
      Test_4   = {F} = ( Test_3 && ( RANK( 6C ) == 2 ) );

           if ( Test_1 && ( Test_2 || Test_4 ) )   /* perform Horne     automove */
      else if ( Test_1 && ( Test_2 || Test_3 ) )   /* perform WKRaymond automove */


      In this scenario, the 6C is not moved to the foundation as a Horne automove, but it is moved to the foundation as a WKRaymond automove.


      Automove logic for Keith's second scenario. Braces contain actual values assigned.


      /* Foundation:        5C 5D AS 5H */
      /* Card in Question:  6C          */

      int   Test_1, Test_2, Test_3, Test_4, val_1[4], val_2[4];

      val_1[C] = {6} = RANK( 5C ) + 1;
      val_1[D] = {6} = RANK( 5D ) + 1;
      val_1[S] = {2} = RANK( AS ) + 1;
      val_1[H] = {6} = RANK( 5H ) + 1;

      val_2[C] = val_2[S] = {7} = MIN( val_1[D] , val_1[H] ) + 1;
      val_2[D] = val_2[H] = {3} = MIN( val_1[C] , val_1[S] ) + 1;

      Test_1   = {T} =   ( RANK( 6C ) == val_1[C] );
      Test_2   = {T} =   ( RANK( 6C ) <  val_2[C] );
      Test_3   = {F} = ( ( RANK( 6C ) == val_2[C] ) && ( RANK( 6C ) <= ( val_1[S] + 2 ) ) );
      Test_4   = {F} = ( Test_3 && ( RANK( 6C ) == 2 ) );

           if ( Test_1 && ( Test_2 || Test_4 ) )   /* perform Horne     automove */
      else if ( Test_1 && ( Test_2 || Test_3 ) )   /* perform WKRaymond automove */


      In this scenario, the 6C is moved to the foundation as a Horne automove.


      Because Test_4 is simply Test_3 with an additional constraint, that's why I consider the Horne automove algorithm to be a subset of the WKRaymond automove algorithm.


    • Gary Campbell
      My belief is that Danny’s programmed logic agrees with Michael’s description. I would agree that these two sets of tests define a Horne Automove and a WKR
      Message 2 of 10 , Nov 29, 2012
      View Source
      • 0 Attachment
        My belief is that Danny’s programmed logic agrees with Michael’s description.
        I would agree that these two sets of tests define a Horne Automove and a WKR
        Automove.  I don’t think we need any other kind of Automoves.
         
        I also agree emphatically with Michael’s suggestion that for purposes of move
        counting solution lengths we should not count any card->home moves Auto or
        otherwise.  I don’t know why I didn’t think of this when Danny and I were
        discussing it!
         
        That only leaves us to decide on Standard Notation, and I would volunteer to
        participate on that.
         
        -Gary
         
        Sent: Thursday, November 29, 2012 1:47 AM
        Subject: Re: When can I play the six of clubs? Observations on the autoplay controversy
         
         


        --- In fc-solve-discuss@yahoogroups.com, "MichaelK" <wgreview@...> wrote:

        >
        > Here are my observations and opinions on the autoplay
        controversy:
        >
        > It is always completely safe to play a card to the
        homecells (foundations), I believe, when any possible card that could be played onto it in a tableau column is either already home or can immediately be played home. So we can play the six of clubs to its foundation pile if the five of clubs, three of spades, and both red fours are already there. This is true because 6C could only hold red fives and the 4S (of the cards not already home). This is, I hope, a clear and obvious rule, and was implemented in some of the earliest FreeCell
        > programs (it is currently implemented by NetCELL
        among others).
        >
        > Are there any such plays which a solver would
        not want to make? I am not aware of any, but I haven't ever designed a solver.
        >
        > Microsoft FreeCell does not fully implement this rule:
        it requires that both red fives be home already before it plays the six of clubs. (It does apply the rule in the case of twos.) MS FC plays the six of clubs in this case, however, regardless of how many cards are on the spade foundation. I would argue that this is an extension of the rule described above, not the other way around. It is safe to play 6C to the foundations 5C AS 5H 5D under the standard rules, since the six of clubs in a tableau column cannot hold 4S or 2S (the necessary intervening red cards being missing). But the play of 6C to 5C AS 5H 5D is *not* always a safe play in the variant of FreeCell where worrying back (playing cards from foundations back to tableau columns or freecells) is permitted. (This variant has been examined for its effect on the winnability of a few rare deals). In that variant, you might conceivably need to extract 4S from some remote spot (or perhaps to unblock a freecell) by playing a red five back from its foundation onto the 6C, and putting 4S on the red five. So if worrying back is allowed, the extra plays that MS FC makes beyond the rule I mentioned first are not automatically safe.
        >
        > Microsoft FC is
        not the definitive version of FreeCell, though Wilson Callan and Adrian Ettlinger considered it so and tried to make FreeCell Pro (to its detriment) behave exactly like MS FC as far as autoplay and supermoves were concerned, in order to make playback of recorded solutions compatible. This was misguided, in my view, because (1) MS FC has no automatic playback capability anyway, (2) it turned some supermoves into monstrosities, and (3) Microsoft FreeCell later changed its supermove rules, so that some recorded solutions no longer play back correctly in MS FC anyway.
        >
        > Since it's my intention to
        eventually replace FreeCell Pro, I think that FC solver designers (Danny, Shlomi, and Gary in particular) should work out standards for what autoplays are recorded in solutions (and how supermoves are recorded) without any reference at all to how Microsoft FreeCell or FreeCell Pro did things. What works best for your solvers? I would be happy to make whatever you three can agree on the standard in both the FAQ and the eventual replacement program, FreeCell Virtuoso.
        >
        > As far as counting moves (for finding minimal
        solutions), I'll suggest something which might simplify the uncertainty there too. I think that no plays to the foundations should count towards the total -- only plays to and from the columns and freecells. That way a particular solution will be designated as having the same number of moves regardless of what autoplay rule you are using (even AutoPlayAll or AutoPlayNone).
        >
        > Comments are
        welcome.
        >

        Automove logic for Keith's first scenario. Braces contain actual values assigned.


        /* Foundation:        5C 4D 3S 4H */
        /* Card in Question:  6C          */

        int   Test_1, Test_2, Test_3, Test_4, val_1[4], val_2[4];

        val_1[C] = {6} = RANK( 5C ) + 1;
        val_1[D] = {5} = RANK( 4D ) + 1;
        val_1[S] = {4} = RANK( 3S ) + 1;
        val_1[H] = {5} = RANK( 4H ) + 1;

        val_2[C] = val_2[S] = {6} = MIN( val_1[D] , val_1[H] ) + 1;
        val_2[D] = val_2[H] = {5} = MIN( val_1[C] , val_1[S] ) + 1;

        Test_1   = {T} =   ( RANK( 6C ) == val_1[C] );
        Test_2   = {F} =   ( RANK( 6C ) <  val_2[C] );
        Test_3   = {T} = ( ( RANK( 6C ) == val_2[C] ) && ( RANK( 6C ) <= ( val_1[S] + 2 ) ) );
        Test_4   = {F} = ( Test_3 && ( RANK( 6C ) == 2 ) );

             if ( Test_1 && ( Test_2 || Test_4 ) )   /* perform Horne     automove */
        else if ( Test_1 && ( Test_2 || Test_3 ) )   /* perform WKRaymond automove */


        In this scenario, the 6C is not moved to the foundation as a Horne automove, but it is moved to the foundation as a WKRaymond automove.


        Automove logic for Keith's second scenario. Braces contain actual values assigned.


        /* Foundation:        5C 5D AS 5H */
        /* Card in Question:  6C          */

        int   Test_1, Test_2, Test_3, Test_4, val_1[4], val_2[4];

        val_1[C] = {6} = RANK( 5C ) + 1;
        val_1[D] = {6} = RANK( 5D ) + 1;
        val_1[S] = {2} = RANK( AS ) + 1;
        val_1[H] = {6} = RANK( 5H ) + 1;

        val_2[C] = val_2[S] = {7} = MIN( val_1[D] , val_1[H] ) + 1;
        val_2[D] = val_2[H] = {3} = MIN( val_1[C] , val_1[S] ) + 1;

        Test_1   = {T} =   ( RANK( 6C ) == val_1[C] );
        Test_2   = {T} =   ( RANK( 6C ) <  val_2[C] );
        Test_3   = {F} = ( ( RANK( 6C ) == val_2[C] ) && ( RANK( 6C ) <= ( val_1[S] + 2 ) ) );
        Test_4   = {F} = ( Test_3 && ( RANK( 6C ) == 2 ) );

             if ( Test_1 && ( Test_2 || Test_4 ) )   /* perform Horne     automove */
        else if ( Test_1 && ( Test_2 || Test_3 ) )   /* perform WKRaymond automove */


        In this scenario, the 6C is moved to the foundation as a Horne automove.


        Because Test_4 is simply Test_3 with an additional constraint, that's why I consider the Horne automove algorithm to be a subset of the WKRaymond automove algorithm.


      • Shlomi Fish
        Hi Danny, trying to understand your logic I ran into what appears to be a bug: On Thu, 29 Nov 2012 09:47:49 -0000 ... Are you sure that it should be RANK( 6C )
        Message 3 of 10 , Dec 10, 2012
        View Source
        • 0 Attachment
          Hi Danny,

          trying to understand your logic I ran into what appears to be a bug:

          On Thu, 29 Nov 2012 09:47:49 -0000
          "dannyjones183" <dannyjones183@...> wrote:

          >
          > --- In fc-solve-discuss@yahoogroups.com, "MichaelK" <wgreview@...>
          > wrote:
          > >
          > > Here are my observations and opinions on the autoplay controversy:
          > >
          > > It is always completely safe to play a card to the homecells
          > (foundations), I believe, when any possible card that could be played
          > onto it in a tableau column is either already home or can immediately be
          > played home. So we can play the six of clubs to its foundation pile if
          > the five of clubs, three of spades, and both red fours are already
          > there. This is true because 6C could only hold red fives and the 4S (of
          > the cards not already home). This is, I hope, a clear and obvious rule,
          > and was implemented in some of the earliest FreeCell
          > > programs (it is currently implemented by NetCELL among others).
          > >
          > > Are there any such plays which a solver would not want to make? I am
          > not aware of any, but I haven't ever designed a solver.
          > >
          > > Microsoft FreeCell does not fully implement this rule: it requires
          > that both red fives be home already before it plays the six of clubs.
          > (It does apply the rule in the case of twos.) MS FC plays the six of
          > clubs in this case, however, regardless of how many cards are on the
          > spade foundation. I would argue that this is an extension of the rule
          > described above, not the other way around. It is safe to play 6C to the
          > foundations 5C AS 5H 5D under the standard rules, since the six of clubs
          > in a tableau column cannot hold 4S or 2S (the necessary intervening red
          > cards being missing). But the play of 6C to 5C AS 5H 5D is *not* always
          > a safe play in the variant of FreeCell where worrying back (playing
          > cards from foundations back to tableau columns or freecells) is
          > permitted. (This variant has been examined for its effect on the
          > winnability of a few rare deals). In that variant, you might
          > conceivably need to extract 4S from some remote spot (or perhaps to
          > unblock a freecell) by playing a red five back from its foundation onto
          > the 6C, and putting 4S on the red five. So if worrying back is allowed,
          > the extra plays that MS FC makes beyond the rule I mentioned first are
          > not automatically safe.
          > >
          > > Microsoft FC is not the definitive version of FreeCell, though Wilson
          > Callan and Adrian Ettlinger considered it so and tried to make FreeCell
          > Pro (to its detriment) behave exactly like MS FC as far as autoplay and
          > supermoves were concerned, in order to make playback of recorded
          > solutions compatible. This was misguided, in my view, because (1) MS FC
          > has no automatic playback capability anyway, (2) it turned some
          > supermoves into monstrosities, and (3) Microsoft FreeCell later changed
          > its supermove rules, so that some recorded solutions no longer play back
          > correctly in MS FC anyway.
          > >
          > > Since it's my intention to eventually replace FreeCell Pro, I think
          > that FC solver designers (Danny, Shlomi, and Gary in particular) should
          > work out standards for what autoplays are recorded in solutions (and how
          > supermoves are recorded) without any reference at all to how Microsoft
          > FreeCell or FreeCell Pro did things. What works best for your solvers?
          > I would be happy to make whatever you three can agree on the standard in
          > both the FAQ and the eventual replacement program, FreeCell Virtuoso.
          > >
          > > As far as counting moves (for finding minimal solutions), I'll suggest
          > something which might simplify the uncertainty there too. I think that
          > no plays to the foundations should count towards the total -- only plays
          > to and from the columns and freecells. That way a particular solution
          > will be designated as having the same number of moves regardless of what
          > autoplay rule you are using (even AutoPlayAll or AutoPlayNone).
          > >
          > > Comments are welcome.
          > >
          >
          > Automove logic for Keith's first scenario. Braces contain actual values
          > assigned.
          >
          >
          > /* Foundation: 5C 4D 3S 4H */
          > /* Card in Question: 6C */
          >
          > int Test_1, Test_2, Test_3, Test_4, val_1[4], val_2[4];
          >
          > val_1[C] = {6} = RANK( 5C ) + 1;
          > val_1[D] = {5} = RANK( 4D ) + 1;
          > val_1[S] = {4} = RANK( 3S ) + 1;
          > val_1[H] = {5} = RANK( 4H ) + 1;
          >
          > val_2[C] = val_2[S] = {6} = MIN( val_1[D] , val_1[H] ) + 1;
          > val_2[D] = val_2[H] = {5} = MIN( val_1[C] , val_1[S] ) + 1;
          >
          > Test_1 = {T} = ( RANK( 6C ) == val_1[C] );
          > Test_2 = {F} = ( RANK( 6C ) < val_2[C] );
          > Test_3 = {T} = ( ( RANK( 6C ) == val_2[C] ) && ( RANK( 6C ) <= (
          > val_1[S] + 2 ) ) );
          > Test_4 = {F} = ( Test_3 && ( RANK( 6C ) == 2 ) );

          Are you sure that it should be RANK( 6C ) == 2 (with a constant of 2.)? 6C can
          never have such a rank so the test will almost always fail. Of can you only
          play cards with a rank of 2 this way?

          Regards,

          Shlomi Fish.

          >
          > if ( Test_1 && ( Test_2 || Test_4 ) ) /* perform Horne
          > automove */
          > else if ( Test_1 && ( Test_2 || Test_3 ) ) /* perform WKRaymond
          > automove */
          >
          >
          > In this scenario, the 6C is not moved to the foundation as a Horne
          > automove, but it is moved to the foundation as a WKRaymond automove.
          >
          >
          > Automove logic for Keith's second scenario. Braces contain actual values
          > assigned.
          >
          >
          > /* Foundation: 5C 5D AS 5H */
          > /* Card in Question: 6C */
          >
          > int Test_1, Test_2, Test_3, Test_4, val_1[4], val_2[4];
          >
          > val_1[C] = {6} = RANK( 5C ) + 1;
          > val_1[D] = {6} = RANK( 5D ) + 1;
          > val_1[S] = {2} = RANK( AS ) + 1;
          > val_1[H] = {6} = RANK( 5H ) + 1;
          >
          > val_2[C] = val_2[S] = {7} = MIN( val_1[D] , val_1[H] ) + 1;
          > val_2[D] = val_2[H] = {3} = MIN( val_1[C] , val_1[S] ) + 1;
          >
          > Test_1 = {T} = ( RANK( 6C ) == val_1[C] );
          > Test_2 = {T} = ( RANK( 6C ) < val_2[C] );
          > Test_3 = {F} = ( ( RANK( 6C ) == val_2[C] ) && ( RANK( 6C ) <= (
          > val_1[S] + 2 ) ) );
          > Test_4 = {F} = ( Test_3 && ( RANK( 6C ) == 2 ) );
          >
          > if ( Test_1 && ( Test_2 || Test_4 ) ) /* perform Horne
          > automove */
          > else if ( Test_1 && ( Test_2 || Test_3 ) ) /* perform WKRaymond
          > automove */
          >
          >
          > In this scenario, the 6C is moved to the foundation as a Horne automove.
          >
          >
          > Because Test_4 is simply Test_3 with an additional constraint, that's
          > why I consider the Horne automove algorithm to be a subset of the
          > WKRaymond automove algorithm.
          >
          >
          >



          --
          -----------------------------------------------------------------
          Shlomi Fish http://www.shlomifish.org/
          The Case for File Swapping - http://shlom.in/file-swap

          Chuck Norris wrote a complete Perl 6 implementation in a day, but then
          destroyed all evidence with his bare hands, so no‐one will know his secrets.

          Please reply to list if it's a mailing list post - http://shlom.in/reply .
        • dannyjones183
          ... ... values ... 2.)? 6C can ... only ... I placed MK s actual cards into the logic used by my solver. The Card in Question was the 6C. The reason
          Message 4 of 10 , Dec 10, 2012
          View Source
          • 0 Attachment
            --- In fc-solve-discuss@yahoogroups.com, Shlomi Fish <shlomif@...> wrote:
            >
            > Hi Danny,
            >
            > trying to understand your logic I ran into what appears to be a bug:
            >

            <snip>

            > >
            > > Automove logic for Keith's first scenario. Braces contain actual values
            > > assigned.
            > >
            > >
            > > /* Foundation: 5C 4D 3S 4H */
            > > /* Card in Question: 6C */
            > >
            > > int Test_1, Test_2, Test_3, Test_4, val_1[4], val_2[4];
            > >
            > > val_1[C] = {6} = RANK( 5C ) + 1;
            > > val_1[D] = {5} = RANK( 4D ) + 1;
            > > val_1[S] = {4} = RANK( 3S ) + 1;
            > > val_1[H] = {5} = RANK( 4H ) + 1;
            > >
            > > val_2[C] = val_2[S] = {6} = MIN( val_1[D] , val_1[H] ) + 1;
            > > val_2[D] = val_2[H] = {5} = MIN( val_1[C] , val_1[S] ) + 1;
            > >
            > > Test_1 = {T} = ( RANK( 6C ) == val_1[C] );
            > > Test_2 = {F} = ( RANK( 6C ) < val_2[C] );
            > > Test_3 = {T} = ( ( RANK( 6C ) == val_2[C] ) && ( RANK( 6C ) <= (
            > > val_1[S] + 2 ) ) );
            > > Test_4 = {F} = ( Test_3 && ( RANK( 6C ) == 2 ) );
            >
            > Are you sure that it should be RANK( 6C ) == 2 (with a constant of 2.)? 6C can
            > never have such a rank so the test will almost always fail. Of can you only
            > play cards with a rank of 2 this way?
            >

            I placed MK's actual cards into the logic used by my solver. The "Card in Question" was the 6C. The reason for the test ( RANK(card) == 2 ) is to allow the Horne automove logic to perform a WKR automove for 2's. There's actually two groups of logic in a Horne automove!

            <snip>

            Regards, Danny

          • Shlomi Fish
            Hi Danny, see below for my response: On Mon, 10 Dec 2012 19:38:37 -0000 ... Trying to implement Raymond s play properly, I ve written this code (hope it is
            Message 5 of 10 , Dec 24, 2012
            View Source
            • 0 Attachment
              Hi Danny,

              see below for my response:

              On Mon, 10 Dec 2012 19:38:37 -0000
              "dannyjones183" <dannyjones183@...> wrote:

              > --- In fc-solve-discuss@yahoogroups.com, Shlomi Fish <shlomif@...>
              > wrote:
              > >
              > > Hi Danny,
              > >
              > > trying to understand your logic I ran into what appears to be a bug:
              > >
              >
              > <snip>
              >
              > > >
              > > > Automove logic for Keith's first scenario. Braces contain actual
              > values
              > > > assigned.
              > > >
              > > >
              > > > /* Foundation: 5C 4D 3S 4H */
              > > > /* Card in Question: 6C */
              > > >
              > > > int Test_1, Test_2, Test_3, Test_4, val_1[4], val_2[4];
              > > >
              > > > val_1[C] = {6} = RANK( 5C ) + 1;
              > > > val_1[D] = {5} = RANK( 4D ) + 1;
              > > > val_1[S] = {4} = RANK( 3S ) + 1;
              > > > val_1[H] = {5} = RANK( 4H ) + 1;
              > > >
              > > > val_2[C] = val_2[S] = {6} = MIN( val_1[D] , val_1[H] ) + 1;
              > > > val_2[D] = val_2[H] = {5} = MIN( val_1[C] , val_1[S] ) + 1;
              > > >
              > > > Test_1 = {T} = ( RANK( 6C ) == val_1[C] );
              > > > Test_2 = {F} = ( RANK( 6C ) < val_2[C] );
              > > > Test_3 = {T} = ( ( RANK( 6C ) == val_2[C] ) && ( RANK( 6C ) <= (
              > > > val_1[S] + 2 ) ) );
              > > > Test_4 = {F} = ( Test_3 && ( RANK( 6C ) == 2 ) );
              > >
              > > Are you sure that it should be RANK( 6C ) == 2 (with a constant of
              > 2.)? 6C can
              > > never have such a rank so the test will almost always fail. Of can you
              > only
              > > play cards with a rank of 2 this way?
              > >
              >
              > I placed MK's actual cards into the logic used by my solver. The "Card
              > in Question" was the 6C. The reason for the test ( RANK(card) == 2 ) is
              > to allow the Horne automove logic to perform a WKR automove for 2's.
              > There's actually two groups of logic in a Horne automove!
              >
              > <snip>
              >
              > Regards, Danny
              >

              Trying to implement Raymond's play properly, I've written this code (hope it
              is easy to understand):

              [CODE]

              extern int fc_solve_sfs_raymond_prune(
              fc_solve_soft_thread_t * soft_thread,
              fcs_kv_state_t * raw_ptr_state_raw,
              fcs_collectible_state_t * * ptr_next_state_val
              )
              {
              tests_define_accessors();
              #ifndef HARD_CODED_NUM_STACKS
              SET_GAME_PARAMS();
              #endif

              fcs_derived_states_list_t derived_states_list_struct;
              derived_states_list_struct.states = NULL;
              derived_states_list_struct.num_states = 0;

              sfs_check_state_begin();

              int num_total_cards_moved = 0;
              int num_cards_moved = 0;
              do {
              num_cards_moved = 0;
              for ( int stack_idx=0 ; stack_idx < LOCAL_STACKS_NUM ; stack_idx++)
              {
              fcs_cards_column_t col = fcs_state_get_col(new_state, stack_idx);
              const int cards_num = fcs_col_len(col);

              if (cards_num)
              {
              /* Get the top card in the stack */
              const fcs_card_t card = fcs_col_get_card(col, cards_num-1);

              const int dest_foundation = CALC_FOUNDATION_TO_PUT_CARD_ON();
              if (dest_foundation >= 0)
              {
              /* We can safely move it. */
              num_cards_moved++;

              my_copy_stack(stack_idx);
              {
              fcs_cards_column_t new_temp_col;
              new_temp_col = fcs_state_get_col(new_state, stack_idx);
              fcs_col_pop_top(new_temp_col);
              }

              fcs_increment_foundation(new_state, dest_foundation);

              fcs_internal_move_t temp_move;
              fcs_int_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_FOUNDATION);
              fcs_int_move_set_src_stack(temp_move,stack_idx);
              fcs_int_move_set_foundation(temp_move,dest_foundation);

              fcs_move_stack_push(moves, temp_move);

              fcs_flip_top_card(stack_idx);
              }
              }
              }

              /* Now check the same for the free cells */
              for ( int fc=0 ; fc < LOCAL_FREECELLS_NUM ; fc++)
              {
              const fcs_card_t card = fcs_freecell_card(new_state, fc);
              if (fcs_card_is_valid(card))
              {
              const int dest_foundation = CALC_FOUNDATION_TO_PUT_CARD_ON();
              if (dest_foundation >= 0)
              {
              num_cards_moved++;

              /* We can put it there */

              fcs_empty_freecell(new_state, fc);

              fcs_internal_move_t temp_move;
              fcs_increment_foundation(new_state, dest_foundation);

              fcs_int_move_set_type(temp_move,FCS_MOVE_TYPE_FREECELL_TO_FOUNDATION);
              fcs_int_move_set_src_freecell(temp_move,fc);
              fcs_int_move_set_foundation(temp_move,dest_foundation);

              fcs_move_stack_push(moves, temp_move);
              }
              }
              }
              num_total_cards_moved += num_cards_moved;
              } while (num_cards_moved);

              #define derived_states_list (&derived_states_list_struct)
              sfs_check_state_end();
              #undef derived_states_list

              {
              register int ret_code;

              if (num_total_cards_moved)
              {
              register fcs_collectible_state_t * ptr_next_state;

              *ptr_next_state_val
              = ptr_next_state
              = derived_states_list_struct.states[0].state_ptr;

              /*
              * Set the GENERATED_BY_PRUNING flag uncondtionally. It won't
              * hurt if it's already there, and if it's a state that was
              * found by other means, we still shouldn't prune it, because
              * it is already "prune-perfect".
              * */
              FCS_S_VISITED(ptr_next_state) |= FCS_VISITED_GENERATED_BY_PRUNING;

              ret_code = PRUNE_RET_FOLLOW_STATE;
              }
              else
              {
              *ptr_next_state_val = NULL;
              ret_code = PRUNE_RET_NOT_FOUND;
              }

              free(derived_states_list_struct.states);

              return ret_code;
              }
              }

              [/CODE]

              Now, not only implementing it instead of my previous prune broke the tests
              (which is expected because some of them check for exact output), it also made
              performance worse - the MS 32k deals ran at 30 seconds instead of 20 seconds
              using the "-l as" preset. Perhaps I need to recalibrate the switch tasking,
              but I don't think it will make much difference.

              Anyway, do you see any obvious bug in my code and the interpretation of the
              Raymond prune based on your Cish pseudocode? I guess I can implement it in the
              other places where it exists (duplicate code for-the-win) assuming it does not
              yield false negatives, though.

              Regards,

              Shlomi Fish

              --
              -----------------------------------------------------------------
              Shlomi Fish http://www.shlomifish.org/
              My Aphorisms - http://www.shlomifish.org/humour.html

              Do not meddle in the affairs of Dragons, for you are crunchy and taste good
              with ketchup. — Unknown source.

              Please reply to list if it's a mailing list post - http://shlom.in/reply .
            • dannyjones183
              Hello Shlomi, I m sorry to say that I couldn t follow your routine. What I saw was numerous calls to external routines/def s for data structures that were
              Message 6 of 10 , Dec 24, 2012
              View Source
              • 0 Attachment
                Hello Shlomi,

                I'm sorry to say that I couldn't follow your routine. What I saw was numerous calls to external routines/def's for data structures that were unfamiliar. In particular, I didn't notice anything similar to the calculations/tests that I perform.

                In my solver, I perform a move and pass the data structure to either my Horne() routine or my WKR() routine. They performs all automoves appropriate for the routine called, and then return the data structure. I then check to see if the deal/game is solved or if I need to perform another move.

                Note: my WKR() routine is written as a super-set of the Horne() routine, so I don't need to make a separate call for those automoves.

                I have a terrible memory anymore, but I seem to recall that my solver ran slightly faster with WKR() over Horne() because the former routine advanced the solution faster because I needed to perform fewer manual moves.

                Regards, Danny



                --- In fc-solve-discuss@yahoogroups.com, Shlomi Fish <shlomif@...> wrote:
                >
                <snip>
                >
                > [CODE]
                >
                > extern int fc_solve_sfs_raymond_prune(
                > fc_solve_soft_thread_t * soft_thread,
                > fcs_kv_state_t * raw_ptr_state_raw,
                > fcs_collectible_state_t * * ptr_next_state_val
                > )
                > {
                > tests_define_accessors();
                > #ifndef HARD_CODED_NUM_STACKS
                > SET_GAME_PARAMS();
                > #endif
                >
                > fcs_derived_states_list_t derived_states_list_struct;
                > derived_states_list_struct.states = NULL;
                > derived_states_list_struct.num_states = 0;
                >
                > sfs_check_state_begin();
                >
                > int num_total_cards_moved = 0;
                > int num_cards_moved = 0;
                > do {
                > num_cards_moved = 0;
                > for ( int stack_idx=0 ; stack_idx < LOCAL_STACKS_NUM ; stack_idx++)
                > {
                > fcs_cards_column_t col = fcs_state_get_col(new_state, stack_idx);
                > const int cards_num = fcs_col_len(col);
                >
                > if (cards_num)
                > {
                > /* Get the top card in the stack */
                > const fcs_card_t card = fcs_col_get_card(col, cards_num-1);
                >
                > const int dest_foundation = CALC_FOUNDATION_TO_PUT_CARD_ON();
                > if (dest_foundation >= 0)
                > {
                > /* We can safely move it. */
                > num_cards_moved++;
                >
                > my_copy_stack(stack_idx);
                > {
                > fcs_cards_column_t new_temp_col;
                > new_temp_col = fcs_state_get_col(new_state, stack_idx);
                > fcs_col_pop_top(new_temp_col);
                > }
                >
                > fcs_increment_foundation(new_state, dest_foundation);
                >
                > fcs_internal_move_t temp_move;
                > fcs_int_move_set_type(temp_move,FCS_MOVE_TYPE_STACK_TO_FOUNDATION);
                > fcs_int_move_set_src_stack(temp_move,stack_idx);
                > fcs_int_move_set_foundation(temp_move,dest_foundation);
                >
                > fcs_move_stack_push(moves, temp_move);
                >
                > fcs_flip_top_card(stack_idx);
                > }
                > }
                > }
                >
                > /* Now check the same for the free cells */
                > for ( int fc=0 ; fc < LOCAL_FREECELLS_NUM ; fc++)
                > {
                > const fcs_card_t card = fcs_freecell_card(new_state, fc);
                > if (fcs_card_is_valid(card))
                > {
                > const int dest_foundation = CALC_FOUNDATION_TO_PUT_CARD_ON();
                > if (dest_foundation >= 0)
                > {
                > num_cards_moved++;
                >
                > /* We can put it there */
                >
                > fcs_empty_freecell(new_state, fc);
                >
                > fcs_internal_move_t temp_move;
                > fcs_increment_foundation(new_state, dest_foundation);
                >
                > fcs_int_move_set_type(temp_move,FCS_MOVE_TYPE_FREECELL_TO_FOUNDATION);
                > fcs_int_move_set_src_freecell(temp_move,fc);
                > fcs_int_move_set_foundation(temp_move,dest_foundation);
                >
                > fcs_move_stack_push(moves, temp_move);
                > }
                > }
                > }
                > num_total_cards_moved += num_cards_moved;
                > } while (num_cards_moved);
                >
                > #define derived_states_list (&derived_states_list_struct)
                > sfs_check_state_end();
                > #undef derived_states_list
                >
                > {
                > register int ret_code;
                >
                > if (num_total_cards_moved)
                > {
                > register fcs_collectible_state_t * ptr_next_state;
                >
                > *ptr_next_state_val
                > = ptr_next_state
                > = derived_states_list_struct.states[0].state_ptr;
                >
                > /*
                > * Set the GENERATED_BY_PRUNING flag uncondtionally. It won't
                > * hurt if it's already there, and if it's a state that was
                > * found by other means, we still shouldn't prune it, because
                > * it is already "prune-perfect".
                > * */
                > FCS_S_VISITED(ptr_next_state) |= FCS_VISITED_GENERATED_BY_PRUNING;
                >
                > ret_code = PRUNE_RET_FOLLOW_STATE;
                > }
                > else
                > {
                > *ptr_next_state_val = NULL;
                > ret_code = PRUNE_RET_NOT_FOUND;
                > }
                >
                > free(derived_states_list_struct.states);
                >
                > return ret_code;
                > }
                > }
                >
                > [/CODE]
                >
                > Now, not only implementing it instead of my previous prune broke the tests
                > (which is expected because some of them check for exact output), it also made
                > performance worse - the MS 32k deals ran at 30 seconds instead of 20 seconds
                > using the "-l as" preset. Perhaps I need to recalibrate the switch tasking,
                > but I don't think it will make much difference.
                >
                > Anyway, do you see any obvious bug in my code and the interpretation of the
                > Raymond prune based on your Cish pseudocode? I guess I can implement it in the
                > other places where it exists (duplicate code for-the-win) assuming it does not
                > yield false negatives, though.
                >
              • Shlomi Fish
                Hi Danny, On Tue, 25 Dec 2012 00:23:19 -0000 ... Oh sorry, I ve copy+pasted the wrong function here. Most of the heavy lifting in determining whether the
                Message 7 of 10 , Dec 25, 2012
                View Source
                • 0 Attachment
                  Hi Danny,

                  On Tue, 25 Dec 2012 00:23:19 -0000
                  "dannyjones183" <dannyjones183@...> wrote:

                  > Hello Shlomi,
                  >
                  > I'm sorry to say that I couldn't follow your routine. What I saw was numerous
                  > calls to external routines/def's for data structures that were unfamiliar. In
                  > particular, I didn't notice anything similar to the calculations/tests that I
                  > perform.
                  >
                  > In my solver, I perform a move and pass the data structure to either my
                  > Horne() routine or my WKR() routine. They performs all automoves appropriate
                  > for the routine called, and then return the data structure. I then check to
                  > see if the deal/game is solved or if I need to perform another move.
                  >
                  > Note: my WKR() routine is written as a super-set of the Horne() routine, so I
                  > don't need to make a separate call for those automoves.
                  >
                  > I have a terrible memory anymore, but I seem to recall that my solver ran
                  > slightly faster with WKR() over Horne() because the former routine advanced
                  > the solution faster because I needed to perform fewer manual moves.
                  >

                  Oh sorry, I've copy+pasted the wrong function here. Most of the heavy lifting in
                  determining whether the foundation should be moved is done in the
                  CALC_FOUNDATION_TO_PUT_CARD_ON() macro which in turn calls this code:

                  <<<CODE>>>

                  #define CALC_FOUNDATION_TO_PUT_CARD_ON__STATE_PARAMS() pass_new_state.key, card

                  #define CALC_FOUNDATION_TO_PUT_CARD_ON()
                  calc_foundation_to_put_card_on(soft_thread,
                  CALC_FOUNDATION_TO_PUT_CARD_ON__STATE_PARAMS())

                  #ifdef FCS_FREECELL_ONLY
                  #define SEQS_ARE_BUILT_BY_RANK() FALSE
                  #else
                  #define SEQS_ARE_BUILT_BY_RANK() (sequences_are_built_by ==
                  FCS_SEQ_BUILT_BY_RANK) #endif

                  static GCC_INLINE int calc_foundation_to_put_card_on(
                  fc_solve_soft_thread_t * soft_thread,
                  fcs_state_t * my_ptr_state,
                  const fcs_card_t card
                  )
                  {
                  #ifndef FCS_FREECELL_ONLY
                  fc_solve_instance_t * instance = soft_thread->hard_thread->instance;
                  #endif

                  tests_define_seqs_built_by();

                  for (int deck = 0 ; deck < INSTANCE_DECKS_NUM ; deck++)
                  {
                  if (fcs_foundation_value(*my_ptr_state, (deck<<2)+fcs_card_suit(card))
                  == fcs_card_rank(card) - 1) {
                  int ret_val = (deck<<2)+fcs_card_suit(card);
                  /* Always put on the foundation if it is built-by-suit */
                  #ifndef FCS_FREECELL_ONLY
                  if (sequences_are_built_by == FCS_SEQ_BUILT_BY_SUIT)
                  {
                  return ret_val;
                  }
                  #endif

                  int other_suit_idx;
                  int min_other_color_val = FCS_MAX_RANK+1, min_same_color_val =
                  FCS_MAX_RANK+1; for (other_suit_idx = 0 ; other_suit_idx < (INSTANCE_DECKS_NUM
                  << 2) ; other_suit_idx++) {
                  if (( other_suit_idx & (4-1)) != fcs_card_suit(card))
                  {
                  if (SEQS_ARE_BUILT_BY_RANK())
                  {
                  min_other_color_val = min(min_other_color_val,
                  fcs_foundation_value(*my_ptr_state, other_suit_idx)); }
                  else if (
                  ((other_suit_idx&0x1) == (fcs_card_suit(card)&0x1))
                  )
                  {
                  min_same_color_val = min(min_same_color_val,
                  fcs_foundation_value(*my_ptr_state, other_suit_idx)); }
                  else
                  min_other_color_val = min(min_other_color_val,
                  fcs_foundation_value(*my_ptr_state, other_suit_idx)); {
                  }
                  }
                  }
                  if (
                  (min_other_color_val+1 < fcs_card_rank(card))
                  &&
                  (SEQS_ARE_BUILT_BY_RANK()
                  ? TRUE
                  :
                  (
                  (min_other_color_val+1 == fcs_card_rank(card))
                  &&
                  (fcs_card_rank(card) <= min_same_color_val+(2+1))
                  )
                  )
                  )
                  {
                  return ret_val;
                  }
                  }
                  }

                  return -1;
                  }

                  <<< / CODE>>>

                  You can also view it online here:

                  https://bitbucket.org/shlomif/fc-solve/src/2a9c72e4ad2957a2cbdc3b827e15b7fb71c0f66a/fc-solve/source/freecell.c?at=correcting_raymonds_prune#cl-1942

                  (Short URL : http://is.gd/kUR1q4 ).

                  Regards,

                  Shlomi Fish

                  > Regards, Danny

                  [SNIPPED]


                  --
                  -----------------------------------------------------------------
                  Shlomi Fish http://www.shlomifish.org/
                  List of Text Processing Tools - http://shlom.in/text-proc

                  To have bugs is human; to fix them — divine.

                  Please reply to list if it's a mailing list post - http://shlom.in/reply .
                • dannyjones183
                  Hello Shlomi, Sorry, but I still can t follow your code. The state of previous #define s and the actions of various functions are unknown to me. See below for
                  Message 8 of 10 , Dec 26, 2012
                  View Source
                  • 0 Attachment
                    Hello Shlomi,

                    Sorry, but I still can't follow your code. The state of previous #define's and the actions of various functions are unknown to me. See below for what I suggest.

                    --- In fc-solve-discuss@yahoogroups.com, Shlomi Fish
                    wrote:
                      
                    >
                    > Oh sorry, I've copy+pasted the wrong function here. Most of the heavy lifting in
                    > determining whether the foundation should be moved is done in the
                    > CALC_FOUNDATION_TO_PUT_CARD_ON() macro which in turn calls this code:
                    >
                      

                    In post #1260, I simulate running two examples through my solver to check for automoves. What does your routine do for these examples?


                    /* Foundation:        5C 4D 3S 4H */
                    /* Card in Question:  6C          */   WKR automove performed

                    /* Foundation:        5C 5D AS 5H */
                    /* Card in Question:  6C          */   Horne automove performed



                  • Shlomi Fish
                    Hi Danny, sorry for the late response, enjoy what s left of 2012 and happy new year. On Wed, 26 Dec 2012 18:42:42 -0000 ... You can find them in my link. ...
                    Message 9 of 10 , Dec 30, 2012
                    View Source
                    • 0 Attachment
                      Hi Danny,

                      sorry for the late response, enjoy what's left of 2012 and happy new year.

                      On Wed, 26 Dec 2012 18:42:42 -0000
                      "dannyjones183" <dannyjones183@...> wrote:

                      > Hello Shlomi,
                      >
                      > Sorry, but I still can't follow your code. The state of previous
                      > #define's and the actions of various functions are unknown to me. See
                      > below for what I suggest.

                      You can find them in my link.

                      >
                      > --- In fc-solve-discuss@yahoogroups.com, Shlomi Fish wrote:
                      >   
                      > >
                      > > Oh sorry, I've copy+pasted the wrong function here. Most of the heavy
                      > lifting in
                      > > determining whether the foundation should be moved is done in the
                      > > CALC_FOUNDATION_TO_PUT_CARD_ON() macro which in turn calls this code:
                      > >
                      >   
                      >
                      > In post #1260, I simulate running two examples through my solver to
                      > check for automoves. What does your routine do for these examples?
                      >
                      >
                      > /* Foundation:        5C 4D 3S 4H */
                      > /* Card in Question:  6C          */   WKR automove performed
                      >
                      > /* Foundation:        5C 5D AS 5H */
                      > /* Card in Question:  6C          */   Horne automove performed
                      >

                      I'm going to write a small test program for that and let you know.

                      Regards,

                      Shlomi Fish

                      --
                      -----------------------------------------------------------------
                      Shlomi Fish http://www.shlomifish.org/
                      My Aphorisms - http://www.shlomifish.org/humour.html

                      <rjbs> sub id { my $self = shift; $json_parser_for{ $self }
                      ->decode($json_for{ $self })->{id} } # Inside‐out JSON‐notated objects

                      Please reply to list if it's a mailing list post - http://shlom.in/reply .
                    Your message has been successfully submitted and would be delivered to recipients shortly.