You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

382 lines
15 KiB

9 years ago
/******************************************************************************
* Copyright © 2014-2015 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. *
* *
******************************************************************************/
#ifdef later
#ifdef DEFINES_ONLY
#ifndef tourney777_h
#define tourney777_h
// nonplaying nodeA
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <memory.h>
#include "../iguana777.h"
struct tourney777_table { uint64_t tableid; union hostnet777 *hn[CARDS777_MAXPLAYERS]; int32_t N,numactive; };
struct tourney777
{
struct tourney777_table tables[1024]; char transport[16],ipaddr[64],name[128]; uint32_t started,finished,numtables; uint16_t port;
union hostnet777 hn[];
} *Tournament;
#define TOURNEY777_TABLESIZE 9
#define TOURNEY777_MINPLAYERS (TOURNEY777_TABLESIZE - 2)
#endif
#else
#ifndef tourney777_c
#define tourney777_c
#ifndef tourney777_h
#define DEFINES_ONLY
#include "tourney777.c"
#undef DEFINES_ONLY
#endif
void tourney777_jointable(struct tourney777 *tp,struct tourney777_table *table,union hostnet777 *player)
{
player->client->tableid = table->tableid;
printf("jointable.%llu tableid.%llu\n",(long long)player->client->H.nxt64bits,(long long)table->tableid);
}
void tourney777_leavetable(struct tourney777 *tp,struct tourney777_table *table,union hostnet777 *player)
{
printf("leavetable.%llu tableid.%llu\n",(long long)player->client->H.nxt64bits,(long long)table->tableid);
player->client->tableid = 0;
}
void tourney777_createtable(struct tourney777 *tp,union hostnet777 *players[],int32_t num)
{
int32_t i; uint64_t tableid = rand();
for (i=0; i<num; i++)
players[i]->client->tableid = tableid;
printf("createtable.%llu numplayers.%d\n",(long long)tableid,num);
}
void tourney777_freetable(struct tourney777 *tp,struct tourney777_table *table)
{
printf("freetable.%llu numplayers.%d numactives.%d\n",(long long)table->tableid,table->N,table->numactive);
}
struct tourney777_table *tourney777_findtable(struct tourney777 *tp,uint64_t tableid,struct tourney777_table *avoid)
{
struct tourney777_table *mintable = 0; int32_t i,minplayers = CARDS777_MAXPLAYERS + 1;
if ( tp->numtables > 0 )
{
for (i=0; i<tp->numtables; i++)
{
if ( tableid == 0 )
{
if ( (avoid == 0 || avoid != &tp->tables[i]) && tp->tables[i].numactive != TOURNEY777_TABLESIZE && tp->tables[i].numactive < minplayers )
{
minplayers = tp->tables[i].numactive;
mintable = &tp->tables[i];
}
}
else if ( tp->tables[i].tableid == tableid )
return(&tp->tables[i]);
}
}
return(mintable);
}
union hostnet777 *tourney777_nextblind(struct tourney777_table *table)
{
int32_t i,ind,j = (rand() % table->N);
for (i=0; i<table->N; i++)
{
ind = (j + i) % table->N;
if ( table->hn[ind] != 0 && table->hn[ind]->client->balance != 0 )
return(table->hn[ind]);
}
return(0);
}
void tourney777_rebalance(struct tourney777 *tp,int32_t delta)
{
int32_t i,j,num,n,pertable,flag,threshold,needs_table = 0; struct hostnet777_server *srv;
union hostnet777 *player,*newtable[TOURNEY777_TABLESIZE]; struct tourney777_table *table,*t;
srv = tp->hn[0].server;
if ( delta < 0 )
{
if ( (table= tourney777_findtable(tp,0,0)) != 0 )
{
if ( table->numactive < TOURNEY777_MINPLAYERS )
{
if ( tp->numtables >= table->numactive )
{
for (j=0; j<table->N; j++)
tourney777_leavetable(tp,table,table->hn[j]);
for (j=0; j<table->N; j++)
{
if ( (t= tourney777_findtable(tp,0,table)) != 0 )
tourney777_jointable(tp,t,table->hn[j]);
else printf("tourney777_rebalance: cant find table with slot\n");
}
tourney777_freetable(tp,table);
}
else
{
printf("tourney777_rebalance: imbalance tableid.%llu numactive.%d vs total tables.%d\n",(long long)table->tableid,table->numactive,tp->numtables);
flag = 0;
for (threshold=TOURNEY777_TABLESIZE; threshold>=TOURNEY777_MINPLAYERS+1; threshold--)
{
for (i=0; i<tp->numtables; i++)
{
if ( tp->tables[i].numactive == threshold )
{
if ( (player= tourney777_nextblind(&tp->tables[i])) != 0 )
{
tourney777_leavetable(tp,&tp->tables[i],player);
tourney777_jointable(tp,table,player);
flag = 1;
break;
}
else printf("tourney777_nextblind: cant find nextblind\n");
}
}
if ( flag != 0 )
break;
}
if ( flag == 0 )
{
printf("tourney777_rebalance: couldnt find donor tableid.%llu numactive.%d vs total tables.%d\n",(long long)table->tableid,table->numactive,tp->numtables);
}
}
}
}
}
else
{
for (i=1; i<srv->num; i++)
{
player = &tp->hn[i];
if ( player != 0 && player->client->tableid == 0 && player->client->balance != 0 )
{
if ( (table= tourney777_findtable(tp,0,0)) != 0 )
tourney777_jointable(tp,table,player);
else needs_table++;
}
}
if ( needs_table >= TOURNEY777_TABLESIZE )
{
num = (needs_table / TOURNEY777_TABLESIZE);
if ( (needs_table % TOURNEY777_TABLESIZE) != 0 )
num++;
pertable = (needs_table / num);
printf("needs_table.%d pertable.%d num.%d\n",needs_table,pertable,num);
for (j=0; j<num; j++)
{
memset(newtable,0,sizeof(newtable));
// find nodes with endpoints and verify connections
for (i=1,n=0; i<srv->num; i++)
{
player = &tp->hn[i];
if ( player != 0 && player->client->tableid == 0 && player->client->balance != 0 )
{
newtable[n++] = player;
if ( n >= pertable )
break;
}
}
tourney777_createtable(tp,newtable,n);
}
}
}
}
void tourney777_newhand(union hostnet777 *hn,uint64_t tableid,cJSON *json,uint8_t *data,int32_t datalen)
{
struct pangea_info *pangea_find(uint64_t tableid,int32_t threadid);
char *pangea_dispsummary(struct pangea_info *sp,int32_t verbose,uint8_t *summary,int32_t summarysize,uint64_t tableid,int32_t handid,int32_t numplayers);
char *handhist; int32_t i,j,handid,numplayers,n,m,busted,rebuy; cJSON *handjson,*array,*balances,*item; struct tourney777_table *table;
handid = juint(json,"handid");
numplayers = juint(json,"numplayers");
if ( (handhist= pangea_dispsummary(pangea_find(tableid,0),1,data,datalen,tableid,handid,numplayers)) != 0 )
{
printf("GOT HANDHIST.(%s)\n",handhist);
if ( (handjson= cJSON_Parse(handhist)) != 0 )
{
if ( (array= jarray(&n,handjson,"hand")) != 0 )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
rebuy = juint(item,"rebuy");
busted = juint(item,"busted");
if ( (balances= jarray(&m,item,"balances")) != 0 && (table= tourney777_findtable(Tournament,tableid,0)) != 0 )
{
for (j=0; j<m; j++)
table->hn[j]->client->balance = j64bits(jitem(balances,j),0);
}
if ( busted != 0 )
tourney777_rebalance(Tournament,-1);
}
}
free_json(handjson);
}
free(handhist);
}
}
void tourney777_poll(union hostnet777 *hn)
{
char *jsonstr; uint64_t senderbits,tableid; uint8_t *buf=0; int32_t maxlen,len,senderind; uint32_t timestamp; char *cmdstr,*hexstr; cJSON *json;
maxlen = 65536;
if ( (buf= malloc(maxlen)) == 0 )
{
printf("tourney777_poll: cant allocate buf\n");
return;
}
if ( (jsonstr= queue_dequeue(&hn->server->H.Q,1)) != 0 )
{
printf("tourney slot.%d GOT.(%s)\n",hn->client->H.slot,jsonstr);
if ( (json= cJSON_Parse(jsonstr)) != 0 )
{
tableid = j64bits(json,"tableid");
if ( tourney777_findtable(Tournament,tableid,0) == 0 )
{
free(buf);
return;
}
senderbits = j64bits(json,"sender");
if ( (senderind= juint(json,"myind")) < 0 || senderind >= hn->server->num )
{
printf("pangea_poll: illegal senderind.%d cardi.%d turni.%d\n",senderind,juint(json,"cardi"),juint(json,"turni"));
goto cleanup;
}
timestamp = juint(json,"timestamp");
hn->client->H.state = juint(json,"state");
len = juint(json,"n");
cmdstr = jstr(json,"cmd");
if ( (hexstr= jstr(json,"data")) != 0 && strlen(hexstr) == (len<<1) )
{
if ( len > maxlen )
{
printf("len too big for tourney777_poll\n");
goto cleanup;
}
decode_hex(buf,len,hexstr);
} else if ( hexstr != 0 )
printf("len.%d vs hexlen.%d (%s)\n",len,(int32_t)strlen(hexstr)>>1,hexstr);
if ( cmdstr != 0 )
{
if ( strcmp(cmdstr,"newhand") == 0 )
tourney777_newhand(hn,tableid,json,buf,len);
}
cleanup:
free_json(json);
}
free_queueitem(jsonstr);
}
free(buf);
}
char *tourney777_start(char *name,cJSON *json)
{
if ( Tournament != 0 && strcmp(Tournament->name,name) == 0 )
{
Tournament->started = (uint32_t)time(NULL);
tourney777_rebalance(Tournament,1);
return(clonestr("{\"result\":\"tournament started\"}"));
} else return(clonestr("{\"error\":\"no matching tournament\"}"));
}
char *tourney777_register(char *name,bits256 pubkey,cJSON *json)
{
int32_t i; struct hostnet777_server *srv;
if ( Tournament != 0 && strcmp(Tournament->name,name) == 0 && (srv= Tournament->hn[0].server) != 0 )
{
if ( Tournament->started != 0 )
return(clonestr("{\"error\":\"tournament already started\"}"));
else
{
for (i=0; i<srv->num; i++)
if ( memcmp(pubkey.bytes,srv->clients[i].pubkey.bytes,sizeof(bits256)) == 0 )
return(clonestr("{\"error\":\"already registered in tournament\"}"));
srv->clients[srv->num].lastcontact = (uint32_t)time(NULL);
// get endpoint
srv->num++;
return(clonestr("{\"result\":\"registered in tournament\"}"));
}
} else return(clonestr("{\"error\":\"no matching tournament\"}"));
}
char *tourney777_deregister(char *name,bits256 pubkey,cJSON *json)
{
int32_t i; struct hostnet777_server *srv;
if ( Tournament != 0 && strcmp(Tournament->name,name) == 0 && (srv= Tournament->hn[0].server) != 0 )
{
if ( Tournament->started != 0 )
return(clonestr("{\"error\":\"tournament already started\"}"));
else
{
for (i=0; i<srv->num; i++)
if ( memcmp(pubkey.bytes,srv->clients[i].pubkey.bytes,sizeof(bits256)) == 0 )
{
memset(&srv->clients[i],0,sizeof(srv->clients[i]));
if ( i == srv->num-1 )
srv->num--;
return(clonestr("{\"result\":\"deregistered from tournament\"}"));
}
return(clonestr("{\"error\":\"not registered in tournament\"}"));
}
} else return(clonestr("{\"error\":\"no matching tournament\"}"));
}
struct tourney777 *tourney777_init(char *name,bits256 privkey,char *transport,char *ipaddr,uint16_t port,int32_t maxplayers,cJSON *json)
{
struct hostnet777_server *srv; bits256 pubkey; struct tourney777 *tourney; int32_t i; char endpoint[128];
tourney = calloc(1,sizeof(*tourney) + sizeof(*tourney->hn)*maxplayers);
pubkey = acct777_pubkey(privkey);
safecopy(tourney->name,name,sizeof(tourney->name)-1);
if ( transport == 0 || transport[0] == 0 )
transport = "tcp";
strcpy(tourney->transport,transport);
if ( ipaddr == 0 || ipaddr[0] == 0 )
ipaddr = "127.0.0.1";
strcpy(tourney->ipaddr,ipaddr);
if ( port == 0 )
port = 8897;
tourney->port = port;
if ( (srv= hostnet777_server(privkey,pubkey,tourney->transport,tourney->ipaddr,tourney->port,maxplayers)) == 0 )
{
printf("tourney777_init: cant create hostnet777 server\n");
return(0);
}
srv->H.privkey = privkey, srv->H.pubkey = pubkey;
for (i=0; i<maxplayers; i++)
{
sprintf(endpoint,"%s://%s:%u",srv->ep.transport,srv->ep.ipaddr,srv->ep.port + i + 1);
srv->clients[i].pmsock = nn_createsocket(endpoint,1,"NN_PULL",NN_PULL,srv->ep.port + i + 1,10,10);
}
srv->H.pollfunc = tourney777_poll;
tourney->hn[0].server = srv;
// set tournament parameters
if ( portable_thread_create((void *)hostnet777_idler,&tourney->hn[0]) == 0 )
printf("error launching server thread\n");
Tournament = tourney;
return(tourney);
}
#endif
#endif
#endif