programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
• Campbell Ritchie
• Jeanne Boyarsky
• Ron McLeod
• Paul Clapham
• Liutauras Vilda
Sheriffs:
• paul wheaton
• Rob Spoor
• Devaka Cooray
Saloon Keepers:
• Stephan van Hulst
• Tim Holloway
• Carey Brown
• Frits Walraven
• Tim Moores
Bartenders:
• Mikalai Zaikin

# Connect four Problem

Greenhorn
Posts: 5
• Number of slices to send:
Optional 'thank-you' note:
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.

Cheers
Bleichiful

Rancher
Posts: 5008
38
• Number of slices to send:
Optional 'thank-you' note:
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).

Sheriff
Posts: 7125
184
• Number of slices to send:
Optional 'thank-you' note:
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
• Number of slices to send:
Optional 'thank-you' note:
Wow thanks for the instant replies!

Heres my main:

And the functions class:

Hope this helps

Cheers
Marc

Rancher
Posts: 5008
38
• Number of slices to send:
Optional 'thank-you' note:
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
• Number of slices to send:
Optional 'thank-you' note:
Sure,

working screenshot:

Rancher
Posts: 5008
38
• Number of slices to send:
Optional 'thank-you' note:
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.

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.

Sheriff
Posts: 17652
300
• Number of slices to send:
Optional 'thank-you' note:
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
• Number of slices to send:
Optional 'thank-you' note:
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: 17652
300
• Number of slices to send:
Optional 'thank-you' note:
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
• Number of slices to send:
Optional 'thank-you' note:
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

Rancher
Posts: 5008
38
• Number of slices to send:
Optional 'thank-you' note:
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: 17652
300
• Number of slices to send:
Optional 'thank-you' note:
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: 17652
300
• Number of slices to send:
Optional 'thank-you' note:
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.

Rancher
Posts: 5008
38
• Number of slices to send:
Optional 'thank-you' note:

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: 17652
300
• Number of slices to send:
Optional 'thank-you' note:
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.

Marshal
Posts: 79392
377
• Number of slices to send:
Optional 'thank-you' note:
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.