I am to create a game in cmd (not gui) in java, its a larger project, but for now, I'd love to know how would I create a 12x12 grid, spawn a player at 0,0 (left top corner) and move him around using keys?
I have attempted to create an array, but didn't seem to get movement to work. I'm a newbie, so would welcome any suggestions.
package hunters;
import java.io.*;
import java.util.*;
import java.awt.*;
public class Hunters {
private static int score;
private static String player = "P";
private static String move;
private static String emptyfield = "X";
private static String [][]a2 = new String [12][12];
private static int pr,cr;
public static void paint_board(){
for (int r = 0 ; r < a2.length; r++){
for (int c= 0; c <a2[r].length; c++){
a2 [r][c] = emptyfield;
a2[pr][cr] = player;
System.out.print(" "+a2[r][c]);
}
System.out.println("");
}
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
score = 0;
paint_board();
do{
System.out.println("Input your move");
move = in.nextLine();
if (move.equalsIgnoreCase("w")){
//move up
a2[pr-1][cr]= player;
//repaint
paint_board();
//check for collision
//check for health
}else if(move.equalsIgnoreCase("s")){
//move down
a2[pr+1][cr]= player;
//repaint
paint_board();
//check for collision
//check for health
}else if(move.equalsIgnoreCase("d")){
//move right
a2[pr][cr+1] = player;
//repaint
paint_board();
//check for collision
//check for health
}else if(move.equalsIgnoreCase("a")){
//move left
a2[pr][cr-1]=player;
//repaint
paint_board();
//check for collision
//check for health
}
}while(score !=5);
}
}
this is the way i'd like it to work. I have tried to create a separate Position class but I have failed in the process...`
Create a 2D array, have a way to paint a cell in the 2D array (which might contain different objects as defined by the value of the cell). So you might check the square to paint, and if the value is HUMAN (pre-defined constant) then draw a human at that location on the screen.
void paint_cell(int x, int y) {
if (array[x][y] == HUMAN) {
printf("H");
} else if (array[x][y] == ENEMY) {
printf("E");
} else if (array[x][y] == EMPTY) {
printf(" ");
}
}
void paint_maze() {
for (int j = 0; j < 12; j++) {
printf("|");
for (int i = 0; i < 12; i++) {
paint_cell(i,j);
}
printf("|\n");
}
}
When you receive a key event, go to the cell that contains the human and move it to a new destination depending on the key. Then draw the maze again.
"An Array" is definitely the right idea -- a two-dimensional array is probably what I would use to contain the spaces of the grid. But -- what is going to be in the array? Objects that represent the spaces that the user moves through? That's cool; you will have to figure out how to define those spaces, and figure out how to display each one on the screen.
You probably can't use a KeyListener to check for user keystrokes, since KeyListener is part of AWT/Swing, but you will need a way to get input from the keyboard. Reading from stdin is the easy way to go here. You will need to run a loop that listens for user input at the keyboard, and moves the user's "gamepiece" from square to square depending on which key they hit.
Related
I managed to figure out how to print the array for my connect four program but I cannot get the board to update with my code, I looked at it and ran it the code works in theory but however the array won't take the new inputs
Ive tried running it through with a for loop but that turned out wrong and I was thinking about putting the drop method in the print board method but I feel that that would result in an error
public class Connect4 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// DON'T MODIFY THE MAIN METHOD UNLESS FOR DEBUGGING
//MAKE SURE YOU GET RID OF YOUR MODIFICATIONS HERE BEFORE
SUBMISSION
String[][] board = createEmptyBoard();
Scanner input = new Scanner(System.in);
boolean bl = true;
printPattern(board);
while(bl) {
int player1 = 1 , player2 = 2 , userInput;
System.out.println("Please drop a RED disk at the column between 0
and 6:");
userInput = input.nextInt();
dropDisk(board, userInput , player1);
printPattern(board);
System.out.println("Please drop a YELLOW disk at the column
between 0 and 6:");
userInput = input.nextInt();
dropDisk(board, userInput , player2);
printPattern(board);
String win = checkWinner(board);
/*
Write code to announce if there is winner and end the game
*/
}
}
public static String[][] createEmptyBoard() {
/* This method prints the first empty pattern for the game
DON'T MODIFY THIS METHOD
*/
String[][] f = new String[7][15];
for (int i =0;i<f.length;i++) {
for (int j =0;j<f[i].length;j++) {
if (j% 2 == 0) f[i][j] ="|";
else f[i][j] = " ";
if (i==6) f[i][j]= "-";
}
}
return f;
} // end of createEmptyBoard
public static void printPattern(String[][] brd) {
for (int i = 0; i < 7; i++){
System.out.println(brd[i][0] + brd[i][1]+ brd[i][2]+ brd[i][3]+
brd[i][4]+ brd[i][5]+ brd[i][6]+ brd[i][7]+ brd[i][8]+ brd[i][9]+
brd[i][10]+ brd[i][11]+ brd[i][12]+ brd[i][13]+ brd[i][14]);
}
} // end of printPattern
public static void dropDisk(String[][] brd, int position, int
player) {
if (player == 1){
brd[6][position] = "R";
if(brd[6][position] == "R"){
brd[6][position] = brd[6 - 1][position];
}
}
else if (player == 2){
brd[6][position] = "Y";
if(brd[6][position] == "Y"){
brd[6][position] = brd[6 - 1][position];
}
}
/*Write your code to drop the disk at the position the user entered
depending on which player*/
} // end of dropDisk
The logic of dropDisk seems to be not finished yet.
It sets the brd[6][position] to R or Y, just to immediately after that set it to the current value of brd[5][position].
And this should always be null.
In Java, objects are passed into methods by value. This means that when you pass a parameter into a function, the JVM makes a copy of that object which can be modified in the method.
In this case, when you pass brd into dropDisk, it is copied, and you make changes to the copy inside dropDisk. But once dropDisk ends, that copy is discarded. No changes are made to the board from your main method. This is because your board is an array of Strings, and Strings are immutable, meaning that they cannot be changed after instantiation.
If you wanted the board from your main method to update, consider returning brd in dropDisk.
This is my first time using this site so don't go hard on me
I'm trying to make my own card game and in the game, the cards are placed in a 6 x 9 gridlayout. Everything else I can handle, but there is one feature in the game that I'm having trouble on, and if I can get it to work, I'll be finished. This is for my final project and it's due in about 5 days
I'm trying to make the cards shuffle when the user clicks on the White Joker card.
When that White Joker is clicked, the faced up cards and the other poker cards that are faced down are shuffled too. I don't want any duplicate cards in the grid
To be more explicit, I'll show my problem visually, because what I'm trying to do is complicated to explain in words and also complicated to make the code for it.
When the user clicks on one or more faced down cards, it'; look something like this:
When the White Joker is clicked it was shuffled and I don't want it to shuffle. I want everything else to shuffle while the White Joker stays in it's spot.
Here is my shuffle method code. Below I want this method to shuffle the JButtons but not the White Joker one. The White Joker one should stay
public JButton[] whiteJokerShuffle(JButton[] button)
{
//shuffles using fisher yates shuffle BUT ONLY White Joker does not
//shuffle
//FIX THISSSSSSSSSSSSSSSSSSSSSSS
Random rand = new Random();
int randomCard;
JButton randomValue;
for (int i = 0; i<button.length; i++)
{
randomCard = rand.nextInt(button.length);
//can't find a way to check for White Joker and make it stay
randomValue = button[randomCard];
button[randomCard] = button[i];
button[i] = randomValue;
}
return button;
}
And again, I do not want to see duplicate poker cards when I shuffle the cards and click on the buttons. I keep making that happen every time I try, and I don't know how to fix it so here is my other code that creates the frame and stuff:
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.GridLayout;
/**
*
* #author elngo
*/
public class GameFrame extends JFrame {
private final int FRAME_WIDTH = 900;
private final int FRAME_HEIGHT = 730;
private int _attempts = 0;
private GridLayout _buttonMatrix;
private ImageIcon _image;
private ImageIcon _faceDownImage;
private JButton[] _button;
private ActionListener _listener;
private JPanel _gridPanel;
private JOptionPane _introduction; //this pops up BEFORE the gamem starts
private JOptionPane _endGameResult; //this ONLY pops up when the game ENDS
//using the Cards class
private Cards _cards;
private String[] _pokerDeck;
private JButton _whiteJoker;
final int GRID_ROWS = 6;
final int GRID_COLUMNS = 9;
//Constructor
/**
*
*/
public GameFrame()
{
frameComponents();
setSize(FRAME_WIDTH, FRAME_HEIGHT);
}
/**
*
*/
private void frameComponents()
{
_cards = new Cards(); //invokes Cards class
String[] faceDown = _cards.getFaceDown();
_pokerDeck = _cards.getPokerDeck();
//makes a matrix of JButtons
_button = new JButton[_pokerDeck.length];
_gridPanel = new JPanel(_buttonMatrix = new GridLayout(GRID_ROWS, GRID_COLUMNS));
_listener = new ClickListener();
//places FACE DOWN cards in the 6x9 grid first
for (int i = 0; i<faceDown.length; i++)
{
_faceDownImage = new ImageIcon(faceDown[i]);
_gridPanel.add(_button[i] = new JButton(_faceDownImage)); //adds to grid
_button[i].addActionListener(_listener);
}
add(_gridPanel);
//shuffle poker cards
//comment this randomizer out UNTIL I find a way to make WhiteJoker work
//_cards.shuffleDeck(_pokerDeck);
}
public class ClickListener implements ActionListener{
#Override
/**
*
*/
public void actionPerformed(ActionEvent event)
{
for (int i=0; i<_button.length; i++)
{
if (event.getSource() == _button[i])
{
_image = new ImageIcon(_pokerDeck[i]);
_button[i].setIcon(_image);
_attempts++;
System.out.println("Attempts: " + _attempts); //delete later
//***THE WHITE JOKER SHUFFLE PROBLEM STARTS HERE***
if (_pokerDeck[i] == "WJ.png") //if White Joker clicked
{
//FIX THISSSSSSSSSSSSSSSsssSSSSSSSSSssssSs
System.out.println("White Joker found"); //delete later
//save off Joker Spot so iterate through _buttonMatrix
String whiteJoker = _pokerDeck[i];
for (int j = 0; j<_button.length; j++)
{
if (_button[j] != null)
{
//***THE SHUFFLE METHOD I SHOWED IS USED BELOW***
_cards.whiteJokerShuffle(_button);
}
}
_gridPanel.removeAll();
for (JButton button : _button)
{
_gridPanel.add(button);
}
_gridPanel.revalidate();
_gridPanel.repaint();
}
//***PROBLEM STOPS HERE***
I really need help on this. Just this one complicated problem, and once it's solved, I'll tidy up my code and I'll be finished.
You can implement a modified version of the Fisher–Yates shuffle (or the modern version, designed for computer use, that was introduced by Richard Durstenfeld in 1964 and popularized by Donald E. Knuth):
When the White Joker is to be shuffled, you leave it on the same position.
When one of the other cards is to be shuffled, you make sure it is not swapped with the White Joker.
In the actionPerformed method, you iterate over all the buttons and then detect that the White Joker is clicked. The loop variable i contains the index of the White Joker, which you do not want to change. This value can be passed to the modified shuffle method.
To keep the example below short, I have passed an array of strings (instead of buttons) and determined the index of the White Joker inside the shuffle method:
import java.util.*;
public class GameFrame {
private static final String WHITE_JOKER_CODE = "*W";
public static void main(String[] arguments) {
String[] originalCards = {"5H", "5C", "6S", WHITE_JOKER_CODE, "7S", "KD"};
System.out.println("Original cards: " + Arrays.toString(originalCards));
String[] shuffledCards = new GameFrame().whiteJokerShuffle(originalCards);
System.out.println("Shuffled cards: " + Arrays.toString(shuffledCards));
}
// Uses the modern version of the Fisher–Yates shuffle, designed for computer use,
// as introduced by Richard Durstenfeld in 1964 and popularized by Donald E. Knuth.
// https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
public String[] whiteJokerShuffle(String[] cards)
{
int whiteJokerIndex = Arrays.asList(cards).indexOf(WHITE_JOKER_CODE);
Random randomNumbers = new Random();
for (int cardIndex = cards.length - 1; cardIndex > 0; cardIndex--)
{
if (cardIndex != whiteJokerIndex) {
// The upper bound is normally one higher than cardIndex, but it is
// lowered by one when the white joker is in the range (to "hide" it).
boolean hideJoker = cardIndex > whiteJokerIndex;
int upperBound = cardIndex + (hideJoker ? 0 : 1);
int swapIndex = randomNumbers.nextInt(upperBound);
if (swapIndex == whiteJokerIndex) {
swapIndex++;
}
// Swap the cards on indices swapIndex and cardIndex.
String swapCard = cards[swapIndex];
cards[swapIndex] = cards[cardIndex];
cards[cardIndex] = swapCard;
}
}
return cards;
}
}
public String tictactoe(String game)
{
game = game.toUpperCase();
char[][] board = new char[3][3];
int loc = 0;
for( char r = 0; r < board.length; r++ )
{
for( char c = 0; c < board[r].length; c++)
{ board[r][c] = game.charAt(loc);
loc++;
}
}
if ((board[0][0] =='X' && board[0][1] =='X' && board[0][2] =='X') ||
(board[1][0] =='X' && board[1][1] =='X' && board[1][2] =='X') ||
(board[2][0] =='X' && board[2][1] =='X' && board[2][2] =='X'))
return("Player 1 wins horizontally!");
else if ((board[0][0] =='O' && board[0][1] =='O' && board[0][2] =='O') ||
(board[1][0] =='O' && board[1][1] =='O' && board[1][2] =='O') ||
(board[2][0] =='O' && board[2][1] =='O' && board[2][2] =='O'))
return("Player 2 wins horizontally!");
else if ((board[0][0] =='X' && board[1][0] =='X' && board[2][0] =='X') ||
(board[0][1] =='X' && board[1][1] =='X' && board[2][1] =='X') ||
(board[0][2] =='X' && board[1][2] =='X' && board[2][2] =='X'))
return("PLayer 2 wins vertically!");
else if ((board[0][0] =='O' && board[1][0] =='O' && board[2][0] =='O') ||
(board[0][1] =='O' && board[1][1] =='O' && board[2][1] =='O') ||
(board[0][2] =='O' && board[1][2] =='O' && board[2][2] =='O'))
return("Player 2 wins vertically!");
return "Tie!";
}
Above is my code for this method. It reads in a 9 letter string for a tic-tac-toe game and then puts it one by one into a 2D array. I unfortunately have to use this method because this is unfortunately what we're learning, and I've continuously had to bother my teacher about this...
The if statements check each row and column for a winner (I realize it does not check the horizontals). My issue here is nothing is being returned, even though it is supposed to return a string. As I have said I have to use 2D-arrays here. The goal is to check a tic-tac-toe game and return whom as won.
Consider replacing each instance of this
if(board[0][0] =='X' && board[0][1] =='X' && board[0][2] =='X') ||
...
With this function:
public boolean isRowFilledWith(int row_index, char x_or_o) {
return (board[row_idx][0] == x_or_o &&
board[row_idx][1] == x_or_o &&
board[row_idx][2] == x_or_o);
}
Now, to see if the top-most row contains all x-s, call it with
if(isRowFilledWith(0, 'X') ||
...
This will make your code a lot more concise, easier to read and easier to debug.
Try doing:
System.out.println(fooObject.tictactoe("XXXXXXOOO");
inside your main argument (public static void main(String[] args)
I suspect you've confused return and System.out.println. The console will not print anything if returned. Instead, returning is what is thrown at the computer after the function is called. Try printing the result of calling the function...THAT is what is returned to the computer and is only going to be visible if you print it. There may not be any error in your code.
First off, to directly answer your question:
Your function works fine, I locally tested it. I tried both horizontal, and vertical, with both x and o. It must be something you are doing with the caller.
The biggest problem with this code is clarity. You can do quite a bit about clarity by separating the logic into groups.
Clarity can be achieved by making application specific objects.
If you have an object to represent a move, a game, and the marker... you can drastically simplify you code and most of all make it easy to read and debug.
I went ahead and implemented tic tac toe just to kinda explain what I mean by clarity.
Any time you start having massive if else chains and block return statements you may need to take the extra time to break up the problem.
This is fully compililable and I think if you debug through it a few times you will find it is much easier to spot mistakes.
It is also easy to ajust the game... Right now, we have 2 players and a 3 by 3 game.
However, we have extra constructors to adjust the size of the game and to give the gamers some options on what they want thier tic tac toe game to look like.
The major reason to do this is for clarity and debugging.
It is always easier to find issues if you have problem specific methods and problem specific objects.
Below is a fully compilable console application for tic tac toe. In its current form, it plays 100 random 3 by 3 games and prints the results of all 100 games.
The application is also capable of taking your string input as console input and processing the moves.
Notice that we are still using two dimensional arrays, but we hidden away the complexity of using them by encapsulating the array in the Board object.
We also gave a move object so we can store moves to play later. This was useful in creating the loop to play many games, as all the facts about the move are contained in a single object.
Since we created three separate methods for validating the move input. We have a much clearer explanation of what we are validating and why we are doing it.
Most debuggers will also show the objects toString method, so by embedding the game display within the toString() we are allowed to see what the board looks like when we are debugging.
The trick to making clean code that doesn't require alot of comments is to attempt to split out any complexity to its own unit.
You probably will cover more about units of work later, but just keep it in mind, the more simple a method, the more reusable it is. The more single purpose a class is, the better and clearer it is.
My Example:
Mark.java
-This enum is the representation of the mark used by a player to signify their move.
public enum Mark{
X, Y;
}
TicTacToe.java
-This class is your main class
it handles gathering user input, cleaning it, processing it, and displaying the output to the user
Notice that I am not doing game display anywhere else but the main method. this keeps all display issues localized to one spot. The advantage to breaking up your code into specific objects is knowing where to fix something when it breaks.
package com.clinkworks.example;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.clinkworks.example.Move;
import com.clinkworks.example.Board;
import com.clinkworks.example.Mark;
public class TicTacToe {
//this variable is simply used for output. Since we cant save CAT in the mark enum, we
// use it to hold cats games.
private static final String catsGameIdentity = "CAT";
//this map contains the counts of wins for each symbol
//it also keeps track of ties and stores it in the map as "CAT"
//soo.. gamesToWinsMap.get("CAT") will produce the amount of ties.
private static final Map<String, Integer> gamesToWinsMap = new HashMap<String, Integer>();
public static void main(String[] args){
String game = args[0].toUpperCase(); //better ways to do this and no validation here.. but it will work
Board board = new Board();
//holds our current place in the string passed in from teh console
int currentStringLocation = 0;
for(int row = 0; row < 3; row++){ //loop through the rows
for(int column = 0; column < 3; column++){ //for each row loop through the columns
if(gameOver(board)){ // we don't care about the rest of the input if the game was won
break;
}
//convert the symbol to a string for use in teh ValueOf function in the enum class
String symbol = "" + game.charAt(currentStringLocation); //better than String.valueOf imho
//allow spaces to represent un marked places
if(" ".equals(symbol)){
currentStringLocation++; //this accounts for spaces in our input
break;
}
//convert the string to a Mark enum... over use of strings is a very very bad practice
Mark nextMarkToPlace = Mark.valueOf(symbol);
Move move = new Move(row, column, nextMarkToPlace); //we create a move object that encapsulates the complexity of placing the mark on the game board
board.play(move); //the game already knows how to play itself, just let it
currentStringLocation++; //increment the posision.
}
}
//since you may not have won the game, or gave a complete string for a cats game,
// lets at least display the board for debugging reasons.
if(board.movesLeft() > 0){
System.out.println("Board isn't finished, but here is what it looks like basd on your input: ");
System.out.println(board);
}
}
//call me main if you want to see what I do
public static void main2(String[] args) {
//lets play 100 games and see the wins and ties
playGames(100);
System.out.println("Number wins by X: " + gamesToWinsMap.get(Mark.X.name()));
System.out.println("Number wins by O: " + gamesToWinsMap.get(Mark.O.name()));
System.out.println("Number of ties: " + gamesToWinsMap.get(catsGameIdentity));
}
public static void playGames(int count) {
//play a new game each iteration, in our example, count = 100;
for (int i = 0; i < count; i++) {
playGame();
}
}
public static void playGame() {
//create a new game board. this initalizes our 2d array and lets the complexity of handling that
// array be deligated to the board object.
Board board = new Board();
//we are going to generate a random list of moves. Heres where we are goign to store it
List<Move> moves = new ArrayList<Move>();
//we are creating moves for each space on the board.
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
moves.add(new Move(row, col));
}
}
//randomize the move list
Collections.shuffle(moves);
//do each move
for (Move move : moves) {
board.play(move);
if(gameOver(board)){
break;
}
}
}
public static boolean gameOver(Board board){
if (board.whoWon() != null) {
System.out.println("Player with the mark: " + board.whoWon() + " won the game!");
System.out.println(board);
Integer winCount = gamesToWinsMap.get(board.whoWon().name());
winCount = winCount == null ? 1 : winCount + 1;
gamesToWinsMap.put(board.whoWon().name(), winCount);
return true;
} else if (board.movesLeft() == 0) {
System.out.println("It was a cats game!!");
System.out.println(board);
Integer catCount = gamesToWinsMap.get(catsGameIdentity);
catCount = catCount == null ? 1 : catCount + 1;
gamesToWinsMap.put(catsGameIdentity, catCount);
return true;
}
return false;
}
Move.java
-This class is responsible for ensuring that only integers are passed to the game board
and for telling the game board who is doing the move (optional)
package com.clinkworks.example;
import com.clinkworks.example.Mark;
public class Move {
private int row;
private int column;
private Mark forcedMark;
public Move(int row, int column) {
this.row = row;
this.column = column;
}
//the board already knows who should be next. only use this constructor to override
// what symbol to put on the game board
public Move(int row, int column, Mark markToPlace){
this.row = row;
this.column = column;
forcedMark = markToPlace;
}
public int getRow() {
return row;
}
public int getColumn() {
return column;
}
public Mark getMark(){
return forcedMark;
}
}
Board.java
-This is where all the state of the board is managed, who is the next player, who won, and
is there any moves left to play. It also ensures that only valid moves are played.
package com.clinkworks.example;
import com.clinkworks.example.Mark;
import com.clinkworks.example.Move;
public class Board {
private final int rowSize;
private final int columnSize;
private final Mark[][] gameBoard;
private Mark currentMark;
private Mark winningMark;
/**
* This constructor defaults the starting player to X with a 3 by 3
* game.
*/
public Board() {
gameBoard = new Mark[3][3];
currentMark = Mark.X; // X always goes first ;P
winningMark = null;
this.rowSize = 3;
this.columnSize = 3;
}
/**
* This constructor defaults the starting player to X, and lets the
* board size be adjusted
*/
public Board(int rowSize, int columnSize) {
gameBoard = new Mark[rowSize][columnSize];
currentMark = Mark.X; // X always goes first ;P
winningMark = null;
this.rowSize = getRowSize();
this.columnSize = columnSize;
}
/**
* this constructor allows the players to choose who goes first on a 3
* by 3 board.
*
* #param firstPlayer
*/
public Board(Mark firstPlayer) {
gameBoard = new Mark[3][3];
currentMark = firstPlayer; // Let the player choose
winningMark = null;
rowSize = 3;
columnSize = 3;
}
/**
* this constructor allows the players to choose who goes first and to
* choose the size of the board.
*
* #param firstPlayer
*/
public Board(Mark firstPlayer, int rowSize, int columnSize) {
gameBoard = new Mark[getRowSize()][columnSize];
currentMark = firstPlayer; // Let the player choose
winningMark = null;
this.rowSize = rowSize;
this.columnSize = columnSize;
}
/**
*
* #return the amount of empty spaces remaining on the game board, or if theres a winning player, zero.
*/
public int movesLeft() {
if(whoWon() != null){
return 0;
}
int moveCount = 0;
for (int x = 0; x < getRowSize(); x++) {
for (int y = 0; y < getColumnSize(); y++) {
moveCount += getMarkAt(x, y) == null ? 1 : 0;
}
}
return moveCount;
}
/**
* If someone won, this will return the winning player.
*
* #return the winning player
*/
public Mark whoWon() {
return winningMark;
}
/**
* This move allows the next player to choose where to place their mark.
* if a move is played without a player given, it will use the current player variable
*
* as a side affect, the next player in rotation is chosen.
*
* #param Move
* #return if the game is over, play will return true, otherwise false.
*/
public boolean play(Move move) {
if (!validMove(move)) {
// always fail early
throw new IllegalStateException("Cannot play " + currentMark + " at " + move.getRow() + ", " + move.getColumn() + "\n" + toString());
}
doMove(move);
boolean playerWon = isWinningMove(move);
if (playerWon) {
winningMark = currentMark;
return true;
}
togglePlayer();
boolean outOfMoves = movesLeft() <= 0;
return outOfMoves;
}
public Mark lastMarkPlayed() {
return currentMark;
}
public int getRowSize() {
return rowSize;
}
public int getColumnSize() {
return columnSize;
}
public Mark getCurrentPlayer() {
return currentMark;
}
public Mark getMarkAt(int row, int column) {
return gameBoard[row][column];
}
private void doMove(Move move) {
if(move.getMark() != null){
currentMark = move.getMark();
}
gameBoard[move.getRow()][move.getColumn()] = getCurrentPlayer();
}
private void togglePlayer() {
if (currentMark == Mark.X) {
currentMark = Mark.O;
} else {
currentMark = Mark.X;
}
}
/**
* A valid move is a move where the row and the column are within boundries
* and no move has been made that the location specified by the move.
*/
private boolean validMove(Move move) {
boolean noMarkAtIndex = false;
boolean indexesAreOk = move.getRow() >= 0 || move.getRow() < getRowSize();
indexesAreOk = indexesAreOk && move.getColumn() >= 0 || move.getColumn() < getColumnSize();
if (indexesAreOk) {
noMarkAtIndex = getMarkAt(move.getRow(), move.getColumn()) == null;
}
return indexesAreOk && noMarkAtIndex;
}
private boolean isWinningMove(Move move) {
// since we check to see if the player won on each move
// we are safe to simply check the last move
return winsDown(move) || winsAcross(move) || winsDiagnally(move);
}
private boolean winsDown(Move move) {
boolean matchesColumn = true;
for (int i = 0; i < getColumnSize(); i++) {
Mark markOnCol = getMarkAt(move.getRow(), i);
if (markOnCol != getCurrentPlayer()) {
matchesColumn = false;
break;
}
}
return matchesColumn;
}
private boolean winsAcross(Move move) {
boolean matchesRow = true;
for (int i = 0; i < getRowSize(); i++) {
Mark markOnRow = getMarkAt(i, move.getColumn());
if (markOnRow != getCurrentPlayer()) {
matchesRow = false;
break;
}
}
return matchesRow;
}
private boolean winsDiagnally(Move move) {
// diagnals we only care about x and y being teh same...
// only perfect squares can have diagnals
// so we check (0,0)(1,1)(2,2) .. etc
boolean matchesDiagnal = false;
if (isOnDiagnal(move.getRow(), move.getColumn())) {
matchesDiagnal = true;
for (int i = 0; i < getRowSize(); i++) {
Mark markOnDiagnal = getMarkAt(i, i);
if (markOnDiagnal != getCurrentPlayer()) {
matchesDiagnal = false;
break;
}
}
}
return matchesDiagnal;
}
private boolean isOnDiagnal(int x, int y) {
if (boardIsAMagicSquare()) {
return x == y;
} else {
return false;
}
}
private boolean boardIsAMagicSquare() {
return getRowSize() == getColumnSize();
}
//prints out the board in a nice to view display
public String toString() {
StringBuffer stringBuffer = new StringBuffer();
for(int y = 0; y < getColumnSize(); y++) {
for(int x = 0; x < getRowSize(); x++) {
Mark mark = getMarkAt(x, y);
String markToPrint = "";
if (mark == null) {
markToPrint = " ";
} else {
markToPrint = mark.name();
}
stringBuffer.append("|").append(markToPrint);
}
stringBuffer.append("|\n");
}
return stringBuffer.toString();
}
}
}
I am creating a hangman game and I was having trouble getting the jlabel that contained each character of the word to update after the right letter button has been clicked. I have been having trouble with this as I am relatively new to working with Java Guis. Below is the action listener for the letter buttons.
private class LetterHandler implements ActionListener{
private char letterVal;
public LetterHandler(char lv){
letterVal = lv;
}
//checks if clicked button has the correct value as word char
public void actionPerformed(ActionEvent e){
for(int x = 1; x <= selectedWord.wordLength; x++){
if(selectedWord.wordValue.charAt(x - 1) == letterVal){
// JLabel letterValLabel = new JLabel(String.valueOf(letterVal));
wordSpacesArray.get(x-1).setName(String.valueOf(letterVal));
wordSpacesArray.get(x-1).revalidate();
continue;
}
else{
continue;
}
}
checkWin();
triesLeft--;
triesLeftLabel.revalidate();
}
//finds if all jlabels are complete or not
public void checkWin(){
for(int x = 1; x <= wordSpacesArray.size(); x++){
String charVal;
charVal = String.valueOf(wordSpacesArray.get(x-1));
if(charVal != "?"){
System.out.println("youWon");
System.exit(0);
}
else{
break;
}
charVal = null;
}
}
}
Any help is appreciated. Let me know if you need for of the programs code Thanks :)
There are some issues with the code. However, I'll first try to focus on your current problem:
I assume that wordSpacesArray is a list that contains the JLabels of individual letters of the word.
When this ActionListener will be notified, you try to update the labels in wordSpacesArray with the letter that corresponds to this button. However, in order to update the text that is shown on a JLabel, you have to call JLabel#setText(String) and not JLabel#setName(String). So the line should be
wordSpacesArray.get(x-1).setText(String.valueOf(letterVal));
// ^ Use setText here!
Now, concerning the other issues:
As pointed out in the comments, you should use 0-based indexing
The calls to revalidate are not necessary
The use of continue in its current for is not necessary
You should not compare strings with ==, but with equals
// if(charVal != "?") { ... } // Don't do this!
if(!charVal.equals("?")){ ... } // Use this instead
But the charVal in this case will be wrong anyhow: It will be the string representation of the label, and not its contents. So you should instead obtain the text from the label like this:
// String charVal = String.valueOf(wordSpacesArray.get(x-1)); // NO!
String charVal = wordSpacesArray.get(x-1).getText(); // Yes!
The triesLeftLabel will not be updated as long as you don't call setText on it
I think the logic of the checkWin method is flawed. You print "You won" when you find the first letter that is not a question mark. I think it should print "You won" when no letter is a question mark.
You should not call System.exit(0). That's a bad practice. Let your application end normally. (In this case, maybe by just disposing the main frame, although that would also be questionable for a game...)
So in summary, the class could probably look like this:
private class LetterHandler implements ActionListener
{
private char letterVal;
public LetterHandler(char lv)
{
letterVal = lv;
}
// checks if clicked button has the correct value as word char
#Override
public void actionPerformed(ActionEvent e)
{
for (int x = 0; x < selectedWord.wordLength; x++)
{
if (selectedWord.wordValue.charAt(x) == letterVal)
{
wordSpacesArray.get(x).setText(String.valueOf(letterVal));
}
}
checkWin();
triesLeft--;
triesLeftLabel.setText(String.valueOf(triesLeft));
}
// finds if all jlabels are complete or not
public void checkWin()
{
for (int x = 0; x < wordSpacesArray.size(); x++)
{
String charVal = wordSpacesArray.get(x).getText();
if (charVal.equals("?"))
{
// There is still an incomplete label
return;
}
}
// When it reaches this line, no incomplete label was found
System.out.println("You won");
}
}
I made a simple game(well not really a game yet) in which the player can move in a room 4x20 characters in size. It runs in console.
But in my game loop I want to be able to move around in the room without pressing enter every time I want to move. The player should be able to press w/a/s/d and have the screen update instantly, but I don't know how to do that.
public class Main{
public static void main(String[] args){
MovementLoop();
}
public static void MovementLoop(){
Scanner input = new Scanner(System.in);
int pos=10, linepos=2;
String keypressed;
boolean playing = true;
while(playing == true){
display dObj = new display(linepos, pos);
dObj.drawImage();
keypressed=input.nextLine();
if(keypressed.equals("w")){
linepos -= 1;
}
else if(keypressed.equals("s")){
linepos += 1;
}
else if(keypressed.equals("a")){
pos -= 1;
}
else if(keypressed.equals("d")){
pos += 1;
}
else if(keypressed.equals("q")){
System.out.println("You have quit the game.");
playing = false;
}
else{
System.out.println("\nplease use w a s d\n");
}
}
}
}
public class display{
private String lines[][] = new String[4][20];
private String hWalls = "+--------------------+";
private String vWalls = "|";
private int linepos, pos;
public display(int linepos1, int pos1){
pos = pos1 - 1;
linepos = linepos1 - 1;
}
public void drawImage(){
for(int x1=0;x1<lines.length;x1++){
for(int x2=0;x2<lines[x1].length;x2++){
lines[x1][x2]="#";
}
}
lines[linepos][pos]="O";
System.out.println(hWalls);
for(int x2=0;x2<lines.length;x2++){
System.out.print(vWalls);
for(int x3=0;x3<lines[x2].length;x3++){
System.out.print(lines[x2][x3]);
}
System.out.println(vWalls);
}
System.out.println(hWalls);
}
}
The answer is simple
You can't do that
Because command line environment is different from swing, as swing can do such a thing as it deals with events and object, whereas, command line have no events.
So, maybe it's a right time to leave command line.