Coin Exchange Algorithm

I am creating a poker game. In my application, I have a ChipSet class. A ChipSet is basically an array of 5 thets (one for each poker chip in poker).

 public class ChipSet { public static final int WHITE_VALUE = 1; public static final int RED_VALUE = 2; public static final int GREEN_VALUE = 5; public static final int BLUE_VALUE = 10; public static final int BLACK_VALUE = 20; public static final int[] VALUES = new int[]{WHITE_VALUE, RED_VALUE, GREEN_VALUE, BLUE_VALUE, BLACK_VALUE}; protected int[] chips; public ChipSet(int[] chips) { if (chips == null || chips.length != 5) throw new IllegalArgumentException("ChipSets should contain exactly 5 integers!"); // store a copy of passed array this.chips = new int[5]; for (int i = 0; i < this.chips.length; i++) { this.chips[i] = chips[i]; } } public int getSum() { return chips[0] * WHITE_VALUE + chips[1] * RED_VALUE + chips[2] * GREEN_VALUE + chips[3] * BLUE_VALUE + chips[4] * BLACK_VALUE; } } 

Now, if I have, for example, a ChipSet with an array of [0,0,2,1,0] (5 + 5 + 10 = 20), and I want to use my ChipSet to pay for something that costs 16 units. I would have to exchange chips to make this possible.

I need an algorithm that exchanges as efficiently as possible (exchange as many chips as possible) to make such a payment possible. A payment will simply deduct the number of chips from the array so that the balances are still in the ChipSet after payment. How can I do it?

I need a method like this:

 public boolean exchangeToMakeAvailable(int goal) { // algorithm to exchange chips as efficient as possible // store the new values in the array, making sure the sum is still the same // return whether it has succeeded (false when the sum is less than the requested amount) } 

I would really appreciate it if you could help me figure this out.

For instance:

Before the algorithm, I have a ChipSet with an array [0,0,2,1,0] that has a sum of 20. I want to pay what costs 16 units. After using the algorithm, I would use the exchange as efficiently as possible, in which case the algorithm would change the array to [1,2,1,1,0] , which also has a sum of 20, but now I can make a payment 16. After payment, ChipSet will have array [0,2,0,0,0] .

I hope that my problem is clear, and if it is not, leave a comment and I will explain further.

+5
source share
2 answers

This is editing, I completely reworked my answer.

** The problem in terms of the game ** The player has 2 green chips (5 points) and 1 blue (10 points). This is 20 points. Now the player wants to buy a game icon that costs 16 points. The player has enough money to buy an item. Thus, the player pays 16 points, but what points will he give the store to pay correctly.

Now I have written a working example with all the work done.

The code

Program.java

 import java.util.Arrays; public class Program { public static void main(String[] args) { // Setting up test environment Player player = new Player("Borrie", new int[]{0,0,0,0, 230}); int itemCost = 16626; // Pay for item System.out.printf("First we check if the player can pay with it current ChipSet"); if (!player.canPayWithChipSet(player.getChips(), 5)) { if (player.exchangeChips(5)) { System.out.printf("\n\nThe players ChipSet:" + Arrays.toString(player.getChips().chips)); System.out.printf("\nThe players ChipSet has been succesfully exchanged."); } else { System.out.printf("\n\nThe players ChipSet:" + Arrays.toString(player.getChips().chips)); System.out.printf("\nThe players ChipSet was not able to be exchanged.\n"); } } else { System.out.printf("\n\nThe player can pay exact with it original ChipSet. No need to exchange."); } } } 

Player.java

  import java.util.ArrayList; import java.util.Arrays; public class Player { private String name; private ChipSet chips; private int points = 0; public Player(String name, int[] chips) { this.name = name; this.chips = new ChipSet(chips); this.points = this.chips.getSum(); } public boolean exchangeChips(int cost) { ChipSet newChipSet = exchangePlayerChipSet(this.chips.getChips(), cost); if (newChipSet == null) { return false; } else { this.chips = newChipSet; return true; } } public ChipSet exchangePlayerChipSet(int[] originalChipValues, int cost) { ChipSet newChipSet = null; // Create possible combinations to compare ArrayList<ChipSet> chipSetCombos = createCombinations(this.chips.getChips()); // Filter the chipset based on if it able to pay without changing chips System.out.printf("\n\n---- Filter which of these combinations are able to be payed with without changing chips ----"); ArrayList<ChipSet> filteredCombos = filterCombinations(chipSetCombos, cost); // Compare the filtered chipsets to determine which one has changed the least if (!filteredCombos.isEmpty()) { newChipSet = compareChipSets(originalChipValues, filteredCombos); } return newChipSet; } private ArrayList<ChipSet> createCombinations(int[] array) { ArrayList<ChipSet> combos = new ArrayList<>(); int[] startCombo = array; System.out.printf("Player has " + getTotalPoints(startCombo) + " points in chips."); System.out.printf("\nPlayer has these chips (WHITE,RED,GREEN,BLUE,BLACK): " + Arrays.toString(startCombo)); while (startCombo[4] != 0) { startCombo = lowerBlack(startCombo); if (getTotalPoints(startCombo) == points) { combos.add(new ChipSet(startCombo)); } } while (startCombo[3] != 0) { startCombo = lowerBlue(startCombo); if (getTotalPoints(startCombo) == points) { combos.add(new ChipSet(startCombo)); } } while (startCombo[2] != 0) { startCombo = lowerGreen(startCombo); if (getTotalPoints(startCombo) == points) { combos.add(new ChipSet(startCombo)); } } while (startCombo[1] != 0) { startCombo = lowerRed(startCombo); if (getTotalPoints(startCombo) == points) { combos.add(new ChipSet(startCombo)); } } System.out.printf("\n\n---- Creating variations on the players chips ----"); System.out.printf("\nVariation (all worth " + getTotalPoints(startCombo) + " points):\n"); int teller = 1; for (ChipSet a : combos) { System.out.printf("\nCombo " + teller + ": " + Arrays.toString(a.getChips())); teller++; } return combos; } private ArrayList<ChipSet> filterCombinations(ArrayList<ChipSet> combinations, int cost) { ArrayList<ChipSet> filteredChipSet = new ArrayList<>(); combinations.stream().filter((cs) -> (canPayWithChipSet(cs, cost))).forEach((cs) -> { filteredChipSet.add(cs); }); return filteredChipSet; } // This method has be worked out public boolean canPayWithChipSet(ChipSet cs, int cost) { ChipSet csOrig = new ChipSet(cs.chips); ChipSet csCopy = new ChipSet(cs.chips); int counterWhite = 0; int counterRed = 0; int counterGreen = 0; int counterBlue = 0; int counterBlack = 0; while (20 <= cost && cost > 0 && csOrig.getChips()[4] != 0) { csOrig.getChips()[4] -= 1; cost -= 20; counterBlack++; } while (10 <= cost && cost > 0 && csOrig.getChips()[3] != 0) { csOrig.getChips()[3] -= 1; cost -= 10; counterBlue++; } while (5 <= cost && cost > 0 && csOrig.getChips()[2] != 0) { csOrig.getChips()[2] -= 1; cost -= 5; counterGreen++; } while (2 <= cost && cost > 0 && csOrig.getChips()[1] != 0) { csOrig.getChips()[1] -= 1; cost -= 2; counterRed++; } while (1 <= cost && cost > 0 && csOrig.getChips()[0] != 0) { csOrig.getChips()[0] -= 1; cost -= 1; counterWhite++; } if (cost == 0){ System.out.printf("\nCombo: %s can pay exact. With %d white, %d red, %d green, %d blue an %d black chips", Arrays.toString(csCopy.chips),counterWhite,counterRed,counterGreen,counterBlue,counterBlack); return true; } else { System.out.printf("\nCombo: %s cannot pay exact.\n\n\n", Arrays.toString(csCopy.chips)); return false; } } private ChipSet compareChipSets(int[] originalChipValues, ArrayList<ChipSet> chipSetCombos) { ChipSet newChipSet; int[] chipSetWaardes = originalChipValues; // originele chipset aantal van kleur int[] chipSetCombosDifferenceValues = new int[chipSetCombos.size()]; int teller = 1; System.out.printf("\n\n---- Calculate differences between players stack and it variations ----"); for (ChipSet cs : chipSetCombos) { int aantalWhite = cs.getChips()[0]; int aantalRed = cs.getChips()[1]; int aantalGreen = cs.getChips()[2]; int aantalBlue = cs.getChips()[3]; int aantalBlack = cs.getChips()[4]; int differenceWhite = Math.abs(chipSetWaardes[0] - aantalWhite); int differenceRed = Math.abs(chipSetWaardes[1] - aantalRed); int differenceGreen = Math.abs(chipSetWaardes[2] - aantalGreen); int differenceBlue = Math.abs(chipSetWaardes[3] - aantalBlue); int differenceBlack = Math.abs(chipSetWaardes[4] - aantalBlack); int totalDifference = differenceWhite + differenceRed + differenceGreen + differenceBlue + differenceBlack; chipSetCombosDifferenceValues[teller - 1] = totalDifference; System.out.printf("\nCombo " + teller + ": " + Arrays.toString(cs.getChips()) + " = " + totalDifference); teller++; } newChipSet = chipSetCombos.get(smallestValueOfArrayIndex(chipSetCombosDifferenceValues)); System.out.printf("\n\nThe least different ChipSet is: " + Arrays.toString(newChipSet.getChips()) + " "); return newChipSet; } private int smallestValueOfArrayIndex(int[] array) { int huidigeWaarde = array[0]; int smallestIndex = 0; for (int j = 1; j < array.length; j++) { if (array[j] < huidigeWaarde) { huidigeWaarde = array[j]; smallestIndex = j; } } return smallestIndex; } private int[] lowerBlack(int[] array) { return new int[]{array[0], array[1], array[2], array[3] + 2, array[4] - 1}; } private int[] lowerBlue(int[] array) { return new int[]{array[0], array[1], array[2] + 2, array[3] - 1, array[4]}; } private int[] lowerGreen(int[] array) { return new int[]{array[0] + 1, array[1] + 2, array[2] - 1, array[3], array[4]}; } private int[] lowerRed(int[] array) { return new int[]{array[0] + 2, array[1] - 1, array[2], array[3], array[4]}; } private int getTotalPoints(int[] array) { return ((array[0] * 1) + (array[1] * 2) + (array[2] * 5) + (array[3] * 10) + (array[4] * 20)); } public String getName() { return this.name; } public int getPoints() { return this.points; } public ChipSet getChips() { return chips; } } 

ChipSet.java

 public class ChipSet { public static final int WHITE_VALUE = 1; public static final int RED_VALUE = 2; public static final int GREEN_VALUE = 5; public static final int BLUE_VALUE = 10; public static final int BLACK_VALUE = 20; public static final int[] VALUES = new int[]{WHITE_VALUE, RED_VALUE, GREEN_VALUE, BLUE_VALUE, BLACK_VALUE}; protected int[] chips; public ChipSet(int[] chips) { if (chips == null || chips.length != 5) { throw new IllegalArgumentException("ChipSets should contain exactly 5 integers!"); } // store a copy of passed array this.chips = new int[5]; for (int i = 0; i < this.chips.length; i++) { this.chips[i] = chips[i]; } } public int getSum() { return chips[0] * WHITE_VALUE + chips[1] * RED_VALUE + chips[2] * GREEN_VALUE + chips[3] * BLUE_VALUE + chips[4] * BLACK_VALUE; } public int[] getChips() { return this.chips; } } 

Some explanation:

  • Creating combinations

We are creating some subtopics for trading a chip for a lower chip. So for example, black = 2 blues. Then we create 5 loops in order. the first ones check if there are still black chips, if so reduce 1 black add 2 blues. Save this new combination in the list if the amount of chips in the new ChipSet is equal to the original ChipSets value. the loop continues until there are no blacks. Then check if there are blues and repeat the same process until there is no red color anymore. Now we have a list with all possible variations of the value of X in Chips.

  • Filter Combinations

You filter ChipSets based on if you can pay X points without exchanging them. We go through all the possible combinations of ChipSets created in the previous part. if you can pay using ChipSet without exchange, add it to the filterList from ChipSets. The result is a submitted list with valid ChipSets.

  • Calculate the difference

For each ChipSet, we count the number of chips of all colors in the ChipSet and subtract the original number of chipset chips. You take the absolute value of this and make up the sum of all these differences between the original and the color of the combo. Now we have a number that is a difference from the original. Now we all need you to compare all the numbers of ChifSets. The one with the smallest difference that we use to assign to the player.

Simple huh

+2
source

You can try binpacking. Sort the chips and choose the best fit. Then calculate how much is left and either trick the chip, or rinse and repeat.

0
source

Source: https://habr.com/ru/post/1209899/


All Articles