import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
class DeckGame {
/*
* Wraps the game state, trivial wrapper of an array of 5 elements, in
* 0..13, sum 13 Eg: n=[5,3,0,4,1] says that 5 numbers have not yet
* appeared, 3 numbers have appeared one, 4 numbers has appear three times,
* and 1 number has appeared 4 times
*/
static class DeckState {
final int[] n = new int[5]; // 0-13, must sum 13
public DeckState(int[] nn) {
System.
arraycopy(nn,
0, n,
0,
5); // deep copy }
@Override
public int hashCode() {
}
@Override
public boolean equals
(Object obj
) { if (this == obj) return true;
else if (obj == null || getClass() != obj.getClass()) return false;
else return Arrays.
equals(n,
((DeckState
) obj
).
n); }
}
/*
* Adds to DeckState the (total or partial) probability of reach that state
*/
static class DeckStateFull {
public static final int MAX_ODD = 7;
final double prob;
final DeckState ds;
public DeckStateFull(DeckState d, double p) {
this.ds = d;
this.prob = p;
}
public static DeckStateFull combin(DeckStateFull d1, DeckStateFull d2) {
if (d1 == null)
return d2 == null ? null : new DeckStateFull(d2.ds, d2.prob);
else if (d2 == null)
return new DeckStateFull(d1.ds, d1.prob);
else
return new DeckStateFull(d1.ds, d2.prob + d1.prob);
}
boolean isValid() {
return ds.n[1] + ds.n[3] <= MAX_ODD;
}
int getT() { // current time (from 0 to 52)
int a = 0;
for (int i = 0; i < 5; i++)
a += ds.n[i] * i;
return a;
}
/*
* Gives all possible states starting from this one, for the next
* iteration It does not take into account the "valid" restriction
*/
public List<DeckStateFull> generateNext() {
int[] nx = new int[5];
List<DeckStateFull> states = new ArrayList<DeckStateFull>();
double px;
int t = getT();
for (int i = 0; i < 4; i++) {
if (ds.n[i] < 1 || ds.n[i + 1] >= 13)
continue;
System.
arraycopy(ds.
n,
0, nx,
0,
5); nx[i]--;
nx[i + 1]++;
px = (4 - i) * ds.n[i] / (52.0 - t);
states.add(new DeckStateFull(new DeckState(nx), px * prob));
}
return states;
}
@Override
public String toString
() { // informational return Arrays.
toString(ds.
n) + " (p= " + prob
+ " t=" + getT
() + ")";
}
}
private List<Map<DeckState, DeckStateFull>> states = new ArrayList<Map<DeckState, DeckStateFull>>();
public DeckGame() {
for (int t = 0; t <= 52; t++)
states.add(new HashMap<DeckState, DeckStateFull>());
}
public void compute() {
// initial state
DeckState ds0 = new DeckState(new int[] { 13, 0, 0, 0, 0 });
states.get(0).put(ds0, new DeckStateFull(ds0, 1.0));
int nst = 1; // total number of states
for (int t = 1; t <= 52; t++) {
double pac = 0; // probability accumulator for reaching this
// iteration
for (DeckStateFull stateprev : states.get(t - 1).values()) {
for (DeckStateFull statenew : stateprev.generateNext()) {
if (!statenew.isValid())
continue;
DeckStateFull stnew2 = DeckStateFull.combin(statenew,
states.get(t).get(statenew.ds));
states.get(t).put(stnew2.ds, stnew2);
}
}
for (DeckStateFull ds : states.get(t).values())
pac += ds.prob;
nst += states.get(t).keySet().size();
System.
out.
printf("t=%d p=%.6f %d states \n", t, pac, states.
get(t
) .keySet().size());
if (t < 3 || t > 49)// extra information
for (DeckStateFull s : states.get(t).values()) {
}
}
System.
out.
println("Total valid states: " + nst
); }
public static void main
(String[] args
) { DeckGame d = new DeckGame();
d.compute();
}
}
aW1wb3J0IGphdmEudXRpbC5BcnJheUxpc3Q7CmltcG9ydCBqYXZhLnV0aWwuQXJyYXlzOwppbXBvcnQgamF2YS51dGlsLkhhc2hNYXA7CmltcG9ydCBqYXZhLnV0aWwuTGlzdDsKaW1wb3J0IGphdmEudXRpbC5Mb2NhbGU7CmltcG9ydCBqYXZhLnV0aWwuTWFwOwoKY2xhc3MgRGVja0dhbWUgewoKCS8qCgkgKiBXcmFwcyB0aGUgZ2FtZSBzdGF0ZSwgdHJpdmlhbCB3cmFwcGVyIG9mIGFuIGFycmF5IG9mIDUgZWxlbWVudHMsIGluCgkgKiAwLi4xMywgc3VtIDEzIEVnOiBuPVs1LDMsMCw0LDFdIHNheXMgdGhhdCA1IG51bWJlcnMgaGF2ZSBub3QgeWV0CgkgKiBhcHBlYXJlZCwgMyBudW1iZXJzIGhhdmUgYXBwZWFyZWQgb25lLCA0IG51bWJlcnMgaGFzIGFwcGVhciB0aHJlZSB0aW1lcywKCSAqIGFuZCAxIG51bWJlciBoYXMgYXBwZWFyZWQgNCB0aW1lcwoJICovCglzdGF0aWMgY2xhc3MgRGVja1N0YXRlIHsKCQlmaW5hbCBpbnRbXSBuID0gbmV3IGludFs1XTsgLy8gMC0xMywgbXVzdCBzdW0gMTMKCgkJcHVibGljIERlY2tTdGF0ZShpbnRbXSBubikgewoJCQlTeXN0ZW0uYXJyYXljb3B5KG5uLCAwLCBuLCAwLCA1KTsgLy8gZGVlcCBjb3B5CgkJfQoKCQlAT3ZlcnJpZGUKCQlwdWJsaWMgaW50IGhhc2hDb2RlKCkgewoJCQlyZXR1cm4gQXJyYXlzLmhhc2hDb2RlKG4pOwoJCX0KCgkJQE92ZXJyaWRlCgkJcHVibGljIGJvb2xlYW4gZXF1YWxzKE9iamVjdCBvYmopIHsKCQkJaWYgKHRoaXMgPT0gb2JqKSByZXR1cm4gdHJ1ZTsKCQkJZWxzZSBpZiAob2JqID09IG51bGwgfHwgZ2V0Q2xhc3MoKSAhPSBvYmouZ2V0Q2xhc3MoKSkgcmV0dXJuIGZhbHNlOwoJCQllbHNlIHJldHVybiBBcnJheXMuZXF1YWxzKG4sICgoRGVja1N0YXRlKSBvYmopLm4pOwoJCX0KCX0KCgkvKgoJICogQWRkcyB0byBEZWNrU3RhdGUgdGhlICh0b3RhbCBvciBwYXJ0aWFsKSBwcm9iYWJpbGl0eSBvZiByZWFjaCB0aGF0IHN0YXRlCgkgKi8KCXN0YXRpYyBjbGFzcyBEZWNrU3RhdGVGdWxsIHsKCQlwdWJsaWMgc3RhdGljIGZpbmFsIGludCBNQVhfT0REID0gNzsKCQlmaW5hbCBkb3VibGUgcHJvYjsKCQlmaW5hbCBEZWNrU3RhdGUgZHM7CgoJCXB1YmxpYyBEZWNrU3RhdGVGdWxsKERlY2tTdGF0ZSBkLCBkb3VibGUgcCkgewoJCQl0aGlzLmRzID0gZDsKCQkJdGhpcy5wcm9iID0gcDsKCQl9CgoJCXB1YmxpYyBzdGF0aWMgRGVja1N0YXRlRnVsbCBjb21iaW4oRGVja1N0YXRlRnVsbCBkMSwgRGVja1N0YXRlRnVsbCBkMikgewoJCQlpZiAoZDEgPT0gbnVsbCkKCQkJCXJldHVybiBkMiA9PSBudWxsID8gbnVsbCA6IG5ldyBEZWNrU3RhdGVGdWxsKGQyLmRzLCBkMi5wcm9iKTsKCQkJZWxzZSBpZiAoZDIgPT0gbnVsbCkKCQkJCXJldHVybiBuZXcgRGVja1N0YXRlRnVsbChkMS5kcywgZDEucHJvYik7CgkJCWVsc2UKCQkJCXJldHVybiBuZXcgRGVja1N0YXRlRnVsbChkMS5kcywgZDIucHJvYiArIGQxLnByb2IpOwoJCX0KCgkJYm9vbGVhbiBpc1ZhbGlkKCkgewoJCQlyZXR1cm4gZHMublsxXSArIGRzLm5bM10gPD0gTUFYX09ERDsKCQl9CgoJCWludCBnZXRUKCkgeyAvLyBjdXJyZW50IHRpbWUgKGZyb20gMCB0byA1MikKCQkJaW50IGEgPSAwOwoJCQlmb3IgKGludCBpID0gMDsgaSA8IDU7IGkrKykKCQkJCWEgKz0gZHMubltpXSAqIGk7CgkJCXJldHVybiBhOwoJCX0KCgkJLyoKCQkgKiBHaXZlcyBhbGwgcG9zc2libGUgc3RhdGVzIHN0YXJ0aW5nIGZyb20gdGhpcyBvbmUsIGZvciB0aGUgbmV4dAoJCSAqIGl0ZXJhdGlvbiBJdCBkb2VzIG5vdCB0YWtlIGludG8gYWNjb3VudCB0aGUgInZhbGlkIiByZXN0cmljdGlvbgoJCSAqLwoJCXB1YmxpYyBMaXN0PERlY2tTdGF0ZUZ1bGw+IGdlbmVyYXRlTmV4dCgpIHsKCQkJaW50W10gbnggPSBuZXcgaW50WzVdOwoJCQlMaXN0PERlY2tTdGF0ZUZ1bGw+IHN0YXRlcyA9IG5ldyBBcnJheUxpc3Q8RGVja1N0YXRlRnVsbD4oKTsKCQkJZG91YmxlIHB4OwoJCQlpbnQgdCA9IGdldFQoKTsKCQkJZm9yIChpbnQgaSA9IDA7IGkgPCA0OyBpKyspIHsKCQkJCWlmIChkcy5uW2ldIDwgMSB8fCBkcy5uW2kgKyAxXSA+PSAxMykKCQkJCQljb250aW51ZTsKCQkJCVN5c3RlbS5hcnJheWNvcHkoZHMubiwgMCwgbngsIDAsIDUpOwoJCQkJbnhbaV0tLTsKCQkJCW54W2kgKyAxXSsrOwoJCQkJcHggPSAoNCAtIGkpICogZHMubltpXSAvICg1Mi4wIC0gdCk7CgkJCQlzdGF0ZXMuYWRkKG5ldyBEZWNrU3RhdGVGdWxsKG5ldyBEZWNrU3RhdGUobngpLCBweCAqIHByb2IpKTsKCQkJfQoJCQlyZXR1cm4gc3RhdGVzOwoJCX0KCgkJQE92ZXJyaWRlCgkJcHVibGljIFN0cmluZyB0b1N0cmluZygpIHsgLy8gaW5mb3JtYXRpb25hbAoJCQlyZXR1cm4gQXJyYXlzLnRvU3RyaW5nKGRzLm4pICsgIiAocD0gIiArIHByb2IgKyAiIHQ9IiArIGdldFQoKQoJCQkJCSsgIikiOwoJCX0KCX0KCglwcml2YXRlIExpc3Q8TWFwPERlY2tTdGF0ZSwgRGVja1N0YXRlRnVsbD4+IHN0YXRlcyA9IG5ldyBBcnJheUxpc3Q8TWFwPERlY2tTdGF0ZSwgRGVja1N0YXRlRnVsbD4+KCk7CgoJcHVibGljIERlY2tHYW1lKCkgewoJCWZvciAoaW50IHQgPSAwOyB0IDw9IDUyOyB0KyspCgkJCXN0YXRlcy5hZGQobmV3IEhhc2hNYXA8RGVja1N0YXRlLCBEZWNrU3RhdGVGdWxsPigpKTsKCX0KCglwdWJsaWMgdm9pZCBjb21wdXRlKCkgewoJCS8vIGluaXRpYWwgc3RhdGUKCQlEZWNrU3RhdGUgZHMwID0gbmV3IERlY2tTdGF0ZShuZXcgaW50W10geyAxMywgMCwgMCwgMCwgMCB9KTsKCQlzdGF0ZXMuZ2V0KDApLnB1dChkczAsIG5ldyBEZWNrU3RhdGVGdWxsKGRzMCwgMS4wKSk7CgkJaW50IG5zdCA9IDE7IC8vIHRvdGFsIG51bWJlciBvZiBzdGF0ZXMKCQlmb3IgKGludCB0ID0gMTsgdCA8PSA1MjsgdCsrKSB7CgkJCWRvdWJsZSBwYWMgPSAwOyAvLyBwcm9iYWJpbGl0eSBhY2N1bXVsYXRvciBmb3IgcmVhY2hpbmcgdGhpcwoJCQkJCQkJLy8gaXRlcmF0aW9uCgkJCWZvciAoRGVja1N0YXRlRnVsbCBzdGF0ZXByZXYgOiBzdGF0ZXMuZ2V0KHQgLSAxKS52YWx1ZXMoKSkgewoJCQkJZm9yIChEZWNrU3RhdGVGdWxsIHN0YXRlbmV3IDogc3RhdGVwcmV2LmdlbmVyYXRlTmV4dCgpKSB7CgkJCQkJaWYgKCFzdGF0ZW5ldy5pc1ZhbGlkKCkpCgkJCQkJCWNvbnRpbnVlOwoJCQkJCURlY2tTdGF0ZUZ1bGwgc3RuZXcyID0gRGVja1N0YXRlRnVsbC5jb21iaW4oc3RhdGVuZXcsCgkJCQkJCQlzdGF0ZXMuZ2V0KHQpLmdldChzdGF0ZW5ldy5kcykpOwoJCQkJCXN0YXRlcy5nZXQodCkucHV0KHN0bmV3Mi5kcywgc3RuZXcyKTsKCQkJCX0KCQkJfQoJCQlmb3IgKERlY2tTdGF0ZUZ1bGwgZHMgOiBzdGF0ZXMuZ2V0KHQpLnZhbHVlcygpKQoJCQkJcGFjICs9IGRzLnByb2I7CgkJCW5zdCArPSBzdGF0ZXMuZ2V0KHQpLmtleVNldCgpLnNpemUoKTsKCQkJU3lzdGVtLm91dC5wcmludGYoInQ9JWQgcD0lLjZmICVkIHN0YXRlcyBcbiIsIHQsIHBhYywgc3RhdGVzLmdldCh0KQoJCQkJCS5rZXlTZXQoKS5zaXplKCkpOwoJCQlpZiAodCA8IDMgfHwgdCA+IDQ5KS8vIGV4dHJhIGluZm9ybWF0aW9uCgkJCQlmb3IgKERlY2tTdGF0ZUZ1bGwgcyA6IHN0YXRlcy5nZXQodCkudmFsdWVzKCkpIHsKCQkJCQlTeXN0ZW0ub3V0LnByaW50bG4ocyk7CgkJCQl9CgkJfQoJCVN5c3RlbS5vdXQucHJpbnRsbigiVG90YWwgdmFsaWQgc3RhdGVzOiAiICsgbnN0KTsKCX0KCglwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB7CgkJTG9jYWxlLnNldERlZmF1bHQoTG9jYWxlLlVTKTsKCQlEZWNrR2FtZSBkID0gbmV3IERlY2tHYW1lKCk7CgkJZC5jb21wdXRlKCk7Cgl9Cn0=
t=1 p=1.000000 1 states
[12, 1, 0, 0, 0] (p= 1.0 t=1)
t=2 p=1.000000 2 states
[11, 2, 0, 0, 0] (p= 0.9411764705882353 t=2)
[12, 0, 1, 0, 0] (p= 0.058823529411764705 t=2)
t=3 p=1.000000 3 states
t=4 p=1.000000 5 states
t=5 p=1.000000 6 states
t=6 p=1.000000 9 states
t=7 p=1.000000 11 states
t=8 p=0.887920 14 states
t=9 p=0.887920 17 states
t=10 p=0.748589 20 states
t=11 p=0.748589 24 states
t=12 p=0.620945 27 states
t=13 p=0.620945 32 states
t=14 p=0.514393 34 states
t=15 p=0.514393 41 states
t=16 p=0.427891 42 states
t=17 p=0.427891 50 states
t=18 p=0.357809 50 states
t=19 p=0.357809 60 states
t=20 p=0.300526 58 states
t=21 p=0.300526 69 states
t=22 p=0.253105 65 states
t=23 p=0.253105 76 states
t=24 p=0.213349 70 states
t=25 p=0.213349 80 states
t=26 p=0.179691 72 states
t=27 p=0.179691 80 states
t=28 p=0.151062 70 states
t=29 p=0.151062 76 states
t=30 p=0.126779 65 states
t=31 p=0.126779 69 states
t=32 p=0.106432 58 states
t=33 p=0.106432 60 states
t=34 p=0.089781 50 states
t=35 p=0.089781 50 states
t=36 p=0.076639 42 states
t=37 p=0.076639 41 states
t=38 p=0.066788 34 states
t=39 p=0.066788 32 states
t=40 p=0.059959 27 states
t=41 p=0.059959 24 states
t=42 p=0.055866 20 states
t=43 p=0.055866 17 states
t=44 p=0.054161 14 states
t=45 p=0.054161 11 states
t=46 p=0.054161 9 states
t=47 p=0.054161 6 states
t=48 p=0.054161 5 states
t=49 p=0.054161 3 states
t=50 p=0.054161 2 states
[0, 0, 0, 2, 11] (p= 0.0502082185231828 t=50)
[0, 0, 1, 0, 12] (p= 0.003952440516964939 t=50)
t=51 p=0.054161 1 states
[0, 0, 0, 1, 12] (p= 0.05416065904014774 t=51)
t=52 p=0.054161 1 states
[0, 0, 0, 0, 13] (p= 0.05416065904014774 t=52)
Total valid states: 1806