0

I'm working on a slot-machine mini-game application. The rules for what constitutes a winning prize are rather complex (n of a kind, n of any kind, specific sequences), and to make matters even more complicated, this code should work for a slot-machine with (n >= 3) reels.

So, after some thought, I believe defining a context-free language is the most efficient and extensible way to go. This way I could define the grammar in an XML file.

So my question is, given a string of symbols S, how do I go about testing if S is in a given Context-Free Language? Would I simply exhaust rules until I'm out of valid rules/symbols, or is there a known algorithm that could help. Thanks.

Also, a language like this seems non-regular, am I correct? I've never been good at proofs, so I've avoided trying.

Any comments on my approach would be appreciated as well.

Thanks.

Wooble
  • 87,717
  • 12
  • 108
  • 131
Hughie Coles
  • 179
  • 1
  • 10
  • *"I've never been good at proofs, so I've avoided trying."* You won't get better at them by not doing them. – Chris Dargis Aug 13 '12 at 14:10
  • Touche. I was actually just looking at the pumping lemma for context-free languages, and if I understand correctly, this language can't be context-free since there is a limit on length (number of reels). – Hughie Coles Aug 13 '12 at 14:25
  • 2
    The [CYK algorithm](http://en.wikipedia.org/wiki/CYK_algorithm) is O(n^3) and works for any context-free grammar. [LR](http://en.wikipedia.org/wiki/LR_parser) is a rather large class of languages which can be parsed in linear time. – sdcvvc Aug 13 '12 at 14:34

3 Answers3

0

General cases of context free grammers are hard to evaluate.

However, there are methods to parse grammers in subsets of the context free grammers.

For example: SLR and LL grammers are often used by compilers to parse programming languages, which are also context free languages. To use these, your grammer must be in one of these "families" (remember - there are infinite number of grammers for each context free language).

Some practical tools you might want to use that are generally used for compilers are JavaCC in java and bison in C++.
(If I remember correctly, Bison is SLR parser and JavaCC is LL Parser, but I could be wrong)

P.S.
For a specific slot machine, with n slots and k symbols - the language is definetly regular, since there are at most kn "words" in it, and every finite language is regular. Things obviously get compilcated if you are looking for a grammer for all slot machines.

amit
  • 175,853
  • 27
  • 231
  • 333
  • Now "Every finite language is regular" is a property of regular languages I wasn't aware of. Thanks. I can definitely work with this, as I can set some arbitrary limit on the number of reels (I doubt they're going to attempt to use 10,000) to make the language finite. – Hughie Coles Aug 13 '12 at 14:47
0

"...given a string of symbols S, how do I go about testing if S is in a given Context-Free Language?"

If a string w is in L(G); the process of finding a sequence of production rules of G by which w is derived is call parsing. So, you have to create a parse tree to search for some derivation. To do this you perform an exhaustive Breadth-First-Search. There is a serious issue that arises: The searching process may never terminate. To prevent endless searches you have to transform the grammer into what is known as normal form.

"Also, a language like this seems non-regular, am I correct?"

Not necessarily. Every regular language is context-free (because it can be described by a CTG), but not every context-free language is regular.

Chris Dargis
  • 5,891
  • 4
  • 39
  • 63
  • Yes, that's why I wanted to make sure that this language was non-regular. If it was regular, I would look into using a regular expression instead. If it is non-regular (which I'm pretty sure this is), CGF is the next class of languages to my knowledge, which is why I'm testing this approach. Your explanation above is great, and sheds much more light on the process, thank you. – Hughie Coles Aug 13 '12 at 14:42
0

Your best bet is to actually code this with a proper programming language. A CFG is overkill, because it can be extremely hard to code some, as you say, "rather complex" rules. For example, grammars are poorly suited to talking about the number of things.

For example, how would you code "the number of cherries is > the number of any other object" in such a language? How would the person you're giving the program to do so? CFGs cannot easily express such concepts, and regular expressions cannot sanely do so by any stretch.

The answer is that grammars are not right for this task, unless the slot machines is trying to make English sentences.

You also have to consider what happens when TWO or more "prize sequences" match! Assuming you want to give out the highest prize, you need an ordered list of recognizers. This is not to say you can't code your recognizers with (for example) regular expressions in addition to arbitrary functions. I'm just saying that general CFG parsing is overkill, because what CFGs get you over regular languages (i.e. regular expressions) is the ability to consider parse trees of arbitrary depth (like nested parentheses of level N or more), which is probably not what you care about.

This is not to say that you don't, for example, want to allow regular expressions. You can make that job easy by using a parser generator to recognize regexes involving cherries bananas and pears, see http://en.wikipedia.org/wiki/Comparison_of_parser_generators, which you can then embed, though you might want to simply roll your own recursive descent parser (assuming again you don't care about CFGs, especially if your tokens are bounded length).

For example, here is how I might implement it in pseudocode (ideally you'd use a statically typechecked language with good list manipulation, which I can't think of off the top of my head):

rules = []
function Rule(name, code) {
    this.name = name
    this.code = code

    rules.push(this)  # adds them in order
}

##########################

Rule("All the same", regex(.*))

Rule("No two-in-a-row", function(list, counts) {
    not regex(.{2}).match(list)
})

Rule("More cherries than anything else", function(list, counts) {
    counts[cherries]>counts[x] for all x in counts
      or
    sorted(counts.items())[0]==cherries
      or
    counts.greatest()==cherries
})

for token in [cherry, banana, ...]:
    Rule("At least 50% "+token, function(list, counts){
        counts[token] >= list.length/2
    })
ninjagecko
  • 88,546
  • 24
  • 137
  • 145