PageRenderTime 50ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/magic_ccparse.php

https://github.com/harvimt/magic_ccparse
PHP | 275 lines | 193 code | 29 blank | 53 comment | 42 complexity | 96a6f0b6d5f5c98f6c1aab602c9aaa88 MD5 | raw file
  1. <?php
  2. /** Author: Mark Harviston
  3. * Purpose: normalize (sort, reduce) Magic: The Gathering color codes
  4. *
  5. * (c) 2010 Mark Harviston <infinull@gmail.com> Some Rights Reserved
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. #color wheel node
  22. class cwn {
  23. public $next;
  24. public $data;
  25. public function __construct($data){$this->data = $data;}
  26. }
  27. #Magic Colorcode parser
  28. function ccparse($str='', $html=false, $ability=false){
  29. /* normalize $str or turn into html
  30. * if $html set to true, output <img> tags to the gatherer
  31. * returns normalized mana cost string or HTML (if $html is true)
  32. * if $ability is set to true, process T for tap, Q for untap, and F for
  33. * flip as well as manacodes
  34. */
  35. $str = strtoupper($str);
  36. //accept the gatherer style strings (2/B) instead of {2B}
  37. //also turn brackets([]) into curlies just 'coz
  38. $str = str_replace('/','',$str); //remove '/'
  39. $str = strtr($str, '()[]','{}{}'); //normalize parentheticals
  40. assert(preg_match('/^([0-9SWUBRGTQFX]+|\{[0-9WUBRGS]+})*$/',$str));
  41. //must contain only digit, space, color code or {}, X or T(tap)
  42. //X and/or Tap(T), flip(F), and untap(Q) must not be w/i {}
  43. //There must be only one nested level of {}
  44. //
  45. if (! $ablity){
  46. $str = strtr($str, 'TQF', '');
  47. }
  48. $colorless = 0;
  49. $colors = array();
  50. $colors[0] = array();
  51. #pass 1 get curly brace code
  52. preg_match_all('/\{([^}]+)}/', $str, $matches);
  53. //var_dump($matches);
  54. foreach ($matches[1] as $match){
  55. preg_match_all('/\d+/', $match, $matches2);
  56. $colorless2 = 0;
  57. foreach ($matches2[0] as $match2){
  58. $colorless2 += $match2;
  59. }
  60. if(empty($colorless2)){
  61. $colorless2 = '';
  62. }
  63. $match = preg_replace('/\d+/', '', $match);
  64. //reorder doubles
  65. $arr = str_split($match);
  66. usort($arr,'magic_cc_cmp');
  67. $match = implode($arr);
  68. $match = $colorless2 . $match;
  69. if(isset($colors[strlen($match)][$match])){
  70. $colors[strlen($match)][$match]++;
  71. }else{
  72. $colors[strlen($match)][$match] = 1;
  73. }
  74. if(isset($colors[0][$match])){
  75. $colors[0][$match]++;
  76. }else{
  77. $colors[0][$match] = 1;
  78. }
  79. }
  80. $str = preg_replace('/{[^}]+\}/', '', $str); //remove curly brace codes
  81. #pass 2 get colorless
  82. #get all digits that are next to each other
  83. preg_match_all('/\d+/', $str, $matches);
  84. foreach ($matches[0] as $match){
  85. $colorless += $match;
  86. }
  87. #pass 3 parse out regular codes
  88. $str = preg_replace('/\d+|\s+/', '', $str); //remove digits, whitespace
  89. $len = strlen($str);
  90. for($i = 0; $i < $len; $i++){
  91. if(isset($colors[1][$str[$i]])){
  92. $colors[1][$str[$i]]++;
  93. }else{
  94. $colors[1][$str[$i]] = 1;
  95. }
  96. if(isset($colors[0][$str[$i]])){
  97. $colors[0][$str[$i]]++;
  98. }else{
  99. $colors[0][$str[$i]] = 1;
  100. }
  101. }
  102. /*X will be parsed as $colors[0]['X'], should probably check to see if
  103. that's present*/
  104. $Xs = 0;
  105. if (isset($colors[1]['X'])){
  106. $Xs = $colors[1]['X'];
  107. unset($colors[1]['X']);
  108. }
  109. if(isset($colors[5]['WUBRG'])){
  110. $colorless += $colors[5]['WUBRG']; //All color mana is the same thing as
  111. //colorless mana. or is it?
  112. unset($colors[5]['WUBRG']);
  113. }
  114. $out = '';
  115. //render colorless and X
  116. if($html){
  117. $out .= str_repeat(clrtoimg('X'), $Xs);
  118. }else{
  119. $out .= str_repeat('X', $Xs);
  120. }
  121. //var_dump( empty($colors[0]) );
  122. if(!empty($colorless) || empty($colors[0])){
  123. if($html){
  124. $out .= clrtoimg($colorless);
  125. }else{
  126. $out .= $colorless;
  127. }
  128. }
  129. //Render multi-colors first
  130. if (false){
  131. //Render multi-colors
  132. for($i = 4; $i > 1; $i--){
  133. if(isset($colors[$i]) && is_array($colors[$i])) {
  134. uksort($colors[$i], 'magic_cc_sort_cmp');
  135. foreach($colors[$i] as $color => $qty){
  136. if($html){
  137. $out .= str_repeat(clrtoimg($color), $qty);
  138. }else{
  139. $out .= str_repeat('{' . $color . '}', $qty);
  140. }
  141. }
  142. }
  143. }
  144. //Render single colors
  145. if (isset($colors[1]) && is_array($colors[1])){
  146. uksort($colors[$i],'magic_cc_sort_cmp');
  147. foreach ($colors[1] as $color => $qty){
  148. if($html){
  149. $out .= str_repeat(clrtoimg($color), $qty);
  150. }else{
  151. $out .= str_repeat($color, $qty);
  152. }
  153. }
  154. }
  155. } else {
  156. //Render all colors at once (sort "in-between" instead of "multis-first")
  157. uksort($colors[0], 'magic_cc_sort_cmp');
  158. foreach ($colors[0] as $color => $qty){
  159. if (strlen($color) > 1){
  160. if ($html){
  161. $out .= str_repeat(clrtoimg($color), $qty);
  162. } else {
  163. $out .= str_repeat('{' . $color . '}', $qty);
  164. }
  165. } else {
  166. if ($html){
  167. $out .= str_repeat(clrtoimg($color), $qty);
  168. } else {
  169. $out .= str_repeat($color, $qty);
  170. }
  171. }
  172. }
  173. }
  174. //Handle, T,Q, and F (tap, untap, and flip) rendering
  175. foreach ( array('T','Q','F') as $i){
  176. if (isset($colors[1][$i])){
  177. if ($out != ''){
  178. $out .= ', ';
  179. }
  180. if($html){
  181. $out .= clrtoimg($i);
  182. }else{
  183. $out .= $i;
  184. }
  185. }
  186. }
  187. return $out;
  188. }
  189. function clrtoimg($clr){
  190. $clr = strtr($clr,
  191. array(
  192. 'T' => 'tap',
  193. 'Q' => 'untap',
  194. 'F' => 'flip', //The gatherer doens't have a symbol, but this way the alt-text will be correct
  195. 'X' => 'x',
  196. 'S' => 'snow',
  197. )
  198. );
  199. return "<img alt=\"$clr\" src=\"http://gatherer.wizards.com/handlers/image.ashx?size=medium&name=$clr&type=symbol\"/>";
  200. }
  201. function magic_cc_sort_cmp($a, $b){
  202. $a = strtr($a,'SWUBRG','abcdef');
  203. $b = strtr($b, 'SWUBRG','abcdef');
  204. return strcmp($a,$b);
  205. }
  206. //compare two colors
  207. function magic_cc_cmp($a,$b){
  208. $colorwheel = $W = new cwn('W');
  209. $U = new cwn('U');
  210. $B = new cwn('B');
  211. $R = new cwn('R');
  212. $G = new cwn('G');
  213. $W->next = $U;
  214. $U->next = $B;
  215. $B->next = $R;
  216. $R->next = $G;
  217. $G->next = $W;
  218. if($a == $b) return 0;
  219. if($a == 'S') return -1; //snow always sorts to the front.
  220. $current = $$a;
  221. for($i = 0; $i < 3; $i++){ //if less than 3 hops away, less than
  222. if($current->data == $b){
  223. return -1;
  224. }
  225. $current = $current->next;
  226. }
  227. return 1; //else greater than
  228. }
  229. function test_magic(){
  230. //unit tester, sort of
  231. assert(ccparse('3W') == '3W');
  232. assert(ccparse('34W') == '34W');
  233. assert(ccparse('3 4W') == '7W');
  234. //assert(ccparse('5WGB {GB} {BG} {3B} {RGU}') == '5{3B}WB{BG}{BG}{RGU}{G}'); //if you use the other sorting method this will fail
  235. //echo ccparse('5WGB {GB} {BG} {3B} {RGU}');
  236. ccparse("{GB}{BG}{WU}{UW}{UB}{BU}{BR}{RB}{GW}{WG}{WB}{UR}{RU}{RW}{WR}{GU}{UG}");
  237. ccparse("{WUBRG}{GRBUW}");
  238. ccparse("XR");
  239. ccparse("");
  240. ccparse("{RG}RG");
  241. ccparse('{2G}{BG}{RG}');
  242. ccparse('W{BU}');
  243. ccparse('{2BU}{2BU}{2BU}');
  244. echo ccparse('T5WGB {GB} {BG} {2B} {WBR}', true);
  245. }
  246. test_magic();