2

I have a chess board array that looks like this:

00 01 02 03 04 05 06 07
08 09 10 11 12 13 14 15
16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31
32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47
48 49 50 51 52 53 54 55
56 57 58 59 60 61 62 63

Now I'm trying to find a function of position, a number on the board, that gives me the second to last number in the up/right diagonal, e.g. for 60, I'm trying to find 38, for 30, I'm trying to find 22. I could hard code the damn thing, but it'd really be nicer to find a function that does this. So far it's stumped me.

I haven't had problems with the down/right and diagonal and up/left diagonals, but this one is stumping me. Any help is appreciated.

Below follows the code I'm working on:

# EightQueens.py
# Joshua Marshall Moore
# thwee.abacadabra.alchemist@gmail.com
# June 24th, 2017

# The eight queens problem consists of setting up eight queens on a chess board
# so that no two queens threaten each other. 

# This is an attempt to find all possible solutions to the problem. 

# The board is represented as a set of 64 numbers each representing a position 
# on the board. Array indexing begins with zero. 

# 00 01 02 03 04 05 06 07
# 08 09 10 11 12 13 14 15
# 16 17 18 19 20 21 22 23
# 24 25 26 27 28 29 30 31
# 32 33 34 35 36 37 38 39
# 40 41 42 43 44 45 46 47
# 48 49 50 51 52 53 54 55
# 56 57 58 59 60 61 62 63

# Test:
# The following combination should yield a True from the check function.

# 6, 9, 21, 26, 32, 43, 55, 60

from itertools import combinations
import pdb

# works
def down_right_boundary(pos):
    boundary = (8-pos%8)*8
    applies = (pos%8)+1 > int(pos/8)
    if applies:
        return boundary
    else:
        return 64

# works
def up_left_boundary(pos):
    boundary = ((int(pos/8)-(pos%8))*8)-1
    applies = (pos%8) <= int(pos/8)
    if applies:
        return boundary
    else:
        return -1

def up_right_boundary(pos):
    boundary = [7, 15, 23, 31, 39, 47, 55, 62][pos%8]-1
    # 7: nil
    # 14:  7-1
    # 15: 15-1
    # 21:  7-1
    # 22: 15-1
    # 23: 23-1
    # 28:  7-1
    # 29: 15-1
    # 30: 23-1
    # 31: 31-1
    # 35:  7-1
    # 36: 15-1
    # 37: 23-1
    # 38: 31-1
    # 39: 39-1
    # 42:  7-1
    # 43: 15-1
    # 44: 23-1
    # 45: 31-1
    # 46: 39-1

    applies = pos%8>=pos%7
    if applies:
        return boundary
    else:
        return -1

def down_left_boundary(pos):
    boundary = 64
    applies = True
    if applies:
        return boundary
    else:
        return 64

def check(positions):

    fields = set(range(64))
    threatened = set()

    # two queens per quadrant
    quadrants = [
        set([p for p in range(0, 28) if (p%8)<4]),
        set([p for p in range(4, 32) if (p%8)>3]),
        set([p for p in range(32, 59) if (p%8)<4]),
        set([p for p in range(36, 64) if (p%8)>3])
    ]

    #for q in quadrants:
    #   if len(positions.intersection(q)) != 2:
    #       return False

    # check the queen's ranges
    for pos in positions:

        pdb.set_trace()

        # threatened |= set(range(pos, -1, -8)[1:]) # up
        # threatened |= set(range(pos, 64, 8)[1:]) # down
        # threatened |= set(range(pos, int(pos/8)*8-1, -1)[1:]) # left
        # threatened |= set(range(pos, (int(pos/8)+1)*8, 1)[1:]) # right

        # down right diagonal:
        # There are two conditions here, one, the position is above the
        # diagonal, two, the position is below the diagonal.
        # Above the diagonal can be expressed as pos%8>int(pos/8).
        # In the event of a position above the diagonal, I need to limit the 
        # range to 64-(pos%8) to prevent warping the board into a field that 
        # connects diagonals like Risk. 
        # Otherwise, 64 suffices as the ending condition. 
        threatened |= set(range(pos, down_right_boundary(pos), 9)[1:]) # down right

        print(pos, threatened)
        pdb.set_trace()
        #

        # up left diagonal:
        # Similarly, if the position is above the diagonal, -1 will suffice as 
        # the range's ending condition. Things are more complicated if the
        # position is below the diagonal, as I must prevent warping, again. 
        threatened |= set(range(pos, up_left_boundary(pos), -9)[1:]) # up left

        print(pos, threatened)
        pdb.set_trace()
        #

        # up right diagonal:
        # Above the diagonal takes on a different meaning here, seeing how I'm
        # dealing with the other diagonal. It is defined by pos58>pos%7. Now I
        # restrict the range to a (pos%8)*8, creating a boundary along the right
        # side of the board. 
        threatened |= set(range(pos, up_right_boundary(pos), -7)[1:]) # up right

        print(pos, threatened)
        pdb.set_trace()
        #

        # down left diagonal:
        # I reuse a similar definition to that of the diagonal as above. The 
        # bound for left hand side of the board looks as follows: 
        # ((pos%8)*7)+(pos%8)
        threatened |= set(range(pos, down_left_boundary(pos), 7)[1:]) # down left

        print(pos, threatened)
        pdb.set_trace()
        # 

    if len(positions.intersection(threatened)) > 0:
        return False

    return True


if __name__ == '__main__':

    # print(check(set([55]))) # pass
    # print(check(set([62]))) # pass
    # print(check(set([63]))) # pass
    # print(check(set([48]))) # pass
    # print(check(set([57]))) # pass
    # print(check(set([56]))) # pass
    # print(check(set([8])))  # pass

    # print(check(set([1])))  # fail
    # print(check(set([0])))
    # print(check(set([6])))
    # print(check(set([15])))
    # print(check(set([7])))

    # print(check(set([6])))
    # print(check(set([9])))
    print(check(set([21])))
    print(check(set([26])))
    print(check(set([32])))
    print(check(set([43])))
    print(check(set([55])))
    print(check(set([60])))





    print(
        check(set([6, 9, 21, 26, 32, 43, 55, 60]))
    )

    # for potential_solution in combinations(range(64), 8):
        # is_solution = check(set(potential_solution))
        # if is_solution:
            # print(is_solution, potential_solution)
4castle
  • 32,613
  • 11
  • 69
  • 106
Joshua M. Moore
  • 381
  • 6
  • 20
  • 1
    Can you please show some code? It's not clear what you've tried and what you're stuck on. I'm also not sure I understand the inputs and outputs of your desired function. 60 isn't on the same diagonal line as 38. – 4castle Jun 28 '17 at 22:14
  • 60 isn't one the same diagonal line as 38. I'm looking for the number that comes before the last item on the diagonal line. – Joshua M. Moore Jun 28 '17 at 23:22
  • It'll be used in a range function, thus the one before the diagonal. – Joshua M. Moore Jun 28 '17 at 23:30

1 Answers1

1

Using the following chessboard positions:

chessboard =    [0,1,2,3,4,5,6,7,
                8,9,10,11,12,13,14,15,
                16,17,18,19,20,21,22,23,
                24,25,26,27,28,29,30,31,
                32,33,34,35,36,37,38,39,
                40,41,42,43,44,45,46,47,
                48,49,50,51,52,53,54,55,
                56,57,58,59,60,61,62,63]

I wrote a function that corresponds to what you want (comments describe code):

def return_diagonal(position):    # with position being chessboard position

    while ((position+1)%8) != 0:  # while (chess position)+1 is not divisible by eight:
            position -= 7         # move diagonally upwards (7 chess spaces back)

    position -= 1                 # when reached the right end of the chessboard, move back one position

    if position < 6:              # if position happens to be in the negative:
        position = 6              # set position by default to 6 (smallest possible value)

    return position               # return the position

The function first asks whether the position is in the last column.

If not, go back 7 spaces, which is going diagonally upwards-right.

And it checks again until it arrives at the last column.

There, it goes back one space, so that it is one space from the left of the right end of the chessboard.

However, if this number is in the negative (as it is for many numbers in the top-left), this means that the diagonal fully extends beyond the 8x8 chessboard.

So, by default, the answer should be 6.

I gave a couple of tests

print(60,return_diagonal(60))
print(30,return_diagonal(30))
print(14,return_diagonal(14))
print(1,return_diagonal(1))

With the following output:

Original position, the second to last number in the up/right diagonal

60 38
30 22
14 6
1 6
Larry
  • 1,312
  • 2
  • 15
  • 22
  • @JoshuaMoore I think I've found a workable solution. If there are any things to clarify, please feel free to reply to this comment. Thanks! – Larry Jun 29 '17 at 01:45
  • 1
    Thanks for the answer. It's so simple I could kick myself. I guess I was hoping for a "pythonic" of solving this, but your way works great, thank you! – Joshua M. Moore Jun 29 '17 at 02:02