FireBase:ゲームで対戦相手を一致させる方法は?
-
21-12-2019 - |
質問
ソーシャルチェスゲームを実装しています。すべてのユーザーが新しいゲームを作成することができ、それらはシステムが彼らのための対戦相手を見つけるまで待ちます。
ユーザーがゲームを作成するとき、それらは制約を指定します:彼らは遊ぶのが好きな色、そして相手の最小限のチェス評価。
対戦相手が一致するかどうか一致させることができます。たとえば、次の2つの対戦相手が一致します。
// User 1 with rating 1700 // User 2 with rating 1800
// creates this game // creates this game
game: { game: {
color: 'white', minRating: 1650
minRating: 1600 }
} // User did not specify a preferred color,
// meaning they do not care which color to play
.
だから、ユーザー1がシステム内の最初のユーザーで、ゲームを作成した場合、彼らは待ちます。ユーザー2が自分のゲームを作成すると、それらはユーザー1とすぐに一致させる必要があります。
反対側では、両方とも白を演奏したいので、次の2つの対戦相手が一致しません。この場合、両方の誰かがcolor: 'black'
(または指定されていない色)を使用してゲームを作成するまで待つ必要があります。
// User 1 with rating 1700 // User 2 with rating 1800
// creates this game // creates this game
game: { game: {
color: 'white', color: 'white'
minRating: 1600 minRating: 1650
} }
.
何千人ものユーザーが同時に新しいゲームを作成するシナリオに関連する私の懸念。デッドロックを作成せずに相手と一致することを確認するにはどうすればよいですか。すなわち、ユーザ1、ユーザ2、およびユーザ3が同時に対戦相手を見つけようとしているときにシナリオをどのように防止し、それらのマッチングアルゴリズムはユーザ99を回復し、そのシナリオから回復することは、以下のいずれかにユーザ99を割り当てることができる。それら?
このようなマッチングシステムを実装するためにFirebaseの力をどのように使用しますか?
解決
NoSQL環境では、複数のフィールドを一致させたい場合は特に
を一致させることができます。あなたの場合、私はカラーで単純なインデックスを設定し、カラー内では、ミニレーティングに設定された優先順位を持つゲームへの参照を保存します。 そのようにして、ミニレーションの優先順位で優先色でゲームを照会することができます。
indexes: {
color:{
white:{
REF_WITH_PRIORITY_TO_RATING: true
},
black:{
REF_WITH_PRIORITY_TO_RATING: true
}
}
}
.
試合がゲームを開くたびに情報を取得したい場合:
ref = new(Firebase)('URL');
query =ref.child('color_index/white/').startAt(minPriority);
query.on('child_added',function(snapshot){
//here is your new game matching the filter
});
.
しかし、これは、dropRate
、GamePlayed 'などのゲームをフィルタリングするための複数のフィールドを導入すると、より複雑になります。この場合、索引をより深くネストすることができます。
indexes: {
GMT0: {
color:{
white:{
REF_WITH_PRIORITY_TO_RATING: true
},
black:{
REF_WITH_PRIORITY_TO_RATING: true
},
}
GMT1: {
// etc
}
}
. 他のヒント
始点の明らかな選択は色になりますが、これは排他的要件です。他の人は加重結果のように見えるので、それらは単に体重を増減することができます。
最小/最大範囲の優先順位を利用し、それぞれを別の「インデックス」に保ちます。次に、それぞれのマッチをつかみ、共用体を作成します。この構造を考慮してください:
/matches
/matches/colors/white/$user_id
/matches/ranking/$user_id (with a priority equal to ranking)
/matches/timezones/$user_id (with a priority of the GMT relationship)
.
今すぐクエリするには、単に各カテゴリの一致をつかみ、それらを一致数でランク付けします。私は色から始めることができます、これはおそらくオプションまたは相対的な評価ではありません:
var rootRef = new Firebase('.../matches');
var VALUE = {
"rank": 10, "timezone": 5, "color": 0
}
var matches = []; // a list of ids sorted by weight
var weights = {}; // an index of ids to weights
var colorRef = rootRef.child('colors/black');
colorRef.on('child_added', addMatch);
colorRef.child('colors/black').on('child_removed', removeMatch);
var rankRef = rootRef.child('ranking').startAt(minRank).endAt(maxRank);
rankRef.on('child_added', addWeight.bind(null, VALUE['rank']));
rankRef.on('child_removed', removeWeight.bind(null, VALUE['rank']));
var tzRef = ref.child('timezone').startAt(minTz).endAt(maxTz);
tzRef.on('child_added', addWeight.bind(null, VALUE['timezone']));
tzRef.on('child_removed', removeWeight.bind(null, VALUE['timezone']));
function addMatch(snap) {
var key = snap.name();
weights[key] = VALUE['color'];
matches.push(key);
matches.sort(sortcmp);
}
function removeMatch(snap) {
var key = snap.name();
var i = matches.indexOf(key);
if( i > -1 ) { matches.splice(i, 1); }
delete weights[key];
}
function addWeight(amt, snap) {
var key = snap.name();
if( weights.hasOwnProperty(key) ) {
weights[key] += amt;
matches.sort(sortcmp);
}
}
function removeWeight(amt, snap) {
var key = snap.name();
if( weights.hasOwnProperty(key) ) {
weights[key] -= amt;
matches.sort(sortcmp);
}
}
function sortcmp(a,b) {
var x = weights[a];
var y = weights[b];
if( x === y ) { return 0; }
return x > y? 1 : -1;
}
.
大丈夫、今、私は誰もがこのユースケースで尋ねるものを与えました - 初歩的な句を作成する方法。ただし、ここでの適切な回答は検索エンジンによって検索が実行されるべきです。これは単純な状態ではありません。色のようなフィールドはオプションではない、または単に Best の試合が一方で、どちらの方向に最も近い一致であるため、これは最良の試合の重み付け検索です。試合の品質。
チェックアウト shiple elasticsearch統合のFlashlight 。このアプローチでは、ESの素晴らしい重み付けツール、ダイナミックなソート、および他のすべてのものを利用できるはずです。
デッドロックについて。あなたが毎秒何百もの取引(すなわち、何十万ものユーザーが一致を競う何百ものユーザー)を持っているまで、私はあまりにも多くの焦点を置くことはありません。参加を受け入れるために書いているパスを分割し、一人の人だけが入手に成功することを確実にするためにトランザクションを実行します。そのパスのロックが処理を遅くしないように、読み取りデータから分離してください。トランザクションを最小限のサイズ(可能であれば1フィールド)に保存してください。