Алгоритм смешивания цветов на 7 отдельных частях игрушки

Я плотник, пытаюсь найти здесь помощь по математике и алгоритмам.

Я пытаюсь сделать 28 наборов Танграма для подарков родственникам, вот так:

введите описание изображения здесь

DanielHolth + RobotE по адресу nl: Wp [CC BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0/)]]»rel= из Wikimedia Commons

Игрушка состоит из 7 деревянных досок, которые необходимо раскрасить в индивидуальные цвета. Чтобы упростить рисование, я думаю, что лучший способ - раскрасить их партиями по 4 набора в один и тот же цвет, а затем смешать их.

Я пометил части 1-7, чтобы облегчить обсуждение:

введите описание изображения здесь

Как наиболее эффективно смешивать детали, чтобы в каждом наборе не было одинаковой цветовой комбинации? Хочется, чтобы подарок был максимально индивидуальным, а сочетание цветов - хороший способ достичь этой цели.

Изменить: каждый набор головоломок состоит из семи частей разного цвета.


person Tianhe Hou    schedule 05.02.2019    source источник
comment
Я добавил еще один решатель с гораздо более случайным назначением к моему ответу, который также позволяет настроить вес, присвоенный конкретным парам, для которых мы предпочли бы минимизировать совпадения (несколько верхних строк во втором фрагменте кода). Когда я играл с ним, один из результатов казался особенно низким при столкновениях; Я включил это в конце.   -  person גלעד ברקן    schedule 10.02.2019


Ответы (3)


Расположите цвета каким-либо образом (скажем, R -> G -> B -> Y -> P -> O -> W), а затем расположите свои части аналогичным образом (что вы уже сделали на своей картинке, 1-7). Выложите их в виде матрицы, поместив каждый цвет в отдельную строку (повторяя столбцы / части, поскольку у каждого будет 4 дубликата). Пусть B3 обозначает синий 3 кусок, O7 оранжевый 7 и т. Д.

     1  2  3  4  5  6  7   1  2  3  4  5  6  7   1  2  3  4  5  6  7   1  2  3  4  5  6  7  
(R)  R1 R2 R3 R4 R5 R6 R7  R1 R2 R3 R4 R5 R6 R7  R1 R2 R3 R4 R5 R6 R7  R1 R2 R3 R4 R5 R6 R7
(G)  G1 G2 G3 G4 G5 G6 G7  G1 G2 G3 G4 G5 G6 G7  G1 G2 G3 G4 G5 G6 G7  G1 G2 G3 G4 G5 G6 G7
(G)  B1 B2 B3 B4 B5 B6 B7  B1 B2 B3 B4 B5 B6 B7  B1 B2 B3 B4 B5 B6 B7  B1 B2 B3 B4 B5 B6 B7
(Y)  Y1 Y2 Y3 Y4 Y5 Y6 Y7  Y1 Y2 Y3 Y4 Y5 Y6 Y7  Y1 Y2 Y3 Y4 Y5 Y6 Y7  Y1 Y2 Y3 Y4 Y5 Y6 Y7
(P)  P1 P2 P3 P4 P5 P6 P7  P1 P2 P3 P4 P5 P6 P7  P1 P2 P3 P4 P5 P6 P7  P1 P2 P3 P4 P5 P6 P7
(O)  O1 O2 O3 O4 O5 O6 O7  O1 O2 O3 O4 O5 O6 O7  O1 O2 O3 O4 O5 O6 O7  O1 O2 O3 O4 O5 O6 O7
(W)  W1 W2 W3 W4 W5 W6 W7  W1 W2 W3 W4 W5 W6 W7  W1 W2 W3 W4 W5 W6 W7  W1 W2 W3 W4 W5 W6 W7

Теперь выньте нижний левый «треугольник» из фигур. То есть - убрать 0 штук из начала первого ряда, 1 из второго, 2 из третьего ...

     1  2  3  4  5  6  7   1  2  3  4  5  6  7   1  2  3  4  5  6  7   1  2  3  4  5  6  7  
(R)  R1 R2 R3 R4 R5 R6 R7  R1 R2 R3 R4 R5 R6 R7  R1 R2 R3 R4 R5 R6 R7  R1 R2 R3 R4 R5 R6 R7
(G)     G2 G3 G4 G5 G6 G7  G1 G2 G3 G4 G5 G6 G7  G1 G2 G3 G4 G5 G6 G7  G1 G2 G3 G4 G5 G6 G7
(B)        B3 B4 B5 B6 B7  B1 B2 B3 B4 B5 B6 B7  B1 B2 B3 B4 B5 B6 B7  B1 B2 B3 B4 B5 B6 B7
(Y)           Y4 Y5 Y6 Y7  Y1 Y2 Y3 Y4 Y5 Y6 Y7  Y1 Y2 Y3 Y4 Y5 Y6 Y7  Y1 Y2 Y3 Y4 Y5 Y6 Y7
(P)              P5 P6 P7  P1 P2 P3 P4 P5 P6 P7  P1 P2 P3 P4 P5 P6 P7  P1 P2 P3 P4 P5 P6 P7
(O)                 O6 O7  O1 O2 O3 O4 O5 O6 O7  O1 O2 O3 O4 O5 O6 O7  O1 O2 O3 O4 O5 O6 O7
(W)                    W7  W1 W2 W3 W4 W5 W6 W7  W1 W2 W3 W4 W5 W6 W7  W1 W2 W3 W4 W5 W6 W7

Затем разместите эти дополнительные предметы в концах соответствующих строк. Теперь просто возьмите первый кусок из каждого ряда и сделайте новый набор. Вы можете повторить это 7 раз, прежде чем оно повторится. Для ясности, в приведенном выше примере ваш первый набор будет R1 G2 B3 Y4 P5 O6 W7, второй набор R2 G3 B4 Y5 P6 O7 W1.

После этого повторите процесс еще раз - удалите 0 из первой строки, 1 из второй и т. Д. Снова переместите дополнительные элементы в концы их строк и нарисуйте 7 новых наборов из первых элементов каждой строки. Повторите этот процесс еще дважды для последних двух партий по 7 подходов в каждой. Каждый набор будет уникальным.

person Dillon Davis    schedule 05.02.2019
comment
Чувак, это так гениально, мне это нравится! И это достаточно просто для выполнения в цехе. Спасибо Спасибо. - person Tianhe Hou; 05.02.2019
comment
Обратите внимание, что в этом шаблоне повторяются последовательности цветов. (Я не говорю, что это плохо, просто указываю на это.) - person גלעד ברקן; 06.02.2019

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

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

from itertools import combinations, permutations
from random import shuffle

def get_subsets(color_set):
    subsets = []
    for d in ({}, {'1':'5'}, {'4':'6'}, {'1':'5', '4':'6'}):
        tr = lambda s: str.translate(s, str.maketrans(d))
        subsets.extend(set(tr(y) for y in x) for x in combinations(color_set, 3))
    return subsets

def make_sets(do_random=True):
    color_sets = [set(c+str(i) for i, c in enumerate(perm)) for perm in permutations("RGBYPOW")]

    results, pairs = [], []
    while color_sets:
        results.append(color_sets[0])
        pairs.extend(get_subsets(color_sets[0]))
        color_sets = [x for x in color_sets if all(y - x for y in pairs)]
        if do_random: shuffle(color_sets)

    results = sorted(sorted(perm, key=lambda x:x[1]) for perm in results)
    print("\n".join(map(str, results)))
    print(len(results))

if __name__ == "__main__":
    make_sets()

Пример вывода:

['B0', 'G1', 'O2', 'W3', 'P4', 'R5', 'Y6']
['B0', 'P1', 'W2', 'Y3', 'O4', 'G5', 'R6']
['B0', 'R1', 'W2', 'O3', 'G4', 'P5', 'Y6']
['B0', 'R1', 'Y2', 'P3', 'W4', 'O5', 'G6']
['B0', 'W1', 'R2', 'G3', 'O4', 'Y5', 'P6']
['G0', 'B1', 'O2', 'P3', 'R4', 'W5', 'Y6']
['G0', 'B1', 'R2', 'W3', 'Y4', 'O5', 'P6']
['G0', 'O1', 'P2', 'B3', 'W4', 'R5', 'Y6']
['G0', 'O1', 'Y2', 'R3', 'B4', 'W5', 'P6']
['G0', 'P1', 'O2', 'Y3', 'B4', 'R5', 'W6']
['G0', 'W1', 'P2', 'O3', 'R4', 'Y5', 'B6']
['O0', 'B1', 'Y2', 'W3', 'R4', 'P5', 'G6']
['O0', 'G1', 'R2', 'Y3', 'W4', 'P5', 'B6']
['O0', 'P1', 'G2', 'R3', 'Y4', 'B5', 'W6']
['O0', 'R1', 'B2', 'G3', 'P4', 'W5', 'Y6']
['P0', 'B1', 'R2', 'O3', 'W4', 'Y5', 'G6']
['P0', 'R1', 'G2', 'W3', 'B4', 'Y5', 'O6']
['P0', 'W1', 'B2', 'Y3', 'O4', 'R5', 'G6']
['P0', 'W1', 'G2', 'B3', 'Y4', 'O5', 'R6']
['R0', 'G1', 'B2', 'Y3', 'P4', 'O5', 'W6']
['R0', 'O1', 'P2', 'Y3', 'G4', 'W5', 'B6']
['R0', 'Y1', 'W2', 'P3', 'G4', 'B5', 'O6']
['W0', 'G1', 'B2', 'P3', 'R4', 'Y5', 'O6']
['W0', 'O1', 'P2', 'G3', 'Y4', 'B5', 'R6']
['W0', 'R1', 'Y2', 'G3', 'O4', 'P5', 'B6']
['W0', 'Y1', 'G2', 'O3', 'B4', 'P5', 'R6']
['W0', 'Y1', 'O2', 'R3', 'P4', 'G5', 'B6']
['Y0', 'B1', 'P2', 'R3', 'W4', 'G5', 'O6']
['Y0', 'G1', 'W2', 'O3', 'B4', 'R5', 'P6']
['Y0', 'O1', 'B2', 'G3', 'R4', 'P5', 'W6']
['Y0', 'P1', 'R2', 'B3', 'G4', 'W5', 'O6']
31
person Dillon Davis    schedule 06.02.2019
comment
Я добавил к своему ответу еще один решатель с гораздо более случайным назначением (также немного настраиваемым). Один из результатов казался довольно хорошим, поэтому я тоже включил его (у него было только два совпадения 4,6 и одно совпадение 1,5 и относительно мало последовательных парных совпадений). - person גלעד ברקן; 10.02.2019

Ради забавы, вот код, который пытается минимизировать, без исчерпывающего поиска, количество последовательных цветовых пар, которые могут сосуществовать в одной и той же позиции, в попытке ответить на ваш запрос «как можно более индивидуально». В нем есть элемент случайности. Иногда это может привести к дублированию тройной последовательности, но в лучшем случае мы получаем только парные дубликаты. (Может быть, шанс, что получатели найдут сходство между своими подарками, будет частью красоты.)

(Диллон Дэвис прокомментировал, что он может создавать идентичные пары для позиций 1 и 5 или 4 и 6, которые кажутся заметными похожими треугольниками в дизайне. Я могу внести в это изменение немного позже, чтобы в первую очередь избегать этих дубликатов.)

let cs = ['R', 'G', 'B', 'Y', 'P', 'O', 'W'];

let pairs = [];

for (let i=0; i<6; i++)
  for (let j=i+1; j<7; j++)
    pairs.push(cs[i] + cs[j], cs[j] + cs[i]);

let positionMatches = [];
const results = pairs.slice(0, 28);

// Build combinations
for (let i=0; i<5; i++){
  // Avoid repeating pairs
  // in the same position
  let set = new Set();

  for (let j=0; j<28; j++){
    const last = results[j].substr(-1);
    let found = false;

    for (let c of cs){
      const candidate = last + c;

      // Match found
      if (!set.has(candidate) && !results[j].includes(c)){
        results[j] += c;
        set.add(candidate);
        found = true;
        break;
      }
    }
    // Match not found
    // Lower the restriction
    // and insert random match
    if (!found){
      const cs_ = cs.filter(
        c => !results[j].includes(c));
      const c = cs_[
        ~~(Math.random()*cs_.length)];
      results[j] += c;
      positionMatches.push((i+2) + ':' + last + c);
    }
  }
}

console.log(results.join('\n'));

console.log('');

for (let p of positionMatches){
  const [pos, pair] = p.split(':');
  console.log(pair + ' duplicate at position ' + pos)
}

ОБНОВИТЬ

Вот решатель с гораздо большим количеством случайных назначений, чем приведенный выше, который является более последовательным и, следовательно, предсказуемым. Мы можем установить пары, которые мы хотели бы «не сопоставить» на карте unmatch, и контролировать, насколько больше мы хотели бы пробовать случайных кандидатов при проверке специально выбранных несовпадающих пар или других пар (мы можем захотеть придать больший вес бывший, чтобы позволить им попробовать больше случайных кандидатов). Один результат, который казался мне довольно хорошим, когда я играл, приведен ниже (он был достигнут с той же случайной настройкой 50/50). Нажимайте «Выполнить сниппет», чтобы каждый раз получать разные результаты!

const unmatch = {
  // Try to avoid duplicate pairs
  // at indexes (0, 4) and (3, 5)
  4: 0,
  5: 3
};
const unmatchTrials = 50;
const regularTrials = 50;

let cs = ['R', 'G', 'B', 'Y', 'P', 'O', 'W'];
let pairs = [];

for (let i=0; i<6; i++)
  for (let j=i+1; j<7; j++)
    pairs.push(cs[i] + cs[j], cs[j] + cs[i]);

let positionMatches = [];
const results = pairs.slice(0, 28);

// Build combinations
for (let i=0; i<5; i++){
  // Avoid repeating pairs in the same position,
  // as well as in custom positions
  let set = new Set();
  let unmatchS = new Set();

  for (let j=0; j<28; j++){
    const last = results[j].substr(-1);
    let found = false;
    const ri = i + 2;
    let count = unmatch.hasOwnProperty(ri) ? unmatchTrials : regularTrials;

    while (!found && --count > 0){
      const ii = ~~(Math.random() * cs.length);
      const c = cs[ii];
      const candidate = last + c;
      let u = unmatch.hasOwnProperty(ri)
      ? unmatchS.has(results[j][unmatch[ri]] + c)
      : false;

      // Match found
      if (!set.has(candidate) && !results[j].includes(c) && !u){
        results[j] += c;
        set.add(candidate);
        if (unmatch.hasOwnProperty(ri))
          unmatchS.add(results[j][unmatch[ri]] + c)
        found = true;
      }
    }
    // Match not found
    // Lower the restriction
    // and insert random match
    if (!found){
      const cs_ = cs.filter(
        c => !results[j].includes(c));
      const c = cs_[
        ~~(Math.random()*cs_.length)];
      results[j] += c;
      positionMatches.push((i+2) + ':' + last + c);
    }
  }
}

console.log(results.join('\n'));

console.log('');

for (let p of positionMatches){
  const [pos, pair] = p.split(':');
  console.log(pair + ' duplicate at position ' + pos)
}

let m04 = new Set();
let m35 = new Set();

for (let r of results){
  const c04 = r[0] + r[4];
  const c35 = r[3] + r[5];
  if (m04.has(c04))
    console.log('15 match: ' + c04);
  m04.add(c04);
  if (m35.has(c35))
    console.log('46 match: ' + c35);
  m35.add(c35);
}

(Результат ниже казался довольно хорошим. Диллон Дэвис заметил там пару танграмов, которые разделяют последовательность «POW». Возможно, они предназначены для двух людей, которые могут или не могут еще знать, что у них есть особая связь. (Мы также могли, знаете, просто настройте один из них вручную :)

RGWBYOP
GROBPYW
RBPWOYG
BRWYOGP
RYWPGOB
YRPBGWO
RPBYWOG
PRYGWBO
ROBWPGY
ORGYPBW
RWGOBYP
WRBOPGY
GBOWYRP
BGOYRWP
GYRWBPO
YGROWPB
GPWORBY
PGYBRWO
GOYPWRB
OGPYBRW
GWPROBY
WGBRYPO
BYGPOWR
YBRPOWG
BPGRWYO
PBYWGOR
BORGPWY
OBWGRPY

PO duplicate at position 4
PG duplicate at position 5
RW duplicate at position 5
OW duplicate at position 5
GO duplicate at position 5
GY duplicate at position 6
WO duplicate at position 6
BY duplicate at position 6
PO duplicate at position 6
46 match: BW
15 match: BO
46 match: PW
person גלעד ברקן    schedule 06.02.2019
comment
Я заметил, что этот код работает в пределах лимита. Будет ли этот код использовать все части из 28 наборов головоломки? Если это так, я могу выровнять части одного цвета вместе и выбрать их, как подсказывает код, вручную, чтобы составить головоломки. - person Tianhe Hou; 06.02.2019
comment
@TianheHou отмечает, что, хотя этот подход пытается минимизировать сосуществующие пары цветов, он, похоже, не учитывает тот факт, что части 1 и 5 и 4 и 6 идентичны, поэтому они неизбежно создадут непредусмотренные / неучтенные пары цветов. - person Dillon Davis; 06.02.2019
comment
@DillonDavis, спасибо, что посмотрели. Я не уверен, что понимаю - что вы имеете в виду, когда части 1 и 5 и 4 и 6 идентичны? - person גלעד ברקן; 06.02.2019
comment
Я имел в виду сами кусочки головоломки OP. Две пары физических треугольников идентичны, поэтому создаются непреднамеренно идентичные пары цветов. - person Dillon Davis; 06.02.2019
comment
@DillonDavis хорошее наблюдение. Вы говорите, что было бы полезно избегать дублирования пар 1 и 5 и 4 и 6? Похоже, это должно быть возможно. - person גלעד ברקן; 06.02.2019
comment
@TianheHou код производит 28 комбинаций из 7 цветов. Щелкните Выполнить фрагмент кода, чтобы увидеть результат. Диллон заметил, что он может создавать идентичные пары для позиций 1 и 5 или 4 и 6, которые выглядят похожими треугольниками в дизайне. Я мог бы попытаться исправить это в коде, но, если заметил это, мы могли бы также вручную настроить его. - person גלעד ברקן; 06.02.2019
comment
@DillonDavis, помимо кодирования настройки для (1,5) (4,6) возможных дубликатов, мы также можем попробовать ручную настройку или подумать, что какое-то случайное сходство может быть очаровательным. - person גלעד ברקן; 06.02.2019
comment
@TianheHou неужели возможное дублирование некоторых (1,5) или (4,6) пар кажется достаточно серьезной проблемой, чтобы вносить изменения в код? Пожалуйста, дайте мне знать, и я посмотрю, смогу ли я это предотвратить. - person גלעד ברקן; 06.02.2019
comment
Я опубликовал свою собственную альтернативу, которая пытается учесть эти более сложные дубликаты, но мой алгоритм намного медленнее и не гарантирует минимальное количество дубликатов - только верхняя граница в 2 дубликата между любыми двумя наборами. Может быть, вам удастся найти в нем какое-то применение, чтобы исправить вашу. - person Dillon Davis; 06.02.2019
comment
Обновление нравится, коллизий точно вроде меньше. Тем не менее, возможно, стоит перезапустить его несколько раз, потому что два ваших текущих дубликата встречаются между одними и теми же наборами, что делает его 3 повторяющимися цветами pow. - person Dillon Davis; 10.02.2019
comment
@DillonDavis - это два человека, которые могут знать, а могут и не знать, что у них есть особая связь. (Вы также можете настроить один из них вручную :) - person גלעד ברקן; 10.02.2019