Related
I decided to create an account in order to ask a question I cant seem to figure out myself, or by some googling, hopefully I didn't just overlook it.
Essentially I am trying to make a text adventure game in Java, and am having a little trouble seeing how I should relate everything in the idea of objects. I have been successful in using XML stax and sending a file to the program, and using attributes and what not, to make it where the user can enter an integer associated with an option, and see if option requires an "item" or gives them an Item. I however did not take an OOP to this.
I want my new program to people able to take a string of user input in, instead of only an integer, and checking it against an array list if it exists. This is closer to the classic MUDs most may be familiar with.
I want to design it in a modular way, so I can slowly add on ideas, and more complexity to go along, so I don't want a "well it works so lets leave it alone" approach either.
Currently I simply want something close to this:
A Room object, which would have: an ID, Description, and interact-able
a Choice object (this one im not sure on) I thought about making an object to hold each rooms possible choices, both for exit, and for interact-ables
if so, the room object may need a Choice Object.
I've thought it over, tried some code, thought it over again, and every time, I keep ending up hard coding more than I feel I should, and making tons more variables than I feel are necessary, which makes me feel like i'm missing something crucial in my thinking.
I also want these rooms to be created through an inputted file, not generated in the code (so essentially the code is a story reader/crafter for any type, not one)
I have also been attempting this too long, and my solutions are becoming worse, but below was my most recent attempt at a rough Idea:
a GameManager class that takes the userInput and checks it some, before passing it along. I havent passed any data because im not sure of the approach. also im not used to regex, so some of that may also be wrong, if it is, maybe point it out, but that is not my focus
import java.util.Scanner;
public class GameManager {
private static final String EXIT_PHRASE = "exit";
public static void main(String[] args) {
Scanner userInput = new Scanner(System.in);
String userStringVal = "";
while(!userStringVal.equals(EXIT_PHRASE)){
userStringVal= userInput.nextLine();
if(checkKeywords(userStringVal)){
System.out.println("matches keyword");
}
else System.out.println("didnt match a keyword");
}
userInput.close();
}
public static boolean checkKeywords(String string){
boolean isKeyword = false;
string.toLowerCase();
if(string.matches("travel.*") || string.matches("search.*")){
System.out.println("passed first check");
String substring = string.substring(6);
if(matchDirection(substring)){
isKeyword = true;
}
}
return isKeyword;
}
public static boolean matchDirection(String string){
boolean hasDirection = false;
if(string.matches(".*\\bnorth|south|east|west|northeast|northwest|southeast| southwest|up|down")){
hasDirection = true;
}
return hasDirection;
}
}
The Room object I thought about as such:
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
public class Room {
private String roomDescription = "";
private int roomID=0;
private int northExit=0;
private int southExit=0;
private int eastExit=0;
private int westExit=0;
private int northeastExit=0;
private int northwestExit=0;
private int southeastExit=0;
private int southwestExit=0;
private int upExit=0;
private int downExit=0;
private String[] interactables = new String[10];
private Options options = new Options();
public Room(XMLStreamReader reader) throws XMLStreamException{
setAttValues(reader);
setRoomDescription(reader);
setUpOptions();
}
public void setinteractables(XMLStreamReader reader){
int count = reader.getAttributeCount();
for(int i = 0; i < count; i++){
interactables[i] = reader.getAttributeValue(i);
}
}
public void setAttValues(XMLStreamReader reader){
int count = reader.getAttributeCount();
for(int i = 0; i < count; i++){
String att = reader.getAttributeLocalName(i);
if(att !=""){
switch(att){
case "North": northExit=Integer.parseInt(att);
case "South": southExit=Integer.parseInt(att);
case "East": eastExit=Integer.parseInt(att);
case "West": westExit=Integer.parseInt(att);
case "NorthEast": northeastExit=Integer.parseInt(att);
case "NorthWest": northwestExit=Integer.parseInt(att);
case "SouthEast": southeastExit=Integer.parseInt(att);
case "SouthWest": southwestExit=Integer.parseInt(att);
case "Up": upExit=Integer.parseInt(att);
case "Down": downExit=Integer.parseInt(att);
case "ID": roomID=Integer.parseInt(att);
}
}
}
}
public void setRoomDescription(XMLStreamReader reader) throws XMLStreamException{
roomDescription = reader.getElementText();
}
public void setUpOptions(){
options.setCardinalPointers(northExit, southExit, eastExit, westExit);
options.setIntercardinalPointers(northeastExit, northwestExit, southeastExit, southwestExit);
options.setElevationPointers(upExit, downExit);
}
}
what can I do to make sure I dont have to state so many directions with so many variables?
here is a quick and rough idea of an Option class that I thought about, but i didn't finish deciding I am already too far in the wrong direction
public class Options {
private int northPointer = 0;
private int southPointer= 0;
private int eastPointer = 0;
private int westPointer = 0;
private int northeastPointer= 0;
private int northwestPointer = 0;
private int southeastPointer = 0;
private int southwestPointer = 0;
private int upPointer = 0;
private int downPointer = 0;
private String northInteractable = "";
private String southInteractable = "";
private String eastInteractable = "";
private String westInteractable = "";
private String northeastInteractable ="";
private String northwestInteractable = "";
private String southeastInteractable = "";
private String southwestInteractable = "";
private String upInteractable = "";
private String downInteractable = "";
public Options(){
}
public void setCardinalPointers(int north, int south, int east, int west){
northPointer = north;
southPointer = south;
eastPointer = east;
westPointer = west;
}
public void setIntercardinalPointers(int northeast, int northwest, int southeast, int southwest){
northeastPointer = northeast;
northwestPointer=northwest;
southeastPointer=southeast;
southwestPointer=southwest;
}
public void setElevationPointers(int up, int down){
upPointer = up;
downPointer = down;
}
public String whatToReturn(String string){
String importantPart = "";
if(string.matches("travel.*")){
String substring = string.substring(6);
}
else {
importantPart = "Interactable";
String substring = string.substring(6);
if (substring.matches("\\bnorth\\b")) {
if(northInteractable!=0){
}
}
else if (substring.matches("\\bsouth\\b"))
else if (substring.matches("\\beast\\b"))
else if (substring.matches("\\bwest\\b"))
else if (substring.contains("northeast"))
else if (substring.contains("northwest"))
else if (substring.contains("southeast"))
else if (substring.contains("southwest"))
else if (substring.contains("up"))
else if (substring.contains("down"))
}
return importantPart;
}
}
I did not see the adventure tag until after I typed this, so I will start perusing through there, but will still post this, so my apologies if there is a good answer to this and I have yet to find it.
as a recap: what would be a good way to relate a few objects to create a room object (that gets its information from a file (XML being what im used to)) having exits, descriptions, and interactions. and the user interacting with these based off keywords that can be inputted freely, and not restricted to say, index values of array's holding keywords.
Im thinking when the user types something like "travel north" to first check if they typed a keyword, in this case being travel, then a direction. Then somewhree else checking if it states travel, check north with a possible northExit a room may or may not have. Then if its another keyword, say like check, to make it easy also have the exact same directions, but check for a different string.
Then if room "northExit" exists, get an option somehow, with a pointer to another roomID. though This thought process causes me issues when thinking about future possibility of requiring items for getting to the next room. Also where to store/acquire these options is causing some difficulties.
There are two things I would like to introduce to you. The first, in the enum. You can think of this as a special kind of class where all the possible options are enumerated in the class definition. This is perfect for things like, in your case, directions. Enums can be simple, where you just list all of the possible options for use in other classes:
public enum Direction {
NORTH, NORTH_EAST, EAST, SOUTH_EAST, SOUTH, SOUTH_WEST, WEST, NOTH_WEST;
}
They can be a bit more complex, if you want them to have methods and attributes of their own:
public enum Direction {
NORTH(true), NORTH_EAST(false), EAST(true), SOUTH_EAST(false), SOUTH(true), SOUTH_WEST(false), WEST(true), NOTH_WEST(false);
private final boolean isCardinal;
private Direction(boolean isCardinal){
this.isCardinal = isCardinal;
}
public boolean isCardinal(){
return isCardinal;
}
public static Collection<Direction> getCardinalDirections(){
return Arrays.asList(Direction.values()).stream().filter(Direction::isCardinal).collect(Collectors.toList());
}
public static Collection<Direction> getIncardinalDirections(){
return Arrays.asList(Direction.values()).stream().filter(x -> !x.isCardinal()).collect(Collectors.toList());
}
}
Please read more about Java enum types here.
The second thing I would like to introduce to you is the data structure known as the Map. Maps are also known as Dictionaries, and that can often help understanding how they work. A Map will take one object and map it to another object, like how a Dictionary maps a word to its definition, or a phonebook maps a person's name to their phone number. We can simplify your Room class a ton by using a Map. I am not going to reproduce all of your code, since I'm focusing on your Room exists right now:
public class Room {
private Map<Direction, Room> exits;
public Room(){
this.exits = new HashMap<>();
}
public void setExit(Direction direction, Room room){
this.exits.put(direction, room);
}
public Room getExit(Direction direction){
return this.exits.get(direction);
}
}
Please read more about the Java Map interface here.
You will, of course, need to adapt your methods which are reading from XML, etc. But, now, your Room class should be greatly simplified.
I hope this points you in a helpful direction.
The problem I'm having is with the last line. I get an error at this section that says "cannot find symbol". This is not my entire program, only the first section.
public class Chap6Project
{
public double shooterExperiment(int dualsPerExperiment, String[] shooters, double[] accuracies, ProbabilitySupplier p)
{
shooters[0] = "aaron";
shooters[1] = "bob";
shooters[2] = "charlie";
String aaron = shooters[0];
String bob = shooters[1];
String charlie = shooters[2];
accuracies[0] = 0.33;
accuracies[1] = 0.5;
accuracies[2] = 1.0;
int duelCount = 0;
boolean aaronAlive = true;
boolean bobAlive = true;
boolean charlieAlive = true;
Chap6Project project = new Chap6Project();
ProbabilitySupplier random = new ProbabilitySupplier();
double rateOfSuccess = project.shooterExperiment(1000, shooters, accuracies, random);
while (duelCount < 1000)
{
int aaronKills = 0;
int aaronWin = 0;
double aaronAccuracy = random.getAsDouble();
if (aaronAccuracy == 0.33)
{
if (charlieAlive != true)
{
aaron.shooterExperiment(1000, bob, accuracies[1], random);
You declare the aaron variable like so:
String aaron = shooters[0];
and then try to use it like so:
aaron.shooterExperiment(1000, bob, accuracies[1], random);
and do this all within this method:
public double shooterExperiment(int dualsPerExperiment, String[] shooters,
double[] accuracies, ProbabilitySupplier p)
The aaron variable is a String and Strings have no shooterExperiment(...) method. Perhaps you meant to call this method on a different variable? Given what you've posted it's very hard to say. It looks like you're trying to call the shooterExperiment method from within itself, meaning making a recursive call, and doing so with incorrect method parameters and on the wrong object, a String object, none of which makes sense.
You'll want to clarify your problem and what your code is supposed to be doing greatly.
Other issues:
Your code suffers from the parallel array anti-pattern, a program structure that makes it very easy to create bugs. Instead create a class to encapsulate your shooter, including its name, health, accuracy, etc. and use a single collection of Shooter objects.
I have a set of incoming records, that needs to be evaluated under a set of logical clauses defined and stored. An example logical clause be like :
Acct1 != 'Y' AND Acct2 > 1004 AND Acct3 >= 96 AND Acct4 < 1004 AND Acct5 = 99 AND ((Acct6 <= 9090 OR Acct7 IN (A1,A2,A6) AND Acct1 NOT IN (A3,A4)) AND Formatted LIKE 'LINUX' AND Acct9 NOT LIKE 'WINDOWS' AND (Acct10 = 'N' AND NOT Acct11 = 'N') AND EditableField BETWEEN (10 AND 20) )
My data input to the clause be like :
map.put(Acct1,"Y")
map.put(Acct2,1010)
map.put(Acct3,99)
map.put(Acct4,1015)
map.put(Acct5,99)
map.put(Acct6,9090)
map.put(Acct7,"A3")
map.put(Formatted,"LINUX_INST")
map.put(Updated,"LINUX_TMP")
map.put(Acct10,"Y")
map.put(Acct11,"N")
map.put(EditableFIeld,25)
I have to evaluate the incoming records populated into the map onto the clause defined above and print true or false based on the evaluation result.
The clause conditions and map values will be changed and executed as well.
I have the following conditional clauses to be evaluated:
!=
>
>=
<
=
<=
IN(
NOT IN(
LIKE(
NOT LIKE(
BETWEEN(
AND
OR
AND NOT
OR NOT
I have tried using grammar generators but I am told that it is not a recommended solution for our application hence I am looking for java code and I have this detailed example for reference to AND,OR,=.
resolving logical operations - AND, OR, looping conditions dynamically and looking for snippets to build on top of that if possible.
If you want to avoid a parser generator, consider using a StreamTokenizer to implement a recursive descent parser, with one method for each grammar rule.
For a subset of your grammar, this should look roughly like this (and should be straightforward to extend to your full grammar):
public class Parser {
public static Node parse(String expr) {
StreamTokenizer tokenizer =
new StreamTokenizer(new StringReader(expr));
tokenizer.nextToken();
Parser parser = new Parser(tokenizer);
Node result = parser.parseExpression();
if (tokenizer.ttype != StreamTokenizer.TT_EOF) {
throw new RuntimeException("EOF expected, got "
+ tokenizer.ttype + "/" + tokenizer.sval);
}
private StreamTokenizer tokenizer;
private Parser(StreamTokenizer tokenizer) {
this.tokenizer = tokenizer;
}
private Node parseExpression() {
Node left = parseAnd();
if (tokenizer.ttype == StreamTokenizer.TT_WORD
&& tokenizer.sval.equals("OR")) {
tokenizer.nextToken();
return new OperationNode(OperationNode.Type.OR,
left, parseExpression());
}
return left;
}
private Node parseAnd() {
Node left = parseRelational();
if (tokenizer.ttype == StreamTokenizer.TT_WORD
&& tokenizer.sval.equals("AND")) {
tokenizer.nextToken();
return new OperationNode(OperationNode.Type.AND,
left, parseAnd());
}
return left;
}
private Node parseRelational() {
Node left = parsePrimary();
OperationNode.Type type;
switch (tokenizer.ttype) {
case '<': type = OperationNode.Type.LESS; break;
case '=': type = OperationNode.Type.EQUAL; break;
case '>': type = OperationNode.Type.GREATER; break;
default:
return left;
}
tokenizer.nextToken();
return new OperationNode(type, left, parseRelational());
}
private Node parsePrimary() {
Node result;
if (tokenizer.ttype == '(') {
tokenizer.nextToken();
result = parseExpression();
if (tokenizer.ttype != ')') {
throw new RuntimeException(") expected, got "
+ tokenizer.ttype + "/" + tokenizer.sval);
}
} else if (tokenizer.ttype == '"' || tokenizer.ttype == '\'') {
result = new LiteralNode(tokenizer.sval);
} else if (tokenizer.ttype == TT_NUMBER) {
result = new LiteralNode(tokenizer.nval);
} else if (tokenizer.ttype == StreamTokenizer.TT_WORD) {
result = new FieldNode(tokenizer.sval);
} else {
throw new RuntimeException("Unrecognized token: "
+ tokenizer.ttype + "/" + tokenizer.sval);
}
tokenizer.nextToken();
return result;
}
}
This assumes a Node object hierarchy like this:
interface Node {
Object eval(Map<String,Object> data);
}
class FieldNode implements Node {
private String name;
FieldNode(String name) {
this.name = name;
}
public Object eval(Map<String,Object> data) {
return data.get(name);
}
}
class LiteralNode implements Node {
private Object value;
FieldNode(Object value) {
this.value = value;
}
public Object eval(Map<String,Object> data) {
return value;
}
}
class OperationNode implements Node {
enum Type {
AND, OR, LESS, GREATER, EQUALS
}
private Type type;
private Node leftChild;
private Node rightChild;
OperationNode(Type type, Node leftChild, Node rightChild) {
this.type = type;
this.leftChild = leftChild;
this.rightChild = rightChild;
}
public Object eval(Map<String,Object> data) {
Object left = leftChild.eval(data);
Object right = rightChild.eval(data);
switch (type) {
case AND: return ((Boolean) left) && ((Boolean) right);
case OR: return ((Boolean) left) || ((Boolean) right);
case LESS: return ((Comparable) left).compareTo(right) < 0;
case EQUALS: return left.equals(right);
case GREATE: return ((Comparable) left).compareTo(right) > 0;
default:
throw new RuntimeException("Invalid op: " + type);
}
}
To directly answer the question, a number of SO questions (e.g. 1, 2) describe the basics of writing a parser by hand, though in practice it is very unusual to write a parser manually outside of university compiler courses due to the boilerplate and exacting detail involved.
As discussed in the comments, it sounds like the main reason to avoid grammar generators is to avoid a dependency on outside libraries. However, when using a grammar generator (parser generator) like JavaCC (Java Compiler-Compiler), there are no JAR files or outside dependencies involved: The JavaCC binary converts a grammar specification into Java code, that can be run without involving any further libraries.
See this IBM tutorial, JoAnn Brereton's "Use JavaCC to build a user friendly boolean query language" (via archive.org) as an example, which incidentally involves a grammar for a search language not unlike yours.
Example inputs:
actor = "Christopher Reeve" and keyword=action and keyword=adventure
(actor = "Christopher Reeve" and keyword=action) or keyword=romance
actor = "Christopher Reeve" and (keyword=action or keyword=romance)
Grammar excerpts:
TOKEN :
{
<STRING : (["A"-"Z", "0"-"9"])+ >
<QUOTED_STRING: "\"" (~["\""])+ "\"" >
}
void queryTerm() :
{
}
{
(<TITLE> | <ACTOR> |
<DIRECTOR> | <KEYWORD>)
( <EQUALS> | <NOTEQUAL>)
( <STRING> | <QUOTED_STRING> )
|
<LPAREN> expression() <RPAREN>
}
Output files:
UQLParser.java
UQLParserConstants.java
UQLParserTokenManager.java
TokenMgrError.java
ParseException.java
Token.java
SimpleCharStream.java
This is one of several parser generators that you can consider; others, like yacc and bison, also generate standalone Java files without requiring outside libraries. If necessary, you can check the generated Java files directly into your repository, leaving the .jj compiler source file only if you need to adjust the syntax. (Though it would probably be better to compile freshly from source as part of your build process and avoid checking generated files into source control, this may better suit your constraints of a Java-only solution.)
So, I'm doing a regular expression parser for school that creates a hierarchy of objects in charge of the matching. I decided to do it object oriented because it's easier for me to imagine an implementation of the grammar that way. So, these are my classes making up the regular expressions. It's all in Java, but I think you can follow along if you're proficient in any object oriented language.
The only operators we're required to implement is Union (+), Kleene-Star (*), Concatenation of expressions (ab or maybe (a+b)c) and of course the Parenthesis as illustrated in the example of Concatination. This is what I've implemented right now and I've got it to work like a charm with a bit of overhead in the main.
The parent class, Regexp.java
public abstract class Regexp {
//Print out the regular expression it's holding
//Used for debugging purposes
abstract public void print();
//Checks if the string matches the expression it's holding
abstract public Boolean match(String text);
//Adds a regular expression to be operated upon by the operators
abstract public void add(Regexp regexp);
/*
*To help the main with the overhead to help it decide which regexp will
*hold the other
*/
abstract public Boolean isEmpty();
}
There's the most simple regexp, Base.java, which holds a char and returns true if the string matches the char.
public class Base extends Regexp{
char c;
public Base(char c){
this.c = c;
}
public Base(){
c = null;
}
#Override
public void print() {
System.out.println(c);
}
//If the string is the char, return true
#Override
public Boolean match(String text) {
if(text.length() > 1) return false;
return text.startsWith(""+c);
}
//Not utilized, since base is only contained and cannot contain
#Override
public void add(Regexp regexp) {
}
#Override
public Boolean isEmpty() {
return c == null;
}
}
A parenthesis, Paren.java, to hold a regexp inside it. Nothing really fancy here, but illustrates how matching works.
public class Paren extends Regexp{
//Member variables: What it's holding and if it's holding something
private Regexp regexp;
Boolean empty;
//Parenthesis starts out empty
public Paren(){
empty = true;
}
//Unless you create it with something to hold
public Paren(Regexp regexp){
this.regexp = regexp;
empty = false;
}
//Print out what it's holding
#Override
public void print() {
regexp.print();
}
//Real simple; either what you're holding matches the string or it doesn't
#Override
public Boolean match(String text) {
return regexp.match(text);
}
//Pass something for it to hold, then it's not empty
#Override
public void add(Regexp regexp) {
this.regexp = regexp;
empty = false;
}
//Return if it's holding something
#Override
public Boolean isEmpty() {
return empty;
}
}
A Union.java, which is two regexps that can be matched. If one of them is matched, the whole Union is a match.
public class Union extends Regexp{
//Members
Regexp lhs;
Regexp rhs;
//Indicating if there's room to push more stuff in
private Boolean lhsEmpty;
private Boolean rhsEmpty;
public Union(){
lhsEmpty = true;
rhsEmpty = true;
}
//Can start out with something on the left side
public Union(Regexp lhs){
this.lhs = lhs;
lhsEmpty = false;
rhsEmpty = true;
}
//Or with both members set
public Union(Regexp lhs, Regexp rhs) {
this.lhs = lhs;
this.rhs = rhs;
lhsEmpty = false;
rhsEmpty = false;
}
//Some stuff to help me see the unions format when I'm debugging
#Override
public void print() {
System.out.println("(");
lhs.print();
System.out.println("union");
rhs.print();
System.out.println(")");
}
//If the string matches the left side or right side, it's a match
#Override
public Boolean match(String text) {
if(lhs.match(text) || rhs.match(text)) return true;
return false;
}
/*
*If the left side is not set, add the member there first
*If not, and right side is empty, add the member there
*If they're both full, merge it with the right side
*(This is a consequence of left-to-right parsing)
*/
#Override
public void add(Regexp regexp) {
if(lhsEmpty){
lhs = regexp;
lhsEmpty = false;
}else if(rhsEmpty){
rhs = regexp;
rhsEmpty = false;
}else{
rhs.add(regexp);
}
}
//If it's not full, it's empty
#Override
public Boolean isEmpty() {
return (lhsEmpty || rhsEmpty);
}
}
A concatenation, Concat.java, which is basically a list of regexps chained together. This one is complicated.
public class Concat extends Regexp{
/*
*The list of regexps is called product and the
*regexps inside called factors
*/
List<Regexp> product;
public Concat(){
product = new ArrayList<Regexp>();
}
public Concat(Regexp regexp){
product = new ArrayList<Regexp>();
pushRegexp(regexp);
}
public Concat(List<Regexp> product) {
this.product = product;
}
//Adding a new regexp pushes it into the list
public void pushRegexp(Regexp regexp){
product.add(regexp);
}
//Loops over and prints them
#Override
public void print() {
for(Regexp factor: product){
factor.print();
}
}
/*
*Builds up a substring approaching the input string.
*When it matches, it builds another substring from where it
*stopped. If the entire string has been pushed, it checks if
*there's an equal amount of matches and factors.
*/
#Override
public Boolean match(String text) {
ArrayList<Boolean> bools = new ArrayList<Boolean>();
int start = 0;
ListIterator<Regexp> itr = product.listIterator();
Regexp factor = itr.next();
for(int i = 0; i <= text.length(); i++){
String test = text.substring(start, i);
if(factor.match(test)){
start = i;
bools.add(true);
if(itr.hasNext())
factor = itr.next();
}
}
return (allTrue(bools) && (start == text.length()));
}
private Boolean allTrue(List<Boolean> bools){
return product.size() == bools.size();
}
#Override
public void add(Regexp regexp) {
pushRegexp(regexp);
}
#Override
public Boolean isEmpty() {
return product.isEmpty();
}
}
Again, I've gotten these to work to my satisfaction with my overhead, tokenization and all that good stuff. Now I want to introduce the Kleene-star operation. It matches on any number, even 0, of occurrences in the text. So, ba* would match b, ba, baa, baaa and so on while (ba)* would match on ba, baba, bababa and so on. Does it even look possible to extend my Regexp to this or do you see another way of solving this?
PS: There's getters, setter and all kinds of other support functions that I didn't write out, but this is mainly for you to get the point quickly of how these classes works.
You seem to be trying to use a fallback algorithm to do the parsing. That can work -- although it is easier to do with higher-order functions -- but it is far from the best way to parse regular expressions (by which I mean the things which are mathematically regular expressions, as opposed to the panoply of parsing languages implemented by "regular expression" libraries in various languages).
It's not the best way because the parsing time is not linear in the size of the string to be matched; in fact, it can be exponential. But to understand that, it's important to understand why your current implementation has a problem.
Consider the fairly simple regular expression (ab+a)(bb+a). That can match exactly four strings: abbb, aba, abb, aa. All of those strings start with a, so your concatenation algorithm will match the first concatenand ((ab+a)) at position 1, and proceed to try the second concatenand (bb+a). That will successfully match abb and aa, but it will fail on aba and abbb.
Now, suppose you modified the concatenation function to select the longest matching substring rather than the shortest one. In that case, the first subexpression would match ab in three of the possible strings (all but aa), and the match would fail in the case of abb.
In short, when you are matching a concatenation R·S, you need to do something like this:
Find some initial string which matches R
See if S matches the rest of the text
If not, repeat with another initial string which matches R
In the case of full regular expression matches, it doesn't matter which order we list matches for R, but usually we're trying to find the longest substring which matches a regular expression, so it is convenient to enumerate the possible matches from longest to shortest.
Doing that means that we need to be able to restart a match after a downstream failure, to find the "next match". That's not terribly complicated, but it definitely complicates the interface, because all of the compound regular expression operators need to "pass through" the failure to their children in order to find the next alternative. That is, the operator R+S might first find something which matches R. If asked for the next possibility, it first has to ask R if there is another string which it could match, before moving on to S. (And that's passing over the question of how to get + to list the matches in order by length.)
With such an implementation, it's easy to see how to implement the Kleene star (R*), and it is also easy to see why it can take exponential time. One possible implementation:
First, match as many R as possible.
If asked for another match: ask the last R for another match
If there are no more possibilities, drop the last R from the list, and ask what is now the last R for another match
If none of that worked, propose the empty string as a match
Fail
(This can be simplified with recursion: Match an R, then match an R*. For the next match, first try the next R*; failing that try the next R and the first following R*; when all else fails, try the empty string.)
Implementing that is an interesting programming exercise, so I encourage you to continue. But be aware that there are better algorithms. You might want to read Russ Cox's interesting essays on regular expression matching.
I am writing a program in Processing that transforms complex numbers. However, I want to have a method of taking an input string and calculating the transformation using a complex variable. For example:
1/(z+1)
(z^2)/(z/2)
where z is a complex number. Now, I've looked at JEP and some examples, but I cannot work out if it would allow you to actually enter z as a variable (and in any case it is not free). Is there an expression parser for Java (that works in processing, which uses an old version of java and does not have generics) that I could use to do this?
If there is not, could someone point me to the basics of how to create one?
As mentioned by PhiLo, you can use generics. Try this Processing sketch:
import java.util.*;
java.util.List<String> list = Arrays.asList("a", "b", "c");
textFont(loadFont("UMingCN-30.vlw"));
for(int i = 0; i < list.size(); i++) {
text(list.get(i), 5, int(i*30)+30);
}
And there's a non commercial version of JEP available (GPL). Download it here and add it to your Processing classpath (import it).
After successfully doing so, you can use JEP like this:
void setup() {
org.nfunk.jep.JEP parser = new org.nfunk.jep.JEP();
parser.addComplex();
try {
parser.parseExpression("(1+2*i) + (3+8*i)");
println(parser.getComplexValue());
} catch(Exception e) {
e.printStackTrace();
}
}
which produces the (expected) output: (4.0, 10.0)
Have a look at this: http://bracer.sourceforge.net It's my implementation of shunting-yard algorithm and this parser supports complex numbers.
Use Apache Common Math. It is very easy to use.
You can initialize both real+imaginary parts. You can also initialize them from a string. It supports a wide array of operations that you can do with imaginary numbers.
Here is a example of code for doing some common operations:
package complex;
import static java.lang.String.format;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.math3.complex.Complex;
import org.apache.commons.math3.complex.ComplexFormat;
public class Do
{
public static void main(String[] args)
{
ComplexFormat format = new ComplexFormat();
Complex lhs = new Complex(1.0, 3.0);
Complex rhs = new Complex(2.0, 5.0);
Complex answer = lhs.add(rhs); // add two complex numbers
System.out.println("Add : "+ format.format(answer));
answer = lhs.subtract(rhs); // subtract two complex numbers
System.out.println("Subtract : "+ format.format(answer));
answer = lhs.conjugate();
System.out.println("Conjgate : "+ format.format(answer));
double d = lhs.abs();
System.out.println("Absolute : "+d);
Complex first = new Complex(1.0, 3.0);
Complex second = new Complex(2.0, 5.0);
answer = first.log(); // natural logarithm.
System.out.println("Logarithm : "+ format.format(answer));
answer = first.cos(); // cosine
System.out.println("Cosine : "+ format.format(answer));
answer = first.pow(second); // first raised to the power of second
System.out.println("Power : "+ format.format(answer));
Complex z = new Complex(2.0,2.0);
Complex z1 = z.reciprocal();
System.out.println("Recipocal : "+ format.format(z1));
System.out.println("Absoltue of 2+2i is "+z.abs());
System.out.println("Argument of 2+2i is "+z.getArgument());
Complex r = new Complex(6.3,9.6);
String conj = format.format(r.conjugate());
String reci = format.format(r.reciprocal());
System.out.println("Conjugate : "+conj+" Recipocal : "+reci);
//answer = lhs.abs(); // absolute value
//answer = lhs.conjugate(rhs); // complex conjugate
//make complex to string
ComplexFormat format = new ComplexFormat(); // default format
Complex c = new Complex(1.1111, 2.2222);
String s = format.format(c); // s contains "1.11 + 2.22i"
System.out.println(s);
//make string to complex
String z = "2.5+3.6i";
Complex e = format.parse(z);
System.out.println(e);
}
}
Another alternative is FrAid, if you want another option.
If for some reason you need more flexibility than the "canned" complex math expression parsers suggested so far (= full control over operators, precedence, tree construction), you may want to consider my configurable parser:
https://github.com/stefanhaustein/expressionparser
Example direct evaluation code for your case:
static HashMap<String, Complex> variables = new HashMap<>();
/**
* Processes the calls from the parser directly to a Complex value.
*/
static class ComplexProcessor extends ExpressionParser.Processor<Complex> {
#Override
public Complex infixOperator(ExpressionParser.Tokenizer tokenizer, String name, Complex left, Complex right) {
switch (name.charAt(0)) {
case '+': return left.plus(right);
case '-': return left.minus(right);
case '*': return left.times(right);
case '/': return left.divides(right);
case '^':
if (right.im() != 0 || right.re() == (int) right.re()) {
return left.pow((int) right.re());
}
throw new RuntimeException("Only integer exponents supported by Complex.pow().");
default:
throw new IllegalArgumentException();
}
}
#Override
public Complex prefixOperator(ExpressionParser.Tokenizer tokenizer, String name, Complex argument) {
return name.equals("-") ? new Complex(0,0).minus(argument) : argument;
}
#Override
public Complex numberLiteral(ExpressionParser.Tokenizer tokenizer, String value) {
return new Complex(Double.parseDouble(value), 0);
}
#Override
public Complex identifier(ExpressionParser.Tokenizer tokenizer, String name) {
Complex value = variables.get(name);
if (value == null) {
throw new IllegalArgumentException("Undeclared variable: " + name);
}
return value;
}
#Override
public Complex group(ExpressionParser.Tokenizer tokenizer, String paren, List<Complex> elements) {
return elements.get(0);
}
/**
* Creates a parser for this processor with matching operations and precedences set up.
*/
static ExpressionParser<Complex> createParser() {
ExpressionParser<Complex> parser = new ExpressionParser<Complex>(new ComplexProcessor());
parser.addCallBrackets("(", ",", ")");
parser.addGroupBrackets("(", null, ")");
parser.addOperators(ExpressionParser.OperatorType.INFIX_RTL, 4, "^");
parser.addOperators(ExpressionParser.OperatorType.PREFIX, 3, "+", "-");
// 2 Reserved for implicit multiplication
parser.addOperators(ExpressionParser.OperatorType.INFIX, 1, "*", "/");
parser.addOperators(ExpressionParser.OperatorType.INFIX, 0, "+", "-");
return parser;
}
}
Example invocation:
variables.put("i", new Complex(0, 1));
variables.put("z", new Complex(1, 1));
ExpressionParser<Complex> parser = ComplexProcessor.createParser();
System.out.println("(z^2)/(z/2):", parser.parse("(z^2)/(z/2)"));
The parser itself is implemented in a single java file without dependencies, so for evaluation purposes it's simple to copy to your own project
I would (and have, actually) manually make a parse table and use a simple LR or LALR parser to process it. At a reduction, you can perform the calculations. One advantage to this is that it is easy to modify the "language", or acceptable input.
Here's crazy solution: java has built-in JavaScript engine (I suppose you can access it from Processing). Now, you write a javascript class that works with complex numbers(copy it from here). Then, overload math operators as specified here. AFter that you can just eval this string from java. It's crazy and I'm not sure that it will work (i don't know javascript). Maybe it will make to find some simplier solution without parsing expressions.
Here is a link to a straight-forward math expression parser (64 lines): http://javadots.blogspot.com/2008/11/arithemetic-expressions-solver-in-64.html
Tweaking it to support your needs should not be too difficult