Как пройти через все комбинации, например, 48 выберите 5 [дубликат]

Возможные Дубликаты:
как итеративно генерировать K подмножеств элементов из набора размера n в java?

Я хочу создать свой собственный оценщик покерных рук, но у меня проблемы с определенной частью.

Если двум игрокам раздают две карты, то в колоде останется 48 карт. В Техасском Холдеме затем раздаются еще 5 возможных карт сообщества (это называется доской). Я хочу перечислите / цикл через все 48 выберите 5 возможных комбинаций досок и подсчитайте раз игрок а выигрывает и раз игрок Б выигрывает и когда они связывают.

Я не уверен, как я могу систематически перебирать каждую комбинацию из 5 карт. У кого-нибудь есть идеи? Карты представлены как массив карты класса, но я мог бы также представить их как битовый набор, если это делает его быстрее.

Я делаю это на Java.

большое спасибо

2 ответов


(отказ от ответственности: я написал очень быстрый покер оценщика)

Я хочу перечислить / цикл через все 48, выберите 5 возможных комбинации досок и подсчет времени Игрок A выигрывает и раз Игрок B выигрывает, и когда они галстук.

вы не хотите оценивать руки C(48,5) (1 712 304) каждый раз, когда у вас есть матч между двумя игроками preflop: большинство программ просто используют предварительно вычисленную таблицу поиска между всеми возможные матчи между двумя игроками preflop.

например, скажем, у вас есть "AC Ad" vs "7c 6c", вы просто смотрите в таблице поиска, которая содержит:1 333 573, 371 831, 6900 (где 1 333 573-количество побед" Ac Ad", 371 831-количество побед" 7c 6c " и 6 900-количество связей (они составляют 1 712 304). Чтобы получить некоторую комнату, вы можете отказаться от 6 900, зная, что количество связей всегда будет C (48,5) - (выигрыши 1 + выигрыши 2).

(больше в таблице поиска в конце этого ответа)

но чтобы ответить на ваш вопрос:

Я не уверен, как я могу систематически цикл через каждые 5 карт сочетание.

Если вы действительно хотите сделать петлю через каждую комбинацию, вы должны знать, что покер рука оценщики, как правило, вид программы, которая должна быть очень, очень быстро. Эти программы обычно могут оценивать сотни миллионов рук в секунду (Вы читаете правильно: сотни миллионов).

когда вам нужен такой высокопроизводительный "номер хрустящий", вы можете забыть о" шаблонах дизайна "и"ОО". Чего вы хотите, так это сырой скорости.

например, следующее пройдет через самый внутренний цикл C (48,5) раз, и это довольно быстро:

    for ( int i = 0; i < n; i++ ) {
        for ( int j = i + 1; j < n; j++ ) {
            for ( int k = j + 1; k < n; k++ ) {
                for (int l = k + 1; l < n; l++) {
                    for (int m = l + 1; m < n; m++) {
                        ...
                    }
                }
            }
        }
    }

еще раз для двух игроков preflop это, вероятно, очень плохая идея: вы будете намного быстрее, используя таблицу поиска.

но для трех игроков префлопа (там, где непрактично использовать таблицы префлопа, слишком много совпадений), вы можете захотеть сделать такой цикл над c(46,5) руками, используя пять вложенных циклов (конечно,вам нужно использовать i,j,k,l, m, чтобы получить правильные 5 карт из 46 карт, которые остались). Затем, как только у вас есть 5 карт, вы используете быстрый оценщик рук, который дает вам лучшее из 7 (5 из доски + два каждого игрока).

относительно таблицы поиска:

большинство людей используют приблизительная таблица поиска 169 vs 169 ("Ac Kd", "As Kh", "Ad Ks" и т. д. все становятся "AK offsuit" и C(52,2) возможные стартовые руки группируются в 169 тип стартовых рук). В статье Википедии объясняется, как получить 169 неэквивалентных стартовых рук:

http://en.wikipedia.org/wiki/Texas_hold_%27em_starting_hands

Они не эквивалентны, когда вы берете один рука в счет, но как только вы это сделаете стрелка 1 против силы 2" 169 vs 169 " является приближением (довольно хорошим, который сказал).

конечно, вы можете получить fancier. Есть только C (52,2) (что дает 1326) реальные разные стартовые руки Холдема, что означает, что очень практично построить идеальную таблицу поиска (без аппроксимации вообще) на современных компьютерах(C (1326,2) не так велик), если вам действительно нужны идеальные числа. Если вы можете жить с приближением, перейдите к таблице 169 vs 169 (для этого потребуется C (169,2) или 14 196 вступления.)


  1. инициализировать массив (A) к первым 5 индексам. (0,1,2,3,4)
  2. переместите последний возможный индекс в A в следующую позицию. A[k]++
  3. переместите следующие индексы в следующие последовательные позиции. (A[k+1] = A[k] + 1, ...). Если какой-то индекс станет слишком большим, попробуйте использовать более ранний индекс на Шаге 2.
  4. выход элементов при текущих показателях в A.
  5. если возможно, повторите с шага 2.

реализовано как итератор:

public class CombinationIterator<T>
        implements Iterable<List<T>>,
                   Iterator<List<T>> {
    private List<T> items;
    private int choose;
    private boolean started;
    private boolean finished;
    private int[] current;

    public CombinationIterator(List<T> items, int choose) {
        if (items == null || items.size() == 0) {
            throw new IllegalArgumentException("items");
        }
        if (choose <= 0 || choose > items.size()) {
            throw new IllegalArgumentException("choose");
        }
        this.items = items;
        this.choose = choose;
        this.finished = false;
    }

    public Iterator<List<T>> iterator() {
        return this;
    }

    public boolean hasNext() {
        return !finished;
    }

    public List<T> next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }

        if (current == null) {
            current = new int[choose];
            for (int i = 0; i < choose; i++) {
                current[i] = i;
            }
        }

        List<T> result = new ArrayList<T>(choose);
        for (int i = 0; i < choose; i++) {
            result.add(items.get(current[i]));
        }

        int n = items.size();
        finished = true;
        for (int i = choose - 1; i >= 0; i--) {
            if (current[i] < n - choose + i) {
                current[i]++;
                for (int j = i + 1; j < choose; j++) {
                    current[j] = current[i] - i + j;
                }
                finished = false;
                break;
            }
        }

        return result;
    }

    public void remove() {
        throw new UnsupportedOperationException();
    }
}

эквивалент в C#, используя метод итератора:

public IEnumerable<IList<T>> Combinations<T>(IEnumerable<T> items, int choose)
{
    if (items == null) throw new ArgumentNullException("items");

    var itemsList = items.ToList();
    int n = itemsList.Count;

    if (n < 1) throw new ArgumentException("Must contain at least one item.", "items");
    if (choose <= 0 || choose >= n) throw new ArgumentOutOfRangeException("choose");

    var indices = Enumerable.Range(0, choose).ToArray();

    bool moreWork = true;
    while (moreWork)
    {
        yield return indices.Select(i => itemsList[i]).ToList();

        moreWork = false;
        for (int i = choose - 1; i >= 0; i--)
        {
            if (indices[i] < n - choose + i)
            {
                indices[i]++;
                for (int j = i + 1; j < choose; j++)
                {
                    indices[j] = indices[i] - i + j;
                }
                moreWork = true;
                break;
            }
        }
    }
}