I am trying to make a text based game in which you have different levels of different aspects of life and other variables. I'm trying to save them to some sort of file so I can get them back later.
So far, this is what I have with the variables:
public class baseLevels {
public boolean gameOver = false;
//100 is a normal level
public int happyLevel = 100;
public int sleepLevel = 100;
public int angerLevel = 100;
public int healthLevel = 100;
public int popularityLevel = 100;
public int smartLevel = 100;
public int weight = 100;
//0 = Single 1 = Not very close, but dating 2 = close and dating 3 = engaged 4 = married
public int relationshipStatus = 0;
public boolean children = false;
public int numberOfChildren = 0;
//Tests if the player is injured, 1-5 on severeness
public boolean injured = false;
public int severity = 1;
public boolean healthCare = false;
//Money status: 1 is poor, 5 is rich
public int money = 5000;
public int wealthStatus = 1;
//Family is alive or dead
public boolean momDead = false;
public boolean dadDead = false;
public boolean sisterDead = false;
public boolean brotherDead = false;
public boolean grandmaDead = false;
public boolean grandpaDead = false;
//Misc. variables
public boolean car = false;
public boolean house = false;
public boolean dead = false;
public boolean likeMusic = false;
}
After looking at the property method someone posted, I like it, but I need a way to set a property value as a number. When I try this, I get an error saying I can't have a string and an integer.
java.util.Properties is probably the best class for something simple like this. It has built-in methods for loading from a file and saving to a file.
Properties props = new Properties();
props.load(new FileInputStream("data.props"));
String someProp = props.getProperty("myName");
props.setProperty("myName", "John Smith");
props.store(new PrintWriter("data.props"));
One option is to use object serialization.
To use serialization your class must implement the Serializable interface.
Suppose you have an instance of your class baseLevels that you want to write to a file, "save.dat":
baseLevels obj = new baseLevels();
Using object serialization you would first create an object output stream to your save file: "save.dat".
ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream( "save.dat" ) );
To write your baseLevels instance, obj, to the file you would invoke writeObject( obj ):
out.writeObject( obj );
Always remember to close the stream:
out.close();
To restore the object to the state it was in when you wrote it to the save file, you would use an object input stream:
ObjectInputStream in = new ObjectInputStream( new FileInputStream( "save.dat" ) );
And invoke method readObject() which reads the next object from the input stream. The return type of readObject() is Object so we need to cast it to the appropriate type; in this example we have only written one object and we know that it is of type baseLevels thus we can safely cast the returned object to baseLevels:
baseLevels obj = (baseLevels)in.readObject().
close the stream:
in.close();
Complete example(Assumes that baseLevels implements Serializable):
// Initialize
String fileName = "save.dat";
baseLevels lvl1 = new baseLevels();
// Set level attributes
lvl1.angerLevel = 0;
lvl1.happyLevel = 200;
// Write level
try( ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream( fileName ) ) ) {
out.writeObject( lvl1 );
}
catch( IOException e ) {
System.err.println( e.getMessage() );
}
// Read level
baseLevels lvl2;
try( ObjectInputStream in = new ObjectInputStream( new FileInputStream( fileName ) ) ) {
lvl2 = (baseLevels)in.readObject();
}
catch( IOException e ) {
System.err.println( e.getMessage() );
}
catch( ClassNotFoundException e ) {
System.err.println( "Class definition could not be found" );
System.err.println( e.getMessage() );
}
For more information on serialization you should look at: http://docs.oracle.com/javase/tutorial/essential/io/objectstreams.html.
The example linked to from the above site - because it is easy to miss if you only skim the site: http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/essential/io/examples/ObjectStreams.java )
As far as a Game Development concerned in java its best approach to user MVC
also you might be using all of the classes and variables differently like you mentioned
100 is a normal level
0 = Single 1 = Not very close, but dating 2 = close and dating 3 = engaged 4 = married
Tests if the player is injured, 1-5 on severeness
Money status: 1 is poor, 5 is rich
and to use them you will need some getters and setters in your classes so its better approach if you use Beans and a separate package for all of the beans with different Bean classes.
javadoc and
Collections inorder to use and map you data with objects
Saving Variables in game
Related
I Want to create test that gets every time (in a loop) different customer number and make some operations on him and after that take the 2nd customer number and etc.
Therefore I create data.properties file containing the next data :
customernumber1=500054237
customernumber2=500054238
customernumber3=500054235
I decelerate the variable
customernumber = getObject("customernumber");
my getObject method
public static String getObject(String Data) throws IOException
{
loadData();
String data = properties.getProperty(Data);
return data;
}
I have this code :
for (int i = 1; i < 3 ; i++ )
{
bo.textfield().sendKeys("customers");
Thread.sleep(1000);
bo.customers().click();
Thread.sleep(1000);
bo.opencustomers().click();
Thread.sleep(1000);
bo.customerid().sendKeys(customernumber + i);
But the result of this is a : "null1", in the 1st run.
How can I call every time the customer number I have in the properties file ?
I think I need to call the property name and not the property value - is this is true ? and if so how can I make it ?
Thanks.
Issue:
The main culprit here is that you are passing "customernumber" in the getObject method, which doesn't exist in the property file.
customernumber = getObject("customernumber");
You can see there is no such thing as "customernumber"
//Actual Property file data:
customernumber1=500054237
customernumber2=500054238
customernumber3=500054235
Also, you are passing (customernumber + i), which has not much effect, as it will only add null1, null2 or so on, as per your current code. bo.customerid().sendKeys(customernumber + i);
One more thing, the loop should be i<=3 instead of i<3
for (int i = 1; i < 3 ; i++ )
{
bo.textfield().sendKeys("customers");
Thread.sleep(1000);
bo.customers().click();
Thread.sleep(1000);
bo.opencustomers().click();
Thread.sleep(1000);
bo.customerid().sendKeys(customernumber + i);
Output:
Solution:
Inside your for loop, plz initilize your String customernumber = getObject("customernumber"+i); and pass "i" dynamic variable to get dynamic data.
public static void main(String[] args) throws IOException {
for (int i = 1; i <= 3 ; i++ ) {
String customernumber = getObject("customernumber"+i);
System.out.println(customernumber);
bo.textfield().sendKeys("customers");
Thread.sleep(1000);
bo.customers().click();
Thread.sleep(1000);
bo.opencustomers().click();
Thread.sleep(1000);
bo.customerid().sendKeys(customernumber);
}
}
public static String getObject(String Data) throws IOException
{
System.out.println(Data);
Properties properties = loadData();
String data = properties.getProperty(Data);
return data;
}
public static Properties loadData() throws IOException {
Properties prop = new Properties();
FileInputStream fn = new FileInputStream(new File("{YOUR-PATH}"));
prop.load(fn);
return prop;
}
Output:
Best Approach: is to use Dataprovider with exce and to pass the data to Dataproviders by reading the data from excel sheet. DataProvider helps to send multiple sets of data to a test method
Ref: https://www.seleniumeasy.com/testng-tutorials/import-data-from-excel-and-pass-to-data-provider
I want to write clean code in java and I am very insecure where to place my attriutes.
I often cannot decide, if I place them on top of the class, in a constructor or directly in the method. Are there some rules out there? The only logic one for me is, to place attributes on top of the class when these attributes are used in more than one method.
Can you evaluate this code in terms of clean code? Should I place the constant currency attributes in the constructor? Can I also put some of the class attributes in a method? Thanks for the advice
public class CsvFileReader {
private SimpleDateFormatStringToDate formatter = new SimpleDateFormatStringToDate();
private IataExchangeRateDataSet exchangeRateDataSet= new IataExchangeRateDataSet();
private final String SEMICOLON_DELIMITER = ";";
// Currency attributes index
private final int CURRENCY_VALUE = 1;
private final int CURRENCY_ISO_CODE = 2;
private final int CURRENCY_PERIOD_START = 3;
private final int CURRENCY_PERIOD_END = 4;
public CsvFileReader(IataExchangeRateDataSet exchangeRateDataSet) {
this.exchangeRateDataSet = exchangeRateDataSet;
}
public void readCsvFile(String fileName, final int maxLengthOfColumn) {
BufferedReader fileReader = null;
try {
String line = "";
fileReader = new BufferedReader(new FileReader(fileName));
while ((line = fileReader.readLine()) != null) {
String[] tokens = line.split(SEMICOLON_DELIMITER);
//TODO: Noch auf Vollständigkeit der Zeile, Korrektheit der Datumsformate und ähnliches überprüfen
if ( tokens.length== maxLengthOfColumn && DateFormat.checkDateFormat(tokens[CURRENCY_PERIOD_START]) && DateFormat.checkDateFormat(tokens[CURRENCY_PERIOD_END])) {
//format currency value in csv
tokens[CURRENCY_VALUE]=tokens[CURRENCY_VALUE].replace(",", ".");
IataExchangeRateData iataExchangeRateData = new IataExchangeRateData(
new BigDecimal(tokens[CURRENCY_VALUE]), tokens[CURRENCY_ISO_CODE],
formatter.parseStringToDate(tokens[CURRENCY_PERIOD_START]),
formatter.parseStringToDate(tokens[CURRENCY_PERIOD_END]));
exchangeRateDataSet.getExchangeRateDataSet().add(iataExchangeRateData);
}
}
}
catch (Exception e) {
System.out.println("Error in CsvFileReader");
e.printStackTrace();
} finally {
try {
fileReader.close();
} catch (IOException e) {
System.out.println("Error while closing fileReader !!!");
e.printStackTrace();
}
}
}
}
If any attribute is used for calculation or manipulation inside a method then use that attribute inside only the method.
If any attribute is being used such that any method can refer it then use it at the top of all the methods.
If any attribute does not depend on the class specifically like counting the number of threads of a particular object then use it as a class variable by making it static.
clean code questions usually spark off arguments, some right and others not so right. But I have felt the way you do now about constants and I have used them just the way you did in your code i.e. right above the constructor. But more recently, I put them in an interface. Something a little like this
public interface CurrencyConstants {
int CURRENCY_VALUE = 1;
int CURRENCY_ISO_CODE = 2;
int CURRENCY_PERIOD_START = 3;
int CURRENCY_PERIOD_END = 4;
}
Then I simply import the interface and use the constants like so..
CurrencyConstants.CURRENCY_VALUE
This helps if the constants are used in more than one class. Cheers!
I am having a big problem with this, now I have a class called FileRelationship, and I have two constructors with it. Class is shown below. I also overrode the equals method in this class.
public class FileRelationship {
String fileName;
String firstLink;
String secondLink;
String thirdLink;
public FileRelationship(String fileName) {
this.fileName = fileName;
}
public FileRelationship(String fileName, String firstLink, String secondLink, String thirdLink) {
this.fileName = fileName;
this.firstLink = firstLink;
this.secondLink = secondLink;
this.thirdLink = thirdLink;
}
public boolean equals(Object o) {
if(o == null) {
return false;
}
if(this == o) {
return true;
}
if(o instanceof FileRelationship) {
return this.fileName.equals(((FileRelationship)o).fileName);
}
return false;
}
}
Now I have an arrayList of FileRelationships and I want to be able to search through this list (These all use the constructor with 4 Strings in it (fileName, firstLink, secondLink, thirdLink)) Now I have a method in another class that is supposed to search this arrayList and this find the index of one that has a matching fileName. When I call this method I am only passing into the constructor with the fileName and that is all. (This is the only I can do it, I will not know the other strings).
This is how I set up the ArrayList of FileRelationships.
fileRelationships = new ArrayList<FileRelationship>();
String MasterLine;
InputStream inputStream = this.getResources().openRawResource(R.raw.masterfile);
InputStreamReader inputreader = new InputStreamReader(inputStream);
BufferedReader buffreader = new BufferedReader(inputreader);
// Creates the arrayList of all the relationships for later use of retreival.
try {
while (( MasterLine = buffreader.readLine()) != null) {
MasterLineArray = MasterLine.split(",");
String filename = MasterLineArray[0];
String choice1 = MasterLineArray[1];
String choice2 = MasterLineArray[2];
String choice3 = MasterLineArray[3];
FileRelationship fr = new FileRelationship(filename, choice1, choice2, choice3);
fileRelationships.add(fr);
}
} catch (IOException e) {
} finally {
closeQuietly(buffreader);
}
This is my method for finding the relationship and then setting it to the variable I need. I want to be able to find the index of the list and apply it to the variable.
public void findRelationship(String nextFileName) {
int pageIndex = fileRelationships.indexOf((new FileRelationship(nextFileName)));
selectedRelationship = fileRelationships.get(pageIndex);
currentPage = pageIndex;
}
EDIT : I'm sorry forgot to say what was wrong. No it doesn't work. pageIndex is returning a -1 (So in other words it isn't finding anything). I don't know what else to do, maybe use HashCode but honestly I've even looked up stuff about it and I can't really figure out how to use that either.
I really really need help on this, as this is for a school project due soon. I have most of the project done as once I get this part finished I should be almost done. Thanks.
Search like this
public void findRelationship(String nextFileName) {
for(FileRelationship file:fileRelationships)
{
if(file.firsFileName.equals(nextFileName))
{
currentPage=fileRelationships.indexOf(file);
}
}
}
list returns -1 when list doesn't contain that object. In your case you where using indexOf() obj by creating new object
int pageIndex = fileRelationships.indexOf((new FileRelationship(nextFileName)));
this is not the right way. because you are creating new object and list does not contains new object
And also make getter setter method for each fields in FileRelationship class directly accessing each field is not the good practice
Say the user runs SomeProgram.java to calculate a bunch of stuff. One of the things they want to keep track of is how many times this program has been run and output the current run number. This is how far I got but it resets each time.
public class SomeProgram
{
public volatile int counter = 1;
public int getNextRun()
{
return counter++;
}
//calculates a bunch of variable that get output to user
public static void main(String args[])
{
SomeProgram variable = new SomeProgram();
runNumber = variable.getNextRun();
System.out.println(runNumber + "Some bunch of calculations");
}
}
Can someone explain why this got downvoted?
Whenever the user stops running your program, you're going to lose any variables stored in memory, so you're going to have to store that value somewhere else. The easiest solution would be to store it in a local file.
If your business needs to know this number, you can have the program call home to a webserver every time it starts up - this prevents the user from modifying the file on their computer - but is far more complicated to set up, and some users might not appreciate this unexpected behavior.
Complete implementation which stores updated counter in a file, invoke it whenever you want a counter to increment (i.e. when program starts). When a file doesn't exist, it is created. This method returns updated counter or 0 if there was some IOException.
public static int updateCounter() {
String counterFileName = "counter.txt";
int counter = 0;
File counterFile = new File(counterFileName);
if (counterFile.isFile()) {
try (BufferedReader reader = new BufferedReader(new FileReader(counterFileName))) {
counter = Integer.parseInt(reader.readLine());
} catch (IOException e) {
e.printStackTrace();
return 0;
}
}
try (FileWriter writer = new FileWriter(counterFileName)) {
writer.write(String.valueOf(++counter));
} catch (IOException e) {
e.printStackTrace();
return 0;
}
return counter;
}
Writing to the local file is not a good idea. You'll have to implement locking mechanism on your local file, otherwise you'll suffer of race conditions in case of simultaneous start of several program instances.
Alternative idea is to log each run into a persistent storage. So if you write each run's date and time to the db, you'll be able to calculate number of runs for arbitrary time interval.
Actual implementation depends on your requirements
You can use a Properties file:
public void loadProperties(String fileName)
{
Properties props = new Properties();
InputStream is = null;
// First try loading from the current directory
try {
File f = new File(fileName);
is = new FileInputStream( f );
}catch ( Exception e ) {
is = null;
e.printStackTrace();
}
try {
if ( is == null ) {
// Try loading from classpath
is = getClass().getResourceAsStream("example.properties");
}
// Try loading properties from the file (if found)
props.load( is );
String counter1 = props.getProperty("COUNTER_RUN");
String counter2 = props.getProperty("COUNTER_OUTPUT");
counterRun = Integer.parseInt(counter1);
counterOutput = = Integer.parseInt(counter2);
}catch ( Exception e ) {
e.printStackTrace();
}
}
public void saveProperties(String fileName) {
try {
Properties props = new Properties();
props.setProperty("COUNTER_RUN", ""+counterRun );
props.setProperty("COUNTER_OUTPUT", ""+counterOutput );
File f = new File(fileName);
OutputStream out = new FileOutputStream( f );
props.store(out, "Config params");
} catch (Exception e ) { e.printStackTrace(); }
}
counterRun and counterOutput are global vars
File example.properties
#Config paramns
#Tue May 03 14:17:35 COT 2016
COUNTER_RUN=241
COUNTER_OUTPUT=123
I was trying to write a mapper class for a practice program and the compiler always gives me error that:
satMath and satVerbal might not have been initialized.
public class UniversityMapper extends Mapper <LongWritable,Text,Text,IntWritable> {
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// TODO convert record (value) to String
StringTokenizer iterator = new StringTokenizer (value.toString(),")" );
int state = 2;
int satVerbal;
int satMath;
while(state != 0 && iterator.hasMoreTokens())
{
String cur = iterator.nextToken();
if (cur.contains("sat verbal"))
{
state--;
StringTokenizer temp = new StringTokenizer(cur,"\\s+");
temp.nextToken();
temp.nextToken();
int satV = (new Integer(temp.nextToken())).intValue();
satVerbal = satV;
//context.write(new Text("satv"), new IntWritable(satVerbal));
}
else if (cur.contains("sat math"))
{
state--;
StringTokenizer temp = new StringTokenizer(cur,"\\s+");
temp.nextToken();
temp.nextToken();
int satM = (new Integer(temp.nextToken())).intValue();
satMath = satM;
//context.write(new Text("satm"), new IntWritable(satMath));
}
}
if (state == 0)
{
System.out.println(satVerbal);
System.out.println(satMath);
context.write(new Text ("satv"), new IntWritable(satVerbal));
context.write(new Text ("satm"), new IntWritable(satMath));
}
} }
If I reposition the context.write() method within the scope of the if statements (commented out in the code) I no longer get this error. I cannot understand why. I usually code in c++ and python I am really new to Java and I need to finish this program. Can somebody help me with this, thanks in advance :)
This is fairly straightforward. If this else if does't execute:
else if (cur.contains("sat math"))
Then you never initialize satMath, and you try to access it later via:
context.write(new Text ("satm"), new IntWritable(satMath));
Same goes with if (cur.contains("sat verbal")) and satVerbal.
If you wish to avoid these altogether you could just initialize + declare those variables yourself:
int satVerbal = 0;
int satMath = 0;
But you should be absolutely certain that they will be assigned something else inside your while, otherwise you will actually use their initialized values (0) later in your context.write, which I assume isn't desirable for you.