我正在玩紙牌遊戲,並且必須在MySQL中存儲洗牌的套牌。在MySQL(單列)中存儲撲克牌套牌
什麼是在一個列中存儲52張卡片的最有效方式?並保存/檢索那些使用PHP。
我需要6位來表示從0到52的數字,因此想到將卡組保存爲二進制數據,但我試過使用PHP的pack
函數,但沒有多少運氣。我最好的辦法是保存一個由104個字符組成的字符串(52個零填充整數),但這並不是最優的。
謝謝。
我正在玩紙牌遊戲,並且必須在MySQL中存儲洗牌的套牌。在MySQL(單列)中存儲撲克牌套牌
什麼是在一個列中存儲52張卡片的最有效方式?並保存/檢索那些使用PHP。
我需要6位來表示從0到52的數字,因此想到將卡組保存爲二進制數據,但我試過使用PHP的pack
函數,但沒有多少運氣。我最好的辦法是保存一個由104個字符組成的字符串(52個零填充整數),但這並不是最優的。
謝謝。
我不同意,這是沒有必要或者說不切實際做任何這一點,但爲了好玩,何不;)
從你的問題我不知道,如果你的目標是在所有的卡編碼爲一個值並相應存儲,或者是否要單獨編碼卡。所以我假設前者。
而且我假定你有一組52張(或項目)與你之間1和52
我看到一些方法,概括如下,不是所有實際使用的更好的整數值表示更小的空間,但包括了被起見完成:使用逗號分隔的列表(CSV),9 + 2 * 42 + 51 = 144個字符
有天然的序列是進一步的辦法,考慮到單純實用,技術或理論方面,如也可通過列出的方法可見。
對於理論方法(我認爲這是最有意思的方法),瞭解一下信息理論和熵有幫助。基本上,根據已知的問題,不需要進一步的信息,分別只需要信息來澄清所有剩餘的不確定性。由於我們正在處理比特和字節,因此在內存使用方面,我們感興趣的實際上是基於比特或字節的(如果您僅考慮沒有底層技術和硬件的比特序列);也就是說,位代表兩種狀態之一,即允許兩種狀態的區分。這實際上是微不足道的,但很重要:/
然後,如果您想在基準B中表示N個狀態,那麼您需要在該基礎中或在您的示例日誌中記錄(N)/ log(B)數字52)/ log(2)= 5.70 ...→6位。你會注意到實際上只需要5.70位,這意味着6位實際上會有損失。 問題轉換出現的時間是:代表52個狀態,而不是單獨表示52個狀態,可以表示整個卡片集。多項式方法是一種做到這一點的方法。基本上它的工作原理是假設基數爲52,也就是卡組被表示爲1'4'29'31 ....或數學上說:52 + 1 = 1'1 == 53十進制,1'1 + 1 = 1'2 == 54十進制,1'52'52 + 1 = 2'1'1 == 5408十進制,
但是如果你進一步看看多項式方法,你會注意到有一個總數52^52可能的值,而我們只會使用52! = 1 * 2 * 3 * ... * 52,因爲一旦卡被固定,剩餘的可能性就會減小,不確定性或熵也會減少。 (請注意,52!/ 52^52 = 4.7257911e-22!這意味着多項式是完全浪費空間)。如果我們現在要在[1,52!]中使用一個非常理論最小值的值,我們可以用log(52!)/ log(2)= 225.581003124來表示卡組。 28.1976字節。與此相關的問題是,表示爲這樣的任何值都不包含任何我們可以從中導出其語義的結構,這意味着對於每個52!可能的值(如果考慮排除原則,那麼52! - 1)我們需要引用它的含義,即查找52!價值觀,這肯定會成爲記憶矯枉過正。
雖然我們可以與編碼有序集的熵減少的知識做出妥協。舉個例子:我們用序列中當時所需的最小位數順序編碼每張卡片。因此,假設N < = 52卡仍然存在,那麼在每一步中卡可以用log(N)/ log(2)位表示,這意味着所需位的數量減少,直到最後一張卡時,你不需要有點在第一位。這將給出(請更正)。
20 * 6位+16 * 5位+8 * 4位+4 * 3位+2 * 2位+ 1位= 249位= 31.125 ..字節
但由於不必要地使用了部分位,所以仍然會有損失,但數據中的結構完全彌補了這一點。
所以一個問題可能是,我們可以將多項式與這個?!?11 ?!其實,我必須考慮這一點,我感到很累。
一般來說,瞭解問題的結構會大大減少必要的內存空間。實際上,在這個時代,對於一般的高層開發人員來說,這種低層次的考慮並不是那麼重要(hej,100kByte的浪費空間,所以!)和其他考慮因素的權重更高;也是因爲底層技術通常會自己減少內存使用量,無論是文件系統還是gzip-ed網絡服務器響應等。儘管如此,這些類型的常識仍然有助於創建服務和數據結構。
但是後面的這些方法是非常具體的問題「壓縮程序」;一般壓縮的工作方式不同,作爲示例方法,程序按順序遍歷數據的字節,並且對於任何看不見的位序列,將這些序列添加到查找表中並用索引(作爲草圖)表示實際序列。
有趣的談話已經足夠了,讓我們開始技術!
第一方法 「CSV」
// your unpacked card set
$cards = range(1,52);
$coded = implode(',',$cards);
$decoded = explode(',',$coded);
第二方法:1卡= 1個字符
// just a helper
// (not really necessary, but using this we can pretty print the resulting string)
function chr2($i)
{
return chr($i + 32);
}
function myPack($cards)
{
$ar = array_map('chr2',$cards);
return implode('',$ar);
}
function myUnpack($str)
{
$set = array();
$len = strlen($str);
for($i=0; $i<$len; $i++)
$set[] = ord($str[$i]) - 32; // adjust this shift along with the helper
return $set;
}
$str = myPack($cards);
$other_cards = myUnpack($str);
第三方法中,1卡= 6個比特
$set = ''; // target string
$offset = 0;
$carry = 0;
for($i=0; $i < 52; $i++)
{
$c = $cards[$i];
switch($offset)
{
case 0:
$carry = ($c << 2);
$next = null;
break;
case 2:
$next = $carry + $c;
$carry = 0;
break;
case 4:
$next = $carry + ($c>>2);
$carry = ($c << 6) & 0xff;
break;
case 6:
$next = $carry + ($c>>4);
$carry = ($c << 4) & 0xff;
break;
}
if ($next !== null)
{
$set .= chr($next);
}
$offset = ($offset + 6) % 8;
}
// and $set it is!
$new_cards = array(); // the target array for cards to be unpacked
$offset = 0;
$carry = 0;
for($i=0; $i < 39; $i++)
{
$o = ord(substr($set,$i,1));
$new = array();
switch($offset)
{
case 0:
$new[] = ($o >> 2) & 0x3f;
$carry = ($o << 4) & 0x3f;
break;
case 4:
$new[] = (($o >> 6) & 3) + $carry;
$new[] = $o & 0x3f;
$carry = 0;
$offset += 6;
break;
case 6:
$new[] = (($o >> 4) & 0xf) + $carry;
$carry = ($o & 0xf) << 2;
break;
}
$new_cards = array_merge($new_cards,$new);
$offset = ($offset + 6) % 8;
}
第四方法中,多項式,剛剛概述(請考慮使用bigint,因爲整數溢出)
$encoded = 0;
$base = 52;
foreach($cards as $c)
{
$encoded = $encoded*$base + $c;
}
// and now save the binary representation
$decoded = array();
for($i=0; $i < 52; $i++)
{
$v = $encoded % $base;
$encoded = ($encoded - $v)/$base;
array_shift($v, $decoded);
}
哇,很好的答案。我仍然不明白爲什麼我不能將原始數據保存到MySQL中 - 如果我現在是存儲數據的最佳方式? –
mhm我從來沒有做過自己,但我會認爲這是至少可能的二進制類型的MySQL? - > http://dev.mysql.com/doc/refman/5.0/en/binary-varbinary.html還是你的意思是將單個位存儲到字段中? (我認爲這在技術上是不合理的) – Filou
是的,我的意思是單個比特。假設我需要存儲一些數據,並且知道一些關於這些數據的信息,這些數據在比特級別進行了非常高效的加密。 –
您是如何提高效率的?檢索時間?內存空間?隨機播放速度?這聽起來像是你想要在這裏提高內存效率,這是基於你如何提出問題,所以我必須問,爲什麼要使用MySQL數據庫,如果6位和128位之間的差異是交易斷路器? – Magnum
表格會有很多行,但說實話,這是因爲我很好奇:-) - 它看起來很簡單(存儲和檢索一串比特),但我做不到。 –
同意瑪格南。但爲了給出可能的答案,爲什麼不嘗試chr()? (你不能有小於一個字節的任何東西..)如果它不是字符串友好的嘗試一個二進制1字節列?但出於興趣,你的洗牌過程(在db?)看起來像什麼? – Filou