I'm trying to write a program that duplicates the "Amazing" game from 101 BASIC Computer Games, in Python. I want it to create the same text mazes using the same characters, and so far I am limiting myself to a program that I can run from a command line, without creating a new GUI. My research has led me to the Wikipedia article "Maze Generation Algorithm" and the page "Think Labyrinth: Maze Algorithms," from the astrolog.org website.
My first thought was to write a program that would build the maze from nothing, but the majority opinion about maze creation seems to be to start with a grid, start at a cell, then write an algorithm that tests the cell's neighbors to see if they have been visited, and break down the wall between the current cell and a random new neighbor that hasn't been visited already.
So far, I have written a program that will generate the text grid according to user input of width and height:
"""Asks user for a width and height, then generates a text grid based on
user input."""
#Only two imports
import random
import sys
width1 = int(input("What width do you want? "))
height1 = int(input("What height do you want? "))
#Text elements for the grid
top_Line = ".--"
top_End = "."
mid_Line = ":--"
mid_End = ":"
yes_Wall = " I"
def grid_Top(width1):
"""Draws the top of a grid of user width."""
top_Lst = []
for i in range(width1):
top_Lst.append(top_Line)
top_Lst.append(top_End)
return top_Lst
def grid_Walls(width1):
"""Draws the walls of the grid."""
walls_Lst = []
walls_Lst.append("I")
for i in range(width1):
walls_Lst.append(yes_Wall)
return walls_Lst
def grid_Floors(width1):
"""Draws the floors of the grid."""
floors_Lst = []
for i in range(width1):
floors_Lst.append(mid_Line)
floors_Lst.append(mid_End)
return floors_Lst
def grid_Create(width1, height1):
"""Creates the grid of user width & height."""
for i in grid_Top(width1):
print(i, end = "")
print("")
for j in range(height1):
for i in grid_Walls(width1):
print(i, end="")
print("")
for i in grid_Floors(width1):
print(i, end="")
print("")
grid_Create(width1, height1)
So, as it stands, each of my cells is defined by the ceiling above it, the walls to either side, and the floor below it. As it stands, this means that testing each cell for whether it has been visited or is intact involves looking at three lists - the previous list, the current list, and the next list, if you get my meaning.
My question is: How do I impose a structure onto my text grid so that each cell is its own entity, which can be tested for whether it has been visited in a depth-first search?
Any and all comments about my code will be welcome, whether or not they are relevant to the actual question I am asking!
Thanks!
I would use a set to explicitly track which cells have been visited:
visited = set()
if candidate_coord not in visited:
visited.add(candidate_coord)
break_wall(candidate_coord, curr_coord)
Related
I have a problem regarding a competition question I'm attempting to do. Here is the question (its a bit long)
""""
Welcome aboard, Captain! Today you are in charge of the first ever doughnut-shaped spaceship, The
Circular. There are N cabins arranged in a circle on the spaceship. They are numbered from 1 to N in
a clockwise direction around the ship. The ith and the (i + 1)th cabins are connected. So too are cabin
1 and cabin N.
Currently the ith cabin has Ai crewmates, however the spaceship cannot depart unless there are exactly
Bi crewmates in this cabin.
To achieve this, you have the power to pay crewmates to change cabins. You can pay a crewmate $1 to
move to an adjacent cabin. A crewmate can be asked to move multiple times, provided that you pay
them $1 each time.
What is the fewest dollars you must pay before you can depart? It is always be possible to depart.
""""
https://orac2.info/problem/aio22spaceship/ (the link to the intereactive Qs)
I searched the web and i found no solutions to the Q. My code seems to be infinite looping i guess but im not sure as i cant see what cases the sit uses to determine if my code is right.
Heres my code
#!/usr/bin/env python
import sys
sys.setrecursionlimit(1000000000)
#
# Solution Template for Spaceship Shuffle
#
# Australian Informatics Olympiad 2022
#
# This file is provided to assist with reading and writing of the input
# files for the problem. You may modify this file however you wish, or
# you may choose not to use this file at all.
#
# N is the number of cabins.
N = None
# A contains the initial number of crewmates in each cabin. Note that here the
# cabins are numbered starting from 0.
A = []
# B contains the desired number of crewmates in each cabin. Note that here the
# cabins are numbered starting from 0.
B = []
answer = 0
# Open the input and output files.
input_file = open("spacein.txt", "r")
output_file = open("spaceout.txt", "w")
# Read the value of N.
N = int(input_file.readline().strip())
# Read the values of A and B.
input_line = input_file.readline().strip()
A = list(map(int, input_line.split()))
input_line = input_file.readline().strip()
B = list(map(int, input_line.split()))
AM = A
#AM is my modifying set
# TODO: This is where you should compute your solution. Store the fewest
# dollars you must pay before you can depart into the variable
while AM != B:
#Check if the set is correct
#notfound is a testing variable to see if my code was looping due to input error
notfound = True
for i in range(N):
#Check which places needs people to be moved
while AM[i]>B[i]:
notfound = False
#RV and LV check the "neediness" for each half's people requirements. I check how many people
#are needed on one side compared to the other and subtract the "overflow of people"
RV = 0
LV = 0
for j in range(int(N/2-0.5)):
#The range thing makes sure that if N is odd, im splitting the middle but if N is even, i leave out the end pod
RV += B[(i+j+1)%N]-AM[(i+j+1)%N]
LV += B[(i-j-1)%N]-AM[(i-j-1)%N]
answer +=1
if RV>LV:
AM[i]+=-1
AM[(i+1)%N]+=1
else:
AM[i]+=-1
AM[(i-1)%N]+=1
print(AM,B)
if notfound:
break
print(answer)
# Write the answer to the output file.
output_file.write("%d\n" % (answer))
# Finally, close the input/output files.
input_file.close()
output_file.close()
please help i really neeed to know the answer, driving me mad ngl
Welp, there aren't any resources online and I've tried everything. I think the problem might be that because of my solving method, passengers may be flicked between two pods indefinitely. Not sure since i could make a case that demoed this.
also my post probably is messy since this is my first time posting
I'm a newbie programmer working on an idea for a small game. I wanted my play space to be a grid for various reasons. Without a lot of good reason, I decided to create a class of GridSquare objects, each object having properties like size, an index to describe what (x,y) coordinates they represented, and some flags to determine if the grid squares were on land or empty space, for example. My grid is a dictionary of these objects, where each GridSquare is a key. The values in the dictionary are going to be various objects in the place space, so that I can easily look up which objects are on each grid square.
Just describing this I feel like a complete lunatic. Please bear in mind that I've only been at this a week.
My problem appears when I try to change the GridSquare objects. For example, I want to use a list to generate the land on each level. So I iterate over the list, and for each value I look through my grid squares using a for loop until I find one with the right index, and flip the GridSquare.land property. But I found that this caused a runtime error, since I was changing keys in a dictionary I was looping through. OK.
Now what I'm trying to do is to create a list of the keys I want to change. For each item in my level-generating list, I go through all the GridSquares in my grid dictionary until I find the one with the index I'm looking for, then I append that GridSquare to a list of old GridSquares that need updating. I then make another copy of the GridSquare, with some properties changed, in a list of altered GridSquares. Finally, I delete any keys from my grid dictionary which match my list of "old" GridSquares, and then add all of the altered ones into my grid dictionary.
The problem is that when I delete keys from my grid dictionary which match my list of "old" keys, I run into keyerrors. I can't understand what is happening to my keys before I can delete them. Using try/except, I can see that it's only a small number of the keys, which seems to vary kind of arbitrarily when I change parts of my code.
I would appreciate any insight into this behaviour.
Here is code for anyone still reading:
aspect_ratio = (4, 3)
screen_size = (1280, 720)
#defining a class of objects called GridSquares
class GridSquare:
def __init__(self, x, y):
self.index = (x, y)
self.land = 0
#creates a dictionary of grid squares which I hope will function as a grid......
grid = {}
for x_index in range(1, (aspect_ratio[0] + 1)):
for y_index in range (1, (aspect_ratio[1] + 1)):
new_square = GridSquare(x_index, y_index)
grid[new_square] = None
#these are lists to hold changes I need to make to the dictionary of grid squares
grid_changes = []
old_gridsquares = []
#this unweildly list is meant to be used to generate a level. Numbers represent land, spaces are empty space.
for number_no, number in enumerate(["1", "1", "1", "1",
" ", " ", " ", " ",
"1", "1", "1", "1"]):
#makes grid squares land if they are designated as such in the list
for gridsquare in grid.keys():
#this if statement is meant to convert each letter's position in the list into an index like the grid squares have.
if gridsquare.index == ((number_no + 1) % (aspect_ratio[0]), ((number_no + 1) // (aspect_ratio[0] + 1)) + 1):
#create a list of squares that need to be updated, and a list of squares to be deleted
old_gridsquares.append(gridsquare)
flagged_gridsquare = GridSquare((number_no + 1) % (aspect_ratio[0]), ((number_no + 1) // (aspect_ratio[0] + 1)) + 1)
flagged_gridsquare.land = 1
#this part is meant to set the flag for the gridsquare that indicates if it is on the far side or the near side,
#if it is land
if number == "1":
flagged_gridsquare.near = 1
grid_changes.append(flagged_gridsquare)
#deletes from grid any items with a key that matches the old squares, and adds updated versions.
for old_gridsquare in old_gridsquares:
try:
del grid[old_gridsquare]
except:
print(old_gridsquare.index)
print(old_gridsquare.land)
for grid_change in grid_changes:
grid[grid_change] = None
I stumbled across an interesting probability problem about half an hour ago. https://en.wikipedia.org/wiki/100_prisoners_problem
Essentially, there are 100 boxes, drawers, etc, each with a unique number between 1-100 inside of them. There are also 100 prisoners. Each prisoner has 50 chances to find the box with their number. If even one does not, they all fail. The chances would be abysmally low if they all randomly picked 50 boxes, but there's a better strategy.
Each prisoner first opens the box labeled with their own number.
If this box contains their number, they are done and were successful.
Otherwise, the box contains the number of another prisoner, and they next open the drawer labeled with this number.
The prisoner repeats steps 2 and 3 until they find their own number, or fail because the number is not found in the first fifty opened drawers.
This should increase their chances to above 30 percent with the way everything can fall into a loop
I glanced through this and decided it was interesting enough to quickly code out in python, but I'm getting a really interesting (and probably wrong) result. Could someone take a look at the code?
import random
def begin(p=False): #print
prisoners = [i for i in range(100)]
boxes = prisoners.copy()
random.shuffle(boxes) #we now have a list of shuffled boxes. index represents box num
if p: #prints
for i,num in enumerate(boxes): #i=index, num=content of box. Just to print it out
print(i,num)
def run(p=True): #print
results ={"Success":False, "NumSucceed":0, "NumFail":0 }
for prisoner in prisoners: #Try every prisoner
fail = True #check if they fail
choice = boxes[prisoner] #initialize choice as box with prisoner num
for i in range(49): #49 becaues first choice counts as well
if choice==prisoner:
fail = False
break
choice = boxes[choice]
if fail:
results["NumFail"] +=1
else:
results["NumSucceed"]+=1
if results["NumSucceed"]==100:
results["Success"] = True
if p: #just if I choose not to print results
print(results)
return results
for i in range(100):
begin()
run()
How many ever times I run it I always get a failing result where 17 prisoners succeeded and the rest failed (I randomize the rotation of the boxes each time too). Does anyone know why? I hope I didn't just make some stupid error somewhere and waste your time lol, if you do look through this I'd appreciate it
Couple of notes first.
Make sure you keep locality/scope in mind with variables. You have a begin() function thats used to declare your variables for the entire script, but they aren't declared globally so when the other method runs, it won't be able to find the variables to declare in begin()
not sure how you got it to run as is tbh
so let's scrap the method and just initialize our prisoners and boxes
import random
prisoners = [i for i in range(100)]
boxes = [i for i in range(100)]
now you can put the shuffle in your run method, since only boxes need to be randomized and conceptually, randomizing boxes would be the first thing done each time the prisoner dilemma happens.
def run(p=True): #print
random.shuffle(boxes)
results ={"Success":False, "NumSucceed":0, "NumFail":0 }
# ...
I ran a couple times and got 20-40 out of 100 total runs where all prisoners found their tag
nice little riddle there.
I tried to execute your code, but ran into an NameError exception due to a name space problem. Basically both prisoners and boxes within your code are only defined while begin() is running.
I've used your solution and modified it a bit:
import random
from operator import countOf
PRISONERS = 100
class PrisonerProblemSolver:
def __init__(self) -> None:
# Generate prisoners and boxes
self.prisoners = list(range(PRISONERS))
self.boxes = self.prisoners.copy()
random.shuffle(self.boxes)
# collector for results
self.results = {"Success": False, "NumSucceed": 0, "NumFail": 0}
def solve(self):
for prisoner in self.prisoners:
fail = True
choice = self.boxes[prisoner] # tries own box first
for _ in range(49): # remaining attempts
if choice == prisoner:
fail = False # will not die
break
choice = self.boxes[choice] # follows and hopes
if fail:
self.results["NumFail"] += 1
else:
self.results["NumSucceed"] += 1
return self.results["NumSucceed"] == PRISONERS
if __name__ == '__main__':
solver = PrisonerProblemSolver()
results = []
# Let's look at 100 prisons
for _ in range(100):
solver = PrisonerProblemSolver()
results.append(solver.solve())
# how successful were they in dying?
print(countOf(results, True))
Hope this helps.
Best regards
Im writing an algorithm in Python which plays this game.
The current state of the board of tiles in the game is a dictionary in the form of:
{
<tile_id>: {
'counters': <number of counters on tile or None>,
'player': <player id of the player who holds the tile or None>,
'neighbours': <list of ids of neighbouring tile>
},
...
}
I have another dictionary which stores all of my tiles which are 'full' (i.e. a tile which has one less counter than its number of neighbours and where the player is me) This dictionary, full_tiles, is in the same form as the board dictionary above.
I am now trying to create a list, chains, where each element in the list is a dictionary of my full tiles that are neighbouring at least one other full tile (i.e a chain of full tiles). So this will be a list of all my seperate chains on the board.
Here is my code so far:
for tile_id, tile in full_tiles.items(): #iterates through all full tiles
current_tile = {tile_id : tile} #temporarily stores current tile
if not chains: #if chains list is empty
chains.append(current_tile) #begin list
else: #if list is not empty
for index, chain in enumerate(chains): #iterate though list of chains
if not (current_tile in chain): #if current tile is not in current chain
for tile_id2, tile2 in chain.items(): #iterate through tiles in current chain
for neighbour in tile2["neighbours"]: #iterate through each neighbour of current tile
#neighbour is in the form of tile_id
if neighbour in chain: #if current tile's neighbour is in chain
chain[tile_id] = tile #add tile to chain
It is very difficult for me to test and debug my code and check if it is working correctly as the code can only be run in an application that simulates the game. As you can see, there is quite a lot going on in this block of code with all of the nested loops which are difficult to follow. I cannot seem to think straight at the minute and so I cannot determine if this mess, in all honesty, will function as I hope.
While I am writing this, I have just realised that - on line 7 of this code - I am only checking if the current tile is not in the current chain and so there will be intersecting chains which, of course, will be a mess. Instead of this, I need to first check if the current tile is in not in any of the chains, not just one.
Apart from this error, will my code achieve what I am attempting? Or can you recommend a simpler, neater way to do it? (There has to be!)
Also, let me know if I have not given enough information on how the code is run or if I need to explain anything further, such as the contents of the board dictionary.
Thank you for any help in advance.
EDIT: Unfortunately, I was under a time constraint to complete this project, and as it was my first time ever working with Python, I currently lack the knowledge in the language to optimise my solution using the sources given below. Here is my final extremely ugly and messy solution to this problem which, in the end, worked fine and wasn't terribly inefficient given the small data set that the code works on.
for x in range(0, len(my_hexplode_chains) - 1):
match_found = False
for y in range(x + 1, len(my_hexplode_chains)):
for tile_id_x, tile_x in my_hexplode_chains[x].items(): #compare each chain in list
for tile_id_y, tile_y in my_hexplode_chains[y].items(): #to every other chain
for neighbour in tile_x["neighbours"]: #if tiles in different lists
if neighbour == tile_id_y: #are neighbours
match_found = True
my_hexplode_chains[x].update(my_hexplode_chains[y]) #append one chain to the other
del my_hexplode_chains[y] #delete appended chain
if match_found: #continue loop at next chain
break #very ugly way to do this
if match_found:
break
if match_found:
break
if match_found:
break
How about this optimization?
def find_match (my_hexplode_chains):
x = 0
len_chain = len(my_hexplode_chains)
while x <= len_chain:
y = x + 1
for tile_id_x, tile_x in my_hexplode_chains[x].items():
for tile_id_y, tile_y in my_hexplode_chains[y].items():
if tile_id_y in tile_x["neighbours"]:
my_hexplode_chains[x].update(my_hexplode_chains[y])
del my_hexplode_chains[y]
return True
x += 1
return False
You could pass this function after each move in your game and trace the output.
I haven't programmed in a year so I am a little rusty. I really want to incorporate a link list but I am having trouble remembering how the code works, and having to implement it in Python isn't helping.
I only have the Node Class set up so far. Apparently, I cant use overloaded constructors which is annoying...
Basically i want to write a program that prompts a user to enter X number of bucket. Each bucket will have an X amount of different color balls. The user will specify how many balls for each color.
I welcome any help!
class Node:
def __init__(self, bucketNumber ,colorONE, colorTWO,
colorTHREE, colorFOUR, colorFIVE ):
self.bucket = bucketNumber # index
self.color1 = colorONE # quantity
self.color2 = colorTWO # quantity
self.color3 = colorTHREE # quantity
self.color4 = colorFOUR # quantity
self.color5 = colorFIVE # quantity
def printN(bucketNum):
for i in range(0,bucketNum):
print(nodes[i].bucket, nodes[i].color1, nodes[i].color2, nodes[i].color3, nodes[i].color4, nodes[i].color5)
colors = []
nodes = []
count = []
bucketNum = int(raw_input("The are 2-5 buckets with 2-5 ball colors. Enter number of Buckets:"))
colorNum = int(raw_input("Enter number of Colors:"))
for i in range(0,colorNum):
colors.append(raw_input("Enter color: " + str(i+1) ))
for i in range(0,bucketNum):
for j in range(0,colorNum):
count.append((raw_input("How many "+ colors[j] +" balls in bucket " + str(i+1))))
nodes.append( Node(i+1, count[0], count[1], count[2], count[3], count[4]) )
del count[ 0:len(count) ]
for i in range(0,colorNum):
print colors[i],
print " "
printN(bucketNum)
You don't seem to have a question, but note that there is probably no need to use a linked list, unless your list will have many insertions AND be large (because of python list memory allocation; and I wouldn't assume that this was a problem until it showed up in profiling), or if you will have many insertions and deletes at the ends of the list.
In that case, python provides collections.deque which is a linked sequence.