Move all elements to right/left/let user choose (python) - python

I want to let the user choose either to move elements in an rng list either to the left, right or let them choose. I saw a similar post, but after reading it I did not see a way to choose which direction and do multiple repeats of the process.
import random
randlist = []
for i in range(10):
randlist.append(random.randint(0,10))
x = input("Right? Left? Choose?")
if x == "Right":
#Move all elements to the right once
elif x == "Left":
#Move all elements to the left once
else:
#Let User input both direction and amount of moves to the specified side

Slicing the array helps here. Only when rotating more than the
length of array needs to be taken care. if lenght of array is
10 then rotaing 13 times is same as rotaing 3 times.
Code:
import random
def rotate_right(arr, n):
m = n % len(arr)
m = len(arr) - m
return arr[m:] + arr[0:m]
def rotate_left(arr, n):
n = n % len(arr)
return arr[n:] + arr[0:n]
randlist = []
for i in range(10):
randlist.append(random.randint(0, 10))
print(randlist)
print(rotate_right(randlist,13))
print(rotate_left(randlist,14))
x = input("Right? Left? Choose?")
if x == "Right":
print(rotate_right(randlist,1))
elif x == "Left":
print(rotate_left(randlist,1))
Output:
[0, 7, 3, 3, 0, 4, 0, 6, 6, 3]
[6, 6, 3, 0, 7, 3, 3, 0, 4, 0]
[0, 4, 0, 6, 6, 3, 0, 7, 3, 3]
Right? Left? Choose?

Related

Breeding new child list from two same length lists, in order, without duplicates and splitting at random index

In this problem I am trying to create a new list of length n from two lists of length n each. I randomly select a subset of the first parent list (using start and end variables) and add them to the new list in the same positions in which they appeared in their corresponding list. Then I populate the remainder of the new list with elements from the second parent list in the order in which they appear, without duplicating any element that was selected from the first parent. The image explains it.
Here is my python code: a plane here is weights for a Perceptron model.
def breed(plane1, plane2):
num_list = list(range(0, len(plane1)))
random.shuffle(num_list)
n1 = num_list[0]
n2 = num_list[1]
start = min(n1, n2)
end = max(n1, n2)
child = [None] * len(plane1)
for i in range(start, end):
child[i] = plane1[i]
idx = (end) % len(plane2)
for i in range(len(plane2)):
pos = (end + i) % len(plane2)
if plane2[pos] not in child:
child[idx] = plane2[pos]
idx = (idx + 1) % len(plane2)
return child
Can anyone recommend a different way that is efficient and concise?
Also, the end of random range is not included in the selection:
one = [1,2,3,4,5,6,7,8,9]
two = [9,8,7,6,5,4,3,2,1]
child = breed(one, two)
print(child)
start: 0
end: 7
Output:
[1, 2, 3, 4, 5, 6, 7, 9, 8]
Here's a solution. It could probably be better, not using a while loop would be more elegant. I don't know if it covers all edge cases. I've split out the logic from the randomly generated numbers to make it easier to test.
import random
def breed(plane1, plane2):
assert len(plane1) == len(plane2)
istart = random.randint(0, len(plane1) - 2)
iend = random.randint(istart + 1, len(plane1) - 1)
print(f"random indices: {istart} to {iend}")
return generate_breed(plane1, plane2, istart, iend)
def generate_breed(plane1, plane2, istart, iend):
child = [-1 for _ in plane1]
child[istart : iend + 1] = plane1[istart : iend + 1]
i = j = 0
while True:
if j == istart:
j = iend + 1
if j >= len(child):
break
if plane2[i] not in child:
child[j] = plane2[i]
j += 1
i += 1
return child
if __name__ == "__main__":
p1, p2 = [1, 2, 3, 4, 5, 6], [7, 3, 2, 1, 2, 6]
start, end = 2, 4
assert generate_breed(p1, p2, start, end) == [7, 2, 3, 4, 5, 1]
assert generate_breed([1, 2, 3], [4, 2, 1], 0, 2) == [1, 2, 3]
# call like this, but answer is unpredictable due to randint call
print(breed([1, 2, 3], [4, 2, 1]))
Edit
Original answer was super wrong, after iterating over this for a while, this works, assuming lists don't have duplicates in themselves.
Magic Numbers
With generating the start and end, the magic -2 and magic +1 can be tuned if you want to set a min length. I set the min length here to 1.
def breed(plane1, plane2):
i = randint(0, len(plane1) - 2)
j = randint(i + 1, len(plane1))
plane2 = [x for x in plane2 if x not in plane1[i:j]]
child = plane2[0:i] + plane1[i:j] + plane2[i:len(plane1) - (j - i)]
return child

Python remove N consecutive duplicates from the list

Here's the problem. The input is a list of integers. If more than three adjacent numbers appear next to each other they should be dropped and the operation goes again. Kind of similar to the Iphone game, where player needs to pop lines of three or more balls of the same colors. The output should be the count of the balls that will be removed.
The algorithm is as follows. Starting with a sample list of say [3,3,4,4,4,4,3,2].
First iteration should remove the 4,4,4,4 - so the list would become [3,3,3,2], and the intermediary output of removed numbers will be 4.
Second iteration should remove 3,3,3 - so the final list would be [2] and final count of removed numbers - 7.
The first implementation for three consecutive items came from another stackoverflow thread - Remove triplets of adjacent numbers from the list
Here's the working function implementation for exactly 3 consecutive numbers:
def balls(l):
values = l
while len(values) >= 3:
print(values) #for demonstrative purposes of this question
for x in range(0,len(values)-2):
if values[x] == values[x+1] and values[x] == values[x+2]:
values = values[:x] + values[x+3:]
break
else:
break
print(values) #for demonstrative purposes of this question
return len(l) - len(values)
balls([3, 3, 4, 4, 4, 3, 4])
Output:
[3, 3, 4, 4, 4, 3, 4]
[3, 3, 3, 4]
[4]
6
How could I update the implementation to include the more general solution of removing 3+ consecutive numbers. I am thinking about tracking the start and end index of the consecutive duplicates, then subsetting the list. However, not sure how to implement that. Here are the tests that should work.
if __name__ == "__main__":
test1 = [3, 3, 4, 4, 4, 3, 4]
print(balls(test1))
#Output should be 6
test2 = [5, 5, 5, 5, 5, 5, 5, 5]
print(balls(test2))
#Output should be 8
test3 = [5, 7, 8, 3]
print(balls(test3))
#Output should be 0
def remove_consecutive(l, length):
amount = len(l)
count = 1
start = 0
current = l[0]
i = 1
while i < len(l):
if l[i] == current:
count += 1
else:
if count >= length:
for i in range(count):
l.pop(start)
start = 0
i = 0
current = l[0]
else:
start = i
current = l[i]
count = 1
i+=1
if count >= length:
for i in range(count):
l.pop(start)
return amount - len(l)
Wuff, i got it. My brain is kinda stinky lately so it took so long.
Here is my code, it works well. But I think there may be better ways to achieve higher efficiency.
def remove_consecutive(lst):
len_init = len(lst)
contain_tuplets = True
while contain_tuplets:
for i in range(len(lst)-2):
indices_to_pop = []
if lst[i]==lst[i+1]==lst[i+2]:
indices_to_pop.extend([i, i+1, i+2])
for j in range(i+3,len(lst)):
if lst[j] == lst[i]:
indices_to_pop.append(j)
else:
break
[lst.pop(i) for _ in indices_to_pop]
contain_tuplets = True
break
else:
contain_tuplets = False
count_removed_numbers = len_init - len(lst)
return count_removed_numbers, lst
test case1:
lst = [3,3,4,4,4,4,3,2]
remove_consecutive(lst)
output
(7, [2])
test case 2:
lst = [2, 2, 1, 1, 1, 2, 1]
remove_consecutive(lst)
output:
(6, [1])
def remove_consecutive(l, length):
amount = 0
count = 1
current = l[0]
for i in range(1, len(l)):
if l[i] == current:
count += 1
if count > length:
amount += 1
elif count == length:
amount += length
else:
current = l[i]
count = 1
return amount

Unable to achieve global functionality in python

So I am new to python and here is my python code:
def main():
N = 1
players = 10
for _ in range(N):
maxi = 0
t1 = [3, 6, 7, 5, 3, 5, 6, 2, 9, 1]
t2 = [2, 7, 0, 9, 3, 6, 0, 6, 2, 6]
for i in range(players):
count = t2[i]+1
flag = 0
def calcWin(count):
global maxi,flag
if(count in t1):
flag = 1
maxi = maxi + 1
t1.remove(count)
else:
count = count + 1
if(count<=max(t1)):
calcWin(count)
calcWin(count)
print(flag)
main()
I want the variable 'maxi' to be accessible inside the function calcWin(). So it declared the variable as global inside the function. But it throws 'NameError'. I want the variable 'maxi' to reinitialize to 0 for each 'N'. Another thing is that the 'flag' variable always prints 0 even though it satisfies the condition 'if(count in t1)'. (Note: I declared 'flag' as global inside the function). Can somebody help me with this?
As you are asking in the comment for a way to do this without global variables, the following could be a proposal. Please understand that I just imitated what I think you intended with your original code. You may have to adapt your algorithm...
def main():
n = 1
players = 10
for _ in range(n):
maxi_persistent = 0
t1 = [3, 6, 7, 5, 3, 5, 6, 2, 9, 1]
t2 = [2, 7, 0, 9, 3, 6, 0, 6, 2, 6]
for i in range(players):
def calc_win(count, maxi):
flag = False
if count in t1:
flag = True
maxi += 1
t1.remove(count)
else:
count += 1
if count <= max(t1):
return calc_win(count, maxi)
return maxi, flag
maxi_persistent, win_flag = calc_win(count=t2[i] + 1, maxi=maxi_persistent)
print(win_flag)
if __name__ == "__main__":
main()
Please note that flag, as you use it in your question, does not need any global handling. It is 0 at each call of the function, so I just set it to 0 (or False) in the beginning of the function instead.

How do I remove a variable with just its value

I'm trying to make a game similar to this one, https://gyazo.com/8d8dff02a09d27ba28ed303979f64894 its called Farkle! How it works is, you roll a dice, if you roll a 1 and get 100 points (or another die gives you points) That die is taken away until you Farkle, change turns or you win the game. But I'm not sure how to temporarily take the dice away based on its value after rolling it. Can someone please tell me the method for removing a variable based on its value?
from random import randint
score1 = 0
def dices():
score1 = 0
a = 0
dice1 = randint(1, 6)
dice2 = randint(1, 6)
dice3 = randint(1, 6)
dice4 = randint(1, 6)
dice5 = randint(1, 6)
dice6 = randint(1, 6)
rolled_dice = [dice1, dice2, dice3, dice4, dice5, dice6]
one_count = rolled_dice.count(1)
a = [0, 100, 200, 300, 1000, 2000, 300][one_count]
two_count = rolled_dice.count(2)
score1 += a
a = [0, 0, 0, 200, 1000, 2000, 3000][two_count]
score1 += a
three_count = rolled_dice.count(3)
a = [0, 0, 0, 300, 1000, 2000, 3000][three_count]
score1 += a
four_count = rolled_dice.count(4)
a = [0, 0, 0, 400, 1000, 2000, 3000][four_count]
score1 += a
five_count = rolled_dice.count(5)
a = [0, 50, 100, 500, 1000, 2000, 3000][five_count]
score1 += a
six_count = rolled_dice.count(6)
a = [0, 0, 0, 600, 1000, 2000, 3000][six_count]
score1 += a
print(score1)
if score1 == 0:
print("Farkle!")
print(rolled_dice)
dices()
Let's think of it as we would in real life. If you roll dices and want to keep some results, you can mark them down or put them aside until you rolled the others. You do not throw them away since the result is still of importance.
The same happens when coding, you do not want to throw away values that you might later need. Instead you write them down somewhere safe until you need them.
You could achieve that by keeping the results of your dices in a list and writing a reroll function that only rerolls some dices, but not all.
import random
def reroll(dices, *pos):
for x in pos:
dices[x] = random.randint(1, 6)
# This creates a list with 6 dices result in it
dices = [random.randint(1, 6) for _ in range(6)]
print(dices) # [1, 5, 3, 6, 6, 5]
# We now only want to reroll the first and third dices
reroll(dices, 0, 2)
print(dices) # [4, 5, 1, 6, 6, 5]
An even better solution that does not mutate your data, i.e. that allows you to keep the previous result when you reroll, would be to make reroll return a new list of values where it rerolled only some dices.
import random, copy
def reroll(dices, *pos):
dices = copy.copy(dices)
for x in pos:
dices[x] = random.randint(1, 6)
return dices
dices = [random.randint(1, 6) for _ in range(6)]
# reroll returns a new list of values
new_dices = reroll(dices, 0, 2)
print(dices) # [6, 3, 4, 2, 4, 3]
print(new_dices) # [1, 3, 2, 2, 4, 3]

Python quicksort - one list - swaps

**I need to make a quicksort algorithm but so that it uses only one list and does swaps inside of it. I managed to make it "sort" or position the first element but now i don't know how to implement the recursion. The biggest problem I'm having is how to recursively work on a part of the list instead of making the new one. Here is my code:
-------------------------------------------------------------------------------**
New code, same problem.
Here is my code. It does the job but gets stuck in the loop.
def qsort(n,l,g):
if l is None:
l=0
if g is None:
g=len(n)
if g-l<=1:
return n
print g-l
p=n[l]
i=1+l
j=1+l
for x in n[l+1:g]:
if x<p:
n[i],n[j]=n[j],n[i]
i+=1
j+=1
n[l],n[i-1]=n[i-1],n[l]
ls=0
le=i-1
gs=i
ge=j
print n
qsort(n,ls,le)
qsort(n,gs,ge)
Can someone give me any suggestions, I'm lost. Can't find whats wrong or how to fix it.
Know its messy but cant do better atm :D
Write it like this:
def qsort(li, lo=None, hi=None):
if lo is None:
lo = 0
if hi is None:
hi = len(li) - 1
...
...
if hi - lo > 1:
qsort(## left half ##)
qsort(## right half ##)
lo and hi are the smallest and largest indexes you should look at in li, respectively.
Swap version of quicksort.
quicksort([10, 0, 9, 1, 8, 2, 7, 3, 6, 4, 5]) >> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
quicksort([0, 4, 2, 3, 6]) >> [0, 2, 3, 4, 6]
def quicksort(seq):
if len(seq) <= 1:
return seq
pivot_index = len(seq)-1
i = 0
while i < pivot_index:
if seq[i] > seq[pivot_index] and pivot_index-1 == i:
seq[i], seq[pivot_index] = seq[pivot_index], seq[i]
pivot_index -= 1
i = 0
elif seq[i] > seq[pivot_index] and pivot_index > 1:
seq[pivot_index-1], seq[pivot_index] = seq[pivot_index], seq[pivot_index-1]
seq[i], seq[pivot_index] = seq[pivot_index], seq[i]
pivot_index -= 1
i = 0
else:
i += 1
return quicksort(seq[:pivot_index]) + [seq[pivot_index]] + quicksort(seq[pivot_index+1:])

Categories

Resources