Java exercise for checkout - java

I'm trying some Java recently and look for some review of my style. If You like to look at this exercise placed in the image, and tell me if my style is good enought? Or maybe it is not good enought, so You can tell me on what aspect I should work more, so You can help me to improve it?
exercise for my question
/*
* File: MathQuiz.java
*
* This program produces Math Quiz.
*/
import acm.program.*;
import acm.util.*;
public class MathQuiz extends ConsoleProgram {
/* Class constants for Quiz settings. */
private static final int CHANCES = 3;
private static final int QUESTIONS = 5;
private static final int MIN = 0;
private static final int MAX = 20;
/* Start program. Number of questions to ask is assigned here. */
public void run() {
println("Welcome to Math Quiz");
while(answered != QUESTIONS) {
produceNumbers();
askForAnswer();
}
println("End of program.");
}
/* Ask for answer, and check them. Number of chances includes
* first one, where user is asked for reply. */
private void askForAnswer() {
int answer = -1;
if(type)
answer = readInt("What is " + x + "+" + y + "?");
else
answer = readInt("What is " + x + "-" + y + "?");
for(int i = 1; i < CHANCES+1; i++) {
if(answer != solution) {
if(i == CHANCES) {
println("No. The answer is " + solution + ".");
break;
}
answer = readInt("That's incorrect - try a different answer: ");
} else {
println("That's the answer!");
break;
}
}
answered++;
}
/* Produces type and two numbers until they qualify. */
private void produceNumbers() {
produceType();
produceFirst();
produceSecond();
if(type)
while(x+y >= MAX) {
produceFirst();
produceSecond();
}
else
while(x-y <= MIN) {
produceFirst();
produceSecond();
}
calculateSolution();
}
/* Calculates equation solution. */
private void calculateSolution() {
if(type) solution = x + y;
else solution = x - y;
}
/* Type of the equation. True is from plus, false is for minus. */
private void produceType() {
type = rgen.nextBoolean();
}
/* Produces first number. */
private void produceFirst() {
x = rgen.nextInt(0, 20);
}
/* Produces second number. */
private void produceSecond() {
y = rgen.nextInt(0, 20);
}
/* Class variables for numbers and type of the equation. */
private static boolean type;
private static int x;
private static int y;
/* Class variables for equation solution. */
private static int solution;
/* Class variable counting number of answered equations,
* so if it reaches number of provided questions, it ends */
private static int answered = 0;
/* Random generator constructor. */
RandomGenerator rgen = new RandomGenerator();
}

One thing I noticed was that all of your methods take no parameters and return void.
I think it would be clearer if you use method parameters and return values to show the flow of data through your program instead of using the object's state to store everything.

There are a few things you should do differently, and a couple you could do differently.
The things you should do differently:
Keep all fields together.
static fields should always be in THIS_FORM
you've used the static modifier for what clearly look like instance fields. (type,x,y,solution, answered). This means you can only ever run one MathsQuiz at a time per JVM. Not a big deal in this case, but will cause problems for more complex programs.
produceFirst and produceSecond use hardcoded parameters to nextInt rather than using MAX and MIN as provided by the class
There is no apparent need for answered to be a field. It could easily be a local variable in run.
Things you should do differently:
There is a small possibility (however tiny), that produceNumbers might not end. Instead of producing two random numbers and hoping they work. Produce one random number and then constrain the second so that a solution will always be formed. eg. say we are doing and addition and x is 6 and max is 20. We know that y cannot be larger than 14. So instead of trying nextInt(0,20), you could do nextInt(0,14) and be assured that you would get a feasible question.
For loop isn't really the right construct for askForAnswer as the desired behaviour is to ask for an answer CHANCES number of times or until a correct answer is received, whichever comes first. A for loop is usually used when you wish to do something a set number of times. Indeed the while loop in run is a good candidate for a for loop. A sample while loop might look like:
int i = 1;
boolean correct = (solution == readInt("What is " + x + "+" + y + "?"));
while (i < CHANCES && !correct) {
correct = (solution == readInt("Wrong, try again."));
i++;
}
if (correct) {
println("Well done!");
} else {
println("Nope, the answer is: "+solution);
}

Looks like a very clean program style. I would move all variables to the top instead of having some at the bottom, but other than that it is very readable.

Here is something I'd improve: the boolean type that is used to indicate whether we have an addition or subtraction:
private void produceType() {
type = rgen.nextBoolean();
}
produceType tells, that something is generated and I'd expect something to be returned. And I'd define enums to represent the type of the quiz. Here's my suggestion:
private QuizType produceType() {
boolean type = rgen.nextBoolean();
if (type == true)
return QuizType.PLUS;
else
return QuizType.MINUS;
}
The enum is defined like this:
public enum QuizType { PLUS, MINUS }

Almost good I have only a few improvements:
variables moves to the top
Inside produceNumbers and your while you have small repeat. I recommend refactor this
Small advice: Code should be like books - easy readable - in your run() method firstly you call produceNumber and then askForAnswer. So it will be better if in your code you will have the same order in definitions, so implementation askForAnswer before produceNumber. But it isn't necessary
Pay attention to have small methods. A method shouldn't have much to do - I think that askForAnswer you could split to two methods

Related

Java - How shorten if statements using lambda expressions?

First of all, I'm aware that there is a similar questions like this. The answer to that question, however, did not help me.
I have the following code:
boolean result = fields[x][y + 1].getRing().getPlayer() == player || fields[x][y - 1].getRing().getPlayer() == player || fields[x + 1][y].getRing().getPlayer() == player || fields[x - 1][y].getRing().getPlayer() == player
The code is supposed to check if there are any rings of the current player above, under or next to the current field.
I'm trying to make this code more readable by using a lambda expression, but I can't get it right. I'm not sure whether this is even possible, though.
I tried to replace fields[x][y] by a variable field and then have field become fields[x][y+1], fields[x][y-1], fields[x+1][y], fields[x-1][y]
boolean result = field.getRing().getPlayer() == player -> field = {fields[x][y+1], fields[x][y-1], fields[x+1][y], fields[x-1][y]};
But this gives me a syntax error, which I expected, since field = {fields[x][y+1], fields[x][y-1], fields[x+1][y], fields[x-1][y]}; sets field to an array, and does not iterate over that array.
Is there any way I can make this code shorter using lambda expression?
You keep repeating the same condition, on 4 different values. So what you want in fact is to avoid this repetition, and write the condition once. And you want to test if any of the 4 values match the condition. So start by storing the 4 values in a collection:
List<Field> neighbors = Arrays.asList(fields[x + 1][y],
fields[x - 1][y],
fields[x][y + 1],
fields[x][y - 1]);
Then test if any of those values match the condition:
boolean result = neighbors.stream().anyMatch(field -> field.getRing().getPlayer() == player);
This doesn't necessarily make the code faster or shorter, but it makes it more readable, and DRY.
I don't think lambdas will help here. What I think is better is just to introduce some methods so that the code is more readable.
For example, you could make four methods ringAbove, ringBelow, ringRight and ringLeft and that would make the code a little more readable.
boolean result = ringAbove(x,y) || ringBelow(x,y) || ringRight(x,y) || ringLeft(x,y);
Now just implement each method, with a bit of refactoring:
private boolean ringAbove( int x, int y ) {
return ringAt( x+1, y);
}
The other three methods can be implemented similarly.
I don't really understand this code, but lets just assume it works. player will need to be available as a global variable, or you'll need to also pass it as a parameter.
private boolean ringAt( int x, int y ) {
if( x < 0 || y < 0 || x >= fields.length || y >= fields[x].length )
return false;
return fields[x][y].getRing().getPlayer() == player;
}
Here is another "tiny embedded domain specific language" for
dealing with positions and fields. It makes use of Java8 Streams and lambdas.
The method neighborhood
abstracts the idea of the shape of a discrete geometric neighborhood, so
that is becomes very easy to deal with all kind of neighborhoods on the
grid, for example with something like this:
# ### # #
#x# #x# # #
# ### x
# #
# #
You wanted the first case, but in the code below, it would be very easy to
replace the concept of "neighborhood" by the 8-cell neighborhood (second case), or by something even weirder, like for example the allowed moves of a knight in chess (third case).
The method neighboringFields makes use of the stream of the purely geometric positions, performs some additional checks on it (to ensure that you don't leave the game universe), and then enumerates all the fields with their content.
You can then use these streams of fields to quickly check various predicates on them, for example using the allMatch and anyMatch methods, as is shown in the very last method checkRingsInNeighborhood,
so that the unwieldy if-expression collapses to just this:
return neighboringFields(pos).anyMatch(
field -> field.getRing().getPlayer() == player
);
Here is the full code snippet:
import java.util.function.*;
import java.util.stream.*;
class NeighborPositions {
// Mock up implementations of `Ring`, `Player`, and `Position`,
// whatever those things are
public static class Ring {
private Player player;
public Ring(Player player) {
this.player = player;
}
public Player getPlayer() {
return this.player;
}
}
public static class Player {
private final String name;
public Player(String name) {
this.name = name;
}
}
public static class Field {
private final Ring ring;
public Field(Ring ring) {
this.ring = ring;
}
public Ring getRing() {
return this.ring;
}
}
// you probably want to fill it somehow...
public static int DIM_X = 100;
public static int DIM_Y = 42;
public static Field[][] fields = null;
/** Position on a rectangular grid */
public static class Position {
final int x;
final int y;
public Position(int x, int y) {
this.x = x;
this.y = y;
}
}
/** Shortcut for accessing fields at a given position */
public static Field field(Position p) {
return fields[p.x][p.y];
}
/** Generates stream of neighboring positions */
public static Stream<Position> neighborhood(Position pos) {
return Stream.of(
new Position(pos.x + 1, pos.y),
new Position(pos.x - 1, pos.y),
new Position(pos.x, pos.y + 1),
new Position(pos.x, pos.y - 1)
);
}
/** Generates stream of neighboring fields */
public static Stream<Field> neighboringFields(Position pos) {
return neighborhood(pos).
filter(p -> p.x >= 0 && p.x < DIM_X && p.y >= 0 && p.y < DIM_Y).
map(p -> field(p));
}
/** This is the piece of code that you've tried to implement */
public static boolean checkRingsInNeighborhood(Position pos, Player player) {
return neighboringFields(pos).anyMatch(
field -> field.getRing().getPlayer() == player
);
}
}
You obviously shouldn't try to cram everything into a single file and declare it public static, it's just an example.
You could create a BiFunction<Integer, Integer, Player> that, given x and y coordinates, returns a Player:
BiFunction<Integer, Integer, Player> fun = (coordX, coordY) ->
fields[coordX][coordY].getRing().getPlayer();
Now, to check whether a given player's ring is above, under or next to a given pair of coordinates, you could use:
boolean result = List.of(
fun.apply(x, y - 1),
fun.apply(x, y + 1),
fun.apply(x - 1, y),
fun.apply(x + 1, y))
.contains(player);
This uses Java 9's List.of. If you are not in Java 9 yet, just use Arrays.asList.
Besides, it also uses the List.contains method, which checks if a given object belongs to the list by means of the Objects.equals method, which in turn uses the equals method (taking care of nulls). If Player doesn't override equals, then identity equality == will be used as a fallback.

Problems with calling a method using an array

I'm relevantly new to Java and just started my first semi serious assignment. I'm confident most of my code is working, the only problem is because I've been using classes I can't seem to call a method which uses an array into my main class. Every other method I want to call seems to work. I wonder if anyone has any explanation or easy solution to this?
Thanks in advance for taking time looking into, really appreciate it!
import java.util.Scanner;
public class GeographyQuizMain
{
public static void main(String[] args)
{
takeQuiz();
}
public static void takeQuiz(Question[][] questions)
{
int score = 0;
RandomNumber randomQuestion = new RandomNumber();
//user chooses catergory
int cat = pickCatergory();
//ask 10 questions
for(int i = 0; i < 10;)
{
Scanner answerChoice = new Scanner(System.in);
randomQuestion.dice();
int q = (randomQuestion.dice() - 1);
//checks to see if question as been asked before
if (!questions[cat][q].beenAsked)
{
questions[cat][q].beenAsked = true; //changes question status to beenAsked
System.out.println(questions[cat][q].promt);
String answer = answerChoice.nextLine();
System.out.println("\nYou picked: " + answer + "\nThe correct answer was: " + questions[cat][q].answer + "\n");
if(answer.equals(questions[cat][q].answer))
{
score++;
}
i++;
}
}
System.out.println("That is the end of the quiz!\n"
+ "You got " + score + "/10");
}
Your problem is with the call itself,
This line public static void takeQuiz(Question[][] questions) states that the method will accept a two dimensional array ([][]) of an object named Question.
On the other hand, your call - takeQuiz(); passes no array of such.
You should initialise an array of such to make this compile and pass it to the function. i.e.
Question[][] questionArray = GenerateQuestionArray(); //you should write this method
takeQuiz(questionArray);
Like you stated, it's clearly you're new to Java and I strongly suggest you to read the instructions and the information provided to you in class about that. I bet the details of Object initialisation, methods and arrays are covered there.
It seems that problem with your method call, in your method takeQuiz(); is taking 2 dimensional array for questions but at the calling time you are not providing that parameter so, compiler not able to found the method.
That's the problem.
try to use like this, this is simple an example for you. replace this with your actual values.
String[][] questions= new String[3][3];
takeQuiz(questions);
this will work.
You have called your method takeQuiz() without actually supplying its arguments Question[][] questions

Calculate Dice Roll from Text Field

QUESTION:
How can I read the string "d6+2-d4" so that each d# will randomly generate a number within the parameter of the dice roll?
CLARIFIER:
I want to read a string and have it so when a d# appears, it will randomly generate a number such as to simulate a dice roll. Then, add up all the rolls and numbers to get a total. Much like how Roll20 does with their /roll command for an example. If !clarifying {lstThen.add("look at the Roll20 and play with the /roll command to understand it")} else if !understandStill {lstThen.add("I do not know what to say, someone else could try explaining it better...")}
Info:
I was making a Java program for Dungeons and Dragons, only to find that I have come across a problem in figuring out how to calculate the user input: I do not know how to evaluate a string such as this.
I theorize that I may need Java's eval at the end. I do know what I want to happen/have a theory on how to execute (this is more so PseudoCode than Java):
Random rand = new Random();
int i = 0;
String toEval;
String char;
String roll = txtField.getText();
while (i<roll.length) {
check if character at i position is a d, then highlight the numbers
after d until it comes to a special character/!aNumber
// so if d was found before 100, it will then highlight 100 and stop
// if the character is a symbol or the end of the string
if d appears {
char = rand.nextInt(#);
i + #'s of places;
// so when i++ occurs, it will move past whatever d# was in case
// d# was something like d100, d12, or d5291
} else {
char = roll.length[i];
}
toEval = toEval + char;
i++;
}
perform evaluation method on toEval to get a resulting number
list.add(roll + " = " + evaluated toEval);
EDIT:
With weston's help, I have honed in on what is likely needed, using a splitter with an array, it can detect certain symbols and add it into a list. However, it is my fault for not clarifying on what else was needed. The pseudocode above doesn't helpfully so this is what else I need to figure out.
roll.split("(+-/*^)");
As this part is what is also tripping me up. Should I make splits where there are numbers too? So an equation like:
String[] numbers = roll.split("(+-/*^)");
String[] symbols = roll.split("1234567890d")
// Rough idea for long way
loop statement {
loop to check for parentheses {
set operation to be done first
}
if symbol {
loop for symbol check {
perform operations
}}} // ending this since it looks like a bad way to do it...
// Better idea, originally thought up today (5/11/15)
int val[];
int re = 1;
loop {
if (list[i].containsIgnoreCase(d)) {
val[]=list[i].splitIgnoreCase("d");
list[i] = 0;
while (re <= val[0]) {
list[i] = list[i] + (rand.nextInt(val[1]) + 1);
re++;
}
}
}
// then create a string out of list[]/numbers[] and put together with
// symbols[] and use Java's evaluator for the String
wenton had it, it just seemed like it wasn't doing it for me (until I realised I wasn't specific on what I wanted) so basically to update, the string I want evaluated is (I know it's a little unorthodox, but it's to make a point; I also hope this clarifies even further of what is needed to make it work):
(3d12^d2-2)+d4(2*d4/d2)
From reading this, you may see the spots that I do not know how to perform very well... But that is why I am asking all you lovely, smart programmers out there! I hope I asked this clearly enough and thank you for your time :3
The trick with any programming problem is to break it up and write a method for each part, so below I have a method for rolling one dice, which is called by the one for rolling many.
private Random rand = new Random();
/**
* #param roll can be a multipart roll which is run and added up. e.g. d6+2-d4
*/
public int multiPartRoll(String roll) {
String[] parts = roll.split("(?=[+-])"); //split by +-, keeping them
int total = 0;
for (String partOfRoll : parts) { //roll each dice specified
total += singleRoll(partOfRoll);
}
return total;
}
/**
* #param roll can be fixed value, examples -1, +2, 15 or a dice to roll
* d6, +d20 -d100
*/
public int singleRoll(String roll) {
int di = roll.indexOf('d');
if (di == -1) //case where has no 'd'
return Integer.parseInt(roll);
int diceSize = Integer.parseInt(roll.substring(di + 1)); //value of string after 'd'
int result = rand.nextInt(diceSize) + 1; //roll the dice
if (roll.startsWith("-")) //negate if nessasary
result = -result;
return result;
}

how to use if-else statement in accessor?

this is part of my program. I have to be sure that the amount of gas does not exceed the top gas capacity. I do not know how to write the else part? I ask the user to enter the current gas and it should be less or equal 30.
private final int GAS_CAP = 30
public int getGasCapacity(int gasCapacity)
{
if(currentGas <= GAS_CAP)
{
gasCapacity = GAS_CAP - currentGas;
}
else gasCapacity = currentGas;
return gasCapacity;
}
private final int GAS_CAP = 30
public int getGasCapacity()
{
int gasCapacity;
if(currentGas <= GAS_CAP)
{
gasCapacity = GAS_CAP - currentGas;
} else {
gasCapacity = 0;
}
return gasCapacity;
}
Your else statement was wrong, and there shouldn't be a parameter.
You could also easily accomplish this with one line, but I'm not sure if you know how to use ternary syntax.
Can made in one line as,
public int getGasCapacity(){
return (currentGas <= GAS_CAP ? (GAS_CAP - currentGas) : 0 );
}
First thing, you should make your question a little more clear because I don't really understand what you're trying to do. I'm going to write you what I think you're trying to achieve and you tell me if it's okay or comment what was wrong in the answer.
private final GAZ_LIMIT = 30;
public int ObserveGazCapacity(int gazCapacity)
{
if(gazCapacity<=GAZ_LIMIT)
{
gazCapacity-=GAZ_LIMIT;
}else{
gazCapacity=0; //in case higher than limit, capacity will be at the maximum value permitted
}
return gazCapacity;
}
Hopes that what you're looking for !

Calculating math in GPS format

I'm making a Android Application to calculate Math in GPS Format.
Example:
Given
N 48°44.(30x4) E 019°08.[(13x31)+16]
the App calculates it, and result is:
N 48°44.120 E 019°08.419
Is it possible to do this?
I searched for plugins and solutions, but it's all just for math strings like as "14 + 6".
I am assuming you are working in Java as it is tagged in your question.
You could create a new public class for your GPS coordinates, and store the actual value of the coordinate in the lowest division, which according to your example appears to be minutes or seconds. This allows you to store the value as an int or a double with whatever precision you wish. You could then create a set of private and public methods to complete your mathematical operations and others to display your values in the appropriate fashion:
public class GPSCoordinate {
private double verticalcoord;
private double horizontalcoord;
//Constructors
GPSCoordinate(){
setVertical(0);
setHorizontal(0);
}
GPSCoordinate(double vert, double horiz){
setVertical(vert);
setHorizontal(horiz);
}
//Display methods
public String verticalString(){
return ((int)verticalcoord / 60) + "°" + (verticalcoord - ((int)verticalcoord / 60) *60);
}
public String horizontalString(){
return ((int)horizontalcoord / 60) + "°" + (horizontalcoord - ((int)horizontalcoord / 60) *60);
}
//Setting Methods
public void setVertical(double x){
this.verticalcoord = x;
}
public void setHorizontal(double x){
this.horizontalcoord = x;
}
//Math Methods
public void addMinutesVertical(double x){
this.verticalcoord += x;
}
}
This will allow you to initiate an instance in your main code with a given GPS coordinate, and then you can call your math functions on it.
GPSCoordinate coord1 = new GPSCoordinate(567.23, 245);
coord1.addMinutesVertical(50);
coord1.otherMathFunction(50 * 30);
You will, of course, need to refine the above to make it fit your project. If this isn't helpful, please provide more specifics and I'll see if I can think of anything else that might fit what your looking for.
Can't you just substring the whole thing and search for the expression in the brackets? Then it's just a matter of simple calculation. If I understood the question correctly. The gps data doesn't look like an ordinary expression, so you can't appy math() directly.

Categories

Resources