Browse Source

Prices example

jl777
jl777 5 years ago
parent
commit
3640e3c4fc
  1. 13
      src/cc/gamescc.cpp
  2. 4
      src/cc/makecclib
  3. 896
      src/cc/prices.c
  4. 461
      src/cc/prices.cpp
  5. 208
      src/cc/prices.h

13
src/cc/gamescc.cpp

@ -14,7 +14,11 @@
******************************************************************************/
#include "gamescc.h"
#include "tetris.c" // replace with game code
#ifdef BUILD_PRICES
#include "prices.c"
#elif
#include "tetris.c"
#endif
int32_t GAMEDATA(struct games_player *P,void *ptr);
@ -161,8 +165,11 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3
}
#ifndef STANDALONE
#include "tetris.cpp" // replace with game specific functions
#ifdef BUILD_PRICES
#include "prices.cpp"
#elif
#include "tetris.cpp"
#endif
void GAMEJSON(UniValue &obj,struct games_player *P);

4
src/cc/makecclib

@ -12,6 +12,10 @@ echo games tetris
gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o gamescc.so cclib.cpp
./maketetris
echo games prices
gcc -O3 -DBUILD_GAMESCC -DBUILD_PRICES -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o pricescc.so cclib.cpp
./makeprices
echo customcc stub
gcc -O3 -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o customcc.so cclib.cpp

896
src/cc/prices.c

@ -0,0 +1,896 @@
#include "tetris.h"
/*
In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure.
also, the standalone game needs to support argv of seed gametxid, along with replay args
*/
int random_tetromino(struct games_state *rs)
{
rs->seed = _games_rngnext(rs->seed);
return(rs->seed % NUM_TETROMINOS);
}
int32_t tetrisdata(struct games_player *P,void *ptr)
{
tetris_game *tg = (tetris_game *)ptr;
P->gold = tg->points;
P->dungeonlevel = tg->level;
//fprintf(stderr,"score.%d level.%d\n",tg->points,tg->level);
return(0);
}
/***************************************************************************/
/** https://github.com/brenns10/tetris
@file main.c
@author Stephen Brennan
@date Created Wednesday, 10 June 2015
@brief Main program for tetris.
@copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised
BSD License. See LICENSE.txt for details.
*******************************************************************************/
#include <stdio.h> // for FILE
#include <stdbool.h> // for bool
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <string.h>
#ifdef BUILD_GAMESCC
#include "rogue/cursesd.h"
#else
#include <curses.h>
#endif
#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
/*******************************************************************************
Array Definitions
*******************************************************************************/
const tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS] =
{
// I
{{{1, 0}, {1, 1}, {1, 2}, {1, 3}},
{{0, 2}, {1, 2}, {2, 2}, {3, 2}},
{{3, 0}, {3, 1}, {3, 2}, {3, 3}},
{{0, 1}, {1, 1}, {2, 1}, {3, 1}}},
// J
{{{0, 0}, {1, 0}, {1, 1}, {1, 2}},
{{0, 1}, {0, 2}, {1, 1}, {2, 1}},
{{1, 0}, {1, 1}, {1, 2}, {2, 2}},
{{0, 1}, {1, 1}, {2, 0}, {2, 1}}},
// L
{{{0, 2}, {1, 0}, {1, 1}, {1, 2}},
{{0, 1}, {1, 1}, {2, 1}, {2, 2}},
{{1, 0}, {1, 1}, {1, 2}, {2, 0}},
{{0, 0}, {0, 1}, {1, 1}, {2, 1}}},
// O
{{{0, 1}, {0, 2}, {1, 1}, {1, 2}},
{{0, 1}, {0, 2}, {1, 1}, {1, 2}},
{{0, 1}, {0, 2}, {1, 1}, {1, 2}},
{{0, 1}, {0, 2}, {1, 1}, {1, 2}}},
// S
{{{0, 1}, {0, 2}, {1, 0}, {1, 1}},
{{0, 1}, {1, 1}, {1, 2}, {2, 2}},
{{1, 1}, {1, 2}, {2, 0}, {2, 1}},
{{0, 0}, {1, 0}, {1, 1}, {2, 1}}},
// T
{{{0, 1}, {1, 0}, {1, 1}, {1, 2}},
{{0, 1}, {1, 1}, {1, 2}, {2, 1}},
{{1, 0}, {1, 1}, {1, 2}, {2, 1}},
{{0, 1}, {1, 0}, {1, 1}, {2, 1}}},
// Z
{{{0, 0}, {0, 1}, {1, 1}, {1, 2}},
{{0, 2}, {1, 1}, {1, 2}, {2, 1}},
{{1, 0}, {1, 1}, {2, 1}, {2, 2}},
{{0, 1}, {1, 0}, {1, 1}, {2, 0}}},
};
const int GRAVITY_LEVEL[MAX_LEVEL+1] = {
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
50, 48, 46, 44, 42, 40, 38, 36, 34, 32,
//10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
30, 28, 26, 24, 22, 20, 16, 12, 8, 4
};
/*******************************************************************************
Helper Functions for Blocks
*******************************************************************************/
void sleep_milli(int milliseconds)
{
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = milliseconds * 1000 * 1000;
nanosleep(&ts, NULL);
}
/*
Return the block at the given row and column.
*/
char tg_get(tetris_game *obj, int row, int column)
{
return obj->board[obj->cols * row + column];
}
/*
Set the block at the given row and column.
*/
static void tg_set(tetris_game *obj, int row, int column, char value)
{
obj->board[obj->cols * row + column] = value;
}
/*
Check whether a row and column are in bounds.
*/
bool tg_check(tetris_game *obj, int row, int col)
{
return 0 <= row && row < obj->rows && 0 <= col && col < obj->cols;
}
/*
Place a block onto the board.
*/
static void tg_put(tetris_game *obj, tetris_block block)
{
int i;
for (i = 0; i < TETRIS; i++) {
tetris_location cell = TETROMINOS[block.typ][block.ori][i];
tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col,
TYPE_TO_CELL(block.typ));
}
}
/*
Clear a block out of the board.
*/
static void tg_remove(tetris_game *obj, tetris_block block)
{
int i;
for (i = 0; i < TETRIS; i++) {
tetris_location cell = TETROMINOS[block.typ][block.ori][i];
tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, TC_EMPTY);
}
}
/*
Check if a block can be placed on the board.
*/
static bool tg_fits(tetris_game *obj, tetris_block block)
{
int i, r, c;
for (i = 0; i < TETRIS; i++) {
tetris_location cell = TETROMINOS[block.typ][block.ori][i];
r = block.loc.row + cell.row;
c = block.loc.col + cell.col;
if (!tg_check(obj, r, c) || TC_IS_FILLED(tg_get(obj, r, c))) {
return false;
}
}
return true;
}
/*
Create a new falling block and populate the next falling block with a random
one.
*/
static void tg_new_falling(struct games_state *rs,tetris_game *obj)
{
// Put in a new falling tetromino.
obj->falling = obj->next;
obj->next.typ = random_tetromino(rs);
obj->next.ori = 0;
obj->next.loc.row = 0;
obj->next.loc.col = obj->cols/2 - 2;
}
/*******************************************************************************
Game Turn Helpers
*******************************************************************************/
/*
Tick gravity, and move the block down if gravity should act.
*/
static void tg_do_gravity_tick(struct games_state *rs,tetris_game *obj)
{
obj->ticks_till_gravity--;
if (obj->ticks_till_gravity <= 0) {
tg_remove(obj, obj->falling);
obj->falling.loc.row++;
if (tg_fits(obj, obj->falling)) {
obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level];
} else {
obj->falling.loc.row--;
tg_put(obj, obj->falling);
tg_new_falling(rs,obj);
}
tg_put(obj, obj->falling);
}
}
/*
Move the falling tetris block left (-1) or right (+1).
*/
static void tg_move(tetris_game *obj, int direction)
{
tg_remove(obj, obj->falling);
obj->falling.loc.col += direction;
if (!tg_fits(obj, obj->falling)) {
obj->falling.loc.col -= direction;
}
tg_put(obj, obj->falling);
}
/*
Send the falling tetris block to the bottom.
*/
static void tg_down(struct games_state *rs,tetris_game *obj)
{
tg_remove(obj, obj->falling);
while (tg_fits(obj, obj->falling)) {
obj->falling.loc.row++;
}
obj->falling.loc.row--;
tg_put(obj, obj->falling);
tg_new_falling(rs,obj);
}
/*
Rotate the falling block in either direction (+/-1).
*/
static void tg_rotate(tetris_game *obj, int direction)
{
tg_remove(obj, obj->falling);
while (true) {
obj->falling.ori = (obj->falling.ori + direction) % NUM_ORIENTATIONS;
// If the new orientation fits, we're done.
if (tg_fits(obj, obj->falling))
break;
// Otherwise, try moving left to make it fit.
obj->falling.loc.col--;
if (tg_fits(obj, obj->falling))
break;
// Finally, try moving right to make it fit.
obj->falling.loc.col += 2;
if (tg_fits(obj, obj->falling))
break;
// Put it back in its original location and try the next orientation.
obj->falling.loc.col--;
// Worst case, we come back to the original orientation and it fits, so this
// loop will terminate.
}
tg_put(obj, obj->falling);
}
/*
Swap the falling block with the block in the hold buffer.
*/
static void tg_hold(struct games_state *rs,tetris_game *obj)
{
tg_remove(obj, obj->falling);
if (obj->stored.typ == -1) {
obj->stored = obj->falling;
tg_new_falling(rs,obj);
} else {
int typ = obj->falling.typ, ori = obj->falling.ori;
obj->falling.typ = obj->stored.typ;
obj->falling.ori = obj->stored.ori;
obj->stored.typ = typ;
obj->stored.ori = ori;
while (!tg_fits(obj, obj->falling)) {
obj->falling.loc.row--;
}
}
tg_put(obj, obj->falling);
}
/*
Perform the action specified by the move.
*/
static void tg_handle_move(struct games_state *rs,tetris_game *obj, tetris_move move)
{
switch (move) {
case TM_LEFT:
//fprintf(stderr,"LEFT ");
tg_move(obj, -1);
break;
case TM_RIGHT:
//fprintf(stderr,"RIGHT ");
tg_move(obj, 1);
break;
case TM_DROP:
tg_down(rs,obj);
break;
case TM_CLOCK:
tg_rotate(obj, 1);
break;
case TM_COUNTER:
tg_rotate(obj, -1);
break;
case TM_HOLD:
tg_hold(rs,obj);
break;
default:
// pass
break;
}
}
/*
Return true if line i is full.
*/
static bool tg_line_full(tetris_game *obj, int i)
{
int j;
for (j = 0; j < obj->cols; j++) {
if (TC_IS_EMPTY(tg_get(obj, i, j)))
return false;
}
return true;
}
/*
Shift every row above r down one.
*/
static void tg_shift_lines(tetris_game *obj, int r)
{
int i, j;
for (i = r-1; i >= 0; i--) {
for (j = 0; j < obj->cols; j++) {
tg_set(obj, i+1, j, tg_get(obj, i, j));
tg_set(obj, i, j, TC_EMPTY);
}
}
}
/*
Find rows that are filled, remove them, shift, and return the number of
cleared rows.
*/
static int tg_check_lines(tetris_game *obj)
{
int i, nlines = 0;
tg_remove(obj, obj->falling); // don't want to mess up falling block
for (i = obj->rows-1; i >= 0; i--) {
if (tg_line_full(obj, i)) {
tg_shift_lines(obj, i);
i++; // do this line over again since they're shifted
nlines++;
}
}
tg_put(obj, obj->falling); // replace
return nlines;
}
/*
Adjust the score for the game, given how many lines were just cleared.
*/
static void tg_adjust_score(tetris_game *obj, int lines_cleared)
{
static int line_multiplier[] = {0, 40, 100, 300, 1200};
obj->points += line_multiplier[lines_cleared] * (obj->level + 1);
if (lines_cleared >= obj->lines_remaining) {
obj->level = MIN(MAX_LEVEL, obj->level + 1);
lines_cleared -= obj->lines_remaining;
obj->lines_remaining = LINES_PER_LEVEL - lines_cleared;
} else {
obj->lines_remaining -= lines_cleared;
}
}
/*
Return true if the game is over.
*/
static bool tg_game_over(tetris_game *obj)
{
int i, j;
bool over = false;
tg_remove(obj, obj->falling);
for (i = 0; i < 2; i++) {
for (j = 0; j < obj->cols; j++) {
if (TC_IS_FILLED(tg_get(obj, i, j))) {
over = true;
}
}
}
tg_put(obj, obj->falling);
return over;
}
/*******************************************************************************
Main Public Functions
*******************************************************************************/
/*
Do a single game tick: process gravity, user input, and score. Return true if
the game is still running, false if it is over.
*/
bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move)
{
int lines_cleared;
// Handle gravity.
tg_do_gravity_tick(rs,obj);
// Handle input.
tg_handle_move(rs,obj, move);
// Check for cleared lines
lines_cleared = tg_check_lines(obj);
tg_adjust_score(obj, lines_cleared);
// Return whether the game will continue (NOT whether it's over)
return !tg_game_over(obj);
}
void tg_init(struct games_state *rs,tetris_game *obj, int rows, int cols)
{
// Initialization logic
obj->rows = rows;
obj->cols = cols;
//obj->board = (char *)malloc(rows * cols);
memset(obj->board, TC_EMPTY, rows * cols);
obj->points = 0;
obj->level = 0;
obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level];
obj->lines_remaining = LINES_PER_LEVEL;
//srand(time(NULL));
tg_new_falling(rs,obj);
tg_new_falling(rs,obj);
obj->stored.typ = -1;
obj->stored.ori = 0;
obj->stored.loc.row = 0;
obj->next.loc.col = obj->cols/2 - 2;
//printf("%d", obj->falling.loc.col);
}
tetris_game *tg_create(struct games_state *rs,int rows, int cols)
{
tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game) + rows*cols);
tg_init(rs,obj, rows, cols);
return obj;
}
/*void tg_destroy(tetris_game *obj)
{
// Cleanup logic
free(obj->board);
}*/
void tg_delete(tetris_game *obj) {
//tg_destroy(obj);
free(obj);
}
/*
Load a game from a file.
tetris_game *tg_load(FILE *f)
{
tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game));
if (fread(obj, sizeof(tetris_game), 1, f) != 1 )
{
fprintf(stderr,"read game error\n");
free(obj);
obj = 0;
}
else
{
obj->board = (char *)malloc(obj->rows * obj->cols);
if (fread(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols )
{
fprintf(stderr,"fread error\n");
free(obj->board);
free(obj);
obj = 0;
}
}
return obj;
}*/
/*
Save a game to a file.
void tg_save(tetris_game *obj, FILE *f)
{
if (fwrite(obj, sizeof(tetris_game), 1, f) != 1 )
fprintf(stderr,"error writing tetrisgame\n");
else if (fwrite(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols )
fprintf(stderr,"error writing board\n");
}*/
/*
Print a game board to a file. Really just for early debugging.
*/
void tg_print(tetris_game *obj, FILE *f) {
int i, j;
for (i = 0; i < obj->rows; i++) {
for (j = 0; j < obj->cols; j++) {
if (TC_IS_EMPTY(tg_get(obj, i, j))) {
fputs(TC_EMPTY_STR, f);
} else {
fputs(TC_BLOCK_STR, f);
}
}
fputc('\n', f);
}
}
/*
2 columns per cell makes the game much nicer.
*/
#define COLS_PER_CELL 2
/*
Macro to print a cell of a specific type to a window.
*/
#define ADD_BLOCK(w,x) waddch((w),' '|A_REVERSE|COLOR_PAIR(x)); \
waddch((w),' '|A_REVERSE|COLOR_PAIR(x))
#define ADD_EMPTY(w) waddch((w), ' '); waddch((w), ' ')
/*
Print the tetris board onto the ncurses window.
*/
void display_board(WINDOW *w, tetris_game *obj)
{
int i, j;
box(w, 0, 0);
for (i = 0; i < obj->rows; i++) {
wmove(w, 1 + i, 1);
for (j = 0; j < obj->cols; j++) {
if (TC_IS_FILLED(tg_get(obj, i, j))) {
ADD_BLOCK(w,tg_get(obj, i, j));
} else {
ADD_EMPTY(w);
}
}
}
wnoutrefresh(w);
}
/*
Display a tetris piece in a dedicated window.
*/
void display_piece(WINDOW *w, tetris_block block)
{
int b;
tetris_location c;
wclear(w);
box(w, 0, 0);
if (block.typ == -1) {
wnoutrefresh(w);
return;
}
for (b = 0; b < TETRIS; b++) {
c = TETROMINOS[block.typ][block.ori][b];
wmove(w, c.row + 1, c.col * COLS_PER_CELL + 1);
ADD_BLOCK(w, TYPE_TO_CELL(block.typ));
}
wnoutrefresh(w);
}
/*
Display score information in a dedicated window.
*/
void display_score(WINDOW *w, tetris_game *tg)
{
wclear(w);
box(w, 0, 0);
wprintw(w, (char *)"Score\n%d\n", tg->points);
wprintw(w, (char *)"Level\n%d\n", tg->level);
wprintw(w, (char *)"Lines\n%d\n", tg->lines_remaining);
wnoutrefresh(w);
}
/*
Save and exit the game.
void save(tetris_game *game, WINDOW *w)
{
FILE *f;
wclear(w);
box(w, 0, 0); // return the border
wmove(w, 1, 1);
wprintw(w, (char *)"Save and exit? [Y/n] ");
wrefresh(w);
timeout(-1);
if (getch() == 'n') {
timeout(0);
return;
}
f = fopen("tetris.save", "w");
tg_save(game, f);
fclose(f);
tg_delete(game);
endwin();
fprintf(stderr,"Game saved to \"tetris.save\".\n");
fprintf(stderr,"Resume by passing the filename as an argument to this program.\n");
exit(EXIT_SUCCESS);
}*/
/*
Do the NCURSES initialization steps for color blocks.
*/
void init_colors(void)
{
start_color();
//init_color(COLOR_ORANGE, 1000, 647, 0);
init_pair(TC_CELLI, COLOR_CYAN, COLOR_BLACK);
init_pair(TC_CELLJ, COLOR_BLUE, COLOR_BLACK);
init_pair(TC_CELLL, COLOR_WHITE, COLOR_BLACK);
init_pair(TC_CELLO, COLOR_YELLOW, COLOR_BLACK);
init_pair(TC_CELLS, COLOR_GREEN, COLOR_BLACK);
init_pair(TC_CELLT, COLOR_MAGENTA, COLOR_BLACK);
init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK);
}
struct games_state globalR;
extern char Gametxidstr[];
int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c);
gamesevent games_readevent(struct games_state *rs);
void *gamesiterate(struct games_state *rs)
{
uint32_t counter = 0; bool running = true; tetris_move move = TM_NONE;
gamesevent c; uint16_t skipcount=0; int32_t prevlevel; uint32_t eventid = 0; tetris_game *tg;
WINDOW *board, *next, *hold, *score;
if ( rs->guiflag != 0 || rs->sleeptime != 0 )
{
// NCURSES initialization:
initscr(); // initialize curses
cbreak(); // pass key presses to program, but not signals
noecho(); // don't echo key presses to screen
keypad(stdscr, TRUE); // allow arrow keys
timeout(0); // no blocking on getch()
curs_set(0); // set the cursor to invisible
init_colors(); // setup tetris colors
}
tg = tg_create(rs,22, 10);
prevlevel = tg->level;
// Create windows for each section of the interface.
board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0);
next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1);
hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1);
score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1);
while ( running != 0 )
{
running = tg_tick(rs,tg,move);
if ( 1 && (rs->guiflag != 0 || rs->sleeptime != 0) )
{
display_board(board,tg);
display_piece(next,tg->next);
display_piece(hold,tg->stored);
display_score(score,tg);
}
if ( rs->guiflag != 0 )
{
#ifdef STANDALONE
sleep_milli(15);
if ( (counter++ % 10) == 0 )
doupdate();
c = games_readevent(rs);
if ( c <= 0x7f || skipcount == 0x3fff )
{
if ( skipcount > 0 )
issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000);
if ( c <= 0x7f )
issue_games_events(rs,Gametxidstr,eventid,c);
if ( tg->level != prevlevel )
{
flushkeystrokes(rs,0);
prevlevel = tg->level;
}
skipcount = 0;
} else skipcount++;
#endif
}
else
{
if ( rs->replaydone != 0 )
break;
if ( rs->sleeptime != 0 )
{
sleep_milli(1);
if ( (counter++ % 20) == 0 )
doupdate();
}
if ( skipcount == 0 )
{
c = games_readevent(rs);
//fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level);
if ( (c & 0x4000) == 0x4000 )
{
skipcount = (c & 0x3fff);
c = 'S';
}
}
if ( skipcount > 0 )
skipcount--;
}
eventid++;
switch ( c )
{
case 'h':
move = TM_LEFT;
break;
case 'l':
move = TM_RIGHT;
break;
case 'k':
move = TM_CLOCK;
break;
case 'j':
move = TM_DROP;
break;
case 'q':
running = false;
move = TM_NONE;
break;
/*case 'p':
wclear(board);
box(board, 0, 0);
wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2);
wprintw(board, "PAUSED");
wrefresh(board);
timeout(-1);
getch();
timeout(0);
move = TM_NONE;
break;
case 's':
save(tg, board);
move = TM_NONE;
break;*/
case ' ':
move = TM_HOLD;
break;
default:
move = TM_NONE;
}
}
return(tg);
}
#ifdef STANDALONE
/*
Main tetris game!
*/
#include "dapps/dappstd.c"
char *clonestr(char *str)
{
char *clone; int32_t len;
if ( str == 0 || str[0] == 0 )
{
printf("warning cloning nullstr.%p\n",str);
#ifdef __APPLE__
while ( 1 ) sleep(1);
#endif
str = (char *)"<nullstr>";
}
len = strlen(str);
clone = (char *)calloc(1,len+16);
strcpy(clone,str);
return(clone);
}
int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c)
{
static FILE *fp;
char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1;
if ( fp == 0 )
fp = fopen("events.log","wb");
rs->buffered[rs->num++] = c;
if ( 0 )
{
if ( sizeof(c) == 1 )
sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid);
else if ( sizeof(c) == 2 )
sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid);
else if ( sizeof(c) == 4 )
sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c&0xffffffff,gametxidstr,eventid);
else if ( sizeof(c) == 8 )
sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid);
if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 )
{
if ( (retjson= cJSON_Parse(retstr)) != 0 )
{
if ( (resobj= jobj(retjson,(char *)"result")) != 0 )
{
retval = 0;
if ( fp != 0 )
{
fprintf(fp,"%s\n",jprint(resobj,0));
fflush(fp);
}
}
free_json(retjson);
} else fprintf(fp,"error parsing %s\n",retstr);
free(retstr);
} else fprintf(fp,"error issuing method %s\n",params);
return(retval);
} else return(0);
}
int tetris(int argc, char **argv)
{
struct games_state *rs = &globalR;
int32_t c,skipcount=0; uint32_t eventid = 0; tetris_game *tg = 0;
memset(rs,0,sizeof(*rs));
rs->guiflag = 1;
rs->sleeptime = 1; // non-zero to allow refresh()
if ( argc >= 2 && strlen(argv[2]) == 64 )
{
#ifdef _WIN32
#ifdef _MSC_VER
rs->origseed = _strtoui64(argv[1], NULL, 10);
#else
rs->origseed = atol(argv[1]); // windows, but not MSVC
#endif // _MSC_VER
#else
rs->origseed = atol(argv[1]); // non-windows
#endif // _WIN32
rs->seed = rs->origseed;
if ( argc >= 3 )
{
strcpy(Gametxidstr,argv[2]);
fprintf(stderr,"setplayerdata %s\n",Gametxidstr);
if ( games_setplayerdata(rs,Gametxidstr) < 0 )
{
fprintf(stderr,"invalid gametxid, or already started\n");
return(-1);
}
}
} else rs->seed = 777;
/* Load file if given a filename.
if (argc >= 2) {
FILE *f = fopen(argv[1], "r");
if (f == NULL) {
perror("tetris");
exit(EXIT_FAILURE);
}
tg = tg_load(f);
fclose(f);
} else {
// Otherwise create new game.
tg = tg_create(rs,22, 10);
}*/
// Game loop
tg = (tetris_game *)gamesiterate(rs);
gamesbailout(rs);
// Deinitialize NCurses
wclear(stdscr);
endwin();
// Output ending message.
printf("Game over!\n");
printf("You finished with %d points on level %d.\n", tg->points, tg->level);
// Deinitialize Tetris
tg_delete(tg);
return 0;
}
#endif

461
src/cc/prices.cpp

@ -1,3 +1,4 @@
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
@ -13,442 +14,60 @@
* *
******************************************************************************/
#include "CCassets.h"
#include "CCPrices.h"
/*
Prices CC would best build on top of the oracles CC, ie. to combine payments for multiple oracles and to calculate a 51% protected price feed.
We need to assume there is an oracle for a specific price. In the event there are more than one provider, the majority need to be within correlation distance to update a pricepoint.
int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format);
Using the above function, a consensus price can be obtained for a datasource.
given an oracletxid, the marketaddr and format can be extracted to be used for future calls to OraclePrice. This allows to set a starting price and that in turn allows cash settled leveraged trading!
Funds work like with dice, ie. there is a Prices plan that traders bet against.
PricesFunding oracletxid, margin, priceaveraging, maxleverage, funding, longtoken, shorttoken, N [pubkeys]
PricesBet -> oracletxid start with 'L', leverage, funding, direction
funds are locked into global CC address
it can be closed at anytime by the trader for cash settlement
the house account can close it if rekt
Implementation Notes:
In order to eliminate the need for worrying about sybil attacks, each prices plan would be able to specific pubkey(s?) for whitelisted publishers. It would be possible to have a non-whitelisted plan that would use 50% correlation between publishers.
delta neutral balancing of riskexposure: fabs(long exposure - short exposure)
bet +B at leverage L
absval(sum(+BLi) - sum(-Bli))
validate: update riskexposure and it needs to be <= funds
PricesProfits: limit withdraw to funds in excess of riskexposure
PricesFinish: payout (if winning) and update riskexposure
need long/short exposure assets
funding -> 1of2 CC global CC address and dealer address, exposure tokens to global 1of2 assets CC address
pricebet -> user funds and exposure token to 1of2 address.
pricewin -> winnings from dealer funds, exposure token back to global address
priceloss -> exposuretoken back to global address
exposure address, funds address
*/
// start of consensus code
int64_t PricesOraclePrice(int64_t &rektprice,uint64_t mode,uint256 oracletxid,std::vector<CPubKey>pubkeys,int32_t dir,int64_t amount,int32_t leverage)
// game specific code for daemon
void games_packitemstr(char *packitemstr,struct games_packitem *item)
{
int64_t price;
// howto ensure price when block it confirms it not known
// get price from oracle + current chaintip
// normalize leveraged amount
if ( dir > 0 )
rektprice = price * leverage / (leverage-1);
else rektprice = price * (leverage-1) / leverage;
return(price);
strcpy(packitemstr,"");
}
CScript EncodePricesFundingOpRet(uint8_t funcid,CPubKey planpk,uint256 oracletxid,uint256 longtoken,uint256 shorttoken,int32_t millimargin,uint64_t mode,int32_t maxleverage,std::vector<CPubKey> pubkeys,uint256 bettoken)
int64_t games_cashout(struct games_player *P)
{
CScript opret;
fprintf(stderr,"implement EncodePricesFundingOpRet\n");
return(opret);
int32_t dungeonlevel = P->dungeonlevel; int64_t mult=1000,cashout = 0;
cashout = (uint64_t)P->gold * mult * dungeonlevel * dungeonlevel;
return(cashout);
}
uint8_t DecodePricesFundingOpRet(CScript scriptPubKey,CPubKey &planpk,uint256 &oracletxid,uint256 &longtoken,uint256 &shorttoken,int32_t &millimargin,uint64_t &mode,int32_t &maxleverage,std::vector<CPubKey> &pubkeys,uint256 &bettoken)
void tetrisplayerjson(UniValue &obj,struct games_player *P)
{
fprintf(stderr,"implement DecodePricesFundingOpRet\n");
return(0);
obj.push_back(Pair("packsize",(int64_t)P->packsize));
obj.push_back(Pair("hitpoints",(int64_t)P->hitpoints));
obj.push_back(Pair("strength",(int64_t)(P->strength&0xffff)));
obj.push_back(Pair("maxstrength",(int64_t)(P->strength>>16)));
obj.push_back(Pair("level",(int64_t)P->level));
obj.push_back(Pair("experience",(int64_t)P->experience));
obj.push_back(Pair("dungeonlevel",(int64_t)P->dungeonlevel));
}
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
int32_t disp_gamesplayer(char *str,struct games_player *P)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
return true; // TODO remove, for test dual-evals
return eval->Invalid("no validation yet");
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
numvins = tx.vin.size();
numvouts = tx.vout.size();
preventCCvins = preventCCvouts = -1;
if ( numvouts < 1 )
return eval->Invalid("no vouts");
else
{
for (i=0; i<numvins; i++)
{
if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
{
return eval->Invalid("illegal normal vini");
}
}
//fprintf(stderr,"check amounts\n");
//if ( PricesExactAmounts(cp,eval,tx,1,10000) == false )
{
fprintf(stderr,"Pricesget invalid amount\n");
return false;
}
//else
{
txid = tx.GetHash();
memcpy(hash,&txid,sizeof(hash));
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
if ( retval != 0 )
fprintf(stderr,"Pricesget validated\n");
else fprintf(stderr,"Pricesget invalid\n");
return(retval);
}
}
}
// end of consensus code
// helper functions for rpc calls in rpcwallet.cpp
int64_t AddTokensInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,char *destaddr,uint256 tolenid,int64_t total,int32_t maxinputs)
{
// add threshold check
int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,destaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
// need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 && vout < vintx.vout.size() )
{
// need to verify assetid
if ( (nValue= vintx.vout[vout].nValue) >= 10000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
nValue = it->second.satoshis;
totalinputs += nValue;
n++;
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
}
}
}
return(totalinputs);
}
UniValue PricesList()
{
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint64_t mode; int32_t margin,maxleverage; std::vector<CPubKey>pubkeys; uint256 txid,hashBlock,oracletxid,longtoken,shorttoken,bettoken; CPubKey planpk,pricespk; char str[65]; CTransaction vintx;
cp = CCinit(&C,EVAL_PRICES);
pricespk = GetUnspendable(cp,0);
SetCCtxids(addressIndex,cp->normaladdr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' )
{
result.push_back(uint256_str(str,txid));
}
}
}
return(result);
}
// longtoken satoshis limits long exposure
// shorttoken satoshis limits short exposure
// both must be in the 1of2 CC address with its total supply
// bettoken
std::string PricesCreateFunding(uint64_t txfee,uint256 bettoken,uint256 oracletxid,uint64_t margin,uint64_t mode,uint256 longtoken,uint256 shorttoken,int32_t maxleverage,int64_t funding,std::vector<CPubKey> pubkeys)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CTransaction oracletx; int64_t fullsupply,inputs,CCchange=0; uint256 hashBlock; char str[65],coinaddr[64],houseaddr[64]; CPubKey mypk,pricespk; int32_t i,N,numvouts; struct CCcontract_info *cp,C;
if ( funding < 100*COIN || maxleverage <= 0 || maxleverage > 10000 )
{
CCerror = "invalid parameter error";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
cp = CCinit(&C,EVAL_PRICES);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp,0);
if ( (N= (int32_t)pubkeys.size()) || N > 15 )
{
fprintf(stderr,"too many pubkeys N.%d\n",N);
return("");
}
for (i=0; i<N; i++)
{
Getscriptaddress(coinaddr,CScript() << ParseHex(HexStr(pubkeys[i])) << OP_CHECKSIG);
if ( CCaddress_balance(coinaddr) == 0 )
{
fprintf(stderr,"N.%d but pubkeys[%d] has no balance\n",N,i);
return("");
}
}
if ( GetCCaddress1of2(cp,houseaddr,pricespk,mypk) == 0 )
{
fprintf(stderr,"PricesCreateFunding cant create globaladdr\n");
return("");
}
if ( CCtoken_balance(houseaddr,longtoken) != CCfullsupply(longtoken) )
{
fprintf(stderr,"PricesCreateFunding (%s) globaladdr.%s token balance %.8f != %.8f\n",uint256_str(str,longtoken),houseaddr,(double)CCtoken_balance(houseaddr,longtoken)/COIN,(double)CCfullsupply(longtoken)/COIN);
return("");
}
if ( CCtoken_balance(houseaddr,shorttoken) != CCfullsupply(shorttoken) )
{
fprintf(stderr,"PricesCreateFunding (%s) globaladdr.%s token balance %.8f != %.8f\n",uint256_str(str,longtoken),houseaddr,(double)CCtoken_balance(houseaddr,longtoken)/COIN,(double)CCfullsupply(shorttoken)/COIN);
return("");
}
if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= oracletx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find oracletxid %s\n",uint256_str(str,oracletxid));
return("");
}
fprintf(stderr,"error check bettoken\n");
if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 )
{
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(pricespk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesFundingOpRet('F',mypk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken)));
}
else
{
CCerror = "cant find enough inputs";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
return("");
}
UniValue PricesInfo(uint256 fundingtxid)
{
UniValue result(UniValue::VOBJ),a(UniValue::VARR); CPubKey pricespk,planpk; uint256 hashBlock,oracletxid,longtoken,shorttoken,bettoken; CTransaction vintx; int64_t balance,supply,exposure; uint64_t funding,mode; int32_t i,margin,maxleverage; char numstr[65],houseaddr[64],exposureaddr[64],str[65]; std::vector<CPubKey>pubkeys; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_PRICES);
pricespk = GetUnspendable(cp,0);
if ( GetTransaction(fundingtxid,vintx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find fundingtxid\n");
ERR_RESULT("cant find fundingtxid");
return(result);
}
if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' )
{
result.push_back(Pair("result","success"));
result.push_back(Pair("fundingtxid",uint256_str(str,fundingtxid)));
result.push_back(Pair("bettoken",uint256_str(str,bettoken)));
result.push_back(Pair("oracletxid",uint256_str(str,oracletxid)));
sprintf(numstr,"%.3f",(double)margin/1000);
result.push_back(Pair("profitmargin",numstr));
result.push_back(Pair("maxleverage",maxleverage));
result.push_back(Pair("mode",(int64_t)mode));
for (i=0; i<pubkeys.size(); i++)
a.push_back(pubkey33_str(str,(uint8_t *)&pubkeys[i]));
result.push_back(Pair("pubkeys",a));
GetCCaddress1of2(cp,houseaddr,pricespk,planpk);
GetCCaddress1of2(cp,exposureaddr,pricespk,pricespk); // assets addr
result.push_back(Pair("houseaddr",houseaddr));
result.push_back(Pair("betaddr",exposureaddr));
result.push_back(Pair("longtoken",uint256_str(str,longtoken)));
supply = CCfullsupply(longtoken);
result.push_back(Pair("longsupply",supply));
balance = CCtoken_balance(houseaddr,longtoken);
result.push_back(Pair("longavail",balance));
exposure = CCtoken_balance(exposureaddr,longtoken);
result.push_back(Pair("longexposure",exposure));
result.push_back(Pair("shorttoken",uint256_str(str,shorttoken)));
supply = CCfullsupply(shorttoken);
result.push_back(Pair("shortsupply",supply));
balance = CCtoken_balance(houseaddr,shorttoken);
result.push_back(Pair("shortavail",balance));
exposure = CCtoken_balance(exposureaddr,shorttoken);
result.push_back(Pair("shortexposure",exposure));
sprintf(numstr,"%.8f",(double)CCtoken_balance(houseaddr,bettoken)/COIN);
result.push_back(Pair("funds",numstr));
}
return(result);
}
std::string PricesAddFunding(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,int64_t amount)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
struct CCcontract_info *cp,C; CPubKey pricespk,planpk,mypk; uint256 hashBlock,oracletxid,longtoken,shorttoken,bettoken; CTransaction tx; int64_t balance,supply,exposure,inputs,CCchange = 0; uint64_t funding,mode; int32_t margin,maxleverage; char houseaddr[64],myaddr[64]; std::vector<CPubKey>pubkeys;
if ( amount < 10000 )
{
CCerror = "amount must be positive";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
cp = CCinit(&C,EVAL_PRICES);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp,0);
GetCCaddress(cp,myaddr,mypk);
if ( GetTransaction(fundingtxid,tx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find fundingtxid\n");
return("");
}
if ( tx.vout.size() > 0 && DecodePricesFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' && bettoken == refbettoken )
{
GetCCaddress1of2(cp,houseaddr,pricespk,planpk);
if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 )
{
if ( (inputs= AddTokensInputs(cp,mtx,myaddr,bettoken,amount,60)) >= amount )
{
mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,amount,pricespk,planpk));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(planpk)) << OP_CHECKSIG));
if ( inputs > amount+txfee )
CCchange = (inputs - amount);
mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk));
// add addr2
std::vector<CPubKey> voutTokenPubkeysEmpty; //TODO: add token vout pubkeys
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,
EncodeTokenOpRet(bettoken, voutTokenPubkeysEmpty,
std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('t',/*bettoken,*/zeroid, 0, Mypubkey())))));
}
else
{
CCerror = "cant find enough bet inputs";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
}
else
{
CCerror = "cant find enough inputs";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
}
return("");
}
std::string PricesBet(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,int64_t amount,int32_t leverage)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
struct CCcontract_info *cp,C; CPubKey pricespk,planpk,mypk; uint256 hashBlock,oracletxid,longtoken,shorttoken,tokenid,bettoken; CTransaction tx; int64_t balance,supply,exposure,inputs,inputs2,longexposure,netexposure,shortexposure,CCchange = 0,CCchange2 = 0; uint64_t funding,mode; int32_t dir,margin,maxleverage; char houseaddr[64],myaddr[64],exposureaddr[64]; std::vector<CPubKey>pubkeys;
if ( amount < 0 )
{
amount = -amount;
dir = -1;
} else dir = 1;
cp = CCinit(&C,EVAL_PRICES);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
pricespk = GetUnspendable(cp,0);
GetCCaddress(cp,myaddr,mypk);
if ( GetTransaction(fundingtxid,tx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find fundingtxid\n");
return("");
}
if ( tx.vout.size() > 0 && DecodePricesFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' && bettoken == refbettoken )
{
if ( leverage > maxleverage || leverage < 1 )
{
fprintf(stderr,"illegal leverage\n");
return("");
}
GetCCaddress1of2(cp,houseaddr,pricespk,planpk);
GetCCaddress1of2(cp,exposureaddr,pricespk,pricespk);
if ( dir < 0 )
tokenid = shorttoken;
else tokenid = longtoken;
exposure = leverage * amount;
longexposure = CCtoken_balance(exposureaddr,longtoken);
shortexposure = CCtoken_balance(exposureaddr,shorttoken);
netexposure = (longexposure - shortexposure + exposure*dir);
if ( netexposure < 0 )
netexposure = -netexposure;
balance = CCtoken_balance(myaddr,bettoken) / COIN;
if ( balance < netexposure*9/10 ) // 10% extra room for dynamically closed bets in wrong direction
{
fprintf(stderr,"balance %lld < 90%% netexposure %lld, refuse bet\n",(long long)balance,(long long)netexposure);
return("");
}
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
{
if ( (inputs= AddTokensInputs(cp,mtx,houseaddr,tokenid,exposure,30)) >= exposure )
{
if ( (inputs2= AddTokensInputs(cp,mtx,myaddr,bettoken,amount,30)) >= amount )
{
mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,amount,pricespk,planpk));
mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,exposure,pricespk,pricespk));
if ( inputs > exposure+txfee )
CCchange = (inputs - exposure);
if ( inputs2 > amount+txfee )
CCchange2 = (inputs2 - amount);
mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,CCchange,pricespk,planpk));
mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange2,mypk));
// add addr2 and addr3
//return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesExtra('T',tokenid,bettoken,zeroid,dir*leverage)));
CScript opret;
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
}
else
{
fprintf(stderr,"cant find enough bettoken inputs\n");
return("");
}
}
else
{
fprintf(stderr,"cant find enough exposure inputs\n");
return("");
}
}
else
{
CCerror = "cant find enough inputsB";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
}
return("");
str[0] = 0;
//if ( P->gold <= 0 )//|| P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 )
// return(-1);
sprintf(str," <- playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",P->gold,P->hitpoints,P->strength&0xffff,P->strength>>16,P->level,P->experience,P->dungeonlevel);
return(0);
}
UniValue PricesStatus(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid)
int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector<uint8_t> payload)
{
UniValue result(UniValue::VOBJ);
// get height of bettxid
// get price and rekt
// get current height and price
// what about if rekt in the past?
return(result);
uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0;
if ( (len= payload.size()) > 36 )
{
len -= 36;
for (i=0; i<32; i++)
((uint8_t *)&gametxid)[i] = payload[len+i];
eventid = (uint32_t)payload[len+32];
eventid |= (uint32_t)payload[len+33] << 8;
eventid |= (uint32_t)payload[len+34] << 16;
eventid |= (uint32_t)payload[len+35] << 24;
//for (i=0; i<len; i++)
// fprintf(stderr,"%02x",payload[i]);
//fprintf(stderr," got payload, from %s %s/e%d\n",pubkey33_str(str,(uint8_t *)&pk),gametxid.GetHex().c_str(),eventid);
return(0);
} else return(-1);
}
std::string PricesFinish(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid)
bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
{
return("");
return(true);
}

208
src/cc/prices.h

@ -0,0 +1,208 @@
#ifndef H_PRICES_H
#define H_PRICES_H
/***************************************************************************/
/** https://github.com/brenns10/tetris
@file main.c
@author Stephen Brennan
@date Created Wednesday, 10 June 2015
@brief Main program for tetris.
@copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised
BSD License. See LICENSE.txt for details.
*******************************************************************************/
/*
Convert a tetromino type to its corresponding cell.
*/
#define TYPE_TO_CELL(x) ((x)+1)
/*
Strings for how you would print a tetris board.
*/
#define TC_EMPTY_STR " "
#define TC_BLOCK_STR "\u2588"
/*
Questions about a tetris cell.
*/
#define TC_IS_EMPTY(x) ((x) == TC_EMPTY)
#define TC_IS_FILLED(x) (!TC_IS_EMPTY(x))
/*
How many cells in a tetromino?
*/
#define TETRIS 4
/*
How many tetrominos?
*/
#define NUM_TETROMINOS 7
/*
How many orientations of a tetromino?
*/
#define NUM_ORIENTATIONS 4
/*
Level constants.
*/
#define MAX_LEVEL 19
#define LINES_PER_LEVEL 10
/*
A "cell" is a 1x1 block within a tetris board.
*/
typedef enum {
TC_EMPTY, TC_CELLI, TC_CELLJ, TC_CELLL, TC_CELLO, TC_CELLS, TC_CELLT, TC_CELLZ
} tetris_cell;
/*
A "type" is a type/shape of a tetromino. Not including orientation.
*/
typedef enum {
TET_I, TET_J, TET_L, TET_O, TET_S, TET_T, TET_Z
} tetris_type;
/*
A row,column pair. Negative numbers allowed, because we need them for
offsets.
*/
typedef struct {
int row;
int col;
} tetris_location;
/*
A "block" is a struct that contains information about a tetromino.
Specifically, what type it is, what orientation it has, and where it is.
*/
typedef struct {
int typ;
int ori;
tetris_location loc;
} tetris_block;
/*
All possible moves to give as input to the game.
*/
typedef enum {
TM_LEFT, TM_RIGHT, TM_CLOCK, TM_COUNTER, TM_DROP, TM_HOLD, TM_NONE
} tetris_move;
/*
A game object!
*/
typedef struct {
/*
Game board stuff:
*/
int rows;
int cols;
/*
Scoring information:
*/
int points;
int level;
/*
Falling block is the one currently going down. Next block is the one that
will be falling after this one. Stored is the block that you can swap out.
*/
tetris_block falling;
tetris_block next;
tetris_block stored;
/*
Number of game ticks until the block will move down.
*/
int ticks_till_gravity;
/*
Number of lines until you advance to the next level.
*/
int lines_remaining;
char board[];
} tetris_game;
/*
This array stores all necessary information about the cells that are filled by
each tetromino. The first index is the type of the tetromino (i.e. shape,
e.g. I, J, Z, etc.). The next index is the orientation (0-3). The final
array contains 4 tetris_location objects, each mapping to an offset from a
point on the upper left that is the tetromino "origin".
*/
extern const tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS];
/*
This array tells you how many ticks per gravity by level. Decreases as level
increases, to add difficulty.
*/
extern const int GRAVITY_LEVEL[MAX_LEVEL+1];
// Data structure manipulation.
void tg_init(tetris_game *obj, int rows, int cols);
tetris_game *tg_create(struct games_state *rs,int rows, int cols);
void tg_destroy(tetris_game *obj);
void tg_delete(tetris_game *obj);
tetris_game *tg_load(FILE *f);
void tg_save(tetris_game *obj, FILE *f);
// Public methods not related to memory:
char tg_get(tetris_game *obj, int row, int col);
bool tg_check(tetris_game *obj, int row, int col);
bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move);
void tg_print(tetris_game *obj, FILE *f);
/******************************************************************************
* Copyright © 2014-2019 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. *
* *
******************************************************************************/
#define GAMENAME "prices" // name of executable
#define GAMEMAIN prices // main program of game
#define GAMEPLAYERJSON pricesplayerjson // displays game specific json
#define GAMEDATA pricesdata // extracts data from game specific variables into games_state
#define CHAINNAME "PRICES" // -ac_name=
typedef uint64_t gamesevent; // can be 8, 16, 32, or 64 bits
#define MAXPACK 23
struct games_packitem
{
int32_t type,launch,count,which,hplus,dplus,arm,flags,group;
char damage[8],hurldmg[8];
};
struct games_player
{
int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,amulet;
struct games_packitem gamespack[MAXPACK];
};
struct games_state
{
uint64_t seed,origseed;
char *keystrokeshex;
uint32_t needflush,replaydone;
int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum;
FILE *logfp;
struct games_player P;
gamesevent buffered[5000],*keystrokes;
uint8_t playerdata[8192];
};
extern struct games_state globalR;
void *gamesiterate(struct games_state *rs);
int32_t flushkeystrokes(struct games_state *rs,int32_t waitflag);
void games_packitemstr(char *packitemstr,struct games_packitem *item);
uint64_t _games_rngnext(uint64_t initseed);
int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis);
gamesevent games_revendian(gamesevent revx);
int32_t disp_gamesplayer(char *str,struct games_player *P);
#endif
Loading…
Cancel
Save