Ймовірність намалювати задане слово з мішка з літерами в Scrabble


18

Припустимо, у вас був мішок з ятьма плитками, на кожному на якому буква. Є плитки з літерою 'A', з 'B' і так далі, і 'wildcard' плитками (у нас ). Припустимо, у вас був словник із обмеженою кількістю слів.ннАнБнн=нА+нБ++нZ+н

Ви вибираєте плитки з сумки без заміни.к

Як би ви обчислили (або оцінили) ймовірність того, що ви зможете сформувати задане слово довжиною (з 1 < = < ) зі словника за вибраними плитками?ллкк

Для тих, хто не знайомий з Scrabble (TM), символом підстановки можна скористатися для відповідності будь-якій букві. Таким чином, слово "BOOT" може бути написане плитками "B", "*", "O", "T". Порядок, в якому малюються букви, значення не має.

Рекомендація: для спрощення написання відповідей, можливо, краще просто відповісти на питання: яка ймовірність того, що слово "BOOT" серед ваших можливих рухів після того, як витягніть 7 листів із свіжого пакетика, може бути краще.

(вступ проблеми було скопійовано з цього подібного питання )


Я б радив вирішити найпростіший випадок, наприклад, такий, що не мав би символів.
Glen_b -Встановіть Моніку

@Glen_b Я згоден. Оскільки моє остаточне призначення - це впорядкування слів імовірно, я вважаю, що ігнорування маклерів є прийнятним наближенням. Однак я все ще не маю навичок будувати формулу для вирішення цієї простішої проблеми
Себастьян

1
Якщо ви хочете почати ще простіше, обчисліть ймовірність вибору "B", потім "O", потім "O", потім "T". Після цього обчисліть ймовірність добору букв у будь-якому порядку. Після цього враховуйте, що у вас сім спроб. Тоді враховуйте знаки підстановки.
Джеррі Ширмер

1
Простим способом вирішити цю проблему було б використання наближення Монте-Карло. Цього вистачить?
Rasmus Bååth

1
Ви говорите про утворення слів із лише вибраних літер або з урахуванням вже вибраних літер та слів, які вже розміщені на дошці?
samthebrand

Відповіді:


12

Формула запитується. На жаль, ситуація є настільки складною, здається, що будь-яка формула буде просто обхідним способом перерахування всіх можливостей. Натомість у цій відповіді пропонується алгоритм, який (а) рівносильний формулі, що включає суми добутків двочленних коефіцієнтів і (b) може бути перенесений на багато платформ.


Щоб отримати таку формулу, розділіть можливості на групи, що перебувають у взаємозв'язку, двома способами: відповідно до того, скільки літер не в цьому слові вибрано у стійці (нехай це буде ) та відповідно до того, скільки обраних марок (пробілів) вибрано ( нехай це буде ш ). Коли в стійці r = 7 плиток, N доступних плиток, M доступних плиток з літерами не в слові, і W = 2 пробіли, кількість можливих варіантів, заданих ( m , w ), становитьмшr=7NМW=2(м,ш)

(Мм)(Wш)(N-М-Wr-м-ш)

тому що вибір несловних букв, пробілів та букв слова незалежно залежать від (м,ш,r).

Це зменшує проблему пошуку кількості способів написання слова під час вибору лише з плиток, що представляють літери слова, враховуючи, що наявні пробіли та вибрано плитки r - m - w . Ситуація безладна, і закрита формула не здається доступною. Наприклад, з w = 0 пробілами та m = 3 непотрібні букви намальовано, залишиться точно чотири літери для написання "завантаження", які були намальовані з плиток "b", "o" та "t" . Враховуючи, що є 2 "b", 8 "o" 'і 6шr-м-шш=0м=3286"Набір" у наборі плиток Scrabble, є позитивні ймовірності малювання (мультисети) "bboo", "bbot", "bbtt", "booo", "boot", "bou", "bttt", "oooo "," ooot "," oott "," ottt "та" tttt ", але лише одне з цих заклинань" boot ". І це був простий випадок! Наприклад, якщо припустити, що стійка містить п’ять плиток, вибраних випадковим чином з плиток "o", "b" та "t", разом з обома заготовками існує ще багато способів написання "boot" - а не написання. Наприклад, "boot" може бути написано з "__boott" і "__bbttt", але не з "__ttttt".

Цей підрахунок - суть проблеми - може бути вирішений рекурсивно. Я опишу це на прикладі. Припустимо, ми хочемо порахувати способи написання "завантаження" однією порожньою та ще чотирма плитками із колекції плиток "b", "o" та "t" (звідки на двох інших плитках відображаються непорожні літери не в { "b", "o", "t"}). Розглянемо першу букву "b":

  1. В ( 2) можна намалювати "b" способи з двох наявних плиток "b". Це зводить проблему до підрахунку кількості способів написання суфіксу "oot", використовуючи як пробіли, так і ще три плитки із колекції плиток "o" та "t".(21)

  2. Один пробіл може бути позначений як "b". Це зводить проблему до підрахунку кількості способів написання «oot», використовуючи залишки та ще три плитки із колекції плиток «o» та «t».

Взагалі, кроки (1) і (2), які є суперечливими і тому додатково сприяють обчисленням ймовірності, - можуть бути реалізовані як цикл щодо можливої ​​кількості заготовок, які можуть бути використані для першої літери. Знижена проблема вирішується рекурсивно. Базовий випадок виникає, коли залишилася одна літера, є певна кількість плиток із цією буквою, і в стійці можуть бути і деякі заготовки. Треба лише переконатися, що кількість заготовок у стійці плюс кількість наявних плиток буде достатньо для отримання потрібної кількості останньої літери.

Ось Rкод для рекурсивного кроку. rackзазвичай дорівнює , являє собою масив підрахунків букв (таких як ), є аналогічною структурою, що дає кількість доступних плиток з цими літерами, і це кількість заготовок, які, як передбачається, трапляються в стійці.7wordc(b=1, o=2, t=1)alphabetwild

f <- function(rack, word, alphabet, wild) {
  if (length(word) == 1) {
    return(ifelse(word > rack+wild, 0, choose(alphabet, rack)))
  }
  n <- word[1]
  if (n <= 0) return(0)
  m <- alphabet[1]
  x <- sapply(max(0, n-wild):min(m, rack), 
              function(i) {
                choose(m, i) * f(rack-i, word[-1], alphabet[-1], wild-max(0, n-i))
              })
  return(sum(x))
}

Інтерфейс цієї функції вказує стандартну плитку Scrabble, перетворює задане слово в його мультисетову структуру даних і виконує подвійну суму над і w . Ось де біноміальні коефіцієнти ( Ммш і ( Ш(Мм) обчислюються та множуються.(Wш)

scrabble <- function(sword, n.wild=2, rack=7, 
              alphabet=c(a=9,b=2,c=2,d=4,e=12,f=2,g=3,h=2,i=9,j=1,k=1,l=4,m=2,
                         n=6,o=8,p=2,q=1,r=6,s=4,t=6,u=4,v=2,w=2,x=1,y=2,z=1),
              N=sum(alphabet)+n.wild) {
  word = sort(table(strsplit(sword, NULL))) # Sorting speeds things a little
  a <- sapply(names(word), function(s) alphabet[s])
  names(a) <- names(word)
  x <- sapply(0:n.wild, function(w) {
    sapply(sum(word):rack-w, 
           function(i) {
             f(i, word, a, wild=w) *
               choose(n.wild, w) * choose(N-n.wild-sum(a), rack-w-i)
           })
  })
  return(list(numerator = sum(x), denominator = choose(N, rack),
              value=sum(x) / choose(N, rack)))
}

Давайте спробуємо це рішення та розберемо його, як ми підемо. Наступний тест використовує ті самі входи, які використовував у моделюванні @Rasmus Bååth :

system.time(x <- sapply(c("boot", "red", "axe", "zoology"), scrabble))

Цей апарат повідомляє про загальний пройдений час секунди: досить швидко. Результати?0,05

> x
            boot        red         axe         zoology     
numerator   114327888   1249373480  823897928   11840       
denominator 16007560800 16007560800 16007560800 16007560800 
value       0.007142118 0.07804896  0.0514693   7.396505e-07

Імовірність «завантаження» з точно дорівнює значенню +2381831 / +333490850 , отриману в моєму іншому відповіді (який використовує подібний метод , але кушетки його в більш потужних рамках вимагають символічну алгебри обчислювальної платформу). Ймовірності всіх чотирьох слів досить близькі до симуляції Баас (які не могли б очікувати , щоб дати точне значення «зоологія» в зв'язку з його низькою ймовірністю 11840 / 16007560800 , що менше , ніж один на мільйон).114327888/160075608002381831/33349085011840/16007560800,


Класне та елегантне рішення! І набагато швидше, ніж у мене ... :)
Rasmus Bååth

1
Це чудова відповідь, дякую. Мені було б важко кодувати ваш алгоритм, тому готовий до використання код дуже вітається. Я не знав, Rале все-таки встиг використати ваші функції менше ніж за годину роботи, так що скрипт бере вхід із файлу словника в 20 клів і записує результати в .csv. (на середній діапазон i5 зайняло менше 10 хвилин)
Себастьян

16

Відповіді на посилається на це питання застосовуються безпосередньо тут: створіть словник, що складається лише з цільового слова (та можливих його мальовничих написань), обчисліть шанс, що випадкова стійка не зможе сформувати ціль, і відніміть її з . Це обчислення швидко.1

Симулятори (показані в кінці) підтримують обчислені відповіді.


Деталі

Як і в попередній відповіді, Mathematica використовується для виконання обчислень.

  1. Вкажіть проблему: слово (або слова, якщо вам подобається), букви, їх кількість та розмір стійки. Оскільки всі літери, які не є у слові, діють однаково, це значно прискорює обчислення, щоб замінити їх одним символом представляє "будь-яку букву не в слові".χ

    word = {b, o, o, t};
    letters = {b, o, t, \[Chi], \[Psi]};
    tileCounts = {2, 8, 6, 82, 2};
    rack = 7;
  2. Створіть словник цього слова (або слів) та доповніть його, щоб включити всі можливі орфограми.

    dict[words_, nWild_Integer] := Module[{wildcard, w},
       wildcard = {xx___, _, yy___} -> {xx, \[Psi], yy};
       w = Nest[Flatten[ReplaceList[#, wildcard] & /@ #, 1] &, words, nWild];
       Union[Times @@@ Join[w, Times @@@ words]]];
    dictionary = dict[{word}, 2]

    {бо2т,бо2ψ,ботψ,о2тψ,боψ2,о2ψ2,бтψ2,отψ2}

  3. Обчисліть неслова:

    alphabet = Plus @@ letters;
    nonwords = Nest[PolynomialMod[# alphabet, dictionary] &, 1, rack]

    б7+7б6о+21б5о2++7χψ6+ψ7

    185

  4. Обчисліть шанси. Для вибірки з заміною просто замініть кількість плиток для змінних:

    chances = (Transpose[{letters, tileCounts/(Plus @@ tileCounts)}] /. {a_, b_} -> a -> b);
    q = nonwords /. chances;
    1 - q

    20726341339062500000

    0,00756036.

    Для вибірки без заміни використовуйте фактичні повноваження замість повноважень:

    multiplicities = MapThread[Rule, {letters, tileCounts}];
    chance[m_] :=  (ReplaceRepeated[m , Power[xx_, n_] -> FactorialPower[xx, n]] 
                   /. multiplicities);
    histor = chance /@ MonomialList[nonwords];
    q0 = Plus @@ histor  / FactorialPower[Total[tiles], nn];
    1 - q0

    2381831333490850

    0,00714212.


Результати моделювання

106

simulation = RandomChoice[tiles -> letters, {10^6, 7}];
u = Tally[Times @@@ simulation];
(p = Total[Cases[Join[{PolynomialMod[u[[All, 1]], dictionary]}\[Transpose], 
       u, 2], {0, _, a_} :> a]] / Length[simulation] ) // N

0,007438

Порівняйте його з обчисленим значенням щодо його стандартної помилки:

(p - (1 - q)) / Sqrt[q (1 - q) / Length[simulation]] // N

-1.41259

Угода чудова, що сильно підтримує обчислений результат.

106

tilesAll = Flatten[MapThread[ConstantArray[#1, #2] &, {letters, tiles}] ]
    (p - (1 - q)) / Sqrt[q (1 - q) / Length[simulation]] // N;
simulation = Table[RandomSample[tilesAll, 7], {i, 1, 10^6}];
u = Tally[Times @@@ simulation];
(p0 = Total[Cases[Join[{PolynomialMod[u[[All, 1]], dictionary]}\[Transpose], 
       u, 2], {0, _, a_} :> a]] / Length[simulation] ) // N

0,00717

Зробіть порівняння:

(p0 - (1 - q0)) / Sqrt[q0 (1 - q0) / Length[simulation]] // N

0,331106

Згода в цій симуляції була чудовою.

12


13

Отже, це рішення Монте-Карло , тобто ми будемо імітувати малювання плитки в мільйон разів, а потім будемо підрахувати, скільки з цих симульованих малюнків призвело до того, що ми змогли сформувати задане слово. Я написав рішення в R, але ви можете використовувати будь-яку іншу мову програмування, скажімо, Python або Ruby.

Спочатку я опишу, як імітувати один малюнок. Спочатку давайте визначимо частоти плитки.

# The tile frequency used in English Scrabble, using "_" for blank.
tile_freq <- c(2, 9 ,2 ,2 ,4 ,12,2 ,3 ,2 ,9 ,1 ,1 ,4 ,2 ,6 ,8 ,2 ,1 ,6 ,4 ,6 ,4 ,2 ,2 ,1 ,2 ,1)
tile_names <- as.factor(c("_", letters))
tiles <- rep(tile_names, tile_freq)
## [1] _ _ a a a a a a a a a b b c c d d d d e e e e e e
## [26] e e e e e e f f g g g h h i i i i i i i i i j k l
## [51] l l l m m n n n n n n o o o o o o o o p p q r r r
## [76] r r r s s s s t t t t t t u u u u v v w w x y y z
## 27 Levels: _ a b c d e f g h i j k l m n o p q r ... z

Потім кодуйте слово як вектор лічильників.

word <- "boot"
# A vector of the counts of the letters in the word
word_vector <- table( factor(strsplit(word, "")[[1]], levels=tile_names))
## _ a b c d e f g h i j k l m n o p q r s t u v w x y z 
## 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 1 0 0 0 0 0 0 

Тепер намалюйте зразок із семи плиток і закодуйте їх так само, як слово.

tile_sample <- table(sample(tiles, size=7))
## _ a b c d e f g h i j k l m n o p q r s t u v w x y z 
## 1 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 1 0 1 0 0 0 

Нарешті, порахуйте, які літери пропущені ...

missing <- word_vector - tile_sample
missing <- ifelse(missing < 0, 0, missing)
## _ a b c d e f g h i j k l m n o p q r s t u v w x y z 
## 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 

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

sum(missing) - tile_sample["blank"] <= 0
## FALSE

У цьому конкретному випадку ми цього не зробили ... Тепер нам просто потрібно повторити це багато разів і обчислити відсоток успішних розіграшів. Все це виконується за допомогою наступної функції R:

word_prob <- function(word, reps = 50000) {
  tile_freq <- c(2, 9 ,2 ,2 ,4 ,12,2 ,3 ,2 ,9 ,1 ,1 ,4 ,2 ,6 ,8 ,2 ,1 ,6 ,4 ,6 ,4 ,2 ,2 ,1 ,2 ,1)
  tile_names <- as.factor(c("_", letters))
  tiles <- rep(tile_names, tile_freq)
  word_vector <- table( factor(strsplit(word, "")[[1]], levels=tile_names))
  successful_draws <- replicate(reps, {
    tile_sample <- table(sample(tiles, size=7))
    missing <- word_vector - tile_sample
    missing <- ifelse(missing < 0, 0, missing)
    sum(missing) - tile_sample["_"] <= 0
  })
  mean(successful_draws)
}

Ось repsкількість модельованих малюнків. Тепер ми можемо спробувати його на кількох різних словах.

> word_prob("boot")
[1] 0.0072
> word_prob("red")
[1] 0.07716
> word_prob("axe")
[1] 0.05088
> word_prob("zoology")
[1] 2e-05

Я отримую різні відповіді. Важко сказати, чому вони не погоджуються, враховуючи складність вашого імітаційного коду, але я б почав шукати причину в нашій роботі з макроконтролерами.
whuber

2
Я вважаю, що sampleце діє не так, як ви начебто очікуєте. Наприклад, що станеться з вашим кодом, якщо гра буде модифікована, щоб забезпечити стійку з 28 плиток? Змініть, size=7щоб size=28дізнатися.
whuber

2
@whuber Ви маєте рацію, дякую за вказівку! Тепер він працює і отримує таку ж відповідь, що і ваш код!
Rasmus Bååth

Дякую за цю приємну роботу. Дійсно, підхід до Монте-Карло цілком підходить. Однак, в основному з міркувань продуктивності, я вирішив використовувати точний алгоритм обчислення, який надає whuber.
Себастьян

7

p0=(нб1)(но2)(нт1)(н-43)(н7)
pкк
p0=(nb1)(no2)(nt1)(n43)(n7)p1=p0+(n1)(no2)(nt1)(n43)(n7)+(nb1)(no1)(n1)(nt1)(n43)(n7)+(nb1)(no2)(n1)(n43)(n7)=p0+(n1)(n43)(n7)((no2)(nt1)+(nb1)(no1)(nt1)+(nb1)(no2))p2=p1+(n2)(n43)(n7)((nb1)(no1)+(nb1)(nt1)+(no2)+(no1)(nt1))p3=p2+(n3)(n43)(n7)((nb1)+(no1)+(nt1))p4=p3+(n4)(n43)(n7)pi=p4,i4

Ідея правильна (хоча це допомогло б пояснити, чому і пояснити позначення, особливо стосовно того, що саме "n"означає: чи вважає він всі інші літери чи всі інші літери та символи), але обробка підстановок неповна. Без будь-якого пояснення та без жодних відпрацьованих прикладів важко визначити, чи правильні ваші формули, тому ми повинні їх врахувати Як правило, можна записати формулу ймовірності у виразі сум продуктів двочленних коефіцієнтів.
whuber

1
There are mistakes in the calculation of p0: it assumes exactly 1 "b", 2 "o"s, and 1 "t" will be chosen; and then it assumes the choice of the other three letters will be independent of those choices, which it is not. Assuming n=100 is the total number of tiles, the resulting value is larger than it should be (it equals 8/25850.0031). The same mistake is propagated into the calculations of the wildcard probabilities.
whuber

-1

Meh.

γc=b0xcln(x)r=0(c+y1)(c+α)r(c+β)r(c+1)r(c+γ)rxr+

+b0xcr=0(c+γ1)(c+α)r(c+β)r(c+1)r(c+γ)r(1c+γ1+

+k=0r1(1c+α+κ+1c+β+κ+1c+1+κ1c+γ+κ))xr

=b0xcr=0(c+γ1)(c+α)r(c+β)r(c+1)r(c+γ)r(ln x+1c+γ1+

+k=0r1(1c+α+κ+1c+β+κ1c+1+κ1c+γ+κ))xr
.

It's been a while since I looked at how I built my project. And my math may be entirely incorrect below, or correct. I may have it backwards. Honestly, I forget. BUT! Using only binomial combination, without taking into account blank tiles which throws the entire thing out of whack. The simple combination solution without wild.

I asked these questions myself, and built my own scrabble words probability dictionary because of it. You don't need a dictionary of possible words pulled out, only the math behind it and available letters based on letters in tile bag. The array of English rules is below. I spent weeks developing the math just to answer this question for all English words that can be used in a game, including words that can not be used in a game. It may all be incorrect.

The probability of drawing a given word from a bag of letters in Scrabble, requires how many letters are available in the bag, for each letter ( A-Z ) and, whether we're using the wild card as an addition to the math. The blank tiles are included in this math - assuming 100 tiles, 2 of which are blank. Also, how many tiles are available differs based on language of the game, and game rules from around the world. English scrabble differs from Arabic scrabble, obviously. Just alter the available letters, and the math should do the work.

If anyone finds errors, I will be sure to update and resolve them.

Boot: The probability of Boot in a game of scrabble is 0.000386% which is a chance of 67 out of 173,758 hands as shown on the word page for boot.

English Tiles

all is the array of letters in the bag. count is the array of available tiles for that letter, and point is the point value of the letter.

// All arranged by letter, number of letters in scrabble game, and point for the letter.
$all = array("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z");
    $count = array("9", "2", "2", "4", "12", "2", "3", "2", "9", "1", "1", "4", "2", "6", "8", "2", "1", "6", "4", "6", "4", "2", "2", "1", "2", "1");
$point = array("1", "3", "3", "2", "1", "4", "2", "4", "1", "8", "5", "1", "3", "1", "1", "3", "10", "1", "1", "1", "1", "4", "4", "8", "4", "10");

There are 100 tiles in an English scrabble game (i.e., the sum of $count). It does not matter how the tiles are pulled, so it's not a permutation.

The Math I Used Determine how many letters are in the word and what letters are in the word, how many of those letters are available in the tile bag ( count for each letter, unique and allchars ). Binomial coefficient of each, divided by binomial coefficient of length word.

Determine the binomial combinations available

let C(n,r) be binomial coefficient: n!/[n!(n-r)!], or 0 if r > n

Foreach letter, what is the binomial coefficient.

There is 1 "B". There are 2 available, a 2% chance of pulling the b.
There is 2 "O". There are 8 available, a 8% chance of pulling the o.
There is 1 "T". There are 6 available, a 6% chance of pulling the t.
BOOT is a 4 letter word, being taken from a 100 tile set with blanks, 98 without.

n = 98. The number of tiles without blank in the English set

B=(21)=2!2!(21)!
O=(82)=8!8!(82)!
T=(61)=6!6!(61)!

B×O×T divided by the binomial coefficient of tilecount 98!98!(98length)!


It's hard to evaluate your solution without knowing what n and r refer to in the final formula. How do you handle the effect of the blank tiles? That's what makes this a difficult problem. Regardless, it would be interesting to see a demonstration that the value of 38248840160075608000.00239 is incorrect: this was obtained using the R solution I posted. Try this one-second R simulation: let <- c(rep("b", 2), rep("o", 8), rep("t", 6), rep("_", 84)); boot <- function(x) sum(x=="b")>=1 && sum(x=="o")>=2 && sum(x=="t")>=1; mean(replicate(1e5, boot(sample(let, 7))))
whuber

Повторіть редагування: одна очевидна помилка полягає в тому, що ваш розрахунок взагалі не враховує кількість заготовок. Наскільки я можу сказати з ваших формул, якби це число змінилося (від 2 до 50, скажімо), то ваша відповідь не змінилася б. Це, очевидно, неправильно. Ще одна проблема, з якою ви стикаєтеся, - це пояснити, як ваша відповідь може суперечити трьом уже опублікованим відповідям, які використовують три абсолютно різні методи, але згодні між собою (і не згодні з вашими).
whuber

Якщо комбінації - математика є двочленними коефіцієнтами. Отже, нехай x - кількість пустих плиток. Єдина математика, яка змінюється, - це n! - чи використовуються заготовки, чи ні. Якщо так, додайте кількість пустих до n! оскільки пустий дозволяє отримати ще 2 варіанти кожної літери (n + x)! - якщо ні, залиште п! як є. Так? Ні? Якщо пробіли не використовуються залежно від мовного правила, встановленого в цьому випадку англійською мовою, n! = 98 або 100 с. Кожна літера без пробілу - це C (n, r), інше з порожнім C ((n + x), r). У масиві порожній є - але я забув поставити порожній у математиці. Тому просто змініть n на роботу з пробілами. Так?
Джеймс Кордейро

Ні, ваші міркування недійсні. Я запрошую вас спробувати свої формули з меншими числами, щоб ви могли бачити, де вони йдуть не так.
whuber

What do you mean by smaller numbers - whuber? Give me an example. Are you saying pulling boot from a set of 10 letters instead, 1 b, 2 o, 1 t's with a 1 blank in the set and 5 other letters. Or something completely different. I'm no math major, but it seems we've become poker players. We're now calculating poker odds with scrabble tiles that don't have suits.
Джеймс Кордейро
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.