Сколько фишек в домино, или погремим костями
Наверняка, многим с детства знакома игра – домино. Скорее всего, не раз видели, как бабушки и дедушки за столиками у подъездов «режутся» целый день в эту игру. Чем же она так интересна? Откуда она появилась? Сколько фишек в домино? Попытаемся сегодня ответить на все эти вопросы.
История домино
Домино считается одной из разновидностей игры в кости. Считается, что родоначальником всех игровых костей является Индия. В те времена костяшки для игры вырезались из ценных пород древесины. Позволить себе играть в такую игру могла только богатейшая прослойка общества, знать.
Через некоторое время домино и кости стали игрой общедоступной. Сколько фишек в домино было в те времена – никому не известно. Различные источники описывают правила игры и состав домино по-разному. В Китае, к примеру, было более пятидесяти различных костей, в том числе и разноцветные варианты. Кости были не просто набором точек, как в настоящее время. Китайские умельцы делали невероятной красоты кости с изображением животных, иероглифов и т.д. Кстати, именно от китайского домино произошла популярная сегодня игра «Маджонг».
В 18 веке кости «переезжают» в Италию, где их внешний вид и количество претерпевают некоторые изменения. Фишки становятся чуть короче, их количество тоже уменьшается. Итальянцы лишают кости дубликатов, рисунков и оставляют семь фишек и дополнительные кости «пусто».
Набор домино
Итак, давайте разберемся, как же сейчас выглядят современные кости в домино, сколько должно быть фишек в домино. Кости для домино представляют собой слегка удлиненные пластины, на которые нанесены точки. Каждая пластина имеет свое количество этих точек. Всего в стандартном наборе содержится 28 пластинок. Как правило, современное домино изготавливается из пластика. Более дорогие варианты – из древесины, драгметаллов или костей животных.
Если говорить о китайском домино, которое является родоначальником западной версии игры, то оно немного отличается от привычного нам. Сколько фишек в домино в Китае? Китайцы играют в домино, которое состоит из 32 костей. Причем, у них отсутствуют фишки «пусто». Вместо них используются несколько дополнительных дубликатов.
Правила игры
Правила игры довольно просты. Участие принимают от двух до четырех человек. В зависимости от количества игроков берется разное число костей. Сколько фишек берут в домино, если играет два человека? – семь. Сколько фишек, если играет четыре или три человека? – пять. Оставшиеся кости остаются «на базаре», откуда игроки, в случае необходимости, могут их брать по одной.
Итак, каждый из игроков набрал себе необходимое количество костей. Первым ходит тот, у кого в руках большой дубль. Дубль – доминошка с одинаковым количеством точек 6-6, 5-5 и т.д. Если ни у кого нет дублей вообще, то право первого хода у игрока, который имеет косточку с самым большим числом очков.
Далее игроки выкладывают по очереди фишки, составляя цепочку. Каждая следующая кость должна иметь край с количеством точек, совпадающим с предыдущей. Если на концах змейки нет костей с тем числом точек, что имеются у вас, следует идти «на базар».
Многие новички думают, что нужно выставить столько, сколько доминошек в домино всего. Нет. Смысл игры и победы заключается в том, чтобы быстрее закончить выставлять свои фишки. Как только один игрок выставил последнюю игровую кость, игра прекращается.
Подсчет очков
После того как победитель выставил свою последнюю фишку, игроки начинают подсчитывать очки. Как правило, перед началом игры все договариваются, до какого конкретно числа в общем счете будет длиться игра. Обычно игра длится до ста или двухсот очков, но возможны и другие варианты. В зависимости от оговоренного числа меняется и длительность игры.
Бывают случаи, что у всех игроков нет фишек, чтобы закрыть имеющиеся на столе. Этот вариант окончания игры называется «рыба». Здесь победителем будет игрок, который ставил фишки последним или тот, у кого на руках осталось меньшее количество очков.
Разновидности игры
Итак, мы уже знает, откуда появилась эта игра, как в нее играть, сколько фишек в домино и как они выглядят. Но существует несколько разновидностей домино, правила в которых меняются.
Самыми популярными в России являются варианты : «Козел», «Осел»», » Морской козел», «Телефон». Эти варианты отличаются друг от друга количеством допускаемых к полю игроков, разными способами подсчета очков. К примеру, в «Козла» каждый сам за себя, а «Морской козел» предусматривает игру парами.
В Англии более популярна игра в домино под названием «Маггинс». Здесь игра начинается не с привычного нам «дубля», а с любой кости. Счет ведется строго до двухсот очков.
Замощение доминошками / Хабр
Одна из первых действительно интересных задач по математике, с которыми я столкнулся формулируется так: «из шахматной доски вырезали две противоположные по диагонали угловые клетки, можно ли оставшуюся часть разрезать на «доминошки» — фигурки из двух клеток, у которых одна сторона общая?». У нее очень простая формулировка, в отличие от великой теоремы Ферма она имет простое, элегантное, но неочевидное решение (если вы знаете решение задачи, то попробуйте применить его к фигуре справа).
В этой статья я расскажу о нескольких алгоритмах, которые умеют покрывать доминошками произвольную клетчатую фигуру на плоскости, если это возможно, находить ситуации, когда это невозможно и считать количество возможных замощений доминошками.
Nota bene! Материал этой статьи — это усеченный вариант вот этого jupyter-notebook, все картинки и анимации, которые вы увидите в статье, сгенерированы кодом из этого ноутбука (правда анимаций не будет в github предпросмотре). К слову, картинки из заголовка также сгенерированы с помощью python/matplotlib
Вспомогательный код для отрисовки, он еще пригодится
import matplotlib.pyplot as plt from matplotlib import colors as mcolors colors = dict(mcolors.BASE_COLORS, **mcolors.CSS4_COLORS) # Sort colors by hue, saturation, value and name. by_hsv = sorted((tuple(mcolors.rgb_to_hsv(mcolors.to_rgba(color)[:3])), name) for name, color in colors.items()) names = [name for hsv, name in by_hsv if name not in {'black', 'k', 'w', 'white', 'crimson', 'royalblue', 'limegreen', 'yellow', 'orange'}] import random random. shuffle(names) names = ['crimson', 'royalblue', 'limegreen', 'yellow', 'orange', *names] names.append('red') names.append('white') names.append('black')
def fill_cell(i, j, color, ax): ax.fill([i, i, i + 1, i + 1, i], [j, j + 1, j + 1, j, j], color=color) def draw_filling(filling): if filling is not None: n = len(filling) m = len(filling[0]) fig = plt.figure(figsize=(m * 0.75, n * 0.75)) ax = fig.add_axes([0, 0, 1, 1]) ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) for name, spine in ax.spines.items(): spine.set_visible(False) spine.set_visible(False) for i, row in enumerate(filling): i = n - i - 1 for j, cell in enumerate(row): fill_cell(j, i, names[cell], ax) for i in range(n + 1): ax.plot([0, m], [i, i], color='black') for i in range(m + 1): ax.plot([i, i], [0, n], color='black') plt. close(fig) return fig else: return None
Прежде, чем перейти дальше, решение исходной задачи
Сделать это невозможно, и этому есть красивое и простое объяснение:
- На оставшейся части доски 30 черных и 32 белых клетки
- Каждая доминошка состоит из одной черной и одной белой клетки
- Как бы мы не разрезали фигуру на доминошки, в итоге на доминошках будет равное число белых и черных клеток
Динамическое программирование по профилю
Про динамического программирования есть статья на хабре, которая даже содержит пример с покрытием доминошками, я немного расширю этот пример.
Основная суть динамического программирования заключается в том, чтобы придумать для исходной задачи какие-то промежуточные подзадачи так, чтобы их можно было легко друг через друга выразить. Например, если мы хотим вычислить двухсотое число Фибоначчи, то для этого можно последовательно вычислить все числа Фибоначчи вплоть до нужного нам применяя соотношение
Аналогично можно вычислить число «сочетаний» , воспользовавшись одним из следующих рекуррентных соотношений
Для задачи «можно ли замостить доминошками прямоугольник ?» к сожалению подобных простых соотношений не существует. Тем не менее, если мы рассмотрим более широкий класс фигурок, то такие соотношения уже станут возможными, главное чтобы это не были слишком маленькие классы и динамическое программирование не превратилось в банальный перебор.
Посмотрим на следующий класс фигурок: у нас есть прямоугольник , на строке присутствуют первые клеток, остальные задаются профилем, на строке первые клеток задаются профилем, остальные не участвуют. Профиль — это последовательность нулей и единичек длины : если на -ой позиции профиля единичка, это значит что в этой фигуре есть соответствующая клетка, всего профилей (красные клетки — единички, синие — нули).
Профиль однозначно задается числом (его бинарное представление вплоть до разрядов является последовательностей нулей и единичек).
Прямоугольник соответствует фигуре с , и нулевым профилем. На фигурках такого типа мы можем считать две основные функции
- Максимальное возможное число покрытых доминошками клеток в этой фигуре
- Количество способов полностью покрыть доминошками эту фигуру
Давайте обозначим за количество способов замостить такую фигурку, тогда и при этом выражается через сумму нескольких , по большому счету переход от к — это перебор трех случаев: поставить вертикальную доминошку, если это возможно
горизонтальную доминошку, если это возможно
и пропустить занятую клетку. В случае, если мы пытаемся понять, какое максимальное число клеток фигурки возможно замостить, то сумма заменяется на максимум и добавляется один несложный переход — пропуск свободной клетки. Важным моментом также является то, что мы можем заранее вырезать несколько клеток, принципиально от этого ничего не поменяется.
Давайте теперь попробуем реализовать это (кода будет много, так что большинство я вынесу в спойлер). Зададим интересующий нас прямоугольник как множество строк из точек и решеток (точка — свободная клетка, решетка — занятая), пока все клетки будут свободными, потом потихоньку будем какие-нибудь вырезать
tiling = [ '........', '........', '........', '........', '........', '........', '........', '........', ]
Начнем с
количества способов замощений доминошками
def count_tilings(tiling): n = len(tiling) m = len(tiling[0]) if ((n + 1) * m * 2 ** m) <= 10000000: dp = [[[(0 if k != 0 or j != 0 or mask != 0 else 1) for mask in range(2 ** m)] for j in range(m)] for k in range(n + 1)] for k in range(n): for j in range(m): for mask in range(2 ** m): # Вертикальная доминошка if k < n - 1 and tiling[k][j] == '.' and tiling[k + 1][j] == '.' and (mask & (1 << j)) == 0: dp[k + ((j + 1) // m)][(j + 1) % m][mask + (1 << j)] += dp[k][j][mask] # Горизонтальная доминошка if j < m - 1 and tiling[k][j] == '.' and tiling[k][j + 1] == '.' and (mask & (3 << j)) == 0: dp[k + ((j + 1) // m)][(j + 1) % m][mask + (2 << j)] += dp[k][j][mask] # Клетка занята if ((1 << j) & mask) != 0 or tiling[k][j] != '.': dp[k + ((j + 1) // m)][(j + 1) % m][(mask | (1 << j)) - (1 << j)] += dp[k][j][mask] return dp
dp = count_tilings(tiling) print(dp[8][0][0])
получаем
12988816
Сверяемся с википедией, пока все в порядке. Давайте еще на всякий случай проверим, количество способов замостить полоску — должно получиться число Фибоначчи.
tiling_fib = [ '..', '..', '..', '..', '..', '. .', '..', '..' ] dp = count_tilings(tiling_fib) for i in range(8): print(dp[i][0][0], end=' ')
1 1 2 3 5 8 13 21
Что ж, поехали дальше, проверим на доске с вырезанными углами
tiling_no_corners_opposite = [ '.......#', '........', '........', '........', '........', '........', '........', '#.......', ] dp = count_tilings(tiling_no_corners_opposite) print(dp[8][0][0])
0
Супер. Допустим вычислять количество мы научились, может найдем хотя бы одно конкретное замощение для наглядности?
код для получения покрытия
def cover_if_possible(tiling, dp=None): if dp is None: dp = count_tilings(tiling) n = len(dp) - 1 m = len(dp[0]) if dp[n][0][0] == 0: return None result = [[-1 if tiling[i][j] == '#' else 0 for j in range(m)] for i in range(n)] num = 0 k = n j = 0 mask = 0 while k > 0 or j > 0: #print(k, j, mask) prev_j = j - 1 prev_k = k if prev_j == -1: prev_j += m prev_k -= 1 # Начинаем перебирать варианты, каким образом мы могли попасть в i, j, mask # Этот вариант очень не оптимален, но занимает меньше кода и все равно быстрее # самого подсчета динамики for prev_mask in range(2 ** m): if prev_k < n - 1 and tiling[prev_k][prev_j] == '. ' and tiling[prev_k + 1][prev_j] == '.' and \ (prev_mask & (1 << prev_j)) == 0 and (prev_mask + (1 << prev_j)) == mask and dp[prev_k][prev_j][prev_mask] != 0: mask = prev_mask result[prev_k][prev_j] = num result[prev_k + 1][prev_j] = num #print(f'Vertical at ({prev_k}, {prev_j}) ({prev_k + 1}, {prev_j})') num += 1 break elif prev_j < m - 1 and tiling[prev_k][prev_j] == '.' and tiling[prev_k][prev_j + 1] == '.' and (prev_mask & (3 << prev_j)) == 0 and \ prev_mask + (2 << prev_j) == mask and dp[prev_k][prev_j][prev_mask] != 0: mask = prev_mask result[prev_k][prev_j] = num result[prev_k][prev_j + 1] = num #print(f'Horisontal at ({prev_k}, {prev_j}) ({prev_k}, {prev_j + 1})') num += 1 break elif (((1 << prev_j) & prev_mask) != 0 or tiling[prev_k][prev_j] != '.') and \ (prev_mask | (1 << prev_j)) - (1 << prev_j) == mask and dp[prev_k][prev_j][prev_mask] != 0: mask = prev_mask break j = prev_j k = prev_k return result
filling = cover_if_possible(tiling) draw_filling(filling)
Слишком просто, давайте вырежем несколько клеток
tiling_random = [ '........', '#.#.....', '..#.....', '........', '........', '........', '........', '...#....' ] filling_random = cover_if_possible(tiling_random) draw_filling(filling_random)
Попробуем теперь сделать тоже самое для замощения максимальной возможной части фигуры
Код для максимального замощения
def maxmimum_cover(tiling): n = len(tiling) m = len(tiling[0]) if ((n + 1) * m * 2 ** m) <= 10000000: dp = [[[(n * m if k != 0 or j != 0 or mask != 0 else 0) for mask in range(2 ** m)] for j in range(m)] for k in range(n + 1)] for k in range(n): for j in range(m): for mask in range(2 ** m): next_k, next_j = k + ((j + 1) // m), (j + 1) % m # Вертикальная доминошка if k < n - 1 and tiling[k][j] == '. ' and tiling[k + 1][j] == '.' and (mask & (1 << j)) == 0: dp[next_k][next_j][mask + (1 << j)] = min(dp[next_k][next_j][mask + (1 << j)], dp[k][j][mask]) # Горизонтальная доминошка if j < m - 1 and tiling[k][j] == '.' and tiling[k][j + 1] == '.' and (mask & (3 << j)) == 0: dp[next_k][next_j][mask + (2 << j)] = min(dp[next_k][next_j][mask + (2 << j)], dp[k][j][mask]) # Клетка занята if ((1 << j) & mask) != 0 or tiling[k][j] != '.': dp[next_k][next_j][(mask | (1 << j)) - (1 << j)] = \ min(dp[next_k][next_j][(mask | (1 << j)) - (1 << j)], dp[k][j][mask]) # Клетка не занята, рассмотриваем случай её пропуска else: dp[next_k][next_j][(mask | (1 << j)) - (1 << j)] = \ min(dp[next_k][next_j][(mask | (1 << j)) - (1 << j)], dp[k][j][mask] + 1) return dp def cover_maximum_possible(tiling, dp=None): if dp is None: dp = maxmimum_cover(tiling) n = len(dp) - 1 m = len(dp[0]) result = [[-1 if tiling[i][j] == '#' else -2 for j in range(m)] for i in range(n)] num = 0 k = n j = 0 mask = 0 while k > 0 or j > 0: #print(k, j, mask) prev_j = j - 1 prev_k = k if prev_j == -1: prev_j += m prev_k -= 1 # Начинаем перебирать варианты, каким образом мы могли попасть в i, j, mask # Этот вариант очень не оптимален, но занимает меньше кода и все равно быстрее # самого подсчета динамики for prev_mask in range(2 ** m): # Раньше мы здесь проверяли, что количество вариантов в этой ветке не 0, сейчас нужно # проверить, что эта ветка ведет к максимальному покрытию if prev_k < n - 1 and tiling[prev_k][prev_j] == '. ' and tiling[prev_k + 1][prev_j] == '.' and \ (prev_mask & (1 << prev_j)) == 0 and (prev_mask + (1 << prev_j)) == mask and \ dp[prev_k][prev_j][prev_mask] == dp[k][j][mask]: mask = prev_mask result[prev_k][prev_j] = num result[prev_k + 1][prev_j] = num num += 1 break elif prev_j < m - 1 and tiling[prev_k][prev_j] == '.' and tiling[prev_k][prev_j + 1] == '.' and (prev_mask & (3 << prev_j)) == 0 and \ prev_mask + (2 << prev_j) == mask and dp[prev_k][prev_j][prev_mask] == dp[k][j][mask]: mask = prev_mask result[prev_k][prev_j] = num result[prev_k][prev_j + 1] = num num += 1 break elif (((1 << prev_j) & prev_mask) != 0 or tiling[prev_k][prev_j] != '.') and \ (prev_mask | (1 << prev_j)) - (1 << prev_j) == mask and dp[prev_k][prev_j][prev_mask] == dp[k][j][mask]: mask = prev_mask break elif ((1 << prev_j) & prev_mask) == 0 and tiling[prev_k][prev_j] == '. ' and \ (prev_mask | (1 << prev_j)) - (1 << prev_j) == mask and dp[prev_k][prev_j][prev_mask] + 1 == dp[k][j][mask]: mask = prev_mask break j = prev_j k = prev_k return result
И попробуем фигурку из заголовка
tiling_custom=[ '...####', '....###', '......#', '#.#....', '#......', '##.....', '###...#', ] filling = cover_maximum_possible(tiling_custom) draw_filling(filling)
Опа! Не получилось, в общем так и должно было быть. Прежде, чем пойти дальше пару слов о сложности алгоритмов. Всего фигурок , все переходы константные, отсюда асимптотика , которая может быть улучшена до если добавить транспонирование в случае, если . Построение конкретного замощения в приведенных реализациях имеет сложность , но можно сделать так, чтобы было просто , но это банально больше кода.
Замощение с помощью решения задачи о максимальном паросочетании
Возвращаясь к черно-белой раскраске как на шахматной доске можно заметить интересную интерпретацию задачи замощения доминошками. Давайте посмотрим на граф, в котором клетки фигуры — это вершины, ребрами соединены клетки, имеющие общую сторону. Так вот, доминошка в этом графе — это как раз ребро. Если раскрасить граф в шахматном порядке, то внезапно можно обнаружить, что этот граф — двудольный, черные — одна доля, белые — другая. Если переформулировать задачу замощения наибольшего числа клеток в терминах этого графа, то получается, что нужно найти максимальное по размеру множество ребер такое, чтобы вершины являлись концом не более одного ребра. В общем то, это довольно известная задача о максимальном паросочетании. Давайте попробуем её применить для решения этой задачи, тут получится даже с анимацией, приведу базовый алгоритм Куна для нахождения максимального паросочетания.
Реализация алгоритма Куна для паросочетаний на графе доминошек
def check_valid(i, j, n, m, tiling): return 0 <= i and i < n and 0 <= j and j < m and tiling[i][j] != '#' def find_augmenting_path(x, y, n, m, visited, matched, tiling): if not check_valid(x, y, n, m, tiling): return False if (x, y) in visited: return False visited. add((x, y)) for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]: if not check_valid(x + dx, y + dy, n, m, tiling): continue if (x + dx, y + dy) not in matched or find_augmenting_path(*matched[(x + dx , y + dy)], n, m, visited, matched, tiling): matched[(x + dx, y + dy)] = (x, y) return True return False def convert_match(matched, tiling, n, m): result = [[-1 if tiling[i][j] == '#' else -2 for j in range(m)] for i in range(n)] num = 0 for x, y in matched: _x, _y = matched[(x, y)] result[x][y] = num result[_x][_y] = num num += 1 return result def match_with_flow(tiling): result_slices = [] n = len(tiling) m = len(tiling[0]) matched = dict() # Для наглядности визуализации rows = list(range(n)) columns = list(range(m)) random.shuffle(rows) random.shuffle(columns) result_slices.append(convert_match(matched, tiling, n, m)) for i in rows: for j in columns: if (i + j) % 2 == 1: continue visited = set() if find_augmenting_path(i, j, n, m, visited, matched, tiling): result_slices. append(convert_match(matched, tiling, n, m)) return result_slices
Здесь даже получается проанимировать процесс
sequencial_match = match_with_flow(tiling_custom)
Суть алгоритма Куна (да и любого другого алгоритм для нахождения максимального паросочетания) заключается в нахождении «аугментирующих путей». В терминах доминошек это цепочка из доминошек, у которой рядом с доминошками на концах есть по свободной клетке, такие цепочки можно заменить на цепочки большей длины, охватывающие те же клетки и заполняя две свободные клетки рядом с концами цепочки. Более того, основное утверждение, на котором работают все алгоритмы нахождения максимального паросочетания, заключается в том, что если такой цепочки не удается найти, то значит большего замощения нам не получить.
UPD. Для последнего примера простое обоснование на основе черно-белой раскраски не работает. Насколько мне известно, есть два общих критерия для существования полного замощения:
- Теорема Холла (теорема о свадьбах)
Проверка условий этой теоремы вычислительно сложнее, чем построить максимальное паросочетание. - Условие высоты Тёрстона про это я мало что знаю
Недавно меня навели на очень интересную статью про замощения, там в том числе описывается про использовании групп для доказательства невозможности различных замощений.
Бонус! Раскраска планарного графа в 5 цветов.
Для визуализации замощения я использовал отдельный цвет для каждой доминошки. К сожалению некоторые цвета не очень хорошо смотрятся, а некоторые плохо контрастируют друг с другом. В этом случае подобрать цвета для хорошего контраста не так уж просто, особенно если доминошек много. Зато можно использовать меньше цветов: доминошки, которые не находятся рядом друг с другом можно раскрасить в одинаковый цвет, тогда визуально все еще будет понятно, как именно выглядит покрытие. В общем то это классическая задача о раскраске вершин планарного графа. Любой планарный граф можно покрасить в 4 цвета, правда хорошего алгоритма для такой покраски нет. Зато есть довольно простой алгоритм для покраски в 5 цветов, когда правда все еще много, и я его мало тестировал (если необходим 5ый цвет, то возможны баги)
Покраска доминошек в 5 цветов
def color_5(filling): result = [[i for i in row] for row in filling] # Строим граф domino_tiles = [[] for i in range(max(map(max, filling)) + 1)] domino_neighbours = [set() for i in range(max(map(max, filling)) + 1)] degree = [0 for i in range(max(map(max, filling)) + 1)] n = len(filling) m = len(filling[0]) for i, row in enumerate(filling): for j, num in enumerate(row): if num >= 0: domino_tiles[num]. append((i, j)) for i, tiles in enumerate(domino_tiles): for x, y in tiles: for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)]: a, b = x + dx, y + dy if 0 <= a and a < n and 0 <= b and b < m and filling[a][b] >= 0 and filling[a][b] != i \ and filling[a][b] not in domino_neighbours[i]: domino_neighbours[i].add(filling[a][b]) degree[i] += 1 # Первым делом нужно найти такой порядок вершин, все вершины имели не больше 5 соседей среди # предыдущих. Такой существует в силу того, что граф планарный, а найти его эффективнее всего # по очереди находя вершину наименьшей степени и удаляя её из графа, так мы получаем обратный порядок active_degrees = [set() for i in range(max(degree) + 1)] for i, deg in enumerate(degree): active_degrees[deg].add(i) reversed_order = [] for step in range(len(domino_tiles)): min_degree = min([i for i, dominoes in enumerate(active_degrees) if len(dominoes) > 0]) domino = active_degrees[min_degree]. pop() reversed_order.append(domino) for other in domino_neighbours[domino]: if other in active_degrees[degree[other]]: active_degrees[degree[other]].remove(other) degree[other] -= 1 active_degrees[degree[other]].add(other) # Теперь перебираем в обратном порядке и либо красим в еще не занятый цвет, # если есть свободный из 5 цветов, иначе находим цепочку из чередующихся цветов, # которые могут быть перекрашены. Такая найдется в силу планарности colors = [-1 for domino in domino_tiles] slices = [draw_filling(result)] for domino in reversed(reversed_order): used_colors = [colors[other] for other in domino_neighbours[domino] if colors[other] != -1] domino_color = len(used_colors) for i, color in enumerate(sorted(set(used_colors))): if i != color: domino_color = i break if domino_color < 5: colors[domino] = domino_color for x, y in domino_tiles[domino]: result[x][y] = domino_color slices. 1 for x, y in domino_tiles[other]: result[x][y] = color[other] color[domino] = c for x, y in domino_tiles[domino]: result[x][y] = c slices.append(draw_filling(result)) return result, slices
Если вы собираетесь использовать этот код, то обратите внимание, что там происходит отрисовка каждого шага — это было нужно для анимации, что сильно замедляет алгоритм. Если вам нужна только конечная покраска, то уберите весь код, задействующий переменную slices.
Ну и наконец попробуем один из примеров, который был чуть раньше
Основные правила — Справочный центр Dominoes
Главная / Геймплей и настройки
Основные правила
Последнее обновление: 272d
ОбзорИгра в домино проходит в течение нескольких раундов. Каждый раунд начинается с раздачи плиток каждому игроку, чтобы можно было сделать первый ход. После этого оба игрока по очереди сопоставляют и вытягивают плитки, пока один из них не очистит свою руку или пока не останется больше плиток. Победителю каждого раунда начисляются очки в зависимости от силы руки его оппонента, а первый игрок, набравший 100 очков (или 150, в зависимости от ваших настроек), объявляется победителем игры. Если ни один игрок не достигает необходимого порога очков для победы в игре, начинается следующий раунд.
Общие
В домино играют 2 игрока и используют 28 костей. Каждая плитка имеет два значения пункта в диапазоне от 0 до 6. В начале игры все 28 плиток смешиваются вместе и каждому игроку раздается по 7 плиток. Оставшиеся 14 плиток становятся кладбищем.
Ходы игроковВ первом раунде каждой новой игры игрок с двойным тайлом с наибольшим значением ходит первым (если ни у одного из игроков нет дублей, первым ходит игрок с тайлом с наибольшим значением). Они должны сыграть этот дубль, чтобы начать игру. После первого раунда первый игрок каждого раунда меняется между обоими игроками. Начиная со второго раунда, игрокам больше не нужно разыгрывать дубль в качестве первого тайла. Они могут начать раунд с любой плитки по своему выбору.
Все пятерки и режим розыгрышаДомино имеет два игровых режима: все пятерки и ничья. В Draw игроки могут набирать очки только в конце каждого раунда, а в All Fives игроки также могут набирать очки во время раунда. Draw обычно разыгрывается до 100 очков, а All Fives обычно разыгрывается до 150 очков (оба этих значения можно изменить в настройках).
Совпадение плитокПосле того, как первая плитка была размещена, другой игрок должен положить плитку, число точек которой совпадает хотя бы с одним концом ранее сыгранной плитки. Если у плитки есть пустая сторона, эту плитку можно сыграть только с пустой стороны другой плитки. В режиме «Все пятерки», если сумма значений на открытых концах костей домино кратна пяти, игрок, поставивший последнюю костяшку домино, получает очки, соответствующие стоимости этих пунктов.
СпиннерыВ режиме «Все пятерки» первое двойное размещение называется спиннером. Спиннер — это особая плитка, которую можно разыгрывать во всех четырех направлениях, а не в двух стандартных. Верх и низ спиннера можно использовать только после того, как были использованы левая и правая стороны. В каждом раунде есть только один спиннер, любые другие размещенные дубли можно разыгрывать только с левой и правой сторон.
МогильникЕсли у игрока в руке нет пригодных для игры костяшек домино, он должен тянуть из кладбища до тех пор, пока он не появится. Кладбище состоит из 14 тайлов, которые лежат лицевой стороной вниз. Если кладбище пусто и игрок не может разыграть ни одной плитки, он должен пройти.
Типы победВ домино доступно три типа побед в различных режимах.
Наиболее распространенный тип, победа в домино, когда игрок успешно убирает все костяшки домино из своей руки раньше своего противника. Когда это происходит, стоимость всех костяшек домино, оставшихся в руке другого игрока, суммируется и присуждается победителю раунда.
Другой тип победы, Блок-победа, происходит, когда оба игрока не могут больше класть плитки, а кладбище также пусто. Сумма рук обоих игроков суммируется, и игрок с наименьшей стоимостью руки объявляется победителем раунда. Затем стоимость руки победителя вычитается из стоимости проигравшего, и ему присуждается разница.
Последний тип, победа в середине раунда, может быть достигнут только при игре в All Fives. Это происходит, когда игрок набирает количество очков, необходимое для завершения игры в середине раунда. Это достигается за счет набора очков на доске путем формирования числа, кратного пяти.
Нужна дополнительная помощь?
Свяжитесь с нами
Как играть в домино «Мексиканский поезд» (двойной-9 и двойной-12): Правила игры
Любимая игра наших клиентов, «Мексиканский поезд» — популярная и веселая игра для 2-10 игроки, играющие в домино. Мы создали наши игральные карты Double 12 Travel Domino специально для игры «Мексиканский поезд» с 10 карточками поездов и кратким руководством. Это полные правила игры, таблица результатов, которую можно распечатать бесплатно, а также немного истории игры:
История игры «Мексиканский поезд»
Как и в игре «Куриная лапка», «Мексиканский поезд» — это сравнительно недавняя разновидность домино, которая стала очень популярной, особенно в США. Из-за своей простоты и интерактивности в нее может играть практически любой и где угодно. Он может длиться от одной 20-минутной игры до 12-часовой игры, в которую играют от 2 до 10+ игроков или команд.
«Мексиканский поезд» можно играть со стандартным набором домино, но фирменные версии обычно включают ряд деталей и аксессуаров, предназначенных в основном только для развлечения, которые облегчают игру и подчеркивают тему, например, вокзал, элементы в форме поезда, отмечать поезда игроков и «мексиканский поезд» и «у-у-у!» свисток поезда.
Почему его называют «мексиканским поездом»?
Короче говоря, никто толком не знает. Есть много теорий. Кто-то предположил, что связь игры с кубинской игрой под названием «Лонгана» могла заставить людей путать одну страну с другой. Популярная теория состоит в том, что его изобрели мексиканские железнодорожники. Мы спросили некоторых друзей в Мексике, но они никогда не слышали об этом!
Как играть в домино «Мексиканский поезд» – правила игры
Подготовка к игре
- Соберите свои домино, игроки, по одному жетону поезда на каждого игрока, ручку и бумагу. Назначьте секретаря.
- Перетасуйте костяшки домино, перевернув их вверх ногами, чтобы не было видно точек, и перемещайте их по кругу, пока не убедитесь, что они случайные (т. н. «перетасовка Монако»)
- Руководство» ниже, чтобы определить, какой размер набора костяшек вам нужен для количества игроков и сколько костяшек должен вытянуть каждый игрок. «D-9» относится к двойному домино 9, а «D-12» относится к двойному 12 домино.
- После того, как каждый игрок вытащил свои костяшки домино, оставшиеся кладутся стопкой в сторону, которая находится в пределах досягаемости, которая называется The Boneyard
Цель игры
Цель игры — набрать наименьшее количество очков после всех раздач.
Цель каждой игры Hand — стать первым игроком, разместившим все свои костяшки домино. Раздача разыгрывается для каждого числа в наборе домино (например, есть 13 раздач с двойными 12 домино (0-12) и 10 раздач с двойными 9 домино (0-9).
Начало игры: первый ход
Двигатель
- Игра начинается с того, что игрок, вытащивший самую высокую двойную костяшку в наборе (например, 12/12 для двойной 12 или 9/9 для двойной 9), кладет ее в центр стола. Стартовый двойник называется Паровоз , и его можно по желанию разместить на узле под названием Станция , чтобы отличать его от других костяшек домино.
- Если ни у одного из игроков нет Паровозика, игроки по очереди тянут его из Могильника, пока он не будет найден. (Примечание: некоторые игроки предпочитают класть требуемую двойную карту лицевой стороной вверх на стол перед перемешиванием. В этом случае игроки начинают по очереди.)
Поезда
- Игрок, разместивший Паровозик, начинает строить свой Поезд , который представляет собой одну линию домино, начинающуюся с Паровозика в центре стола и простирающуюся к игроку. Концы соседних костяшек должны совпадать по количеству, включая домино, примыкающее к паровозу. Только в этот первый ход игрок может разыграть столько костяшек домино, сколько пожелает, при условии, что они образуют действующий поезд. Один поезд может выглядеть так:
- Поезд может быть до тех пор, пока игроки могут его сделать; он заканчивается только тогда, когда все домино, которые могут соответствовать его конечной точке, уже сыграны. В результате поезда могут стать довольно длинными, особенно с расширенным набором домино. Допустимо «изгибать» поезд на 90° или 180°, чтобы поезд оставался на игровой поверхности, если он не мешает концам других поездов.
- Продолжая движение по часовой стрелке вокруг стола, каждый игрок затем строит свой поезд, также начиная с Паровозика в центре стола.
- Если какой-либо игрок не может запустить свой Поезд из-за того, что у него нет домино, соответствующего Паровозику, он должен просто поместить свой Жетон Поезда (объяснение ниже) в положение, с которого должен был начаться его Поезд. Они не черпают из Могильника.
- Игрок может закончить свой первый ход в поезде двойником, поставленным перпендикулярно, который затем должен быть «удовлетворен» — см. подробнее ниже о двойнике .
- Иногда игрок может разыграть все свои плитки в первый ход. В этом случае игра не заканчивается сразу, а продолжается до тех пор, пока все игроки не сделают свой первый ход. После этого подсчитываются баллы (см. ниже).
- После первого хода, в котором все, если возможно, начали свой поезд, правила игры меняются. Теперь каждый игрок размещает только одну костяшку костяшки за ход (за исключением 90 107 двойных 90 108 , подробнее см. ниже), сопоставляя соседние концы.
- Игроки должны поставить домино в свой ход, если это возможно. (Игроки не могут тянуть с кладбища, если у них есть подходящее домино).
- В свой ход игрок может поставить одну костяшку (или двойную…) на одно из трех мест:
- на собственном «частном» / «закрытом» поезде игрока или
- на «открытом» поезде другого игрока, если он доступен. Поезд другого игрока доступен, если он помечен жетоном поезда , чтобы показать, что его владелец не смог сыграть на нем в последний ход, или
- в «общественном» / «открытом» поезде, известном как . Мексиканский поезд , который всегда доступен для всех игроков, как описано ниже.
- Если у игрока нет подходящей костяшки ни для одного доступного поезда, игрок должен взять костяшку из Могильника.
- Если Могильник пуст, игрок должен просто пройти и поместить жетон на свой поезд, как описано ниже.
- Если в вытащенное домино можно играть, игрок должен сыграть в него.
«Открытые» и «закрытые» — Маркировка поездов жетонами
- Если игрок не может играть в домино, вытащенное игроком, и игрок не может играть где-либо на доске, игрок должен пройти и положить на нее жетон поезда. его Поезд, что указывает на то, что его/ее Поезд теперь «открыт» и любой игрок может добавить в него костяшку домино. Открытые/закрытые поезда также иногда называют «общественными»/«частными».
- Жетоны поездов обычно представляют собой никель или пенни, а некоторые наборы мексиканских поездов содержат специальные жетоны поездов или карточки поездов. (Наш набор Double 12 Travel Domino включает 10 карточек поездов, которые можно использовать в качестве жетонов. )
- Игрок, на чьем поезде есть жетон, может играть как обычно на любом доступном поезде, включая Мексиканский поезд, как обычно.
- Игрок может «закрыть» свой Поезд и удалить жетон, который удаляется только тогда, когда он снова помещает домино на свой Поезд. Как только жетон будет удален, другие игроки больше не смогут добавлять в этот поезд.
- Если владелец отмеченного поезда с жетоном на нем добавляет домино к отмеченному поезду другого игрока, все маркеры остаются на месте, изменений нет.
- Если игрок не смог запустить свой Поезд в первом ходе, но в позднем ходе вытянул совпадающую костяшку, игрок может начать свой Поезд по правилу последующих ходов одно домино (или двойное ) за ход и уберите жетон со своего поезда). Невозможность запустить поезд с первого хода лишает игрока возможности разыграть сразу серию соединяющихся костей домино.
Мексиканский поезд
- Мексиканский поезд — это дополнительный поезд, который является «открытым»/«общедоступным» на протяжении всей раздачи, и играть на нем может любой желающий.
- Мексиканский поезд запускается любым игроком, начиная со второго хода, начиная с одной кости домино, соответствующей паровозику. На него ставится маркер, чтобы отличить его от других поездов и показать, что он открыт для всех игроков. Весь макет с закрытыми поездами для четырех игроков и мексиканским поездом может выглядеть примерно так:
Парные игры
Играющие парные игры
- Двойные домино (0/0, 1/1, 2/2 и т. д.) размещаются перпендикулярно поезду в соответствии с предпочтениями игроков, но они не являются «ветвящимися» дублями — то есть они не создают пересечения, и игрок не может начать новый ряд костяшек с дубля. (Разветвление является отличительным правилом в «Куриной лапке», но не в «Мексиканском поезде».)
- Начиная со второго хода, всякий раз, когда игрок ставит дубль, он также должен разыграть дополнительное домино, которое может находиться в любом месте на доступной для игры раскладке, но не обязательно на дубле, который только что поставил игрок.
- Если вторая выложенная костяшка костяшки является второй двойной, игрок должен положить третью костяшку и так далее.
- Если игрок не может поставить вторую костяшку костяшки, как и прежде, когда игроки не могут поставить костяшку костяшки, они должны взять из Могильника (если есть). Если вытянутая плитка не может быть использована, игрок должен пройти и положить жетон на свой поезд.
- Двойной ход заканчивается после размещения одной костяшки домино, которая не является двойной, или (не имея возможности сделать это) помечая свой Поезд жетоном.
Удовлетворение двойников
- Если двойник остался в конце поезда без соседней с ним дополнительной костяшки домино, то он не был «удовлетворен».
- Такая ситуация возникает в нескольких случаях:
- игрок двойки не смог поставить еще одну костяшку, или
- игрок двойки поставил вторую костяшку на другой поезд, или
- игрок поставил еще одну костяшку чем один дубль — и наличие только одного бесплатного хода не может удовлетворить более одного из них.
- Если дубль не был «удовлетворен», то после окончания хода этого игрока следующее добавленное в раскладку домино должно быть сыграно на дубле. Это называется «удовлетворением» двойника.
- Обязанность удовлетворить двойную сумму ложится первым на следующего игрока. Если они могут удовлетворить двойную сумму, они должны это сделать, даже если это будет в частном поезде, где они обычно не могли бы играть.
- Если второй игрок не может удовлетворить двойную сумму из своей руки, он должен тянуть из Boneyard (если есть), и если это также не соответствует двойному, он должен пройти и поместить жетон на свой поезд (если нет один уже на нем).
- Если второй игрок все еще не может удовлетворить двойную сумму, то обязанность удовлетворить двойную сумму переходит к следующим игрокам по очереди.
- Если игрок оставляет несколько дублей неудовлетворенными в конце хода, каждый из выставленных дублей должен быть удовлетворен последующими игроками в том порядке, в котором они были сыграны.
- Если один или несколько игроков заканчивают поезд, в который они играют в свой первый ход, дублем, то эти дубли должны быть удовлетворены, чтобы как только все сделали свой первый ход, то есть начиная со второго хода первого игрока .
- Единственным исключением является последний ход, если самая последняя выложенная костяшка домино является двойной, рука немедленно завершается и подсчитывается.
Завершение раздачи
- Игра продолжается по часовой стрелке слева, пока первый игрок не разыграет все свои костяшки домино. Это немедленно завершает раздачу.
- Иногда Могильник пуст, а у игроков остаются костяшки домино, но расклад становится «заблокированным», так что никто не может играть, что завершает Раздачу.
- Каждый игрок получает в качестве штрафных очков количество косточек на оставшихся костяшках домино. Например, игрок, оставшийся с 6/7 и 2/3, получит 18 очков (6+7+2+3=18). Игрок, у которого закончились кости домино, не получает штрафных очков за эту игру.
- Счета можно записывать на листе бумаги или использовать нашу бесплатную распечатанную таблицу результатов игры «Мексиканский поезд» на полстраницы:
Победа
- Последующие раздачи будут начинаться со следующего выпавшего двойного домино, например, 11/11 с удвоением 12 или 8/8 с удвоением 9 в качестве нового двигателя, затем 10/10 и так далее до двойного пробела 0/0 для последняя Рука.
- Полная игра будет состоять из 13 раздач с двойными 12 домино (0-12) и 10 раздач с двойными 9 домино (0-9).
- В конце раздачи 0/0 игрок с наименьшим общим счетом становится победителем!
Вариации
Существует множество вариантов правил и ярлыков, позволяющих сделать игру короче или длиннее, проще или сложнее. Нам очень понравились четко написанные правила и варианты, задокументированные на Pagat.com, а также на Wikipedia и Board Game Geek.
«Мексиканский поезд» — отличная игра для вечеринок и встреч. Количество игроков можно варьировать, игру легко запускать и останавливать, а затем возобновлять. Нам нравится разыгрывать раздачу или две раздачи каждый день за обедом, превращая Игру в непрерывное событие в течение нескольких дней или даже недель, только вдвоем, а на вечеринках людям очень легко приходить и уходить из игры без необходимости начать сначала. Он гибкий для до 10 игроков (и, возможно, больше, если вы проявите творческий подход, особенно с командами!). Попробуйте и дайте нам знать, что вы думаете!
Мы разработали наши игральные карты Double 12 Travel Domino специально для мексиканского поезда, любимой игры наших клиентов по всему миру. Вдохновленные ими, мы создали уникальное рисованное издание с аксессуарами «Мексиканский поезд», в котором вы сможете играть на ходу с участием до 10 человек ростом всего 1,75 дюйма и весом 1,5 унции!
Игральные карты Double 12 Travel Domino
В нашей дорожной версии домино Double 12 используется самый эффективный материал для путешествий: игральные карты!
Наш набор домино, специально разработанный для мексиканского поезда, включает 10 карточек поезда для жетонов и краткое руководство по началу игры.
Наш дизайн игральных карт домино напечатан на игральных картах размера 1/4, нарисован от руки и имеет уникальные цвета точек и инновационные угловые номера для раскладывания карт веером одной рукой.
Купить домино Double 12 Travel >>>
Играйте в домино и другие игры о путешествиях на ходу с семьей и друзьями, используя наши креативные версии ручной работы для путешествий. Ознакомьтесь со всеми нашими играми о путешествиях ручной работы:
Shop Travel Dominoes
О Walnut Studiolo
Walnut Studiolo изготавливает оригинальные современные модели вручную в нашей мастерской в Орегоне, используя только натуральные материалы. Мы семейная компания, расположенная на побережье Северного Орегона. Узнайте больше о нас на нашем веб-сайте: https://walnutstudiolo.com
Подпишитесь на нашу рассылку, чтобы получать больше подобных публикаций, ежемесячную рассылку семинаров и скидку 10% на первый заказ. Узнайте первыми о нашей популярной ежегодной распродаже «КАК ЕСТЬ» для друзей и семьи.