Loop unrolling? in Julia with metaprogramming - metaprogramming

is there a way to "metaprogrammatically" obtain a block of code with the following structure:
if r1 < R1
s = 1
elseif r1 < R2
s = 2
... etc until N
end
end
Thanks!

Check out Base.Cartesian.#nif
I think this should work for you...
julia> macroexpand(:(#nif 10 d->(r1 < R_d) d->begin s=d; break end))
:(if r1 < R_1 # REPL[9], line 1:
s = 1 # REPL[9], line 1:
break
else
if r1 < R_2 # REPL[9], line 1:
s = 2 # REPL[9], line 1:
break
else
if r1 < R_3 # REPL[9], line 1:
s = 3 # REPL[9], line 1:
break
else
if r1 < R_4 # REPL[9], line 1:
s = 4 # REPL[9], line 1:
break
else
if r1 < R_5 # REPL[9], line 1:
s = 5 # REPL[9], line 1:
break
else
if r1 < R_6 # REPL[9], line 1:
s = 6 # REPL[9], line 1:
break
else
if r1 < R_7 # REPL[9], line 1:
s = 7 # REPL[9], line 1:
break
else
if r1 < R_8 # REPL[9], line 1:
s = 8 # REPL[9], line 1:
break
else
if r1 < R_9 # REPL[9], line 1:
s = 9 # REPL[9], line 1:
break
else # REPL[9], line 1:
s = 10 # REPL[9], line 1:
break
end
end
end
end
end
end
end
end
end)

Related

Incrementing the for loop in python given a certain condition

The i+=1 isn't working, it should have increased the i value but it isn't
n = int(input())
for j in range(n):
a = input()
pair = 0
for i in range(len(a)-1):
print(i)
if a[i] == "x" and a[i+1] == "y":
pair += 1
print("*")
elif a[i] == "y" and a[i+1] =="x":
pair += 1
print('**')
else:
continue
i+=1
print(pair)
print("****")
print(pair)strong text
```
You are trying to modify a parameter that is implicitly set by the for loop.
This isn't C-Code, increasing the counter variable will not skip the next iteration.
The reason for that is quite simple: for itself does not increase i in every iteration, it just steps through the given iteratable. In this case the iteratable is a range, which behaves like for would increase i every iteration, but it really just takes the next value from the range.
So i+=1 doesn't have an effect on the next iteration, as it doesn't modify the next value in the range.
Your for-loop already increments i on every iteration. But if you want to increment by more than 1 when certain condition is satisfied, then you can use while loop as follows:
n = int(input())
for j in range(n):
a = input()
pair = 0
i = 0
while i < len(a)-1:
print(i)
if a[i] == "x" and a[i+1] == "y":
pair += 1
print("*")
elif a[i] == "y" and a[i+1] =="x":
pair += 1
print('**')
else:
i += 1
continue
i+=2
print(pair)
print("****")
print(pair)strong text
You could explicitely skip the next iteration when a pair is found.
Here is your code with the changes pointed at by # <---.
n = int(input())
for j in range(n):
a = input()
pair = 0
skip_next = False # <---
for i in range(len(a)-1):
if skip_next is True: # <---
skip_next = False # <---
continue # <---
print(i)
if a[i] == "x" and a[i+1] == "y":
pair += 1
print("*")
skip_next = True # <---
elif a[i] == "y" and a[i+1] =="x":
pair += 1
print('**')
skip_next = True # <---
else:
continue
print(pair)
print("****")
print(pair)

My minesweeper program works just fine until I click on the top left tile. Everything looks fine

I am attempting to make minesweeper in Python by using tkinter. When the program checks for bombs, it works just fine unless the tile clicked is at 0, 0 (top left), in which case the program always has tileNorth and tileWest True, causing the program to check a variable that doesn't exist. This causes an error and leaves the 0, 0 tile blank. The checking works in every other tile, including corners, just not the top left. This should not be happening.
TLDR:
My minesweeper program works just fine, but it always messes up at 0, 0 and creates an error. I don't understand what's wrong...
The Error:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
File "<string>", line 11, in <lambda>
File "/home/pi/Documents/Python/Minesweeper/Minesweeper.py", line 133, in tileClicked
stringVar_{x}_{y}.set(tileValue)""")
File "<string>", line 56
if bomb_-1_-1 == True:
^
SyntaxError: invalid token
It mentions bomb_-1_-1 which doesn't exist and can't exist... This is why that one if statement needs to work.
My Code:
import random
import tkinter
# Functions
def tileClicked(x, y): # Function is ran when a tile is clicked. The tile is defined by the inputted 'x' and 'y' values.
exec(f"""
global tileNorth, tileEast, tileSouth, tileWest
if y > 0:
tileNorth = True
else:
tileNorth = False
if x < game.size[0] - 1:
tileEast = True
else:
tileEast = False
if y < game.size[1] - 1:
tileSouth = True
else:
tileSouth = False
if x > 0:
tileWest = True
else:
tileWest = False""")
print(f"""{tileNorth}
{tileEast}
{tileSouth}
{tileWest}
DIV""")
exec(f"""
print("{x}, {y}")
if bomb_{x}_{y} == True:
stringVar_{x}_{y}.set("Bomb")
game.failed = True
if x == 0 and y == 0:
tileValue = int(0)
if tileNorth == True:
if tileEast == True:
if bomb_{x + 1}_{y - 1} == True:
tileValue += 1
if tileEast == True:
if bomb_{x + 1}_{y} == True:
tileValue += 1
if tileSouth == True:
if tileEast == True:
if bomb_{x + 1}_{y + 1} == True:
tileValue += 1
if tileWest == True:
if bomb_{x - 1}_{y + 1} == True:
tileValue += 1
if bomb_{x}_{y + 1} == True:
tileValue += 1
if tileWest == True:
if bomb_{x - 1}_{y} == True:
tileValue += 1
else:
tileValue = int(0)
if tileNorth == True:
if tileEast == True:
if bomb_{x + 1}_{y - 1} == True:
tileValue += 1
if tileWest == True:
if bomb_{x - 1}_{y - 1} == True:
tileValue += 1
if bomb_{x}_{y - 1} == True:
tileValue += 1
if tileEast == True:
if bomb_{x + 1}_{y} == True:
tileValue += 1
if tileSouth == True:
if tileEast == True:
if bomb_{x + 1}_{y + 1} == True:
tileValue += 1
if tileWest == True:
if bomb_{x - 1}_{y + 1} == True:
tileValue += 1
if bomb_{x}_{y + 1} == True:
tileValue += 1
if tileWest == True:
if bomb_{x - 1}_{y} == True:
tileValue += 1
if tileValue == 0:
tileValue = "Clear"
stringVar_{x}_{y}.set(tileValue)""")
# Classes
class game:
title = "Minesweeper"
bg = "white"
fg = "black"
size = [10, 10]
tileWidth = 3
tileHeight = 2
failed = False
bombFrequency = 4
flagMode = False
# Execution
window = tkinter.Tk() # The window.
window.title(game.title)
window.config(bg = game.bg)
mainFrame = tkinter.Frame(window, bg = game.bg) # Main frame that everything is located in.
titleFrame = tkinter.Frame(mainFrame, bg = game.bg) # Title frame.
titleLabel = tkinter.Label(titleFrame, bg = game.bg, fg = game.fg, text = game.title, font = "none 20").grid(row = 0, column = 0)
titleFrame.grid(row = 0, column = 0)
tileFrame = tkinter.Frame(mainFrame, bg = game.bg) # Frame where tiles are located.
x = 0
y = 0
for tiles_x in range(game.size[0]): # Generates tiles.
for tiles_y in range(game.size[1]):
exec(f"""global tile_{x}_{y}, stringVar_{x}_{y}, bomb_{x}_{y}
bomb_{x}_{y} = random.randint(1, game.bombFrequency)
if bomb_{x}_{y} == 1:
bomb_{x}_{y} = True
else:
bomb_{x}_{y} = False
stringVar_{x}_{y} = tkinter.StringVar(tileFrame)
tile_{x}_{y} = tkinter.Button(tileFrame, bg = 'lightgrey', fg = 'black', width = game.tileWidth, height = game.tileHeight, textvariable = stringVar_{x}_{y}, command = lambda: tileClicked({x}, {y})).grid(row = {y}, column = {x})""")
y += 1
x += 1
y = 0
tileFrame.grid(row = 1, column = 0)
mainFrame.pack() # The main frame is packed so everything is centered.
window.mainloop()
I don't care if you think dynamic variables are inefficient, it's my choice. I don't want people to comment on my methods of accomplishing a task... unless it's causing the problem...
Thanks!
Using dynamic variables is bad practice, and your experience is a good demonstration why.
Variable names cannot have a minus sign in them. The minus sign is interpreted as the arithmetic operator. So bomb_-1_-1 is interpreted as bomb_ - 1_ - 1. The bomb_ part is understood as a variable name, the 1 as a number, but the underscore following that number is triggering the syntax error.
This also demonstrates that dynamic code is not that great: syntax errors only pop up when certain circumstances are created (like selecting a particular cell).
A quick fix, just to show a work around, is to test first the values of x and y:
if {x} >= 0 and {y} >= 0 and bomb_{x}_{y} == True:
You would have to do similar tests for any other place where you create a dynamic reference like that. So also:
if {x} >= 1 and {y} >= 1 and bomb_{x-1}_{y-1} == True:
...etc.
But this is really patching a terrible design.
Note that even if only one of the variables is negative, you'll evaluate an expression that you did not really intend. You could get this for when only y == -1: bomb_5_-1. This produces no syntax error, but it evaluates as bomb_5_ minus 1. Obviously that is not intended by the algorithm.
Instead of dynamic variables and parsing code at run-time, use lists. They can be nested to have the 2D coverage.

List index out of range when moving

This is my code for the game of fifteen, excluding the 'won' function:
import sys
d = int(sys.argv[1])
dimension = (d * d) - 1
board = [[0 for x in range(d)] for y in range(d)]
def main():
global d
if len(sys.argv) != 2 or 0 > d or d > 9:
print("usage: python fifteen.py size")
exit()
def init():
global d
global dimension
global board
for row in range(d):
for col in range(d):
board[row][col] = dimension
dimension -= 1
if d % 2 == 0:
board[d-1][d-3] = 1
board[d-1][d-2] = 2
def draw():
global d
global dimension
global board
for row in range(d):
for col in range(d):
if board[row][col] == 0:
print("__", end="")
else:
print("{:0=2d} ".format(board[row][col]), end="")
print("")
def move():
global d
global dimension
global board
while True:
tile = int(input("Tile to move: "))
if tile > 0:
break
for row in range(d):
for col in range(d):
if board[row][col] == tile:
colleft = col - 1
colright = col + 1
rowup = row - 1
rowdown = row + 1
if board[row][colleft] == 0 and colleft >= 0:
board[row][colleft] = tile
board[row][col] = 0
return True
elif board[row][colright] == 0 and colright < d:
board[row][colright] = tile
board[row][col] = 0
return True
elif board[rowup][col] == 0 and rowup >= 0:
board[rowup][col] = tile
board[row][col] = 0
return True
elif board[rowdown][col] == 0 and rowdown < d:
board[rowdown][col] = tile
board[row][col] = 0
return True
return False
return True
main()
init()
draw()
move()
draw()
When I want to move 2 or 3 for instance, I keep getting "IndexError: list index out of range":
Erorr message:
python3 fifteen.py 3
Traceback (most recent call last):
File "fifteen.py", line 83, in <module>
move()
File "fifteen.py", line 72, in move
elif board[rowdown][col] == 0 and rowdown < d:
IndexError: list index out of range
What do I have to do to make this work properly?
because rowdown and colright could be bigger than the max index of your board.
for example, d = 3.
when row = 2, rowdown = 3 which is out of index of board.

Omit last line in nested for loop

I have a nested for loop:
for i in range(0,6):
for j in range(0,10):
print(j, end="")
print("\n",0)
Which results in the following:
0123456789
0
0123456789
0
0123456789
0
0123456789
0
0123456789
0
0123456789
0
How do I omit the last 0 from the result?
you can simply add an if as follows:
for i in range(0, 6):
for j in range(0, 10):
print(j, end="")
if i != 5:
print("\n", 0)
You can keep a variable to see if the process is complete and there is no need for more zeroes.
done = False
for i in range(0,6):
for j in range(0,10):
print(j, end="")
if i == 5 and j == 9:
done = True
if not done:
print("\n",0)
# You can also use this variable to break the loop
# after the process is complete.

Connect 4 Like Game

I am making a connect four like game in python, what I have so far is creating the board and implementing game play against the computer. I am running into the issue that does not allow me to play past the second row. Any ideas on why?
#Define the board
row = int(input("Please enter # of rows: ")) #User input Rows
column = int(input("Please enter # of columns: ")) #User input Columns
board = [] #empty board
space = ' '
p1 = 'x'
p2 = 'o'
#create board based on user input
for i in range(0,row):
board.append([])
for j in range(0, column):
board[i].append(space)
print(board)
#print board with character decorations
for i in board:
line=''
print('+'+'-+'*len(i))
for j in range(len(i)):
line = line + '|'+i[j]
line = line + '|'
print(line)
print('+'+'-+'*len(i))
print(len(board))
while True:
#User input column
myC = int(input("Player 1, choose your column: "))
i = len(board)-1
x = len(board)-1
while i >= 0:
if board[x][myC] == space:
i = i+1
board[x][myC] = 'x'
break
elif board[x][myC] == p1 or p2:
i = i+1
x = x - 1
print(x)
board[x][myC] = 'x'
break
# print the board!
for i in board:
line=''
print('+'+'-+'*len(i))
for j in range(len(i)):
line = line + '|'+i[j]
line = line + '|'
print(line)
print('+'+'-+'*len(i))
#Computer input column
from random import randint
theC = randint(0, len(board)-1)
print("Computer's Turn: Column " , theC)
i = len(board)-1
x = len(board)-1
while i >= 0:
if board[x][theC] == space:
board[x][theC] = 'o'
i = i+1
break
elif board[x][theC] == p1 or p2:
i = i+1
x = x - 1
print(x)
board[x][theC] = 'o'
break
# print the board!
for i in board:
line=''
print('+'+'-+'*len(i))
for j in range(len(i)):
line = line + '|'+i[j]
line = line + '|'
print(line)
print('+'+'-+'*len(i))
I believe I figured out what's going on. Your x is always initialized to len(board)-1 and then if the space is occupied it is reduced by one. If you make a (>2)x(>2) board and row 0 is occupied then this will always force x = 2.
This is close to correct, but what you actually need is to iterate through all rows until you find the first unoccupied row. I created a loop that will find the first row and assign that to the value of x. I tested it out and I'm now able to play passed 2 rows.
#Define the board
row = int(input("Please enter # of rows: ")) #User input Rows
column = int(input("Please enter # of columns: ")) #User input Columns
board = [] #empty board
space = ' '
p1 = 'x'
p2 = 'o'
#create board based on user input
for i in range(0,row):
board.append([])
for j in range(0, column):
board[i].append(space)
print(board)
#print board with character decorations
for i in board:
line=''
print('+'+'-+'*len(i))
for j in range(len(i)):
line = line + '|'+i[j]
line = line + '|'
print(line)
print('+'+'-+'*len(i))
print(len(board))
while True:
#User input column
myC = int(input("Player 1, choose your column: "))
i = len(board)-1
x = len(board)-1
while i >= 0:
if board[x][myC] == space:
i = i+1
board[x][myC] = 'x'
break
# Find last empty row for new piece
elif board[x][myC] == p1 or p2:
for j in range(x-1,-1,-1):
if board[j][myC] == space:
x = j
break
i = i+1
#x = x - 1
print(x)
board[x][myC] = 'x'
break
# print the board!
for i in board:
line=''
print('+'+'-+'*len(i))
for j in range(len(i)):
line = line + '|'+i[j]
line = line + '|'
print(line)
print('+'+'-+'*len(i))
#Computer input column
from random import randint
theC = randint(0, len(board)-1)
print("Computer's Turn: Column " , theC)
i = len(board)-1
x = len(board)-1
while i >= 0:
if board[x][theC] == space:
board[x][theC] = 'o'
i = i+1
break
# Find last empty row for new piece
elif board[x][theC] == p1 or p2:
for j in range(x-1,-1,-1):
if board[j][theC] == space:
x =j
break
i = i+1
#x = x - 1
print(x)
board[x][theC] = 'o'
break
# print the board!
for i in board:
line=''
print('+'+'-+'*len(i))
for j in range(len(i)):
line = line + '|'+i[j]
line = line + '|'
print(line)
print('+'+'-+'*len(i))

Resources