string indices must be integers Battle ships codewars kata - python

Im getting this error when inputting my code in codewars. "Traceback:in module
in damaged_or_sunk
IndexError: list index out of range". However, when I try my code in spyder3, it works just fine. there are no indicators as to where this error is in the function damaged_or_sunk though.
def damaged_or_sunk (board, attacks):
a = sum(x.count(1) for x in board)
b = sum(x.count(2) for x in board)
c = sum(x.count(3) for x in board)
a1 = 0
b1 = 0
c1 = 0
points = 0
sunk = 0
damaged = 0
not_touched = 0
for each in attacks:
rand_row = each[0]
rand_col = each[1]
if board[rand_row][rand_col] == 1:
a1 += 1
elif board[rand_row][rand_col] == 2:
b1 += 1
elif board[rand_row][rand_col] == 3:
c1 += 1
else:
pass
if a1 == a:
points += 1
sunk += 1
elif a1 == 0:
points -= 1
not_touched += 1
else:
points += 0.5
damaged += 1
if b1 == b:
points += 1
sunk += 1
elif b1 == 0:
points -= 1
not_touched += 1
else:
points += 0.5
damaged += 1
if c1 == c:
points += 1
sunk += 1
elif c1 == 0:
points -= 1
not_touched += 1
else:
points += 0.5
damaged += 1
return '{\'sunk\': %s, \'damaged\': %s, \'not_touched\': %s, \'points\': %s}' %(sunk, damaged, not_touched, points)

The couples in attacks contains (x, y) coordinates which must be list index.
I make the assumption that they are randomly generated, make sure that:
0 <= x < len(board[0])
0 <= y < len(board)
all( len(board[0]) == len(board[row]) for row in board)

Related

operating function in another function

I'm trying to operate 50/50 player win/lose game based on random.sample([0,1],1).
def player_win():
global player_win_count
player_win_count += 1
return player_win_count
def player_lose():
global dealer_win_count
dealer_win_count += 1
return dealer_win_count
def game_draw():
draw_game_count += 1
return draw_game_count
def gameplay():
i = 0
while i <= 300:
test01 = random.sample([0,1],1)
i += 1
if test01 == 1:
player_win()
else:
player_lose()
print("player_win",player_win_count)
print("dealer_win",dealer_win_count)
gameplay()
The 'random.sample' code works fine, but instead of expected result, it returns
player_win 0
dealer_win 301
what's wrong with my code?
random.sample will return a list of the samples so test01 == 1 is always False.
Example:
In [181]: random.sample([0, 1], 1)
Out[181]: [1]
In [182]: random.sample([0, 1], 1)
Out[182]: [0]
In [183]: random.sample([0, 1], 1)
Out[183]: [1]
In [184]: random.sample([0, 1], 1)
Out[184]: [0]
One solution is test01[0] == 1.
Alternatively, one could use random.choices instead and generate all the flips at once:
In [188]: wins = 0
...: losses = 0
...: for flip in random.choices([0, 1], k=20):
...: if flip:
...: wins += 1
...: else:
...: losses += 1
In [189]: print(wins, losses)
7 13
As #salt-die has noted, random.sample() is designed to return a sample of the population and does so as a list.
To achieve the intended result, you could substitute random.choice() for random.sample(), which will return a single selection from the population:
def gameplay():
i = 0
while i <= 300:
test01 = random.choice([0,1]) # use random.choice()
i += 1
if test01 == 1:
player_win()
else:
player_lose()
print("player_win",player_win_count)
print("dealer_win",dealer_win_count)
If for some reason, you are required to use random.sample(), then you can use the following modification to select the first element out of the list of sample results:
while i <= 300:
test01 = random.sample([0,1], 1)[0] # use list indexing to get
# the zeroeth item from the list
Lastly, as a point of style:
It is sometimes considered Pythonic to simply test for truthiness/falsiness and thus this code could be refined a bit, if desired:
while i <= 300:
i += 1
if random.choice([0, 1]): # A `1` is considered equivalent to True
# in Python, so we can skip setting the value
# of test01 to being either 1 OR 0 and
# simply return a 1 or 0 into the if statement.
Best practice in Python is to avoid global scopes so something like this is better if you really had to use a function.
import random
def _counter(count: int):
count += 1
return count
def gameplay():
draw_game_count = 0
dealer_win_count = 0
player_win_count = 0
for i in range(300):
test01 = random.randint(0, 2)
if test01 == 0:
draw_game_count = _counter(draw_game_count)
elif test01 == 1:
player_win_count = _counter(player_win_count)
else:
dealer_win_count = _counter(dealer_win_count)
print("draw", draw_game_count)
print("player_win", player_win_count)
print("dealer_win", dealer_win_count)
if __name__ == "__main__":
gameplay()
Otherwise you could simply do this:
import random
def gameplay():
draw_game_count = 0
dealer_win_count = 0
player_win_count = 0
for i in range(300):
test01 = random.randint(0, 2)
if test01 == 0:
draw_game_count += 1
elif test01 == 1:
player_win_count += 1
else:
dealer_win_count += 1
print("draw", draw_game_count)
print("player_win", player_win_count)
print("dealer_win", dealer_win_count)
if __name__ == "__main__":
gameplay()

Issues with final output

Expected Output :
I was working on the functions to get the code for elementary cellular automaton. I got all the outputs correct but I could not get my desired output printed.
def main():
N= int(input("Enter number of steps,N:"))
C= int(input("Enter number of cells,C:"))
i_list=list(map(int,input("Enter the indices of occupied cells (space-separated):").split()))
cell= [0]*C
for i in i_list:
cell[int(i)] = 1
displayCells(cell)
for step in range(N):
newCells = updateCells(cell)
displayCells(newCells)
cells = []
cells += newCells # concatenates new state to new list
def displayCells(Cells):
for cell in Cells:
if cell == 1:
print("#", end='')
def updateCells(cells):
nc = [] # makes a new empty list
nc += cells # copy current state into new list
for a in range(1, len(nc)-1):
if nc[a-1] == 1 and nc[a] == 1 and nc[a+1] == 1:
nc[a] = 0
elif nc[a-1] == 1 and nc[a] == 1 and nc[a+1] == 0:
nc[a] = 1
elif nc[a-1] == 1 and nc[a] == 0 and nc[a+1] == 1:
nc[a] = 1
elif nc[a-1] == 1 and nc[a] == 0 and nc[a+1] == 0:
nc[a] = 0
elif nc[a-1] == 0 and nc[a] == 1 and nc[a+1] == 1:
nc[a] = 1
elif nc[a-1] == 0 and nc[a] == 1 and nc[a+1] == 0:
nc[a] = 1
elif nc[a-1] == 0 and nc[a] == 0 and nc[a+1] == 1:
nc[a] = 1
else:
nc[a] = 0
return nc
main()
I expect the output to be the loop that follows the rule of updateCells function and draw the # whenever the program sees 1.

Python matrix is resetting outside of function

I'm trying to build a system to randomly generate ship positions for a basic battleship game. To represent the grid I'm using nested list. However once the function has finished the matrix appears to revert back to what it was before I ran the function.
As you can see by running this code, the whole matrix works as intended when printed within the function but afterwards not. It's my first program I've tried building on my own and I've never gotten stuck for this long before. Thanks
import random
row, column = 10, 10;
Matrix = [[0 for x in range(row)] for y in range(column)]
ships = {'battleship':5, 'cruiser':4,'destroyer':3}
any_left = 1
def position_ship(type):
row, column = 10, 10;
Matrix = [[0 for x in range(row)] for y in range(column)]
ship_size_to_assign = type
start_pointV = 5 ### random.randint(0,10)
start_pointH = 5 ### random.randint(0,10)
start_point_direction = 1 ###random.randint(0,4)
print start_pointV
print start_pointH
print start_point_direction
start_point_direction = 1
if start_point_direction == 1:
n = 0
if (start_pointV + type) <= 10:
while ship_size_to_assign != 0:
Matrix[(start_pointH-1)][(start_pointV+n-1)] = 1
print "----------"
print Matrix[(start_pointH-1)][(start_pointV+n-1)]
print "----"
n = n + 1
ship_size_to_assign = ship_size_to_assign - 1
if start_point_direction == 2:
print "/////"
n = 0
if (start_pointH + type) <= 10:
while ship_size_to_assign != 0:
Matrix[start_pointH+n-1][start_pointV-1] = 1
n = n + 1
ship_size_to_assign = ship_size_to_assign - 1
if start_point_direction == 3:
print "/////"
n = 0
if (start_pointV - type) > 0:
while ship_size_to_assign != 0:
Matrix[start_pointH-1][start_pointV-n-1] = 1
n = n + 1
ship_size_to_assign = ship_size_to_assign - 1
if start_point_direction == 4:
print "/////"
n = 0
if (start_pointH - type) > 0:
while ship_size_to_assign != 0:
Matrix[start_pointH-1][start_pointV+n-1] = 1
n = n + 1
ship_size_to_assign = ship_size_to_assign - 1
print "####"
print Matrix[0]
print Matrix[1]
print Matrix[2]
print Matrix[3]
print Matrix[4]
print Matrix[5]
print Matrix[6]
print Matrix[7]
print Matrix[8]
print Matrix[9]
position_ship(5)
print "/////"
print Matrix[0]
print Matrix[1]
print Matrix[2]
print Matrix[3]
print Matrix[4]
print Matrix[5]
print Matrix[6]
print Matrix[7]
print Matrix[8]
print Matrix[9]

Simulations in Evolutionary Biology - too many loops?

At the moment, I managed to code, successfully, a simulation for a work that I need to do. However, I'm fairly new to python. And so, I'm now in the process of making the simulation more efficient.
For instance:
if random.random() < mm:
z = numpy.random.choice(pat)
if random.random() < 0.5:
if random.random() < mut:
if maleadult[z][0] == 0:
malejuv[y][x][0] = 1
elif maleadult[z][0] == 1:
malejuv[y][x][0] = 0
else:
malejuv[y][x][0] = maleadult[z][0]
else:
if random.random() < mut:
if femaleadult[z][0] == 0:
malejuv[y][x][0] = 1
elif femaleadult[z][0] == 1:
malejuv[y][x][0] = 0
else:
malejuv[y][x][0] = femaleadult[z][0]
if random.random() < 0.5:
if random.random() < mut:
if maleadult[z][1] == 0:
malejuv[y][x][1] = 1
elif maleadult[z][1] == 1:
malejuv[y][x][1] = 0
else:
malejuv[y][x][1] = maleadult[z][1]
else:
if random.random() < mut:
if femaleadult[z][1] == 0:
malejuv[y][x][1] = 1
elif femaleadult[z][1] == 1:
malejuv[y][x][1] = 0
else:
malejuv[y][x][1] = femaleadult[z][0]
where:
mm - male dispersal,
mf - female dispersal,
mut - mutations,
pat - patch,
maleadult - adult male,
femaleadult - adult female,
malejuv - juvenile male,
femalejuv - juvenile female.
As you can see, the code is big. And this is only for males and when they disperse. The rest of the code is very similar. These are standard genetic and demographic processes - but I feel like this can be improved. I feel like these processes are simple enough, so maybe code as big as this is not necessary.
Does anyone have any ideas to shorten this and, by consequence, making it more efficient?
Your example does not have any loops but it looks like it could be simplified by one:
if random.random() < mm:
z = numpy.random.choice(pat)
for i in range(2):
if random.random() < 0.5:
if random.random() < mut:
if maleadult[z][i] == 0:
malejuv[y][x][i] = 1
elif maleadult[z][i] == 1:
malejuv[y][x][i] = 0
else:
malejuv[y][x][i] = maleadult[z][i]
else:
if random.random() < mut:
if femaleadult[z][i] == 0:
malejuv[y][x][i] = 1
elif femaleadult[z][i] == 1:
malejuv[y][x][i] = 0
else:
malejuv[y][x][i] = femaleadult[z][i]
It is also possible to pass a mutable object as reference to a function which can modify it, which allows further reduction of almost redundant code. I've added some data to test it:
#!python3
#coding=utf-8
import random
maleadult = [[["male adult"], ["another male adult"], ]]
femaleadult = [[["female adult"], ["another female adult"], ]]
malejuv = [[[["male juv"],["another male juv"]]]]
mut = 0.5
mm = 1.0
x = 0
y = 0
z = 0
def some_logic(a, j):
""" does something """
if random.random() < mut:
if a[z][i] == 0:
j[y][x][i] = 1
elif a[z][i] == 1:
j[y][x][i] = 0
# added!
else:
j[y][x][i] = 0
else:
j[y][x][i] = a[z][i]
if random.random() < mm:
z = 0 #numpy.random.choice(pat)
for i in range(2):
print(i)
if random.random() < 0.5:
some_logic(maleadult, malejuv)
else:
some_logic(femaleadult, malejuv)
print(maleadult)
print(malejuv)
print(femaleadult)

Error in return in trace function

I am trying to perform dynamic programming for approximate pattern matching in this code.Once the matrix is created,I am trying to trace back to my answer using the function trace.But when I run the program,the trace function is not returning any result and the program isn't getting terminated.
class Structure :
def __init__(self):
self.vertical =[]
self.horizontal =[]
self.diagnol=[]
def merge(self, s):
for i in s.vertical :
self.vertical.append(i)
for i in s.horizontal :
self.horizontal.append(i)
for i in s.diagonal:
self.diagonal.append(i)
def __str__(self):
return "horizontal \n"+str(self.horizontal) +"\n vertical \n"+str(self.vertical)+"\n diagonal"+str(self.diagonal)
def posList(pattern, text): #determine the positions in the matrix
retList = list()
textList = [x for x in text.strip()]
for i, char1 in enumerate(pattern):
textPos = [j for j, char2 in enumerate(textList) if char1==char2]
for j in textPos:
retList.append((i+1,j+1))
return retList
def trace(M,text,pattern,k) :
positions=posList(pattern,text)
struct = Structure()
for i in range(0,2):
for j in range(0,7):
while M[i,j]<=k and M[2,j]!=0:
if M[i,j] == M[i,j-1]+1:
struct.horizontal.append(j)
j -= 1
elif M[i,j] == M[i-1,j]+1:
struct.vertical.append(i)
i -= 1
elif (i+1,j+1)in positions and M[i,j]==M[i-1,j-1] :
struct.diagonal.append((i,j))
i -= 1
j -= 1
elif (i+1,j+1) not in positions and M[i,j]==M[i-1,j-1]+1 and M[i,j]==M[i-1,j]+1:
struct.vertical.append(i)
i-=1
print "error"
elif (i+1,j+1) not in positions and M[i,j]==M[i-1,j-1]+1 and M[i,j]==M[i,j-1]+1:
struct.horizontal.append(j)
j-=1
elif M[i,j]==M[i-1,j]+1 and M[i,j]==M[i,j-1]+1:
struct.vertical.append(i)
elif M[i,j]==M[i-1,j]+1 and M[i,j]==M[i,j-1]+1 and M[i,j]==M[i-1,j-1]+1:
struct.vertical.append(i)
i-=1
else :
pass
return struct
text='ACAGCAG'
pattern='GC'
n = len(pattern)
m = len(text)
text1=list(text)
pattern1=list(pattern)
M = [[0 0 0 0 0 0 0 0],[1 1 1 1 0 1 1 0],[2 2 1 2 1 0 1 1]]
#perform traceback
s= trace(M,text,pattern,1)
print s
s = trace(M, w, seq, max, 0, n-1)
print str(s)
print seq
result=real_string(s)
print "".join(result)
Can anyone suggest me where I maybe going wrong in the function ?

Categories

Resources