Я бы рекомендовал двухэтапный подход: написание вспомогательных функций для вытягивания карт из колоды, а затем вызывать эти функции в порядке, соответствующем вашим ограничениям.
Heads-up, когда вы читаете: IЯ называю карты по-другому, чем вы (я называю два из клубов "2C" вместо 1), но общий совет остается в силе.
Вспомогательные функции для карточных колод
Вы можете справиться с проблемами, связанными с карточками, создав список или data.frame для представления колоды карт, с которой вы работаете.
make_deck <- function(){
list(club = paste0('C', 2:6),
diamond = paste0('D', 2:6),
heart = paste0('H', 2:6),
spade = paste0('S', 2:6))
}
Затем вы можете написать функции для рисования случайной карты из определенных мастей в колоде:
draw_from_suits <- function(deck, suits){
cards <- unlist(deck[suits], use.names = FALSE)
# If there are no cards in the requested suits, return NA
if (length(cards) == 0) { return(NA) }
# Otherwise, grab a random card
sample(cards, 1)
}
Как только вы узнаете, какую карту вы выбрали, вы можете удалить ее из колоды другойвспомогательная функция:
get_suit <- function(card){
switch(substr(card, 1, 1),
C = 'club',
D = 'diamond',
H = 'heart',
S = 'spade')
}
remove_from_deck <- function(deck, card){
suit <- get_suit(card)
deck[[suit]] <- setdiff(deck[[suit]], card)
return(deck)
}
Теперь, если мы хотим взять карту из набора червей, у нас будет такой трехэтапный процесс:
deck <- make_deck()
card <- draw_from_suits(deck, 'heart')
deck <- remove_from_deck(deck, card)
Выборка с ограничениями
Вторая проблема в этой проблеме, которую вы идентифицируете, заключается в том, что вы можете зайти в тупик на полпути.Вы можете написать функцию сэмплирования так, чтобы она сбрасывалась и начиналась с нуля каждый раз, когда она заходит в тупик.
Вы можете сделать это многими способами.Одним из них является использование цикла while
, чтобы продолжать попытки до тех пор, пока вы не добьетесь успеха:
sample_with_constraint <- function(){
# The suits we're allowed to draw from at each step
suit_sequence <- list(c('heart', 'diamond'),
c('club', 'diamond', 'spade'),
c('heart', 'club'))
# We'll use this variable to track whether we're done dealing cards
dealt <- FALSE
while (dealt == FALSE) {
deck <- make_deck()
hand <- rep(NA, length(unlist(deck)))
# Step through the hand and build it card-by-card
for (ii in seq_along(hand)) {
# Use the modulo operator to identify the step of the sequence
which_suits <- suit_sequence[[(ii %% 3) + 1]]
card <- draw_from_suits(deck, which_suits)
# If we failed to draw a card, this is a dead end
# So break out of this for-loop
if (is.na(card)) { break }
hand[ii] <- card
deck <- remove_from_deck(deck, card)
}
# If there are no more cards in the deck, we've successfully dealt a hand
# In this case, flip 'dealt' to TRUE. Otherwise it stays FALSE and we try again.
dealt <- length(unlist(deck)) == 0
}
return(hand)
}
sample_with_constraint()
Вы также можете адаптировать цикл for в конце вашей функции random_w_contraint
, чтобы сделать нечто подобное.