I redid a Python Reversi move preview routine that is online. I could use comments about using Python better and/or better OOP design since the original did not use classes. There are three main classes:
Board for the Reversi board, Location to hold an x,y coordinate (0-7,0-7), and Move to store a location to put a disc on a board and how many discs would be affected by that move. I separated out Move because I would like to keep a sequence of Moves in memory to play forward or reverse. Board knows about where the discs are in a bitfield and knows how to turn over discs and return if a disc is at a location.


    import unittest
    import copy
    from bitarray import bitarray
    
    INITIAL_BOARD = """
    |_|_|_|_|_|_|_|_|
    |_|_|_|_|_|_|_|_|
    |_|_|_|_|_|_|_|_|
    |_|_|_|B|W|_|_|_|
    |_|_|_|W|B|_|_|_|
    |_|_|_|_|_|_|_|_|
    |_|_|_|_|_|_|_|_|
    |_|_|_|_|_|_|_|_|
    """
    
    def other_player(playerId):
        return 'B' if playerId == 'W' else 'W'
    
    class Location:
        def __init__(self,x=0,y=0):
            self.offset = self.convertToOffset(x,y)
            
        def convertToOffset(self,x,y):
            self.invalid = (x < 0 or x > 7 or y < 0 or y > 7)
            return x + y * 8
    
        def translate(self,dx,dy):
            self.invalid = ((self.offset < 8 and dy == -1) or 
                (self.offset > 56 and dy == 1) or
                (self.offset % 8 == 0 and dx == -1) or
                (self.offset % 8 == 7 and dx == 1))
            self.offset = self.offset + dx + dy * 8
    
        def __eq__(self, other):
            if isinstance(other, self.__class__):
                return self.__dict__ == other.__dict__
            else:
                return False
    
        def __ne__(self, other):
            return not self.__eq__(other)
        
    class Board:
        def __init__(self, board=INITIAL_BOARD):
            self.discs = self.parse_board(board)
            
        def make_bitstring(self,board,color_current):
            other_color = other_player(color_current)
            def parse_to_bit(square):
                if square == color_current:
                    return '1'
                elif square == '_' or square == other_color:
                    return '0'
                return ''
            return bitarray(''.join(map(parse_to_bit,board)))
    
        def parse_board(self,board):
             return (self.make_bitstring(board,'B'), self.make_bitstring(board,'W'))
        
        def show(self):
            print self.discs    
            
        def at(self, location, player):
            return not location.invalid and self.discs[int(player=='W')][location.offset]
    
        def empty(self, location):
            return location.invalid or (not self.at (location,'B') and not self.at (location,'W'))
    
        def turnoverDisc(self, location):
            offset = location.offset
            self.discs[0][offset], self.discs[1][offset] = self.discs[1][offset], self.discs[0][offset]
    
        def placeDisc(self, location, player):
            self.discs[int(player=='W')][location.offset] = 1
    
        def __eq__(self, other):
            if isinstance(other, self.__class__):
                return self.__dict__ == other.__dict__
            else:
                return False
    
        def __ne__(self, other):
            return not self.__eq__(other)
    
    class Move:
        def __init__(self, board, location, color_player):    
            self.location = location
            self.player = color_player
            self.board = board
            self.discDelta = self.makeDiscDelta()
            
        def makeDiscDelta(self):
            result = []
            other = other_player(self.player)
            if not self.board.empty(self.location):
                return result
            next_location = Location()
            for dir in [(1,0),(1,-1),(0,-1),(-1,-1),(-1,0),(-1,1),(0,1),(1,1)]:
                next_location.offset = self.location.offset
                next_location.translate(dir[0],dir[1])
                dirDelta = []
                while self.board.at(next_location,other):
                    dirDelta.append(copy.copy(next_location))
                    next_location.translate(dir[0],dir[1])
                if self.board.at(next_location,self.player):
                    result.extend(dirDelta)
            return result
            
        def makeBoard(self):
            result = copy.deepcopy(self.board)
            for location in self.discDelta:
                result.turnoverDisc(location)
            result.placeDisc(self.location,self.player)
            return result

    class ReversiTest(unittest.TestCase):
    
        def testMovePreviewWhite(self):
            board = Board()
            location = Location(4,5)
            move = Move(board,location,'W')        
            self.assertEquals([Location(4,4)], move.discDelta)
    
        def testMovePreviewBlack(self):
            board = Board()
            location = Location(3,2)
            move = Move(board,location,'W')        
            self.assertEquals([Location(3,3)], move.discDelta)
        
        def testMove(self):
            board = Board()
            expected_board = """
                |_|_|_|_|_|_|_|_|
                |_|_|_|_|_|_|_|_|
                |_|_|_|_|_|_|_|_|
                |_|_|_|B|W|_|_|_|
                |_|_|_|W|W|_|_|_|
                |_|_|_|_|W|_|_|_|
                |_|_|_|_|_|_|_|_|
                |_|_|_|_|_|_|_|_|
                """
            expected = Board(expected_board)
            location = Location(4,5)
            move = Move(board,location,'W') 
            result = move.makeBoard()
            self.assertEquals(expected, result)
            self.assertEquals(board, Board())
            self.assertEquals(location, Location(4,5))