Android Open Source - TwentyEightForAndroid aisuitlengthsolver






From Project

Back to project page TwentyEightForAndroid.

License

The source code is released under:

GNU General Public License

If you think the Android project TwentyEightForAndroid listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*******************************************************************************
 *                                                                             *
 * Twenty-Eight for Android is port of popular Asian card game called Rosanne: *
 * Twenty-eight (28) <http://sourceforge.net/projects/rosanne/>. Project       *
 * development is done as NBU Java training course held in Sofia, Bulgaria.    *
 *                                                                             *
 * Copyright (C) 2013-2014 by Todor Balabanov  ( tdb@tbsoft.eu )               *
 *                                                                             *
 * This program is free software: you can redistribute it and/or modify        *
 * it under the terms of the GNU General Public License as published by        *
 * the Free Software Foundation, either version 3 of the License, or           *
 * (at your option) any later version.                                         *
 *                                                                             *
 * This program is distributed in the hope that it will be useful,             *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of              *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
 * GNU General Public License for more details.                                *
 *                                                                             *
 * You should have received a copy of the GNU General Public License           *
 * along with this program. If not, see <http://www.gnu.org/licenses/>.        *
 *                                                                             *
 ******************************************************************************/
/*from  w w  w  .  ja  v  a2 s.c  o m*/
package eu.veldsoft.twenty.eight.ai;

import eu.veldsoft.twenty.eight.common.GlobalSpace;

//#ifndef _AI_SUITLENGTHSOLVER_H_
//#define _AI_SUITLENGTHSOLVER_H_
////#include <assert.h>
////#include <memory.h>
////#include <stdio.h>
//#include "wx/wx.h"

// Super type for holding suit length for hands

class slMatrix { static public int values[][] = new int[GlobalSpace.slTOTAL_HANDS][GlobalSpace.slTOTAL_SUITS]; }

// The data which represents played cards, which is provided as one of the inputs to the
// suit length solver. The format is identical to that of slProblem
class slPlayed extends slMatrix {} 

// Solution to the problem
class slSolution extends slMatrix {}

// The data which represents the problem which is provided as one of the inputs to the
// suit length solver.

class slPROBLEM
{
  slMatrix suit_length;
  int suit_total_length[GlobalSpace.slTOTAL_SUITS];
  int hand_total_length[GlobalSpace.slTOTAL_HANDS];
}slProblem;

// Working data for computing the solution.

// Each cell will have
// a) min - the minimum number of cards which must be allocated
// b) max - the maximum number ofa cards that can be callocated
// c) suit_length - number of cards allocated. If it is vacant, the value is slVACANT

class slCELL
{
  int min;
  int max;
  int suit_length;
}slCell;
class slDATA
{
  slCell cells[slTOTAL_HANDS][slTOTAL_SUITS];

  int suit_total_length[slTOTAL_SUITS];
  int hand_total_length[slTOTAL_HANDS];
  int suit_allocated[slTOTAL_SUITS];
  int hand_allocated[slTOTAL_HANDS];

  int suit_sum_of_maxs[slTOTAL_SUITS];
  int hand_sum_of_maxs[slTOTAL_HANDS];

    // This is not really the sum of min values.
    // It is the sum of min values of vacant cells
  int suit_sum_of_vacant_mins[slTOTAL_SUITS];
  int hand_sum_of_vacant_mins[slTOTAL_HANDS];

}slData;

class aiSuitLengthSolver
{
private:
  slProblem m_problem;
  slData m_saved, m_working;
  slPlayed m_played;
  int m_suit_sum_of_min[slTOTAL_SUITS];
  int m_hand_sum_of_min[slTOTAL_HANDS];
  // Disallow copy constructor/assignment operators
  aiSuitLengthSolver(final aiSuitLengthSolver &);
    aiSuitLengthSolver & operator=(final aiSuitLengthSolver &);
    void InitializeWorkingData(slData *data);
    boolean RecalcCellMax(slData *data, int hand, int suit);
  boolean SetCell(slData *data, int hand, int suit, int suit_length);
  boolean RecalcMaxForImpactedCells(slData *data, int hand, int suit);
  boolean RecalcMinForImpactedCells(slData *data, int hand, int suit);
  //boolean RecalcSumOfMaxForAllCells()
  boolean RecalcCellMin(slData *data, int hand, int suit);
  boolean RecalcMinForAllCells(slData *data, boolean * changed = null);
  boolean RecalcMaxForAllCells(slData *data);
  int GenerateRandomFill(int min, int max);

public:
  aiSuitLengthSolver();
  ~aiSuitLengthSolver();
  static void InitializeProblem(slProblem *problem);
  static void InitializePlayed(slPlayed played);
  boolean SetProblem(slProblem *problem, slPlayed played);
  boolean GenerateRandomSolution(slSolution solution);
  //static String PrintProblem(slProblem *problem);
  static String PrintData(slData *data);
  static String PrintMatrix(slMatrix matrix);
  String PrintSavedData();
  String PrintWorkingData();
  //static String PrintSolution(slSolution *solution);
};



//#endif


//




//




//




// What is the suit length problem?
// ********************************
//
// In the following matrix where we have 4 hands (h(1) to h(4)) holding cards from 4 suits (s(1) to s(4)),
// c(x,y) represents the number of cards beloning to suit (y) held by hand (x)
//
//     |  s(1)|  s(2)|  s(3)|  s(4)
// ----+------+------+------+------
// h(1)|c(1,1)|c(1,2)|c(1,3)|c(1,4)
// ----+------+------+------+------
// h(2)|c(2,1)|c(2,2)|c(2,3)|c(2,4)
// ----+------+------+------+------
// h(3)|c(3,1)|c(3,2)|c(3,3)|c(3,4)
// ----+------+------+------+------
// h(4)|c(4,1)|c(4,2)|c(4,3)|c(4,4)
//
//
// Given one or more c(x,y) are unknown, the object of the problem is to fill these randomly.
//
// Preconditions
// *************
//
// Let sum(h(x)) be (c(n,1) + c(n,2) + c(n,3) + c(n,4)), the sum of cards in hand h(x).
// Similary let sum(s(y)) be the sum of cards in suit s(y).
// All sum(h(x)) and (s(y)) are known.
//
// Solution
// ********
//
// The c(x,y) which are unknown are called vacant cells.
//
// Let filled(h(x)) be the sum of cards already filled in previously vacant cells in hand h(x). This will be zero before
// solving the problem and will increase as the problem gets solved, as solving the problem involves filling vacant cells.
// Similarly, let filled(s(y)) be the usm of cards already filled in previously vacant cells for suit s(y).
//
// Each vacant cell c(x,y) will have a max(c(x,y)) and min(c(x,y)).
// max(c(x,y)) is the maximum number of cards which can be allocated to the vacant cell c(x,y).
// Similarly, min(c(x,y)) is the minimum number of cards which should be allocated to the vacant cell c(x,y).
//
// Vacant cells, once filled will have min(c(x,y)) = max(c(x,y)) = (suit length for the cell)
//
//
// Let sum_min(h(x)) be the sum of min values for all cells in hand h(x) which have not been filled.
// let sum_min(s(y)) be the sum of min values for all cells in suit s(y) which have not been filled.
//
// Let MIN be a function such that, MIN(x,y) returns minimum value amongst x and y.
// Let MAX be a function such that, MAX(x,y) returns maximum value amongst x and y.
//
// max(c(x,y)) = MIN(
//                   sum(h(x)) - filled(h(x)) - sum_min(h(x)) + min(c(x,y)),
//                   sum(s(y)) - filled(s(y)) - sum_min(s(y)) + min(c(x,y))
//                  )
//
// Let sum_max(h(x)) be (max(c(x,1)) + max(c(x,2)) + max(c(x,3)) + max(c(x,4)))
// and sum_max(s(y)) be (max(c(1,y)) + max(c(2,y)) + max(c(3,y)) + max(c(4,y)))
//
// There are totally sum(h(x)) cards to be distributed among c(x, n), n=1 to 4.
// For cells c(x,n) where n !=y, the maximum total which can be distributed is sum_max(h(x)) + max(c(x,y)).
// So, c(x,y) should be allocated at least sum(h(x)) - sum_max(h(x)) + max(c(x,y)).
//
// min(c(x,y)) = MAX(
//                  (sum(h(x)) - sum_max(h(x)) + max(c(x,y))),
//                  (sum(s(y)) - sum_max(s(y)) + max(c(x,y)))
//                  )
//
// The following algorithm is then used,
//
// for each vacant cell c(x,y):
//     Get a random(non-linear) i such that min(c(x,y)) <= i <=max(c(x,y))  ---. Refer to the section below
//     Set c(x,y) = i = max(c(x,y)) = min(c(x,y))
//     Recalculate sum_max for h(x) and s(y).
//     Recalculate sum_min for h(x) and s(y).
//     Recalcualte filled for h(x) and s(y).
//     Recalculate max for all impacted cells. That is, all cells in h(x) and s(y).
//     Recalculate min for all impacted cells. That is, all cells in h(x) and s(y).
//
// The last two steps are recursive as change of max for a cell will impact min of other cells and vice versa.
//
// Computation of relative probability
// ***********************************
//
// The process of shuffling generates various permutations of cards.
//
// While solving the suit length problem, a slot where at the most m cards can be accommodated needs
// to be filled randomly with n cards where 0 <= n <= m. Now, the probability of this slot getting filled
// with a zero or m is quite less compared to mod(m/2), the latter being the most probable.
// Hence we cannot pick a number n using a pseudo random number generator satisfying 0 <= n <= m ,
// as the probability for all n is not equal.
//
// The probability of a slot being filled with n, given
// (t) is the total number of cards in the deck used for play,
// (s) the size of the slot open to be filled up, and
// (a) the available number of cards in the suit is given by
//
// (sCn * (t-a)P(s-n) * aPn) / (tPs)
//
// Total number of ways in which (s) cards can be dealt from a total of (t) cards is (tPs).
// The possible ways in which (s-n) cards can be dealt from (t-a) and (n) cards from (a) is (sCn * (t-a)P(s-n) * aPn).
// (sCn) provides the number of ways in which the two separate permutations of
// ((t-a)P(s-n)) and (aPn) can be combined together.
//
// And finally to complicate matters further, we want the generated solution to mirror real-world shuffling.
// Hence the process of filling vacant slots should consider played cards also while computing relative probability.
//
// The algorithm used is as following:
//
// Let there be a slot c(x,y) which is vacant.
// Let a = min(c(x,y)) and b = max(c(x,y)).
// Let played(x,y) be the cards of suit y belonging to hand x which have already been played.
// We ned to pick random i such that a <= i <=b
//
// For i in range a to b
//     Check the probability p(i) of hand x getting (i + played(x,y)) cards of suit y
//
// Please note that in the formula (sCn * (t-a)P(s-n) * aPn) / (tPs), t and s are constant and the denominator can be
// ignore for this calculation. So p(i) is only the numberator
//
// Let sum_played(x,y) be sum of p(i) when i=a to b
// Pick a random number j between 0 and sum_played(x,y)
//
// if j is between 0 and p(0) pick i as 0
// if j is between p(0) and p(1) pick i as 1
// Generalizing
// if j is between p(k-1) and p(k) i = k.


//#include "ai/aisuitlengthsolver.h"
//#include "SFMT.h"
//#include "SFMT-params.h"

////#define slLOG_DEBUG_SETPROBLEM 0
////#define slLOG_DEBUG_SETCELL 0
////#define slLOG_DEBUG_RECALCCELL_MAX 0
////#define slLOG_DEBUG_RECALCCELL_MIN 0
////#define slLOG_DEBUG_GETRANDSOLN 0
////#define slLOG_DEBUG_SETIMPCELLS 0
////#define slLOG_DEBUG_GENRANDFILL 0

// The probability of a hand of 8 cards to get 0 to 8 cards of the same suit
static final int SL_SUIT_LEN_PROBS[] = {699230, 2632395, 3582982, 2262936, 707167, 107759, 7347, 183, 1};
//static final int SL_SUIT_LEN_TOTAL_PROB = 10000000;


aiSuitLengthSolver.aiSuitLengthSolver()
{
  return;
}
aiSuitLengthSolver.~aiSuitLengthSolver()
{
  return;
}

void aiSuitLengthSolver.InitializeProblem(slProblem *problem)
{
    int i = 0;
    int j = 0;

    // Problem is initialized by setting suit lengths for all spots as vacant
    // and setting the total length for all hands and suits as zero.

    memset(problem, 0, sizeof(slProblem));
    for(i = 0; i < slTOTAL_HANDS; i++)
    {
        for(j = 0; j < slTOTAL_SUITS; j++)
        {
            problem.suit_length[i][j] = slVACANT;
        }
    }

    return;
}

void aiSuitLengthSolver.InitializePlayed(slPlayed played)
{
    // Played is initialized by setting suit lengths for all spots as zero
    // and setting the total length for all hands and suits also as zero.

    memset(played, 0, sizeof(slPlayed));

    return;
}

void aiSuitLengthSolver.InitializeWorkingData(slData *data)
{
    int i = 0;
    int j = 0;

    // Problem is initialized by setting suit lengths for all spots as vacant
    // and setting the total length for all hands and suits as zero.

    memset(data, 0, sizeof(slData));
    for(i = 0; i < slTOTAL_HANDS; i++)
    {
        for(j = 0; j < slTOTAL_SUITS; j++)
        {
            data.cells[i][j].suit_length = slVACANT;
        }
    }

    return;
}


boolean aiSuitLengthSolver.SetProblem(slProblem *problem, slPlayed played)
{
    int i = 0;
    int j = 0;
    int hand_total_played[slTOTAL_HANDS] = {0, 0, 0, 0};
    int suit_total_played[slTOTAL_SUITS] = {0, 0, 0, 0};

    if(problem == null)
    {
        .wxLogError(String.Format(("Input variable problem for aiSuitLengthSolver.SetProblem is null. %s:%d"),
                                    (__FILE__), __LINE__));
        return false;
    }
    if(played == null)
    {
        .wxLogError(String.Format(("Input variable played for aiSuitLengthSolver.SetProblem is null. %s:%d"),
                                    (__FILE__), __LINE__));
        return false;
    }

  InitializeWorkingData(&m_saved);

  // Create a copy of the problem

  memcpy(&m_problem, problem, sizeof(slProblem));
  memcpy(m_played, played, sizeof(slPlayed));

  // Check the sanity of data.
  // The array played contains the list of played cards.
  // The hand_total_length and suit_total_length arrays in problem contain the list of cards to be allocatd.
  // Both added together for should be 8

    for(i = 0; i < slTOTAL_HANDS; i++)
    {
        for(j = 0; j < slTOTAL_SUITS; j++)
        {
            hand_total_played[i] += m_played[i][j];
            suit_total_played[j] += m_played[i][j];
        }
    }

    //wxLogDebug(PrintMatrix(m_played));
    for(i = 0; i < slTOTAL_HANDS; i++)
    {
        if((hand_total_played[i] + m_problem.hand_total_length[i]) != slLENGTH_MAX)
        {
            .wxLogError(String.Format(("No of played cards and the cards to be set does not add up to slLENGTH_MAX for hand %d. %s:%d"),
                                        i, (__FILE__), __LINE__));
            .wxLogError(String.Format(("hand_total_played[%d] = %d"), i , hand_total_played[i]));
            .wxLogError(String.Format(("m_problem.hand_total_length[%d] = %d"), i , m_problem.hand_total_length[i]));
            assert(false);
            return false;
        }
    }

    for(i = 0; i < slTOTAL_SUITS; i++)
    {
        if((suit_total_played[i] + m_problem.suit_total_length[i]) != slLENGTH_MAX)
        {
            .wxLogError(String.Format(("No of played cards and the cards to be set does not add up to slLENGTH_MAX for suit %d. %s:%d"),
                                        i, (__FILE__), __LINE__));
            .wxLogError(String.Format(("suit_total_played[%d] = %d"), i , suit_total_played[i]));
            .wxLogError(String.Format(("m_problem.suit_total_length[%d] = %d"), i , m_problem.suit_total_length[i]));
            assert(false);
            return false;
        }
    }

  // Copy the status of each cell (which must be zero to slLENGTH_MAX or slVACANT)

  for(i = 0; i < slTOTAL_HANDS; i++)
  {
      for(j = 0; j < slTOTAL_SUITS; j++)
      {
          assert((m_problem.suit_length[i][j] == slVACANT) ||
                  ((m_problem.suit_length[i][j] >= 0) && (m_problem.suit_length[i][j] <= slLENGTH_MAX)));

            //SetCell(&m_saved, i, j, m_problem.suit_length[i][j]);
          m_saved.cells[i][j].suit_length = m_problem.suit_length[i][j];

          // If the suit length for the cell is fixed already
          // set max and min as the fixed value.

          if (m_problem.suit_length[i][j] != slVACANT)
          {
              m_saved.cells[i][j].max = m_problem.suit_length[i][j];
              m_saved.cells[i][j].min = m_problem.suit_length[i][j];

              // Adjust the sum of maxes
              m_saved.hand_sum_of_maxs[i] += m_saved.cells[i][j].max;
              m_saved.suit_sum_of_maxs[j] += m_saved.cells[i][j].max;

              // Adjust allocated cards
              m_saved.hand_allocated[i] += m_problem.suit_length[i][j];
              m_saved.suit_allocated[j] += m_problem.suit_length[i][j];
          }

      }
  }

  // Calc max for each cell
  // Zero or -1 will not affect alloc
  // Calculate sum of maxes
  // Calculate min

    memcpy(&(m_saved.hand_total_length), &(m_problem.hand_total_length), sizeof(m_saved.hand_total_length));
    memcpy(&(m_saved.suit_total_length), &(m_problem.suit_total_length), sizeof(m_saved.suit_total_length));

    // Calculate max for all cells
    // This also calculates the sum of maxes for all hands and suits internally

    RecalcMaxForAllCells(&m_saved);

    // Calculate min for all cells
    // TODO: Is this required?

    //RecalcMinForAllCells(&m_saved);

  for(i = 0; i < slTOTAL_HANDS; i++)
  {
      for(j = 0; j < slTOTAL_SUITS; j++)
      {
          RecalcMinForImpactedCells(&m_saved, i, j);
      }

    }

    // Calcualte max for all cells. This is done again because mins would have changed.

    //RecalcMaxForAllCells(&m_saved);
    //RecalcMinForAllCells(&m_saved);
    return true;
}

boolean aiSuitLengthSolver.RecalcCellMax(slData *data, int hand, int suit)
{
    int old_max = 0;
    int new_max = 0;

    assert(data != null);
    assert(hand < slTOTAL_HANDS);
    assert(suit < slTOTAL_SUITS);
    assert(data.cells[hand][suit].suit_length == slVACANT);

    int h = (data.hand_total_length[hand] - data.hand_allocated[hand] - data.hand_sum_of_vacant_mins[hand]
             + data.cells[hand][suit].min);
    assert(h >= 0);
    int s = (data.suit_total_length[suit] - data.suit_allocated[suit] - data.suit_sum_of_vacant_mins[suit]
             + data.cells[hand][suit].min);
    assert(s >= 0);

    // Store the old max value

    old_max = data.cells[hand][suit].max;

    // Compute the new max value

    new_max = std.min(h, s);
    assert((new_max <= old_max) || (old_max == 0));

    data.cells[hand][suit].max = new_max;

    // If the new max value is different from the older one,
    // then the sum of max values for the hand and the suit has to be corrected

    if(new_max != old_max)
    {
        data.hand_sum_of_maxs[hand] -= (old_max - new_max);
        data.suit_sum_of_maxs[suit] -= (old_max - new_max);
        return true;
    }

    return false;
}

boolean aiSuitLengthSolver.SetCell(slData *data, int hand, int suit, int val)
{

//#ifdef slLOG_DEBUG_SETCELL
    wxLogDebug(String.Format(("Entering aiSuitLengthSolver.SetCell (%d, %d) = %d"), hand, suit, val));
//#endif

    assert(data != null);
    assert(hand < slTOTAL_HANDS);
    assert(suit < slTOTAL_SUITS);

    assert((val >= 0) || (val <= slLENGTH_MAX));

    // SetCell should be recalculated only for vacant slots

    assert(data.cells[hand][suit].suit_length == slVACANT);

    // Fix the suit length for the cell

    data.cells[hand][suit].suit_length = val;

    // As the max value for the cell is changing, correct the sum of maxes beforehand

    data.hand_sum_of_maxs[hand] -= (data.cells[hand][suit].max - val);
    data.suit_sum_of_maxs[suit] -= (data.cells[hand][suit].max - val);

    // As the min value for the cell is changing, correct the sum of mins beforehand

    if(data.cells[hand][suit].min > 0)
    {
        data.hand_sum_of_vacant_mins[hand] -= data.cells[hand][suit].min;
        data.suit_sum_of_vacant_mins[suit] -= data.cells[hand][suit].min;
    }

    // Fix the max and min as the same as the suit length

    data.cells[hand][suit].max = val;
    data.cells[hand][suit].min = val;

    // val number of cards have been allocated from the hand and from the suit

    data.hand_allocated[hand] += val;
    data.suit_allocated[suit] += val;
    assert(data.hand_allocated[hand] <= data.hand_total_length[hand]);
    assert(data.suit_allocated[suit] <= data.suit_total_length[suit]);

    // Recalculate the max for all the affected cells

    RecalcMaxForImpactedCells(data, hand, suit);
    RecalcMinForImpactedCells(data, hand, suit);

    // Recalculate the min for all the cells

    //RecalcMinForAllCells(data);

    // Calcualte max for all cells. This is done again because mins would have changed.

    //RecalcMaxForAllCells(data);
    //RecalcMinForAllCells(data);

    return true;
}

boolean aiSuitLengthSolver.RecalcMaxForImpactedCells(slData *data, int hand, int suit)
{
    int i = 0;

    assert(data != null);
    assert(hand < slTOTAL_HANDS);
    assert(suit < slTOTAL_SUITS);

//#ifdef slLOG_DEBUG_SETIMPCELLS

    .wxLogDebug(String.Format(("Entering aiSuitLengthSolver.RecalcMaxForImpactedCells for (%d, %d)"), hand, suit));
    .wxLogDebug(String.Format(("Data : %s"), PrintData(data).c_str()));

//#endif

    // Recalculate the max for all the affected cells
    // Recalculate the max for all cell in hand


    for(i = 0; i < slTOTAL_SUITS; i++)
    {
        // Avoid recalculating for the cell for which data is being set
        // and for non-vacant cells.

        //if((i != suit) && (data.cells[hand][i].suit_length == slVACANT))
        if(data.cells[hand][i].suit_length == slVACANT)
        {
            if(RecalcCellMax(data, hand, i) == true)
            {
                RecalcMinForImpactedCells(data, hand, i);
            }
        }
    }
    // Recalculate the max for all cell in suit

    for(i = 0; i < slTOTAL_HANDS; i++)
    {
        // Avoid recalculating for the cell for which data is being set
        // and for non-vacant cells.

        //if((i != hand) && (data.cells[i][suit].suit_length == slVACANT))
        if(data.cells[i][suit].suit_length == slVACANT)
        {
            if(RecalcCellMax(data, i, suit) == true)
            {
                RecalcMinForImpactedCells(data, i, suit);
            }
        }
    }
    return true;
}

boolean aiSuitLengthSolver.RecalcMinForImpactedCells(slData *data, int hand, int suit)
{
    int i = 0;

    assert(data != null);
    assert(hand < slTOTAL_HANDS);
    assert(suit < slTOTAL_SUITS);

//#ifdef slLOG_DEBUG_SETIMPCELLS

    .wxLogDebug(String.Format(("Entering aiSuitLengthSolver.RecalcMinForImpactedCells for (%d, %d)"), hand, suit));
    .wxLogDebug(String.Format(("Data : %s"), PrintData(data).c_str()));

//#endif

    // Recalculate the min for all the affected cells
    // Recalculate the min for all cell in hand

    for(i = 0; i < slTOTAL_SUITS; i++)
    {
        // Avoid recalculating for the cell for which data is being set
        // and for non-vacant cells.

        //if((i != suit) && (data.cells[hand][i].suit_length == slVACANT))
        if(data.cells[hand][i].suit_length == slVACANT)
        {
            if(RecalcCellMin(data, hand, i) == true)
            {
                RecalcMaxForImpactedCells(data, hand, i);
            }
        }
    }
    // Recalculate the max for all cell in suit

    for(i = 0; i < slTOTAL_HANDS; i++)
    {
        // Avoid recalculating for the cell for which data is being set
        // and for non-vacant cells.

        //if((i != hand) && (data.cells[i][suit].suit_length == slVACANT))
        if(data.cells[i][suit].suit_length == slVACANT)
        {
            if(RecalcCellMin(data, i, suit) == true)
            {
                RecalcMaxForImpactedCells(data, i, suit);
            }
        }
    }
    return true;
}
boolean aiSuitLengthSolver.RecalcCellMin(slData *data, int hand, int suit)
{
    int i = 0;
    int j = 0;
    int old_min = 0;
    int new_min = 0;

    assert(data != null);
    assert(hand < slTOTAL_HANDS);
    assert(suit < slTOTAL_SUITS);
    assert(data.cells[hand][suit].suit_length == slVACANT);

//  min(c(x,y)) = MAX(
//                       (sum(h(x)) - sum_max(h(x)) + max(c(x,y))),
//                       (sum(s(y)) - sum_max(s(y)) + max(c(x,y)))

//                   )
//
//  If min(c(x,y)) is negative, set this as zero.

    i = data.hand_total_length[hand] - data.hand_sum_of_maxs[hand] + data.cells[hand][suit].max;
    if(i < 0)
    {
        i = 0;
    }

    j = data.suit_total_length[suit] - data.suit_sum_of_maxs[suit] + data.cells[hand][suit].max;
    if(j < 0)
    {
        j = 0;
    }

    old_min = data.cells[hand][suit].min;
    new_min = std.max(i, j);

    // The new minimum should be equal to or more than the old minimum

    assert(new_min >= old_min);

    data.cells[hand][suit].min = new_min;

    // If the new min is different from the old min, correct the sum of vacant mins

    if(new_min != old_min)
    {
        data.hand_sum_of_vacant_mins[hand] += (new_min - old_min);
        data.suit_sum_of_vacant_mins[suit] += (new_min - old_min);
        return true;
    }

    return false;
}
boolean aiSuitLengthSolver.RecalcMinForAllCells(slData *data, boolean * changed)
{
    int i = 0;
    int j = 0;

    assert(data != null);

    // Reset the sum of min values for all hands and suits
    //memset(data.hand_sum_of_vacant_mins, 0, sizeof(data.hand_sum_of_vacant_mins));
    //memset(data.suit_sum_of_vacant_mins, 0, sizeof(data.suit_sum_of_vacant_mins));

    // Calculate min for all cells
    // At the same time, calculate the sum of mins for the hand

  for(i = 0; i < slTOTAL_HANDS; i++)
  {
      for(j = 0; j < slTOTAL_SUITS; j++)
      {
          // If the suit length for a cell is fixed, then min
          // has already been calculated.

          if(data.cells[i][j].suit_length == slVACANT)
          {
                RecalcCellMin(data, i, j);
                assert((data.cells[i][j].min >= 0) && (data.cells[i][j].min <= slLENGTH_MAX));

                // If the min for a vacant cell is not zero, add that to the sum of mins for vacant cells

                //if(data.cells[i][j].min > 0)
                //{
                //    data.hand_sum_of_vacant_mins[i] += data.cells[i][j].min;
                //    data.suit_sum_of_vacant_mins[j] += data.cells[i][j].min;
                //}
          }

      }
  }
  return true;
}

boolean aiSuitLengthSolver.RecalcMaxForAllCells(slData *data)
{
    int i = 0;
    int j = 0;

    assert(data != null);

    // Calculate max for each cell
    // This also calculates the sum of maxes for all hands and suits internally

  for(i = 0; i < slTOTAL_HANDS; i++)
  {
      for(j = 0; j < slTOTAL_SUITS; j++)
      {
          // If the suit length for a cell is fixed, then max
          // has already been calculated.

          if(data.cells[i][j].suit_length == slVACANT)
          {
                RecalcCellMax(data, i, j);

          }
      }
  }

    return true;
}

// This method picks a value between min and max, both inclusive, to fill a vacant slot.
// However, the probability of a slot to be filled with min is different from probabilityof a slot to be filled with max.
// Hence the relative probability is computed and stored in SL_SUIT_LEN_PROBS and this is used

int aiSuitLengthSolver.GenerateRandomFill(int min, int max)
{
    assert(min >= 0);
    assert(min < max);
    assert(max <= slLENGTH_MAX);

    int i = 0;
    int total = 0;
    int cumul[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
    int rand_val = 0;

    for(i = min; i <= max; i++)
    {
        total += SL_SUIT_LEN_PROBS[i];
        cumul[i] = total;
    }


    rand_val = (gen_rand32() % (total + 1));

//#ifdef slLOG_DEBUG_GENRANDFILL
    wxLogDebug(String.Format(("min = %d"), min));
    wxLogDebug(String.Format(("max = %d"), max));
    for(i = min; i <= max; i++)
    {
        wxLogDebug(String.Format(("cumul[%d] = %u"), i, cumul[i]));
    }
    wxLogDebug(String.Format(("total = %u"), total));
    wxLogDebug(String.Format(("rand_val = %u"), rand_val));
//#endif
    for(i = min; i <= max; i++)
    {
        if(rand_val <= cumul[i])
        {
//#ifdef slLOG_DEBUG_GENRANDFILL
            wxLogDebug(String.Format(("GenerateRandomFill returns %d"), i));
//#endif
            return i;
        }
    }
    assert_MSG(false, ("Control should not reach here"));
    return -1;

}

boolean aiSuitLengthSolver.GenerateRandomSolution(slSolution solution)
{
  int i = 0;
  int j = 0;
    int fill = 0;

    if(solution == null)
    {
        return false;
    }

  memcpy(&m_working, &m_saved, sizeof(slData));
//#ifdef slLOG_DEBUG_GETRANDSOLN
    wxLogDebug(("Problem :"));
    wxLogDebug(PrintData(&m_working));
//#endif

  for(i = 0; i < slTOTAL_HANDS; i++)
  {
      for(j = 0; j < slTOTAL_SUITS; j++)
      {
          // Fill only if the cell is vacant

            if(m_working.cells[i][j].suit_length == slVACANT)
            {
                // In a vacant cell, if max and min are the same, then that is the only option.
                // No need to try to get a random number.

                if(m_working.cells[i][j].max == m_working.cells[i][j].min)
                {
                    fill = m_working.cells[i][j].max;
                }
                else
                {
                    //fill = m_working.cells[i][j].min + (gen_rand32() % (m_working.cells[i][j].max - m_working.cells[i][j].min + 1));
                    fill = GenerateRandomFill(m_working.cells[i][j].min, m_working.cells[i][j].max);
                }
//#ifdef slLOG_DEBUG_GETRANDSOLN
                .wxLogDebug(String.Format(("Attempting to fill (%d, %d) with %d"), i, j, fill));
//#endif
                SetCell(&m_working, i, j, fill);
//#ifdef slLOG_DEBUG_GETRANDSOLN
                .wxLogDebug(PrintData(&m_working));
//#endif
            }
      }
  }

    // Set the solution

  for(i = 0; i < slTOTAL_HANDS; i++)
  {
      for(j = 0; j < slTOTAL_SUITS; j++)
      {
            solution[i][j] = m_working.cells[i][j].suit_length;
      }
  }

//#ifdef slLOG_DEBUG_GETRANDSOLN
    .wxLogDebug(PrintMatrix(solution));
//#endif
    return true;
}

String aiSuitLengthSolver.PrintSavedData()
{
    return aiSuitLengthSolver.PrintData(&m_saved);
}

String aiSuitLengthSolver.PrintWorkingData()
{
    return aiSuitLengthSolver.PrintData(&m_working);
}

String aiSuitLengthSolver.PrintData(slData *data)
{
  String out;
  int i = 0;
  int j = 0;

  out.Empty();
  // Debug log output text is prefixed with "Debug :". Hence add a new line so that the first line is
  // aligned with the rest
  out.Append(("\n"));
  if(!data)
  {
    .wxLogError(String.Format(("Input variable data is null. %s:%d"),
      (__FILE__), __LINE__));
    return out;
  }

  // Print the header or the table
  // S1    |S2    |S3    |S4
  // ------+------+------+------

  out.Append(("       "));
  for(i = 0; i < slTOTAL_SUITS; i++)
  {
    out.Append(String.Format(("S%d    |"), i + 1));
    }

    out.Append(("TotLen|Allocd|SumMax|SumMin"));
    out.Append(("\n"));
    out.Append(("------+------+------+------+------+------+------+------+------\n"));

    // Print the rest of the table

    for(i = 0; i < slTOTAL_HANDS; i++)
    {
        // Print the first column
        // H1    |
        // ------+
        // H2    |

        out.Append(String.Format(("H%d    |"), i));

        // Print cells for each hand in the format <suit_length>(<min>, <max>)

        for(j = 0; j < slTOTAL_SUITS; j++)
        {
            // If the cell is vacant, an "x" is printed instead of the numberic value of slVACANT

            if(data.cells[i][j].suit_length == slVACANT)
            {
                out.Append(("x"));
            }
            else
            {
                out.Append(String.Format(("%d"), data.cells[i][j].suit_length));
            }
            out.Append(String.Format(("(%d,%d)|"),
                                        data.cells[i][j].min, data.cells[i][j].max
                                        ));
        }

        // Print data for the following columns
        // TotLen|Allocd|SumMax

        out.Append(String.Format(("%6d|"), data.hand_total_length[i]));
        out.Append(String.Format(("%6d|"), data.hand_allocated[i]));
        out.Append(String.Format(("%6d|"), data.hand_sum_of_maxs[i]));
        out.Append(String.Format(("%6d"), data.hand_sum_of_vacant_mins[i]));
        out.Append(("\n"));
        out.Append(("------+------+------+------+------+------+------+------+------\n"));

    }

    // Print data for the following rows
    // TotLen|...
    // ------+...
    // Allocd|...
    // ------+...
    // SumMax|...
    // ------+...
    // SumMin|...

    out.Append(("TotLen|"));
    for(i = 0; i < slTOTAL_SUITS; i++)
    {
        out.Append(String.Format(("%6d|"), data.suit_total_length[i]));
    }
    out.Append(("\n"));
    out.Append(("------+------+------+------+------+\n"));

    out.Append(("Allocd|"));
    for(i = 0; i < slTOTAL_SUITS; i++)
    {
        out.Append(String.Format(("%6d|"), data.suit_allocated[i]));
    }
    out.Append(("\n"));
    out.Append(("------+------+------+------+------+\n"));

    out.Append(("SumMax|"));
    for(i = 0; i < slTOTAL_SUITS; i++)
    {
        out.Append(String.Format(("%6d|"), data.suit_sum_of_maxs[i]));
    }
    out.Append(("\n"));
    out.Append(("------+------+------+------+------+\n"));

    out.Append(("SumMin|"));
    for(i = 0; i < slTOTAL_SUITS; i++)
    {
        out.Append(String.Format(("%6d|"), data.suit_sum_of_vacant_mins[i]));
    }
    out.Append(("\n"));

    return out;
}

String aiSuitLengthSolver.PrintMatrix(slMatrix matrix)
{
    String out;
  int i = 0;
  int j = 0;

  out.Empty();
  out.Append(("\n"));

  if(!matrix)
  {
    .wxLogError(String.Format(("Input variable matrix is null. %s:%d"),
      (__FILE__), __LINE__));
    return out;
  }

  // Print the header or the table
  // S1|S2|S3|S4
  // --+--+--+--

  out.Append(("   "));
  for(i = 0; i < slTOTAL_SUITS; i++)
  {
    out.Append(String.Format(("S%d"), i + 1));
    if(i != (slTOTAL_SUITS - 1))
    {
        out.Append(("|"));
    }
    }
    out.Append(("\n"));
    out.Append(("--+--+--+--+--\n"));

    for(i = 0; i < slTOTAL_HANDS; i++)
    {
        // Print the first column
        // H1|
        // --+
        // H2|

        out.Append(String.Format(("H%d|"), i));

        // Print cells for each hand in the format <suit_length>(<min>, <max>)

        for(j = 0; j < slTOTAL_SUITS; j++)
        {
            out.Append(String.Format(("%2d"), matrix[i][j]));
            if(j != (slTOTAL_SUITS - 1))
            {
                out.Append(("|"));
            }
        }
        out.Append(("\n"));
        if(i != (slTOTAL_HANDS - 1))
        {
            out.Append(("--+--+--+--+--\n"));
        }

    }

    return out;
}




Java Source Code List

eu.veldsoft.twenty.eight.MainActivity.java
eu.veldsoft.twenty.eight.ai.aiAgent.java
eu.veldsoft.twenty.eight.ai.aiEval.java
eu.veldsoft.twenty.eight.ai.aiMove.java
eu.veldsoft.twenty.eight.ai.aisuitlengthsolver.java
eu.veldsoft.twenty.eight.ai.ut_suitlengthsolver.java
eu.veldsoft.twenty.eight.common.GlobalSpace.java
eu.veldsoft.twenty.eight.gg.ggcard.java
eu.veldsoft.twenty.eight.gg.ggpanel.java
eu.veldsoft.twenty.eight.gm.gmEngineData.java
eu.veldsoft.twenty.eight.gm.gmUtil.java
eu.veldsoft.twenty.eight.gm.gmengine.java
eu.veldsoft.twenty.eight.gm.gmrand.java
eu.veldsoft.twenty.eight.ra.ra.java
eu.veldsoft.twenty.eight.ra.rabid.java
eu.veldsoft.twenty.eight.ra.racommon.java
eu.veldsoft.twenty.eight.ra.raconfig.java
eu.veldsoft.twenty.eight.ra.radlgabout.java
eu.veldsoft.twenty.eight.ra.radlgprefs.java
eu.veldsoft.twenty.eight.ra.radlgrules.java
eu.veldsoft.twenty.eight.ra.raevents.java
eu.veldsoft.twenty.eight.ra.ragamepanel.java
eu.veldsoft.twenty.eight.ra.rainfo.java
eu.veldsoft.twenty.eight.ra.ramain.java
eu.veldsoft.twenty.eight.ra.raplayer.java
eu.veldsoft.twenty.eight.ra.raupdate.java