Лица Экмана и проблемка с ними...
Пол Экман - известный психолог, в частности, автор книги "Психология лжи". За последние пару дней я набросал вот такой тест по методике "Лица Экмана", инициирована эта работа г-жей Буровой :) Увы, пока не выберу времени подумать над комбинаторной проблемой, всплывшей во время написания, запишем её хоть в блог.
Что имеем: 10 актёров (занумерованы от 1 до 10), каждый из которых представляет по 6 эмоций (обозначены шестью разными буквами - a, u, s ,f , h, d). Надо вывести 10 порций по 6 картинок так, чтобы, во-первых, все 6 эмоций-букв в каждой порции были разными, во-вторых, на каждом шаге не было повторяющихся актёров.
Очевидно, что раскидывать "чисто случайно" нельзя, нельзя также избежать повторений, просто проверяя, не выбирался ли уже данный актёр для текущего шага. 6 актёров вполне могут случайно "закрыть" первые 6 шагов (распределившись по принципу определителя матрицы 6x6), а оставшиеся 4 актёра тогда не смогут закрыть оставшихся 4 шага без повторений одного актёра на части шагов.
Пока ограничился тем, что просто перетасовал как буквы-эмоции, так и цифры-актёров простой функцией
function select_random_items ($k,$arr) { //выбрать $k случайных элементов из массива $arr $c=count($arr); if ($k>$c) $k=$c; $a = array (); for ($i=0; $i<$k; ) { $n=rand (0,$c-1); if (!in_array($arr[$n],$a)) { array_push ($a,$arr[$n]); $i++; } } return $a; }
следя, чтобы в столбцах матрицы перестановок цифр не было повторяющихся значений выше обрабатываемой строки:
$selection = array ( array ('01','02','03','04','05','06','07','08','09','10'), array ('01','02','03','04','05','06','07','08','09','10'), array ('01','02','03','04','05','06','07','08','09','10'), array ('01','02','03','04','05','06','07','08','09','10'), array ('01','02','03','04','05','06','07','08','09','10'), array ('01','02','03','04','05','06','07','08','09','10') ); $i=0; while ($i<6) { $selection[$i] = select_random_items (10,$selection[$i]); $found=true; for ($ii=0; $ii<$i; $ii++) for ($jj=0; $jj<10; $jj++) { if ($selection[$ii][$jj]==$selection[$i][$jj]) { $found=false; $ii=$i; break; } } if ($found==false) continue; else $i++; }
и потом соединил буквы с цифрами, образуя имена картинок. Увы, это не гарантирует вывода без повторений, вот пример:
a02,u07,s01,f10,h03,d09, d09,f01,u06,a05,h10,s03, s07,h09,f05,a01,u06,d08, a03,s05,u07,d02,f09,h01, u05,s08,h04,f03,d02,a06, f04,h03,d02,u06,a08,s07, s01,h04,f10,u08,a07,d05, a10,s02,d03,h09,f05,u04, f06,s10,a08,h04,d01,u02, f08,s06,a09,u07,d04,h10
Актёр 9 представляет одну и ту же эмоцию на 1 и 2 шаге теста :(
Очевидно, что поступить так же с буквами-эмоциями не удастся - в их матрице всего 6 столбцов и 10 строк по числу шагов теста. Придумаю нормальный алгоритм - допишу... Кстати, если пройдёте тест до конца, получите и постоянный линк на результаты, вот что вышло у меня при тестовом прохождении: http://test.kislenko.net/ekmanfaces/result.php?id=1
P.S. пару часов спустя. Мдя, что-то я совсем затупил, но бутылка пива помогла :)
Если во всех "перемешанных" первым фрагментом строках уже правильно присутствуют цифры от 1 до 10, зачем вообще генерировать случайные перестановки ещё и для букв? Просто соединяем первую строчку с первой буквой и т.д. Потом выбираем значения по столбцам и уже набор из 6 значений сортируем. Код лишь слегка изменился и всё стало правильно.
Было:
$items=''; for ($i=0; $i<10; $i++) { $fix=select_random_items (6,$prefix); for ($k=0; $k<6; $k++) { $fix[$k].=$selection[$k][$i]; $items.=$fix[$k]; if ($i*$k<45) $items.=','; } }
Стало:
$items=''; for ($i=0; $i<10; $i++) { for ($k=0; $k<6; $k++) $fix[$k]=$prefix[$k].$selection[$k][$i]; $fix=select_random_items (6,$fix); for ($k=0; $k<6; $k++) { $items.=$fix[$k]; if ($i*$k<45) $items.=','; } }
27.10.2010, 11:11 [10033 просмотра]