Qbasicnews.com

Full Version: Obtaining a Word Within A Sentance
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
Hey guys. Long time no see. Anyway, here's the deal:

I'm currently trying my hand at programming a Chatroom simulator (don't ask; I was bored), and I'm having a little trouble with the basics. You see, I'm storing the responses to and from the "characters" within a text file that looks like this:

Quote:@HELLO HI HOWDY SUP HEY
8
hi
hello
sup
how ya doin'
howdy
nice 2 c u
ello
hey dude

@BYE CYA
8
cyah
adios
so long
ttfn
bye
bi
ciao
hasta luego

...etc, etc...

I obtain these responses by using this code:

Code:
Sub GetResponse(user as STRING, response AS STRING)
Open "conversation.txt" For Input As #1
        Do While Not EOF(1)
            Input #1, doodad$
            If LEFT$(doodad$,1) = "@" AND INSTR(doodad$, user$) Then Exit Do
        Loop
        
         Input #1, totalrec$
         num = Int(Rnd * VAL(totalrec$)) + 1
        
        Do While Not EOF(1)
            Input #1, response$
            cnt = cnt + 1
            If (cnt = num) Then Exit Do
        Loop
        
Close #1
End Sub

If the user types something that isn't in the conversation file, I make the characters say "huh?" However, that is not the problem. I want the characters to respond to someone in a certain way if a certain keyword is within that sentance, i.e. if someone says "hola amigos sup" the other characters would respond with "how yah doin'" or "hello".

The catch: I don't know how to do this.

The code only makes the characters respond as appropriate if the reply is one word and is in the conversation file (the characters respond if the user types "hi", but not if the user types "hi gang what's going on?"). I've tried using FOR-NEXTs within each other, letter counting (letter$ = letter$ + MID$(string$, loop var, 1)), and MID$ itself, but I can't get anything to work.

Can someone guide me in the right direction? :-?

PS: I'm making this in FreeBasic, but it seems to me the code I currently have would look no different than if I wrote it into QBASIC. I also didn't post all the code because I thought that would've been a waste of time.
This is the general outline:

1) Alphabetize the search words.
2) Parse the sentence into words and:
For each word (definition: space or start/end of line on either side, minus . or " or ' etc.) search for the word in the word list.. using a neat function I made ...

...which is somewhere in the old qbasicnews logs..

3) Convert each word into its index value.. then search for the index value set in your defined index value searches. Ex:

Word string is: 91 2104 344 4567
You have a search value set of the same values, say set 84: (91 2104 344 4567)
You then respond with set 244 to set 84, ex: (466 23 23 12)
I'm sorry, but I don't understand what you mean by "converting the words string into an index value" and then searching for said value.
Yes I feared you wouldn't..

Did you understand everything else? :lol:

Word string example:


A tall green tree grows here.

A
tall
green
tree
grows
here

You have an alphabetized array of words. A is 1 on the array list. Its index is 1. Tall is say 573, green is maybe 124, tree is 590, grows is 129, here is 110.

Thus your values are:
1, 573, 124, 590, 129, 110.

Let's say you have a response (sentence) to that statement and the response code is

346, 23, 1, 311, 93, 116.

Then you should match up your input (1, 573, 124, 590, 129, 110) to the output (346, 23, 1, 311, 93, 116)

In qbasic or freebasic you may use the following structure:
inputquestion%(1 to questionamount)
outputresponse%(1 to questionamount)
inputquestionLength%(1 to questionamount)
outputresponseLength%(1 to questionamount)

inputquestionlist%(1 to questionamount*5)
outputresponselist%(1 to questionamount*5)

Inputquestion% and outputresponse%, and the Length% values indicate the starting index number and length of the sentence in the inputquestionlist% and outputresponselist% arrays.

Code:
Example:
inputquestion%(1) = 1
outputresponse%(1) = 1
inputquestionLength%(1) = 6
outputresponseLength%(1) = 6

inputquestionlist%(1) = 1
inputquestionlist%(2) = 573
inputquestionlist%(3) = 124
inputquestionlist%(4) = 590
inputquestionlist%(5) = 129
inputquestionlist%(6) = 110

outputresponselist%(1) = 346
outputresponselist%(2) = 23
outputresponselist%(3) = 1
outputresponselist%(4) = 311
outputresponselist%(5) = 93
outputresponselist%(6) = 116

EDIT:
For now, just try making something that separates the string into words.
Quote:EDIT:
For now, just try making something that separates the string into words.
Done:

Code:
CLS
arrayno% = 1

DIM words$(20)

INPUT "Message: ", msg$

IF INSTR(msg$, "!") THEN msg$ = LEFT$(msg$, LEN(msg$) - 1)
IF INSTR(msg$, "?") THEN msg$ = LEFT$(msg$, LEN(msg$) - 1)
IF INSTR(msg$, ".") THEN msg$ = LEFT$(msg$, LEN(msg$) - 1)

FOR i = 1 to LEN(msg$)
  IF MID$(msg$, i, 1) = " " THEN arrayno% = arrayno% + 1
  IF arrayno% > 20 THEN EXIT FOR

  words$(arrayno%) = words$(arrayno%) + LTRIM$(MID$(msg$, i ,1))
NEXT i

PRINT

FOR j = 1 to arrayno%
  PRINT words$(j)
NEXT j

I pretty much figured that wasn't enough when I popped it into my program and it didn't work right.

Anyway, what next?
For simplicity, that's fine, but for a user:
You can't assume that each message has just one sentence, not that each word is separated by just one space.

Now you alphabetize the array..
Well, I'm pretty much still a novice at programming, so the only way I can think to seperate words with no space between them is to make a database of common words than search through them.

Anyway, here's the new code. I took the sorting code from a great QBASIC tutorial book and altered it (aka "changed the variables") to work with my program. I also moved my punctuation code so if the user types something like "o.ops! a mist.a?ke" the program will still take it as a valid answer, and will take into account the contents of two sentances.

Code:
CLS
arrayno% = 1

DIM words$(20)

INPUT "Message: ", msg$

FOR i = 1 to LEN(msg$)
  IF MID$(msg$, i, 1) = " " THEN arrayno% = arrayno% + 1
  IF arrayno% > 20 THEN PRINT "Only 20 words or less.": EXIT FOR

  words$(arrayno%) = UCASE$(words$(arrayno%) + LTRIM$(MID$(msg$, i ,1)))
  
  IF INSTR(words$(arrayno%), "!") THEN words$(arrayno%) = LEFT$(words$(arrayno%), LEN(words$(arrayno%) - 1)
  IF INSTR(words$(arrayno%), "?") THEN words$(arrayno%) = LEFT$(words$(arrayno%), LEN(words$(arrayno%) - 1)
  IF INSTR(words$(arrayno%), ".") THEN words$(arrayno%) = LEFT$(words$(arrayno%), LEN(words$(arrayno%) - 1)
NEXT i

FOR word1 = 1 to arrayno%
  FOR word2 = word1 + 1 to arrayno%
       IF words$(word1) > words$(word2) THEN SWAP words$(word1), words$(word2)
  NEXT word2
NEXT word1

PRINT

FOR j = 1 to arrayno%
  PRINT words$(j)
NEXT j

Now I hope you're gonna teach me the hard stuff. Big Grin
What I meant is if you have two spaces, it will add two instead of 1.

And, that is a really newb searching algorithm. You can try quicksort, which I have a link for here:
http://forum.qbasicnews.com/viewtopic.ph...=quicksort

Let's cut to the chase though. Add this sub in your code, and call it like so:

Code:
qsort.string.lowstart words$, UBOUND(words$) 'assuming you start from 1..


'The sub can use amax, amin, and array2() as optional values.
SUB qsort.string.lowstart (array1() AS STRING, amax AS INTEGER)
DIM g2(1 TO 32) AS INTEGER, h2(1 TO 32) AS INTEGER 'Holds the ranges to sort and helps calculate pivot positions. This value should be at least log(UBOUND(array1)).

DIM e as INTEGER 'should be be able to hold at least log(UBOUND(array1)) + 1.
DIM i AS INTEGER, j AS INTEGER, r AS INTEGer, g AS INTEGER, h AS INTEGER 'These values should be able to hold a value of at least UBOUND(array1).
DIM k AS STRING 'this should be the same value as the array to sort. (array1())
e = 1
g2(1) = 1 'The starting position of the sort. Set it to LBOUND for the array min value.
h2(1) = amax 'The ending position of the sort. Set it to UBOUND for the array max value.

1
g = g2(e)
h = h2(e)
2 j = g: i = h: r = (g + h) \ 2: k = array1(r)

'to switch from a low to high order or vice versa, just switch these two signs:
'low to high:
'array1(j) < k
'array1(i) > k
'high to low:
'array1(j) > k
'array1(i) < k
3 IF array1(j) < k THEN j = j + 1: GOTO 3
4 IF array1(i) > k THEN i = i - 1: GOTO 4

IF j > i THEN GOTO 7
'To add an array linked to this one, swap it here too. ie: SWAP array2(i), array2(j)
SWAP array1(i), array1(j)
j = j + 1
i = i - 1
IF j > i THEN GOTO 7
GOTO 3

7
IF i + j < h + g THEN
IF j < h THEN g2(e) = j: h2(e) = h: e = e + 1
h = i
ELSE
IF g < i THEN g2(e) = g: h2(e) = i: e = e + 1
g = j
END IF

IF g < h THEN GOTO 2
e = e - 1
IF e THEN goto 1

ERASE g2, h2
END SUB
Now, step 2 consists of you thinking up how exactly you want to do this.

Do you want to have a response to each "question", word for word? Several responses picked randomly? Maybe you want to somehow weigh each word, giving a number, and then pick a response that has the closest weight?
Well, I just want the response based on the first key word within a sentance. For example, say the user says "Hey everyone. I like pie." Even though "pie" and "hey" are two different keywords, the characters will only respond to "hey," and then say a random response based on the list of responses under the "hey" keyword.

Also, I think I have another idea on how to do it. I'll try that out, then have another look at your code. Thanks for the help!
Pages: 1 2