Four Letter Word generator based on an associative word dictionary.

Dependencies:   _24LCXXX

Dependents:   vfd_modular_clock_mbed

Four Letter Word generator based on an associative word dictionary.

Needs an EEPROM to function (can be programmed onto a 24LC512 I2C EEPROM, or available as a pre-programmed add-on board)

Comes with a censored mode that removes expletives as well as a fully uncensored mode.

For details see:

flw.cpp

Committer:
Backstrom
Date:
2017-01-13
Revision:
9:93f52963c4ff
Parent:
6:f3455eff2ae4

File content as of revision 9:93f52963c4ff:

/*
 * Four Letter Word Generator
 * (C) 2015 Akafugu Corporation
 *
 * 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 2 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.
 *
 */

/*
 * To use this Four Letter Word generator you will need the following:
 *
 * - A 512kbit/64kb I2C EEPROM
 * - A database file, generated from this Processing application:
 *   https://github.com/perjg/fourletterword
 * - A method for uploading the data file to the EEPROM
 *   (Either an Arduino Mega, or a normal Arduino with a micro SD card)
 */

#include <string.h>
#include "flw.h"
#include "flw_blacklist.h"


#define EEPROM_ADDR 0b1010000

void FourLetterWordBase::rot13(char* w)
{
    while (*w != '\0') {
        if (*w >= 'A' && *w <= 'M') {
            *w += 13;
        }
        else if (*w >= 'N' && *w <= 'Z') {
            *w -= 13;
        }

      w++;
    }
}

bool FourLetterWordBase::binary_search(const char *key, int imin, int imax)
{
  int pos;
  int cond = 0;
  char buf[5];

  while (imin <= imax) {
    pos = (imin+imax) / 2;
    
    strcpy(buf, flw_blacklist[pos]);
    rot13(buf);
    cond = strcmp(key, buf);
    
    if (cond == 0)   return true;
    else if (cond>0) imin = pos+1;
    else             imax = pos-1;
  }
  
  return false;
}

void FourLetterWordBase::begin(uint32_t seed, bool censored)
{
  m_lfsr = seed + 1;
  m_censored = censored;
}

uint32_t FourLetterWordBase::randomize()
{
  // http://en.wikipedia.org/wiki/Linear_feedback_shift_register
  // Galois LFSR: taps: 32 31 29 1; characteristic polynomial: x^32 + x^31 + x^29 + x + 1 */
  m_lfsr = (m_lfsr >> 1) ^ (-(m_lfsr & 1u) & 0xD0000001u);
  return m_lfsr;  
}

bool FourLetterWordBase::hasEeprom()
{
   uint8_t b1 = read_byte(0); 
   uint8_t b2 = read_byte(1); 
   
   if (b1 == 65 && b2 == 66)
     return true;
   return false;
}

char* FourLetterWordBase::get_word_censored()
{
  char* w = get_word_uncensored();
  
  // assume a maximum of 5 censored words chosen in a row
  for (uint8_t i = 0; i < 5; i++) {
    if (binary_search(w, 0, BLACKLIST_SIZE)) { // censored
      w = get_word_uncensored();
    }
    else
      return w;
  }
  
  return w;
}

char* FourLetterWordBase::get_word_uncensored()
{
  unsigned char low = 0xFF, high = 0xFF;
  unsigned char count = 0;
  int next = 0;

  read_buffer(m_offset, (uint8_t*)m_current_word, 5);
  count = m_current_word[4];
  m_current_word[4] = '\0';

  next = randomize() % count;
  m_offset += 5 + next * 2;

  high = read_byte(m_offset++);
  low  = read_byte(m_offset++);

  m_offset = (high << 8) | low;

  return m_current_word;
}

char* FourLetterWordBase::getWord(bool adjustCase)
{
  char* ret;
  
  if (m_censored) ret = get_word_censored();
  ret = get_word_uncensored();
  
  if (adjustCase) {
    // lowercase letters
    ret[1] += 32;
    ret[2] += 32;
    ret[3] += 32;
  }
  
  return ret;
}

/////////////////////////////////////////////////////
// EEPROM

uint8_t FourLetterWord::read_byte(unsigned int addr) {
  uint8_t rdata = 0xFF;
  
  _24lc.nbyte_read(addr, &rdata, 1);
  return rdata;
}

void FourLetterWord::read_buffer(unsigned int addr, uint8_t *buffer, int length) {
  _24lc.nbyte_read(addr, buffer, length);
}

/////////////////////////////////////////////////////
// Data stored in local array

uint8_t FourLetterWordLocal::read_byte(unsigned int addr) {
  return data[addr];  
}

void FourLetterWordLocal::read_buffer(unsigned int addr, uint8_t *buffer, int length) {
  unsigned char* ptr = (unsigned char*)data;
  ptr += addr;
  memcpy(buffer, ptr, length); 
}