Sagor Ahmed Sagor Ahmed - 1 month ago 7
Java Question

My code is showing error

I want to implement the following algorithm :


  1. If there are less than
    Config.MAX_ACTION
    sticks remaining
    then the chooser must pick the minimum number of sticks (
    Config.MIN_ACTION
    ).

  2. For
    Config.MAX_ACTION
    or more sticks remaining then pick based on the
    actionRanking
    parameter.

  3. The
    actionRanking
    array has one element for each possible action. The
    0

    index corresponds to
    Config.MIN_ACTION
    and the highest index corresponds
    to
    Config.MAX_ACTION
    .

  4. For example, if
    Config.MIN_ACTION
    is
    1
    and
    Config.MAX_ACTION
    is
    3
    , an
    action can be to pick up 1, 2 or 3 sticks.

  5. actionRanking[0]
    corresponds to
    1
    ,
    actionRanking[1]
    corresponds to
    2
    , etc. The higher the element for an action in comparison to other elements, the more likely the action should be chosen.

  6. First calculate the total number of possibilities by summing all the element values. Then choose a particular action based on the relative frequency of the various rankings.

  7. For example, if
    Config.MIN_ACTION
    is
    1
    and
    Config.MAX_ACTION
    is 3: If the action rankings are
    {9,90,1}
    the total is
    100
    . Since
    actionRanking[0]
    is
    9
    , then an action of picking up 1 should be chosen about 9/100 times. 2 should be chosen about 90/100 times and 1 should be chosen about 1/100 times.

  8. Use
    Config.RNG.nextInt(?)
    method to generate appropriate random numbers.

  9. sticksRemaining
    means The number of sticks remaining to be picked up.

  10. actionRanking
    : The counts of each action to take. The
    0
    index corresponds to
    Config.MIN_ACTION
    and the highest index corresponds to
    Config.MAX_ACTION
    .

  11. return The number of sticks to pick up.
    0
    is returned for the following conditions:
    actionRanking
    is
    null
    ,
    actionRanking
    has a length of
    0
    , or
    sticksRemaining
    is
    <= 0
    .



I have written the code as follows :

static int aiChooseAction(int sticksRemaining, int[] actionRanking) {
if(actionRanking == null || actionRanking.length == 0 || sticksRemaining <= 0)
return 0 ;
else if(sticksRemaining < Config.MAX_ACTION)
return Config.MIN_ACTION; //TODO change to appropriate value
else
{
int max = Integer.MIN_VALUE;
int index = 0 ;
for(int i = 0; i < actionRanking.length; i++) {
if(actionRanking[i] >= max) {
max = actionRanking[i];
index = i ;
}
}
if(sticksRemaining<max)
return index+1;
else
return Config.RNG.nextInt(Config.MAX_ACTION)+Config.MIN_ACTION;
}
}


The code for testing this function is as follows :

private static void testAiChooseAction() {
boolean error = false;

// 1.
int action = Sticks.aiChooseAction(0, null);
if (action != 0) {
error = true;
System.out.println("testAiChooseAction 1: for 0 sticks or null "
+ "actionRanking, response should be 0.");
}

// 2.
int[] actionRanking = new int[] { 1, 100, 0 };
action = Sticks.aiChooseAction(-5, actionRanking);
if (action != 0) {
error = true;
System.out.println("testAiChooseAction 2: for negative sticks,"
+ " response should be 0.");
}

// 3.
action = Sticks.aiChooseAction(10, actionRanking);
if (action < Config.MIN_ACTION || action > Config.MAX_ACTION) {
error = true;
System.out.println("testAiChooseAction 3: invalid action "
+ action);
}

// 4.
// create and initialize to 0 an action ranking array
actionRanking = new int[NUM_ACTIONS];

// set the highest index to the highest ranking
// so we expect the MAX_ACTION to be chosen
actionRanking[actionRanking.length - 1] = 100;

action = Sticks.aiChooseAction(10, actionRanking);

if (action != Config.MAX_ACTION) {
error = true;
System.out.println("testAiChooseAction 4: expected "
+ Config.MAX_ACTION + " rather than " + action);
}

// 5.
actionRanking = new int[] { 1, 6, 3 }; // test for 3 actions
int[] responses = new int[actionRanking.length];

// set seed to get repeatable "random" values
Config.RNG.setSeed(123);

// call a bunch of times so there is reasonable chance of seeing the
// expected distribution.
for (int i = 0; i < 10000; i++) {
action = Sticks.aiChooseAction(10, actionRanking);
responses[action - Config.MIN_ACTION]++;
}
if (responses[0] != 1037 || responses[1] != 5819
|| responses[2] != 3144) {
error = true;
System.out.println("testAiChooseAction 5: for seed 123 "
+ "responses were expected to be [1037, 5819, 3144] "
+ " but found " + Arrays.toString(responses));

}

// can you think of other tests that would be useful?
// if so, then you can add them.

if (error) {
System.out.println("testAiChooseAction: failed");
} else {
System.out.println("testAiChooseAction: passed");
}
}


But it does not pass in test .The error is as follows :

testAiChooseAction 5: for seed 123 responses were expected to be [1037, 5819, 3144] but found [3327, 3370, 3303]
testAiChooseAction: failed


How can I solve the error ? Please help me .

Answer

The key is item 7:

For example, if Config.MIN_ACTION is 1 and Config.MAX_ACTION is 3: If the action rankings are {9,90,1} the total is 100. Since actionRanking[0] is 9, then an action of picking up 1 should be chosen about 9/100 times. 2 should be chosen about 90/100 times and 1 should be chosen about 1/100 times.

Here's how that example should be implemented:

  • First generate a random number between 0 and 99 inclusive (100 possible values).

  • If the random number is less than 9, then return 1. Otherwise subtract 9 from the random number.

  • If the adjusted random number is less than 90, then return 2. Otherwise subtract 90 from the adjusted random number.

  • The only possibility left is that the adjusted random number is 0, which is less than 1, so return 3.

In general, the pseudocode for the AI function (after the special cases at the beginning) should look like this:

compute the 'sum' of the entries in the 'actionRanking' array
generate a random number `R` between '0' and 'sum-1' inclusive
for each entry in 'actionRanking'
   if the entry is greater than 'R'
      return 'Config.MIN_ACTION' + the index for that entry
   otherwise
      subtract the entry from 'R'