Lógica Combinada Matrix

NOTA: ** Leia todas as outras questões relacionadas : **

Aqui estão as minhas primeiras e segundas tentativas de fazer esta pergunta:

  • Modo eficiente para determinar o resultado da matriz de teste
  • O produto cartesiano será a melhor abordagem para isso

Aqui está o problema:

  • Eu tenho várias (como 20) validações booleanas (verdadeiro / falso)
  • Todas as validações booleanas como um todo também têm uma validação Resultado

Estou tentando encontrar a melhor solução para testar todas as validações e também o resultado da validação. Eu estava olhando para uma Matrix para segurar todas as combinações possíveis, mas isso pode ser um exagero.

Aqui está um exemplo (1 – 20):

  • test_1 = Tem 30 mortes
  • test_2 = encontrou mapa 1
  • test_3 = Dominou Nível 1
  • test_4 = Conseguiu Grunt Status
  • test_5 = Tem arma de assalto
  • test_6 = Tem faca
  • test_7 = tem granada
  • test_x = Etc …

Então, quando o Player tiver todas essas validações como TRUE, posso dar um resultado de nível

  • se test_1, test_2, test_3 (qualquer combinação dos três): nível = verde

Todas as combinações são (15):

  • test_1
  • test_2
  • test_3
  • test_1, test_2
  • test_1, test_3
  • test_2, test_1 (o duplicado pode ignorar isso)
  • test_2, test_3
  • test_3, test_1 (o duplicado pode ignorar isso)
  • test_3, test_2 (o duplicado pode ignorar isso)
  • test_1, test_2, test_3
  • test_1, test_3, test_2 (o duplicado pode ignorar isso)
  • test_2, test_1, test_3 (o duplicado pode ignorar isso)
  • test_2, test_3, test_1 (o duplicado pode ignorar isso)
  • test_3, test_1, test_2 (o duplicado pode ignorar isso)
  • test_3, test_2, test_1 (o duplicado pode ignorar isso)

As combinações únicas são (7 em vez de 15):

  • test_1
  • test_2
  • test_3
  • test_1, test_2
  • test_1, test_3
  • test_2, test_3
  • test_1, test_2, test_3

Agora estou tentando encontrar a melhor solução possível para encontrar combinações únicas para todas as 20 validações e chegar a uma validação de nível a partir dessa matriz.

ATUALIZAR:

Também eu preciso encontrar apenas TRUE Combinations para que você possa ler as Combinações únicas como esta:

  • test_1
  • test_2
  • test_3
  • test_1, test_2
  • test_1, test_3
  • test_2, test_3
  • test_1, test_2, test_3

Resultados do valor booleano dos testes de validação

  • VERDADEIRO, FALSO, FALSO
  • FALSO, VERDADEIRO, FALSO
  • FALSO, FALSO, VERDADEIRO
  • VERDADEIRO, VERDADEIRO, FALSO
  • VERDADEIRO, FALSO, VERDADEIRO
  • FALSO, VERDADEIRO, VERDADEIRO
  • VERDADEIRO, VERDADEIRO, VERDADEIRO

Então, qualquer uma dessas combinações seria um nível VERDE.

Também preciso saber a ordem das validações de teste, bem como a ordem da matriz para comparar a atribuição de nível. Então, para o nível VERDE, eu só preciso da matriz de combinação de resultados de validação para os testes 1, 2 e 3. Então eu poderia ignorar os testes 4 a 20

UPDATE # 2:

Eu sei que isso parece uma condição OR simples, mas eu queria tirar a lógica de combinação para definir o nível em uma matriz. Eu poderia usar a matriz de combinações para determinar a lógica de nível sem ter que codificar adicionais ou modificar a lógica atual no próprio código. Eu queria apenas comparar os resultados das validações para um determinado conjunto de testes e atribuir um nível a esses resultados. Diferentes permutações das combinações de validação resultariam em diferentes atribuições de nível.

Eu entendo que eu poderia adicionar a lógica de combinação no próprio código, mas como essa lógica parece ser muito volátil e pensou que isso poderia oferecer uma solução mais flexível. Sugestões?

   

(retirou minhas duas respostas anteriores para maior clareza)

Após sua última edição, em vez de responder diretamente, gostaria de ter certeza de que 100% entende o ” algoritmo de detecção de nível ” que deseja.

Se eu entender bem, você gostaria de definir / manter uma estrutura de configuração simples, indicando quais testes dão qual nível.

por exemplo, com uma matriz associativa:

 array( 'green' => array('test1', 'test2', 'test3'), 'orange' => array('test2', 'test3', 'test5') ... ); 

Com o significado: se um ou mais dos testes na lista estiverem satisfeitos, atribua esse nível (chave de matriz) ao jogador. Essa lógica poderia facilmente cobrir muitas combinações e evitaria manipular uma enorme matriz.

Talvez você queira estender a lógica para dizer, por exemplo, que pelo menos N testes entre a lista de teste estão satisfeitos.

 array( 'green' => array( 'tests' => array('test1', 'test2', 'test3'), 'nb_required' => 2 ), ... ); 

É isso que você quer?

BTW, por que você não usa um sistema clássico XP / level up? :-p

Não é mesmo para responder sua pergunta, mas parece que você está perdendo alguma coisa.

Digamos que você tenha vinte testes, rotulados como 1, porém n . Decida o teste n se deseja validar ou não. Ou você inclui o teste para validação, ou você não. São duas escolhas para cada teste. Prossiga ( n -1) até que você não tenha mais testes. Para n = 20, isso é 2 ^ 20 = 1048576 possíveis combinações de testes (incluindo uma combinação em que você não seleciona nenhum teste), o que significa 1048576 resultados. Agora eu ainda não entendo o que você quer dizer com “nível de validação”, mas eu tenho que me perguntar por que você precisaria de muitas combinações de testes em primeiro lugar.

Edit: Bem, uma matriz de teste (por assim dizer) poderia funcionar … mas você ainda precisaria gerar a matriz. É provável que não digite todas as combinações 1048576. Mas, supondo que você já criou o mapeamento, você simplesmente possui uma matriz zero indexada como uma tabela de pesquisa com 1048576 valores que você deseja e você terminou! Tudo o que você precisa para mapear os resultados do teste para a matriz seria atribuir a cada teste um dígito binário (o teste1 seria o lugar de cada um, o teste2 seria o lugar de 2, etc.)

O que eu suspeito que você realmente deseja é uma maneira rápida de gerar o mapeamento dado algumas regras mais amplas que você pode codificar em php … mas aqui é uma parte divertida sobre isso. Se você tivesse algum código que gerasse a matriz para qualquer conjunto de testes, a matriz é então supérflua; Seu código é essencialmente uma representação compactada para a matriz. O único ponto em usar um sobre o outro é se um seria ou não mais rápido do que o outro.

Também parece que você realmente não se importa com todas as combinações de 1048576. Eu suspeito que isso possa beneficiar você para particionar seus testes em seu próprio conjunto de testes (um para o vermelho, um para o azul, etc.). Por exemplo, se você particionar testes em grupos de 5, e há, oh, 3 possibilidades diferentes (em vez de 16) para cada grupo, você está trabalhando apenas (3 resultados diferentes por grupo) ^ (4 grupos) = 81 resultados únicos. Oitenta e um resultados únicos são muito mais gerenciáveis ​​do que mais de um milhão.

Parece que você também pode precisar de partições diferentes para diferentes coisas independentes. Também pode não importar mesmo quais testes resultam em verdade, enquanto um certo número deles é verdadeiro , ou seja, “objective: 3 dos objectives azuis alcançados” meta: 7 dos 10 objectives vermelhos e azuis encontrados “ou o que quer que seja . Esses testes teriam que ser acessados ​​de forma independente e não seriam necessariamente multiplicativos com os resultados dos outros testes – nunca haverá 7 dos 10 objectives vermelhos e azuis satisfeitos se nenhum dos seus objectives azuis for atingido (eu vou admita, isso é difícil de explicar ainda mais sem um exemplo).

Então, na verdade, não há uma resposta rápida. Ou você lida com todas e cada uma das combinações 1048576 individualmente , ou você cria e codifica algum tipo de esquema de agrupamento genérico para seus testes para reduzir drasticamente as combinações. Você certamente pode criar seu esquema de matriz completo por esse esquema e, talvez, gerar dinamicamente sua matriz completa de elementos 1048576 para um determinado conjunto de combinações. Mas você não pode queimar uma vela inteira apenas queimando metade disso.

Editar II (e III):

Eu vou fazer mais um palpite. Os níveis que você propôs parecem estar relacionados ao número de objectives concluídos por cada (e lote anterior). Então, codifique seus resultados em uma seqüência de caracteres (“T” e “F”) e conte os “F” para cada lote e determine a partir daí. Se a contagem de Fs for o número de caracteres na string, nenhum objective do lote será concluído, se o número de Fs for zero, todos os objectives do lote serão concluídos.

Digamos o lote depois que o azul é roxo. Alguém poderia alcançar um objective em roxo sem completar todo o lote verde? Se assim for, você terá outra cor a atribuir para essa possibilidade; se não, então, eu suponho que esses níveis são ordenados (laranja entre verde e azul, talvez “marrom” ou algo entre azul e roxo – você pode dizer que tirei isso do nada – e deveria ser bastante simples para fazer uma cascata através dessas contagens para determinar o “nível” atual.

Se não houver pedidos, então é bastante análogo à situação que mencionei acima: Cada grupo tem um resultado {“sem objectives concluídos”, “alguns objectives concluídos”, “todos os objectives concluídos”}. Existem x grupos, o que significa 3^x resultados possíveis. Você deve basear sua matriz de nível nesses resultados, não nos resultados dos testes anteriormente mencionados.

Introdução

Você pode obter combinações simples assim:

 echo "
"; $test = ["test_1","test_2","test_3"]; // Get Combination $return = uniqueCombination($test); //Sort sort($return); //Pretty Print print_r(array_map(function($v){ return implode(",", $v); }, $return)); function uniqueCombination($in, $minLength = 1, $max = 10) { $count = count($in); $members = pow(2, $count); $return = array(); for($i = 0; $i < $members; $i ++) { $b = sprintf("%0" . $count . "b", $i); $out = array(); for($j = 0; $j < $count; $j ++) $b{$j} == '1' and $out[] = $in[$j]; count($out) >= $minLength && count($out) < = $max and $return[] = $out; } return $return; } 

Saída

 Array ( [0] => test_1 [1] => test_2 [2] => test_3 [3] => test_1,test_2 [4] => test_1,test_3 [5] => test_2,test_3 [6] => test_1,test_2,test_3 ) 

O problema

Eles são cerca de 1,048,576 combinações e acredito que este não é o tipo de matriz que deseja, eu sugeriria uma combinação baseada em condições, em vez de toda a combinação possível

Exemplo

 // Game Conditions $game = new Game(); $game->addCondition(new Condition(new Level(1), new Kill(30))); $game->addCondition(new Condition(new Level(2), new Map(1), new Kill(10))); $game->addCondition(new Condition(new Level(3), new Grunt(10))); $game->addCondition(new Condition(new Level(4), new Knife(1), new Ak47(1))); $game->addCondition(new Condition(new Level(5), new Grenade(1), new Combo(7))); $game->addCondition(new Condition(new Level(6), new Kill(100), new Blow(10), new Stab(10))); $game->addCondition(new Condition(new Level(7), new Herb(10), new Medipack(1), new Map(1), new Artwork(1))); $game->addCondition(new Condition(new Level(8), new Grenade(20),new Artwork(5))); // User Starts Game $user = new User($game); $user->task(new Map(1)); $user->task(new Herb(5)); $user->task(new Kill(10)); $user->task(new Kill(10)); $user->task(new Herb(10)); $user->task(new Kill(10)); $user->task(new Kill(10)); $user->task(new Ak47(1)); $user->task(new Knife(1)); $user->task(new Map(1)); $user->task(new Grunt(17)); $user->task(new Kill(60)); $user->task(new Combo(1)); $user->task(new Kill(40)); $user->task(new Medipack(1)); $user->task(new Artwork(1)); $user->task(new Grenade(1)); $user->task(new Combo(10)); $user->task(new Blow(10)); $user->task(new Stab(5)); $user->task(new Blow(10)); $user->task(new Stab(5)); $user->task(new Stab(5)); printf("\nTotal Point %s",number_format($user->getPoint(),0)); 

Saída

 +Task Map Added (1) +Task Herb Added (5) +Task Kill Added (10) ^Task Kill Updated (20) ^Task Herb Updated (15) ^Task Kill Updated (30) *Level 1 Completed* *Level 2 Completed* ^Task Kill Updated (40) +Task Ak47 Added (1) +Task Knife Added (1) ^Task Map Updated (2) +Task Grunt Added (17) *Level 3 Completed* *Level 4 Completed* ^Task Kill Updated (100) +Task Combo Added (1) ^Task Kill Updated (140) +Task Medipack Added (1) +Task Artwork Added (1) +Task Grenade Added (1) ^Task Combo Updated (11) *Level 5 Completed* +Task Blow Added (10) +Task Stab Added (5) ^Task Blow Updated (20) ^Task Stab Updated (10) *Level 6 Completed* *Level 7 Completed* ^Task Stab Updated (15) Total Point 1,280 

Classes Usados

 class Task { private $no; function __construct($no = 1) { $this->no = $no; } function getNo() { return $this->no; } function getName() { return get_called_class(); } function merge(Task $task) { $this->no += $task->getNo(); return $this; } } class User { private $game; private $point; private $tasks = array(); function __construct(Game $game) { $this->game = $game; } function getPoint() { return $this->point; } function getTask() { return $this->tasks; } function task(Task $task) { if (isset($this->tasks[$task->getName()])) { $this->tasks[$task->getName()]->merge($task); printf("^Task %s \tUpdated (%s)\n", $this->tasks[$task->getName()]->getName(), $this->tasks[$task->getName()]->getNo()); } else { printf("+Task %s \tAdded (%s)\n", $task->getName(), $task->getNo()); $this->tasks[$task->getName()] = $task; } $this->point += $task->getNo() * $task->d; $this->game->notify($this); } } class Condition { private $task = array(); private $status = false; function __construct(Level $level) { $this->level = $level; $tasks = func_get_args(); array_shift($tasks); $this->task = new SplObjectStorage($tasks); foreach ( $tasks as $task ) $this->task->attach($task); } function update(Game $game, User $user) { if ($this->status) return; $n = 0; foreach ( $this->task as $cTask ) { foreach ( $user->getTask() as $task ) { if ($cTask->getName() == $task->getName()) { if ($task->getNo() >= $cTask->getNo()) $n ++; } } } if ($n === count($this->task) && ($game->getLevel()->getNo() + 1) == $this->level->getNo()) { $this->status = true; $game->setLevel($this->level); printf("\n*Level %d Completed* \n\n", $this->level->getNo()); } } function getStatus() { return $this->status; } } class Game { private $taskCondition; private $level; public function __construct() { $this->taskCondition = new SplObjectStorage(); $this->level = new Level(0); } function setLevel(Level $level) { $this->level = $level; } function getLevel() { return $this->level; } function addCondition($condition) { $this->taskCondition->attach($condition); } public function notify($user) { foreach ( $this->taskCondition as $conditions ) { if ($conditions->getStatus() === true) { // detached completed condition $this->taskCondition->detach($conditions); continue; } $conditions->update($this, $user); } } public function hasCondition() { return count($this->taskCondition); } } class Level extends Task{} class Action extends Task{}; class Weporn extends Task{}; class Skill extends Task{}; class Tresure extends Task{}; class Medicine extends Task{}; class Kill extends Action{public $d = 5 ;}; class Blow extends Action{public $d = 7 ;}; class Stab extends Action{public $d = 10 ;}; class Map extends Tresure{public $d = 10 ;}; class Artwork extends Tresure{public $d = 20 ;}; class Knife extends Weporn{public $d = 5 ;}; class Grenade extends Weporn{public $d = 10 ;}; class Ak47 extends Weporn{public $d = 10 ;}; class Jump extends Skill{public $d = 2 ;}; class Grunt extends Skill{public $d = 4 ;}; class Combo extends Skill{public $d = 7 ;}; class Medipack extends Medicine{public $d = 5 ;}; class Herb extends Medicine{public $d = 5 ;}; 

Demo Online Simples

Eu encontrei a exibição gráfica de sua pergunta como você mencionou.

 |0|1|2|3|4|5|6|7|8|9| |1|T|T|T|T|T|T|T|T|T| |2|F|T|T|T|T|T|T|T|T| |3|F|F|T|T|T|T|T|T|T| |4|F|F|F|T|T|T|T|T|T| |5|F|F|F|F|T|T|T|T|T| |6|F|F|F|F|F|T|T|T|T| |7|F|F|F|F|F|F|T|T|T|=>[7,9] if this is the answer |8|F|F|F|F|F|F|F|T|T| |9|F|F|F|F|F|F|F|F|T| 

Na minha opinião, você deve verificar as condições em ordem diagonal reversa, depois da esquerda para a direita. Que significa

primeiro cheque [9,9]

se ele falhar, verifique [8,8]

se isso falhar, verifique [7,7]

se dá um cheque verdadeiro [7,8]

se isso der um cheque falso [7,9], essa deve ser a resposta e o atalho simples,

Esse método irá reduzir ao longo de todo o tempo de processo.