Related
I am working in Python. I want to make a function that takes two values: maxSum and n. The output should be all the n-tuples of non-negative integers that add up to maxSum or less. For example, if maxSum is 2 and n is three, the output should be:
[[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 1, 0], [0, 1, 1], [0, 2, 0], [1, 0, 0], [1, 0, 1], [1, 1, 0], [2, 0, 0]]
For any given value of n, I can do it, just by going through n for-loops. For example, if n is 3, I can simply do:
result = []
for i in range(maxSum + 1):
for j in range(maxSum + 1 - i):
for k in range(maxSum + 1 - i - j):
tuple = [i, j, k]
result.insert(len(result), tuple)
return result
But in the above example, I have typed the three for-loops by hand. That is not what I want. I want to be able to make a function that works for any n, that is, a function tupleGenerator(maxSum, n) that generates all such n-tuples. The problem is, I am unable to change the number of for-loops in the function based on the input n.
Sorry don't have enough rep yet to comment, but here's a solution from math stackexchange
https://math.stackexchange.com/questions/2410399/how-to-find-all-the-n-tuples-with-nonnegative-integers-that-add-up-to-a-fixed-in
In particular Ocean Wong's answer, which includes a recursive Python solution (last answer on the page).
EDIT: slightly revised answer to include code as OP requested.
def stars_and_bars(num_objects_remaining, num_bins_remaining, filled_bins=()):
"""
The Stars and Bars (https://en.wikipedia.org/wiki/Stars_and_bars_(combinatorics)) problem can be thought of as
1. Putting m-1 bars ("|") in amongst a row of n stars
OR
2. Putting n balls into m bins.
This program lists all the possible combinations by doing so.
"""
if num_bins_remaining > 1:
# case 1: more than one bins left
novel_arrangement = [] # receptacle to contain newly generated arrangements.
for num_distributed_to_the_next_bin in range(0, num_objects_remaining + 1):
# try putting in anything between 0 to num_objects_remaining of objects into the next bin.
novel_arrangement.extend(
stars_and_bars(
num_objects_remaining - num_distributed_to_the_next_bin,
num_bins_remaining - 1,
filled_bins=filled_bins + (num_distributed_to_the_next_bin,),
)
# one or multiple tuple enclosed in a list
)
return novel_arrangement
else:
# case 2: reached last bin. terminate recursion.
# return a single tuple enclosed in a list.
return [
filled_bins + (num_objects_remaining,),
]
result = []
n = 3
for i in range(maxSum + 1):
result.extend(stars_and_bars(i, n))
print(result)
Python provides the itertools module that you can leverage for this:
maxSum, n = 2, 3
p1 = it.combinations_with_replacement(range(n), n)
p2 = filter( lambda m: sum(m) <= maxSum, p1 )
p3 = it.chain.from_iterable(it.permutations(p) for p in p2)
p4 = list(set(list(p3)))
sorted(p4)
This should be much easier on the memory consumption. You should print each step (for example print(list(p1))) to understand what each step is doing. That is easier to understand than anything that I will write in text here.
I've tried posting this question onto other websites and I have received, lightly to say, little to no feedback that helps.
This is the question at hand: Image Here
The code is asking to divide the numbers in a 2d array by 3, and if they're not divisible by 3, then return them to a 0 in the array.
This is the current code I have:
a = [[34,38,50,44,39],
[42,36,40,43,44],
[24,31,46,40,45],
[43,47,35,31,26],
[37,28,20,36,50]]
#print it
def PrintIt(x):
for r in range(len(x)):
for c in range(len(x[0])):
print(x[r][c], end = " ")
print("")
#is supposed to divide and return the sum. but does not
def divSUM(x):
sum = 3
for r in range(len(x)):
for c in range(len(x[0])):
sum = x[r][c] % 3
if sum != 0:
return 0
return sum
divSUM(a)
The divide (divSUM) returns as nothing. and I'm unsure if numpy would work, every time I try it says its outdated so I assume it doesn't. Any help would be nice, but I'm mainly having issues with putting the undivisble by 3 numbers to a 0.
When return is run, the function is stopped. You can append all the values to a list and return that.
Try this:
a = [[34,38,50,44,39],
[42,36,40,43,44],
[24,31,46,40,45],
[43,47,35,31,26],
[37,28,20,36,50]]
#print it
def PrintIt(x):
for r in x:
for c in r:
print(c, end = " ")
print()
def divSUM(x):
sum = 3
output = []
for r in x:
tmp_lst = []
for c in r:
sum = c % 3
if sum != 0:
tmp_list.append(0)
else:
tmp_list.append(sum)
output.append(tmp_lst)
return output
print(divSUM(a))
(What I understood is that if the number % 3 == 0 you let the same number otherwise you put 0.)
I propose to work with numpy it's easy to do it in a simple line :
import numpy as np
a = np.array([[34,38,50,44,39],
[42,36,40,43,44],
[24,31,46,40,45],
[43,47,35,31,26],
[37,28,20,36,50]])
result = np.where(a%3 ==0, a, 0)
>>>result
array([[ 0, 0, 0, 0, 39],
[42, 36, 0, 0, 0],
[24, 0, 0, 0, 45],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 36, 0]])
Otherwise, the problem with your code is that you wrongly choose the place where to put return.
So, you have to do this:
def divSUM(x):
result = []
for r in x:
tmp = []
for c in r:
if c % 3 != 0:
tmp.append(0)
else:
tmp.append(c)
result.append(tmp)
return result
For instance, given list [1, 0, 1] the code would return [1,1,0]. Other examples:
[1,1,1] -- > [1,0,0,0]
[1,0,0,1] --> [1,0,1,0]
I'm having most trouble understanding what my base case for recursion would be and then how to implement for the (n-1) case.
def increment_helper(number):
newNum = []
if len(number) ==1:
if number[0] == 1:
carry = 1
newNum.append(0)
else:
carry = 0
newNum.append(1)
else:
return increment_helper(number-1)
return newNum
So I'm sure that there are a lot of errors in here specifically how I am calling my recursion because I am not sure how to recurse on the list while storing the number that is removed somehow. The else return statement is obviously incorrect but I am using that as a placeholder. I am unsure of what condition to use as my base case for incrementation. I think I should be using a carry variable that keeps track of whether I am carrying a one over but other than that I am stuck on how to proceed.
Ah, ha! Okay, you have some idea of what you're doing. The basic outline is
Base case: how do I know when I'm done?
You're done when you run out of digits. number should be a list of individual digits; check its length to figure out when not to recur.
Recursion case: what next?
The general concept of recursion is "do something simple, reduce the problem by a small amount, and recur with the smaller problem." Your job in this part is to do the addition for one digit. If you need to keep going (is there a carry from that digit?), then recur. Otherwise, you have all the info you need to finish.
Specific application
Your recursion step will involve calling increment_helper with one digit less: not number - 1, but number[:-1].
After you return from each recursion, you'lll then want to append the digit you just finished. For instance, if you're incrementing 1101, your first call will see that the right-hand one, incremented, has a carry. The new digit is 0, and you have to recur. Hold onto the 0 for a moment, call yourself with 110, and get the result of that call. Append your saved 0 to that, and return to your main program.
Does that get you moving?
This one is "tricky" because you have two things going at each step:
what is the current number I'm looking at? (binary question 0/1)
should it be incremented? (do we have carry?) (binary question yes/no)
This leads to 4 cases.
There is the extra "case" of did we even get a list but it isn't that interesting.
So I would describe it as follows:
if not carry:
# technically meaningless so just return the entire list immediately
return list
# we have "carry", things will change
if not list:
# assumes [] == [0]
return [1]
if list[0]:
# step on `1` (make it 0 and carry)
return [0] + increment(rest_of_list)
# step on `0` (make it 1 and no more carry)
return [1] + rest_of_list
I strongly advise to change lists to tuples and work with these.
Also note that the recursion is on the reversed list, so apply as follows:
def increment_helper(lst, carry):
if not carry:
return lst
if not lst:
return [1]
if lst[0]:
return [0] + increment_helper(lst[1:], True)
return [1] + lst[1:]
def increment(lst):
# long but really just reverse input and output
return increment_helper(lst[::-1], True)[::-1]
I used some shortcuts by returning lists immediately (short-circuiting), but you can make it more "pure" by carrying on the recursion even without carry.
Another recursive approach.
Is the current input an empty list?
If yes return [1]
If no, continue
Is the sum (value) of the last element in the list and 1 greater than 1?
If so recursively call your function on the list without the last element (number_list[:-1]) and append [0] to the result.
If no, set the last element of the list to the sum.
Return the number_list
Code:
def increment_helper(number_list):
if not number_list:
return [1]
value = number_list[-1] + 1
if value > 1:
number_list = increment_helper(number_list[:-1]) + [0]
else:
number_list[-1] = value
return number_list
Example output:
numbers = [[1, 0, 1], [1,1,1], [1,0,0,1]]
for n in numbers:
print("%r ---> %r" % (n, increment_helper(n)))
#[1, 0, 1] ---> [1, 1, 0]
#[1, 1, 1] ---> [1, 0, 0, 0]
#[1, 0, 0, 1] ---> [1, 0, 1, 0]
Try this:
def add1(listNum):
if listNum.count(0):
oneArr = [[0] * (len(listNum) - 1)] + [1]
sumArr = []
for i in range(len(listNum)):
sumArr.append(sum(listNum[i], oneArr[i]))
newArr = []
for j in range(len(sumArr) - 1):
if sumArr[len(sumArr) - 1 - j] < 2:
newArr.insert(0, sumArr[len(sumArr) - 1 - j])
else:
newArr.insert(0, 1)
sumArr[len(sumArr) - 1 - j] += 1
return sumArr
else:
return [1] + [[0] * len(listNum)]
There aren't many reasons for using recursion for a program as simple as this, which is why I have chosen to provide a non-recursive solution.
In case it interests you, I've calculated the time complexity of this function and it is O(n).
It may be best to use two functions: one to check if a simple increment of the last position would suffice and another to perform the recursion should the previous attempt fail:
vals = [[1, 0, 1], [1,1,1], [1,0,0,1]]
def update_full(d):
if all(i in [1, 0] for i in d):
return d
start = [i for i, a in enumerate(d) if a > 1]
return update_full([1]+[0 if i > 1 else i for i in d] if not start[0] else [a+1 if i == start[0] -1 else 0 if i == start[0] else a for i, a in enumerate(d)])
def increment(d):
if not d[-1]:
return d[:-1]+[1]
return update_full(d[:-1]+[2])
print(list(map(increment, vals)))
Output:
[[1, 1, 0], [1, 0, 0, 0], [1, 0, 1, 0]]
You can treat the (binary) digits recursively by traversing the number from tail to head (just like addition works).
Before performing the recursion you have to check for two special cases:
No increment at the current digit is to be performed. Then just return the unmodified digits.
A single digit remains (you're at the head of the number). Then you possibly need to append the overflow to the head.
For the remaining cases you can increment the current digit and treat all digits before the current one in a recursive manner.
def bin_incr(n, incr=True):
if not incr:
return n
if len(n) == 1:
return [1, 0] if n[0] == 1 else [1]
return (
# `n[-1] == 1` denotes an overflow to the next digit.
bin_incr(n[:-1], n[-1] == 1)
+ [(n[-1] + 1) % 2]
)
I understand you don't want to use decimal addition, but if you must use big endian bit order, converting back to decimal first is probably the most practical. Otherwise, you end up with unnecessary reverse calls or awkward negative array indices
def binary (dec): # big endian bit order
if dec < 2:
return [ dec ]
else:
return binary (dec >> 1) + [ dec & 1 ]
def decimal (bin, acc = 0):
if not bin:
return acc
else:
return decimal (bin[1:], (acc << 1) + bin[0])
def increment (bin):
# sneaky cheat
return binary (decimal (bin) + 1)
for x in range (10):
print (x, binary (x), increment (binary (x)))
# 0 [0] [1]
# 1 [1] [1, 0]
# 2 [1, 0] [1, 1]
# 3 [1, 1] [1, 0, 0]
# 4 [1, 0, 0] [1, 0, 1]
# 5 [1, 0, 1] [1, 1, 0]
# 6 [1, 1, 0] [1, 1, 1]
# 7 [1, 1, 1] [1, 0, 0, 0]
# 8 [1, 0, 0, 0] [1, 0, 0, 1]
# 9 [1, 0, 0, 1] [1, 0, 1, 0]
If however you can represent your binary numbers in little endian bit order, things change. Instead of converting back to decimal, increment can be defined directly as a beautiful recursive function
def binary (dec): # little endian bit order
if dec < 2:
return [ dec ]
else:
return [ dec & 1 ] + binary (dec >> 1)
def increment (bin):
if not bin:
return [1]
elif bin[0] == 0:
return [1] + bin[1:]
else:
return [0] + increment(bin[1:])
for x in range (10):
print (x, binary (x), increment (binary (x)))
# 0 [0] [1]
# 1 [1] [0, 1]
# 2 [0, 1] [1, 1]
# 3 [1, 1] [0, 0, 1]
# 4 [0, 0, 1] [1, 0, 1]
# 5 [1, 0, 1] [0, 1, 1]
# 6 [0, 1, 1] [1, 1, 1]
# 7 [1, 1, 1] [0, 0, 0, 1]
# 8 [0, 0, 0, 1] [1, 0, 0, 1]
# 9 [1, 0, 0, 1] [0, 1, 0, 1]
Aside: converting the little endian representation back to decimal is a little different. I provide this to show that use cases for recursion exist everywhere
def decimal (bin, power = 0):
if not bin:
return 0
else:
return (bin[0] << power) + decimal (bin[1:], power + 1)
This part of the answer gives you cake and allows you to eat it too. You get big endian bit order and a recursive increment that steps through the bits in left-to-right order – You should use either implementation above for a number of reasons, but this aims to show you that even though your problem is complex, it's still possible to think about it recursively. No reverse or arr[::-1] was misused in the making of this function.
def binary (dec): # big endian bit order
if dec < 2:
return [ dec ]
else:
return binary (dec >> 1) + [ dec & 1 ]
def increment (bin, cont = lambda b, carry: [1] + b if carry else b):
if bin == [0]:
return cont ([1], 0)
elif bin == [1]:
return cont ([0], 1)
else:
n, *rest = bin
return increment (rest, lambda b, carry:
cont ([n ^ carry] + b, n & carry))
for x in range (10):
print (x, binary (x), increment (binary (x)))
# 0 [0] [1]
# 1 [1] [1, 0]
# 2 [1, 0] [1, 1]
# 3 [1, 1] [1, 0, 0]
# 4 [1, 0, 0] [1, 0, 1]
# 5 [1, 0, 1] [1, 1, 0]
# 6 [1, 1, 0] [1, 1, 1]
# 7 [1, 1, 1] [1, 0, 0, 0]
# 8 [1, 0, 0, 0] [1, 0, 0, 1]
# 9 [1, 0, 0, 1] [1, 0, 1, 0]
We start by breaking the problem up into smaller parts; n is the first problem, and rest is the rest of the problems. But the key to thinking with continuations (like cont above) is to think big.
In this particular problem, n gets updated based on whether rest gets updated. So we immediately recur on rest and pass a continuation that will receive the result of the subproblem. Our continuation receives the answer to the subproblem b, and whether or not that subproblem results in a carry.
...
else:
n, *rest = bin
return increment (rest, lambda b, carry:
cont ([n ^ carry] + b, n & carry))
The n ^ carry and n & carry expressions determine what the answer to this subproblem is and what the next carry will be. The following truth table shows that ^ and & encodes our answer and next_carry respectively. For example, if n is 0 and carry is 1, the carry can be consumed. The answer will be [1] + the answer to the subproblem and the next carry will be 0.
n carry (answer, next_carry) n ^ carry n & carry
0 0 ([0] + b, 0) 0 0
0 1 ([1] + b, 0) 1 0
1 0 ([1] + b, 0) 1 0
1 1 ([0] + b, 1) 0 1
The base cases are simple. If the subproblem is [0], the answer is [1] and no carry of 0. If the subproblem is [1], then the answer is [0]with a carry of 1
...
if bin == [0]:
return cont ([1], 0)
elif bin == [1]:
return cont ([0], 1)
Lastly, design the default continuation – if the answer to the problem b results in a carry, simply prepend [1] to the answer, otherwise just return the answer.
cont = lambda b, carry: [1] + b if carry else b
You are asking for the increment/successor/next function that will generate a sequence of sequences. Since other have given code, I will give a general method for developing such functions.
First, develop a multiple recursion (2 or more recursive calls) for calculating, say, all sequences of the type of length N. For binary sequences (bs) in big-endian order, from N 0s to N 1s, the base case bs(0) expression is [[]], the sequence that contains the one sequence with no binary digits. The double recursion for bs(n) in terms of bs(n-1) is ([0] concatenated to all members of bs(n-1) (in order)) plus ([1] contanenated to all members of bs(n-1)).
Next, focus on the transition between the subsequences returned by adjacent recursive calls. Here there is just one: 0, 1, ..., 1 to 1, 0, ..., 0. To increment across this boundary, we need to replace 0 followed by 0 or more 1s by 1 followed by the same number of 0s. We find such breaks by scanning from the right for the first 0, as others have shown.
It turns out the every increment crosses the boundary between adjacent bs(k) calls for some value of k, which is to say, at some level of the tree of calls resulting from double recursion.
So far, that I know of, the same idea works for designing the increment function for sequences of grey codes, sequences of conbinations (n things taken k at a time), and sequences of permutations.
Note 1: the 1->0 transitions can be done 1 at a time or all at once.
Note 2: the binary bit testing and flipping is the turing machine algorithm for count + 1. Stephen Wolfram, A New Kind of Science, presents, as I remember, 3 different implementations in the TM chapter.
Note 3 (added in edit): If one switches from prepending 0 first to prepending 1 first, or from prepending to appending, or both, one gets 3 other sequence of sequences, with 3 other increment functions.
You do not need recursion in this case. Let us start with the simplest implementation:
implement a full adder which will operate on bits.
implement a ripple adder using the full adder which will operate on 2 lists of bits.
The full adder implementation is straight forrward.
def full_adder(a,b,cin):
sum_ = a^(b^cin)
cout = (a&b) | (a|b)&cin
return sum_, cout
Tests to make sure the full adder conforms to the specs:
>>> zero_one = (0,1)
>>> [full_adder(*x) for x in [(a,b,c) for a in zero_one for b in zero_one for c in zero_one]]
[(0, 0), (1, 0), (1, 0), (0, 1), (1, 0), (0, 1), (0, 1), (1, 1)]
Since the parameters of the ripple adder are lists, we need to ensure the list lengths match before the addition. This is done by padding the shorter list with leading zeros.
def ripple_adder(xs,ys):
x, y = map(len, (xs, ys))
alen = max(x, y)
ax, by = map(lambda f: f if len(f) == alen else [0]*(alen-len(f)) + f, (xs, ys))
cout = 0
res = [0]*(alen)
for i in range(alen-1, -1, -1):
a, b, cin = ax[i], by[i], cout
s, cout = full_adder(a, b, cin)
res[i] = s
if cout:
res = [1] + res
return res
Finally, we define bin_inc the binary increment function in terms of the ripple adder
def bin_inc(bin_lst):
return ripple_adder(bin_lst, [1])
>>> bin_inc([1,1,1])
[1, 0, 0, 0]
>>> bin_inc([1,0,0,1])
[1, 0, 1, 0]
Now for a solution that is simpler but requires a little insight. Consider the following
obervations for an input xs with length L and output ys
if xs is all ones, ys will have length L+1, the first element of ys will be 1 and the rest will be zeros.
if xs has a zero element, let p be the index of the last zero element in xs.
Then ys will be the list consisting of the first p elements of xs followed by a 1 followed by zeros of length L - p. That is
ys = xs[:p] + [1] + [0]*(L-p).
We can translate this to python code easily. We use python's list.index method to find the last occurence of zero by working on the reverse of the list and adjust the algorithm appropriately:
def bin_inc_2(xs):
if all(xs):
return [1] + [0]*len(xs)
p = xs[::-1].index(0)
return xs[:-p-1] + [1] + [0]*p
This works and is simpler than the ripple_adder based implementation. One minor drawback you might notice is when xs has a zero element, we traverse it to check if it is all ones, then traverse it again to find the first occurence of zero.
We can simplify the implementation and make it more pythonic atthe same time by using a try except block:
def bin_inc_3(bin_lst):
try:
p = bin_lst[::-1].index(0)
return bin_lst[:-p-1] + [1] + [0]*p
except ValueError:
return [1] + [0]*len(bin_lst)
This implementation is simple in terms of source text, and idiomatic python. Now we test it against the ripple_adder based adder to make sure it works well.
>>> z_n = (0,1)
>>> xs = [[a,b,c,d,e,f,g,h] for a in z_n for b in z_n for c in z_n for d in z_n
for e in z_n for f in z_n for g in z_n for h in z_n ]
>>> print(all(ripple_adder(x, [1]) == bin_inc_3(x) for x in xs))
True
Fantastic, it works as intended and correctly handles leading zeros as evidenced by the tests (which increments every number from 0 to 255).
There's only a need to recurse when there is a carry:
def f(n):
# Base cases
if not n:
return [1]
if n == [1]:
return [1, 0]
if n[-1] == 0:
return n[:-1] + [1]
if n[-2:] == [0, 1]:
return n[:-2] + [1, 0]
# Recurse
return f(n[:-2]) + [0, 0]
numbers = [[1, 0, 1], [1,1,1], [1,0,0,1], [1, 0, 1, 1]]
for n in numbers:
print n, f(n)
I have to program this puzzle and solve it (I'm using 100 coins instead of 26), and currently all I have are:
def flip():
if (coin == 0):
coin = 1
if (coin == 1):
coin = 0
def move():
table_one.remove(coin)
table_two.append(coin)
def CoinPuzzle():
table_one = [[1]*20 + [0]*80]
table_two = []
#Move 20 coins from table_one to table_two
#Flip all 20 coins in table_two
#Both tables should have an equal number of 1s
I have a hard time linking individual coin objects with items in the list so that I can execute flip and move functions. I'm new to Python, can someone guide me how to do this?
NEW EDIT: How should I modify the code if I have input like this:
L=[0]*100
for i in random.sample(range(100),20):
L[i]=1
[L1,L2]=tables(L)
Here is small python implementation:
import random
heads_count = 20
total_coins = 100
table_one = [True] * heads_count + [False] * (total_coins-heads_count)
table_two = []
def flip(table, coin):
table[coin] = not table[coin]
def move_random():
coin = random.randint(0, len(table_one)-1)
table_two.append(table_one[coin])
del table_one[coin]
for i in range(heads_count):
move_random()
for i in range(heads_count):
flip(table_two, i)
print(sum(table_one))
print(sum(table_two))
Here's an alternative to Stephen's version. To make the output easier to read I'll use the numbers from the original puzzle.
We use the shuffle function to randomize the order of the coins in table_one in a single step, then use slicing to move heads_count coins from table_one to table_two. To flip the coins, we use the fact that 1 - 0 = 1 and 1 - 1 = 0.
from random import seed, shuffle
# seed the randomizer so we get repeatable results
seed(42)
total_coins = 26
heads_count = 10
# Put all the coins in table_one and randomize their order
table_one = [1] * heads_count + [0] * (total_coins - heads_count)
shuffle(table_one)
print('Initial')
print('Table one:', table_one, sum(table_one), len(table_one))
# move heads_count coins to table_two
table_one, table_two = table_one[heads_count:], table_one[:heads_count]
#flip all the coins in table_two
table_two = [1 - coin for coin in table_two]
print('Final')
print('Table one:', table_one, sum(table_one), len(table_one))
print('Table two:', table_two, sum(table_two), len(table_two))
output
Initial
Table one: [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1] 10 26
Final
Table one: [1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1] 8 16
Table two: [1, 1, 1, 0, 0, 1, 1, 1, 1, 1] 8 10
We could even combine the last two steps into a single statement:
table_one, table_two = table_one[heads_count:], [1 - coin for coin in table_one[:heads_count]]
I am trying to write a function that takes the number or rows and columns in a grid, simulates a random walk starting in the center of the grid, and computes the number of times each intersection has been visited by the random walk. Then prints the table line by line once the random walk moves outside the grid
So far I have this but i cant get it to work right.
def manhattan(x,y):
'int,int==>nonetype'
import random
res=[]
for i in range(x):
res.append([])
for i in res:
for j in range(y):
i.append(0)
position=(x//2+1,y//2+1)
z=position[0]
v=position[1]
while z!=-1 or z!=x or v!=-1 or v!=y:
direction=random.randrange(1,5)
if direction==1:
v+=1
elif direction==2:
z+=1
elif direction==3:
v-=1
else:
z-=1
for i in range(len(res)):
if i ==z:
res[i]+=1
for j in range(i):
if v==j:
i[j]+=1
for i in res:
print(i)
It should read when done:
manhattan(5,11)
[0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,1,1,1,1,2,2]
[0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0]
You were very close, try the following:
def manhattan(x,y):
'int,int==>nonetype'
import random
res=[]
for i in range(x):
res.append([])
for i in res:
for j in range(y):
i.append(0)
position=(x//2+1,y//2+1)
z=position[0]
v=position[1]
while z!=-1 and z!=x and v!=-1 and v!=y:
res[z][v] += 1
direction=random.randrange(1,5)
if direction==1:
v+=1
elif direction==2:
z+=1
elif direction==3:
v-=1
else:
z-=1
for i in res:
print(i)
Nothing is different until the while loop, and there are only a couple of changes. First you need to use and instead of or in the loop condition check since you want to exit if any of those conditions are met.
The other change was to remove the for loop from the bottom of the while loop and replace it by res[z][v] += 1, this works because z and v represent the intersection and you already initialized res to be a two-dimensional list of all the intersections so looping is unnecessary. I also moved this up to the top of the loop because otherwise you might try to modify res after moving past the boundary.
Here is a bit less verbose version that uses random.choice instead of your chained elif statements. I found it helpful when learning python to see the same problem in different ways, so here is a pure python and a numpy + python implementation.
Pure Python
import random
def manhattan(n,m):
grid = [[0,]*m for _ in xrange(n)]
directions = [[-1,0],[1,0],[0,-1],[0,1]]
pt = [n//2, m//2]
while pt[0]>=0 and pt[0]<n and pt[1]>=0 and pt[1]<m:
grid[pt[0]][pt[1]] += 1
d = random.choice(directions)
pt[0] += d[0]
pt[1] += d[1]
return grid
for row in manhattan(5,11):
print row
This gives, for example,
[0, 0, 0, 1, 3, 3, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 3, 3, 2, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0]
[0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0]
Python + numpy
import numpy as np
import random
def manhattan(n,m):
grid = np.zeros((n,m),dtype=int)
directions = [[-1,0],[1,0],[0,-1],[0,1]]
pt = np.array([n//2, m//2])
while (pt>=0).all() and (pt<grid.shape).all():
grid[pt[0],pt[1]] += 1
pt += random.choice(directions)
return grid
print manhattan(5,11)