• Post Reply Bookmark Topic Watch Topic
  • New Topic

Connect four Problem  RSS feed

 
marc lee
Greenhorn
Posts: 5
Chrome Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Team,

Im quite new to Java and took on the challenge of programming a game of "connect four" (console-version). So far all went pretty good, but now I'm stuck with the problem that i cant figure out why my function of evaluating the array for four connecting symbols isn't working the way i want.
Checking rows and columns is working, so is the diagonal for the symbol of 'x' (Player 1), but the same algorithm doesn't work for 'o' (PL2)...

I uploaded 2 snippets from the code:

Working algorithm for rows and columns:
http://pastebin.com/1HZ8rpyM

Not working algorithm for the diagonals:
http://pastebin.com/3vdw4MqZ

I made an Array of 6 X 7 Tiles, and didn't know any better way of checking each diagonal with more than 4 Tiles in that array.

Idea was to go through each neighboring tile diagonally and check if its the same symbol as the previous, then when 4 Tiles match, break out of the search, algorithm and set "Winner" to whoever won.

Hope someone has an answer.

Thanks a lot in advance!
Cheers
Bleichiful

 
Norm Radder
Rancher
Posts: 2240
28
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Please post the code here in the forum so all can see without having to download.  Be sure to wrap the code in code tags (see Code button above input area).
 
Knute Snortum
Sheriff
Posts: 4288
127
Chrome Eclipse IDE Java Postgres Database VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi marc, and Welcome to the Ranch.

As Norm said, please post your complete code here and UseCodeTags (that's a link).  Pastbin.com is spammy -- and the problem might be elsewhere in your program.
 
marc lee
Greenhorn
Posts: 5
Chrome Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Wow thanks for the instant replies!

Heres my main:




And the functions class:




Hope this helps

Cheers
Marc
 
Norm Radder
Rancher
Posts: 2240
28
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Can you copy the console's contents from when you execute the program to show what it does?


A suggestion for easier testing:  Preload the Scanner class's constructor with input responses that demonstrate the problem.  For example:
Having the players' inputs in the program will make for much faster debugging.
 
marc lee
Greenhorn
Posts: 5
Chrome Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sure,



working screenshot:


 
Norm Radder
Rancher
Posts: 2240
28
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Can you post a Scanner class's constructor with all the inputs needed for testing?  See my last post.
Several different input series would be useful for the different problems the code is having.


Some questions about the logic:
Should only the last play made be tested to see if it is a winner?
From the last play, the possible winning directions are: to left if there are enough columns to the left, down if enough rows down, to right if enough columns to right.
 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I haven't analyzed your algorithm but I can point out a few things that are making your code more complicated than it needs to be.

First, you have a lot of duplicate code.  In your drawBoard() method, you are also trying to evaluate if there is a winner. Yet, you also have very similar code in your evaluateWinner() method.  This makes your code unfocused. Your drawBoard() method also updates the state of the board.  Again, this is not something you'd expect would be done by a method whose name suggests that its responsibility is to draw the board.

Also, a class named "functions" has a couple of problems: 1. It does not put you in an object-oriented mindset  and 2. It does not follow standard Java naming conventions for classes (class name should start with a capital letter).

I would break down the solution into these subtasks:

1. drawBoard()
2. nextMove(column) - OO-wise, the board can track whose turn it is.
3. hasWinner() - boolean
4. winner() - player name/number of winner, null if none
5. hasFourInRow(String) - see if there is a series of 4 same characters in string
6. hasWinnerInColumn(x)
7. hasWinnerInRow(x)
8. hasWinnerInDiagonal(x) - find some way of numbering diagonals in all possible directions.

Breaking down the problem into smaller problems makes each one more manageable.
 
marc lee
Greenhorn
Posts: 5
Chrome Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks so much guys for the quick replies, I will have a careful look at all of your suggestions soon, I don't have time to do so now right now.

I appreciate the warm welcome!!

cheers
Marc



 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just a clarification about my previous suggestion.  Separating the logic for checking for four marks in a row from the logic of iterating through a column or diagonal or row allows you to reuse logic. That is,


This would be just a start but you might see how you're able to reuse the logic that checks for four marks in a row.
 
marc lee
Greenhorn
Posts: 5
Chrome Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi again


So I tried some of your suggestions, but i can't quite understand how your Methods work(yet).

Just that you know, I just started studying Java couple weeks ago, in school we've covered the OO-process a bit.

I can see the that separating the logic from the iteration is useful, what I don't get is which method does what exactly.

For example: what function does marksInRow(i) have? And where is it defined?


What is the easiest way of searching an Array diagonally? As you can see i made a sequence for every possible diagonal in the array that is at least four chars long. I believe their must be a more convenient way.


Cheers
Marc
 
Norm Radder
Rancher
Posts: 2240
28
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Something to consider when looking for the winning 4 in a row:  Only look from the last play to see if it made the 4 in a row.
 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Norm made a valid point so I will incorporate this idea with this explanation of the purpose of the marksInRow() method I suggested. Keep in mind that these suggestions are just off the top of my head. You'd have to experiment with them to see if they really work as suggested. With experimentation, you see how it really works and you'll be able to decide whether to go with it, tweak it, or abandon it.

That said, the idea behind marksInRow() is to separate the logic for checking for four-of-a-kind from the logic of iterating through a row, column, or diagonal. The findFour() method does not need to know whether the string it checks comes from a row, column, or diagonal. All it cares about is whether there is a series of 4 of the same mark in the string.  The marksInRow() method looks specifically at a given row and builds a String that represents the marks in that row. So, in the graphic you have where Player 2 wins, a call to marksInRow(1) will give back the string "xooxx" which is passed to findFour() which would return a char value that is neither 'x' nor 'o' to indicate that there was no 4-peat series found.  On the other hand, with the same board, a call to marksInDiagonalRight(1) would return "xxxx" and findFour() would return 'x' to signify that four consecutive 'x' characters were found.

Taking Norm's suggestion into consideration, you don't need to iterate over all rows, columns, and diagonals every time a move is made. You just need to look at the column, row, and diagonals where the move was made.
 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Note also that experimentation can help you find names that can make the code more readable and more sensical. For example, I would experiment with renaming findFour() to see what names make the code read better.

I happen to like how the version on line 10 reads. I think it helps explain what the code is doing perfectly.  One thing that I find disappointing in the way students are taught these days is the overemphasis on purely technical things and almost non-existent discussion on things like choosing proper names, readability, organization, and style. Simple things like showing how a good name can make a big difference in the quality of the code is never too advanced for new programmers, IMO.
 
Norm Radder
Rancher
Posts: 2240
28
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
how a good name can make a big difference in the quality of the code 

That statement should be big and bold.
 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
One simplification you can do is to use only one for-loop when traversing diagonally. You can do this because the indices of cells on a diagonal change at the same time.  For example, these index pairs represent one diagonal [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)] and this is an adjacent diagonal: [(1,2), (2,3), (3,4), (4,5), (5,6)]. A for-loop can have multiple index variables of the same type. It can also have multiple increments. Here's what the loop would look like:

You would have to make the initial values of row and col variable instead of hard-coding to 0 but that's the basic idea. To traverse diagonally in a different direction, you simply change the initial values, loop conditions, and either increment or decrement each index variable as appropriate.
 
Campbell Ritchie
Marshal
Posts: 56599
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Haven't been following the whole of this thread, but the complicated nature of the code suggests you haven't completely understood how the game is played. If you watch it being played, you find that it is a variant of noughts and crosses (=tic‑tac‑toe). Nobody says
Oh, look, I had four yellow tokens in a row back there ten moves ago.
No. The players say,
I have just put my yellow token to make a row of four here: I win
You do not need to go through all the board to look for a winning move. You need to look at the most recently‑placed token and see whether that is a winning token. So you need to look left right down and diagonally to SE and SW. All your checking of rows and columns is unnecessary: only sixteen locations need to be checked.

Also: why didn't you create Token objects? Much better than using Strings.
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!