IndexError: string index out of range for Conway's game of life tutorial - conways-game-of-life

I am following a tutorial (from https://automatetheboringstuff.com/2e/chapter4/) for a text-based version of Conway's game of life, and i have put it exactly like the tutorial says and it still produces an IndexError:
the error message is as follows:
print(currentCells[x][y], end='')
IndexError: string index out of range
my goal is to place a blank space while the cells are 'alive' (meeting certain requirements) and a # when they are 'dead' (meeting other requirements)
im confused why the tutorial even when i copy directly from it, gets it wrong. the tutorial is for python 3.8
the entire block of code is as follows:
while True:
print('\n\n\n\n\n')
currentCells = copy.deepcopy(nextCells)
for y in range(HEIGHT):
for x in range(WIDTH):
print(currentCells[x][y], end='')
print()
for x in range(WIDTH):
for y in range(HEIGHT):
leftCoord = (x - 1) % WIDTH
rightCoord = (x + 1) % WIDTH
aboveCoord = (y - 1) % HEIGHT
belowCoord = (y + 1) % HEIGHT
numNeighbors = 0
if currentCells[leftCoord][aboveCoord] == '#':
numNeighbors += 1
if currentCells[x][aboveCoord] == '#':
numNeighbors += 1
if currentCells[rightCoord][aboveCoord] == '#':
numNeighbors += 1
if currentCells[leftCoord][y] == '#':
numNeighbors += 1
if currentCells[rightCoord][y] == '#':
numNeighbors += 1
if currentCells[leftCoord][belowCoord] == '#':
numNeighbors += 1
if currentCells[x][aboveCoord] == '#':
numNeighbors += 1
if currentCells[rightCoord][belowCoord] == '#':
numNeighbors += 1
if currentCells[x][y] == '#' and (numNeighbors == 2 or numNeighbors == 3):
nextCells[x][y] = '#'
elif currentCells[x][y] == ' ' and numNeighbors == 3:
nextCells[x][y] = '#'
else:
nextCells[x][y] = ' '
time.sleep(1)
i'm new to coding so i tried commenting out the lines but of course that just renders the other parts that use those functions unusable. also the other questions on this topic seem to be about much more advanced versions of this game. like i said this is one of my first programs.

I'm too new to programming in Python! It's great language to learn:-)
Anyway I think I found the problem with the code. There is small mistake...
If you look at line 25, it says 'nextCells is a list of column list'.
So instead of appending empty string is should be:
line 25: nextCells.append(column)

Related

Why did index go out of range

Hello i'm doing the simple FizzBuzz challenge. I figured out a solution to the problem. But I don't understand why my first attempt went out of range or what is happening behind the scenes.
To stop it from going out of range I changed
array.remove(at: i)
to
array.remove(at: i - 1)
Below is my entire project.
First attempt
var array = [String]()
for i in 1...100{
array.append("\(i)")
if i % 3 == 0 && i % 5 == 0 {
array.remove(at: i)
array.append("FizzBuzz")
}else if i % 3 == 0{
array.remove(at: i)
array.append("Fizz")
} else if i % 5 == 0{
array.remove(at: i)
array.append("Buzz")
}
}
print(array)
Second attempt
var array = [String]()
for i in 1...100{
array.append("\(i)")
if i % 3 == 0 && i % 5 == 0 {
array.remove(at: i - 1 )
array.append("FizzBuzz")
}else if i % 3 == 0{
array.remove(at: i - 1)
array.append("Fizz")
} else if i % 5 == 0{
array.remove(at: i - 1)
array.append("Buzz")
}
}
print(array)
Because arrays are zero index and you're starting at 1 in your for loop, so when you get to three and try to retrieve the third element (which indicates they're four elements in the array) swift will throw an error. The simple solution will be to start at 0
for i in 0...100{
print(i)
array.append("\(i)")
if i % 3 == 0 && i % 5 == 0 {
array.remove(at: i)
array.append("FizzBuzz")
}else if i % 3 == 0{
array.remove(at: i)
array.append("Fizz")
} else if i % 5 == 0{
array.remove(at: i)
array.append("Buzz")
}
}
print(array)
}
The remove(at:) function removes the element at the specified position. For example, if I have an array like [1,2,3,4] and I call array.remove(at: 2) the resulting array would be [1,2,4].
It is important to understand that the function removes the element at the specified INDEX location. Not the values itself. Swift arrays are zero indexed meaning, the first element is at location 0.
Now with this knowledge, I suggest you go ahead and debug your first code with some print statements and you be able to quickly understand why your code is going out of range. Hopefully through this experiment you can understand some basic concepts.
Good luck!
You are saying
for i in 1...100{
But array indices start at 0. So on every loop the item you just added has index i-1. There is no item with index i yet.
To put it another way, consider this part of your code:
if i % 3 == 0 && i % 5 == 0 {
array.remove(at: i)
Here you are prevaricating on the meaning of i. In the first line, it is what number i is. But in the second line, it is what index i is at. And because you started with 1, those two numbers are apart by 1. For example, the first time thru the loop, i is 1, but the value 1 is at index 0.

Displaying multiple values in for statement in Swift

Hi I am new to programming. I apologize beforehand if this is a stupid question, but I'm learning about For loops. The below is an example code I understand. I know how to write a basic For loop that iterates through a single variable in each loop, but how do I use a For loop to display multiple values in one loop. Example:
let treeArray = ["Pine", "Oak", "Yew", "Maple", "Birch", "Myrtle"]
for tree in treeArray {
print(tree)
}
I want to be able to print three variables in one loop so the code would print
Pine Oak Yew on one line
Maple Birch Myrtle and on the next
Instead of
Pine
Oak
Yew
Maple
Birch
Myrtle
Thanks!
You could use .enumerated() to pair the index with the element and then print(_:terminator:) using index % 3 to select the appropriate terminator (newline "\n" or space " "):
let treeArray = ["Pine", "Oak", "Yew", "Maple", "Birch", "Myrtle"]
for (index, tree) in treeArray.enumerated() {
print(tree, terminator: index % 3 == 2 ? "\n" : " ")
}
Output:
Pine Oak Yew
Maple Birch Myrtle
The general case: printing n items per line
In general, for printing n items per line:
print(tree, terminator: index % n == n - 1 ? "\n" : " ")
or equivalently:
print(tree, terminator: (index + 1) % n == 0 ? "\n" : " ")
If you want the last item to always be followed by a newline, then add an addition check for that:
print(tree, terminator: index % n == n - 1 || index == treeArray.endIndex - 1 ? "\n" : " ")
Use an array to store trees and
joined(separator: String)
on array to stitch them together.
let treeArray = ["Pine", "Oak", "Yew", "Maple", "Birch", "Myrtle"]
var treeNames = [String]()
for (count, tree) in treeArray.enumerated() {
treeNames.append(tree)
if ((count + 1) % 3) == 0 {
let treeLine = treeNames.joined(separator: " ")
print(treeLine)
treeNames.removeAll()
}
}

Why is my code returning 0? And not the numbers of Upper and Lower characters?

I'm trying to code that calculates how many upper and lower characters in a string. Here's my code.
I've been trying to convert it to string, but not working.
def up_low(string):
result1 = 0
result2 = 0
for x in string:
if x == x.upper():
result1 + 1
elif x == x.lower():
result2 + 1
print('You have ' + str(result1) + ' upper characters and ' +
str(result2) + ' lower characters!')
up_low('Hello Mr. Rogers, how are you this fine Tuesday?')
I expect my outcome to calculate the upper and lower characters. Right now I'm getting "You have 0 upper characters and 0 lower characters!".
It's not adding up to result1 and result2.
Seems your error is in the assignation, missimg a '=' symbol (E.g. result1 += 1)
for x in string:
if x == x.upper():
result1 += 1
elif x == x.lower():
result2 +**=** 1
The problem is in the line result1 + 1 and result2 + 1. This is an expression, but not an assignment. In other words, you increment the counter, and then the incremented value goes nowhere.
The solution is to work the assignment operator = into there somewhere.

stress centrality in social network

i got the error of this code which is:
path[index][4] += 1
IndexError: list index out of range
why this happened?how can i remove this error ?
Code:
def stress_centrality(g):
stress = defaultdict(int)
for a in nx.nodes_iter(g):
for b in nx.nodes_iter(g):
if a==b:
continue
pred = nx.predecessor(G,b) # for unweighted graphs
#pred, distance = nx.dijkstra_predecessor_and_distance(g,b) # for weighted graphs
if a not in pred:
return []
path = [[a,0]]
path_length = 1
index = 0
while index >= 0:
n,i = path[index]
if n == b:
for vertex in list(map(lambda x:x[0], path[:index+1]))[1:-1]:
stress[vertex] += 1
if len(pred[n]) >i:
index += 1
if index == path_length:
path.append([pred[n][i],0])
path_length += 1
else:
path[index] = [pred[n][i],0]
else:
index -= 1
if index >= 0:
path[index][4] += 1
return stress
Without the data it's hard to give you anything more than an indicative answer.
This line
path[index][4] += 1
assumes there are 5 elements in path[index] but there are fewer than that. It seems to me that your code only assigns or appends to path lists of length 2. As in
path = [[a,0]]
path.append([pred[n][i],0])
path[index] = [pred[n][i],0]
So it's hard to see how accessing the 5th element of one of those lists could ever be correct.
This is a complete guess, but I think you might have meant
path[index][1] += 4

speed up prime number generating

I have written a program that generates prime numbers . It works well but I want to speed it up as it takes quite a while for generating the all the prime numbers till 10000
var list = [2,3]
var limitation = 10000
var flag = true
var tmp = 0
for (var count = 4 ; count <= limitation ; count += 1 ){
while(flag && tmp <= list.count - 1){
if (count % list[tmp] == 0){
flag = false
}else if ( count % list[tmp] != 0 && tmp != list.count - 1 ){
tmp += 1
}else if ( count % list[tmp] != 0 && tmp == list.count - 1 ){
list.append(count)
}
}
flag = true
tmp = 0
}
print(list)
Two simple improvements that will make it fast up through 100,000 and maybe 1,000,000.
All primes except 2 are odd
Start the loop at 5 and increment by 2 each time. This isn't going to speed it up a lot because you are finding the counter example on the first try, but it's still a very typical improvement.
Only search through the square root of the value you are testing
The square root is the point at which a you half the factor space, i.e. any factor less than the square root is paired with a factor above the square root, so you only have to check above or below it. There are far fewer numbers below the square root, so you should check the only the values less than or equal to the square root.
Take 10,000 for example. The square root is 100. For this you only have to look at values less than the square root, which in terms of primes is roughly 25 values instead of over 1000 checks for all primes less than 10,000.
Doing it even faster
Try another method altogether, like a sieve. These methods are much faster but have a higher memory overhead.
In addition to what Nick already explained, you can also easily take advantage of the following property: all primes greater than 3 are congruent to 1 or -1 mod 6.
Because you've already included 2 and 3 in your initial list, you can therefore start with count = 6, test count - 1 and count + 1 and increment by 6 each time.
Below is my first attempt ever at Swift, so pardon the syntax which is probably far from optimal.
var list = [2,3]
var limitation = 10000
var flag = true
var tmp = 0
var max = 0
for(var count = 6 ; count <= limitation ; count += 6) {
for(var d = -1; d <= 1; d += 2) {
max = Int(floor(sqrt(Double(count + d))))
for(flag = true, tmp = 0; flag && list[tmp] <= max; tmp++) {
if((count + d) % list[tmp] == 0) {
flag = false
}
}
if(flag) {
list.append(count + d)
}
}
}
print(list)
I've tested the above code on iswift.org/playground with limitation = 10,000, 100,000 and 1,000,000.