Техника программирования: Как создать простую карточную игру - PullRequest
9 голосов
/ 15 апреля 2010

Поскольку я изучаю язык Ruby, я все ближе к реальному программированию. Я думал о создании простой карточной игры. Мой вопрос не ориентирован на Ruby, но я знаю, что хочу научиться решать эту проблему с помощью подлинного ООП подхода. В моей карточной игре я хочу иметь четырех игроков, использующих стандартную колоду из 52 карт, без джокеров / подстановочных знаков. В игре я не буду использовать туза в качестве двойной карты, это всегда самая старшая карта.

Итак, проблемы программирования, которые меня интересуют, следующие:

  1. Как я могу отсортировать / рандомизировать колоду карт? Есть четыре типа, каждый из которых имеет 13 значений. В конечном итоге могут быть только уникальные значения, поэтому выбор случайных значений может привести к дублированию.

  2. Как я могу реализовать простой ИИ? Поскольку существует множество карточных игр, кто-то уже понял бы эту часть, так что ссылки были бы отличными.

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

Кроме того, ссылки на сайты, где объясняются такие проблемы, были бы отличным ресурсом!

Спасибо за ваши комментарии, ответы и отзывы!

Ответы [ 6 ]

15 голосов
/ 15 апреля 2010

Что-то, с чего можно начать

Вы можете легко получить уникальные карты, используя цифры от 0 до 51.

Метод Array#shuffle основан на алгоритме тасования Кнута-Фишера-Йейтса. http://en.wikipedia.org/wiki/Fisher–Yates_shuffle

class Card
  RANKS = %w(2 3 4 5 6 7 8 9 10 J Q K A)
  SUITS = %w(Spade Heart Club Diamond)

  attr_accessor :rank, :suit

  def initialize(id)
    self.rank = RANKS[id % 13]
    self.suit = SUITS[id % 4]
  end
end

class Deck
  attr_accessor :cards
  def initialize
    # shuffle array and init each Card
    self.cards = (0..51).to_a.shuffle.collect { |id| Card.new(id) }
  end
end

# people with Ruby 1.9 (or 1.8.7 with backports) can safely ignore this duck punch
class Array
  # knuth-fisher-yates shuffle algorithm
  def shuffle!
    n = length
    for i in 0...n
      r = rand(n-i)+i
      self[r], self[i] = self[i], self[r]
    end
    self
  end
  def shuffle
    dup.shuffle!
  end
end

тест

d = Deck.new
d.cards.each do |card|
  puts "#{card.rank} #{card.suit}"
end

выход

6 Spade
5 Heart
2 Heart
8 Heart
8 Diamond
7 Club
J Diamond
4 Club
K Spade
5 Diamond
J Heart
8 Spade
10 Club
4 Diamond
9 Heart
7 Diamond
3 Diamond
K Diamond
7 Spade
Q Diamond
9 Diamond
6 Heart
A Heart
9 Club
A Spade
5 Club
J Club
Q Spade
2 Club
2 Spade
Q Heart
A Diamond
10 Spade
10 Diamond
Q Club
3 Club
A Club
K Club
6 Club
10 Heart
2 Diamond
3 Spade
K Heart
5 Spade
9 Spade
7 Heart
4 Spade
J Spade
3 Heart
4 Heart
8 Club
6 Diamond
5 голосов
/ 16 апреля 2010

Вместо того, чтобы втиснуть это все в комментарии, я добавляю это как примечание для людей, которые могут найти это полезным. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

* * * * * * * * * * * *1004* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

рубиново-1.9.1-P376 / array.c

/*
 *  call-seq:
 *     array.shuffle!        -> array
 *  
 *  Shuffles elements in _self_ in place.
 */

static VALUE
rb_ary_shuffle_bang(VALUE ary)
{
    long i = RARRAY_LEN(ary);

    rb_ary_modify(ary);
    while (i) {
    long j = rb_genrand_real()*i;
    VALUE tmp = RARRAY_PTR(ary)[--i];
    RARRAY_PTR(ary)[i] = RARRAY_PTR(ary)[j];
    RARRAY_PTR(ary)[j] = tmp;
    }
    return ary;
}


/*
 *  call-seq:
 *     array.shuffle -> an_array
 *  
 *  Returns a new array with elements of this array shuffled.
 *     
 *     a = [ 1, 2, 3 ]           #=> [1, 2, 3]
 *     a.shuffle                 #=> [2, 3, 1]
 */

static VALUE
rb_ary_shuffle(VALUE ary)
{
    ary = rb_ary_dup(ary);
    rb_ary_shuffle_bang(ary);
    return ary;
}
3 голосов
/ 15 апреля 2010

Не ищите пакет AI

Вы узнаете больше и получите большее удовлетворение, кодируя «ИИ» самостоятельно.

Начните с простого, просто подумайте:

  • состояние игры - какие карты были сыграны или просмотрены, какие карты видны всем игрокам
  • стратегия - как компьютерный игрок реагирует на основании его текущей руки и его знания о состоянии игры

Как только вы начнете работать, вы сможете разработать более сложные стратегии:

тогда, если вы хотите действительно изощренно, вы можете начать изучать моделирование противника

2 голосов
/ 15 апреля 2010

Ответ Мацека хорош в том, что касается установки колоды.

Вы также спрашивали о других сущностях.

Вы, вероятно, хотите четырех "Игроков". Каждый игрок может управляться человеком или машиной.

Чтобы реализовать человека-игрока, вы взаимодействуете с экраном / мышью / клавиатурой; чтобы реализовать игроков, контролируемых машиной, у вас есть рука, и вы можете видеть несколько центральных карт на столе (все игроки должны знать центральный стол, на котором находятся любые карты, которые будут на столе).

Отсюда логика основана на том, в какую игру вы играете.

Как только ваш «Игрок» (ИИ) получает ход (например, для вашего объекта игрока вызывается метод takeTurn), он должен исследовать свои карты и принимать правильные решения - брать карты из стопок на столе. или положить карты из его руки на стол. (Таблица почти наверняка имеет как минимум два стека, к которым игрок может получить доступ - «Дро» и «Сброс».)

Когда у игрока-человека вызывается метод takeTurn, он должен взаимодействовать с экраном, обновляя руку игрока, позволяя ему рисовать и сбрасывать.

Когда каждый игрок завершает свой ход, он должен вернуться. Он не может напрямую вызвать следующего игрока (иначе вы начнете собирать стек), поэтому вам нужна некоторая форма контроля хода, которая может вызывать игроков по порядку. Этот централизованный контроль также препятствует тому, чтобы игроки знали друг о друге, в котором они не должны на самом деле (одна из лучших тактик разработки ОО состоит в том, что каждый объект должен знать как можно меньше о других объектах).

... Все еще думаю ... Я могу добавить еще ...

1 голос
/ 15 апреля 2010

Я не уверен, какую карточную игру вы хотите построить, но самый распространенный способ создания такого ИИ - это создание дерева возможных вариантов. Я не думаю, что для этого есть библиотека, но ruby ​​может легко создавать деревья.

Цель состоит в том, чтобы иметь корневой узел, который является текущим временем, и тогда каждый дочерний узел является возможным действием. Тогда ребенок каждого возможного действия является следующим возможным действием. Оттуда вы можете построить дерево каждого возможного результата. Осталось только выбрать понравившийся вам результат.

Если у вас нет всей информации (т.е. вы не можете видеть карты своих оппонентов), вы имитируете ее. Под симуляцией я подразумеваю догадку. Среднее значение всех симуляций / предположений даст вам хорошее представление о том, какие ветви деревьев «могут быть лучшими».

Если вы можете делать все, что у вас хорошо в пути (и это действительно хорошее упражнение), есть сотни статей об искусственном интеллекте, Google станет вашим другом. Единственная проблема с подходом, который я описал, заключается в том, что он может быть крайне медленным, но есть много хитрых техник для его ускорения, таких как таблицы транспозиции, альфа-бета-отсечение и т. Д., Которые я не советую вам искать еще. *

0 голосов
/ 19 апреля 2010

Что-то очень простое, чтобы начать:

class CardGame
  DECK = %w[A 2 3 4 5 6 7 8 9 T J Q K].product(%w[c d h s]).map(&:join)

  def initialize(decks=1)
    @decks = decks
  end

  def shuffle
    @playing_deck = (DECK*@decks).shuffle
  end

  def deal(players=1, cards=5)
    shuffle
    @dealt = Array.new(players) { Array.new }

    @dealt.map { |hand| cards.times { hand << @playing_deck.pop } }
  end

  def display
    @dealt.each_with_index { |cards, i| puts "Player #{i+1}: #{cards.join(' | ')}" }
    puts "Cards used: #{@dealt.flatten.size}"
    puts "Cards remaining: #{@playing_deck.size}"
  end

  private :shuffle   
end

game1 = CardGame.new   
game1.deal   
game1.display    
puts 
game1.deal(4)  
game1.display   
puts   
game2 = CardGame.new(2)   
game2.deal(6,10)   
game2.display
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...