5

注:**他のすべての関連する質問をお読みください:**

この質問をするための私の最初と2番目の試みは次のとおりです。

ここに問題があります:

  • 私はいくつかの(20のような)ブール検証を持っています(true / false)
  • 全体としてのすべてのブール検証にも検証結果があります

私はすべての検証と検証結果をテストするための最良の解決策を見つけようとしています。私はすべての可能な組み合わせを保持するためにマトリックスを調べていましたが、それはやり過ぎかもしれません。

次に例を示します(1〜20)。

  • test_1=30キルあり
  • test_2=マップ1が見つかりました
  • test_3=レベル1をマスターしました
  • test_4=グラントステータスを達成しました
  • test_5=アサルト武器を持っている
  • test_6=ナイフがあります
  • test_7=手榴弾を持っている
  • test_x=など..。

したがって、プレーヤーがこれらすべての検証をTRUEにすると、レベルの結果を出すことができます。

  • test_1、test_2、test_3(3つの任意の組み合わせ)の場合:レベル=緑

すべての組み合わせは(15)です:

  • test_1
  • test_2
  • test_3
  • test_1、test_2
  • test_1、test_3
  • test_2、test_1(重複はこれをスキップできます)
  • test_2、test_3
  • test_3、test_1(重複はこれをスキップできます)
  • test_3、test_2(重複はこれをスキップできます)
  • test_1、test_2、test_3
  • test_1、test_3、test_2(重複するとこれをスキップできます)
  • test_2、test_1、test_3(重複するとこれをスキップできます)
  • test_2、test_3、test_1(重複するとこれをスキップできます)
  • test_3、test_1、test_2(重複するとこれをスキップできます)
  • test_3、test_2、test_1(重複するとこれをスキップできます)

したがって、一意の組み合わせは(15ではなく7)です。

  • test_1
  • test_2
  • test_3
  • test_1、test_2
  • test_1、test_3
  • test_2、test_3
  • test_1、test_2、test_3

今、私は20の検証すべてに固有の組み合わせを見つけ、そのマトリックスからレベル検証を考え出すための最良の解決策を見つけようとしています。

アップデート:

また、次のような一意の組み合わせを読むことができるように、TRUEの組み合わせのみを見つける必要があります。

  • test_1
  • test_2
  • test_3
  • test_1、test_2
  • test_1、test_3
  • test_2、test_3
  • test_1、test_2、test_3

検証テストのブール値の結果

  • 真、偽、偽
  • FALSE、TRUE、FALSE
  • FALSE、FALSE、TRUE
  • 真、真、偽
  • 真、偽、真
  • FALSE、TRUE、TRUE
  • TRUE、TRUE、TRUE

したがって、これらの組み合わせはいずれも緑のレベルになります。

また、レベル割り当てのために比較するマトリックスの順序だけでなく、テスト検証の順序も知る必要があります。したがって、GREENレベルの場合、テスト1、2、および3の検証結果の組み合わせマトリックスのみが必要です。したがって、テスト4〜20は無視できます。

更新#2:

これは単純なOR条件のように見えますが、レベルをマトリックスに設定するために組み合わせロジックを取り出したいと思いました。組み合わせのマトリックスを使用して、追加のコードを記述したり、コード自体の現在のロジックを変更したりすることなく、レベルロジックを決定できます。特定のテストセットの検証結果を比較し、それらの結果にレベルを割り当てたいと思いました。検証の組み合わせの順列が異なると、レベルの割り当ても異なります。

コード自体に組み合わせロジックを追加できることは理解していますが、このロジックは非常に不安定であるように見え、これがより柔軟なソリューションを提供する可能性があると考えました。提案?

4

4 に答える 4

1

序章

次のような組み合わせを簡単に取得できます。

echo "<pre>";
$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;
}

出力

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
)

問題

それらは1,048,576組み合わせに関するものであり、これはあなたが望む種類の配列ではないと私は信じています私はすべての可能な組み合わせではなく条件ベースの組み合わせを提案します

// 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("\n<b>Total Point %s",number_format($user->getPoint(),0));

出力

+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)


<b>Total Point 1,280</b>

使用されるクラス

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 ;};

シンプルなオンラインデモ

于 2012-11-23T15:59:38.323 に答える
1

(わかりやすくするために、以前の2つの回答を削除しました)

最後に編集した後、直接答えるのではなく、まず、必要な「レベル検出アルゴリズム」を100%理解してください。

私がよく理解しているなら、どのテストがどのレベルを与えるかを示す単純な構成構造を定義/維持したいと思います。

例:連想配列の場合:

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

意味:リスト内の1つ以上のテストが満たされた場合、そのレベル(配列キー)をプレーヤーに割り当てます。このようなロジックは、非常に多くの組み合わせを簡単にカバーでき、巨大なマトリックスの処理を回避できます。

たとえば、ロジックを拡張して、テストリストの中で少なくともN個のテストが満たされていることを通知したい場合があります。

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

それはあなたが望むものですか?

ところで、クラシックなXP /レベルアップシステムを使ってみませんか?:-p

于 2012-11-23T15:51:48.373 に答える
1

あなたの質問に答えるのは完全ではありませんが、何かが足りないようです。

1からnまでのラベルが付いた20個のテストがあるとします。テストnを検証するかどうかを決定します。検証用のテストを含めるか、含めないかのどちらかです。これは、すべてのテストで2つの選択肢です。テストがなくなるまで(n -1)を続行します。n = 20の場合、これは2 ^ 20 = 1048576の可能なテストの組み合わせ(テストを選択しない1つの組み合わせを含む)であり、これは1048576の結果を意味します。「検証のレベル」が何を意味するのかはまだわかりませんが、そもそもなぜこれほど多くのテストの組み合わせが必要になるのか疑問に思います。

編集:まあ、(いわば)テストマトリックスは機能するかもしれません....しかし、それでもマトリックスを生成する必要があります。1048576のすべての組み合わせを手作業でコーディングすることはおそらくないでしょう。ただし、マッピングをすでに作成しているとすると、必要な1048576値のルックアップテーブルとして、インデックスがゼロの配列があり、これで完了です。テスト結果をマトリックスにマップするために必要なのは、各テストに2進数を割り当てることだけです(test1は1の位、test2は2の位など)。

私が本当に望んでいるのは、 phpでエンコードする可能性のあるより広範なルールを前提として、マッピングをすばやく生成する方法です...しかし、これについては面白い部分があります。すべてのテストセットのマトリックスを生成するコードがある場合、マトリックスは不要になります。コードは基本的に、マトリックスの圧縮表現です。どちらか一方を使用する場合の唯一のポイントは、一方が他方よりも高速であるかどうかです。

また、1048576のすべての組み合わせを気にしないようです。テストを独自のテストセット(1つは赤用、もう1つは青用など)に分割することは有益かもしれないと思います。たとえば、テストを5つのグループに分割し、グループごとに(16ではなく)3つの異なる可能性がある場合、作業しているのは(グループごとに3つの異なる結果)^(4グループ)= 81ユニークな結果。81のユニークな結果は、100万を超えるよりもはるかに管理しやすくなっています。

独立したものごとに異なるパーティションが必要になる場合もあるようです。また、特定の数のテストが真である限り、どのテストが真になるかは問題ではありません。つまり、「目標:5つの青の目標のうち3つが満たされている」、「目標:10の赤と青の目標のうち7つが満たされている」などです。 。これらのテストには個別にアクセスする必要があり、必ずしも他のテストの結果と乗法になるとは限りません。青の目標のいずれも満たされない場合、赤と青の目標の10のうち7が満たされることはありません(認めてください、これは例なしでこれ以上説明するのは難しいです)。

ですから、本当に、簡単な答えはありません。1048576の組み合わせのすべてを個別に処理するか、テスト用のある種の一般的なグループ化スキームを作成してエンコードし、組み合わせを大幅に削減します。あなたは確かにそのスキームによってあなたの完全なマトリックススキームを作成することができます、そして多分与えられた組み合わせのセットのためにあなたの完全な1048576要素マトリックスを動的に生成することさえできます。しかし、ろうそくの半分だけを燃やすことで、ろうそく全体を燃やすことはできません。

編集II(およびIII):

もう1つ推測します。あなたが提案したレベルは、それぞれ(および前のバッチ)ごとに完了した目標の数に関連しているようです。したがって、結果を文字列( "T"、および "F")にエンコードし、各バッチの "F"をカウントして、そこから決定します。Fsの数が文字列内の文字数である場合、バッチの目的は完了しません。Fsの数がゼロの場合、バッチのすべての目的が完了します。

青の後のバッチが紫だとしましょう。誰かがすべての緑のバッチを完了せずに紫の目標を達成できますか?もしそうなら、あなたはその可能性のために割り当てる別の色を持っています。そうでない場合は、これらのレベルが順序付けられていると思います(緑と青の間のオレンジ、おそらく「茶色」または青と紫の間の何か-これを薄い空気から引き出したことがわかります-そしてそれはかなり単純なはずですこれらのカウントをカスケードして、現在の「レベル」を決定します。

順序付けがない場合は、前述の状況と非常によく似ています。各グループの結果は{「目標が完了していません」、「一部の目標が完了しました」、「すべての目標が完了しました」}です。x可能な結果を​​意味するグループがあり3^xます。前述のテストの結果ではなく、これらの結果に基づいてレベルマトリックスを作成する必要があります。

于 2012-11-23T17:25:03.870 に答える
0

あなたが言ったように、私はあなたの質問のグラフィック表示を見つけました。

|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|

私の意見では、条件を対角線の逆順でチェックしてから、左から右にチェックする必要があります。つまり、

最初のチェック[9,9]

失敗した場合はチェック[8,8]

これが失敗した場合はチェック[7,7]

それが真のチェックを与えるかどうか[7,8]

これで誤ったチェックが行われる場合[7,9]、これが答えであり、簡単なショートカットである必要があります。

この方法は、すべてのプロセス時間を短縮します。

于 2012-11-23T16:01:56.670 に答える