Issue with nested loops in Ruby - ruby
So I right now I have a list of edges of a graph. With this list, I'm trying to build a adjacency map, in which its key is an edge and the value is a list of edges that are adjacent to the edge. I'm using a nested loop that compares each edge in the list to every other edge in the list. However, this is not building a map that I expect it to. Below is my code:
def build_adjacency
#paths.each do |start_path|
#paths.each do |end_path|
# 3 cases for edge adcency
if (start_path.end_node == end_path.start_node) || (start_path.start_node == end_path.end_node) || (start_path.start_node == end_path.start_node)
if #adjacency_map.has_key?("#{start_path}".to_s)
#adjacency_map[:"#{start_path}".to_s] << end_path
else
value = [end_path]
#adjacency_map[:"#{start_path}".to_s] = value
end
end
end
end
end
I also tried array.combination but that is not working either. Thank you for the help.
Test input: (start node, end node, color, type)
A B R C
B E B C
B C B T
C D G T
Output for #adjacency_map:
C:\Users\Jin\Documents\Mines\Algorithms (CSCI 406)\Project_3>ruby graph.rb
Key: A B R C Value: [#<Path:0x2548a28 #start_node="A", #end_node="B", #color=
"R", #type="C">, #<Path:0x2548968 #start_node="B", #end_node="E", #color="B", #t
ype="C">, #<Path:0x25488a8 #start_node="B", #end_node="C", #color="B", #type="T"
>, #<Path:0x25487e8 #start_node="C", #end_node="D", #color="G", #type="T">]
Key: B E B C Value: [#<Path:0x2548a28 #start_node="A", #end_node="B", #color=
"R", #type="C">, #<Path:0x2548968 #start_node="B", #end_node="E", #color="B", #t
ype="C">, #<Path:0x25488a8 #start_node="B", #end_node="C", #color="B", #type="T"
>, #<Path:0x25487e8 #start_node="C", #end_node="D", #color="G", #type="T">]
Key: B C B T Value: [#<Path:0x2548a28 #start_node="A", #end_node="B", #color=
"R", #type="C">, #<Path:0x2548968 #start_node="B", #end_node="E", #color="B", #t
ype="C">, #<Path:0x25488a8 #start_node="B", #end_node="C", #color="B", #type="T"
>, #<Path:0x25487e8 #start_node="C", #end_node="D", #color="G", #type="T">]
Key: C D G T Value: [#<Path:0x2548a28 #start_node="A", #end_node="B", #color=
"R", #type="C">, #<Path:0x2548968 #start_node="B", #end_node="E", #color="B", #t
ype="C">, #<Path:0x25488a8 #start_node="B", #end_node="C", #color="B", #type="T"
>, #<Path:0x25487e8 #start_node="C", #end_node="D", #color="G", #type="T">]
The following is strange:
:"#{start_path}".to_s
What ever class your object start_path is, you convert it to a string via interpolation, than convert it to a symbol, only to then convert it to a string again. You can just use strings as hash keys. And in your call to has_key? you have not used the colon. (should normally make no difference)
Also, if you unsure about you implemented the condition correctly, I recommend to create a method to encapsulate it. Especially when the condition has a semantic meaning.
It seems that only problem with your code that it's not checking if start_path and end_path are the same. So, it adds unnecessary "A-B is adjacent to A-B" into your map.
Maybe you should try just add one line?
def build_adjacency
#paths.each do |start_path|
#paths.each do |end_path|
next if start_path == end_path # this one!
# 3 cases for edge adcency
if (start_path.end_node == end_path.start_node) || (start_path.start_node == end_path.end_node) || (start_path.start_node == end_path.start_node)
if #adjacency_map.has_key?("#{start_path}".to_s)
#adjacency_map[:"#{start_path}".to_s] << end_path
else
value = [end_path]
#adjacency_map[:"#{start_path}".to_s] = value
end
end
end
end
end
Here's my full code, reproducing the solution: https://gist.github.com/zverok/6785c213fd78430cd423
Related
using construct_undefined in ruamel from_yaml
I'm creating a custom yaml tag MyTag. It can contain any given valid yaml - map, scalar, anchor, sequence etc. How do I implement class MyTag to model this tag so that ruamel parses the contents of a !mytag in exactly the same way as it would parse any given yaml? The MyTag instance just stores whatever the parsed result of the yaml contents is. The following code works, and the asserts should should demonstrate exactly what it should do and they all pass. But I'm not sure if it's working for the right reasons. . . Specifically in the from_yaml class method, is using commented_obj = constructor.construct_undefined(node) a recommended way of achieving this, and is consuming 1 and only 1 from the yielded generator correct? It's not just working by accident? Should I instead be using something like construct_object, or construct_map or. . .? The examples I've been able to find tend to know what type it is constructing, so would either use construct_map or construct_sequence to pick which type of object to construct. In this case I effectively want to piggy-back of the usual/standard ruamel parsing for whatever unknown type there might be in there, and just store it in its own type. import ruamel.yaml from ruamel.yaml.comments import CommentedMap, CommentedSeq, TaggedScalar class MyTag(): yaml_tag = '!mytag' def __init__(self, value): self.value = value #classmethod def from_yaml(cls, constructor, node): commented_obj = constructor.construct_undefined(node) flag = False for data in commented_obj: if flag: raise AssertionError('should only be 1 thing in generator??') flag = True return cls(data) with open('mytag-sample.yaml') as yaml_file: yaml_parser = ruamel.yaml.YAML() yaml_parser.register_class(MyTag) yaml = yaml_parser.load(yaml_file) custom_tag_with_list = yaml['root'][0]['arb']['k2'] assert type(custom_tag_with_list) is MyTag assert type(custom_tag_with_list.value) is CommentedSeq print(custom_tag_with_list.value) standard_list = yaml['root'][0]['arb']['k3'] assert type(standard_list) is CommentedSeq assert standard_list == custom_tag_with_list.value custom_tag_with_map = yaml['root'][1]['arb'] assert type(custom_tag_with_map) is MyTag assert type(custom_tag_with_map.value) is CommentedMap print(custom_tag_with_map.value) standard_map = yaml['root'][1]['arb_no_tag'] assert type(standard_map) is CommentedMap assert standard_map == custom_tag_with_map.value custom_tag_scalar = yaml['root'][2] assert type(custom_tag_scalar) is MyTag assert type(custom_tag_scalar.value) is TaggedScalar standard_tag_scalar = yaml['root'][3] assert type(standard_tag_scalar) is str assert standard_tag_scalar == str(custom_tag_scalar.value) And some sample yaml: root: - item: blah arb: k1: v1 k2: !mytag - one - two - three-k1: three-v1 three-k2: three-v2 three-k3: 123 # arb comment three-k4: - a - b - True k3: - one - two - three-k1: three-v1 three-k2: three-v2 three-k3: 123 # arb comment three-k4: - a - b - True - item: argh arb: !mytag k1: v1 k2: 123 # blah line 1 # blah line 2 k3: k31: v31 k32: - False - string here - 321 arb_no_tag: k1: v1 k2: 123 # blah line 1 # blah line 2 k3: k31: v31 k32: - False - string here - 321 - !mytag plain scalar - plain scalar - item: no comment arb: - one1 - two2
In YAML you can have anchors and aliases, and it is perfectly fine to have an object be a child of itself (using an alias). If you want to dump the Python data structure data: data = [1, 2, 4, dict(a=42)] data[3]['b'] = data it dumps to: &id001 - 1 - 2 - 4 - a: 42 b: *id001 and for that anchors and aliases are necessary. When loading such a construct, ruamel.yaml recurses into the nested data structures, but if the toplevel node has not caused a real object to be constructed to which the anchor can be made a reference, the recursive leaf cannot resolve the alias. To solve that, a generator is used, except for scalar values. It first creates an empty object, then recurses and updates it values. In code calling the constructor a check is made to see if a generator is returned, and in that case next() is done on the data, and potential self-recursion "resolved". Because you call construct_undefined(), you always get a generator. Practically that method could return a value if it detects a scalar node (which of course cannot recurse), but it doesn't. If it would, your code could then not load the following YAML document: !mytag 1 without modifications that test if you get a generator or not, as is done in the code in ruamel.yaml calling the various constructors so it can handle both construct_undefined and e.g. construct_yaml_int (which is not a generator).
Tool/Algorithm for text comparision after every key hit
I am struggling to find a text comparison tool or algorithm that can compare an expected text against the current state of the text being typed. I will have an experimentee typewrite a text that he has in front of his eyes. My idea is to compare the current state of the text against the expected text whenever something is typed. That way I want to find out when and what the subject does wrong (I also want to find errors that are not in the resulting text but were in the intermediate text for some time). Can someone point me in a direction? Update #1 I have access to the typing data in a csv format: This is example output data of me typing "foOBar". Every line has the form (timestamp, Key, Press/Release) 17293398.576653,F,P 17293398.6885,F,R 17293399.135282,LeftShift,P 17293399.626881,LeftShift,R 17293401.313254,O,P 17293401.391732,O,R 17293401.827314,LeftShift,P 17293402.073046,O,P 17293402.184859,O,R 17293403.178612,B,P 17293403.301748,B,R 17293403.458137,LeftShift,R 17293404.966193,A,P 17293405.077869,A,R 17293405.725405,R,P 17293405.815159,R,R
In Python Given your input csv file (I called it keyboard_records.csv) 17293398.576653,F,P 17293398.6885,F,R 17293399.135282,LeftShift,P 17293399.626881,LeftShift,R 17293401.313254,O,P 17293401.391732,O,R 17293401.827314,LeftShift,P 17293402.073046,O,P 17293402.184859,O,R 17293403.178612,B,P 17293403.301748,B,R 17293403.458137,LeftShift,R 17293404.966193,A,P 17293405.077869,A,R 17293405.725405,R,P 17293405.815159,R,R The following code does the following: Read its content and store it in a list named steps For each step in steps recognizes what happened and If it was a shift press or release sets a flag (shift_on) accordingly If it was an arrow pressed moves the cursor (index of current where we insert characters) – if it the cursor is at the start or at the end of the string it shouldn't move, that's why those min() and max() If it was a letter/number/symbol it adds it in curret at cursor position and increments cursor Here you have it import csv steps = [] # list of all actions performed by user expected = "Hello" with open("keyboard.csv") as csvfile: for row in csv.reader(csvfile, delimiter=','): steps.append((float(row[0]), row[1], row[2])) # Now we parse the information current = [] # text written by the user shift_on = False # is shift pressed cursor = 0 # where is the cursor in the current text for step in steps: time, key, action = step if key == 'LeftShift': if action == 'P': shift_on = True else: shift_on = False continue if key == 'LeftArrow' and action == 'P': cursor = max(0, cursor-1) continue if key == 'RightArrow' and action == 'P': cursor = min(len(current), cursor+1) continue if action == 'P': if shift_on is True: current.insert(cursor, key.upper()) else: current.insert(cursor, key.lower()) cursor += 1 # Now you can join current into a string # and compare current with expected print(''.join(current)) # printing current (just to see what's happening) else: # What to do when a key is released? # Depends on your needs... continue To compare current and expected have a look here. Note: by playing around with the code above and a few more flags you can make it recognize also symbols. This will depend on your keyboard. In mine Shift + 6 = &, AltGr + E = € and Ctrl + Shift + AltGr + è = {. I think this is a good point to start. Update Comparing 2 texts isn't a difficult task and you can find tons of pages on the web about it. Anyway I wanted to present you an object oriented approach to the problem, so I added the compare part that I previously omitted in the first solution. This is still a rough code, without primary controls over the input. But, as you asked, this is pointing you in a direction. class UserText: # Initialize UserText: # - empty text # - cursor at beginning # - shift off def __init__(self, expected): self.expected = expected self.letters = [] self.cursor = 0 self.shift = False # compares a and b and returns a # list containing the indices of # mismatches between a and b def compare(a, b): err = [] for i in range(min(len(a), len(b))): if a[i] != b[i]: err.append(i) return err # Parse a command given in the # form (time, key, action) def parse(self, command): time, key, action = command output = "" if action == 'P': if key == 'LeftShift': self.shift = True elif key == 'LeftArrow': self.cursor = max(0, self.cursor - 1) elif key == 'RightArrow': self.cursor = min(len(self.letters), self.cursor + 1) else: # Else, a letter/number was pressed. Let's # add it to self.letters in cursor position if self.shift is True: self.letters.insert(self.cursor, key.upper()) else: self.letters.insert(self.cursor, key.lower()) self.cursor += 1 ########## COMPARE WITH EXPECTED ########## output += "Expected: \t" + self.expected + "\n" output += "Current: \t" + str(self) + "\n" errors = UserText.compare(str(self), self.expected[:len(str(self))]) output += "\t\t" i = 0 for e in errors: while i != e: output += " " i += 1 output += "^" i += 1 output += "\n[{} errors at time {}]".format(len(errors), time) return output else: if key == 'LeftShift': self.shift = False return output def __str__(self): return "".join(self.letters) import csv steps = [] # list of all actions performed by user expected = "foobar" with open("keyboard.csv") as csvfile: for row in csv.reader(csvfile, delimiter=','): steps.append((float(row[0]), row[1], row[2])) # Now we parse the information ut = UserText(expected) for step in steps: print(ut.parse(step)) The output for the csv file above was: Expected: foobar Current: f [0 errors at time 17293398.576653] Expected: foobar Current: fo [0 errors at time 17293401.313254] Expected: foobar Current: foO ^ [1 errors at time 17293402.073046] Expected: foobar Current: foOB ^^ [2 errors at time 17293403.178612] Expected: foobar Current: foOBa ^^ [2 errors at time 17293404.966193] Expected: foobar Current: foOBar ^^ [2 errors at time 17293405.725405]
I found the solution to my own question around a year ago. Now i have time to share it with you: In their 2003 paper 'Metrics for text entry research: An evaluation of MSD and KSPC, and a new unified error metric', R. William Soukoreff and I. Scott MacKenzie propose three major new metrics: 'total error rate', 'corrected error rate' and 'not corrected error rate'. These metrics have become well established since the publication of this paper. These are exaclty the metrics i was looking for. If you are trying to do something similiar to what i did, e.g. compare the writing performance on different input devices this is the way to go.
Remove nTh record from array using loop [closed]
Closed. This question needs debugging details. It is not currently accepting answers. Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question. Closed 6 years ago. Improve this question I'm writing a program that reads a .csv file, and then loops through it removing every 10th record it encounters before outputting it. I've been stuck on what I believe is a syntax issue for a while now and just can't seem to nail it. Anyone mind having a look? lines = [] i = 0 elements = [] element2 = [] output = [] file = File.open("./properties.csv", "r") while (line = file.gets) i += 1 # use split to break array up using commas arr = line.split(',') elements.push({ id: arr[0], streetAddress: arr[1], town: arr[2], valuationDate: arr[3], value: arr[4] }) end file.close # filter out blanks and nill rows x = elements.select { |elements| elements[:id].to_i >= 0.1} # Loop to remove every 10th record e = 0 d = 1 loop do x.length if e == (10 * d) d ++ e ++ else x = elements.select[e] e ++ end puts x puts "#{x.length} house in list, #{d} records skipped." CSV FILE ID,Street address,Town,Valuation date,Value 1,1 Northburn RD,WANAKA,1/1/2015,280000 2,1 Mount Ida PL,WANAKA,1/1/2015,280000 3,1 Mount Linton AVE,WANAKA,1/1/2015,780000 4,1 Kamahi ST,WANAKA,1/1/2015,155000 5,1 Kapuka LANE,WANAKA,1/1/2015,149000 6,1 Mohua MEWS,WANAKA,1/1/2015,560000 7,1 Kakapo CT,WANAKA,1/1/2015,430000 8,1 Mt Gold PL,WANAKA,1/1/2015,1260000 9,1 Penrith Park DR,WANAKA,1/1/2015,1250000 10,1 ATHERTON PL,WANAKA,1/1/2015,650000 11,1 WAIMANA PL,WANAKA,1/1/2015,780000 12,1 ROTO PL,WANAKA,1/1/2015,1470000 13,1 Toms WAY,WANAKA,1/1/2015,2230000 14,1 MULBERRY LANE,WANAKA,1/1/2015,415000 15,1 Range View PL,WANAKA,1/1/2015,300000 16,1 Clearview ST,WANAKA,1/1/2015,1230000 17,1 Clutha PL,WANAKA,1/1/2015,700000 18,1 Centre CRES,WANAKA,1/1/2015,295000 19,1 Valley CRES,WANAKA,1/1/2015,790000 20,1 Edgewood PL,WANAKA,1/1/2015,365000 21,1 HUNTER CRES,WANAKA,1/1/2015,335000 22,1 KOWHAI DR,WANAKA,1/1/2015,480000 23,1 RIMU LANE,WANAKA,1/1/2015,465000 24,1 CHERRY CT,WANAKA,1/1/2015,495000 25,1 COLLINS ST,WANAKA,1/1/2015,520000 26,1 AUBREY RD,WANAKA,1/1/2015,985000 27,1 EELY POINT RD,WANAKA,1/1/2015,560000 28,1 LINDSAY PL,WANAKA,1/1/2015,385000 29,1 WINDERS ST,WANAKA,1/1/2015,760000 30,1 Manuka CRES,WANAKA,1/1/2015,510000 31,1 WILEY RD,WANAKA,1/1/2015,420000 32,1 Baker GR,WANAKA,1/1/2015,820000 33,1 Briar Bank DR,WANAKA,1/1/2015,1260000 34,1 LAKESIDE RD,WANAKA,1/1/2015,440000 35,1 PLANTATION RD,WANAKA,1/1/2015,345000 36,1 Allenby PL,WANAKA,1/1/2015,640000 37,1 ROB ROY LANE,WANAKA,1/1/2015,380000 38,1 Ansted PL,WANAKA,1/1/2015,590000 39,1 Fastness CRES,WANAKA,1/1/2015,640000 40,1 APOLLO PL,WANAKA,1/1/2015,385000 41,1 AEOLUS PL,WANAKA,1/1/2015,370000 42,1 Peak View RDGE,WANAKA,1/1/2015,1750000 43,1 Moncrieff PL,WANAKA,1/1/2015,530000 44,1 Islington PL,WANAKA,1/1/2015,190000 45,1 Hidden Hills DR,WANAKA,1/1/2015,1280000 46,1 Weatherall CL,WANAKA,1/1/2015,425000 47,1 Terranova PL,WANAKA,1/1/2015,900000 48,1 Cliff Wilson ST,WANAKA,1/1/2015,1200000 49,1 TOTARA TCE,WANAKA,1/1/2015,460000 50,1 Koru WAY,WANAKA,1/1/2015,570000 51,1 Bovett PL,Wanaka,1/1/2015,495000 52,1 Pearce PL,Wanaka,1/1/2015,675000 53,1 Ironside DR,WANAKA,1/1/2015,570000 54,1 Bob Lee PL,WANAKA,1/1/2015,610000 55,1 Hogan LANE,WANAKA,1/1/2015,395000 56,1 ARDMORE ST,WANAKA,1/1/2015,1190000 57,1 Bullock Creek LANE,WANAKA,1/1/2015,11125000 58,1 DUNMORE ST,WANAKA,1/1/2015,1300000 59,1 Primary LANE,WANAKA,1/1/2015,430000 60,1 SYCAMORE PL,WANAKA,1/1/2015,720000 61,1 FAULKS TCE,WANAKA,1/1/2015,780000 62,1 Alpha CL,WANAKA,1/1/2015,500000 63,1 Coromandel ST,WANAKA,1/1/2015,530000 64,1 Niger ST,WANAKA,1/1/2015,475000 65,1 Maggies Way,WANAKA,1/1/2015,375000 66,1 Hollyhock LANE,QUEENSTOWN,1/1/2015,1080000 67,1 ELDERBERRY CRES,WANAKA,1/1/2015,1340000 68,1 Foxglove HTS,WANAKA,1/1/2015,2520000 69,1 MEADOWSTONE DR,WANAKA,1/1/2015,650000 70,1 OAKWOOD PL,WANAKA,1/1/2015,580000 71,1 MEADOWBROOK PL,WANAKA,1/1/2015,645000 72,1 Jessies CRES,WANAKA,1/1/2015,320000 73,1 Lansdown ST,WANAKA,1/1/2015,700000 74,1 Stonebrook DR,WANAKA,1/1/2015,640000 75,1 Hyland ST,WANAKA,1/1/2015,500000 76,1 TAPLEY PADDOCK,WANAKA,1/1/2015,720000 77,1 Homestead CL,WANAKA,1/1/2015,1750000 78,1 NORMAN TCE,WANAKA,1/1/2015,620000 79,1 Sunrise Bay DR,WANAKA,1/1/2015,3000000 80,1 LARCH PL,WANAKA,1/1/2015,570000 81,1 MILL END,WANAKA,1/1/2015,600000 82,1 Bills WAY,WANAKA,1/1/2015,750000 83,1 Heuchan LANE,WANAKA,1/1/2015,610000 84,1 SARGOOD DR,WANAKA,1/1/2015,455000 85,1 Frederick ST,WANAKA,1/1/2015,455000 86,1 Connell TCE,WANAKA,1/1/2015,600000 87,1 Soho ST,QUEENSTOWN,1/1/2015,320000 88,1 Hikuwai DR,ALBERT TOWN,1/1/2015,280000 89,1 Harrier LANE,WANAKA,1/1/2015,1000000 90,1 Ewing PL,WANAKA,1/1/2015,780000 91,1 Sherwin AVE,ALBERT TOWN,1/1/2015,440000 92,1 Hardie PL,WANAKA,1/1/2015,830000 93,1 Finch ST,ALBERT TOWN,1/1/2015,540000 94,1 Poppy LANE,ALBERT TOWN,1/1/2015,395000 95,1 Warbler LANE,ALBERT TOWN,1/1/2015,410000 96,1 Balneaves LANE,WANAKA,1/1/2015,250000 97,1 Mill Green,Arrowtown,1/1/2015,800000
require 'csv' elements = {} CSV.foreach("properties.csv", :headers => true, :header_converters => :symbol) do |row| elements[row.fields[0]] = Hash[row.headers[1..-1].zip(row.fields[1..-1])] end d = 0 e = 0 elements.delete_if do |key, value| e += 1 if e == 10 e = 0 d += 1 end e == 0 end puts "#{elements.length} house in list, #{d} records skipped." At the end of this, elements will have every 10th row removed, and d contains the number of rows removed.
Positional Argument Undefined
I am working on a larger project to write a code so the user can play Connect 4 against the computer. Right now, the user can choose whether or not to go first and the board is drawn. While truing to make sure that the user can only enter legal moves, I have run into a problem where my function legal_moves() takes 1 positional argument, and 0 are given, but I do not understand what I need to do to male everything agree. #connect 4 #using my own formating import random #define global variables X = "X" O = "O" EMPTY = "_" TIE = "TIE" NUM_ROWS = 6 NUM_COLS = 8 def display_instruct(): """Display game instructions.""" print( """ Welcome to the second greatest intellectual challenge of all time: Connect4. This will be a showdown between your human brain and my silicon processor. You will make your move known by entering a column number, 1 - 7. Your move (if that column isn't already filled) will move to the lowest available position. Prepare yourself, human. May the Schwartz be with you! \n """ ) def ask_yes_no(question): """Ask a yes or no question.""" response = None while response not in ("y", "n"): response = input(question).lower() return response def ask_number(question,low,high): """Ask for a number within range.""" #using range in Python sense-i.e., to ask for #a number between 1 and 7, call ask_number with low=1, high=8 low=1 high=NUM_COLS response = None while response not in range (low,high): response=int(input(question)) return response def pieces(): """Determine if player or computer goes first.""" go_first = ask_yes_no("Do you require the first move? (y/n): ") if go_first == "y": print("\nThen take the first move. You will need it.") human = X computer = O else: print("\nYour bravery will be your undoing... I will go first.") computer = X human = O return computer, human def new_board(): board = [] for x in range (NUM_COLS): board.append([" "]*NUM_ROWS) return board def display_board(board): """Display game board on screen.""" for r in range(NUM_ROWS): print_row(board,r) print("\n") def print_row(board, num): """Print specified row from current board""" this_row = board[num] print("\n\t| ", this_row[num], "|", this_row[num], "|", this_row[num], "|", this_row[num], "|", this_row[num], "|", this_row[num], "|", this_row[num],"|") print("\t", "|---|---|---|---|---|---|---|") # everything works up to here! def legal_moves(board): """Create list of column numbers where a player can drop piece""" legals = [] if move < NUM_COLS: # make sure this is a legal column for r in range(NUM_ROWS): legals.append(board[move]) return legals #returns a list of legal columns #in human_move function, move input must be in legal_moves list print (legals) def human_move(board,human): """Get human move""" legals = legal_moves(board) print("LEGALS:", legals) move = None while move not in legals: move = ask_number("Which column will you move to? (1-7):", 1, NUM_COLS) if move not in legals: print("\nThat column is already full, nerdling. Choose another.\n") print("Human moving to column", move) return move #return the column number chosen by user def get_move_row(turn,move): move=ask_number("Which column would you like to drop a piece?") for m in range (NUM_COLS): place_piece(turn,move) display_board() def place_piece(turn,move): if this_row[m[move]]==" ": this_row.append[m[move]]=turn display_instruct() computer,human=pieces() board=new_board() display_board(board) move= int(input("Move?")) legal_moves() print ("Human:", human, "\nComputer:", computer)
Right down the bottom of the script, you call: move= int(input("Move?")) legal_moves() # ^ no arguments This does not supply the necessary board argument, hence the error message.
Radix sort not working in Lua
Firstly I should mention I've not been coding very long at all, although that much is probably obvious from my code :P I'm having two problems, firstly the sort isn't functioning correctly but does sort the numbers by their length. Any help here would be appreciated. Secondly it's changing both the table it grabs and the table it returns (not sure why). How do I prevent it changing the table it grabs? I'd prefer if people didn't post a fully optisimised premade code as I'm not going to learn or understand anything that way. function radix_sort(x) pass, bucket, maxstring = 0, x, 2 while true do pass = pass + 1 queue = {} for n=#bucket,1,-1 do key_length = string.len(bucket[n]) key = bucket[n] if pass == 1 and key_length > maxstring then maxstring = key_length end if key_length == pass then pool = string.sub(key, 1,1) if queue[pool + 1] == nil then queue[pool + 1] = {} end table.insert(queue[pool + 1], key) table.remove(bucket, n) end end for k,v in pairs(queue) do for n=1,#v do table.insert(bucket, v[n]) end end if pass == maxstring then break end end return bucket end
There's a lot of changes I made to get this working, so hopefully you can look through and pickup on them. I tried to comment as best I could. function radix_sort(x) pass, maxstring = 0, 0 -- to avoid overwriting x, copy into bucket like this -- it also gives the chance to init maxstring bucket={} for n=1,#x,1 do -- since we can, convert all entries to strings for string functions below bucket[n]=tostring(x[n]) key_length = string.len(bucket[n]) if key_length > maxstring then maxstring = key_length end end -- not a fan of "while true ... break" when we can set a condition here while pass <= maxstring do pass = pass + 1 -- init both queue and all queue entries so ipairs doesn't skip anything below queue = {} for n=1,10,1 do queue[n] = {} end -- go through bucket entries in order for an LSD radix sort for n=1,#bucket,1 do key_length = string.len(bucket[n]) key = bucket[n] -- for string.sub, start at end of string (LSD sort) with -pass if key_length >= pass then pool = tonumber(string.sub(key, pass*-1, pass*-1)) else pool = 0 end -- add to appropriate queue, but no need to remove from bucket, reset it below table.insert(queue[pool + 1], key) end -- empty out the bucket and reset, use ipairs to call queues in order bucket={} for k,v in ipairs(queue) do for n=1,#v do table.insert(bucket, v[n]) end end end return bucket end Here's a test run: > input={55,2,123,1,42,9999,6,666,999,543,13} > output=radix_sort(input) > for k,v in pairs(output) do > print (k , " = " , v) > end 1 = 1 2 = 2 3 = 6 4 = 13 5 = 42 6 = 55 7 = 123 8 = 543 9 = 666 10 = 999 11 = 9999
pool = string.sub(key, 1,1) always looks at the first character; perhaps you meant string.sub(key, pass, 1)