/**
* Copyright (c) 2024, SWGY, Inc. <ron@sw.gy>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <err.h>
#include <errno.h>
#include <getopt.h> /* getopt_long */
#include <stdio.h>
#include <stdlib.h>
#include <time.h> /* ctime */
#include <unistd.h>
#include <sys/stdint.h> /* UINT16_MAX */
#include <sys/types.h> /* ctime etc */
/*
* Print a task definition with the given proportion of congruence for stimulus
* and responses.
*/
int print_task(float s_c, float s_r, int last_task);
static struct option longopts[] = {
{ "num-tasks", required_argument, NULL, 'n' },
{ "stimulus-congruent", required_argument, NULL, 's' },
{ "response-congruent", required_argument, NULL, 'r' },
{ NULL, 0, NULL, 0 }
};
static __dead void
usage(const char *n)
{
fprintf(stderr, "usage: %s -n NUM_TASKS --stimulus-congruent=X "
"--response-congruent=Y\n", n);
exit(1);
}
int
main(int argc, char **argv)
{
int ch, numjobs, last_task;
float s_c, r_c;
time_t now;
const char *errstr, *time_str;
numjobs = -1;
s_c = r_c = 0.0f;
while ((ch = getopt_long(argc, argv, "n:s:r:", longopts, NULL)) != -1) {
switch (ch) {
case 'n':
numjobs = strtonum(optarg, 1, 1800, &errstr);
if (errstr != NULL)
err(1, "Problem parsing num jobs %s: %s",
errstr, optarg);
break;
case 's':
s_c = (float) atof(optarg);
break;
case 'r':
r_c = (float) atof(optarg);
break;
default:
usage(*argv); /* does not return */
}
}
if (pledge("stdio", NULL) == -1 || pledge(NULL, NULL) == -1)
err(1, "pledge");
if (numjobs < 1 || numjobs > 1800)
usage(*argv); /* does not return */
if (s_c < 0.0 || s_c > 1.0 || r_c < 0.0 || r_c > 1.0) {
fprintf(stderr, "Congruence ratios must be between 0 and 1\n");
exit(1);
}
time(&now);
if ((time_str = ctime(&now)) == NULL)
err(1, "ctime");
printf("# Tasks generated on %s", time_str);
printf("# %s -n %d --stimulus-congruent %f --response-congruent %f\n",
*argv, numjobs, s_c, r_c);
last_task = -1;
for (; numjobs > 0; --numjobs) {
last_task = print_task(s_c, r_c, last_task);
}
exit(0);
}
static int
tt(float s_c, float s_r, uint32_t v)
{
int retval;
retval = 0;
if (v & 1) /* red stimulus */
retval = 4;
else /* blue stimulus */
retval = 0;
/* Now determine the stimulus type using the upper 16 bits */
if ((((v>>16) & UINT16_MAX) / (float) UINT16_MAX) > s_c)
retval += 2;
/* determine the response placement using the high bit */
if (!(v & (1<<31)))
retval += 8;
/* next determine the response type using the lower 16 bits */
if (((v & UINT16_MAX) / (float) UINT16_MAX) > s_r)
retval += 1;
return retval;
}
int
print_task(float s_c, float s_r, int last_task)
{
uint32_t v;
for (v = arc4random(); tt(s_c, s_r, v) == last_task; v = arc4random()) ;
/* The low bit determines which stimulus to use: one or two */
if (v & 1)
printf("1");
else
printf("2");
/* Now determine the stimulus type using the upper 16 bits */
if ((((v>>16) & UINT16_MAX) / (float) UINT16_MAX) > s_c)
printf("SI "); /* incongruent */
else
printf("SC "); /* congruent */
/* determine the response placement using the high bit */
if (v & (1<<31))
printf("1");
else
printf("2");
/* next determine the response type using the lower 16 bits */
if (((v & UINT16_MAX) / (float) UINT16_MAX) > s_r)
printf("RI\n"); /* incongruent */
else
printf("RC\n"); /* congruent */
return tt(s_c, s_r, v);
}