Skip to content

Commit f1dab6b

Browse files
committed
Fix Atm task implementation to unignore test
1 parent e1c062c commit f1dab6b

2 files changed

Lines changed: 34 additions & 32 deletions

File tree

src/main/java/by/andd3dfx/common/atm/Atm.java

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class Atm {
2222

2323
public Atm(Map<Integer, Integer> state) {
2424
this.state = new HashMap<>(state);
25+
// Порядок важен для backtracking: сначала пробуем крупные номиналы.
2526
this.nominals = state.keySet().stream()
2627
.sorted(Comparator.reverseOrder()).toList();
2728
}
@@ -33,44 +34,48 @@ public Atm(Map<Integer, Integer> state) {
3334
* @return map with solution - pairs {banknote nominal->quantity}
3435
*/
3536
public Map<Integer, Integer> withdraw(int amount) {
36-
// Try to make withdraw using banknote of highest nominal,
37-
// in case of fail - try to start from next nominal
38-
for (int i = 0; i < nominals.size(); i++) {
39-
try {
40-
return withdraw(amount, i);
41-
} catch (IllegalStateException ex) {
42-
// do nothing
43-
}
37+
if (amount == 0) {
38+
return Map.of();
39+
}
40+
41+
// Перебор всех комбинаций (не жадный): для каждого номинала пробуем 0..max купюр.
42+
var result = new HashMap<Integer, Integer>();
43+
if (findSolution(amount, 0, result)) {
44+
mutateAtm(result);
45+
return result;
4446
}
4547

4648
throw new IllegalStateException("Could not perform withdraw!");
4749
}
4850

49-
private Map<Integer, Integer> withdraw(int amount, int nominalIndex) {
50-
var result = new HashMap<Integer, Integer>();
51+
/**
52+
* Рекурсивный поиск комбинации купюр для {@code amount}, начиная с номинала {@code index}.
53+
* Найденное решение накапливается в {@code result}.
54+
*/
55+
private boolean findSolution(int amount, int index, Map<Integer, Integer> result) {
56+
if (amount == 0) {
57+
return true;
58+
}
59+
if (index >= nominals.size()) {
60+
return false; // купюры закончились, сумма не набрана
61+
}
5162

52-
for (var index = nominalIndex; index < nominals.size(); index++) {
53-
var nominal = nominals.get(index);
54-
if (nominal > amount || state.get(nominal) == 0) {
55-
continue;
63+
var nominal = nominals.get(index);
64+
// Сколько купюр этого номинала можно взять: min(есть в банкомате, amount / nominal).
65+
int maxCount = Math.min(state.get(nominal), amount / nominal);
66+
// От max к 0: сначала варианты с большим числом крупных купюр (см. тесты).
67+
for (int count = maxCount; count >= 0; count--) {
68+
if (count > 0) {
69+
result.put(nominal, count);
5670
}
57-
58-
int count = amount / nominal;
59-
count = Math.min(count, state.get(nominal));
60-
result.put(nominal, count);
61-
amount -= nominal * count;
62-
63-
if (amount == 0) {
64-
break;
71+
if (findSolution(amount - nominal * count, index + 1, result)) {
72+
return true;
73+
}
74+
if (count > 0) {
75+
result.remove(nominal); // backtrack
6576
}
6677
}
67-
68-
if (amount > 0) {
69-
throw new IllegalStateException("Could not perform withdraw!");
70-
}
71-
72-
mutateAtm(result);
73-
return result;
78+
return false;
7479
}
7580

7681
private void mutateAtm(Map<Integer, Integer> result) {

src/test/java/by/andd3dfx/common/atm/AtmTest.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package by.andd3dfx.common.atm;
22

33
import org.junit.Before;
4-
import org.junit.Ignore;
54
import org.junit.Test;
65

76
import java.util.Map;
@@ -81,8 +80,6 @@ public void withdrawForConsequentCalls() {
8180
));
8281
}
8382

84-
// TODO: fix implementation to make this test passed
85-
@Ignore
8683
@Test
8784
public void withdraw_vsGreedyAlgorithm() {
8885
var atm2 = buildAtm(Map.of(

0 commit comments

Comments
 (0)