Reputation: 658
I'm writing a class for a simple game of 4 in a row, but I'm running into a problem calling a method in the same class. Here's the whole class for the sake of completeness:
class Grid:
grid = None
# creates a new empty 10 x 10 grid
def reset():
Grid.grid = [[0] * 10 for i in range(10)]
# places an X or O
def place(player,x,y):
Grid.grid[x][y] = player
# returns the element in the grid
def getAt(x,y):
return Grid.grid[x][y]
# checks for wins in a certain direction
def checkLine(player,v,count,x,y):
x = x+v[0]
y = y+v[1]
if x < 0 or x > 9:
return
if y < 0 or y > 9:
return
if Grid.grid[x][y] == p:
count = count+1
if count == 4:
return True
checkLine(player,v,count,x,y)
return False
# returns the number of the player that won
def check():
i = 'i'
for x in range(0,10):
for y in range(0,10):
if Grid.grid[x][y] > 0:
p = Grid.grid[x][y]
f = checkLine(p,0,array(i,[1,0]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[0,1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[1,1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[-1,0]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[0,-1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[-1,-1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[1,-1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[-1,1]),x,y)
if f:
return p
return 0
reset = staticmethod(reset)
place = staticmethod(place)
getAt = staticmethod(getAt)
check = staticmethod(check)
checkLine = staticmethod(checkLine)
I'm trying to call checkLine() from check(), but I get the error "NameError: global name 'checkLine' is not defined". When I call Grid.checkLine() instead, I get "TypeError: 'module' object is not callable"
How do I call checkLine()?
EDIT:
@beer_monk
class Grid(object):
grid = None
# creates a new empty 10 x 10 grid
def reset(self):
Grid.grid = [[0] * 10 for i in range(10)]
# places an X or O
def place(self,player,x,y):
Grid.grid[x][y] = player
# returns the element in the grid
def getAt(self,x,y):
return Grid.grid[x][y]
# checks for wins in a certain direction
def checkLine(self,player,v,count,x,y):
x = x+v[0]
y = y+v[1]
if x < 0 or x > 9:
return
if y < 0 or y > 9:
return
if Grid.grid[x][y] == p:
count = count+1
if count == 4:
return True
checkLine(self,player,v,count,x,y)
return False
# returns the number of the player that won
def check(self):
i = 'i'
for x in range(0,10):
for y in range(0,10):
if Grid.grid[x][y] > 0:
p = Grid.grid[x][y]
for vx in range(-1,2):
for vy in range(-1,2):
f = self.checkLine(p,0,array(i,[vx,vy]),x,y)
if f:
return p
return 0
reset = staticmethod(reset)
place = staticmethod(place)
getAt = staticmethod(getAt)
check = staticmethod(check)
checkLine = staticmethod(checkLine)
Upvotes: 7
Views: 26995
Reputation: 1
Java programmer as well here, here is how I got it to call an internal method:
class Foo:
variable = 0
def test(self):
self.variable = 'Hi'
print(self.variable)
def test2(self):
Foo.test(self)
tmp = Foo()
tmp.test2()
Upvotes: 0
Reputation: 625
Syntax:
class_Name.function_Name(self)
Example:
Turn.checkHoriz(self)
Upvotes: 3
Reputation: 956
Instead of operating on an object, you are actually modifying the class itself. Python lets you do that, but it's not really what classes are for. So you run into a couple problems
-You will never be able to make multiple Grids this way
After your grid definition, try instantiating your grid and calling methods on it like this
aGrid = Grid()
...
aGrid.checkLine()
To do that you, you first need to modify all of the method definitions to take "self" as your first variable and in check, call self.checkLine()
def check(self):
...
self.checkLine()
...
Also, your repeated checking cries out for a FOR loop. You don't need to write out the cases.
Upvotes: 0
Reputation: 56694
A reworked example (hopefully showing a better use of classes!)
import itertools
try:
rng = xrange # Python 2.x
except NameError:
rng = range # Python 3.x
class Turn(object):
def __init__(self, players):
self.players = itertools.cycle(players)
self.next()
def __call__(self):
return self.now
def next(self):
self.now = self.players.next()
class Grid(object):
EMPTY = ' '
WIDTH = 10
HEIGHT = 10
WINLENGTH = 4
def __init__(self, debug=False):
self.debug = debug
self.grid = [Grid.EMPTY*Grid.WIDTH for i in rng(Grid.HEIGHT)]
self.player = Turn(['X','O'])
def set(self, x, y):
if self.grid[y][x]==Grid.EMPTY:
t = self.grid[y]
self.grid[y] = t[:x] + self.player() + t[x+1:]
self.player.next()
else:
raise ValueError('({0},{1}) is already taken'.format(x,y))
def get(self, x, y):
return self.grid[y][x]
def __str__(self):
corner = '+'
hor = '='
ver = '|'
res = [corner + hor*Grid.WIDTH + corner]
for row in self.grid[::-1]:
res.append(ver + row + ver)
res.append(corner + hor*Grid.WIDTH + corner)
return '\n'.join(res)
def _check(self, s):
if self.debug: print("Check '{0}'".format(s))
# Exercise left to you!
# See if a winning string exists in s
# If so, return winning player char; else False
return False
def _checkVert(self):
if self.debug: print("Check verticals")
for x in rng(Grid.WIDTH):
winner = self._check([self.get(x,y) for y in rng(Grid.HEIGHT)])
if winner:
return winner
return False
def _checkHoriz(self):
if self.debug: print("Check horizontals")
for y in rng(Grid.HEIGHT):
winner = self._check([self.get(x,y) for x in rng(Grid.WIDTH)])
if winner:
return winner
return False
def _checkUpdiag(self):
if self.debug: print("Check up-diagonals")
for y in rng(Grid.HEIGHT-Grid.WINLENGTH+1):
winner = self._check([self.get(d,y+d) for d in rng(min(Grid.HEIGHT-y, Grid.WIDTH))])
if winner:
return winner
for x in rng(1, Grid.WIDTH-Grid.WINLENGTH+1):
winner = self._check([self.get(x+d,d) for d in rng(min(Grid.WIDTH-x, Grid.HEIGHT))])
if winner:
return winner
return False
def _checkDowndiag(self):
if self.debug: print("Check down-diagonals")
for y in rng(Grid.WINLENGTH-1, Grid.HEIGHT):
winner = self._check([self.get(d,y-d) for d in rng(min(y+1, Grid.WIDTH))])
if winner:
return winner
for x in rng(1, Grid.WIDTH-Grid.WINLENGTH+1):
winner = self._check([self.get(x+d,d) for d in rng(min(Grid.WIDTH-x, Grid.HEIGHT))])
if winner:
return winner
return False
def isWin(self):
"Return winning player or False"
return self._checkVert() or self._checkHoriz() or self._checkUpdiag() or self._checkDowndiag()
def test():
g = Grid()
for o in rng(Grid.WIDTH-1):
g.set(0,o)
g.set(Grid.WIDTH-1-o,0)
g.set(Grid.WIDTH-1,Grid.HEIGHT-1-o)
g.set(o,Grid.HEIGHT-1)
print(g)
return g
g = test()
print g.isWin()
Upvotes: 1
Reputation: 56951
There are multiple problems in your class definition. You have not defined array which you are using in your code. Also in the checkLine call you are sending a int, and in its definition you are trying to subscript it. Leaving those aside, I hope you realize that you are using staticmethods for all your class methods here. In that case, whenever you are caling your methods within your class, you still need to call them via your class's class object. So, within your class, when you are calling checkLine, call it is as Grid.checkLine That should resolve your NameError problem.
Also, it looks like there is some problem with your module imports. You might have imported a Module by name Grid and you have having a class called Grid here too. That Python is thinking that you are calling your imported modules Grid method,which is not callable. (I think,there is not a full-picture available here to see why the TypeError is resulting)
The best way to resolve the problem, use Classes as they are best used, namely create objects and call methods on those objects. Also use proper namespaces. And for all these you may start with some good introductory material, like Python tutorial.
Upvotes: 0
Reputation: 880757
Get rid of the class. Use plain functions and module level variable for grid
.
The class is not helping you in any way.
PS. If you really want to call checkline
from within the class, you'd call Grid.checkline
. For example:
class Foo:
@staticmethod
def test():
print('Hi')
@staticmethod
def test2():
Foo.test()
Foo.test2()
prints
Hi
Upvotes: 12
Reputation: 26281
Unlike java or c++, in python all class methods must accept the class instance as the first variable. In pretty much every single python code ive seen, the object is referred to as self
. For example:
def reset(self):
self.grid = [[0] * 10 for i in range(10)]
See http://docs.python.org/tutorial/classes.html
Note that in other languages, the translation is made automatically
Upvotes: 0