jl777
9 years ago
34 changed files with 3294 additions and 1101 deletions
@ -0,0 +1,4 @@ |
|||
<div class="form-group"> |
|||
<label for="%s">%s</label> |
|||
<textarea class="form-control" name="%s" rows="1" cols="%s" %s></textarea> |
|||
</div> |
@ -0,0 +1,12 @@ |
|||
</div> |
|||
|
|||
</div> |
|||
|
|||
<!-- API fileds --> |
|||
|
|||
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> |
|||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script> |
|||
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script> |
|||
<!-- Include all compiled plugins (below), or include individual files as needed --> |
|||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script> |
|||
</body></html> |
@ -0,0 +1,19 @@ |
|||
|
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="form-group"> |
|||
<label for="broadcast">Response</label> |
|||
<figure class="highlight" for="%s" disabled=""> |
|||
<pre> |
|||
<code id="%s" class="language-html" data-lang="javascript"></code> |
|||
</pre> |
|||
</figure> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<input type="submit" value="%s" class="btn btn-default"> |
|||
</form> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
@ -0,0 +1,16 @@ |
|||
|
|||
<div class="panel panel-default"> |
|||
<div class="panel-heading" role="tab" id="heading-%s"> |
|||
<h4 class="panel-title"> |
|||
<a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse-%s" aria-expanded="false" aria-controls="collapse-%s"> |
|||
%s %s |
|||
</a> |
|||
</h4> |
|||
</div> |
|||
<div id="collapse-%s" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading-%s"> |
|||
<div class="panel-body"> |
|||
|
|||
<form action="http://127.0.0.1:7778/api/%s/%s" oninput="%s"> |
|||
<div class="row"> |
|||
<div class="col-md-6"> |
|||
|
@ -0,0 +1,49 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|||
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> |
|||
<title>SuperNET API></title> |
|||
|
|||
|
|||
<!-- Bootstrap --> |
|||
<!-- Latest compiled and minified CSS --> |
|||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous"> |
|||
|
|||
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> |
|||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// --> |
|||
<!--[if lt IE 9]> |
|||
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> |
|||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> |
|||
<![endif]--> |
|||
|
|||
<!-- Optional theme --> |
|||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous"> |
|||
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css"> |
|||
|
|||
</head> |
|||
<body> |
|||
|
|||
<!-- Navigation Bar --> |
|||
<div class="navbar navbar-default" role="navigation"> |
|||
<div class="container" style="min-width: 90%;"> |
|||
<div class="navbar-header"> |
|||
<a class="navbar-brand" href="#">SuperNET API</a> |
|||
</div> |
|||
<div class="navbar-collapse collapse"> |
|||
<ul class="nav navbar-nav navbar-right"> |
|||
<li><a href="https://phabricator.supernet.org/w/" target="_blank" style="margin-left:20px;">Developer Wiki</a></li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- Navigation Bar --> |
|||
|
|||
<!-- API fileds --> |
|||
<div class="container" style="min-width: 90%"> |
|||
|
|||
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true"> |
|||
|
|||
|
@ -0,0 +1,4 @@ |
|||
<div class="form-group"> |
|||
<label for="%s">%s</label> |
|||
<textarea class="form-control" name="%s" rows="1" cols="%s" %s></textarea> |
|||
</div> |
@ -0,0 +1,12 @@ |
|||
</div> |
|||
|
|||
</div> |
|||
|
|||
<!-- API fileds --> |
|||
|
|||
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> |
|||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script> |
|||
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script> |
|||
<!-- Include all compiled plugins (below), or include individual files as needed --> |
|||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script> |
|||
</body></html> |
@ -0,0 +1,19 @@ |
|||
|
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="form-group"> |
|||
<label for="broadcast">Response</label> |
|||
<figure class="highlight" for="%s" disabled=""> |
|||
<pre> |
|||
<code id="%s" class="language-html" data-lang="javascript"></code> |
|||
</pre> |
|||
</figure> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<input type="submit" value="%s" class="btn btn-default"> |
|||
</form> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
@ -0,0 +1,16 @@ |
|||
|
|||
<div class="panel panel-default"> |
|||
<div class="panel-heading" role="tab" id="heading-%s"> |
|||
<h4 class="panel-title"> |
|||
<a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse-%s" aria-expanded="false" aria-controls="collapse-%s"> |
|||
%s %s |
|||
</a> |
|||
</h4> |
|||
</div> |
|||
<div id="collapse-%s" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading-%s"> |
|||
<div class="panel-body"> |
|||
|
|||
<form action="http://127.0.0.1:7778/api/%s/%s" oninput="%s"> |
|||
<div class="row"> |
|||
<div class="col-md-6"> |
|||
|
@ -0,0 +1,49 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|||
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> |
|||
<title>SuperNET API></title> |
|||
|
|||
|
|||
<!-- Bootstrap --> |
|||
<!-- Latest compiled and minified CSS --> |
|||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous"> |
|||
|
|||
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> |
|||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// --> |
|||
<!--[if lt IE 9]> |
|||
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> |
|||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> |
|||
<![endif]--> |
|||
|
|||
<!-- Optional theme --> |
|||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous"> |
|||
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css"> |
|||
|
|||
</head> |
|||
<body> |
|||
|
|||
<!-- Navigation Bar --> |
|||
<div class="navbar navbar-default" role="navigation"> |
|||
<div class="container" style="min-width: 90%;"> |
|||
<div class="navbar-header"> |
|||
<a class="navbar-brand" href="#">SuperNET API</a> |
|||
</div> |
|||
<div class="navbar-collapse collapse"> |
|||
<ul class="nav navbar-nav navbar-right"> |
|||
<li><a href="https://phabricator.supernet.org/w/" target="_blank" style="margin-left:20px;">Developer Wiki</a></li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- Navigation Bar --> |
|||
|
|||
<!-- API fileds --> |
|||
<div class="container" style="min-width: 90%"> |
|||
|
|||
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true"> |
|||
|
|||
|
@ -1,3 +1,3 @@ |
|||
#iguana_html.c |
|||
|
|||
SOURCES := SuperNET.c SuperNET_hexmsg.c pangea_api.c pangea_funds.c cards777.c pangea_fsm.c pangea_network.c pangea_init.c poker.c ramchain_api.c iguana_tx.c iguana_wallet.c iguana_pubkeys.c iguana_recv.c iguana_bundles.c iguana_msg.c iguana_rpc.c iguana777.c iguana_chains.c iguana_peers.c iguana_accept.c iguana_bitmap.c iguana_init.c iguana_ramchain.c iguana_blocks.c iguana_json.c main.c |
|||
SOURCES := SuperNET.c SuperNET_hexmsg.c pangea_api.c pangea_bets.c cards777.c pangea_summary.c pangea_json.c pangea_hand.c poker.c ramchain_api.c iguana_tx.c iguana_wallet.c iguana_pubkeys.c iguana_recv.c iguana_bundles.c iguana_msg.c iguana_rpc.c iguana777.c iguana_chains.c iguana_peers.c iguana_accept.c iguana_bitmap.c iguana_init.c iguana_ramchain.c iguana_blocks.c iguana_json.c main.c |
|||
|
@ -0,0 +1,387 @@ |
|||
/******************************************************************************
|
|||
* Copyright © 2014-2016 The SuperNET Developers. * |
|||
* * |
|||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * |
|||
* the top-level directory of this distribution for the individual copyright * |
|||
* holder information and the developer policies on copyright and licensing. * |
|||
* * |
|||
* Unless otherwise agreed in a custom licensing agreement, no part of the * |
|||
* SuperNET software, including this file may be copied, modified, propagated * |
|||
* or distributed except according to the terms contained in the LICENSE file * |
|||
* * |
|||
* Removal or modification of this copyright notice is prohibited. * |
|||
* * |
|||
******************************************************************************/ |
|||
|
|||
#include "pangea777.h" |
|||
|
|||
void pangea_fold(struct supernet_info *myinfo,struct table_info *tp,struct player_info *player) |
|||
{ |
|||
uint8_t tmp; |
|||
//printf("player.%d folded\n",player); //getchar();
|
|||
tp->hand.handmask |= (1 << player->ind); |
|||
player->betstatus = CARDS777_FOLD; |
|||
player->action = CARDS777_FOLD; |
|||
tmp = player->ind; |
|||
pangea_summaryadd(myinfo,tp,CARDS777_FOLD,&tmp,sizeof(tmp),(void *)&player->bets,sizeof(player->bets)); |
|||
} |
|||
|
|||
int32_t pangea_bet(struct supernet_info *myinfo,struct table_info *tp,struct player_info *player,int64_t bet,int32_t action) |
|||
{ |
|||
uint64_t sum; uint8_t tmp; struct hand_info *hand = &tp->hand; |
|||
if ( Debuglevel > 2 ) |
|||
printf("PANGEA_BET[%d] <- %.8f\n",player->ind,dstr(bet)); |
|||
if ( player->betstatus == CARDS777_ALLIN ) |
|||
return(CARDS777_ALLIN); |
|||
else if ( player->betstatus == CARDS777_FOLD ) |
|||
return(CARDS777_FOLD); |
|||
if ( bet > 0 && bet >= player->balance ) |
|||
{ |
|||
bet = player->balance; |
|||
player->betstatus = action = CARDS777_ALLIN; |
|||
} |
|||
else |
|||
{ |
|||
if ( bet > hand->betsize && bet > hand->lastraise && bet < (hand->lastraise<<1) ) |
|||
{ |
|||
printf("pangea_bet %.8f not double %.8f, clip to lastraise\n",dstr(bet),dstr(hand->lastraise)); |
|||
bet = hand->lastraise; |
|||
action = CARDS777_RAISE; |
|||
} |
|||
} |
|||
sum = player->bets; |
|||
if ( sum+bet < hand->betsize && action != CARDS777_ALLIN ) |
|||
{ |
|||
pangea_fold(myinfo,tp,player); |
|||
action = CARDS777_FOLD; |
|||
if ( Debuglevel > 2 ) |
|||
printf("player.%d betsize %.8f < hand.betsize %.8f FOLD\n",player->ind,dstr(bet),dstr(hand->betsize)); |
|||
return(action); |
|||
} |
|||
else if ( bet >= 2*hand->lastraise ) |
|||
{ |
|||
hand->lastraise = bet; |
|||
hand->numactions = 0; |
|||
if ( action == CARDS777_CHECK ) |
|||
{ |
|||
action = CARDS777_FULLRAISE; // allows all players to check/bet again
|
|||
if ( Debuglevel > 2 ) |
|||
printf("FULLRAISE by player.%d\n",player->ind); |
|||
} |
|||
} |
|||
sum += bet; |
|||
if ( sum > hand->betsize ) |
|||
{ |
|||
hand->numactions = 0; |
|||
hand->betsize = sum, hand->lastbettor = player->ind; |
|||
if ( sum > hand->lastraise && action == CARDS777_ALLIN ) |
|||
hand->lastraise = sum; |
|||
else if ( action == CARDS777_CHECK ) |
|||
action = CARDS777_BET; |
|||
} |
|||
if ( bet > 0 && action == CARDS777_CHECK ) |
|||
action = CARDS777_CALL; |
|||
tmp = player->ind; |
|||
pangea_summaryadd(myinfo,tp,action,&tmp,sizeof(tmp),(void *)&bet,sizeof(bet)); |
|||
player->balance -= bet, player->bets += bet; |
|||
if ( Debuglevel > 2 ) |
|||
printf("player.%d: player.%d BET %f -> balances %f bets %f\n",tp->myind,player->ind,dstr(bet),dstr(player->balance),dstr(player->bets)); |
|||
return(action); |
|||
} |
|||
|
|||
void pangea_antes(struct supernet_info *myinfo,struct table_info *tp) |
|||
{ |
|||
int32_t i,n,N; struct player_info *p; uint64_t threshold; int32_t handid; |
|||
N = tp->numactive; |
|||
for (i=0; i<tp->G.N; i++) |
|||
{ |
|||
tp->G.P[i].ind = i; |
|||
if ( (tp->snapshot[i]= tp->G.P[i].balance) <= 0 ) |
|||
pangea_fold(myinfo,tp,&tp->G.P[i]); |
|||
} |
|||
handid = tp->numhands - 1; |
|||
pangea_summaryadd(myinfo,tp,CARDS777_SNAPSHOT,(void *)&handid,sizeof(handid),(void *)tp->snapshot,sizeof(uint64_t)*CARDS777_MAXPLAYERS); |
|||
if ( tp->G.ante != 0 ) |
|||
{ |
|||
for (i=0; i<N; i++) |
|||
{ |
|||
if ( (p= tp->active[i]) != 0 ) |
|||
{ |
|||
if ( p->balance < tp->G.ante ) |
|||
pangea_fold(myinfo,tp,p); |
|||
else pangea_bet(myinfo,tp,p,tp->G.ante,CARDS777_ANTE); |
|||
} else printf("unexpected null player ptr\n"); |
|||
} |
|||
} |
|||
for (i=n=0; i<N; i++) |
|||
{ |
|||
if ( i == 0 ) |
|||
threshold = (tp->G.bigblind >> 1) - 1; |
|||
else if ( i == 1 ) |
|||
threshold = tp->G.bigblind - 1; |
|||
else threshold = 0; |
|||
if ( (p= tp->active[i]) != 0 && p->balance < threshold ) |
|||
pangea_fold(myinfo,tp,p); |
|||
else n++; |
|||
} |
|||
if ( n < 2 ) |
|||
printf("pangea_antes not enough players n.%d\n",n); |
|||
else |
|||
{ |
|||
pangea_bet(myinfo,tp,tp->active[0],(tp->G.bigblind>>1),CARDS777_SMALLBLIND); |
|||
pangea_bet(myinfo,tp,tp->active[1],tp->G.bigblind,CARDS777_BIGBLIND); |
|||
|
|||
} |
|||
} |
|||
|
|||
void pangea_checkantes(struct supernet_info *myinfo,struct table_info *tp) |
|||
{ |
|||
int64_t bets[CARDS777_MAXPLAYERS+1]; int32_t i,N = tp->numactive; struct hand_info *hand = &tp->hand; |
|||
pangea_snapshot(tp,bets); |
|||
for (i=0; i<N; i++) |
|||
{ |
|||
//printf("%.8f ",dstr(dp->balances[i]));
|
|||
if ( bets[i] != 0 ) |
|||
break; |
|||
} |
|||
if ( i == N && hand->checkprod.txid != 0 ) |
|||
{ |
|||
for (i=0; i<N; i++) |
|||
if ( bets[i] != 0 ) |
|||
break; |
|||
if ( i == N ) |
|||
{ |
|||
//printf("i.%d vs N.%d call antes\n",i,N);
|
|||
pangea_antes(myinfo,tp); |
|||
} else printf("bets i.%d\n",i); |
|||
} |
|||
} |
|||
|
|||
uint64_t pangea_winnings(int32_t player,uint64_t *pangearakep,uint64_t *hostrakep,uint64_t total,int32_t numwinners,int32_t rakemillis,uint64_t maxrake) |
|||
{ |
|||
uint64_t split,pangearake,rake; |
|||
if ( numwinners > 0 ) |
|||
{ |
|||
split = (total * (1000 - rakemillis)) / (1000 * numwinners); |
|||
pangearake = (total - split*numwinners); |
|||
if ( pangearake > maxrake ) |
|||
{ |
|||
pangearake = maxrake; |
|||
split = (total - pangearake) / numwinners; |
|||
pangearake = (total - split*numwinners); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
split = 0; |
|||
pangearake = total; |
|||
} |
|||
if ( rakemillis > PANGEA_MINRAKE_MILLIS ) |
|||
{ |
|||
rake = (pangearake * (rakemillis - PANGEA_MINRAKE_MILLIS)) / rakemillis; |
|||
pangearake -= rake; |
|||
} |
|||
else rake = 0; |
|||
*hostrakep = rake; |
|||
*pangearakep = pangearake; |
|||
printf("\nP%d: rakemillis.%d total %.8f split %.8f rake %.8f pangearake %.8f\n",player,rakemillis,dstr(total),dstr(split),dstr(rake),dstr(pangearake)); |
|||
return(split); |
|||
} |
|||
|
|||
int32_t pangea_sidepots(struct supernet_info *myinfo,struct table_info *tp,int32_t dispflag,int64_t sidepots[CARDS777_MAXPLAYERS][CARDS777_MAXPLAYERS],int64_t *bets) |
|||
{ |
|||
int32_t i,j,nonz,N,n = 0; uint64_t bet,minbet = 0; |
|||
memset(sidepots,0,sizeof(uint64_t)*CARDS777_MAXPLAYERS*CARDS777_MAXPLAYERS); |
|||
N = tp->numactive; |
|||
for (j=0; j<N; j++) |
|||
sidepots[0][j] = bets[j]; |
|||
nonz = 1; |
|||
while ( nonz > 0 ) |
|||
{ |
|||
for (minbet=j=0; j<N; j++) |
|||
{ |
|||
if ( (bet= sidepots[n][j]) != 0 ) |
|||
{ |
|||
if ( tp->active[j] != 0 && tp->active[j]->betstatus != CARDS777_FOLD ) |
|||
{ |
|||
if ( minbet == 0 || bet < minbet ) |
|||
minbet = bet; |
|||
} |
|||
} |
|||
} |
|||
for (j=nonz=0; j<N; j++) |
|||
{ |
|||
if ( sidepots[n][j] > minbet && tp->active[j] != 0 && tp->active[j]->betstatus != CARDS777_FOLD ) |
|||
nonz++; |
|||
} |
|||
if ( nonz > 0 ) |
|||
{ |
|||
for (j=0; j<N; j++) |
|||
{ |
|||
if ( sidepots[n][j] > minbet ) |
|||
{ |
|||
sidepots[n+1][j] = (sidepots[n][j] - minbet); |
|||
sidepots[n][j] = minbet; |
|||
} |
|||
} |
|||
} |
|||
if ( ++n >= N ) |
|||
break; |
|||
} |
|||
if ( dispflag != 0 ) |
|||
{ |
|||
for (i=0; i<n; i++) |
|||
{ |
|||
for (j=0; j<N; j++) |
|||
printf("%.8f ",dstr(sidepots[i][j])); |
|||
printf("sidepot.%d of %d\n",i,n); |
|||
} |
|||
} |
|||
return(n); |
|||
} |
|||
|
|||
int64_t pangea_splitpot(struct supernet_info *myinfo,struct table_info *tp,uint64_t *pangearakep,int64_t sidepot[CARDS777_MAXPLAYERS],int32_t rakemillis) |
|||
{ |
|||
struct player_info *winners[CARDS777_MAXPLAYERS]; |
|||
int32_t j,n,N,numwinners = 0; uint32_t bestrank,rank; uint8_t tmp; struct player_info *p; |
|||
uint64_t total = 0,bet,split,maxrake,rake=0,pangearake=0; char handstr[128],besthandstr[128]; |
|||
N = tp->numactive; |
|||
bestrank = 0; |
|||
besthandstr[0] = 0; |
|||
for (j=n=0; j<N; j++) |
|||
{ |
|||
if ( (bet= sidepot[j]) != 0 ) |
|||
{ |
|||
total += bet; |
|||
if ( (p= tp->active[j]) != 0 && p->betstatus != CARDS777_FOLD ) |
|||
{ |
|||
if ( p->handrank > bestrank ) |
|||
{ |
|||
bestrank = p->handrank; |
|||
set_handstr(besthandstr,p->hand,0); |
|||
//printf("set besthandstr.(%s)\n",besthandstr);
|
|||
} |
|||
} |
|||
} |
|||
} |
|||
for (j=0; j<N; j++) |
|||
{ |
|||
if ( (p= tp->active[j]) != 0 && p->betstatus != CARDS777_FOLD && sidepot[j] > 0 ) |
|||
{ |
|||
if ( p->handrank == bestrank ) |
|||
winners[numwinners++] = p; |
|||
rank = set_handstr(handstr,p->hand,0); |
|||
if ( handstr[strlen(handstr)-1] == ' ' ) |
|||
handstr[strlen(handstr)-1] = 0; |
|||
//if ( hn->server->H.slot == 0 )
|
|||
printf("(p%d %14s)",j,handstr[0]!=' '?handstr:handstr+1); |
|||
//printf("(%2d %2d).%d ",dp->hands[j][5],dp->hands[j][6],(int32_t)dp->balances[j]);
|
|||
} |
|||
} |
|||
if ( numwinners == 0 ) |
|||
printf("pangea_splitpot error: numwinners.0\n"); |
|||
else |
|||
{ |
|||
uint64_t maxrakes[CARDS777_MAXPLAYERS+1] = { 0, 0, 1, 2, 2, 3, 3, 3, 3, 3 }; // 2players 1BB, 3-4players, 2BB, 5+players 3BB
|
|||
for (j=n=0; j<N; j++) |
|||
if ( (p= tp->active[j]) != 0 && p->bets > 0 ) |
|||
n++; |
|||
if ( (maxrake= maxrakes[n] * tp->G.bigblind) > tp->G.maxrake ) |
|||
{ |
|||
maxrake = tp->G.maxrake; |
|||
//if ( strcmp(dp->coinstr,"BTC") == 0 && maxrake < PANGEA_BTCMAXRAKE )
|
|||
// maxrake = PANGEA_BTCMAXRAKE;
|
|||
//else if ( maxrake < PANGEA_MAXRAKE )
|
|||
maxrake = PANGEA_MAXRAKE; |
|||
} |
|||
split = pangea_winnings(tp->priv.myind,&pangearake,&rake,total,numwinners,rakemillis,maxrake); |
|||
(*pangearakep) += pangearake; |
|||
for (j=0; j<numwinners; j++) |
|||
{ |
|||
tmp = winners[j]->ind; |
|||
pangea_summaryadd(myinfo,tp,CARDS777_WINNINGS,&tmp,sizeof(tmp),(void *)&split,sizeof(split)); |
|||
winners[j]->balance += split; |
|||
winners[j]->won += split; |
|||
} |
|||
if ( split*numwinners + rake + pangearake != total ) |
|||
printf("pangea_split total error %.8f != split %.8f numwinners %d rake %.8f pangearake %.8f\n",dstr(total),dstr(split),numwinners,dstr(rake),dstr(pangearake)); |
|||
//if ( hn->server->H.slot == 0 )
|
|||
{ |
|||
printf(" total %.8f split %.8f rake %.8f Prake %.8f hand.(%s) N%d winners ",dstr(total),dstr(split),dstr(rake),dstr(pangearake),besthandstr,tp->numhands); |
|||
for (j=0; j<numwinners; j++) |
|||
printf("%d ",winners[j]->ind); |
|||
printf("\n"); |
|||
} |
|||
} |
|||
return(rake); |
|||
} |
|||
|
|||
/*char *pangea_input(uint64_t my64bits,uint64_t tableid,cJSON *json)
|
|||
{ |
|||
char *actionstr; uint64_t sum,amount=0; int32_t action=0,num,threadid; struct table_info *sp; struct cards777_pubdata *dp; char hex[4096]; |
|||
threadid = juint(json,"threadid"); |
|||
if ( (sp= pangea_threadtables(&num,threadid,tableid)) == 0 ) |
|||
return(clonestr("{\"error\":\"you are not playing on any tables\"}")); |
|||
if ( 0 && num != 1 ) |
|||
return(clonestr("{\"error\":\"more than one active table\"}")); |
|||
else if ( (dp= sp->dp) == 0 ) |
|||
return(clonestr("{\"error\":\"no pubdata ptr for table\"}")); |
|||
else if ( dp->hand.undergun != pangea_ind(sp,sp->myslot) || dp->hand.betsize == 0 ) |
|||
{ |
|||
printf("undergun.%d threadid.%d myind.%d\n",dp->hand.undergun,sp->tp->threadid,pangea_ind(sp,sp->myslot)); |
|||
return(clonestr("{\"error\":\"not your turn\"}")); |
|||
} |
|||
else if ( (actionstr= jstr(json,"action")) == 0 ) |
|||
return(clonestr("{\"error\":\"on action specified\"}")); |
|||
else |
|||
{ |
|||
if ( strcmp(actionstr,"check") == 0 || strcmp(actionstr,"call") == 0 || strcmp(actionstr,"bet") == 0 || strcmp(actionstr,"raise") == 0 || strcmp(actionstr,"allin") == 0 || strcmp(actionstr,"fold") == 0 ) |
|||
{ |
|||
sum = dp->hand.bets[pangea_ind(sp,sp->myslot)]; |
|||
if ( strcmp(actionstr,"allin") == 0 ) |
|||
amount = sp->balances[sp->myslot], action = CARDS777_ALLIN; |
|||
else if ( strcmp(actionstr,"bet") == 0 ) |
|||
amount = j64bits(json,"amount"), action = 1; |
|||
else |
|||
{ |
|||
if ( dp->hand.betsize == sum ) |
|||
{ |
|||
if ( strcmp(actionstr,"check") == 0 || strcmp(actionstr,"call") == 0 ) |
|||
action = 0; |
|||
else if ( strcmp(actionstr,"raise") == 0 ) |
|||
{ |
|||
action = 1; |
|||
if ( (amount= dp->hand.lastraise) < j64bits(json,"amount") ) |
|||
amount = j64bits(json,"amount"); |
|||
} |
|||
else printf("unsupported userinput command.(%s)\n",actionstr); |
|||
} |
|||
else |
|||
{ |
|||
if ( strcmp(actionstr,"check") == 0 || strcmp(actionstr,"call") == 0 ) |
|||
action = 1, amount = (dp->hand.betsize - sum); |
|||
else if ( strcmp(actionstr,"raise") == 0 ) |
|||
{ |
|||
action = 2; |
|||
amount = (dp->hand.betsize - sum); |
|||
if ( amount < dp->hand.lastraise ) |
|||
amount = dp->hand.lastraise; |
|||
if ( j64bits(json,"amount") > amount ) |
|||
amount = j64bits(json,"amount"); |
|||
} |
|||
else if ( strcmp(actionstr,"fold") == 0 ) |
|||
action = 0; |
|||
else printf("unsupported userinput command.(%s)\n",actionstr); |
|||
} |
|||
} |
|||
if ( amount > sp->balances[sp->myslot] ) |
|||
amount = sp->balances[sp->myslot], action = CARDS777_ALLIN; |
|||
pangea_sendcmd(hex,&sp->tp->hn,"action",-1,(void *)&amount,sizeof(amount),dp->hand.cardi,action); |
|||
printf("ACTION.(%s)\n",hex); |
|||
return(clonestr("{\"result\":\"action submitted\"}")); |
|||
} |
|||
else return(clonestr("{\"error\":\"illegal action specified, must be: check, call, bet, raise, fold or allin\"}")); |
|||
} |
|||
}*/ |
|||
|
|||
|
@ -0,0 +1,933 @@ |
|||
/******************************************************************************
|
|||
* Copyright © 2014-2016 The SuperNET Developers. * |
|||
* * |
|||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * |
|||
* the top-level directory of this distribution for the individual copyright * |
|||
* holder information and the developer policies on copyright and licensing. * |
|||
* * |
|||
* Unless otherwise agreed in a custom licensing agreement, no part of the * |
|||
* SuperNET software, including this file may be copied, modified, propagated * |
|||
* or distributed except according to the terms contained in the LICENSE file * |
|||
* * |
|||
* Removal or modification of this copyright notice is prohibited. * |
|||
* * |
|||
******************************************************************************/ |
|||
|
|||
#include "pangea777.h" |
|||
|
|||
int32_t pangea_slotA(struct table_info *tp) { return(0); } |
|||
int32_t pangea_slotB(struct table_info *tp) { return(1); } |
|||
int32_t pangea_lastnode(struct table_info *tp) { return(tp->numactive-1); } |
|||
int32_t pangea_nextnode(struct table_info *tp) { return(tp->priv.myind+1); } |
|||
int32_t pangea_prevnode(struct table_info *tp) { return(tp->priv.myind-1); } |
|||
|
|||
void pangea_rwaudit(int32_t saveflag,bits256 *audit,bits256 *audits,int32_t cardi,int32_t destplayer,int32_t N) |
|||
{ |
|||
int32_t i; |
|||
audits = &audits[(cardi * N + destplayer) * N]; |
|||
if ( saveflag != 0 ) |
|||
{ |
|||
for (i=0; i<N; i++) |
|||
audits[i] = audit[i]; |
|||
} |
|||
else |
|||
{ |
|||
for (i=0; i<N; i++) |
|||
audit[i] = audits[i]; |
|||
} |
|||
} |
|||
|
|||
int32_t pangea_tableismine(struct supernet_info *myinfo,struct table_info *tp) |
|||
{ |
|||
int32_t i; |
|||
if ( tp->G.creatorbits == myinfo->myaddr.nxt64bits ) |
|||
{ |
|||
tp->G.ismine = tp->G.numactive; |
|||
return(tp->G.numactive); |
|||
} |
|||
else |
|||
{ |
|||
for (i=0; i<tp->G.numactive; i++) |
|||
if ( tp->G.P[i].nxt64bits == myinfo->myaddr.nxt64bits ) |
|||
{ |
|||
tp->G.ismine = 1; |
|||
return(i); |
|||
} |
|||
} |
|||
return(-1); |
|||
} |
|||
|
|||
int32_t pangea_Pind(struct table_info *tp,bits256 playerpub) |
|||
{ |
|||
int32_t i; |
|||
for (i=0; i<tp->G.N; i++) |
|||
{ |
|||
if ( memcmp(tp->G.P[i].playerpub.bytes,playerpub.bytes,sizeof(playerpub)) == 0 ) |
|||
return(i); |
|||
} |
|||
return(-1); |
|||
} |
|||
|
|||
int32_t pangea_actives(int32_t *activej,struct table_info *tp) |
|||
{ |
|||
int32_t i,n; struct player_info *p; |
|||
*activej = -1; |
|||
for (i=n=0; i<tp->numactive; i++) |
|||
{ |
|||
if ( (p= tp->active[i]) != 0 && p->betstatus != CARDS777_FOLD ) |
|||
{ |
|||
if ( *activej < 0 ) |
|||
*activej = i; |
|||
n++; |
|||
} |
|||
} |
|||
return(n); |
|||
} |
|||
|
|||
int32_t pangea_myrank(struct supernet_info *myinfo,struct table_info *tp,struct player_info *p) |
|||
{ |
|||
int32_t i; uint32_t myrank = p->handrank; |
|||
for (i=0; i<tp->numactive; i++) |
|||
if ( tp->active[i] != 0 && tp->active[i] != p && tp->active[i]->handrank > myrank ) |
|||
return(-1); |
|||
return(myrank != 0); |
|||
} |
|||
|
|||
void pangea_clearhand(struct table_info *tp) |
|||
{ |
|||
bits256 *final,*cardpubs; int32_t i; struct hand_info *hand = &tp->hand; |
|||
final = hand->final, cardpubs = hand->cardpubs; |
|||
memset(hand,0,sizeof(*hand)); |
|||
hand->final = final, hand->cardpubs = cardpubs; |
|||
memset(final,0,sizeof(*final) * tp->G.N * tp->G.numcards); |
|||
memset(cardpubs,0,sizeof(*cardpubs) * (1 + tp->G.numcards)); |
|||
for (i=0; i<5; i++) |
|||
hand->community[i] = 0xff; |
|||
for (i=0; i<tp->G.N; i++) |
|||
memset(tp->G.P[i].hand,0xff,sizeof(tp->G.P[i].hand)); |
|||
tp->priv.hole[0] = tp->priv.hole[1] = tp->priv.cardis[0] = tp->priv.cardis[1] = 0xff; |
|||
memset(tp->priv.holecards,0,sizeof(tp->priv.holecards)); |
|||
} |
|||
|
|||
uint32_t pangea_rank(struct supernet_info *myinfo,struct table_info *tp,int32_t senderind) |
|||
{ |
|||
int32_t i; char handstr[128]; struct player_info *p; struct hand_info *hand = &tp->hand; |
|||
if ( senderind < tp->G.N && (p= tp->active[senderind]) != 0 ) |
|||
{ |
|||
if ( p->handrank != 0 ) |
|||
return(p->handrank); |
|||
for (i=0; i<7; i++) |
|||
{ |
|||
if ( i < 5 ) |
|||
p->hand[i] = hand->community[i]; |
|||
if ( p->hand[i] == 0xff ) |
|||
break; |
|||
} |
|||
if ( i == 7 ) |
|||
{ |
|||
p->handrank = set_handstr(handstr,p->hand,0); |
|||
hand->handmask |= (1 << senderind); |
|||
PNACL_message("sender.%d (%s) rank.%x handmask.%x\n",senderind,handstr,p->handrank,hand->handmask); |
|||
} |
|||
return(p->handrank); |
|||
} |
|||
printf("pangea_rank.%d illegal senderind\n",senderind); |
|||
return(0); |
|||
} |
|||
|
|||
// "state machine" funcs
|
|||
int32_t pangea_newdeck(struct supernet_info *myinfo,struct table_info *tp) |
|||
{ |
|||
bits256 *playerpubs; int32_t i,j,n,datalen,button; struct hand_info *hand = &tp->hand; |
|||
button = (tp->numhands % tp->G.N); |
|||
pangea_clearhand(tp); |
|||
playerpubs = &hand->cardpubs[tp->G.numcards + 1]; |
|||
for (j=n=0; j<tp->G.N; j++) |
|||
{ |
|||
i = (j + button) % tp->G.N; |
|||
if ( tp->G.P[i].balance > 0 ) |
|||
playerpubs[n++] = tp->G.P[i].playerpub; |
|||
} |
|||
if ( n < tp->G.minplayers ) |
|||
{ |
|||
printf("pangea_newdeck %d < %d minplayers\n",n,tp->G.minplayers); |
|||
return(-1); |
|||
} |
|||
hand->checkprod = hand->cardpubs[tp->G.numcards] = cards777_initdeck(tp->priv.outcards,hand->cardpubs,tp->G.numcards,n,playerpubs,0); |
|||
datalen = (tp->G.numcards + 1 + n) * sizeof(bits256); |
|||
pangea_sendcmd(myinfo,tp,"newhand",-1,hand->cardpubs[0].bytes,datalen,n,n); |
|||
PNACL_message("host sends NEWDECK checkprod.%llx numhands.%d\n",(long long)hand->checkprod.txid,tp->numhands); |
|||
return(0); |
|||
} |
|||
|
|||
void pangea_newhand(PANGEA_HANDARGS) |
|||
{ |
|||
int32_t i,handid,numcards,n,ind; struct hand_info *hand; bits256 *pubkeys; |
|||
hand = &tp->hand; |
|||
numcards = tp->G.numcards; |
|||
if ( data == 0 || datalen != (numcards + 1) * sizeof(bits256) ) |
|||
{ |
|||
PNACL_message("pangea_newhand invalid datalen.%d vs %ld\n",datalen,(long)((numcards + 1) * sizeof(bits256))); |
|||
return; |
|||
} |
|||
pubkeys = (bits256 *)data; |
|||
n = pm->turni; |
|||
tp->myind = -1; |
|||
for (i=0; i<n; i++) |
|||
{ |
|||
if ( (ind= pangea_Pind(tp,pubkeys[numcards + 1 + i])) < 0 ) |
|||
{ |
|||
printf("illegal pubkey, cant find player[%d]\n",i); |
|||
return; |
|||
} |
|||
tp->active[i] = &tp->G.P[ind]; |
|||
if ( i == 0 ) |
|||
hand->button = ind; |
|||
if ( tp->G.P[ind].nxt64bits == myinfo->myaddr.nxt64bits ) |
|||
tp->priv.myind = i; |
|||
} |
|||
tp->priv.mypriv = myinfo->privkey, tp->priv.mypub = myinfo->myaddr.pubkey; |
|||
tp->G.M = (tp->numactive >> 1) + 1; |
|||
hand->startdecktime = pm->sig.timestamp; |
|||
memcpy(hand->cardpubs,pubkeys,numcards * sizeof(bits256)); |
|||
PNACL_message("player.%d NEWHAND.%llx received numhands.%d button.%d cardi.%d | N %d numactive.%d\n",tp->myind,(long long)hand->cardpubs[numcards].txid,tp->numhands,hand->button,hand->cardi,tp->G.N,n); |
|||
hand->checkprod = cards777_pubkeys(hand->cardpubs,numcards,hand->cardpubs[numcards]); |
|||
if ( bits256_cmp(hand->checkprod,hand->cardpubs[numcards]) != 0 ) |
|||
{ |
|||
printf("checkprod mismatch myind.%d\n",tp->myind); |
|||
return; |
|||
} |
|||
tp->numactive = n; |
|||
memset(tp->summary,0,sizeof(tp->summary)); |
|||
hand->summaries = hand->mismatches = tp->summarysize = 0; |
|||
handid = tp->numhands++; |
|||
pangea_summaryadd(myinfo,tp,CARDS777_START,&handid,sizeof(handid),hand->cardpubs[0].bytes,sizeof(bits256) * (numcards + 1)); |
|||
if ( tp->myind >= 0 ) |
|||
pangea_sendcmd(myinfo,tp,"gotdeck",-1,hand->checkprod.bytes,sizeof(bits256),hand->cardi,hand->button); |
|||
} |
|||
|
|||
void pangea_checkstart(struct supernet_info *myinfo,struct table_info *tp) |
|||
{ |
|||
int32_t i; struct hand_info *hand = &tp->hand; |
|||
if ( bits256_nonz(hand->checkprod) > 0 && hand->encodestarted == 0 ) |
|||
{ |
|||
for (i=0; i<tp->numactive; i++) |
|||
{ |
|||
if ( bits256_cmp(hand->othercardpubs[i],hand->checkprod) != 0 ) |
|||
break; |
|||
} |
|||
if ( i == tp->numactive ) |
|||
{ |
|||
if ( PANGEA_PAUSE > 0 ) |
|||
sleep(PANGEA_PAUSE); |
|||
if ( time(NULL) > (tp->myind*3 + hand->startdecktime) ) |
|||
{ |
|||
hand->encodestarted = (uint32_t)time(NULL); |
|||
PNACL_message("SERVERSTATE issues encoded %llx\n",(long long)hand->checkprod.txid); |
|||
pangea_sendcmd(myinfo,tp,"encoded",pangea_slotB(tp),tp->priv.outcards[0].bytes,sizeof(bits256) * tp->numactive * tp->G.numcards,tp->numactive*tp->G.numcards,-1); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
void pangea_gotdeck(PANGEA_HANDARGS) |
|||
{ |
|||
int32_t i,senderind; uint64_t total = 0; |
|||
senderind = pm->myind; |
|||
tp->hand.othercardpubs[senderind] = *(bits256 *)data; |
|||
if ( Debuglevel > 2 ) |
|||
{ |
|||
for (i=0; i<tp->G.N; i++) |
|||
{ |
|||
total += tp->G.P[i].balance; |
|||
PNACL_message("(p%d %.8f) ",i,dstr(tp->G.P[i].balance)); |
|||
} |
|||
PNACL_message("balances %.8f [%.8f] | ",dstr(total),dstr(total + tp->G.hostrake + tp->G.pangearake)); |
|||
PNACL_message("player.%d pangea_gotdeck from P.%d otherpubs.%llx\n",tp->myind,senderind,(long long)tp->hand.othercardpubs[senderind].txid); |
|||
} |
|||
pangea_checkstart(myinfo,tp); |
|||
} |
|||
|
|||
void pangea_encoded(PANGEA_HANDARGS) |
|||
{ |
|||
bits256 audit[CARDS777_MAXPLAYERS]; int32_t i,iter,cardi,destplayer,N = tp->numactive; |
|||
struct hand_info *hand = &tp->hand; |
|||
if ( N <= 1 || data == 0 || datalen != (tp->G.numcards * N) * sizeof(bits256) ) |
|||
{ |
|||
PNACL_message("pangea_encode invalid datalen.%d vs %ld\n",datalen,(long)((tp->G.numcards * N) * sizeof(bits256))); |
|||
return; |
|||
} |
|||
hand->encodestarted = pm->sig.timestamp; |
|||
cards777_encode(tp->priv.outcards,tp->priv.xoverz,tp->priv.allshares,tp->priv.myshares,hand->sharenrs[tp->myind],tp->G.M,(void *)data,tp->G.numcards,N); |
|||
PNACL_message("player.%d ind.%d encodes into %p %llx -> %llx next.%d N %d\n",tp->myind,tp->myind,tp->priv.outcards,(long long)*(uint64_t *)data,(long long)tp->priv.outcards[0].txid,pangea_nextnode(tp),N); |
|||
if ( tp->myind > 0 ) |
|||
{ |
|||
if ( tp->myind < tp->numactive-1 ) |
|||
{ |
|||
//PNACL_message("send encoded\n");
|
|||
pangea_sendcmd(myinfo,tp,"encoded",pangea_nextnode(tp),tp->priv.outcards[0].bytes,datalen,N*tp->G.numcards,-1); |
|||
} |
|||
else |
|||
{ |
|||
memcpy(hand->final,tp->priv.outcards,sizeof(bits256)*N*tp->G.numcards); |
|||
pangea_sendcmd(myinfo,tp,"final",-1,tp->priv.outcards[0].bytes,datalen,N*tp->G.numcards,-1); |
|||
for (iter=cardi=0; iter<2; iter++) |
|||
for (i=0; i<N; i++,cardi++) |
|||
for (destplayer=0; destplayer<N; destplayer++) |
|||
{ |
|||
pangea_rwaudit(0,audit,tp->priv.audits,cardi,destplayer,N); |
|||
audit[0] = hand->final[cardi*N + destplayer]; |
|||
pangea_rwaudit(1,audit,tp->priv.audits,cardi,destplayer,N); |
|||
} |
|||
PNACL_message("call preflop %ld\n",(long)((2 * N) * (N * N * sizeof(bits256)))); |
|||
pangea_preflop(myinfo,pm,tp,tp->priv.audits[0].bytes,(2 * N) * (N * N * sizeof(bits256))); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void pangea_final(PANGEA_HANDARGS) |
|||
{ |
|||
if ( data == 0 || datalen != (tp->G.numcards * tp->numactive) * sizeof(bits256) ) |
|||
{ |
|||
PNACL_message("pangea_final invalid datalen.%d vs %ld\n",datalen,(long)((tp->G.numcards * tp->numactive) * sizeof(bits256))); |
|||
return; |
|||
} |
|||
if ( Debuglevel > 2 ) |
|||
PNACL_message("player.%d final into %p\n",tp->myind,tp->priv.outcards); |
|||
memcpy(tp->hand.final,data,sizeof(bits256) * tp->numactive * tp->G.numcards); |
|||
} |
|||
|
|||
void pangea_preflop(PANGEA_HANDARGS) |
|||
{ |
|||
int32_t i,iter,cardi,destplayer,maxlen,N; bits256 audit[CARDS777_MAXPLAYERS]; |
|||
N = tp->numactive; |
|||
maxlen = (int32_t)(2 * N * N * CARDS777_MAXCARDS * sizeof(bits256)); |
|||
if ( N <= 1 || data == 0 || datalen != (2 * N) * (N * N * sizeof(bits256)) ) |
|||
{ |
|||
PNACL_message("pangea_preflop invalid datalen.%d vs %ld\n",datalen,(long)(2 * N) * (N * N * sizeof(bits256))); |
|||
return; |
|||
} |
|||
//PNACL_message("preflop player.%d\n",tp->myind);
|
|||
memcpy(tp->priv.audits,data,datalen); |
|||
if ( tp->myind != pangea_slotA(tp) && tp->myind != pangea_slotB(tp) ) |
|||
{ |
|||
//for (i=0; i<tp->G.numcards*N; i++)
|
|||
// PNACL_message("%llx ",(long long)tp->priv.outcards[i].txid);
|
|||
//PNACL_message("player.%d outcards\n",tp->myind);
|
|||
for (cardi=0; cardi<N*2; cardi++) |
|||
for (destplayer=0; destplayer<N; destplayer++) |
|||
{ |
|||
pangea_rwaudit(0,audit,tp->priv.audits,cardi,destplayer,N); |
|||
//if ( 1 && (card= cards777_checkcard(&cardpriv,cardi,tp->myind,destplayer,hn->client->H.privkey,hand->cardpubs,tp->G.numcards,audit[0])) >= 0 )
|
|||
//PNACL_message("ERROR: unexpected decode player.%d got card.[%d]\n",tp->myind,card);
|
|||
audit[0] = cards777_decode(&audit[tp->myind],tp->priv.xoverz,destplayer,audit[0],tp->priv.outcards,tp->G.numcards,N); |
|||
pangea_rwaudit(1,audit,tp->priv.audits,cardi,destplayer,N); |
|||
} |
|||
//PNACL_message("issue preflop\n");
|
|||
pangea_sendcmd(myinfo,tp,"preflop",pangea_prevnode(tp),tp->priv.audits[0].bytes,datalen,N * 2 * N,-1); |
|||
} |
|||
else |
|||
{ |
|||
//PNACL_message("sendout cards\n");
|
|||
for (iter=cardi=0; iter<2; iter++) |
|||
for (i=0; i<N; i++,cardi++) |
|||
{ |
|||
destplayer = (tp->hand.button + i) % N; |
|||
pangea_rwaudit(0,audit,tp->priv.audits,cardi,destplayer,N); |
|||
//PNACL_message("audit[0] %llx -> ",(long long)audit[0].txid);
|
|||
audit[0] = cards777_decode(&audit[tp->myind],tp->priv.xoverz,destplayer,audit[0],tp->priv.outcards,tp->G.numcards,N); |
|||
pangea_rwaudit(1,audit,tp->priv.audits,cardi,destplayer,N); |
|||
//PNACL_message("[%llx + %llx] ",*(long long *)&audit[0],(long long)&audit[tp->myind]);
|
|||
if ( destplayer == tp->myind ) |
|||
pangea_card(myinfo,pm,tp,audit[0].bytes,sizeof(bits256)*N); |
|||
else pangea_sendcmd(myinfo,tp,"card",destplayer,audit[0].bytes,sizeof(bits256)*N,cardi,-1); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void pangea_card(PANGEA_HANDARGS) |
|||
{ |
|||
struct hand_info *hand; int32_t destplayer,card,selector,N,cardi,validcard = -1; |
|||
bits256 cardpriv,audit[CARDS777_MAXPLAYERS]; char cardAstr[8],cardBstr[8]; struct player_info *destp; |
|||
N = tp->numactive, cardi = pm->cardi, destplayer = pm->destplayer; hand = &tp->hand; |
|||
destp = tp->active[destplayer]; |
|||
if ( N <= 1 || data == 0 || datalen != sizeof(bits256)*N || destp == 0 ) |
|||
{ |
|||
PNACL_message("pangea_card invalid datalen.%d vs %ld\n",datalen,(long)sizeof(bits256)*N); |
|||
return; |
|||
} |
|||
pangea_rwaudit(1,(void *)data,tp->priv.audits,cardi,destplayer,N); |
|||
pangea_rwaudit(0,audit,tp->priv.audits,cardi,destplayer,N); |
|||
//PNACL_message("card.%d destplayer.%d [%llx]\n",cardi,destplayer,(long long)audit[0].txid);
|
|||
if ( (card= cards777_checkcard(&cardpriv,cardi,tp->myind,destplayer,myinfo->privkey,hand->cardpubs,tp->G.numcards,audit[0])) >= 0 ) |
|||
{ |
|||
destplayer = tp->myind; |
|||
if ( Debuglevel > 2 ) |
|||
PNACL_message("player.%d got card.[%d]\n",tp->myind,card); |
|||
selector = (cardi / N); |
|||
tp->priv.holecards[selector] = cardpriv; |
|||
tp->priv.cardis[selector] = cardi; |
|||
destp->hand[5 + selector] = tp->priv.hole[selector] = cardpriv.bytes[1]; |
|||
validcard = 1; |
|||
cardAstr[0] = cardBstr[0] = 0; |
|||
if ( tp->priv.hole[0] != 0xff ) |
|||
cardstr(cardAstr,tp->priv.hole[0]); |
|||
if ( tp->priv.hole[1] != 0xff ) |
|||
cardstr(cardBstr,tp->priv.hole[1]); |
|||
PNACL_message(">>>>>>>>>> dest.%d holecards[%02d] cardi.%d / N %d (%02d %02d) -> (%s %s)\n",destplayer,tp->priv.hole[cardi / N],cardi,N,tp->priv.hole[0],tp->priv.hole[1],cardAstr,cardBstr); |
|||
if ( cards777_validate(cardpriv,hand->final[cardi*N + destplayer],hand->cardpubs,tp->G.numcards,audit,N,tp->priv.mypub) < 0 ) |
|||
PNACL_message("player.%d decoded cardi.%d card.[%02d] but it doesnt validate\n",tp->myind,cardi,card); |
|||
} else PNACL_message("ERROR player.%d got no card %llx\n",tp->myind,*(long long *)data); |
|||
if ( cardi < N*2 ) |
|||
pangea_sendcmd(myinfo,tp,"facedown",-1,(void *)&cardi,sizeof(cardi),cardi,validcard); |
|||
else pangea_sendcmd(myinfo,tp,"faceup",-1,cardpriv.bytes,sizeof(cardpriv),cardi,0xff); |
|||
} |
|||
|
|||
int64_t pangea_snapshot(struct table_info *tp,int64_t *snapshot) |
|||
{ |
|||
struct player_info *p; int64_t betsize; int32_t i,N = tp->numactive; |
|||
memcpy(snapshot,0,N * sizeof(int64_t)); |
|||
for (betsize=i=0; i<N; i++) |
|||
{ |
|||
if ( (p= tp->active[i]) != 0 ) |
|||
{ |
|||
if ( p->bets > betsize ) |
|||
betsize = p->bets; |
|||
snapshot[i] = p->bets; |
|||
} else snapshot[i] = 0; |
|||
} |
|||
snapshot[N] = betsize; |
|||
return(betsize); |
|||
} |
|||
|
|||
void pangea_startbets(struct supernet_info *myinfo,struct table_info *tp,int32_t cardi) |
|||
{ |
|||
uint32_t now,i,N = tp->numactive; struct player_info *p; int64_t snapshot[CARDS777_MAXPLAYERS+1]; |
|||
struct hand_info *hand = &tp->hand; |
|||
if ( PANGEA_PAUSE > 0 ) |
|||
sleep(PANGEA_PAUSE); |
|||
if ( hand->betstarted == 0 ) |
|||
hand->betstarted = 1; |
|||
else hand->betstarted++; |
|||
hand->numactions = 0; |
|||
hand->cardi = cardi; |
|||
now = (uint32_t)time(NULL); |
|||
for (i=0; i<CARDS777_MAXPLAYERS; i++) |
|||
{ |
|||
p = &tp->G.P[i]; |
|||
p->action = 0; |
|||
p->turni = 0xff; |
|||
if ( cardi > N*2 ) |
|||
p->snapshot = p->bets; |
|||
} |
|||
hand->undergun = ((hand->button + 3) % N); |
|||
if ( cardi < N*2 ) |
|||
pangea_checkantes(myinfo,tp); |
|||
hand->betsizesnapshot = hand->betsize = pangea_snapshot(tp,snapshot); |
|||
printf("STARTBETS.%d cardi.%d numactions.%d undergun.%d betsize %.8f N %d\n",hand->betstarted,cardi,hand->numactions,hand->undergun,dstr(hand->betsize),N); |
|||
pangea_sendcmd(myinfo,tp,"turn",-1,(void *)snapshot,sizeof(*snapshot)*(N+1),cardi,hand->undergun); |
|||
} |
|||
|
|||
void pangea_facedown(PANGEA_HANDARGS) |
|||
{ |
|||
int32_t i,validcard,cardi,senderind,N,n = 0; uint64_t havemask; struct player_info *p; |
|||
N = tp->numactive, senderind = pm->myind, cardi = pm->cardi; |
|||
p = tp->active[senderind]; |
|||
if ( p == 0 || N <= 1 || data == 0 || datalen != sizeof(int32_t) ) |
|||
{ |
|||
PNACL_message("pangea_facedown invalid datalen.%d vs %ld\n",datalen,(long)sizeof(bits256)); |
|||
return; |
|||
} |
|||
validcard = pm->turni; |
|||
if ( validcard > 0 ) |
|||
p->havemask |= (1LL << cardi); |
|||
if ( Debuglevel > 2 ) |
|||
PNACL_message(" | player.%d sees that destplayer.%d got cardi.%d valid.%d | %llx | n.%d\n",tp->myind,senderind,cardi,validcard,(long long)p->havemask,n); |
|||
for (i=0; i<N; i++) |
|||
{ |
|||
if ( (p= tp->active[i]) != 0 ) |
|||
{ |
|||
havemask = p->havemask; |
|||
if ( Debuglevel > 2 ) |
|||
PNACL_message("%llx ",(long long)havemask); |
|||
if ( bitweight(havemask) == 2 ) |
|||
n++; |
|||
} |
|||
} |
|||
if ( tp->myind == pangea_slotA(tp) && n == N ) |
|||
pangea_startbets(myinfo,tp,N*2); |
|||
} |
|||
|
|||
void pangea_faceup(PANGEA_HANDARGS) |
|||
{ |
|||
int32_t cardi,validcard,i,senderind,N; struct hand_info *hand; uint16_t tmp; struct player_info *p,*destp; |
|||
N = tp->numactive, senderind = pm->myind, cardi = pm->cardi, hand = &tp->hand; |
|||
destp = tp->active[senderind]; |
|||
if ( destp == 0 || N <= 1 || data == 0 || datalen != sizeof(bits256) ) |
|||
{ |
|||
PNACL_message("pangea_faceup invalid datalen.%d vs %ld\n",datalen,(long)((tp->G.numcards + 1) * sizeof(bits256))); |
|||
return; |
|||
} |
|||
validcard = (pm->turni >= 0); |
|||
if ( Debuglevel > 2 || tp->myind == pangea_slotA(tp) ) |
|||
{ |
|||
PNACL_message("from.%d -> player.%d COMMUNITY.[%d] cardi.%d valid.%d\n",senderind,tp->myind,data[1],cardi,validcard); |
|||
} |
|||
//PNACL_message("got FACEUP.(%s)\n",jprint(json,0));
|
|||
if ( validcard > 0 ) |
|||
{ |
|||
tmp = (cardi << 8); |
|||
tmp |= (pm->turni & 0xff); |
|||
pangea_summaryadd(myinfo,tp,CARDS777_FACEUP,&tmp,sizeof(tmp),data,sizeof(bits256)); |
|||
if ( cardi >= N*2 && cardi < N*2+5 ) |
|||
{ |
|||
hand->community[cardi - N*2] = data[1]; |
|||
for (i=0; i<N; i++) |
|||
{ |
|||
if ( (p= tp->active[i]) != 0 ) |
|||
p->hand[cardi - N*2] = data[1]; |
|||
} |
|||
memcpy(hand->community256[cardi - N*2].bytes,data,sizeof(bits256)); |
|||
PNACL_message("set community[%d] <- %d\n",cardi - N*2,data[1]); |
|||
if ( senderind == tp->myind ) |
|||
pangea_rank(myinfo,tp,senderind); |
|||
if ( tp->myind == pangea_slotA(tp) && cardi >= N*2+2 && cardi < N*2+5 ) |
|||
pangea_startbets(myinfo,tp,cardi+1); |
|||
//else PNACL_message("dont start bets %d\n",cardi+1);
|
|||
} |
|||
else |
|||
{ |
|||
PNACL_message("valid.%d cardi.%d vs N.%d\n",validcard,cardi,N); |
|||
if ( cardi < N*2 ) |
|||
{ |
|||
memcpy(hand->cards[senderind][cardi/N].bytes,data,sizeof(bits256)); |
|||
destp->hand[5 + cardi/N] = data[1]; |
|||
pangea_rank(myinfo,tp,senderind); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
void pangea_turn(PANGEA_HANDARGS) |
|||
{ |
|||
int32_t turni,cardi,senderind,N; struct player_info *destp; |
|||
int64_t snapshot[CARDS777_MAXPLAYERS+1]; struct hand_info *hand = &tp->hand; |
|||
N = tp->numactive, senderind = pm->myind, turni = pm->turni, cardi = pm->cardi; |
|||
destp = tp->active[senderind]; |
|||
if ( destp == 0 || N <= 1 ) |
|||
{ |
|||
PNACL_message("pangea_turn illegal arg\n"); |
|||
return; |
|||
} |
|||
if ( Debuglevel > 2 ) |
|||
printf("P%d: got turn.%d from %d | cardi.%d summary[%d] crc.%u\n",tp->myind,turni,senderind,cardi,tp->summarysize,calc_crc32(0,tp->summary,tp->summarysize)); |
|||
destp->turni = turni; |
|||
if ( senderind == 0 ) |
|||
{ |
|||
hand->cardi = cardi; |
|||
hand->betstarted = 1; |
|||
hand->undergun = turni; |
|||
if ( tp->myind != pangea_slotA(tp) ) |
|||
{ |
|||
pangea_checkantes(myinfo,tp); |
|||
hand->betsizesnapshot = pangea_snapshot(tp,snapshot); |
|||
//printf("player.%d sends confirmturn.%d\n",tp->myind,turni);
|
|||
pangea_sendcmd(myinfo,tp,"confirm",-1,(void *)snapshot,sizeof(uint64_t)*(N+1),cardi,turni); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void pangea_confirm(PANGEA_HANDARGS) |
|||
{ |
|||
uint32_t starttime; int32_t i,N,senderind,turni,cardi; uint64_t betsize=0,amount=0; |
|||
int64_t snapshot[CARDS777_MAXPLAYERS+1]; struct player_info *p; struct hand_info *hand; |
|||
N = tp->numactive, senderind = pm->myind, turni = pm->turni, cardi = pm->cardi; |
|||
hand = &tp->hand; p = tp->active[senderind]; |
|||
if ( p == 0 || N <= 1 || data == 0 ) |
|||
{ |
|||
printf("pangea_turn: null data\n"); |
|||
return; |
|||
} |
|||
printf("got confirmturn.%d cardi.%d sender.%d\n",turni,cardi,senderind); |
|||
//if ( datalen == sizeof(betsize) )
|
|||
// memcpy(&betsize,data,sizeof(betsize));
|
|||
starttime = hand->starttime; |
|||
if ( senderind == 0 && tp->myind != pangea_slotA(tp) ) |
|||
{ |
|||
hand->undergun = turni; |
|||
hand->cardi = cardi; |
|||
betsize = pangea_snapshot(tp,snapshot); |
|||
if ( betsize != hand->betsizesnapshot ) |
|||
printf("T%d ERROR BETSIZE MISMATCH: %.8f vs %.8f\n",tp->priv.myind,dstr(betsize),dstr(hand->betsizesnapshot)); |
|||
hand->betsize = betsize; |
|||
} |
|||
p->turni = turni; |
|||
for (i=0; i<N; i++) |
|||
{ |
|||
if ( (p= tp->active[i]) != 0 && p->turni != turni ) |
|||
break; |
|||
} |
|||
//printf("sp.%p vs turni.%d cardi.%d hand.cardi %d\n",sp,turni,cardi,hand->cardi);
|
|||
if ( tp->myind == pangea_slotA(tp) && i == N ) |
|||
{ |
|||
betsize = pangea_snapshot(tp,snapshot); |
|||
hand->betsize = hand->betsizesnapshot = betsize; |
|||
//if ( Debuglevel > 2 )
|
|||
printf("player.%d sends confirmturn.%d cardi.%d betsize %.0f\n",tp->myind,hand->undergun,hand->cardi,dstr(betsize)); |
|||
if ( senderind != 0 ) |
|||
pangea_sendcmd(myinfo,tp,"confirm",-1,(void *)snapshot,sizeof(*snapshot)*(N+1),hand->cardi,hand->undergun); |
|||
} |
|||
if ( senderind == 0 && (turni= hand->undergun) == tp->myind && (p= tp->active[senderind]) != 0 ) |
|||
{ |
|||
if ( hand->betsize != betsize ) |
|||
printf("P%d: pangea_turn warning hand.betsize %.8f != betsize %.8f\n",tp->myind,dstr(hand->betsize),dstr(betsize)); |
|||
//if ( sp->isbot[tp->priv.myind] != 0 )
|
|||
// pangea_bot(myinfo,tp,turni,cardi,betsize);
|
|||
//else
|
|||
if ( p->betstatus == CARDS777_FOLD || p->betstatus == CARDS777_ALLIN ) |
|||
pangea_sendcmd(myinfo,tp,"action",-1,(void *)&amount,sizeof(amount),cardi,0); |
|||
else if ( tp->priv.autofold != 0 ) |
|||
pangea_sendcmd(myinfo,tp,"action",-1,(void *)&amount,sizeof(amount),cardi,0); |
|||
else |
|||
{ |
|||
hand->userinput_starttime = (uint32_t)time(NULL); |
|||
hand->cardi = cardi; |
|||
hand->betsize = betsize; |
|||
fprintf(stderr,"Waiting for user input cardi.%d: ",cardi); |
|||
} |
|||
if ( tp->myind == pangea_slotA(tp) ) |
|||
{ |
|||
char *str = jprint(pangea_tablestatus(myinfo,tp),1); |
|||
printf("%s\n",str); |
|||
free(str); |
|||
} |
|||
//pangea_statusprint(dp,priv,tp->myind);
|
|||
} |
|||
} |
|||
|
|||
void pangea_finish(struct supernet_info *myinfo,struct table_info *tp) |
|||
{ |
|||
int64_t tsnap,sidepots[CARDS777_MAXPLAYERS][CARDS777_MAXPLAYERS];//,list[CARDS777_MAXPLAYERS];
|
|||
uint64_t pangearake,rake; int64_t balances[CARDS777_MAXPLAYERS],bets[CARDS777_MAXPLAYERS+1]; |
|||
uint32_t changes; uint16_t busted,rebuy; int32_t j,n,r,N,norake = 0; struct hand_info *hand; |
|||
N = tp->numactive, hand = &tp->hand; |
|||
if ( hand->finished == 0 ) |
|||
{ |
|||
memset(sidepots,0,sizeof(sidepots)); |
|||
pangea_snapshot(tp,bets); |
|||
n = pangea_sidepots(myinfo,tp,1,sidepots,bets); |
|||
if ( hand->community[0] == 0xff ) |
|||
norake = 1; |
|||
for (pangearake=rake=j=0; j<n; j++) |
|||
rake += pangea_splitpot(myinfo,tp,&pangearake,sidepots[j],norake == 0 ? tp->G.rakemillis : 0); |
|||
hand->finished = (uint32_t)time(NULL); |
|||
tp->hostrake += rake; |
|||
tp->pangearake += pangearake; |
|||
tp->G.hostrake = rake; |
|||
tp->G.pangearake = pangearake; |
|||
for (j=busted=rebuy=r=0; j<N; j++) |
|||
{ |
|||
if ( tp->active[j] != 0 ) |
|||
{ |
|||
balances[j] = tp->active[j]->balance; |
|||
tsnap = tp->snapshot[tp->active[j]->ind]; |
|||
//balances[j] += hand->won[j];
|
|||
//sp->balances[pangea_slot(sp,j)] = balances[j];
|
|||
if ( tsnap > 0 && balances[j] <= 0 ) |
|||
{ |
|||
busted |= (1 << j); |
|||
//list[r++] = sp->active[j];
|
|||
} |
|||
else if ( tsnap <= 0 && balances[j] > 0 ) |
|||
rebuy |= (1 << j); |
|||
} |
|||
} |
|||
changes = (((uint32_t)rebuy<<20) | ((uint32_t)busted<<4) | (tp->G.N&0xf)); |
|||
pangea_summaryadd(myinfo,tp,CARDS777_CHANGES,(void *)&changes,sizeof(changes),(void *)balances,sizeof(uint64_t)*tp->G.N); |
|||
pangea_summaryadd(myinfo,tp,CARDS777_RAKES,(void *)&rake,sizeof(rake),(void *)&pangearake,sizeof(pangearake)); |
|||
if ( tp->priv.myind == pangea_slotA(tp) ) |
|||
{ |
|||
char *sumstr,*statstr; |
|||
statstr = jprint(pangea_tablestatus(myinfo,tp),1); |
|||
sumstr = pangea_dispsummary(myinfo,tp,1,tp->summary,tp->summarysize,tp->G.tablehash,tp->numhands-1,tp->G.N); |
|||
printf("%s\n\n%s",statstr,sumstr); |
|||
free(statstr), free(sumstr); |
|||
pangea_sendcmd(myinfo,tp,"summary",-1,tp->summary,tp->summarysize,0,0); |
|||
} |
|||
/*if ( 0 && busted != 0 )
|
|||
{ |
|||
for (j=0; j<r; j++) |
|||
{ |
|||
if ( list[j] != sp->active[0] ) |
|||
{ |
|||
pangea_inactivate(dp,sp,list[j]); |
|||
printf("T%d: INACTIVATE.[%d] %llu\n",sp->myslot,j,(long long)list[j]); |
|||
} |
|||
} |
|||
}*/ |
|||
} |
|||
} |
|||
|
|||
int32_t pangea_lastman(struct supernet_info *myinfo,struct table_info *tp) |
|||
{ |
|||
int32_t activej = -1; struct hand_info *hand = &tp->hand; |
|||
if ( hand->betstarted != 0 && pangea_actives(&activej,tp) <= 1 ) |
|||
{ |
|||
if ( hand->finished != 0 ) |
|||
{ |
|||
printf("DUPLICATE LASTMAN!\n"); |
|||
return(1); |
|||
} |
|||
if ( 0 && tp->myind == activej && tp->priv.automuck == 0 ) |
|||
{ |
|||
pangea_sendcmd(myinfo,tp,"faceup",-1,tp->priv.holecards[0].bytes,sizeof(tp->priv.holecards[0]),tp->priv.cardis[0],tp->priv.cardis[0] != 0xff); |
|||
pangea_sendcmd(myinfo,tp,"faceup",-1,tp->priv.holecards[1].bytes,sizeof(tp->priv.holecards[1]),tp->priv.cardis[1],tp->priv.cardis[1] != 0xff); |
|||
} |
|||
pangea_finish(myinfo,tp); |
|||
return(1); |
|||
} |
|||
return(0); |
|||
} |
|||
|
|||
void pangea_action(PANGEA_HANDARGS) |
|||
{ |
|||
uint32_t now; struct player_info *p; int64_t x,snapshot[CARDS777_MAXPLAYERS + 1]; |
|||
int32_t action,cardi,i,j,senderind,N,destplayer = 0; |
|||
bits256 audit[CARDS777_MAXPLAYERS]; struct hand_info *hand; uint8_t tmp; uint64_t amount = 0; |
|||
action = pm->turni, senderind = pm->myind, cardi = pm->cardi, N = tp->numactive, hand = &tp->hand; |
|||
p = tp->active[senderind]; |
|||
memcpy(&amount,data,sizeof(amount)); |
|||
if ( N <= 1 || p == 0 || cardi < 2*N ) |
|||
{ |
|||
printf("pangea_action: illegal cardi.%d\n",cardi); |
|||
return; |
|||
} |
|||
if ( senderind != hand->undergun ) |
|||
{ |
|||
printf("T%d: out of turn action.%d by player.%d (undergun.%d) cardi.%d amount %.8f\n",tp->myind,action,senderind,hand->undergun,cardi,dstr(amount)); |
|||
return; |
|||
} |
|||
tmp = senderind; |
|||
pangea_bet(myinfo,tp,tp->active[pm->myind],amount,CARDS777_CHECK); |
|||
p->action = action; |
|||
hand->undergun = (hand->undergun + 1) % N; |
|||
hand->numactions++; |
|||
if ( Debuglevel > 2 )//|| tp->myind == 0 )
|
|||
printf("player.%d: got action.%d cardi.%d senderind.%d -> undergun.%d numactions.%d\n",tp->myind,action,cardi,senderind,hand->undergun,hand->numactions); |
|||
if ( pangea_lastman(myinfo,tp) > 0 ) |
|||
return; |
|||
if ( tp->myind == pangea_slotA(tp) ) |
|||
{ |
|||
now = (uint32_t)time(NULL); |
|||
for (i=j=0; i<N; i++) |
|||
{ |
|||
j = (hand->undergun + i) % N; |
|||
if ( (p= tp->active[j]) != 0 ) |
|||
{ |
|||
if ( p->betstatus == CARDS777_FOLD || p->betstatus == CARDS777_ALLIN ) |
|||
{ |
|||
p->action = p->betstatus; |
|||
//printf("skip player.%d\n",j);
|
|||
hand->numactions++; |
|||
} else break; |
|||
} |
|||
} |
|||
hand->undergun = j; |
|||
if ( hand->numactions < N ) |
|||
{ |
|||
//printf("T%d: senderind.%d i.%d j.%d -> undergun.%d numactions.%d\n",tp->myind,senderind,i,j,hand->undergun,hand->numactions);
|
|||
//if ( senderind != 0 )
|
|||
memset(snapshot,0,sizeof(*snapshot)*(N+1)); |
|||
for (x=i=0; i<N; i++) |
|||
if ( (p= tp->active[i]) != 0 ) |
|||
{ |
|||
if ( p->snapshot > x ) |
|||
x = p->snapshot; |
|||
snapshot[i] = p->snapshot; |
|||
} |
|||
snapshot[N] = x; |
|||
pangea_sendcmd(myinfo,tp,"turn",-1,(void *)snapshot,sizeof(*snapshot)*(N+1),hand->cardi,hand->undergun); |
|||
} |
|||
else |
|||
{ |
|||
for (i=0; i<5; i++) |
|||
{ |
|||
if ( hand->community[i] == 0xff ) |
|||
break; |
|||
printf("%02x ",hand->community[i]); |
|||
} |
|||
printf("COMMUNITY\n"); |
|||
if ( i == 0 ) |
|||
{ |
|||
if ( hand->cardi != N * 2 ) |
|||
printf("cardi mismatch %d != %d\n",hand->cardi,N * 2); |
|||
cardi = hand->cardi; |
|||
printf("decode flop\n"); |
|||
for (i=0; i<3; i++,cardi++) |
|||
{ |
|||
memset(audit,0,sizeof(audit)); |
|||
audit[0] = hand->final[cardi*N + destplayer]; |
|||
pangea_sendcmd(myinfo,tp,"decoded",-1,audit[0].bytes,sizeof(bits256)*N,cardi,N-1); |
|||
} |
|||
} |
|||
else if ( i == 3 ) |
|||
{ |
|||
if ( hand->cardi != N * 2+3 ) |
|||
printf("cardi mismatch %d != %d\n",hand->cardi,N * 2 + 3); |
|||
cardi = hand->cardi; |
|||
printf("decode turn\n"); |
|||
memset(audit,0,sizeof(audit)); |
|||
audit[0] = hand->final[cardi*N + destplayer]; |
|||
pangea_sendcmd(myinfo,tp,"decoded",-1,audit[0].bytes,sizeof(bits256)*N,cardi,N-1); |
|||
//pangea_sendcmd(myinfo,tp,"decoded",-1,hand->final[cardi*N + destplayer].bytes,sizeof(hand->final[cardi*N + destplayer]),cardi,N-1);
|
|||
} |
|||
else if ( i == 4 ) |
|||
{ |
|||
printf("decode river\n"); |
|||
if ( hand->cardi != N * 2+4 ) |
|||
printf("cardi mismatch %d != %d\n",hand->cardi,N * 2+4); |
|||
cardi = hand->cardi; |
|||
memset(audit,0,sizeof(audit)); |
|||
audit[0] = hand->final[cardi*N + destplayer]; |
|||
pangea_sendcmd(myinfo,tp,"decoded",-1,audit[0].bytes,sizeof(bits256)*N,cardi,N-1); |
|||
//pangea_sendcmd(myinfo,tp,"decoded",-1,hand->final[cardi*N + destplayer].bytes,sizeof(hand->final[cardi*N + destplayer]),cardi,N-1);
|
|||
} |
|||
else |
|||
{ |
|||
cardi = N * 2 + 5; |
|||
if ( hand->cardi != N * 2+5 ) |
|||
printf("cardi mismatch %d != %d\n",hand->cardi,N * 2+5); |
|||
for (i=0; i<N; i++) |
|||
{ |
|||
j = (hand->lastbettor + i) % N; |
|||
if ( tp->active[j] != 0 && tp->active[j]->betstatus != CARDS777_FOLD ) |
|||
break; |
|||
} |
|||
hand->undergun = j; |
|||
printf("sent showdown request for undergun.%d\n",j); |
|||
pangea_sendcmd(myinfo,tp,"showdown",-1,(void *)&hand->betsize,sizeof(hand->betsize),cardi,hand->undergun); |
|||
} |
|||
} |
|||
} |
|||
if ( Debuglevel > 2 )// || tp->myind == 0 )
|
|||
{ |
|||
char *str = jprint(pangea_tablestatus(myinfo,tp),1); |
|||
printf("player.%d got pangea_action.%d for player.%d action.%d amount %.8f | numactions.%d\n%s\n",tp->myind,cardi,senderind,action,dstr(amount),hand->numactions,str); |
|||
free(str); |
|||
} |
|||
} |
|||
|
|||
void pangea_decoded(PANGEA_HANDARGS) |
|||
{ |
|||
int32_t cardi,destplayer,card,turni,N; bits256 cardpriv,audit[CARDS777_MAXPLAYERS]; struct hand_info *hand; |
|||
cardi = pm->cardi, turni = pm->turni, N = tp->numactive, hand = &tp->hand; |
|||
if ( N <= 1 || data == 0 || datalen != sizeof(bits256)*N ) |
|||
{ |
|||
PNACL_message("pangea_decoded invalid datalen.%d vs %ld\n",datalen,(long)sizeof(bits256)); |
|||
return; |
|||
} |
|||
if ( cardi < N*2 || cardi >= N*2 + 5 ) |
|||
{ |
|||
PNACL_message("pangea_decoded invalid cardi.%d\n",cardi); |
|||
return; |
|||
} |
|||
destplayer = 0; |
|||
pangea_rwaudit(1,(void *)data,tp->priv.audits,cardi,destplayer,N); |
|||
pangea_rwaudit(0,audit,tp->priv.audits,cardi,destplayer,N); |
|||
if ( turni == tp->myind ) |
|||
{ |
|||
if ( tp->myind != pangea_slotA(tp) ) |
|||
{ |
|||
audit[0] = cards777_decode(&audit[tp->myind],tp->priv.xoverz,destplayer,audit[0],tp->priv.outcards,tp->G.numcards,N); |
|||
pangea_rwaudit(1,audit,tp->priv.audits,cardi,destplayer,N); |
|||
pangea_sendcmd(myinfo,tp,"decoded",-1,audit[0].bytes,sizeof(bits256)*N,cardi,pangea_prevnode(tp)); |
|||
} |
|||
else |
|||
{ |
|||
if ( (card= cards777_checkcard(&cardpriv,cardi,tp->myind,tp->myind,tp->priv.mypriv,hand->cardpubs,tp->G.numcards,audit[0])) >= 0 ) |
|||
{ |
|||
if ( cards777_validate(cardpriv,hand->final[cardi*N + destplayer],hand->cardpubs,tp->G.numcards,audit,N,tp->priv.mypub) < 0 ) |
|||
PNACL_message("player.%d decoded cardi.%d card.[%d] but it doesnt validate\n",tp->myind,cardi,card); |
|||
pangea_sendcmd(myinfo,tp,"faceup",-1,cardpriv.bytes,sizeof(cardpriv),cardi,cardpriv.txid!=0?0xff:-1); |
|||
//PNACL_message("-> FACEUP.(%s)\n",hex);
|
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
void pangea_showdown(PANGEA_HANDARGS) |
|||
{ |
|||
struct player_info *p; int32_t i,turni,N,cardi,myind; struct hand_info *hand; uint64_t amount=0; |
|||
cardi = pm->cardi, turni = pm->turni, N = tp->numactive, hand = &tp->hand; |
|||
myind = tp->priv.myind; |
|||
if ( (p= tp->active[myind]) == 0 ) |
|||
{ |
|||
printf("error nullp myind.%d\n",myind); |
|||
return; |
|||
} |
|||
if ( Debuglevel > 2 ) |
|||
printf("P%d: showdown from sender.%d\n",myind,pm->myind); |
|||
if ( p->betstatus != CARDS777_FOLD && ((tp->priv.automuck == 0 && p->action != CARDS777_SENTCARDS) || (turni == myind && hand->lastbettor == myind)) ) |
|||
{ |
|||
if ( tp->priv.automuck != 0 && pangea_myrank(myinfo,tp,p) < 0 ) |
|||
pangea_sendcmd(myinfo,tp,"action",-1,(void *)&amount,sizeof(amount),cardi,CARDS777_FOLD); |
|||
else |
|||
{ |
|||
pangea_sendcmd(myinfo,tp,"faceup",-1,tp->priv.holecards[0].bytes,sizeof(tp->priv.holecards[0]),tp->priv.cardis[0],myind); |
|||
pangea_sendcmd(myinfo,tp,"faceup",-1,tp->priv.holecards[1].bytes,sizeof(tp->priv.holecards[1]),tp->priv.cardis[1],myind); |
|||
p->action = CARDS777_SENTCARDS; |
|||
} |
|||
} |
|||
if ( pangea_lastman(myinfo,tp) > 0 ) |
|||
return; |
|||
if ( myind == pangea_slotA(tp) && pm->myind != 0 ) |
|||
{ |
|||
for (i=0; i<N; i++) |
|||
{ |
|||
hand->undergun = (hand->undergun + 1) % N; |
|||
if ( hand->undergun == hand->lastbettor ) |
|||
{ |
|||
printf("all players queried with showdown handmask.%x finished.%u\n",hand->handmask,hand->finished); |
|||
return; |
|||
} |
|||
if ( (p= tp->active[hand->undergun]) != 0 && p->betstatus != CARDS777_FOLD ) |
|||
break; |
|||
} |
|||
printf("senderind.%d host sends showdown for undergun.%d\n",pm->myind,hand->undergun); |
|||
pangea_sendcmd(myinfo,tp,"showdown",-1,(void *)&hand->betsize,sizeof(hand->betsize),cardi,hand->undergun); |
|||
} |
|||
} |
|||
|
|||
int32_t pangea_anotherhand(struct supernet_info *myinfo,struct table_info *tp,int32_t sleepflag) |
|||
{ |
|||
int32_t i,n,activej = -1; int64_t balance,onlybalance = 0,total = 0; |
|||
for (i=n=0; i<tp->G.N; i++) |
|||
{ |
|||
PNACL_message("(p%d %.8f) ",i,dstr(tp->G.P[i].balance)); |
|||
if ( (balance= tp->G.P[i].balance) != 0 ) |
|||
{ |
|||
total += balance; |
|||
onlybalance = balance; |
|||
if ( activej < 0 ) |
|||
activej = i; |
|||
n++; |
|||
} |
|||
} |
|||
PNACL_message("balance %.8f [%.8f]\n",dstr(total),dstr(total + tp->G.hostrake + tp->G.pangearake)); |
|||
if ( n == 1 ) |
|||
{ |
|||
PNACL_message("Only player.%d left with %.8f | get sigs and cashout after numhands.%d\n",activej,dstr(onlybalance),tp->numhands); |
|||
sleep(60); |
|||
return(1); |
|||
} |
|||
else |
|||
{ |
|||
if ( sleepflag != 0 ) |
|||
sleep(sleepflag); |
|||
//hand->betstarted = 0;
|
|||
pangea_newdeck(myinfo,tp); |
|||
if ( sleepflag != 0 ) |
|||
sleep(sleepflag); |
|||
} |
|||
return(n); |
|||
} |
@ -0,0 +1,316 @@ |
|||
/******************************************************************************
|
|||
* Copyright © 2014-2016 The SuperNET Developers. * |
|||
* * |
|||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * |
|||
* the top-level directory of this distribution for the individual copyright * |
|||
* holder information and the developer policies on copyright and licensing. * |
|||
* * |
|||
* Unless otherwise agreed in a custom licensing agreement, no part of the * |
|||
* SuperNET software, including this file may be copied, modified, propagated * |
|||
* or distributed except according to the terms contained in the LICENSE file * |
|||
* * |
|||
* Removal or modification of this copyright notice is prohibited. * |
|||
* * |
|||
******************************************************************************/ |
|||
|
|||
#include "pangea777.h" |
|||
|
|||
cJSON *pangea_tablejson(struct game_info *gp) |
|||
{ |
|||
char ipaddr[64],str[64]; struct tai t; int32_t seconds; cJSON *json = cJSON_CreateObject(); |
|||
jaddbits256(json,"tablehash",gp->tablehash); |
|||
expand_ipbits(ipaddr,gp->hostipbits); |
|||
jaddstr(json,"host",ipaddr); |
|||
jaddnum(json,"minbuyin",dstr(gp->minbuyin)); |
|||
jaddnum(json,"maxbuyin",dstr(gp->maxbuyin)); |
|||
jaddnum(json,"minplayers",gp->minplayers); |
|||
jaddnum(json,"maxplayers",gp->maxplayers); |
|||
jaddnum(json,"M",gp->M); |
|||
jaddnum(json,"N",gp->N); |
|||
jaddnum(json,"numcards",gp->numcards); |
|||
jaddnum(json,"rake",(double)gp->rakemillis/10.); |
|||
jaddnum(json,"maxrake",dstr(gp->maxrake)); |
|||
jaddnum(json,"hostrake",dstr(gp->hostrake)); |
|||
jaddnum(json,"pangearake",dstr(gp->pangearake)); |
|||
jaddnum(json,"bigblind",dstr(gp->bigblind)); |
|||
jaddnum(json,"ante",dstr(gp->ante)); |
|||
if ( gp->opentime != 0 ) |
|||
{ |
|||
OS_conv_unixtime(&t,&seconds,gp->opentime); |
|||
jaddstr(json,"opentime",utc_str(str,t)); |
|||
if ( gp->started != 0 ) |
|||
{ |
|||
OS_conv_unixtime(&t,&seconds,gp->started); |
|||
jaddstr(json,"started",utc_str(str,t)); |
|||
if ( gp->finished != 0 ) |
|||
{ |
|||
OS_conv_unixtime(&t,&seconds,gp->finished); |
|||
jaddstr(json,"finished",utc_str(str,t)); |
|||
} |
|||
} |
|||
} |
|||
return(json); |
|||
} |
|||
|
|||
void pangea_gamecreate(struct game_info *gp,uint32_t timestamp,bits256 tablehash,cJSON *json) |
|||
{ |
|||
gp->gamehash = calc_categoryhashes(0,"pangea",0); |
|||
gp->tablehash = tablehash; |
|||
gp->hostipbits = calc_ipbits(jstr(json,"myipaddr")); |
|||
gp->minbuyin = jdouble(json,"minbuyin") * SATOSHIDEN; |
|||
gp->maxbuyin = jdouble(json,"maxbuyin") * SATOSHIDEN; |
|||
gp->minplayers = juint(json,"minplayers"); |
|||
gp->maxplayers = juint(json,"maxplayers"); |
|||
if ( (gp->N= juint(json,"N")) < gp->minplayers ) |
|||
gp->N = gp->minplayers; |
|||
if ( (gp->M= juint(json,"M")) > gp->N ) |
|||
gp->M = gp->N; |
|||
if ( (gp->numcards= juint(json,"numcards")) != 52 ) |
|||
gp->numcards = 52; |
|||
gp->rakemillis = jdouble(json,"rake") * 10.; |
|||
gp->maxrake = jdouble(json,"maxrake") * SATOSHIDEN; |
|||
gp->hostrake = jdouble(json,"hostrake") * SATOSHIDEN; |
|||
gp->pangearake = jdouble(json,"pangearake") * SATOSHIDEN; |
|||
gp->bigblind = jdouble(json,"bigblind") * SATOSHIDEN; |
|||
gp->ante = jdouble(json,"ante") * SATOSHIDEN; |
|||
gp->opentime = timestamp; |
|||
} |
|||
|
|||
int32_t pangea_opentable(struct game_info *gp) |
|||
{ |
|||
if ( gp->opentime != 0 && gp->started == 0 ) |
|||
return(1); |
|||
else if ( gp->finished != 0 ) |
|||
return(0); |
|||
else return(-1); |
|||
} |
|||
|
|||
cJSON *pangea_lobbyjson(struct supernet_info *myinfo) |
|||
{ |
|||
struct category_info *cat,*sub,*tmp; struct table_info *tp; cJSON *array,*retjson; |
|||
retjson = cJSON_CreateObject(); |
|||
array = cJSON_CreateArray(); |
|||
if ( (cat= category_find(calc_categoryhashes(0,"pangea",0),GENESIS_PUBKEY)) != 0 ) |
|||
{ |
|||
HASH_ITER(hh,cat->sub,sub,tmp) |
|||
{ |
|||
if ( (tp= sub->info) != 0 && pangea_opentable(&tp->G) > 0 ) |
|||
jaddi(array,pangea_tablejson(&tp->G)); |
|||
} |
|||
} |
|||
jadd(retjson,"tables",array); |
|||
return(retjson); |
|||
} |
|||
|
|||
int32_t pangea_playerparse(struct player_info *p,cJSON *json) |
|||
{ |
|||
char *handle,*ipaddr; |
|||
if ( (handle= jstr(json,"handle")) != 0 && strlen(handle) < sizeof(p->handle)-1 ) |
|||
strcpy(p->handle,handle); |
|||
p->playerpub = jbits256(json,"playerpub"); |
|||
if ( (ipaddr= jstr(json,"myipaddr")) != 0 && is_ipaddr(ipaddr) > 0 ) |
|||
{ |
|||
p->ipbits = calc_ipbits(ipaddr); |
|||
return(0); |
|||
} |
|||
return(-1); |
|||
} |
|||
|
|||
cJSON *pangea_handjson(struct hand_info *hand,uint8_t *holecards,int32_t isbot) |
|||
{ |
|||
int32_t i,card; char cardAstr[8],cardBstr[8],pairstr[18],cstr[128]; cJSON *array,*json = cJSON_CreateObject(); |
|||
array = cJSON_CreateArray(); |
|||
cstr[0] = 0; |
|||
for (i=0; i<5; i++) |
|||
{ |
|||
if ( (card= hand->community[i]) != 0xff ) |
|||
{ |
|||
jaddinum(array,card); |
|||
cardstr(&cstr[strlen(cstr)],card); |
|||
strcat(cstr," "); |
|||
} |
|||
} |
|||
jaddstr(json,"community",cstr); |
|||
jadd(json,"cards",array); |
|||
if ( (card= holecards[0]) != 0xff ) |
|||
{ |
|||
jaddnum(json,"cardA",card); |
|||
cardstr(cardAstr,holecards[0]); |
|||
} else cardAstr[0] = 0; |
|||
if ( (card= holecards[1]) != 0xff ) |
|||
{ |
|||
jaddnum(json,"cardB",card); |
|||
cardstr(cardBstr,holecards[1]); |
|||
} else cardBstr[0] = 0; |
|||
sprintf(pairstr,"%s %s",cardAstr,cardBstr); |
|||
jaddstr(json,"holecards",pairstr); |
|||
jaddnum(json,"betsize",dstr(hand->betsize)); |
|||
jaddnum(json,"lastraise",dstr(hand->lastraise)); |
|||
jaddnum(json,"lastbettor",hand->lastbettor); |
|||
jaddnum(json,"numactions",hand->numactions); |
|||
jaddnum(json,"undergun",hand->undergun); |
|||
jaddnum(json,"isbot",isbot); |
|||
jaddnum(json,"cardi",hand->cardi); |
|||
return(json); |
|||
} |
|||
|
|||
char *pangea_statusstr(int32_t status) |
|||
{ |
|||
if ( status == CARDS777_FOLD ) |
|||
return("folded"); |
|||
else if ( status == CARDS777_ALLIN ) |
|||
return("ALLin"); |
|||
else return("active"); |
|||
} |
|||
|
|||
int32_t pangea_countdown(struct table_info *tp,struct player_info *p) |
|||
{ |
|||
struct hand_info *hand = &tp->hand; |
|||
if ( p != 0 && hand->undergun == p->ind && hand->userinput_starttime != 0 ) |
|||
return((int32_t)(hand->userinput_starttime + PANGEA_USERTIMEOUT - time(NULL))); |
|||
else return(-1); |
|||
} |
|||
|
|||
cJSON *pangea_tablestatus(struct supernet_info *myinfo,struct table_info *tp) |
|||
{ |
|||
int64_t sidepots[CARDS777_MAXPLAYERS][CARDS777_MAXPLAYERS],totals[CARDS777_MAXPLAYERS],sum; |
|||
struct player_info *p; int32_t i,n,N,j,countdown,iter; cJSON *item,*array,*json; |
|||
int64_t won[CARDS777_MAXPLAYERS],snapshot[CARDS777_MAXPLAYERS],bets[CARDS777_MAXPLAYERS]; |
|||
int64_t total,val; char *handhist,*str; struct game_info *gp; struct hand_info *hand; |
|||
hand = &tp->hand, gp = &tp->G, N = tp->numactive; |
|||
json = cJSON_CreateObject(); |
|||
jaddbits256(json,"tablehash",gp->tablehash); |
|||
jadd64bits(json,"myind",tp->priv.myind); |
|||
jaddnum(json,"minbuyin",gp->minbuyin); |
|||
jaddnum(json,"maxbuyin",gp->maxbuyin); |
|||
jaddnum(json,"button",tp->hand.button); |
|||
jaddnum(json,"M",gp->M); |
|||
jaddnum(json,"N",tp->numactive); |
|||
jaddnum(json,"numcards",gp->numcards); |
|||
jaddnum(json,"numhands",tp->numhands); |
|||
jaddnum(json,"rake",(double)gp->rakemillis/10.); |
|||
jaddnum(json,"maxrake",dstr(gp->maxrake)); |
|||
jaddnum(json,"hostrake",dstr(gp->hostrake)); |
|||
jaddnum(json,"pangearake",dstr(gp->pangearake)); |
|||
jaddnum(json,"bigblind",dstr(gp->bigblind)); |
|||
jaddnum(json,"ante",dstr(gp->ante)); |
|||
array = cJSON_CreateArray(); |
|||
for (i=0; i<tp->numactive; i++) |
|||
jaddi64bits(array,tp->active[i]!=0?tp->active[i]->nxt64bits:0); |
|||
jadd(json,"addrs",array); |
|||
total = 0; |
|||
for (iter=0; iter<6; iter++) |
|||
{ |
|||
array = cJSON_CreateArray(); |
|||
for (i=0; i<tp->numactive; i++) |
|||
{ |
|||
val = 0; |
|||
if ( (p= tp->active[i]) != 0 ) |
|||
{ |
|||
switch ( iter ) |
|||
{ |
|||
case 0: val = p->turni; str = "turns"; break; |
|||
case 1: val = p->balance; str = "balances"; break; |
|||
case 2: val = p->snapshot; str = "snapshot"; break; |
|||
case 3: val = p->betstatus; str = "status"; break; |
|||
case 4: val = p->bets; str = "bets"; break; |
|||
case 5: val = p->won; str = "won"; break; |
|||
} |
|||
} |
|||
if ( iter == 5 ) |
|||
won[i] = val; |
|||
else |
|||
{ |
|||
if ( iter == 3 ) |
|||
jaddistr(array,pangea_statusstr((int32_t)val)); |
|||
else |
|||
{ |
|||
if ( iter == 4 ) |
|||
total += val, bets[i] = val; |
|||
else if ( iter == 2 ) |
|||
snapshot[i] = val; |
|||
jaddinum(array,val); |
|||
} |
|||
} |
|||
} |
|||
jadd(json,str,array); |
|||
} |
|||
jaddnum(json,"totalbets",dstr(total)); |
|||
for (iter=0; iter<2; iter++) |
|||
if ( (n= pangea_sidepots(myinfo,tp,0,sidepots,iter == 0 ? snapshot : bets)) > 0 && n < N ) |
|||
{ |
|||
array = cJSON_CreateArray(); |
|||
for (i=0; i<n; i++) |
|||
{ |
|||
item = cJSON_CreateArray(); |
|||
for (sum=j=0; j<N; j++) |
|||
jaddinum(item,dstr(sidepots[i][j])), sum += sidepots[i][j]; |
|||
totals[i] = sum; |
|||
jaddi(array,item); |
|||
} |
|||
jadd(json,iter == 0 ? "pots" : "RTpots",array); |
|||
item = cJSON_CreateArray(); |
|||
for (sum=i=0; i<n; i++) |
|||
jaddinum(item,dstr(totals[i])), sum += totals[i]; |
|||
jadd(json,iter == 0 ? "potTotals" : "RTpotTotals",item); |
|||
jaddnum(json,iter == 0 ? "sum" : "RTsum",dstr(sum)); |
|||
} |
|||
jadd64bits(json,"automuck",tp->priv.automuck); |
|||
jadd64bits(json,"autofold",tp->priv.autofold); |
|||
jadd(json,"hand",pangea_handjson(hand,tp->priv.hole,0)); |
|||
if ( (handhist= pangea_dispsummary(myinfo,tp,0,tp->summary,tp->summarysize,tp->G.tablehash,tp->numhands-1,N)) != 0 ) |
|||
{ |
|||
if ( (item= cJSON_Parse(handhist)) != 0 ) |
|||
jadd(json,"actions",item); |
|||
free(handhist); |
|||
} |
|||
if ( (countdown= pangea_countdown(tp,tp->active[tp->priv.myind])) >= 0 ) |
|||
jaddnum(json,"timeleft",countdown); |
|||
if ( hand->finished != 0 ) |
|||
{ |
|||
item = cJSON_CreateObject(); |
|||
jaddnum(item,"hostrake",dstr(tp->G.hostrake)); |
|||
jaddnum(item,"pangearake",dstr(tp->G.pangearake)); |
|||
array = cJSON_CreateArray(); |
|||
for (i=0; i<N; i++) |
|||
jaddinum(array,dstr(won[i])); |
|||
jadd(item,"won",array); |
|||
jadd(json,"summary",item); |
|||
} |
|||
return(json); |
|||
} |
|||
|
|||
void pangea_playerprint(struct supernet_info *myinfo,struct table_info *tp,int32_t i,int32_t myind) |
|||
{ |
|||
int32_t countdown; char str[8]; struct player_info *p; |
|||
if ( (p= tp->active[i]) != 0 ) |
|||
{ |
|||
if ( (countdown= pangea_countdown(tp,tp->active[tp->priv.myind])) >= 0 ) |
|||
sprintf(str,"%2d",countdown); |
|||
else str[0] = 0; |
|||
printf("%d: %6s %12.8f %2s | %12.8f %s\n",i,pangea_statusstr(p->betstatus),dstr(p->bets),str,dstr(p->balance),i == myind ? "<<<<<<<<<<<": ""); |
|||
} |
|||
} |
|||
|
|||
void pangea_statusprint(struct supernet_info *myinfo,struct table_info *tp,int32_t myind) |
|||
{ |
|||
int32_t i,N; char handstr[64]; uint8_t handvals[7]; struct hand_info *hand = &tp->hand; |
|||
N = tp->numactive; |
|||
for (i=0; i<N; i++) |
|||
pangea_playerprint(myinfo,tp,i,myind); |
|||
handstr[0] = 0; |
|||
if ( hand->community[0] != hand->community[1] ) |
|||
{ |
|||
for (i=0; i<5; i++) |
|||
if ( (handvals[i]= hand->community[i]) == 0xff ) |
|||
break; |
|||
if ( i == 5 ) |
|||
{ |
|||
if ( (handvals[5]= tp->priv.hole[0]) != 0xff && (handvals[6]= tp->priv.hole[1]) != 0xff ) |
|||
set_handstr(handstr,handvals,1); |
|||
} |
|||
} |
|||
printf("%s\n",handstr); |
|||
} |
|||
|
|||
|
@ -0,0 +1,311 @@ |
|||
/******************************************************************************
|
|||
* Copyright © 2014-2016 The SuperNET Developers. * |
|||
* * |
|||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * |
|||
* the top-level directory of this distribution for the individual copyright * |
|||
* holder information and the developer policies on copyright and licensing. * |
|||
* * |
|||
* Unless otherwise agreed in a custom licensing agreement, no part of the * |
|||
* SuperNET software, including this file may be copied, modified, propagated * |
|||
* or distributed except according to the terms contained in the LICENSE file * |
|||
* * |
|||
* Removal or modification of this copyright notice is prohibited. * |
|||
* * |
|||
******************************************************************************/ |
|||
|
|||
#include "pangea777.h" |
|||
|
|||
char *pangea_typestr(uint8_t type) |
|||
{ |
|||
static char err[64]; |
|||
switch ( type ) |
|||
{ |
|||
case 0xff: return("fold"); |
|||
case CARDS777_START: return("start"); |
|||
case CARDS777_ANTE: return("ante"); |
|||
case CARDS777_SMALLBLIND: return("smallblind"); |
|||
case CARDS777_BIGBLIND: return("bigblind"); |
|||
case CARDS777_CHECK: return("check"); |
|||
case CARDS777_CALL: return("call"); |
|||
case CARDS777_BET: return("bet"); |
|||
case CARDS777_RAISE: return("raise"); |
|||
case CARDS777_FULLRAISE: return("fullraise"); |
|||
case CARDS777_SENTCARDS: return("sentcards"); |
|||
case CARDS777_ALLIN: return("allin"); |
|||
case CARDS777_FACEUP: return("faceup"); |
|||
case CARDS777_WINNINGS: return("won"); |
|||
case CARDS777_RAKES: return("rakes"); |
|||
case CARDS777_CHANGES: return("changes"); |
|||
case CARDS777_SNAPSHOT: return("snapshot"); |
|||
} |
|||
sprintf(err,"unknown type.%d",type); |
|||
return(err); |
|||
} |
|||
|
|||
cJSON *pangea_handitem(int32_t *cardip,cJSON **pitemp,uint8_t type,uint64_t valA,uint64_t *bits64p,bits256 card,int32_t numplayers) |
|||
{ |
|||
int32_t cardi,n,i,rebuy,busted; char str[128],hexstr[65],cardpubs[(CARDS777_MAXCARDS+1)*64+1]; cJSON *item,*array,*pitem = 0; |
|||
item = cJSON_CreateObject(); |
|||
*cardip = -1; |
|||
switch ( type ) |
|||
{ |
|||
case CARDS777_START: |
|||
jaddnum(item,"handid",valA); |
|||
init_hexbytes_noT(cardpubs,(void *)bits64p,(int32_t)((CARDS777_MAXCARDS+1) * sizeof(bits256))); |
|||
jaddstr(item,"cardpubs",cardpubs); |
|||
break; |
|||
case CARDS777_RAKES: |
|||
jaddnum(item,"hostrake",dstr(valA)); |
|||
jaddnum(item,"pangearake",dstr(*bits64p)); |
|||
break; |
|||
case CARDS777_SNAPSHOT: |
|||
jaddnum(item,"handid",valA); |
|||
array = cJSON_CreateArray(); |
|||
for (i=0; i<CARDS777_MAXPLAYERS; i++) |
|||
{ |
|||
if ( i < numplayers ) |
|||
jaddinum(array,dstr(bits64p[i])); |
|||
else jaddinum(array,dstr(0)); |
|||
} |
|||
jadd(item,"snapshot",array); |
|||
//printf("add snapshot for numplayers.%d\n",numplayers);
|
|||
break; |
|||
case CARDS777_CHANGES: |
|||
n = (int32_t)(valA & 0xf); |
|||
busted = (int32_t)((valA>>4) & 0xffff); |
|||
rebuy = (int32_t)((valA>>20) & 0xffff); |
|||
if ( busted != 0 ) |
|||
jaddnum(item,"busted",busted); |
|||
if ( rebuy != 0 ) |
|||
jaddnum(item,"rebuy",rebuy); |
|||
array = cJSON_CreateArray(); |
|||
for (i=0; i<n; i++) |
|||
jaddinum(array,dstr(bits64p[i])); |
|||
jadd(item,"balances",array); |
|||
break; |
|||
case CARDS777_WINNINGS: |
|||
if ( (int32_t)valA >= 0 && valA < numplayers ) |
|||
jaddnum(item,"player",valA); |
|||
jaddnum(item,"won",dstr(*bits64p)); |
|||
if ( pitem == 0 ) |
|||
pitem = cJSON_CreateObject(); |
|||
jaddnum(pitem,"won",dstr(*bits64p)); |
|||
break; |
|||
case CARDS777_FACEUP: |
|||
*cardip = cardi = (int32_t)(valA >> 8); |
|||
if ( cardi >= 0 && cardi < 52 ) |
|||
jaddnum(item,"cardi",cardi); |
|||
else printf("illegal cardi.%d valA.%llu\n",cardi,(long long)valA); |
|||
valA &= 0xff; |
|||
if ( (int32_t)valA >= 0 && valA < numplayers ) |
|||
jaddnum(item,"player",valA); |
|||
else if ( valA == 0xff ) |
|||
jaddnum(item,"community",cardi - numplayers*2); |
|||
cardstr(str,card.bytes[1]); |
|||
jaddnum(item,str,card.bytes[1]); |
|||
init_hexbytes_noT(hexstr,card.bytes,sizeof(card)); |
|||
jaddstr(item,"privkey",hexstr); |
|||
break; |
|||
default: |
|||
if ( (int32_t)valA >= 0 && valA < numplayers ) |
|||
jaddnum(item,"player",valA); |
|||
jaddstr(item,"action",pangea_typestr(type)); |
|||
if ( pitem == 0 ) |
|||
pitem = cJSON_CreateObject(); |
|||
if ( *bits64p != 0 ) |
|||
{ |
|||
jaddnum(item,"bet",dstr(*bits64p)); |
|||
jaddnum(pitem,pangea_typestr(type),dstr(*bits64p)); |
|||
} |
|||
else jaddstr(pitem,"action",pangea_typestr(type)); |
|||
break; |
|||
} |
|||
*pitemp = pitem; |
|||
return(item); |
|||
} |
|||
|
|||
int32_t pangea_parsesummary(uint8_t *typep,uint64_t *valAp,uint64_t *bits64p,bits256 *cardp,uint8_t *summary,int32_t len) |
|||
{ |
|||
int32_t handid; uint16_t cardi_player; uint32_t changes=0; uint8_t player; |
|||
*bits64p = 0; |
|||
memset(cardp,0,sizeof(*cardp)); |
|||
len += SuperNET_copybits(1,&summary[len],(void *)typep,sizeof(*typep)); |
|||
if ( *typep == 0 ) |
|||
{ |
|||
printf("len.%d type.%d [%d]\n",len,*typep,summary[len-1]); |
|||
return(-1); |
|||
} |
|||
if ( *typep == CARDS777_START || *typep == CARDS777_SNAPSHOT ) |
|||
len += SuperNET_copybits(1,&summary[len],(void *)&handid,sizeof(handid)), *valAp = handid; |
|||
else if ( *typep == CARDS777_CHANGES ) |
|||
len += SuperNET_copybits(1,&summary[len],(void *)&changes,sizeof(changes)), *valAp = changes; |
|||
else if ( *typep == CARDS777_RAKES ) |
|||
len += SuperNET_copybits(1,&summary[len],(void *)valAp,sizeof(*valAp)); |
|||
else if ( *typep == CARDS777_FACEUP ) |
|||
len += SuperNET_copybits(1,&summary[len],(void *)&cardi_player,sizeof(cardi_player)), *valAp = cardi_player; |
|||
else len += SuperNET_copybits(1,&summary[len],(void *)&player,sizeof(player)), *valAp = player; |
|||
if ( *typep == CARDS777_FACEUP ) |
|||
len += SuperNET_copybits(1,&summary[len],cardp->bytes,sizeof(*cardp)); |
|||
else if ( *typep == CARDS777_START ) |
|||
len += SuperNET_copybits(1,&summary[len],(void *)bits64p,sizeof(bits256)*(CARDS777_MAXCARDS+1)); |
|||
else if ( *typep == CARDS777_SNAPSHOT ) |
|||
len += SuperNET_copybits(1,&summary[len],(void *)bits64p,sizeof(*bits64p) * CARDS777_MAXPLAYERS); |
|||
else if ( *typep == CARDS777_CHANGES ) |
|||
len += SuperNET_copybits(1,&summary[len],(void *)bits64p,sizeof(*bits64p) * (changes & 0xf)); |
|||
else len += SuperNET_copybits(1,&summary[len],(void *)bits64p,sizeof(*bits64p)); |
|||
return(len); |
|||
} |
|||
|
|||
char *pangea_dispsummary(struct supernet_info *myinfo,struct table_info *tp,int32_t verbose,uint8_t *summary,int32_t summarysize,bits256 tablehash,int32_t handid,int32_t numplayers) |
|||
{ |
|||
int32_t i,cardi,n = 0,len = 0; uint8_t type; uint64_t valA,bits64[CARDS777_MAXPLAYERS + (CARDS777_MAXCARDS+1)*4]; bits256 card; |
|||
cJSON *item,*json,*all,*cardis[52],*players[CARDS777_MAXPLAYERS],*pitem,*array = cJSON_CreateArray(); |
|||
all = cJSON_CreateArray(); |
|||
memset(cardis,0,sizeof(cardis)); |
|||
memset(players,0,sizeof(players)); |
|||
for (i=0; i<numplayers; i++) |
|||
players[i] = cJSON_CreateArray(); |
|||
while ( len < summarysize ) |
|||
{ |
|||
memset(bits64,0,sizeof(bits64)); |
|||
len = pangea_parsesummary(&type,&valA,bits64,&card,summary,len); |
|||
if ( (item= pangea_handitem(&cardi,&pitem,type,valA,bits64,card,numplayers)) != 0 ) |
|||
{ |
|||
if ( cardi >= 0 && cardi < 52 ) |
|||
{ |
|||
//printf("cardis[%d] <- %p\n",cardi,item);
|
|||
cardis[cardi] = item; |
|||
} |
|||
else jaddi(array,item); |
|||
item = 0; |
|||
} |
|||
if ( pitem != 0 ) |
|||
{ |
|||
jaddnum(pitem,"n",n), n++; |
|||
if ( (int32_t)valA >= 0 && valA < numplayers ) |
|||
jaddi(players[valA],pitem); |
|||
else free_json(pitem), printf("illegal player.%llu\n",(long long)valA); |
|||
pitem = 0; |
|||
} |
|||
} |
|||
for (i=0; i<numplayers; i++) |
|||
jaddi(all,players[i]); |
|||
if ( verbose == 0 ) |
|||
{ |
|||
for (i=0; i<52; i++) |
|||
if ( cardis[i] != 0 ) |
|||
free_json(cardis[i]); |
|||
free_json(array); |
|||
return(jprint(all,1)); |
|||
} |
|||
else |
|||
{ |
|||
json = cJSON_CreateObject(); |
|||
jaddbits256(json,"tablehash",tablehash); |
|||
jaddnum(json,"size",summarysize); |
|||
jaddnum(json,"handid",handid); |
|||
//jaddnum(json,"crc",_crc32(0,summary,summarysize));
|
|||
jadd(json,"hand",array); |
|||
array = cJSON_CreateArray(); |
|||
for (i=0; i<52; i++) |
|||
if ( cardis[i] != 0 ) |
|||
jaddi(array,cardis[i]); |
|||
jadd(json,"cards",array); |
|||
//jadd(json,"players",all);
|
|||
return(jprint(json,1)); |
|||
} |
|||
} |
|||
|
|||
void pangea_summaryadd(struct supernet_info *myinfo,struct table_info *tp,uint8_t type,void *arg0,int32_t size0,void *arg1,int32_t size1) |
|||
{ |
|||
uint64_t valA,bits64[CARDS777_MAXPLAYERS + (CARDS777_MAXCARDS+1)*4]; |
|||
bits256 card; uint8_t checktype; int32_t len,startlen = tp->summarysize; |
|||
if ( type == 0 ) |
|||
{ |
|||
printf("type.0\n"); getchar(); |
|||
} |
|||
//printf("summarysize.%d type.%d [%02x %02x]\n",dp->summarysize,type,*(uint8_t *)arg0,*(uint8_t *)arg1);
|
|||
tp->summarysize += SuperNET_copybits(0,&tp->summary[tp->summarysize],(void *)&type,sizeof(type)); |
|||
//printf("-> %d\n",tp->summary[tp->summarysize-1]);
|
|||
tp->summarysize += SuperNET_copybits(0,&tp->summary[tp->summarysize],arg0,size0); |
|||
tp->summarysize += SuperNET_copybits(0,&tp->summary[tp->summarysize],arg1,size1); |
|||
//printf("startlen.%d summarysize.%d\n",startlen,tp->summarysize);
|
|||
len = pangea_parsesummary(&checktype,&valA,bits64,&card,tp->summary,startlen); |
|||
if ( len != tp->summarysize || checktype != type || memcmp(&valA,arg0,size0) != 0 ) |
|||
printf("pangea_summary parse error [%d] (%d vs %d) || (%d vs %d).%d || cmp.%d size0.%d size1.%d\n",startlen,len,tp->summarysize,checktype,type,tp->summary[startlen],memcmp(&valA,arg0,size0),size0,size1); |
|||
if ( card.txid != 0 && memcmp(card.bytes,arg1,sizeof(card)) != 0 ) |
|||
printf("pangea_summary: parse error card mismatch %llx != %llx\n",(long long)card.txid,*(long long *)arg1); |
|||
else if ( card.txid == 0 && memcmp(arg1,bits64,size1) != 0 ) |
|||
printf("pangea_summary: parse error bits64 %llx != %llx\n",(long long)bits64[0],*(long long *)arg0); |
|||
/*if ( 1 && hn->client->H.slot == pangea_slotA(tp->table) )
|
|||
{ |
|||
if ( (item= pangea_handitem(&cardi,&pitem,type,valA,bits64,card,tp->G.N)) != 0 ) |
|||
{ |
|||
str = jprint(item,1); |
|||
printf("ITEM.(%s)\n",str); |
|||
free(str); |
|||
} |
|||
if ( pitem != 0 ) |
|||
{ |
|||
str = jprint(pitem,1); |
|||
printf("PITEM.(%s)\n",str); |
|||
free(str); |
|||
} |
|||
}*/ |
|||
if ( Debuglevel > 2 )//|| hn->client->H.slot == pangea_slotA(tp->table) )
|
|||
printf("pangea_summary.%d %d | summarysize.%d crc.%u\n",type,*(uint8_t *)arg0,tp->summarysize,calc_crc32(0,tp->summary,tp->summarysize)); |
|||
} |
|||
|
|||
void pangea_summary(PANGEA_HANDARGS) |
|||
{ |
|||
char *otherhist,*handhist = 0; int32_t senderind,N,matched = 0; struct hand_info *hand = &tp->hand; |
|||
senderind = pm->myind, N = tp->numactive; |
|||
if ( Debuglevel > 2 ) // ordering changes crc
|
|||
printf("player.%d [%d]: got summary.%d from %d memcmp.%d\n",tp->priv.myind,tp->summarysize,datalen,senderind,memcmp(data,tp->summary,datalen)); |
|||
if ( datalen == tp->summarysize ) |
|||
{ |
|||
if ( memcmp(tp->summary,data,datalen) == 0 ) |
|||
{ |
|||
//printf("P%d: matched senderind.%d\n",priv->myslot,senderind);
|
|||
matched = 1; |
|||
} |
|||
else |
|||
{ |
|||
if ( (handhist= pangea_dispsummary(myinfo,tp,1,tp->summary,tp->summarysize,tp->G.tablehash,tp->numhands-1,N)) != 0 ) |
|||
{ |
|||
if ( (otherhist= pangea_dispsummary(myinfo,tp,1,data,datalen,tp->G.tablehash,tp->numhands-1,N)) != 0 ) |
|||
{ |
|||
if ( strcmp(handhist,otherhist) == 0 ) |
|||
{ |
|||
//printf("P%d: matched B senderind.%d\n",priv->myslot,senderind);
|
|||
matched = 1; |
|||
} |
|||
else printf("\n[%s] MISMATCHED vs \n[%s]\n",handhist,otherhist); |
|||
free(otherhist); |
|||
} else printf("error getting otherhist\n"); |
|||
free(handhist); |
|||
} else printf("error getting handhist\n"); |
|||
} |
|||
} |
|||
if ( matched != 0 ) |
|||
hand->summaries |= (1LL << senderind); |
|||
else |
|||
{ |
|||
//printf("P%d: MISMATCHED senderind.%d\n",priv->myslot,senderind);
|
|||
hand->mismatches |= (1LL << senderind); |
|||
} |
|||
if ( senderind == 0 && tp->priv.myind != pangea_slotA(tp) ) |
|||
pangea_sendcmd(myinfo,tp,"summary",-1,tp->summary,tp->summarysize,0,0); |
|||
if ( (hand->mismatches | hand->summaries) == (1LL << N)-1 ) |
|||
{ |
|||
if ( Debuglevel > 2 ) |
|||
printf("P%d: hand summary matches.%llx errors.%llx | size.%d\n",tp->priv.myind,(long long)hand->summaries,(long long)hand->mismatches,tp->summarysize); |
|||
//if ( handhist == 0 && (handhist= pangea_dispsummary(sp,1,dp->summary,dp->summarysize,sp->tableid,dp->numhands-1,dp->N)) != 0 )
|
|||
// printf("HAND.(%s)\n",handhist), free(handhist);
|
|||
if ( tp->priv.myind == 0 ) |
|||
{ |
|||
hand->mismatches = hand->summaries = 0; |
|||
pangea_anotherhand(myinfo,tp,PANGEA_PAUSE); |
|||
} |
|||
} |
|||
} |
Loading…
Reference in new issue