Ok so I'm to create a code in C which outputs all the possible solutions of a board. The board is a nxn board with a row looking like this(3x3): AA BA BB.
The objective of the game is to visit every position in the board by only going vertically or horizontally across the board. Also, you can only go to the next position if the first or second letter is the same so I can go from AA to BA but not from AA to BB and you can only visit each position once. The starting position is always the upper left corner or the 00 position.
Anyway, I thought of an algorithm where the computer starts at 00 and checks the next valid position, let's say 01. Then the computer checks all possible solutions using the chain of 00 and 01 as starting positions. When there's no more, the computer checks a new chain lets say 00, 10 and so on. How do you know not to repeat the previous solutions? I was thinking something with recursion. Are there more efficient path-finding algorithms other than mine?
Re: How do you know not to repeat the previous solutions?
A part of the depth first search algorithm involves marking the visited nodes so as not to visit them twice. This can be done in various ways: spare bits on the nodes themselves, initialized before every search, or a dynamic set data structure external to the graph being searched.
The problem is related to Gray code, by the way, which is a way of arranging the codes of a binary word so that only one bit changes between successive codes. E.g. 000 001 011 010 110 100 101 111.
What this means is that in your board, you can navigate to a neighboring square if and only if it is a two bit Gray code successor or predecessor.
But Gray code forms a sequence. So the problem is isomorphic to one in which there is a simple numbering from 0 to 3, and you are allowed from N to a N+1 successor or N-1 predecessor.
This can help you think about the problem.
Here's a very inefficient solution in Python. You should be able to follow along. I didn't want to just give away the answer in your own language :P
class Finder:
def __init__(self, board, n, x, y):
self.board = board
self.n = n
# Create a copy of the board.
self.copy = []
for i in range(n):
row = []
self.copy += [row]
for j in range(n):
row += [False]
# The best move sequence (longest).
self.best = []
# The current move sequence.
self.move = []
self.find(x, y)
def valid_move(self,x1, y1, x2, y2):
# Don't move off the board!
if x2 < 0 or x2 > self.n - 1 or y2 < 0 or y2 > self.n - 1:
return False
# Don't go somewhere we've gone before!
if self.copy[y2][x2]:
return False
# See if this is a valid move.
a = self.board[y1][x1]
b = self.board[y2][x2]
return a[0] == b[0] or \
a[0] == b[1] or \
a[1] == b[0] or \
a[1] == b[1]
def find(self,x, y):
self.move += [(x, y, board[y][x])]
self.copy[y][x] = True
# If this is the best path, then create a copy.
if len(self.move) > len(self.best):
self.best = list(self.move)
# Short-circuit if the optimal route is found.
if len(self.best) == self.n * self.n:
return
newX = x - 1
newY = y
if self.valid_move(x, y, newX, newY):
self.find(newX, newY)
newX = x
newY = y - 1
if self.valid_move(x, y, newX, newY):
self.find(newX, newY)
newX = x + 1
newY = y
if self.valid_move(x, y, newX, newY):
self.find(newX, newY)
newX = x
newY = y + 1
if self.valid_move(x, y, newX, newY):
self.find(newX, newY)
# Clean up by removing the last move.
self.move = self.move[:-1]
self.copy[y][x] = False
# The board
board = \
[["AB", "XX", "DE"],
["BB", "FE", "DD"],
["BC", "CC", "CD"],
]
# The size of the board.
n = 3
# Find!!
finder = Finder(board, n, 0, 0)
for row in board:
print(row)
# Print empty line.
print()
for move in finder.best:
print(move)
Here's the output:
['AB', 'XX', 'DE']
['BB', 'FE', 'DD']
['BC', 'CC', 'CD']
(0, 0, 'AB')
(0, 1, 'BB')
(0, 2, 'BC')
(1, 2, 'CC')
(2, 2, 'CD')
(2, 1, 'DD')
(2, 0, 'DE')
Related
Given an Array A consisting of N elements and an integer K. You can perform following operations on array any number of times(Can be 0).
Choose an element from array A. Let us denote as A[i]
Choose a positive integer Y.
Change A[i] to A[i] xor Y.
The Sum of all the Y's used in the operations should not be greater than K.
Your task is to find the maximum sum of all the elements of array A after operations.
Example:-
N=5
K=6
A={9,7,7,4,3}
Output:- 36
Explanation:- In the first operation, choose the fourth element and Y=2. Then change 4 to 4 xor 2, that is 6.
the updated array will be:- 9,7,7,6,3
In second Operation, choose the fifth element and Y=4. Then change 3 to 3 xor 4, that is 7.
The updated array will be 9,7,7,6,7
Hence sum is 36.
Please someone explain the logic behind the problem. I am not getting the idea.
Since you didn't clarify my comment about Y I will assume that the answer is no, you can not count unique Y values once towards the budget K.
This problem is simply a modified 0-1 knapsack problem in disguise. To solve it using the knapsack problem:
Let the item value & weight pairs be defined as the set
I = { (Y ^ a - a, Y) : a \in A, Y \in {1,K}}
Apply the dynamic programming solution to the 0-1 knapsack problem with weight limit K, and the requirement that only one item may be picked per a \in A. The total optimal weight of the knapsack problem + any unmodified a \in A is the solution.
Here is an implementation in python that solves the example given.
#!/usr/bin/python
def solve2(w,v,W,nK):
n = len(w)
m = dict()
for j in range(0,W+1):
m[-1, j] = 0
for i in range(-1,n):
m[i, 0] = 0
for i in range(0,n):
for j in range(0,W+1):
b_w = -1
b_v = -1
found = False
for k in range(0,nK):
if w[i][k] <= j and v[i][k] >= b_v:
b_w = w[i][k]
b_v = v[i][k]
found = True
if found:
m[i, j] = max(m[i-1, j], m[i-1, j-b_w] + b_v)
else:
m[i, j] = m[i-1, j]
return m[n-1,W]
A = [9,7,7,4,3]
K = 6
v = [ [ (Y^a)-a for Y in range(1,K+1) ] for a in A]
w = [ [ Y for Y in range(1,K+1) ] for a in A]
print ('Solution value is:', sum(A) + solve2(w,v,K,K))
I came to a solution for this problem, but it takes O(n^2). Is it possible to do better?
Problem: Suppose we want to make change for D dollars. We have an array A with N elements. The denominations exist within the array as dollar values, but we do not know the exact denominations in advanced. However, we are given that 0 < A[j] < 125*N. The restrictions are, we only have 6 of each type of denomination and we must be able to determine if we can give change using exactly 6 total bills (we can repeat bills and assume bills come in any type, so we can have 4$ bills)..
Ex:
If A = [3,4,6,5,20,18,10,30] and D = 50. Then the algorithm returns true since 5+5+5+5+10+20.
My attempts:
I tried sorting and then dividing but then I get stuck because I am not sure how to eliminate possible choices since I do not know exactly what is in the array. Better yet, without explicitly going through in O(n^2) time, I am not sure how to for sure say that it is not possible. Is it possible to take advantage of the fact that I know I am restricted to exactly 6 bills?
To me it looks like a typical recursion problem. Lets write a function that will check if we can make change for the D dollars. For that we will take the first bill (lets say it's $3), remove it from the the D and then recursively check if we can make change for the D - 3 dollars.
We can make this solution much faster if we don't check the combinations that we have already checked. So if we already know that bills 3, 5, 10 don't fit our needs then we don't need to check the combination 5, 10, 3 either. For that we need firstly to sort the A array and then pass the number of last used bill (last_bill_id) to the check function. Inside the function we don't need to check any combinations with bills with number less than last_bill_id.
Full solution in python:
A = [3, 4, 6, 5, 20, 18, 10, 30]
D = 50
def check(counters, current_sum, depth, last_bill_id):
global A
if depth > 6: # max amount of bills is 6
return False
if depth == 6: # we used 6 bill, did we get the correct sum?
return current_sum == 0
if current_sum <= 0: # we gave too much change
return False
# current_sum > 0 and depth < 6
for i in xrange(last_bill_id, len(A)):
if counters[i] < 6:
# we can use i-th bill another time
counters[i] += 1
if check(counters, current_sum - A[i], depth + 1, i):
return True
counters[i] -= 1
return False
# init counters with zeros
counters = [0] * len(A)
# check if we can change for `D`
A = sorted(A) # sort A before the function
print 'Can make change:', check(counters, D, 0, 0)
# print bills with counters
for i, c in enumerate(counters):
if c > 0:
print '$%d x %d' % (A[i], c)
Output:
Can make change: True
$3 x 4
$18 x 1
$20 x 1
EDIT
Previous solution has complexity O(n^6). But actually we can make it even faster with memoization (or, we put it in the other way, dynamic programming). Lets sort the A array and repeat every number in it 6 times, so we'll get something like A = [3, 3, 3, 3, 3, 3, 5, 5, ...]. Now lets fill the 3D matrix M[,,], where M[bills_num, i, d] is true iff we can make change for the d dollars with bills_num bills starting in i-th position of the A array. The result will be in the cell M[6, 0, D]. This matrix has size 6 x (6 * n) x D, so we can fill it in O(6 * (6 * n) * D) == O(n * D) time (with the recursive approach similar to the solution before). Code in python:
A = [3, 4, 6, 5, 20, 18, 10, 30]
D = 50
# sort A and repeat 6 times
A = sorted(A * 6)
# create matrix M, where:
# 0 == uncomputed, 1 == True, -1 == False
arr1d = lambda x: [0] * x
arr2d = lambda x, y: [arr1d(y) for i in xrange(x)]
arr3d = lambda x, y, z: [arr2d(y, z) for i in xrange(x)]
M = arr3d(6 + 1, len(A), D + 1)
def fill_m(bills_num, start_pos, d):
global A, M
if d == 0: # can make change for 0 only with 0 bills
return True if bills_num == 0 else False
if d < 0 or bills_num <= 0 or start_pos >= len(A):
return False
if M[bills_num][start_pos][d] == 0:
# need to compute cell value
if fill_m(bills_num, start_pos + 1, d):
M[bills_num][start_pos][d] = 1
elif fill_m(bills_num - 1, start_pos + 1, d - A[start_pos]):
M[bills_num][start_pos][d] = 1
else:
M[bills_num][start_pos][d] = -1
return M[bills_num][start_pos][d] == 1
print 'Can make change for $', D, fill_m(6, 0, D)
Let us assume that we have 2 sorted arrays A and B of integers and a given interval [L,M] . If x is an element of A and y an element of B ,our task is to find all pairs of (x,y) that hold the following property: L<=y-x<=M.
Which is the most suitable algorithm for that purpose?
So far ,I have considered the following solution:
Brute force. Check the difference of all possible pairs of elements with a double loop .Complexity O(n^2).
A slightly different version of the previous solution is to make use of the fact that arrays are sorted by not checking the elements of A ,once difference gets out of interval .Complexity would still be O(n^2) but hopefully our program would run faster at an average case.
However ,I believe that O(n^2) is not optimal .Is there an algorithm with better complexity?
Here is a solution.
Have a pointer at the beginning of each array say i for array A and j for array B.
Calculate the difference between B[j] and A[i].
If it is less than L, increment the pointer in array B[], i.e increment j by 1
If it is more than M, increment i, i.e pointer of A.
If the difference is in between, then do the following:
search for the position of an element whose value is B[j]-A[i]-L or the nearest
element whose value is lesser than (B[j]-A[i])-L in array A. This
takes O(logN) time. Say the position is p. Increment the count of
(x,y) pairs by p-i+1
Increment only pointer j
My solution only counts the number of possible (x,y) pairs in O(NlogN) time
For A=[1,2,3] and B=[10,12,15] and L=12 and M=14, answer is 3.
Hope this helps. I leave it up to you, to implement the solution
Edit: Enumerating all the possible (x,y) pairs would take O(N^2) worst case time. We will be able to return the count of such pairs (x,y) in O(NlogN) time. Sorry for not clarifying it earlier.
Edit2: I am attaching a sample implementation of my proposed method below:
def binsearch(a, x):
low = 0
high = len(a)-1
while(low<=high):
mid = (low+high)/2
if a[mid] == x:
return mid
elif a[mid]<x:
k = mid
low = low + mid
else:
high = high - mid
return k
a = [1, 2, 3]
b = [10, 12, 15, 16]
i = 0
j = 0
lenA = len(a)
lenB = len(b)
L = 12
M = 14
count = 0
result = []
while i<lenA and j<lenB:
if b[j] - a[i] < L:
j = j + 1
elif b[j] - a[i] > M:
i = i + 1
else:
p = binsearch(a,b[j]-L)
count = count + p - i + 1
j = j + 1
print "number of (x,y) pairs: ", count
Because it's possible for every combination to be in the specified range, the worst-case is O([A][B]), which is basically O(n^2)
However, if you want the best simple algorithm, this is what I've come up with. It starts similarly to user-targaryen's algorithm, but handles overlaps in a simplistic fashion
Create three variables: x,y,Z and s (set all to 0)
Create a boolean 'success' and set to false
Calculate Z = B[y] - A[x]
if Z < L
increment y
if Z >= L and <= M
if success is false
set s = y
set success = true
increment y
store x,y
if Z > M
set y = s //this may seem inefficient with my current example
//but you'll see the necessity if you have a sorted list with duplicate values)
//you can just change the A from my example to {1,1,2,2,3} to see what I mean
set success = false
an example:
A = {1,2,3,4,5}
B = {3,4,5,6,7}
L = 2, M = 3
In this example, the first pair is x,y. The second number is s. The third pair is the values A[x] and B[y]. The fourth number is Z, the difference between A[x] and B[y]. The final value is X for not a match and O for a match
0,0 - 0 - 1,3 = 2 O
increment y
0,1 - 0 - 1,4 = 3 O
increment y
0,2 - 0 - 1,5 = 4 X
//this is the tricky part. Look closely at the changes this makes
set y to s
increment x
1,0 - 0 - 2,3 = 1 X
increment y
1,1 - 0 - 2,4 = 2 O
set s = y, set success = true
increment y
1,2 - 1 - 2,5 = 3 O
increment y
1,3 - 1 - 2,6 = 4 X
set y to s
increment x
2,1 - 1 - 3,4 = 1 X
increment y
2,2 - 1 - 3,5 = 2 O
set s = y, set success = true
increment y
2,3 - 2 - 3,6 = 3 O
... and so on
I have a 3-dimensional array. Think of it as a brick. There are 24 possible rotations of this brick (that keep its edges parallel to coordinate axes). How do I generate all corresponding 3-dimensional arrays?
A die (half a pair of dice) is handy for observing the 24 different orientations, and can suggest operation sequences to generate them. You will see that any of six faces can be uppermost, and the sides below can be rotated into four different cardinal directions. Let us denote two operations: “turn” and “roll”, where turn rotates the die about the z axis from one cardinal to the next, and roll rotates the die 90° away from you, so the away-face becomes the bottom face and the near face the top. These operations can be expressed using rotation matrices as mentioned in the answer of Felipe Lopes, or can be expressed as simple functions that when given (x,y,z) return (-y,x,z) or (x,z,-y), respectively.
Anyhow, if you place the die with 1 on the near face, 2 at right, and 3 on top, you will find that the following sequence of steps generates the twelve different orientations with 1, 2, or 3 spots on top: RTTTRTTTRTTT. Then the sequence RTR exposes 6, 4, 5 where 1, 2, 3 originally were, and a repeat of the sequence RTTTRTTTRTTT generates the twelve orientations with 4, 5, or 6 spots on top. The mentioned sequence is embedded in the following python code.
def roll(v): return (v[0],v[2],-v[1])
def turn(v): return (-v[1],v[0],v[2])
def sequence (v):
for cycle in range(2):
for step in range(3): # Yield RTTT 3 times
v = roll(v)
yield(v) # Yield R
for i in range(3): # Yield TTT
v = turn(v)
yield(v)
v = roll(turn(roll(v))) # Do RTR
p = sequence(( 1, 1, 1))
q = sequence((-1,-1, 1))
for i in sorted(zip(p,q)):
print i
The rationale for printing out a sorted list of transformed pairs of points is twofold: (i) any face orientation can be specified by the locations of two of its corners; (ii) it then is easy to check for uniqueness of each pair, eg by piping output to uniq.
Here is how the sorted output begins:
((-1, -1, -1), (-1, 1, 1))
((-1, -1, -1), (1, -1, 1))
((-1, -1, -1), (1, 1, -1))
((-1, -1, 1), (-1, 1, -1))
((-1, -1, 1), (1, -1, -1))
((-1, -1, 1), (1, 1, 1))
((-1, 1, -1), (-1, -1, 1))
((-1, 1, -1), (1, -1, -1))
((-1, 1, -1), (1, 1, 1))
Let X rotate 90 degrees around the X-axis and Y rotate 90 degrees around the Y-axis then the 24 possible unique combinations are (all possible combinations up to 5 rotations are given except those with four times the same rotation (eg XXXX, XXXXY XYYYY, etc):
1. I
2. X
3. Y
4. XX = YXXY
5. XY
6. YX
7. YY = XYYX
8. XXX = XYXXY = YXXYX = YXYXY = YYXYY
9. XXY = YXXYY = YYYXX
10. XYX = YXY
11. XYY = XXYYX = YYXXX
12. YXX = XXYYY = YYXXY
13. YYX = XXXYY = XYYXX
14. YYY = XXYXX = XYXYX = XYYXY = YXYYX
15. XXXY
16. XXYX = XYXY = YXYY
17. XXYY = YYXX
18. XYXX = YXYX = YYXY
19. XYYY
20. YXXX
21. YYYX
22. XXXYX = XXYXY = XYXYY = YXYYY
23. XYXXX = YXYXX = YYXYX = YYYXY
24. XYYYX = YXXXY
Of course you can use any two 90 degree rotations in place of the X and Y. For example, Y and Z.
Or, if you also use Z, a 90 degree rotation around the Z axis then 4 rotations suffice:
1. I
2. X = YXZ
3. Y = ZYX
4. Z = XZY
5. XX = XYXZ = YXXY = YXYZ = YXZX = YYZZ = YZXZ = ZXXZ = ZZYY
6. XY = YZ = ZX = XZYX = YXZY = ZYXZ
7. XZ = XXZY = YXZZ = YYYX = ZYYY
8. YX = XZZZ = YYXZ = ZYXX = ZZZY
9. YY = XXZZ = XYYX = YZYX = ZXYX = ZYXY = ZYYZ = ZYZX = ZZXX
10. ZY = XXXZ = XZYY = YXXX = ZZYX
11. ZZ = XXYY = XYZY = XZXY = XZYZ = XZZX = YYXX = YZZY = ZXZY
12. XXX
13. XXY = XYZ = XZX = YZZ = ZXZ
14. XXZ = ZYY
15. XYX = YXY = YYZ = YZX = ZXX
16. XYY = YZY = ZXY = ZYZ = ZZX
17. XZZ = YYX
18. YXX = ZZY
19. YYY
20. ZZZ
21. XXXY = XXYZ = XXZX = XYZZ = XZXZ = YZZZ = ZXZZ = ZYYX
22. XXYX = XYXY = XYYZ = XYZX = XZXX = YXYY = YYZY = YZXY = YZYZ = YZZX = ZXXY = ZXYZ = ZXZX = ZYZZ = ZZXZ
23. XYXX = XZZY = YXYX = YYXY = YYYZ = YYZX = YZXX = ZXXX
24. XYYY = YXXZ = YZYY = ZXYY = ZYZY = ZZXY = ZZYZ = ZZZX
These 24 matrices all exist of three column vectors that each exist of two zeroes and a minus one or plus one. On every row there are also exactly two zeroes. As such, they can easily be generated: the first column vector has six possibilities ((1,0,0), (-1,0,0), (0,-1,0), (0,1,0), (0,0,-1) and (0,0,1)), this corresponds to moving the positive X-axis to the positive or negative x, y or z axis. The second column vector only has four possibilities because it must contain a zero where the first column has a non-zero value. Finally the third column vector has only one place left where its plus or minus one can be. This gives 6 * 4 * 2 = 48 matrices, half of them mirror the original as well however (they are combination of a mirror and optionally a rotation). Hence only 24 are pure rotations. The matrices that are mirror operations will have a determinant equal to -1, the determinant of the pure rotations is 1.
James Waldby's answer is inspiring, and I want to add a slightly improved version with only two for-loops.
We know that there are 24 unique orientations. I calculated this by imagining a dice: there are 6 possible choices for the top face, and 4 possible rotations for each face on top.
What if we iterate with that idea? I thought. If we can figure out a way to travel all 6 faces of the dice, then we only need to observe the 4 rotations on each face, and we are done!
So I grabbed the nearest "brick" (in my case, a Vitasoy carton) and started rotating to see what would be the easiest pattern to visit all 6 faces. If we introduce an additional counter-clockwise turn, such that our operations are:
Roll (in a fixed direction, e.g. so that the face facing you is now rotated downwards)
Turn CW (along a fixed axis, e.g. so that the face facing you is turned clockwise, but still facing you)
Turn CCW (along the same axis as the last one)
Then we can visit all faces by doing:
Roll -> Turn CW -> Roll -> Turn CCW -> Roll -> Turn CW -> Roll -> Turn CCW -> Roll -> Turn CW -> Roll -> Turn CCW
With the last roll and turn, we are back to the original orientation. As you can see, it is a repeated sequence of roll + alternating CW turns and CCW turns.
Now, if we expand this to include all rotations of each face we visit, this becomes:
Roll -> 3x Turn CW -> Roll -> 3x Turn CCW -> Roll -> 3x Turn CW -> Roll -> 3x Turn CCW -> Roll -> 3x Turn CW -> Roll -> 3x Turn CCW
...and we are back to where we started! This can be translated into two for-loops (one fewer!):
def sequence(m):
for roll_index in range(6):
m = roll(m)
yield(m)
for turn_index in range(3):
m = turn_cw(m) if roll_index % 2 == 0 else turn_ccw(m)
yield(m)
You can use rotation matrices. Rotating a 3D array around the x-axis means that the element at position (i,j,k) will be mapped to position (i,-k,j). Of course, if your array is 0-indexed, you probably have to replace -k with size-1-k or something like that.
Similarly, rotating around the y-axis maps (i,j,k) to (k,j,-i). These two rotations can be represented as matrices. For the x-axis rotation:
|i'| |1 0 0| |i|
|j'| = |0 0 -1|*|j|
|k'| |0 1 0| |k|
And for the y-axis rotation:
|i'| |0 0 1| |i|
|j'| = |0 1 0|*|j|
|k'| |-1 0 0| |k|
Any general rotation can be described as a sequence of those two rotations. Applying two rotations consecutively is just multiplying the 3x3 matrices. So, if you find all possible products of them, you'd get 24 matrices (including the identity), each one corresponds to a valid rotation of your array. It's a little tricky to find all possible multiplications, because they don't commute.
I think you can just brute-force all products of the form (A^p)*(B^q)*(A^r)*(B^s), where A and B are the two matrices before and p,q,r,s are their powers, and range from 0 to 3 (exponentiating A or B to 4 will take them back to the identity matrix).
Doing it this way, you can generate all 24 valid rotation matrices, and rotate the 3D array using each one of them, taking the care to shift the negative indexes so that you don't access out of bounds.
import numpy as np
def rotations(array):
for x, y, z in permutations([0, 1, 2]):
for sx, sy, sz in itertools.product([-1, 1], repeat=3):
rotation_matrix = np.zeros((3, 3))
rotation_matrix[0, x] = sx
rotation_matrix[1, y] = sy
rotation_matrix[2, z] = sz
if np.linalg.det(rotation_matrix) == 1:
yield np.matmul(rotation_matrix, array)
all_rotations = list(rotations(np.array(array)))
Idea is to generate all coordinates relabelings with possible axis' direction changes, ex. (-z, y, x). The question that remains is whether all coordinates relabelings are obtainable from (x, y, z) axes using only rotations. Half of the 6 * (2^3) = 48 labelings aren't because they are rotations of a mirrored version of the (x, y, z) cooridnates (left-handed coordinates, https://en.wikipedia.org/wiki/Right-hand_rule).
Rows of the corresponding rotation matrix A of relabeling operation will have only one value in each row. The value determines which axis to select on that index, and whether to flip the axis.
A * (x, y, z) = (-z, y, x)
| 0, 0, -1 |
A = | 0, 1, 0 |
| 1, 0, 0 |
We keep only those rotations, whose det(A) == 1 meaning that only rotations were applied by the operation. det(A) == -1 means that it is a rotation with mirroring.
So i m trying to make hexagonal grid in C for a game. I am really dumb founded on where to start on it. ANyone have any ideas.
EDIT: I need about 15-20 hexagons in a grip shape all joined,something like a game board. for a game i m working on. Sorry for not being clear
Absolutely. Despite their odd shape, hexagons can still be contained in your usual multidimensional array, for future use (I assume you'll want to put things in your hexagons). As for drawing them, it's simple. Sum of angles = (6 - 2) * 180 = 4 * 180 = 720. One angle is 720 / 6 = 120 degrees. Calculate first the leftmost angle's Y position, which is equal to √(hexagonSide - hexagonWidth * hexagonWidth). I'm sure you can figure out hexagonWidth, right? Okay, now the X position relative to the last one will be 0. You'll need to offset the Y position by half the height of the hexagon before it, up or down depending on whether row * col is even or odd. Since you know the hexagon's width you have the coordinates of the opposite angle. Rotate by 120° and repeat.
Before I continue, is this supposed to be in the console? Or is it real graphics?
So let's get this straight, the game will be played on the console? Right, well now you will need to set up your data structures, the most obvious is with nodes.
The nodes
Each hexagon is a node with six edges.
typedef struct Node {
void *object; /* Pointer to object */
Node *node_array; /* Pointer to node_array with 'node_count' nodes */
int node_count; /* size of node_array */
} Node;
How to initialize and connect the node structure
Imagine the following hexagon:
/\
| |
\/
It has the following edges, NORTHEAST, EAST, SOUTHEAST, SOUTHWEST, WEST and NORTHWEST. Next observe how they will be arranged (10, 11 and 12 were represented in Hex so that they can fit in one space):
// 0 1 2 3
// 4 5 6 7 8
// 9 A B C
So 0 will link to 5 through it's SOUTHEAST link, and 4 through it's SOUTHWEST link. Also notice how the rows alternate between odd and even numbers of elements. Let's call {0, 1, 2, 3} row[0], and {4, 5, 6, 7, 8} row[1]. And let's call this a 5x3 hexmap. The easiest way to create this array is with malloc(sizeof(Node) * width * height).
Connecting the nodes
First of all let me point out that every even row (0, 2, 4, ...) will have width-1 elements. But there's more, each element (x, y) on this row will link to the following element in your array:
(x+1, y-1) - NORTHEAST
(x+1, y) - EAST
(x+1, y+1) - SOUTHEAST
(x, y+1) - SOUTHWEST
(x-1, y) - WEST
(x, y-1) - NORTHWEST
Elements on the other rows, such as {4, 5, 6, 7, 8} will have width elements, where element (x, y) links to the following:
(x, y-1) - NORTHEAST
(x+1, y) - EAST
(x, y+1) - SOUTHEAST
(x-1, y+1) - SOUTHWEST
(x-1, y) - WEST
(x-1, y-1) - NORTHWEST
When trying to link (x1,y1) with (x2, y2), ensure that 0 <= x < width and 0 <= y < height.
Remember ...
Your array contains one unused element at the end of every two rows (row[0], row[2], etc.). Also you might want to provide them all with some sort of label or index so that you can refer the player to them. You could label them as (x,y) pairs, or numerically by their index, it's all up to you. The (x, y) pair is very easy for you since that will map directly to the array they are stored in.