TGuy 0.18.1
TrashGuy C library created to be easily usable from other languages with CFFI support.
Loading...
Searching...
No Matches
Classes | Macros | Functions
libtguy.c File Reference
#include <libtguy.h>
#include <math.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>

Classes

struct  TGStrViewArr
 
struct  TrashGuyState
 

Macros

#define TGUY_NO_GRAPHEME
 
#define ignored_   (void)
 
#define tg_max(a, b)   ((a) > (b) ? (a) : (b))
 

Functions

static TGStrViewcstr2tgstrv (TGStrView *res, const char *str, size_t len)
 
static size_t strvarr_strlen (const TGStrView arr[], size_t len)
 
static size_t strvarr_write (char str_out[], const TGStrView arr[], size_t len)
 
static size_t strvarr_copy_src (TGStrView *dst, const TGStrView *src, size_t len, const char str_mem[])
 
static void strvarr_copy (TGStrView *dst, const TGStrView *src, size_t len)
 
static unsigned get_first_frame_for_element (unsigned first_element_frames_count, unsigned element_index)
 
static void tguy_clear_field (const TrashGuyState *st, unsigned n_clear_elements)
 
TrashGuyStatetguy_from_arr_ex_2 (const TGStrView arr[], size_t len, unsigned spacing, const TGStrView *sprite_space, const TGStrView *sprite_can, const TGStrView *sprite_right, const TGStrView *sprite_left, int preserve_strings)
 
TrashGuyStatetguy_from_arr_ex (const TGStrView arr[], size_t len, unsigned spacing, const TGStrView *sprite_space, const TGStrView *sprite_can, const TGStrView *sprite_right, const TGStrView *sprite_left)
 
TrashGuyStatetguy_from_arr (const TGStrView arr[], size_t len, unsigned spacing)
 
static char * tguy_utf8_next (const char *begin, const char *end)
 
static size_t tguy_codepoints_len (const char *string, size_t len)
 
TrashGuyStatetguy_from_utf8_ex (const char string[], size_t len, unsigned spacing, const char *sprite_space, size_t sprite_space_len, const char *sprite_can, size_t sprite_can_len, const char *sprite_right, size_t sprite_right_len, const char *sprite_left, size_t sprite_left_len)
 
TrashGuyStatetguy_from_utf8 (const char string[], size_t len, unsigned spacing)
 
TrashGuyStatetguy_from_cstr_arr_ex (const char *const arr[], size_t len, unsigned spacing, const char *sprite_space, size_t sprite_space_len, const char *sprite_can, size_t sprite_can_len, const char *sprite_right, size_t sprite_right_len, const char *sprite_left, size_t sprite_left_len)
 
TrashGuyStatetguy_from_cstr_arr (const char *const arr[], size_t len, unsigned spacing)
 
void tguy_free (TrashGuyState *st)
 
unsigned tguy_set_frame (TrashGuyState *restrict st, unsigned frame)
 
unsigned tguy_set_pos (TrashGuyState *st, unsigned sprite_pos, unsigned facing_right, unsigned element_index)
 
void tguy_get_frame_state (const TrashGuyState *st, unsigned *frame, unsigned *sprite_pos, unsigned *facing_right, unsigned *element_index)
 
size_t tguy_fprint (const TrashGuyState *st, FILE *fp)
 
size_t tguy_print (const TrashGuyState *st)
 
size_t tguy_sprint (const TrashGuyState *st, char *buf)
 
const TGStrViewtguy_get_arr (const TrashGuyState *st, size_t *len)
 
unsigned tguy_get_frames_count (const TrashGuyState *st)
 
size_t tguy_get_bsize (TrashGuyState *st)
 
const char * tguy_get_string (TrashGuyState *st, size_t *len)
 
unsigned tguy_get_first_frame_for_element (const TrashGuyState *st, unsigned element_index)
 
unsigned tguy_get_version (void)
 

Function Documentation

◆ cstr2tgstrv()

static TGStrView * cstr2tgstrv ( TGStrView res,
const char *  str,
size_t  len 
)
static
Parameters
[out]reswhere to keep resulting TGStrView for str
strstring or NULL
lenstr length or -1 if string is nul terminated
Returns
res or NULL if str is NULL

◆ get_first_frame_for_element()

static unsigned get_first_frame_for_element ( unsigned  first_element_frames_count,
unsigned  element_index 
)
inlinestatic

Returns first frame of sequence of frames involving the work with element_index of TrashGuyState::text.
You can perceive this function as a parabola, where each x is element_index and y is returned frame (starts from 0):
frame = element_index2 + (TrashGuyState::first_element_frames_count - 1)element_index
See this visualization.
For example:
(get_first_frame_for_element(4, i + 1) - get_first_frame_for_element(4, i))
will yield number of frames needed to process i-th element if TrashGuyState::first_element_frames_count was 4.

Parameters
first_element_frames_countTrashGuyState::first_element_frames_count
element_indexindex of text element in TrashGuyState::text[element_index]
Returns
first frame index for element_index

◆ tguy_clear_field()

static void tguy_clear_field ( const TrashGuyState st,
unsigned  n_clear_elements 
)
inlinestatic

Replaces TrashGuyState::arena[1:n+1] with with TrashGuyState::sprite_space

Parameters
stValid TrashGuyState
n_clear_elementsnumber of TrashGuyState::text elements to clear with TrashGuyState::sprite_space

◆ tguy_fprint()

size_t tguy_fprint ( const TrashGuyState st,
FILE *  fp 
)

Writes currently set TrashGuy frame to fp without newline

Parameters
stValid TrashGuyState with frame set
fpValid FILE
Returns
Number of bytes written

◆ tguy_free()

void tguy_free ( TrashGuyState st)

Deallocates memory used by a TrashGuyState, does nothing if pointer is NULL

Parameters
stValid TrashGuyState * or NULL

◆ tguy_from_cstr_arr()

TrashGuyState * tguy_from_cstr_arr ( const char *const  arr[],
size_t  len,
unsigned  spacing 
)
Parameters
arrArray of nul-terminated C strings, in case of NULL, acts like empty array and len is set as 0
lenNumber of elements in array
spacingNumber of space sprites to be placed between the TrashGuy sprite and fist element initially
Returns

◆ tguy_from_cstr_arr_ex()

TrashGuyState * tguy_from_cstr_arr_ex ( const char *const  arr[],
size_t  len,
unsigned  spacing,
const char *  sprite_space,
size_t  sprite_space_len,
const char *  sprite_can,
size_t  sprite_can_len,
const char *  sprite_right,
size_t  sprite_right_len,
const char *  sprite_left,
size_t  sprite_left_len 
)
Parameters
arrArray of nul-terminated C strings, in case of NULL, acts like empty array and len is set as 0
lenNumber of elements in array
spacingNumber of space sprites to be placed between the TrashGuy sprite and fist element initially
sprite_spaceSprite to be used as empty space
sprite_space_lenNumber of bytes for sprite_space
sprite_canSprite to be used as trash can
sprite_can_lenNumber of bytes for sprite_can
sprite_rightSprite to be used when TrashGuy moves right
sprite_right_lenNumber of bytes for sprite_right
sprite_leftSprite to be used when TrashGuy moves left
sprite_left_lenNumber of bytes for sprite_left
Returns

◆ tguy_from_utf8()

TrashGuyState * tguy_from_utf8 ( const char  string[],
size_t  len,
unsigned  spacing 
)

Creates new TrashGuysState from valid utf-8 string, where each grapheme cluster is made into an element to dump

Parameters
stringValid utf-8 string, in case of NULL, acts like empty string and len is set as 0
lenNumber of bytes string has, if -1, then strlen will be used
spacingNumber of space sprites to be placed between the TrashGuy sprite and fist element initially
Returns
TrashGuyState * or NULL on allocation failure, must be freed with tguy_free() after use

◆ tguy_get_arr()

const TGStrView * tguy_get_arr ( const TrashGuyState st,
size_t *  len 
)

Returns read-only array view of current TrashGuy frame: TGStrView[]{ {"t",1}, {"e",1}, {"ї",2}, {"s",1}, {"t",1}, {NULL,0} }

Parameters
stValid TrashGuyState with frame set
[out,optional]len Length of the returned array, excluding NULL terminator
Returns
Array of const TGStrView, terminated with TGStrView.str == NULL

◆ tguy_get_bsize()

size_t tguy_get_bsize ( TrashGuyState st)

If bsize is not set, then iterate over possible arena layout and compute buf size big enough to keep any frame plus nul terminator

◆ tguy_get_first_frame_for_element()

unsigned tguy_get_first_frame_for_element ( const TrashGuyState st,
unsigned  element_index 
)

Returns first frame for when certain element is being processed. You can get a range of frames [first,last] for when certain element is processed by calling first = tguy_get_first_frame_for_element(element_index) last = tguy_get_first_frame_for_element(element_index + 1) - 1

Parameters
stValid TrashGuyState
element_indexElement index, in tguy_from_utf8("teїst",-1,4), 't' would be index 0, 'ї' would be index 2, etc.
Returns

◆ tguy_get_frame_state()

void tguy_get_frame_state ( const TrashGuyState st,
unsigned *  frame,
unsigned *  sprite_pos,
unsigned *  facing_right,
unsigned *  element_index 
)
Parameters
stValid TrashGuyState *
[out,optional]frame Current frame, 0 <= frame < tguy_get_frames_count()
[out,optional]sprite_pos Position within the arena, 0 < sprite_pos < tguy_get_arr().len
[out,optional]facing_right Whether sprite is facing right
[out,optional]element_index Index of the element that's currently being processed, see tguy_get_first_frame_for_element()

◆ tguy_get_frames_count()

unsigned tguy_get_frames_count ( const TrashGuyState st)

Returns number of frames particular TrashGuyState has

Parameters
stValid TrashGuyState
Returns
Number of frames, >= 1

◆ tguy_get_version()

unsigned tguy_get_version ( void  )

Get version as integer in format MMMmmmppp. 020107002 -> 20.107.2

Returns
Version number

◆ tguy_print()

size_t tguy_print ( const TrashGuyState st)

Writes currently set TrashGuy frame to stdout without newline

Parameters
stValid TrashGuyState with frame set
Returns
Number of bytes written

◆ tguy_set_frame()

unsigned tguy_set_frame ( TrashGuyState *restrict  st,
unsigned  frame 
)

In order to properly set frame we need to know few things beforehand:

  1. element_index for TrashGuyState::text[element_index] we're currently working on
  2. number of frames per element
  3. first frame (boundary) involving the work on element with element_index
  4. sub frame (frame index)
  5. direction
  6. index within the arena

All we know is desired frame and number of frames per first element.

  1. Because of the get_first_frame_for_element() we know that initial frame of each element is computed as:
    frame = element_index * (first_element_frames_count + element_index - 1)
    which after moving frame to the right, is equivalent to this quadratic equation:
    1*element_index2 + (first_element_frames_count - 1)*element_index + (-frame) = 0
    ax2 + bx + c = 0
    We solve this equation for element_index, which is x1.
    (x1 means right wing of the parabola, x2 (left side) is meaningless to us, valid indices/frames only reside on the right side)
    x1 = (-b + sqrt(b2 - 4ac)) / 2a
    but because c is always negative and a is always 1, we can rewrite it as:
    x1 = (sqrt(b2 + 4c) - b) / 2 , which is the final formula
  2. Simple arithmetic progression, with each next element number of frames increases by 2.
  3. We now have all the values needed to call get_first_frame_for_element().
  4. boundary <= (boundary + sub_frame) < boundary + frames_per_element ,
    thus sub_frame = frame - boundary
  5. we spend the same number of frames moving left/right, if sub_frame < (total / 2) -> right, else -> left
  6. index i within the arena is computed as sub_frame % (total / 2)

◆ tguy_set_pos()

unsigned tguy_set_pos ( TrashGuyState st,
unsigned  sprite_pos,
unsigned  facing_right,
unsigned  element_index 
)

Sets the current frame for TrashGuyState from state components Position is index into arena received via tguy_get_arr().
Example:

spacing = 1
text = "test"
tguy_get_frames_count() = 29
sprite_pos = 1, facing_right = 1, element_index = 0
[ 0] "U(> ^_^)> test"
sprite_pos = 2, facing_right = 1, element_index = 0
[ 1] "U (> ^_^)>test"
sprite_pos = 3, facing_right = 1, element_index = 0
[-1] INVALID, can't overlap with element with index 0
sprite_pos = 2, facing_right = 0, element_index = 0
[ 2] "Ut<(^_^ <) est"
sprite_pos = 1, facing_right = 0, element_index = 0
[ 3] "U<(^_^ <) est"
sprite_pos = 1, facing_right = 1, element_index = 1
[ 4] "U(> ^_^)> est"
There's no element with index 4, but this special case is allowed to face right with all elements cleared
sprite_pos = 1, facing_right = 1, element_index = 4
[28] "U(> ^_^)> "
Parameters
stValid TrashGuyState *
sprite_posPosition within the arena, 0 < sprite_pos < tguy_get_arr().len
facing_rightWhether sprite should be facing right, otherwise left carrying the element
element_indexIndex of the element that's currently being processed, see tguy_get_first_frame_for_element()
Returns
frame on success, -1 (UINT_MAX) on failure