~pixelherodev/DSM-9

443ac5e88c3d8ddae85e5ee92e120477a0bf3832 — Noam Preil a day ago a9302f5
tmp
4 files changed, 187 insertions(+), 45 deletions(-)

M dsm9.h
M due.c
M log.c
M sm2.c
M dsm9.h => dsm9.h +5 -2
@@ 29,10 29,13 @@ typedef struct{
	uint8_t *intervals;
	size_t decklen;
	uint16_t cardnum;
	char *basepath;
	FILE *logs;
	struct{
		uint32_t *due, *new;
		uint16_t *due, *new;
		uint32_t duecount, newcount;
		uint32_t lastupdated;
		char *names;
	} accel;
} dsm9deck;



@@ 52,6 55,6 @@ char *dsm9cardback(uint32_t);
/*
	Appends a log entry to the log file, updates the card information, and flushes the card information to the DSM accelerator file.
*/
int dsm9log(dsm9deck, uint32_t index, uint8_t grade, uint32_t timestamp);
int dsm9log(dsm9deck*, uint32_t index, uint8_t grade, uint32_t timestamp);



M due.c => due.c +5 -4
@@ 33,8 33,10 @@ parse_arguments(dsm9deck *deck, int argc, char **argv)
		}
		else {
			delta();
			if(!dsm9load(argv[i], deck))
				fprintf(stderr, "Failed to load deck into new format\n");
			if(!dsm9load(argv[i], deck)){
				fprintf(stderr, "Failed to load deck '%s'\n", argv[i]);
				exit(1);
			}
			dt = delta();
			printf("Loaded deck of %d cards into new format in %fs\n", deck->cardnum, dt);
		}


@@ 55,8 57,7 @@ main(int argc, char **argv)
	uint32_t total = deck.accel.duecount + deck.accel.newcount;
	if(conf.count > total - conf.offset)
		conf.count = total - conf.offset;
	if(conf.count != 0)
		puts("Due:");
	puts(conf.count > 0 ? "Due:" : "Nothing is due.");
	for(uint32_t i = conf.offset; i < conf.count + conf.offset; i += 1){
		if(!new && i >= deck.accel.duecount)
			new = 1;

M log.c => log.c +32 -35
@@ 1,5 1,4 @@
#ifndef _PLAN9_NOAPE
// POSIX or APE
#ifndef _POSIX_SOURCE
#include <stdlib.h>
#include <stdint.h>
#include <string.h>


@@ 9,11 8,13 @@
#include <libc.h>
#include "9compat.h"
#endif

#include <stdio.h>
#include "sm2.h"
#include "dsm9.h"
#include "util.h"

#ifdef _PLAN9_NOAPE
#ifdef _PLAN9_SOURCE
void
exit(int code)
{


@@ 21,7 22,7 @@ exit(int code)
}
#endif

struct sm2_instance instance;
dsm9deck deck;
unsigned long max_cards;
long timestamp;
int sequential;


@@ 30,7 31,6 @@ void
parse_arguments(int argc, char **argv)
{
	int i;
	long count;
	for (i = 1; i < argc; i += 1){
		if (strcmp(argv[i], "-t") == 0){
			i += 1;


@@ 43,37 43,38 @@ parse_arguments(int argc, char **argv)
			continue;
		}
		if(strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--sequential") == 0){
			printf("SEQ\n");
			sequential = 1;
			continue;
		}
		delta();
		count = sm2_load(&instance, argv[i], 0);
		if(count < 0){
		if(!dsm9load(argv[i], &deck)){
			printf("Failed to load %s!\n", argv[i]);
			continue;
		}
		printf("Loaded %lud cards in %fs\n", count, delta());
		count = sm2_load(&instance, argv[i], 1);
		if(count < 0){
			printf("Failed to open log file: '%s.log', continuing without...\n", argv[i]);
			continue;
			exit(1);
		}
		printf("Loaded %lud log entries in %fs\n", count, delta());
		printf("Loaded %d cards in %fs\n", deck.cardnum, delta());
	}
}

void
card_prompt(struct sm2_card card)
static void
prompt(uint32_t index)
{
	char buf[3];
	printf("%s: ", card.id);
	char *name = dsm9cardname(&deck, index);
	if(name == NULL){
		fprintf(stderr, "Failed to load card name\n");
		exit(1);
	}
	printf("%s: ", name);
	free(name);
	if (fgets(buf, 3, stdin) != NULL) {
		if(buf[0] < '0' || buf[0] > '5' || buf[1] != '\n') {
			fputs("expected a line containing one digit in [0,5]\n", stderr);
			exit(1);
		}
		sm2_log(&instance, card.id, buf[0] - '0', timestamp);
		if(!dsm9log(&deck, index, buf[0] - '0', timestamp)){
			fputs("Logging failed!\n", stderr);
			exit(1);
		}
	} else {
		fputs("Failed to read\n",stderr);
		exit(1);


@@ 91,26 92,22 @@ default_options(void)
int
main(int argc, char **argv)
{
	uint32_t i, count;
	struct sm2_card *cards;
	uint32_t i;
	default_options();
	sm2_init(&instance);
	pin(0);
	memset(&deck, 0, sizeof(deck));
	parse_arguments(argc, argv);
	if(instance.card_count == 0){
	if(deck.cardnum == 0){
		fputs("No cards found!\n",stderr);
		exit(1);
	}
	if(sequential == 0){
		cards = h_find_cards(&instance, time(NULL), &count);
		if (cards != NULL)
			repetition_sort(cards, count);
	} else {
		cards = instance.cards;
		count = instance.card_count;
	}
	for(i = 0; i < count; i += 1)
		card_prompt(cards[i]);
	// let the kernel free the memory
		for(i = 0; i < deck.cardnum && i < deck.accel.duecount; i += 1)
			prompt(deck.accel.due[i]);
		for(; i < deck.cardnum && i + deck.accel.duecount < deck.accel.newcount; i += 1)
			prompt(deck.accel.new[i]);
	} else
		for(i = 0; i < deck.cardnum; i += 1)
			prompt(i);
	/* let the kernel free the memory */
	return 0;
}
\ No newline at end of file

M sm2.c => sm2.c +145 -4
@@ 9,7 9,9 @@
#include <string.h>

#endif

#include <stdio.h>
#include <time.h>

/* v1 header; this should be removed as soon as v2 is finished */
#include "sm2.h"


@@ 25,9 27,70 @@ dsm9unload(dsm9deck *deck)
	free(deck->deckbuf);
	sbfree(deck->accel.new);
	sbfree(deck->fronts);
	if(deck->logs != NULL)
		fclose(deck->logs);
	memset(deck, 0, sizeof(*deck));
}

static void
dolog(dsm9deck *deck, uint32_t index, uint8_t grade, uint32_t timestamp)
{
	double e = deck->easinesses[index];
	double i = deck->intervals[index];
	double ts = timestamp;
	double g = grade;
	deck->reps[index] += 1;
	if(grade < 3){
		deck->dues[index] = 0;
		deck->intervals[index] = 1;
		printf("Already due: %d\n",index);
		pushu16(&deck->accel.due, index);
		return;
	}
	e = e - 0.8 + (0.28 * g) - (0.02 * g * g);
	if(e < 1.3)
		e = 1.3;
	deck->easinesses[index] = 1.3;
	deck->dues[index] = (uint32_t)(ts + ((double)60 * (double)60 * (double)24 * i * e));
	if(deck->dues[index] < time(NULL)){
		printf("Already due: %d\n",index);
		pushu16(&deck->accel.due, index);
	}
	deck->intervals[index] = deck->reps[index] == 1 ? 3 : deck->reps[index] == 2 ? 6 : deck->easinesses[index] * (double)deck->intervals[index];
}

static int
openlogs(dsm9deck *deck)
{
	if(deck->logs != NULL)
		return 1;
	char *path = aprintf("%s.log", deck->basepath);
	if(path == NULL)
		return 0;
	deck->logs = fopen(path, "a");
	free(path);
	if(deck->logs == NULL){
		fprintf(stderr, "Failed to open log for %s", deck->basepath);
		return 0;
	}
	return 1;
}

int
dsm9log(dsm9deck *deck, uint32_t index, uint8_t grade, uint32_t timestamp)
{
	char *id = dsm9cardname(deck, index);
	if(id == NULL)
		return 0;
	dolog(deck,index,grade,timestamp);
	if(!openlogs(deck))
		return 0;
	fprintf(deck->logs, "%s@@@%u@@@%u\n", id, timestamp, grade);
	fflush(deck->logs);
	free(id);
	return 1;
}

static int
fastidpush(uint32_t **ids, uint32_t id, uint16_t *index)
{


@@ 94,12 157,33 @@ initcards(dsm9deck *deck)
	return 1;
}

static uint32_t
find(dsm9deck *deck, char *name)
{
	char *withdelim = aprintf("%s@@@", name);
	if(withdelim == NULL)
		return -1;
	for(uint32_t i = 0; i < deck->cardnum; i += 1)
		if(strncmp(withdelim, deck->deckbuf + deck->ids[i], strlen(withdelim)) == 0){
			free(withdelim);
 			return i;
	}
	printf("Unable to find card '%s', search str '%s'\n", name,withdelim);
	free(withdelim);
	return (uint32_t)-1;
}

/* Log entries have three fields: id, timestamp, grade */
/* Returns 0 on failure to process logs, 1 on success, and 2 if logs can't be loaded */
static int
logsload(dsm9deck *deck, char *basepath)
{
	delta();
	double dt;
	char *buf, *logpath = aprintf("%s.log", basepath);
	char *line, *delim, *id, *timestamp;
	uint32_t count = 0, l = 0, index, len;
	uint8_t grade;
	size_t size;
	if(logpath == NULL)
		return 0;


@@ 109,8 193,56 @@ logsload(dsm9deck *deck, char *basepath)
		fprintf(stderr, "Unable to read logs for '%s', continuing without...\n", basepath);
		return 2;
	}
	(void)deck;
	return 0;
	line = strtok(buf, "\n");
	while(line != NULL){
		l += 1;
		delim = strstr(line, "@@@");
		if(delim == NULL){
			fprintf(stderr, "expected three fields on line %d, found one\n", l);
			return 0;
		}
		len = delim - line;
		id = malloc(len + 1);
		memcpy(id, line, len);
		id[len] = 0;
		line = delim + 3;
		delim = strstr(line, "@@@");
		if(delim == NULL){
			fprintf(stderr, "expected three fields on line %d, found two", l);
			free(id);
			return 0;
		}
		len = delim - line;
		timestamp = malloc(len + 1);
		memcpy(timestamp, line, len);
		timestamp[len] = 0;
		if(strlen(delim+3) != 1){
			fprintf(stderr, "grade must be a single digit");			
			free(id);
			free(timestamp);
			return 0;
		}
		grade = *(delim + 3) - '0';
		if(grade > 5){
			fprintf(stderr,"grade must be a single digit between 0 and 5 (inclusive)");			
			free(id);
			free(timestamp);
			return 0;
		}
		index = find(deck, id);
		if(index == (uint32_t)-1){
			printf("card '%s' unknown, ignoring log entry...\n", id);
		} else{
			dolog(deck, index, grade, atol(timestamp));
			count += 1;
		}
		line = strtok(NULL, "\n");
		free(id);
		free(timestamp);
	}
	dt = delta();
	printf("Loaded %d log entries in %fs\n", count, dt);
	return 1;
}

static int


@@ 185,6 317,7 @@ dsm9load(char *basepath, dsm9deck *deck)
		return 0;
	dsm9unload(deck);
	deck->deckbuf = readfile(deckpath, &deck->decklen);
	deck->basepath = basepath;
	free(deckpath);
	if(deck->deckbuf == NULL){
		fprintf(stderr, "Unable to read deck for '%s'\n", basepath);


@@ 194,9 327,9 @@ dsm9load(char *basepath, dsm9deck *deck)
	if(!accelload(deck, basepath))
		switch(logsload(deck, basepath)){
		case 0:
			return 1;
		case 1:
			return 0;
		case 1:
			break;
		case 2:
			if(!sbexactcapacity(&deck->accel.new, deck->cardnum, 4))
				return 0;


@@ 206,6 339,14 @@ dsm9load(char *basepath, dsm9deck *deck)
			deck->accel.newcount = deck->cardnum;
			return 1;
		}
	if(!sbexactcapacity(&deck->accel.new, deck->cardnum, 4))
		return 0;
	for(uint16_t i = 0; i < deck->cardnum; i += 1)
		if(deck->reps[i] == 0)
			if(!pushu16(&deck->accel.new, i))
				return 0;
	deck->accel.newcount = sbcount(deck->accel.new);
	deck->accel.duecount = sbcount(deck->accel.due);
	return 1;
}