Today i had my first serious experience with Adobe Alchemy. It's appeared as a pretty good tool for some tasks.
My task was to try and add C library poker-eval into my project. This library is de-facto standard of poker hand calculations. It has a heavily macro C-style source and you can't just rewrite it on any other language.
There is however a pretty good attempt to rewrite part of library logic onto actionscript: http://blog.houen.net/actionscript-3-poker-hand-evaluator/. Unfortunately there is a problem of speed. It's pretty good if you need to compute value of only one hand (ex: show combo name to player), but it you want to compute thousands its worthless. I wanted to compute thousands :)
So my steps where:
First, download poker-eval source. Comprehend that it's not comprehensible and move on.
Second, download Adobe Alchemy (http://labs.adobe.com/technologies/alchemy/). Read it's samples. All of them pretty basic but gives an idea how to work with it. Try to compile some of it sample. README file is always a good start.
Third, try to compile poker-eval with adobe alchemy's compiler. May be you will have more luck with it, but i didn't. It didn't compile sending obscure messages about errors in some auto-generated as3 wrappers.
After having no luck with compilation i decided to take parts of poker-eval into my project.
I can't provide full source code, but you can easily follow from here. That what i got:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "AS3.h"
#include "pe/lib/t_astudcardmasks.c"
#include "pe/lib/t_botcard.c"
#include "pe/lib/t_botfivecards.c"
#include "pe/lib/t_botfivecardsj.c"
#include "pe/lib/t_cardmasks.c"
#include "pe/lib/t_evx_flushcards.c"
#include "pe/lib/t_evx_pairval.c"
#include "pe/lib/t_evx_strval.c"
#include "pe/lib/t_evx_tripsval.c"
#include "pe/lib/t_jokercardmasks.c"
#include "pe/lib/t_jokerstraight.c"
#include "pe/lib/t_maskrank.c"
#include "pe/lib/t_nbits.c"
#include "pe/lib/t_nbitsandstr.c"
#include "pe/lib/t_straight.c"
#include "pe/lib/t_topbit.c"
#include "pe/lib/t_topcard.c"
#include "pe/lib/t_topfivebits.c"
#include "pe/lib/t_topfivecards.c"
#include "pe/lib/t_toptwobits.c"
#include "pe/include/inlines/eval.h"
#include "pe/include/inlines/eval_type.h"
#include "pe/include/poker_defs.h"
#include "pe/lib/deck.c"
#include "pe/lib/deck_std.c"
#include "pe/lib/enumerate.c"
// a C thunk for an AS3 function
// takes to string params: "2s 3s 4s 5s 6s", "2d 3d"
AS3_Val pokerEntry(void *data, AS3_Val args)
{
// set up some vars w/ default values
char *board_c;
char *player_c;
char buf[256];
// parse the input args (if there are <3 args, not all vars
// will be set and will retain default values
AS3_ArrayValue(args, "StrType, StrType", &board_c, &player_c);
fprintf(stderr, "Board %s, %d", board_c, strlen(board_c));
fprintf(stderr, "Player %s, %d", player_c, strlen(player_c));
CardMask board; /**< cards on table */
CardMask player; /**< cards in hand */
CardMask_RESET(board);
CardMask_RESET(player);
int i;
int card;
char *p;
for (p = board_c; *p; p += 3) {
if (Deck_stringToCard(p, &card) == 0) {
fprintf(stderr, "ERROR!");
return AS3_String("error");
}
CardMask_SET(board, card);
}
fprintf(stderr, "Board mask %lld", board.cards_n);
fprintf(stderr, "Board cards by mast %s", StdDeck_maskString(board));
card = 0;
for (p = player_c; *p; p += 3) {
if (Deck_stringToCard(p, &card) == 0) {
fprintf(stderr, "ERROR!");
return AS3_String("error");
}
CardMask_SET(player, card);
}
fprintf(stderr, "Players mask %lld", player.cards_n);
fprintf(stderr, "Players card by mask %s", StdDeck_maskString(player));
// put something in the buf
sprintf(buf, "Yo %s | %s | %f", board_c, player_c);
// return it
return AS3_String(buf);
}
int main()
{
// regular function
AS3_Val pokerEntryVal = AS3_Function(NULL, pokerEntry);
// construct an object that holds refereces to the 2 functions
AS3_Val result = AS3_Object("pokerEntry: AS3ValType",
pokerEntryVal);
AS3_Release(pokerEntryVal);
// notify that we initialized -- THIS DOES NOT RETURN!
AS3_LibInit(result);
// XXX never get here!
return 0;
}
Lets follow my steps further. Now you need to take include and lib directories from poker-eval source and put them into pe/include and pe/lib directories under your project root.
Next you will need pre-compiled tables (all thous t_ files). This is how you make them: go to poker-eval source root and run ./configure then go into lib directory and run make. After libs finish building you will have all thous t_ files. Copy them into pe/include directory.
Now if you run make in your alchemy project after some crunching it will produce test.swc file.
Copy test.swc file into your as3/flex project. This is how you run pokerEntry function:
package
{
import cmodule.test.CLibInit;
class MyClass
{
static public var poker_eval:*;
public function MyClass()
{
trace("Initing");
var lib:CLibInit = new CLibInit();
trace("Inited");
poker_eval = lib.init();
poker_eval.pokerEntry("2s 3s 4s 5s 6s", "2d 3d");
}
}
}
If everything goes well you will see masks of your hands. Now you can run native poker-eval function such as Hand_EVAL_N!
On my benchmarks (MacPro i5) this code is 40 times faster than as3 code and only 100 times slower than same code in compiled and run in native environment (you may not believe it but it's a great result for as3)!
Good information here. casinogamesfun I will post these information to my facebook page. It is really very informative for others.
ReplyDelete