Saturday, July 2, 2022

Day 17/100 Shuf

 Day 17/100 Shuf

Fortune be your Quote of the Day


Part of the coreutils package is a program called "shuf", short for shuffle. This is used to select random lines from a file. It can be a simple, single line or many. There is also a program called "fortune" which will select a random line(s) entry from the data file. I suggest that you look it up, but basically it's a more sophisticated form of shuf. Quote of the Day (QOTD) is also similar to it. Quite a family!


Another way to use this program is to generate random numbers. This is where the special number mode is used. You simply specify Lo-Hi range of numbers, and the program will generate random numbers within that range. This works, whether you want the numbers to repeat or not. Quite a feat!


  for (i--;i && Cnt;Cnt--) {
    j=i; r=rand()%j;
    t=Nums[i];Nums[i]=Nums[r];Nums[r]=t;
    printf("%d\n",Nums[i]);
    if (Rep==0) i--;
  }


I built this program based off the modified FileGlob program, but it still takes me upward 3 hours to do because of all the different options out there. In fact, I added one more thing: String! You can have it generate a bunch of random strings with number of characters specified with the range option.


  for (j=strlen(Text);Cnt;Cnt--) {
  for (i=Lo+rand()%(Hi-Lo+1);i;i--) {
    r=rand()%j; printf("%c",Text[r]);
  } printf("\n"); }


It's even easier than generating numbers, but this has usefulness as well. You can generate extra large numbers with it, simply by specifying digits as the string, while having the range for the desired number ranges.


Of course, dice rolling is easy, too! Let's get some examples:


3D6: shuf3.c -n 3 -i 1 6 -r
D100: shuf3.c -i 1 100
Lotto:  shuf.c -i 1 49 -n 5


So, here's the completed source code:


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

#define CHUNK 65535
#define MAXLINE 65535
#define MDFILE  0
#define MDNUMS  1
#define MDEND   2
#define MDSTR   3
#define MAXSTR  256

int Mode=MDFILE;
int NumLo=0;
int NumHi=9;
int Cnt=1;
int Rep=0;
int Debug=0;
char Text[MAXSTR]="abc";

char *Data;
int DataSize=0;
int DataUsed=0;
FILE *fp;

char *Lines[MAXLINE];
int  LineUsed=0;

void Init(int argc, char *argv[]) {
  Data=(char *)malloc(CHUNK);\
  DataSize=CHUNK;
  srand(time(NULL));
}

void ShowMsg() {
puts("
Usage: shuf [OPTION]...
  or:  shuf -i LO-HI [OPTION]...
Write a random permutation of the input lines to standard output.
When FILE is -, read standard input
With no FILE and no -i, 0-9 is default.
  -i LO HI   treat each number LO through HI as an input line
  -n COUNT    output at most COUNT lines
  -r         output lines can be repeated
  -s STRING  Randomize STRING with length according to -i
  --help     display this help and exit
  --debug    Activate DEBUG Mode
");
}


int ReadData(int argc, char *argv[]) {
  int c;

  for (int i=1;i<=argc;i++) {
//    puts(argv[i]);

    if (i<argc) {
    if (!strcmp(argv[i],"--help")) {
      ShowMsg(); exit(0);
    }
    if (!strcmp(argv[i],"--debug")) {
      Debug=1;
      if (Debug) printf("Debug Mode: %s\n",(Debug)?"ON":"OFF");
      continue;
    }
    if (!strcmp(argv[i],"-r")) {
      Rep=1;
      if (Debug) printf("Rep: %d\n",Rep);
      continue;
    }
    if (!strncmp(argv[i],"-n",2)) {
      Cnt=atoi(argv[++i]);
      if (Debug) printf("Cnt: %d\n",Cnt);
      continue;
    }
    if (!strncmp(argv[i],"-s",2)) {
      strcpy(Text,argv[++i]);
      if (Debug) printf("Text: %s\n",Text);
      Mode=MDSTR;
      continue;
    }
    if (!strncmp(argv[i],"-i",2)) {
      NumLo=atoi(argv[++i]);
      NumHi=atoi(argv[++i]);
      Mode=MDNUMS;
      if (Debug) printf("Rng: %d - %d\n",NumLo,NumHi);
      continue;
    }
    }

    if (i==argc) {
      if (Mode==MDEND) continue;
      if (Mode==MDNUMS || MDSTR) continue;
      if (Mode==MDFILE) fp=stdin;
    }
    else if (!strcmp(argv[i],"-")) { fp=stdin; }
    else if ((fp=fopen(argv[i],"r"))==NULL) {
      puts("File open Error");
      return 1;
    }
    Mode==MDEND;

    while ((c=fgetc(fp))!=EOF) {
      Data[DataUsed++]=c;
      if (DataUsed>=DataSize) {
        Data=(char *)realloc(Data,(DataSize+CHUNK+1));
        DataSize+=CHUNK;
        printf("DataUsed DataSize %d %d\n",DataUsed,DataSize);
        if (Data==NULL) exit(1);
      }
    }
    Data[DataUsed]='\0';

    if (fp!=stdin) fclose(fp);
  }
  return 0;
}

void ProcessData() {
  int Lo,Hi;
  int i,j,r;
  char *t;


  puts("ShowLines...");
  Lines[LineUsed++]=&Data[0];
  for (i=0;i<DataUsed;i++) {
    if (Data[i]=='\n') {
      Data[i]='\0';
      Lines[LineUsed++]=&Data[i+1];
      if (LineUsed>=MAXLINE) LineUsed--;
    }
  }
  LineUsed--;

  for (i=LineUsed-1;i && Cnt;Cnt--) {
    j=i;
    r=rand()%j;
    t=Lines[i];Lines[i]=Lines[r];Lines[r]=t;
    if (Debug) printf("%s  %d %d %d\n",Lines[i],i,j,r);
    else printf("%s\n",Lines[i]);
    if (Rep==0) i--;
  }
  if (Debug) printf("%s  %d %d %d\n",Lines[i],i,j,r);
  else printf("%s\n",Lines[i]);
}


void CleanUp() {
  free(Data);
}

void RandNums() {
  int Nums[MAXLINE];
  int Lo,Hi;
  int i,j,t,r;

  Lo=NumLo; Hi=NumHi;
  for (i=0,j=Lo;j<=Hi;j++) {
    Nums[i++]=j;
  }

  for (i--;i && Cnt;Cnt--) {
    j=i;
    r=rand()%j;
    t=Nums[i];Nums[i]=Nums[r];Nums[r]=t;
    if (Debug) printf("%d  %d %d %d\n",Nums[i],i,j,r);
    else printf("%d\n",Nums[i]);
    if (Rep==0) i--;
  }
//  if (Debug) printf("%d  %d %d %d\n",Nums[i],i,j,r);
//  else printf("%d\n",Nums[i]);
}

void RandStr() {
  int Nums[MAXLINE];
  int Lo,Hi;
  int i,j,t,r;

  Lo=NumLo; Hi=NumHi;
  for (j=strlen(Text);Cnt;Cnt--) {
  for (i=Lo+rand()%(Hi-Lo+1);i;i--) {
    r=rand()%j;
    if (Debug) printf("%c  %d %d %d\n",Text[r],i,j,r);
    else printf("%c",Text[r]);
  } printf("\n"); }
}


int main (int argc, char *argv[] ) {
  int e=0;

  if (argc<2) { ShowMsg(); return 1; }

  Init(argc,argv);
  ReadData(argc,argv);
  if (Mode==MDNUMS) RandNums();
  else if (Mode==MDSTR) RandStr();
  else ProcessData();
  CleanUp();
  return e;
}


That's quite long! It's not so bad because it's based on earlier FileGlob program, but it's still rather long as far as tiny program is concerned. Like I said, it's all the options that bog it down. Having done professional quality program, though, it would be even worse since professional programmers use frameworks, and it can be rather bothersome, indeed!


No comments:

Post a Comment