I'm pretty new to Java and learning it as a hobby mainly after school to kill my free time productively. I find it really interesting and picking it up relatively pain free however I'm a bit stuck trying to implement a basic chess program that can be played via the command line. Ideally, I'd like to print out the board initially with just Kings and Queens on both sides and get them moving forwards, backwards and diagonally. (Once I get the hang of this I would try adding all other pieces, but at first I would like to just start as simply as possible). For simplicity I will just be using the standard 8x8 playing board.
I've already created a main game loop which uses a command line input of 1 to switch players and 2 to exit the game but I am stuck when it comes to printing out positions and having them change during the game. Firstly I would like to print out the starting positions of both kings and queens as a string (e.g ["D1","E1","D8","E8"]) for the player to see. I imagine the best way to do this is by using the ASCII index but I'm not really sure where to go from this, I tried the code below I know it's not correct and I don't know what to change...
int num[] = {65, 66, 67, 68, 69, 70, 71, 72};
String start_Pos =null;
for(int i = 4; i < 6; i++){
start_Pos[i] = (Character.toString((char)i) + "1");
}
int num[] = {65, 66, 67, 68, 69, 70, 71, 72};
String start_Pos =null;
for(int i = 4; i < 6; i++){
start_Pos1[i] = (Character.toString((char)i) + "8");
}
System.out.println(start_Pos + start_Pos1);
I have also tried coding the board set-up but this is literally just printing out the starting positions of the pieces and therefore will not change when a player makes a move - ideally it should. An example would be the starting positions are shown on the board like so:
Photo (PS I know QK should be swapped on one side so they're not opposite each other, my bad!
But after an input of "D1 D3" (first coordinates indicating what piece and the second indicating final position)from player 1 the board changes to reflect this. Is this possible without having to recompile the entire code after each turn? (Maybe a stupid question...).
Any help would be greatly appreciated. I find learning through making small games like these a lot more interesting and rewarding so if anyone is able to help me implement this I would be very thankful.
Java is an Object Oriented language, so it is best to use classes and object instances.
Of course, with a chessboard, you'll still want to perform calculations on the x, y coordinates. Computers are just better with numbers, they have problems interpreting things. The chess notation is mainly of use to us humans.
So here is a class that can be used to parse and interpret chess positions. Note that you should keep this class immutable and simply use a new object instance rather than changing the x or y field.
public final class ChessPosition {
// use constants so you understand what the 8 is in your code
private static final int BOARD_SIZE = 8;
// zero based indices, to be used in a 2D array
private final int x;
private final int y;
public ChessPosition(int x, int y) {
// guards checks, so that the object doesn't enter an invalid state
if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE) {
throw new IllegalArgumentException("Invalid position");
}
this.x = x;
this.y = y;
}
public ChessPosition(String chessNotation) {
// accept upper and lowercase, but output only uppercase
String chessNotationUpper = chessNotation.toUpperCase();
// use a regular expression for this guard
if (!chessNotationUpper.matches("[A-H][0-7]")) {
throw new IllegalArgumentException("Invalid position");
}
// can be done in one statement, but we're not in a hurry
char xc = chessNotationUpper.charAt(0);
// chars are also numbers, so we can just use subtraction with another char
x = xc - 'A';
char yc = chessNotation.charAt(1);
// note that before calculation, they are converted to int by Java
y = yc - '1';
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public String getChessNotation() {
// perform the reverse and create a string out of it
// using StringBuilder#append(char c) is another option, but this is easier
return new String(new char[] {
// Java converts 'A' to int first (value 0x00000041)
(char) (x + 'A'),
(char) (y + '1')
});
}
// this will be helpfully displayed in your debugger, so implement toString()!
#Override
public String toString() {
return getChessNotation();
}
}
Now probably you want to also create a Board class with a backing 2D array of ChessPiece[][] and perform board.set(WHITE_KING, new ChessPosition("E1")) or something similar.
Related
I have made a simple chess game that when the user types an input like a2a4, it moves the piece from a2 to a4.
Here I want user to be able to type any input like b2b4, but the only input it uses is a2a4. It is not using the scanner user input at all. How do I change that?
I have put comments in my code explaining everything. The ones with ******* at the end of comments are the ones im having problems with.Please help, I really need to finish this.
import java.util.Scanner;
/* Class Chess
* with 1 field variable chessBoard
* Created a 2 d array called board which contains a, b, c, d, e, f, g, h.
* These are String arrays which contain the pieces.
*
*/
public class Chess2 {
board[1][1] = " ";
//and put in here. [endLetter][endNumber]
board[1][3] = temp;
Instead of the "1"'s and "3"'s put here your numbers you got from your input just like that:
board[startLetters][startNumbers] = " ";
//and put in here. [endLetter][endNumber]
board[endLetter][endNumber] = temp;
Did not test it but thats one of the problems u had solved.
edit:
int startLetters = userInput.charAt(0) - 97;
int startNumbers = userInput.charAt(1) - 48;
int endLetter = userInput.charAt(2) - 97;
int endNumber = userInput.charAt(3) - 48;
since you are asking for the ascii value of your input you need to lower the value of your number input by 48 (http://www.chip.de/ii/1/2/5/4/9/5/8/0/ascii-93c823e7009f26b0.png).
Okay I found your problem. It's at int startNumbers = userInput.charAt(1); and int endNumber = userInput.charAt(3);. When you read the number in ASCII you need to decrement by 48 to get the actual number but since the position in arrays is counted from 0 not from 1, you need to decrement by 49 here. example: a2a4 will move the 3rd piece from the bottom up 2 places instead of the 2nd piece.
so just do
int startLetters = userInput.charAt(0) - 97;
int startNumbers = userInput.charAt(1)-49;
int endLetter = userInput.charAt(2) - 97;
int endNumber = userInput.charAt(3)-49;
Hope this helps!
I'm a college student and a beginner Java developer. I got this assignment for which I need to simulate a unidimensional battleship game using strings. The rules given to me are as follows:
The board has to be 10 in length and 1 in height
The computer puts on the board one length-one-ship and one length-two- ship
The user has to repeatedly shoot in one of the 10 possible position
Computer will respond to every shot with "water", "hit", "sunk", "already hit"
When all the ships have sunk, the game ends with the computer that tells you how many shots were needed.
What I came up with until now:
Define a method String buildBoard() that returns a random string made of 7 characters "water"; 2 characters, which have to be next to each other, for the "no hit length-two-ship"; and 1 character for the "no hit length-one-ship"
Define a method boolean endGame(String s) that returns true if all the ships were sunk.
Define a method String manageShot(String s, int p) that, given a Board configuration and a shot in position p, prints out the outcome of the shot (as explained above), and returns the new Board configuration.
Finally, define a void main(String[] args) method that manages input, method calls and the final print.
Do you think it could work?
Hopefully I have explained it in an understandable way.
My problem is that I have absolutely no idea on how to generate a random String especially if I have to keep two characters next to each other. Can someone please explain me how to do it?
Can you have a look at my code and see if it's all right or if it can be simplified?
public class UnidimensionalBattleship {
/* x - miss (no ships here)
* . - sea (available for firing)
* s - enemy ship (available for firing)
* c - enemy ship (2 spaces, available for firing) */
public static String map() {
String sea = new String("..........");
int pos;
Random rnd = new Random();
pos = rnd.nextInt(sea.length());
sea = sea.substring(0, pos) + "s" + sea.substring(pos + 1);
int shipsSet = 0;
do {
if (sea.substring(pos).equals(".") && sea.substring(pos+1).equals(".")) { //pos available
sea.substring(pos).equals("cc");
shipsSet++;
}
}while(shipsSet < 2);
return sea;
}
public static String manageShot(String sea, int p) {
char outcome = sea.charAt(p);
switch(outcome) {
case '.': System.out.println("Miss");
sea=sea.substring(p, p) + "x" + sea.substring(p+1);
break;
case 's': System.out.println("Sunk!");
sea=sea.substring(p, p) + "x" + sea.substring(p+1);
break;
case 'c': System.out.println("Hit!");
sea=sea.substring(p, p) + "x" + sea.substring(p+1);
break;
case 'x': System.out.println("Already Hit");
break;
}
return sea;
}
public static boolean endGame(String sea) {
int i; //counter
i=0;
for (i=0; i<sea.length(); i++) {
if (sea.charAt(i)=='.'|| sea.charAt(i)=='x')
i++;
}
return true;
}
My problem is that I have absolutely no idea on how to generate a random String especially if I have to keep two characters next to each other. Can someone please explain me how to do it?
Since you need to do it in String, some simple String manipulation with String functions will work. In order for you to determine whether it is a "hit", a "sunk", a "miss", or already hit, you can have a set of predefined letters to represent each of those.
For example:
x - miss (no ships here)
. - sea (available for firing)
s - enemy ship (available for firing)
c - enemy ship (2 spaces, available for firing)
To generate a string with ships on random positions, there are many ways to do this. You can use a StringBuilder and concatenate the String or simply use a char array and convert it to string after positioning the ships:
char[] sea = new char[10];
for(int x=0; x<sea.length; x++)
sea[x] = '.'; //set everything as sea first
Random rnd = new Random();
sea[rnd.nextInt(sea.length)] = 's'; //sea ship at random position
If you have multiple types of ships, use a different symbol to identify them.
If you have more than one ship, use a loop to fill the sea:
int shipsSet = 0;
do
{
int pos = rnd.nextInt(sea.length);
if(sea[pos] == '.'){ //pos available
sea[pos] = 's';
shipsSet++;
}
}while(shipsSet < 2);
Converting char array to String:
String map = String.valueOf(sea);
Generating the outcome:
int attackPos = scn.nextInt();
char outcome = map.charAt(attackPos);
switch(outcome){
case '.': System.out.println("Miss");
//use substring to mark this spot as "X"
break;
case 's': System.out.println("Sunk!"); //ship 's' only takes 1 space
//use substring to mark this spot as "X"
break;
case 'c': System.out.println("Hit!"); //ship 'c' takes 2 spaces
//use substring to mark this spot as "X"
break;
case 'x': System.out.println("Already Hit");
break;
}
The above shall give you a very good idea where to start and how to implement your entire program. If you are not allowed to use char array, simply use StringBuilder. If it is also not allowed, just use substring to generate a map with ships on random positions.
I think I've got the first part with this - you can use RandomStringUtils from Apache Commons...
https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/RandomStringUtils.html#random(int, java.lang.String)
As you can see, it takes an integer and a String - the Integer is the length of the string and the String is the group of characters it will use.
I will have a poke around in the internet to see if I can help you with keeping the two characters together.
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;
}
I am trying to reproduce the Game of Life but I've a bug. Cells are born according to design, but they don't die. This confuses me because my strategy for killing cells is the same as for giving birth to them. Here is a segment of the console output, 'x' represents living cells, '-' represents dead cells.
---------
---------
---------
---xx----
----x----
----x----
----xx---
---------
---------
---------
---------
---------
---xx----
----xx---
---xx----
----xx---
---------
---------
---------
---------
---------
---xxx---
----xx---
---xx----
---xxx---
---------
---------
And the relevant piece of code:
public class Life {
final static int WIDTH = 9, HEIGHT = 9;
void start(){
// scanning input file
char[][][] board = new char[WIDTH][HEIGHT][maxAllowedGenerations];
board = getInitialBoard(initialBoardString, maxAllowedGenerations, board);
for (int generation = 1; generation < maxAllowedGenerations; generation++){
for (int y = 0; y < HEIGHT; y++)
for (int x = 0; x < WIDTH; x++){
int numberOfNeighbours = getNumberOfNeighbours(x, y, generation - 1 , board);
if (board[x][y][generation - 1] == '-' && numberOfNeighbours == 3)
board[x][y][generation] = 'x';
else if (board[x][y][generation - 1] == 'x' && numberOfNeighbours < 2)
board[x][y][generation] = '-';
else board[x][y][generation] = board[x][y][generation - 1];
if (board[x][y][generation] == 'x')
ui.place(x, y, LifeUserInterface.ALIVE);
else
ui.place(x, y, LifeUserInterface.DEAD);
out.print(board[x][y][generation]);
}
out.println();
}
}
out.println("Max number of generations reached");
System.exit(0);
}
I agree with #elyashiv - if you change char[][][] board to SomeEnum[][][] board, with SomeEnum defined with values LIVE_CELL and DEAD_CELL that would make things much more readable.
Also, there is no such thing as an empty character ''. An empty String is simply a String with zero length (ie no characters), but '' makes no sense. You could use null, but then you'd have to move away from the primitive char declaration and use Character instead since primitives can't be null.
That said, much better to use enums to represent the data. If you want, you can even make your enum look like this so you can represent your X and empty characters like so:
public enum SomeEnum {
LIVE_CELL("X"),
DEAD_CELL("");
public final displayString;
SomeEnum(String displayString) {
this.displayString = displayString;
}
}
Then for your display you could reference SomeEnum.LIVE_CELL.displayString in your code
Found two bugs! One of them was impossible for you to spot because I didn't post the code in which it was contained: I am a cell at [x][y][g]. I was considering [x][y][g - 1] to be a neighbour, but that is of course me! I am not my own neighbour.
The other bug was a bit embarrasing actually. I had left out rule number 2... >.<
I also realize I should have posted the rules of the Game of Life instead of assuming that you all know them or that you would bother researching them. It's a bit late now of course, but I'll post them anyway in case you are interested. Also, I really reccomend the wiki article for anyone interested in self-organization.
Rules:
Live cells with < 2 live neighbours die, as if by loneliness.
Live cells with > 3 live neighbours die, as if by overpopulation.
Live cells with 2 || 3 live neighbours survive to the next generation.
Dead cells with 3 live neighbours are revived, as if by reproduction.
Thank you for all input!
I am writing a snake game, specifically, is a centipede game. It needs me to draw a snake and that snake will automatically move one line by one line.
I did draw a snake, and it can move from left side to right side. However, the problem is:
I can't make the snake changes line, if it finish the first line, I need it changes to the second line and which starts from the right side.
My code is like this:
private void move()
{
myCentipedes[0] =
new Centipede(Settings.centipedeStartSize, Settings.RIGHT,
Settings.DOWN);
myCentipedes[0].segments = new Point[Settings.centipedeStartSize];
myCentipedes[0].segments[0] = new Point(0, 0);
boolean dr = true;
if (dr == true) {
if (myCentipedes[0].segments[0].x < 30) {
System.out.println(myCentipedes[0].segments[0].x +
" " +
myCentipedes[0].segments[0].y);
myCentipedes[0].segments[0] = new Point(x, 0);
for (int i = 1; i < 10; i++) {
myCentipedes[0].segments[i] =
new Point(myCentipedes[0].segments[i - 1].x - 1,
myCentipedes[0].segments[i - 1].y);
}
x++;
}
}
if (myCentipedes[0].segments[0].x == 29) {
x = 29;
dr = false;
}
if (dr == false) {
if (myCentipedes[0].segments[0].x > 0) {
myCentipedes[0].segments[0] = new Point(x, 1);
for (int i = 1; i < 10; i++) {
myCentipedes[0].segments[i] =
new Point(myCentipedes[0].segments[i - 1].x + 1, 1);
}
x--;
}
}
}
It appears to me that you re-create your entire centipede on every single move:
private void move()
{
myCentipedes[0] =
new Centipede(Settings.centipedeStartSize, Settings.RIGHT,
Settings.DOWN);
Is re-creating the centipede every move() intentional? Or should move() run the centipede entirely down the board, from start to finish? (If so, you'll need to add some looping to this method.)
I assume the myCentipedes[0] is simply a placeholder for future extensions, involving two or more centipedes on the board simultaneously. This sort of over-generic programming can sometimes make the code more difficult to read and write while initially programming, and almost certainly doesn't help matters. You can always re-factor a move() method that works on one centipede to a move(int centipede) method that works on a specific centipede and a move() method that calls move(int) for every centipede on the board. Or maybe you'll find it easier to place the movement code into the Centipede class, and need to remove the array indexes then and use class member storage instead.
boolean dr = true;
if (dr == true) {
dr will always equal true at this point. You might as well remove the variable and the test.
for (int i = 1; i < 10; i++) {
myCentipedes[0].segments[i] =
new Point(myCentipedes[0].segments[i - 1].x - 1,
myCentipedes[0].segments[i - 1].y);
}
Since you're counting up, you'll actually copy the value from segment[0] through to all elements in the array, one element at a time. Can't you just assign the Point objects new array indexes? Starting from i=centipede.segments.length and counting down, it'll look more like this:
for (int i=myCentipede[0].segments.length; i > 0; i--) {
myCentipede[0].segments[i] = myCentipede[0].segments[i-1];
}
myCentipede[0].segments[0] = new Point(...,...);
Some of your tests can be simplified:
if (myCentipedes[0].segments[0].x == 29) {
x = 29;
dr = false;
}
if (dr == false) {
if (myCentipedes[0].segments[0].x > 0) {
If dr == false at this point, you might as well have written it like this instead:
if (myCentipedes[0].segments[0].x == 29) {
x = 29;
if (myCentipedes[0].segments[0].x > 0) {
But then the second if is obviously not needed -- after all, 29 > 0.
While you're here, clean up all those hard-coded 10 with either a constant (Settings.centipedeStartSize) or find the actual length of the centipede (myCentipedes[0].segments.length).
Now that I've critiqued your current approach, I'd like to suggest a different tack:
Take a step back and break your problem down into smaller methods.
You've embedded two for loops that move the centipede one segment at a time by assigning to segment[i] the values from segment[i-1]. Instead of duplicating the code, write a new method with the body of the for loop to move the centipede forward. Make it take a Point object for the new first element each trip through the function. (Don't forget to make it count down rather than up.)
Once you've broken apart the for loops, I think it will be easier to make whatever changes are necessary for traveling left-to-right and right-to-left. You will probably want to write it with nested for loops -- one to control the vertical dimension, and within it, perhaps one or two new for loops to control the horizontal dimension. Make these loops work with a simple Centipede c, rather than the complicated expression you've currently got.
Breaking apart the larger function into smaller function will give you a better opportunity to test your functions in isolation -- test movement manually, with simple test methods like this:
move_forward(Centipede c, Point p) {
/* code to move forward one space to occupy `p` */
}
test_right() {
Centipede c = new Centipede(/* ... */);
move_forward(c, new Point(0,0));
move_forward(c, new Point(1,0));
move_forward(c, new Point(2,0));
move_forward(c, new Point(3,0));
move_forward(c, new Point(4,0));
move_forward(c, new Point(5,0));
/* ... */
}
Take it slow, test every method as you write them, and I think you'll find this is an easier problem than it currently looks.