поскольку я учу язык Ruby, я становлюсь ближе к фактическому программированию. Я думал о создании простой карточной игры. Моим вопросом не является ориентированный Ruby, но я действительно знаю, хотят изучить, как решить эту проблему с подлинным подходом ООП. В моей карточной игре я хочу иметь четыре плеера, с помощью стандартной деки с 52 картами, никакими шутниками/подстановочными знаками. В игре я не буду использовать туз в качестве двойной карты, это всегда - самая высокая карта.
Так, проблемы программирования интересно о, следующие:
Как я могу сортировать/рандомизировать деку карт? Существует четыре типа, каждый имеющий 13 значений. В конечном счете могут быть только уникальные значения, так выбор случайных значений мог генерировать дубликаты.
Как я могу реализовать простой AI? Как существуют тонны карточных игр, кто-то уже понял бы эту часть, таким образом, ссылки будут большими.
Я - истинный Ruby nuby, и моя цель здесь состоит в том, чтобы учиться решать проблемы, таким образом, псевдо код был бы большим, только чтобы понять, как решить проблему программно. Я приношу извинения за свою грамматику и пишущий стиль, если это неясно, поскольку это не мой родной язык.
Кроме того, указатели на сайты, где такие проблемы объяснены, были бы большим ресурсом!
Спасибо за Ваши комментарии, ответы и обратную связь!
Вы можете очень легко гарантировать уникальность карточек, используя числа от 0 до 51.
Массив # Метод перемешивания
основан на алгоритме перемешивания Кнута-Фишера-Йейтса. 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
Ответ Мачека хорош в том, что касается создания колоды.
Вы также спрашивали о других сущностях.
Вы, вероятно, захотите четырех «Игроков». Каждый игрок может управляться человеком или машиной.
Чтобы реализовать человека-игрока, вы взаимодействуете с экраном / мышью / клавиатурой; для реализации игроков, управляемых машиной, у вас есть рука, и вы можете видеть некоторые центральные карты на столе (все игроки должны знать о центральном столе, на котором хранятся все карты, которые будут на столе).
Отсюда логика зависит от того, в какую игру вы играете.
Как только ваш «Игрок» (ИИ) получит ход (например, для вашего объекта игрока вызывается метод takeTurn
), он должен изучить свои карты и принять правильные решения - взять карты из складывает на стол или кладет карты из руки на стол. (На столе почти наверняка есть как минимум два стека, к которым игрок может получить доступ - «Draw» и «Discard».)
Когда игрок-человек вызывает свой метод takeTurn
, он должен взаимодействовать с экраном - обновление руки игрока, позволяющее ему брать и сбрасывать.
Когда каждый игрок закончит свой ход, он должен вернуться. Он не может напрямую вызвать следующего игрока (иначе вы начнете наращивать стек), поэтому вам нужна какая-то форма управления ходом, которая может вызывать игроков по порядку.Этот централизованный контроль также не позволяет игрокам знать друг о друге, в этом им на самом деле не должно быть (одна из лучших тактик объектно-ориентированного проектирования состоит в том, что каждый объект должен знать как можно меньше о других объектах).
... Все еще думаю ... Я могу добавить еще ...
Вы узнаете больше и получите большее удовлетворение, написав код «AI» себя.
Начните с простого, просто подумайте:
, как только вы это заработаете, вы сможете разработать более сложные стратегии:
, тогда, если вы хотите получить действительно изощренный, вы можете начать изучать моделирование оппонента
Я не уверен, какую карточную игру вы хотите создать, но наиболее распространенный способ создания такого рода ИИ - это создание дерева возможных вариантов. Я не Думаю, есть библиотека, чтобы сделать это как таковое, но Ruby может легко создавать деревья.
Цель состоит в том, чтобы иметь корневой узел, который является настоящим временем, а затем каждый дочерний узел является возможным действием. Тогда дочерний узел каждого возможного действия является следующее возможное действие. Оттуда вы можете построить дерево всех возможных исходов. Все, что остается, - это выбрать тот результат, который вам нравится.
Если у вас нет всей информации (например, вы не можете видеть карты оппонентов) вы моделируете это. Под моделированием я подразумеваю предположение. Среднее значение всех имитаций / предположений даст вам хорошее представление о том, какое дерево ches, вероятно, будут лучшими.
Если вы можете сделать все, что у вас хорошо получается (а это действительно хорошее упражнение), о котором написаны сотни статей об ИИ, Google станет вашим другом. Единственная проблема с подходом, который я описал, заключается в том, что он может быть очень медленным, но есть много умных методов для его ускорения, таких как таблицы транспонирования, альфа-бета-обрезка и т. Д., Которые я пока не рекомендую вам искать.
Вместо того, чтобы втиснуть все это в комментарий, я добавляю это как примечание для людей, которые могут найти его полезным. Собственный Ruby 1.9 Array # shuffle!
и Array # shuffle
на самом деле использует алгоритм перемешивания Knuth-Fisher-Yates .
/*
* 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;
}
Что-то очень простое для начала:
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