Pie chart using graphics 2d having trouble using arrays [duplicate] - java

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 7 years ago.
import javax.swing.*;
public class Main {
public static void main(String[] args) throws FileNotFoundException {
File file = new File(args[0]);
Scanner input = new Scanner(file);
int i = 0;
String names[] = null;
int slices[] = {};
while (input.hasNext()) {
names[i] = input.next();
slices[i] = input.nextInt();
i++;
}
JFrame f = new JFrame("Pie chart");
f.setSize(600, 350);
f.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
f.add(new PieChart());
f.setVisible(true);
}
}
Here is my second file...
import java.awt.*;
import javax.swing.*;
public class PieChart
extends JComponent {
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
Graphics2D g3 = (Graphics2D) g.create();
g3.setColor(Color.BLACK);
g2.setColor(Color.BLUE);
for (int i = 0; i < 5; i = i + 1) {
g2.fillRect(230, 20 * i + 50 , 20, 20);
g3.drawString("swallow", 255, 20 * i + 65);
g3.drawString("37.0%", 385, 20 * i + 65);
}
g2.fillArc(50, 50, 150, 150, 0, 360);
}
}
I am trying to read from a text file into two separate arrays. I want one array to hold the names and then one to hold the values. I then want to be able to then access the values from the array from my second file. My current problem is that it isn't accepting the input.next(); into the arrays for names[] and slices[]. How can I fix this?
Here is a sample text file:
swallow 10
magpie 5
fairywren 7
osprey 2
fantail 3

My current problem is that it isn't accepting the input.next(); into the arrays for names[] and slices[]. How can I fix this?
while (input.hasNext()) { should probably be while (input.hasNextLine()) {
You may then need to use input.nextLine() to get the actually text and use a second Scanner to parse the individual line
I am trying to read from a text file into two separate arrays. I want one array to hold the names and then one to hold the values. I then want to be able to then access the values from the array from my second file.
You should be passing the arrays to your PieChart class, maybe via the constructor.
You should also be calling super.paintComponent before doing any custom painting
It is giving me a NullPointerException error and it says it's on line 16 which is "names[i] = input.next();"
names is never initialised (is null)...
String names[] = null;
int slices[] = {};
Arrays are not dynamic, so unless you know in advance how many lines there are, it's not particular easy to manager.
In you case, assuming that the file doesn't change, you could use something like...
String names[] = new String[5];
int slices[] = new int[5];
Another choice would be to use a List of some kind or a Map, which are dynamic, so you don't need to know how many elements you might need before hand.
See Collections Trail for more details

String names[] = null;
You need to assign a non-null array to name before you can assign values to its elements; otherwise you will get the NullPointerException you observe.
However, you don't know how many elements you are going to need, so you should use a resizable data structure like an ArrayList.
Had you assigned {} to names like you did for slices, you'd get an ArrayIndexOutOfBoundsException, because it has no elements, but you are trying to assign a value to the zeroth one.

You should use an array if you know before you start adding items what the size of it will be (e.g. it will have 20 indices). Here, it seems that you don't know until runtime. So an array would not be the best data structure for this. Consider an array list instead.
ArrayList<String> names = new ArrayList()<String>;
while(...){
names.add(input.nextLine());
}
System.out.print(names.get(3)) //prints the 4th name

Related

How do you make variables made inside a method available to all other methods in a class?

I'm a coding newb and want to learn some more java. I'm currently taking an introductory programming course in high school and am just trying to play around outside of class. This program I'm creating is supposed to print out a few instructions and questions in the console, to which I want to retrieve user input using a scanner and variable. The goal of the program is for the user to be able to create a 'drawing' based on pure instinct, then this drawing is displayed after the fact.
Here's my problem. I'm asking the user and storing the information in variables that are native to the main method, but I need to use this information in the paintComponent method.
I tried adding static in front of the variable such as:
static int emptyRectW1 = kboard.nextInt(); but this just shows the error "Illegal modifier for parametic emptyRectW1; only final is permitted."
I knew it was a long shot trying that out, but that's the best I've got.
I'm using Java Eclipse as my IDE.
Thanks for any help, looks like the only way to learn is to mess up and have somebody else point out my mistake! :)
Here's the code:
import java.util.Scanner;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BlindDrawing extends JPanel {
public static void main (String[] args) {
Scanner kboard = new Scanner(System.in);
System.out.println("Welcome to the Blind Drawing Game!");
System.out.println("In this game, you will be asked questions about how to construct an image using rectangles and ovals. You will be asked the shape's dimensions and position. The origin (0,0) is the top left corner.");
System.out.println("First you're making an empty rectangle, how wide do you want it to be?");
int emptyRectW1 = kboard.nextInt();
System.out.println("What about the height?");
int emptyRectH1 = kboard.nextInt();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0,0,emptyRectW1, emptyRectH1);
}
}
Update: In the comments an example was requested, so here's a simple one. This is just a simple demonstration of the ideas I talk about; it does not build on the above code. The reason is that, as others have noted, there are additional things you'd want to correct about the structure of that code. Rather than try to address them in detail, or give an example that encourages them, I'll just focus on the points I was making in my original answer:
public class SampleObject {
private int aValue;
protected void getVAlue() {
Scanner kboard = new Scanner(System.in);
System.out.println("Enter a value:");
aValue = kboard.nextInt();
}
protected void printValue() {
System.out.println("The value is " + aValue);
}
public void processValue() {
System.out.println("Welcome");
getValue();
printValue();
}
public static void main(String[] args) {
SampleObject sampleObject = new SampleObject();
sampleObject.processValue();
}
}
Some styles would have the main method in a separate "application class"; some frameworks have such a thing, wich might have responsibilities like handling outside messages requesting the app shut down, or whatver.
And generally as your applications get beyond simple exercises, you'll want to have more than just one class/object - each with distinct responsibilities that make up your application's functionality.
But for now, this should show how instance data woriks, and how to bootstrap a collection of objects rather than doing lots of processing in a static main method.
Good luck!
As a general answer to the question: variables defined inside a method are not available to other methods, and this is by design of the language. (Some advanced features twist this rule a little, but not in the way you want; and those things are a bit down the road from where you are anyway.)
To share state among methods, you add data members (sometimes called fields) to the class itself. Then values can be assigned in one method and read in another, or whatever, throughout the class.
However, as soon as you try to use that advice you're going to run into another problem, because main() is (and must be) static and your other method isn't (and probably shouldn't be). So you're going to do one of two things to fix that - the easy thing, or the right thing.
The easy thing would be to add static data members - making the data belong to the class rather than an instance of the object. The non-static methods could still see those. But this is leading you in the wrong direction.
The right thing is to do nothing more than bootstrap your application in the main method. What this means is, create object instances that can collaborate to carry out your program's function, and then set those objects in motion. Then all the actual work - like prompting for user input, etc. - should happen in (generally non-static) methods of those objects.
It's a very surface explanation, but really this isn't the place for an in-depth programming lesson. If your curiosity is getting ahead of the coursework, there certainly are good tutorials for OO programming and Java online (or at your local book store... though I may be dating myself with that suggestion).
Good luck.
The simple answer: pass the information obtained in the main method into the BlindDrawing object via either a method or a constructor's parameters.
But having said that you really don't want to mix a linear console type application with an event driven GUI app. Choose one or the other and stick with it. Here you can get the information you need via JOptionPanes if you need to get them before launching the main GUI application, and then again pass them into the main GUI application as described above -- via constructor parameters.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.*;
public class BlindDrawing extends JPanel {
private Rectangle rectangle;
public BlindDrawing(Rectangle rectangle) {
setPreferredSize(new Dimension(1000, 800));
this.rectangle = rectangle;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (rectangle != null) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
g2.draw(rectangle);
}
}
private static void createAndShowGui(Rectangle rect) {
BlindDrawing mainPanel = new BlindDrawing(rect);
JFrame frame = new JFrame("BlindDrawing");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
String message = "Enter 4 numbers for X, Y, Width, and Height, separated by a space";
String title = "Get Rectangle Coordinates";
int messageType = JOptionPane.PLAIN_MESSAGE;
String input = JOptionPane.showInputDialog(null, message, title, messageType);
String[] tokens = input.split("\\s+");
if (tokens.length == 4) {
int x = Integer.parseInt(tokens[0]);
int y = Integer.parseInt(tokens[1]);
int width = Integer.parseInt(tokens[2]);
int height = Integer.parseInt(tokens[3]);
Rectangle rect = new Rectangle(x, y, width, height);
SwingUtilities.invokeLater(() -> createAndShowGui(rect));
}
}
}
EDIT
You asked in comments:
What I don't understand are the ones towards the bottom that have tokens. I don't really understand what these tokens do, if you could clarify, that would be great!
The question for me is: how can we most easily allow the user to enter for ints to use in a Swing application, but to sub-divide this even further we can ask for solutions that are most easy for the coder and solutions that are most easy for the user. In general you will want to prefer going after the latter.
The easiest for the coder is to create a simple console application and have the user enter the numbers using String prompts and a Scanner object that has been initialized to the standard input or System.in. As I've mentioned, while this is easy for the coder, it does not work well for the user since console applications and GUI applications don't play nice together as one is structured in a linear fashion while the other is much more free-flowing and event driven. If you want to get data later on while the program runs, and you again have the user enter information through the console, you risk either freezing the Swing application, rendering it useless, or updating the Swing application inappropriately in a background thread.
My solution above is a compromise where we prompt the user for a single String by using a JOptionPane.showInputDialog(...). This will give the user a prompt, and allow him to enter a single String into a text field. Here I ask the user to enter four numbrers separated, each separated by a space, and I think that you understand this part, but one problem with it is, once you get that String, which I call input, how do you extract the four numbers out of it.
One way is to split the String into an array of Strings (which I call tokens) using String's split(...) method. A simple way to do this is like so:
String[] tokens = input.split(" ");
This will split the input String into an array of sub-strings by splitting on a single space. It doesn't work so well if the user accidentally uses more than one space between his numbers, or if he uses different "white-space" to separate the numbers. I instead used:
String[] tokens = input.split("\\s+");
This uses something called regular expressions or "regex" for short to split the String. \\s represents any white-space character, and the + means that we'll split on one or more white-space characters. So if the user puts 2 or 3 spaces between his numbers, this still will work.
Another possible way to split this String is to put it into a Scanner and then "scan" for ints. Here we don't Scan with the standard input, with System.in, but rather we scan the entered String, here input. For example:
// get our line of input same as we did before
String input = JOptionPane.showInputDialog(null, message, title, messageType);
// create a Scanner object that scans through the line
Scanner inputScanner = new Scanner(input);
// extract the four numbers from the line
int x = inputScanner.nextInt();
int y = inputScanner.nextInt();
int width = inputScanner.nextInt();
int height = inputScanner.nextInt();
// close the Scanner so we don't waste resources
inputScanner.close();
There are still problems with this since all these solutions fail if the user enters 2 or 3 numbers and not 4, or if the user enters non-numeric input, and there are other ways of checking for this and correcting, such as using a JSpinner or JComboBox that limits the user's selections to allowed numbers, or by using try/catch blocks to catch invalid input and then prompt the user for more correct input.
You can initialize them as instance variables so they can be used by various other methods, like so:
public class BlindDrawing extends JPanel {
private int emptyRectW1;
private int emptyRectH1;
public static void main (String[] args) {
new BlindDrawing().run();
}
private void run() {
Scanner kboard = new Scanner(System.in);
System.out.println("Welcome to the Blind Drawing Game!");
System.out.println("In this game, you will be asked questions about how to construct an image using rectangles and ovals. You will be asked the shape's dimensions and position. The origin (0,0) is the top left corner.");
System.out.println("First you're making an empty rectangle, how wide do you want it to be?");
emptyRectW1 = kboard.nextInt();
System.out.println("What about the height?");
emptyRectH1 = kboard.nextInt();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0, 0, emptyRectW1, emptyRectH1);
}
}
Actually, a variable declared inside a method is a local variable.
Please extend the scope of the the two variables just before your main method. See code below.
static int emptyRectW1, emptyRectH1;
public static void main (String[] args) {
Then manipulate the latter code to avoid duplicate variable declaration as shown below.
emptyRectW1 = kboard.nextInt();
System.out.println("What about the height?");
emptyRectH1 = kboard.nextInt();
I hope this helps.

I need to make a reference to a JLabel based off a string

So I have numbered JLabels declared like so (In the class)
OP_1
OP_2
OP_3
etc..
And I have a number and a string.
What I want is that when, for example, the number is 2. I want to change the label text to the content of the string. This is part of a method that is supposed to take a string, put it into the last available JLabel, and then increment the number.
I am very confused, and help would be appreciated.
Here I created an array of JLabels and a method, updateNextLabel(String), which will update the next JLabel with whatever you enter for str.
public class Example {
static int count = 0; //Create a count
static JLabel[] array = new JLabel[3]; //Create an array to hold all three JLabels
public static void main(String[] args) {
//Set the default text for each JLabel
array[0] = new JLabel("This is OP1");
array[1] = new JLabel("This is OP2");
array[2] = new JLabel("This is OP3");
//Here is an example if you wanted to use a for-loop to update the JLabels
for (int x = 0; x < array.length; x++) {
updateNextLabel("This is the new text for OP" + (count + 1));
System.out.println(array[x].getText());
}
}
public static void updateNextLabel(String str) {
array[count].setText(str);
count++;
}
}
Instead of / additional to naming your labels by specific names you can later match them on, I'd think a Map of JLabels with Strings or Integers as keys might be a better approach:
Map<String,JLabel> labelMap = new HashMap<String,JLabel>();
labelMap.put("1", OP_1);
labelMap.put("2", OP_2);
This will allow later access of "The label for key 2" as well as "list me all that labels and find the one with text 2" as well

Fill ArrayList with colors for Android

I want to create 2 ArrayList. One holding 16 colors, the other one holding 139.
I have the list with colors (both RGB as 255,126,32 and Hex as 0xFFFF2552). I want to use the ArrayList to later pick random colors from.
I've tried int[], that doesn't work. I've tried ArrayList<Integer> and ArrayList<Color>. My problem is; I don't understand how to add the colors to the ArrayLists.
Thanks!!
For now, I'm exploring this:
Color cBlue = new Color(0,0,255);
Color cRed = new Color(255,0,0);
ArrayList colors = new ArrayList();
colors.add(cBlue);
colors.add(cRed);
and so on...
I really like int[] colors = = new int[] {4,5}; because it's only one line of code... but how do I get colors in, to later on, pick from?
or.. would it be better to store the colors in a strings.xml file and then fill the ArrayList from there? If so, how should I do that?
Thanks!!
You could try:
int[] colors = new int[] {Color.rgb(1,1,1), Color.rgb(...)};
For example, but I don't think it's a good idea to decide only using "one line" argument.
List<Integer> coloras = Arrays.asList(new Integer[]{Color.rgb(1, 1, 1), Color.rgb(...)});
Will also work.
You can create an arraylist in arrays.xml file:
<resources>
<string-array name="colors">
<item>#ff0000</item>
<item>#00ff00</item>
<item>#0000ff</item>
</string-array>
</resources>
Then use the loop to read them:
String[] colorsTxt = getApplicationContext().getResources().getStringArray(R.array.colors);
List<Integer> colors = new ArrayList<Integer>();
for (int i = 0; i < colorsTxt.length; i++) {
int newColor = Color.parseColor(colorsTxt[i]);
colors.add(newColor);
}
In my opinion keeping colors in the list is the most convinient solution.
To take a color from the list randomly, you do:
int rand = new Random().nextInt(colors.size());
Integer color = colors.get(rand);
I would make a text file or xml file populated with the color info and have a function that reads in each line of the file using a loop, creates a Color object for each line and adds it to the array list and then goes to the next line until there are no lines left.
I would recommend against using a configuration file unless you want to be able to change your colors without code changes. I suspect your colors are constant though, so the file would just add unnecessary complexity to your application.
The code sample in your question assumes java.awt.Color when you would actually use the utility class android.graphics.Color which cannot be instantiated.
Therefore I recommend the following solution as a static variable (and be careful not to modify the contents of the array later):
static final int[] colors16 = {
Color.rgb(255, 0, 0),
Color.rgb(0, 255, 0),
Color.rgb(0, 0, 255)
};
Now add a static instance of Random to use for selecting random colors from the list.
static final Random random = new Random();
And then pick your color!
int colorIndex = random.nextInt(colors16.size());
Color color = colors16.get(colorIndex);
If you feel it's important to protect the contents of your list, you can make it immutable as follows, at the small expense of boxing your color ints into Integer objects.
static final List<Integer> colors = Collections.unmodifiableList(
Arrays.asList(
Integer.valueOf(Color.rgb(255, 0, 0)),
Integer.valueOf(Color.rgb(0, 255, 0)),
Integer.valueOf(Color.rgb(0, 0, 255))
)
);
Technically you can leave out the Integer.valueOf() conversion in the above snippet and Java will autobox the ints.
You can also can use int[] colors = new int[]{color1.getRGB(),color2.getRGB()};
And decode using: Color color = new Color(colors[0]);
What you have looks like it makes sense, but you should specify the type of the ArrayList.
List<Color> colorList = new ArrayList<Color>();
colorList.add(cBlue);
... etc
(The difference between declaring it as a List or an ArrayList is that List is the interface that ArrayList implements. This is a generally pretty good practice, but for your purposes it probably won't make a difference if you declare it as a List or an ArrayList).
If you want to do it in fewer lines of code, you can use an ArrayList initializer block, like this:
List<Color> colorList = new ArrayList<Color> { new Color(...), cBlue };
Or with Arrays.asList, which takes in an array and returns a List.
But in general you should get used to verbosity with Java, don't try to optimize your lines of code so much as the performance of those lines.
(Sidenote: make sure you're using the correct Color class. There's android.graphics.Color and java.awt.Color, and they're totally different, incompatible types. The constructor you're using is from java.awt.Color, and with Android you're probably going to want to use android.graphics.Color).

creating new array when adding/deleting elements?

Good Evening. I am working on a program thats similar to the old game LiteBrite, where you place colored pegs on a panel and it lights up. In my program, it works similar in that when you click on the panel, it will create a new Ellipse (which ive named ColorEllipse that has specifications for location, size, and color) and that it will store it to be saved. Currently it is as an arraylist but i need it to be in a regular array. I am told the way that would be to make a new array, and copy all the contents of the old array into the new array. Now currently i use an arraylist, but unforutnately this program has specifications where we need to use a regular Array.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.lang.reflect.Array;
import java.util.ArrayList;
public class LiteBritePanel extends javax.swing.JPanel{
private final static int OFFSET = 5;
private static int LINE_WIDTH = 2;
private static int CELL_WIDTH = 25;
public ArrayList <Colorable> _circles; // where ColorEllipses will be stored
private ButtonPanel controlpanel; // used to set the color of peg that will be placed
public LiteBritePanel() {
this.setBackground(java.awt.Color.black);
_circles = new ArrayList<Colorable>();
controlpanel = new ButtonPanel(this);
this.addMouseListener(new MyMouseListener(this));
this.add(controlpanel);
}
public void paintComponent(java.awt.Graphics aPaintBrush) {
super.paintComponent(aPaintBrush);
java.awt.Graphics2D pen = (java.awt.Graphics2D) aPaintBrush;
java.awt.Color savedColor = pen.getColor();
pen.setColor(java.awt.Color.black);
for (int ball=0;ball<_circles.size();ball++)
if(_circles.get(ball).isEmpty())
return;
else
_circles.get(ball).fill(pen);
pen.setColor(savedColor);
this.repaint();
}
public void mouseClicked(java.awt.event.MouseEvent e){
boolean foundSquare = false;
for (int ball=0; ball < _circles.size() && !foundSquare; ball++){
if (_circles.get(ball).contains(e.getPoint()) == true){
foundSquare = true;
_circles.remove(ball);
this.repaint();
}
}
}
private class MyMouseListener extends java.awt.event.MouseAdapter {
private LiteBritePanel _this;
public MyMouseListener(LiteBritePanel apanel){
_this = apanel;
}
public void mouseClicked(java.awt.event.MouseEvent e){
_circles.add(new ColorEllipse(controlpanel.getColor(), e.getPoint().x - (e.getPoint().x%CELL_WIDTH), e.getPoint().y - (e.getPoint().y%CELL_WIDTH), CELL_WIDTH-3,_this));
_this.requestFocus();
boolean foundSquare = false;
for (int ball=0; ball < _circles.size() && !foundSquare; ball++){
if (_circles.get(ball).contains(e.getPoint()) == true){
foundSquare = true;
// code for removing ball if one is placed
_this.repaint();
}
}
}
}
}`
Now currently it is set as an Arraylist, but I need it to be in a regular array per this specification. then when the panel is clicked on, it adds a new ColorEllipse into that Array at that specific location (and repaints as necessary for it to show up). A later part of the program would be when i touch a peg thats already placed, it removes it, but thats for another time. right now I need to know how to increment sizes of the array and copy its contents into it. Would anyone be able to tell me what I should change?
To copy arrays, you could use the System.arraycopy(...) method (System API):
public static void arraycopy(
Object src,
int srcPos,
Object dest,
int destPos,
int length)
where you would first create a destination array, perhaps twice as big as the the source array, and pass the old array, the starting index (0), the new array, the destination starting index (0), the length (length of old array), and it should do the rest.
Also you don't want to call repaint inside of paintComponent, trust me. Use a Swing Timer instead. There's a good tutorial on this that Google can help you find.
Depending on how big your board is you can just create an array that has the same size as your board. Alternatively you can do as Hovercraft suggested but it all depends on whether you want to trade cpu for memory.
int MAX_POSSIBLE_ELEMENTS = ...
Colorable[] _circles = new Colorable[MAX_POSSIBLE_ELEMENTS];
....rest of code...
Notice that the maximum number depends on the height and width of the board so you should know this at compiletime.

Java TicTacToe Game

I'm working on my assignment which is to create a TicTacToe checker, and for some reason I'm unable to think of a way to do the first steps of creating the game. We read in from a text file that contains a line which represents one game; for example:
x,x,o, , ,x, ,o,o
That would look like this on a traditional board:
x|x|o
-----
| |x
-----
|o|o
Here's what I have so far:
class TicTacToe{
static String[][] game;
public TicTacToe(int size){
this.game = new String[size][size];
}
public static TicTacToe create(String input){
String tokens = input.split(",");
int size = (int)Math.sqrt(tokens.length); //For setting a size
// of the board
return null;
}
}
What I don't understand is how to return a new TicTacToe object: when I write my methods for checking rows, columns, etc. how will I get the board to check on? Am I going about this the right way?
[W]hen I write my methods for checking rows, columns, etc. how will I
get the board to check on?
The instance of your object should contain all of the information about the board. You have this (mostly) done already - game is the field which contains the information about the board. The only catch is that every board will contain the same board information, and if it's updated, it will contain the updated information.
If you want to treat this like a factory, then there are four things that you'll want to do:
Remove the static modifier from game. It's unnecessary and will lead to inconsistent states across multiple objects.
Make your constructor private - unless I'm missing something, there's no reason to initialize it outside of the factory.
private TicTacToe(int size) {
game = new String[size][size];
}
Or, better yet:
private TicTacToe(String[][] hydratedBoard) {
game = hydratedBoard;
}
I'll show you why in a moment.
Implement TicTacToe.create(String), and return the fully hydrated object. A suggestion would be to create the String[][] implicitly, create the object with that passed in as an argument to the constructor, and return your TicTacToe object.
public static TicTacToe create(String input) {
String[][] board = new String[3][3];
int i = 0; // count the row we're on
String[] tokens = input.split(",");
for(int j = 0; j < board.length; j++) {
if (j % 3 == 0) { // advanced to the end of the column set (SO)
i++;
}
board[i][j] = tokens[i*3 + j];
}
return new TicTacToe(board);
}
Provide some sort of getter to the board object. You might not have to do this per the assignment, but it's good practice. It could be either a straight-up getter on the String[][], or some sort of pretty-print representation; I don't know. I'll leave this implementation to the reader instead.
You're overthinking it. Rather than "return null;", use "return new TicTacToe(size);".
Although, usually when I create a static factory method (like your "create" method) I make the constructor private so it can only be called from the static create method.
...and then you will need to update the board if you want to actually remember the x/o positions you passed in...
Here I added an integration test for this game that might give you some ideas of how to create/think about the game.
public void testWinnerPlayerIWithVerticalLine() {
this.displayUnitTestDescription("Integration Test for having player 'X' as winner on a vertical line use case");
final IBoardGame<TicTacToeMove, TicTacToePlayer> ticTacTocGame = new TicTacToeGame();
final String playerIDisplayName = "X";
final String playerIIDisplayName = "O";
final TicTacToePlayer playerI = new TicTacToePlayer(playerIDisplayName);
final TicTacToePlayer playerII = new TicTacToePlayer(playerIIDisplayName);
ticTacTocGame.setGamePlayers(new TicTacToePlayer[]{playerI, playerII});
TicTacToePlayer[][] expectedBoardInteractionSnapshot = new TicTacToePlayer[][]{
new TicTacToePlayer[]{playerI, null, playerII},
new TicTacToePlayer[]{playerI, playerII, null},
new TicTacToePlayer[]{playerI, playerII, playerI}
};
ticTacTocGame.start();
ticTacTocGame.makeMove(new TicTacToeMove(0, 0));
ticTacTocGame.makeMove(new TicTacToeMove(1, 1));
ticTacTocGame.makeMove(new TicTacToeMove(2, 2));
ticTacTocGame.makeMove(new TicTacToeMove(0, 2));
ticTacTocGame.makeMove(new TicTacToeMove(2, 0));
ticTacTocGame.makeMove(new TicTacToeMove(2, 1));
ticTacTocGame.makeMove(new TicTacToeMove(1, 0));
this.displayBoardPlayerInteractionSnapshot(ticTacTocGame);
final TicTacToePlayer[][] actualBoardInteractionSnapshot = ticTacTocGame.getPlayerInteractionSnapshotBoard();
Assert.assertFalse(ticTacTocGame.isGameDraw());
Assert.assertTrue(ticTacTocGame.existWinner());
Assert.assertEquals(ticTacTocGame.getWinner().getDisplayName(), playerIDisplayName);
Assert.assertArrayEquals(actualBoardInteractionSnapshot, expectedBoardInteractionSnapshot);
}
If you are interested to find out more you can find the whole java implementation of the TicTacToe game: https://github.com/ncaralicea/tictactoe

Categories

Resources