Author Topic: Detective Spooner (just for fun)  (Read 3266 times)

0 Members and 1 Guest are viewing this topic.

Offline Sudo

  • Newbie
  • *
  • Posts: 3
  • Karma: +0/-0
Detective Spooner (just for fun)
« on: 22 March, 2012, 22:13:33 »
Confuse and amuse your hubizens with Detective Spooner
Variable subtlety!
Intelligent punctuation!
Optimisable word selection!

Code: [Select]
--Detective Spooner--

--Author: Sudo (aka SudoNhim)
--Version: 1.1 - 22/03/2012

--Detective Spooner examines each significant pair of long words and tries
--to establish which pairs make good spoonerisms. If a pair is selected,
--the words are substituted for the spoonerism.
--Spoonerisms are recorded so they will not happen if the user tries to
--repeat them <trollface.jpg>


-------------------------------------------------------------------
--Configuration

--Filepaths are relative to the PtokaX exe

--Where to find the dictionary file, must be list of words one per line
DICT_FILE = "texts/dict.txt"

--Where/if to save logging data
LOGGING_FILE = "scripts/DetectiveSpoonersLog.txt"
LOGGING_ENABLED = true

----------------------
--Change these settings to make Detective Spooner more invasive/subtle

--Ignore words shorter than...
MIN_WORD_LENGTH = 4

--Skipped words; these are words that should not 'break' a spoonerism, for
--example in "nooks and crannies" we want to skip the "and" so we get
--"crooks and nannies". These should be shorter than MIN_WORD_LENGTH
SKIPPED_WORDS = {'and','or','a','the','so','to','be','he','she','is','for',
'my','in','can'}

--Starting words that should cause the message to be skipped eg user commands
SKIP_MESSAGE_WORDS = {'/me','!faq','!catchup'}

--Chance of spoonerising based on dictionary matches of resulting spoonerism
NO_MATCH_CHANCE = 0.02
ONE_MATCH_CHANCE = 0.9
TWO_MATCH_CHANCE = 1.0

--This function determines the likelyhood that the words will be spooned
--based on the length of the words
function LENGTH_CHANCE(word1,word2)
if (math.random(5,word1:len()+word2:len())>=7) then
return true
else
return false
end
end

-------------------------------------------------------------------
--Some 'helper' functions


function Set(t)
  --For set operations, we want hashing rather enumeration
  local s = {}
  for _,v in pairs(t) do s[v] = true end
  return s
end


function split(s,sep) --Bug; always splits at a '/'
local fields = {}
local s = s..sep
s:gsub("([^"..sep.."]*)"..sep, function(c) table.insert(fields, c) end)
return fields
end

function join(t,sep)
return table.concat(t, sep)
end


function strip(word)
--Remove leading and trailing punctuation
local out = ""
local char = "DUMMY"
local i = 1
while (i <= word:len()) do
char = word:sub(i,i)
if (letters[char:lower()]) then
out = out..char
end
i = i+1
end
return out
end


function unstrip(fromword,toword)
--Add fromword's leading and trailing puctuation to toword and
--return toword. (For undoing strip after modding word)
local out = ""
local char = fromword:sub(1,1)
local i = 1
while (not letters[char:lower()] and i < fromword:len()) do
out = out..char
i = i+1
char = fromword:sub(i,i)
end
out = out..toword
while (letters[char:lower()]) do
i = i+1
char = fromword:sub(i,i)
end
out = out..fromword:sub(i)
return out
end


function write_debug(message)
if LOGGING_ENABLED then
local debug_out = io.open(LOGGING_FILE,'a')
debug_out:write(message..'\n')
io.close(debug_out)
end
end


-------------------------------------------------------------------
--When the script is loaded


function OnStartup()
local dict_file = assert(io.input(DICT_FILE))
local wordtable = split(dict_file:read("*all"),'\n')
dictionary = Set(wordtable)
vowels = Set({'a','e','i','o','u'})
letters = Set({'a','b','c','d','e','f','g','h','i','j','k','l','m',
  'n','o','p','q','r','s','t','u','v','w','x','y','z'})
SKIPPED_WORDS = Set(SKIPPED_WORDS)
SKIP_MESSAGE_WORDS = Set(SKIP_MESSAGE_WORDS)
used_words = {}

--Auto-erase logging file
local debug_out = io.open(LOGGING_FILE,'w')
io.close(debug_out)
end


-------------------------------------------------------------------
--When a message arrives


function ChatArrival(user, data)
write_debug("Arrived: "..data)

local i = 1
local prev_word = false
local words = {}

--remove the name tag from the start of data
if (string.sub(data, 1, 1) == "<" ) then
data = split(data,'>')
table.remove(data,1)
data = join(data,'>')
data = data:sub(1,data:len()-1)
else
write_debug("Message ignored (did not start with '<')")
return false
end

words = split(data,' ')
--Seems to always split at '/' so for user commands:
if (words[1] == '') then
table.remove(words,1)
end

if (SKIP_MESSAGE_WORDS[words[1]]) then
write_debug("Message began with "..words[1]..", exiting")
return false
end

--Perform spoonerism function on valid word pairs
for _,word in pairs(words) do
word = strip(word)
if (word:len()>=MIN_WORD_LENGTH
    and dictionary[string.lower(word)]) then
write_debug("Recieved valid word: "..word)

if (not prev_word == false) then
local spooned
spooned = spoonerise(strip(words[prev_word]),strip(words[i]))
words[prev_word] = unstrip(words[prev_word],spooned[1])
words[i] = unstrip(words[i],spooned[2])
prev_word = i
else
prev_word = i
end
else
if (not SKIPPED_WORDS[word]) then
prev_word = false
else write_debug("Word skipped: "..word)
end
end
i = i+1
end
local sMessage = "<"..user.sNick.."> "..join(words,' ').."|"
Core.SendToAll(sMessage)
write_debug("Sent: "..sMessage..'\n')
return true
end


-------------------------------------------------------------------
--Perform teh spooning magic


function spoonerise(word1,word2)
write_debug("Attempting spoonerise on: "..word1.." "..word2)

if (used_words[word1] and used_words[word2]) then
write_debug("Avoiding possible respooning")
return {word1,word2}
end

if(not LENGTH_CHANCE(word1,word2)) then
write_debug("Randomly decided not to spoon based on length")
return {word1,word2}
end

    local bits = {} --The four segments of word to be recombined
for _,w in pairs({word1,word2}) do
local i = 1
local char = 'DUMMY'
while (not vowels[char] and i<5) do
char = w:sub(i,i):lower()
i = i+1
end
if (not vowels[char]) then
write_debug("Words not valid for spooning")
return {word1,word2}
end
if (char == 'u' and w:sub(i-1,i-1) == 'q') then
i = i+1
end
table.insert(bits,w:lower():sub(1,i-2))
table.insert(bits,w:lower():sub(i-1,w:len()))
end

local spooned = {bits[3]..bits[2], bits[1]..bits[4]}

--Keep case consistent
if (word1:sub(1,1):upper()==word1:sub(1,1)) then
spooned[1] = spooned[1]:sub(1,1):upper()..spooned[1]:sub(2)
else
spooned[1] = spooned[1]:sub(1,1):lower()..spooned[1]:sub(2)
end
if (word2:sub(1,1):upper()==word2:sub(1,1)) then
spooned[2] = spooned[2]:sub(1,1):upper()..spooned[2]:sub(2)
else
spooned[2] = spooned[2]:sub(1,1):lower()..spooned[2]:sub(2)
end
write_debug("Spoons created: "..join(spooned,' '))

--Check to see if spoonerisms are in the dictionary
--and decide whether to go through with it
local matches = 0
for _,word in pairs(spooned) do
if (dictionary[string.lower(word)]) then
matches = matches + 1
end
end
write_debug("Spoonerism contains "..matches.." dictionary words")
if((matches == 0 and math.random()<NO_MATCH_CHANCE)
   or (matches == 1 and math.random()<ONE_MATCH_CHANCE)
   or (matches == 2 and math.random()<TWO_MATCH_CHANCE)) then
used_words[word1] = true
used_words[word2] = true
return spooned
end

write_debug("Randomly decided not to spoonerise")
return {word1,word2}
end

This is my first Lua script, so be gentle :)
Has been -reasonably- thoroughly debugged on a PtokaX 4.2 server on default settings
REQUIRES CONFIGURATION!
Also once you have it working you should turn off logging as it is rather verbose
Enjoy :D

Sudo


EDIT
Updated to fix a punctuation bug
Also minor improvement to evaluation of good spoonerisms

Script: http://www.mediafire.com/?fpazg62npfe2fh7
Suitable dictionary file: http://www.mediafire.com/?b9685avxfie4wc8
« Last Edit: 30 March, 2012, 12:28:51 by Sudo »

PtokaX forum

Detective Spooner (just for fun)
« on: 22 March, 2012, 22:13:33 »

Offline Psycho_Chihuahua

  • Systemspecialist IT
  • Emperor
  • **
  • Posts: 1 054
  • Karma: +112/-1
  • I am wherever i want to be
    • PtokaX Luaboard
Re: Detective Spooner (just for fun)
« Reply #1 on: 22 March, 2012, 22:39:49 »
Uploaded it here for you  ;D

Detective Spooner
PtokaxWiki ?PtokaX Mirror + latest Libs

01100001011011000111001101101111001000000110101101101110011011110111011101101110001000000110000101110011001000000101010001101111011010110110111101101100011011110111001101101000

Offline Sudo

  • Newbie
  • *
  • Posts: 3
  • Karma: +0/-0
Re: Detective Spooner (just for fun)
« Reply #2 on: 22 March, 2012, 23:22:27 »
Uploaded it here for you  ;D

Detective Spooner

Ah thank you, I get "Error: Upload directory not writeable", pretty sure it's not on my side so don't know what's going on there...

May be a 1.3 version of this script soon with improved detection of inferior spoonerisms + a fix for "a"/"an" when the spoonerism switches the first letters between consonant and vowel.

Offline Psycho_Chihuahua

  • Systemspecialist IT
  • Emperor
  • **
  • Posts: 1 054
  • Karma: +112/-1
  • I am wherever i want to be
    • PtokaX Luaboard
Re: Detective Spooner (just for fun)
« Reply #3 on: 22 March, 2012, 23:24:24 »
Did you try uploading it here ?
Anyway, i'll check the Folder permissions for the Attachments as well


Edit: Attachments should work again now. Seems last Update changed Rights on more folders than i had noticed  ::)
« Last Edit: 22 March, 2012, 23:27:49 by Psycho_Chihuahua »
PtokaxWiki ?PtokaX Mirror + latest Libs

01100001011011000111001101101111001000000110101101101110011011110111011101101110001000000110000101110011001000000101010001101111011010110110111101101100011011110111001101101000

Offline bastya_elvtars

  • Forum God
  • ****
  • Posts: 3 745
  • Karma: +173/-7
  • The rock n' roll doctor
    • The FreshStuff3 Site
Re: Detective Spooner (just for fun)
« Reply #4 on: 07 April, 2012, 13:27:27 »
It's good to see that new scripts are still getting made. I've looked at the code, nice job. Thanks for sharing.
Everything could have been anything else and it would have just as much meaning.

Offline Sudo

  • Newbie
  • *
  • Posts: 3
  • Karma: +0/-0
Re: Detective Spooner (just for fun)
« Reply #5 on: 18 April, 2012, 05:28:53 »
Thank you very much  ;D

PtokaX forum

Re: Detective Spooner (just for fun)
« Reply #5 on: 18 April, 2012, 05:28:53 »