My Question is as follows:
Objective or problem statement : Find the dots in rectangle that are separated by a distance and store it in a list (collection) which will be my final output
Spec:
We start with an x offset and y offset to begin with and then we keep on incrementing in x and y direction till we reach upper right rectangle boundary.
Expected Output
My rect_boundary is {0 0} {112 96} as llx lry urx ury (lower left x, lower right y, upper right x .... cordinates) It can change each time based on procedural argument , rectangle box can be (00) (200 200) I have used this as an example
x offset for first red box = 5
y offset from first red box to boundary = 5
Distance between 1st and 2nd dot = 45, Distance between 2 and 3 = 45 , Distance between 4 and 5 = 45, Distance between 6 and 7 = 45 , so basically all horizontal points are separated by a distance of 45, that will always stay constant.
1 , 2 and 4 form a triangle, so "4 is located exactly in center of 1 and 2 but vertical distance of 45.
Example: 1st point = (5 5 ) , 2nd point = (50 5) so position of "4th point" will be ((5+50/2), 5+45) i.e., (27.5 50)
Position of 5th point on row 2 will be dependent on 4 as their cordinate will be (27.5+45, 50) = (72.5 50)
Now position of 6 and 7 point in rectangle will also be dependent on point 4
Center Point = Box 4 (x, y+45) = (27.5 95) and Box 6 = {(27.5 -45/2) 95) = (5, 95)
i.e Point 6 will be exactly on top of Point 1 = (5, 95)
What I have tried so far and it is giving slightly different output
set output [open "output.txt" w]
proc getPointList {rect_boundary xOffset yOffset } {
global output
set cordlist $rect_boundary
set xl [lindex $cordlist 0]
set yl [lindex $cordlist 1]
set xh [lindex $cordlist 2]
set yh [lindex $cordlist 3]
set xIncr 45
set yIncr 45
set x_margin 2
set y_margin 2
set count 0
set list ""
for {set y [expr {$yl +$yOffset}]} {$y <= $yh} {incr y $yIncr} {
for {set x [expr {$xl + $xOffset}]} {$x <= $xh } {incr x $xIncr} {
set point_lookup_window [list [list [expr {$x - $x_margin}] [expr {$y - $y_margin}]] [list [expr {$x + $x_margin}] [expr {$y + $y_margin}]]]
set point_list [index collection [(#some logic_ get_boxes -within $point_lookup_window] 0]
}
incr count
puts $point_list
}
}
set rect_boundary {0 0 111 96}
set xOffset 5
set yOffset 5
getPointList $rect_boundary $xOffset $yOffset
close $output
Note: Rectanglular boundary and offsets will change as they are procedural arguments
Above code gives me equidistant points (have shown dots) as follows, so need the calculation from 2nd row onwards working
Please help expedite and feel free to ask questions.
For each row, you're initializing x at the same value, $xl + $xOffset.
That's what you want for the 1st, 3rd, 5th, ... rows, but x in the even rows should be initialized by an extra half of $xIncr.
I see you're setting a count variable which will keep track of the odd/even rows. You can use this variable to make odd/even rows different.
for {set y [expr {$yl +$yOffset}]} {$y <= $yh} {incr y $yIncr} {
# Define x_start differently on odd/even rows
if {$count % 2 == 0} {
set x_start [expr {$xl + $xOffset}]
} else {
set x_start [expr {$xl + $xOffset + $xIncr/2}]
}
# Iterate x as usual.
for {set x $x_start} {$x <= $xh } {incr x $xIncr} {
...
...
}
incr count
puts $point_list
}
Related
I was playing around with the following problem:
Given a 2-d array find all the possible ways we can move from the top
left cell [0][0] to the bottom right cell [N-1][N-1] given that we
can only move either downward or rightward?
I defined the following:
For an array such as [ [ 1 ] ] there is only 1 way to go from the start cell to the destination cell. We are already there.
Otherwise it the total number of ways is the total number of ways we go from the cell to the right to the destination plus 1 (there is 1 way to go from current cell to the next cell) plus the total number of ways we go from the cell bellow to the destination plus 1 (there is 1 way to go from current cell to the bellow cell)
So for an array such as:
[
[1, 2]
[3, 4]
]
the answer would be 4 (1->2, 2->4, 1->3, 3->4).
For an array such as:
[
[1, 2, 3],
[3, 4, 5],
]
The answer should be 8. 4 comes from the subarray to the right + 1 to go for (1)->(2) plus 1->3 3->4 4->5 total 3.
So 5 + 3 = 7.
The following code seems to me correct but I am messing something up and I get the wrong result.
my $array = [
[1, 2, 3],
[3, 4, 5],
];
sub number_of_ways {
my ( $input, $source_row, $source_col, $dest_row, $dest_col ) = #_;
if ( $source_row == $dest_row && $source_col == $dest_col ) {
return 1;
}
if ( $source_row >= scalar #$input) {
return 0;
}
if ( $source_col >= scalar #{$input->[$source_row]} ) {
return 0;
}
my $ways_down = number_of_ways($input, $source_row + 1, $source_col, $dest_row, $dest_col);
my $ways_right = number_of_ways($input, $source_row, $source_col + 1, $dest_row, $dest_col);
my $total = $ways_right + 1 if ( $ways_right );
$total += $ways_down + 1 if ( $ways_down );
return $total;
}
print "Number of ways: " . number_of_ways($array, 0, 0, 1, 2). "\n";
This give me 11.
Is the logic wrong?
Update:
With the help of #m69 I found the problem.
In recursion is a bad idea to do the iteration if we already can check if it is going to fail. In this case, even after changing the code after the comments of #m69 it failed because there is no distinction between 0 because we are in an subarray with 1 element (source and destination are the same) or outside of the array.
The following code seems to be correct.
sub number_of_ways {
my ( $input, $source_row, $source_col, $dest_row, $dest_col ) = #_;
if ( $source_row == $dest_row && $source_col == $dest_col ) {
return 0;
}
my $total = 0;
if ( $source_row < #$input - 1) {
my $ways_down = number_of_ways($input, $source_row + 1, $source_col, $dest_row, $dest_col);
$total += $ways_down + 1;
}
if ( $source_col < #{$input->[$source_row]} - 1 ) {
my $ways_right = number_of_ways($input, $source_row, $source_col + 1, $dest_row, $dest_col);
$total += $ways_right + 1;
}
return $total;
}
print "Number of ways: " . number_of_ways($array, 0, 0, 1, 2). "\n";
Your algorithm uses this recursion:
0 1 2 0---1 2 0
= + |
3 4 5 4 5 3 4 5
which then goes on to:
1 2 1---2 1
= + | AND
4 5 5 4 5 3 4 5 = 3---4 5
and then:
2 2
= | AND AND
5 5 4 5 = 4---5 4 5 = 4---5
and finally:
5 AND 5 AND 5
In itself, this is a useful way of recursing in the 3x2 grid, but the way you then add the steps is problematic; e.g. after receiving 4 as the result of the recursion with the 2x2 grid [[1,2][4,5]], you add 1 to it because it takes 1 step to go from position 0 to the 2x2 grid. However, there are two paths through the 2x2 grid, so you should add the 1 step twice. Knowing how many paths there were through the 2x2 grid requires calculating the Taxicab distance through it, and then dividing the number of steps by this distance. You'll see that this results in a lot of unnecessary calculations, because the number of steps in each complete path is always the same. So it's much easier to just find the number of paths, and then multiply them by the number of steps per path.
You can use the recursion you have to find the number of paths; from the breakdown into steps of the recursion above you'll see that you end up with the 1x1 grid [5] three times. This is because there are three paths that lead to position 5. If you simply count how many times you recurse with that 1x1 grid), you know the number of paths. To know the number of steps you can then multiply by (width - 1) + (height - 1) which is the number of steps in each path.
The disadvantage of simply incrementing a variable outside the scope of the recursion is that you cannot easily turn it into a dynamic programming solution, because you have to go through with every recursion to the end, to count how many times you get to the bottom-right corner. So it's probably better to pass the results back up the recursion chain.
If you return 1 when the input is a 1x1 grid, and the sum of the right and down result in a larger grid (without adding anything to it), this also gives you the total number of paths. Then you can memoize the results by storing that a 2x1 and 1x2 grid return 1, a 2x2 grid returns 2, a 3x2 and 2x3 grid returns 3, a 3x3 grid returns 6, and use these stored values instead of recursing over grids with the same size again.
You'll see that the number of paths through any size grid is given by this table:
1 1 1 1 1 ...
1 2 3 4 5
1 3 6 10 15
1 4 10 20 35
1 5 15 35 70
where each value is the sum of the values above and to the left of it, which also points to a simple non-recursive way to calculate the number of paths (or steps) through any size grid.
This code snippet in JavaScript uses the recursion method from your code to count the number of paths, and then calculates the total number of steps:
function count_paths(grid, x, y) {
x = x || 0; y = y || 0;
var height = grid.length - y;
var width = grid[0].length - x;
if (width == 0 || height == 0) return 0;
if (width == 1 && height == 1) return 1;
return count_paths(grid, x + 1, y) + count_paths(grid, x, y + 1);
}
var grid = [[0,1,2,3],[4,5,6,7],[8,9,10,11],[12,13,14,15]];
var paths = count_paths(grid);
var steps = paths * (grid.length - 1 + grid[0].length - 1);
document.write("paths: " + paths + "<br>steps: " + steps);
To integrate the calculation of the total number of steps into the recursion, you'd have to return the number of paths and the number of steps, so that you can multiply the step it takes to go right or down by the number of paths that that step leads to:
function count_steps(grid, x, y) {
x = x || 0; y = y || 0;
var height = grid.length - y;
var width = grid[0].length - x;
if (width == 0 || height == 0) return {paths: 0, steps: 0};
if (width == 1 && height == 1) return {paths: 1, steps: 0};
var right = count_steps(grid, x + 1, y);
var down = count_steps(grid, x, y + 1);
var paths = right.paths + down.paths;
var steps = right.steps + down.steps + paths;
return {paths: paths, steps: steps};
}
var grid = [[0,1,2,3],[4,5,6,7],[8,9,10,11],[12,13,14,15]];
var count = count_steps(grid);
document.write("paths: " + count.paths + "<br>steps: " + count.steps);
I am trying to allocate (x, y) points to the cells of a non-uniform rectangular grid. Simply speaking, I have a grid defined as a sorted non-equidistant array
xGrid = [x1, x2, x3, x4];
and an array of numbers x lying between x1 and x4. For each x, I want to find its position in xGrid, i.e. such i that
xGrid(i) <= xi <= xGrid(i+1)
Is there a better (faster/simpler) way to do it than arrayfun(#(x) find(xGrid <= x, 1, 'last'), x)?
You are looking for the second output of histc:
[~,where] = histc(x, xGrid)
This returns the array where such that xGrid(where(i)) <= x(i) < xGrid(where(i)+1) holds.
Example:
xGrid = [2,4,6,8,10];
x = [3,5,6,9,11];
[~,where] = histc(x, xGrid)
Yields the following output:
where =
1 2 3 4 0
If you want xGrid(where(i)) < x(i) <= xGrid(where(i)+1), you need to do some trickery of negating the values:
[~,where] = histc(-x,-flip(xGrid));
where(where~=0) = numel(xGrid)-where(where~=0)
This yields:
where =
1 2 2 4 0
Because x(3)==6 is now counted for the second interval (4,6] instead of [6,8) as before.
Using bsxfun for the comparisons and exploiting find-like capabilities of max's second output:
xGrid = [2 4 6 8]; %// example data
x = [3 6 5.5 10 -10]; %// example data
comp = bsxfun(#gt, xGrid(:), x(:).'); %'// see if "x" > "xGrid"
[~, result] = max(comp, [], 1); %// index of first "xGrid" that exceeds each "x"
result = result-1; %// subtract 1 to find the last "xGrid" that is <= "x"
This approach gives 0 for values of x that lie outside xGrid. With the above example values,
result =
1 3 2 0 0
See if this works for you -
matches = bsxfun(#le,xGrid(1:end-1),x(:)) & bsxfun(#ge,xGrid(2:end),x(:))
[valid,pos] = max(cumsum(matches,2),[],2)
pos = pos.*(valid~=0)
Sample run -
xGrid =
5 2 1 6 8 9 2 1 6
x =
3 7 14
pos =
8
4
0
Explanation on the sample run -
First element of x, 3 occurs last between ...1 6 with the criteria of xGrid(i) <= xi <= xGrid(i+1) at the backend of xGrid and that 1 is at the eight position, so the first element of the output pos is 8. This continues for the second element 7, which is found between 6 and 8 and that 6 is at the fourth place in xGrid, so the second element of the output is 4. For the third element 14 which doesn't find any neighbours to satisfy the criteria xGrid(i) <= xi <= xGrid(i+1) and is therefore outputted as 0.
If x is a column this might help
xg1=meshgrid(xGrid,1:length(x));
xg2=ndgrid(x,1:length(xGrid));
[~,I]=min(floor(abs(xg1-xg2)),[],2);
or a single line implementation
[~,I]=min(floor(abs(meshgrid(xGrid,1:length(x))-ndgrid(x,1:length(xGrid)))),[],2);
Example: xGrid=[1 2 3 4 5], x=[2.5; 1.3; 1.7; 4.8; 3.3]
Result:
I =
2
1
1
4
3
I am new to Tcl arrays. My question is as follows.
I have a rectangle box with two rows R1 and R2. Each of these rows has 8 different values.
I want to return these 16 values (x and y coordinates) either in a text file or as an list output from a proc. I read some earlier posts about Tcl proc cannot output an array unless we use dict.
So, I will try to draw a picture so u can understand my question better.
R1 x1y1 x2y2 ... x8,y8
R2 x9,y9 ... x16, y16
Expected output when I run the proc either on command prompt or in a file with dummy values as an example
$> (1,2) (2,3) (3,4) ....... (7,8)
(9,10) (10,11) ......... (15,16)
So this is what I tried and I am getting the results that I need. But this is hardcoded for two rows. I want to make it able to detect how many rows are there and then accordingly output the number of rows.
proc getPointList {rect_boundary rowOffset colOffset rowIncr colIncr } {
set cordlist $rect_boundary
set xl [lindex $cordlist 0]
set yl [lindex $cordlist 1]
set xh [lindex $cordlist 2]
set yh [lindex $cordlist 3]
set list "" ;
for {set y [expr {$yh - $colOffset}]} {$y >= [expr {$yl + $colOffset}]} { incr y $colIncr } {
for {set x [expr {$xl + $rowOffset}]} {$x <= [expr {$xh - $rowOffset}]} { incr x $rowIncr } {
set list "$list $x $y" ;
puts "Value of x is: $x"; puts "\t Value of y is: $y" ;
}
}
return $list
}
set rect_boundary {10 15 100 40} # xl yl xh yh
set rowOffset 5
set colOffset 5
set rowIncr 10
set colIncr 15
Some Logic I need to implement in this code based on yh-yl and xh-xl to calculate height and width of rectangle and accordingly output rows
Command to call the proc
$> getPointList $rect_boundary $rowOffset $colOffset $rowIncr $colIncr
Just for your understanding there are eight x,y points inside the rectangle on a particular row.
x offset is the first x point on a row from the left or roght boundary, thereafter all the points are separated by an increment value which I call rowIncr. Same holds true for column.
Expected output : This is what the above code does but it is hardcoded for two rows. I want to increase and implement the logic if the rows and column are variable.
$> R1: (15 40) (25 40) (35 40) (45 40) (55 40) (65 40) (75 40) (85 40) (95 40)
R2: (15 15) (25 15) (35 15) (45 15) (55 15) (65 15) (75 15) (85 15) (95 15)
Rectangle Image for better clarity as this thing wont let me update pictures
__________________________________________________________________________ (100,40)
| |- 5 |
| . . . . . . . . |
| |- 15 |
|-5-. . --10---. . . . . . |
| |
|_________________________________________________________________________|
(10,15)
For Jerry:
Case1 rowIncr 10 colIncr 20
__________________________________________________________________________ (80,40)
| |- 5 |
| . . . . . . . . |
| |- 20 |
|-5-. . --10---. . . . . . |
| |
|_________________________________________________________________________|
(10,10)
Case2 rowIncr 20 colIncr 35
_________________________________________________ (100,70)
| |- 5 |
| . . . . . |
| |- 35 |
|-5-. . --20---. . . |
| | |-5 |
|________________________________________________|
(10,25)
and so on ...
Okay, I think I now understand what you were trying to do, and I think that your proc would have worked for any number of rows after some fixing:
set output [open "output.txt" w]
proc getPointList {rect_boundary rowOffset colOffset plist} {
global output
set cordlist $rect_boundary
set xl [lindex $cordlist 0]
set yl [lindex $cordlist 1]
set xh [lindex $cordlist 2]
set yh [lindex $cordlist 3]
set xpoints [llength [lindex $plist 0]]
set ypoints [llength $plist]
set rowIncr [expr {($xh-$xl-2*$rowOffset)/($xpoints-1)}]
set colIncr [expr {($yh-$yl-2*$colOffset)/($ypoints-1)}]
set count 0
set list ""
for {set y [expr {$yh - $colOffset}]} {$y >= [expr {$yl + $colOffset}]} {incr y -$colIncr} {
for {set x [expr {$xl + $rowOffset}]} {$x <= [expr {$xh - $rowOffset}]} {incr x $rowIncr} {
lappend list "($x,$y)"
}
incr count
puts $output "R$count: [join $list " "]"
set list ""
}
}
set plist {{A B C D E} {A B C D E} {A B C D E} {A B C D E} {A B C D E}}
set rect_boundary {0 0 100 100}
set rowOffset 0
set colOffset 0
getPointList $rect_boundary $rowOffset $colOffset $plist
close $output
I changed the colIncr to put more rows.
In the first loop, I used incr y -$colIncr because this is actually a decrement if you start with the higher y coordinate.
I also changed the output structure to match the one you were looking for. The above snippet returns the coordinates:
R1: (0,100) (25,100) (50,100) (75,100) (100,100)
R2: (0,75) (25,75) (50,75) (75,75) (100,75)
R3: (0,50) (25,50) (50,50) (75,50) (100,50)
R4: (0,25) (25,25) (50,25) (75,25) (100,25)
R5: (0,0) (25,0) (50,0) (75,0) (100,0)
EDIT: Added variable offsets, blank final row and variable columns per row.
proc getPointList {rect_boundary uRowOffset lRowOffset uColOffset lColOffset plist} {
set cordlist $rect_boundary
set xl [lindex $cordlist 0]
set yl [lindex $cordlist 1]
set xh [lindex $cordlist 2]
set yh [lindex $cordlist 3]
set xpoints 0
foreach r $plist {
if {[llength $r] > $xpoints} {set xpoints [llength $r]}
}
set ypoints [llength $plist]
set rowIncr [expr {($xh-$xl-$lRowOffset-$uRowOffset)/($xpoints-1)}]
set colIncr [expr {($yh-$yl-$lColOffset-$uColOffset)/$ypoints}]
set count 0
set list ""
for {set y [expr {$yh - $uColOffset}]} {$y >= [expr {$yl + $lColOffset}]} {incr y -$colIncr} {
set x [expr {$xl + $lRowOffset}]
foreach n [lindex $plist $count] {
lappend list $x $y
incr x $rowIncr
}
incr count
if {$count == $ypoints} {return $list}
}
}
set plist {{A B C D X} {E F G H} {I K L} {M N}}
set qlist 1
foreach n $plist {
set pattern$plist $n
incr qlist
}
set rect_boundary {0 0 100 100}
set upperRowOffset 0
set lowerRowOffset 0
set upperColOffset 0
set lowerColOffset 0
set pointList [getPointList $rect_boundary $upperRowOffset $lowerRowOffset $upperColOffset $lowerColOffset $plist]
set count 1
foreach sub_list $plist {
foreach n $sub_list {
set pattern$count $n
incr count
}
}
set count 1
foreach {a b} $pointList {
set text "pattern$count"
puts "command -point $a,$b -text [set $text]"
incr count
}
It is up to you how to organize the nested lists. In simplest form, return a single list:
set result {x1 y1 x2 y2 ... x16 y16}
Or, you can have a list of two rows:
set result {
{x1 y1 x2 y2 ... x8 y8}
{x9 y9 x10 y10 ... x16 y16}
}
Or, more complex: each pair is a sub-list:
set result {
{ {x1 y1} {x2 y2} ... }
{ {x9 y9} {x10 y10} ... }
}
I don't think you want to use array in this case. FYI, an "array" in TCL is equivalent to a hash in other languages.
Well, with Tcl 8.6
proc parsedata {input} {
lmap a [split $input \n] {
lmap b [split $b \t] {
regexp {x(\d+),?\s*y(\d+)} $b -> c d
list $c $d
}
}
}
Now you can process the data, for example:
foreach line [parsedata $input] {
puts [lmap pair $line {
expr {"([lindex $line 0],[linedex $line 1])"}
}
}
I wanted to create a list of numbers with missing numbers in a given list as provided in the example below
Existing list { 1,3, 5, 9 , 13, 15}
Resultant list { 2,4,6,7,8,10,11,12,14}
Extended TCL has the function intersect3 which as one of its return values gives a list of A-B. You could intersect your list with a list of all possible numbers that span your list.
If you don't use Extended TCL, you'll have to implement something yourself.
I hardly ever use TCL, so maybe there's a better way, but the basic approach is to just sort the list, then run through it and find the missing values:
#!/usr/bin/tclsh
set A {1 3 5 9 13 15}
set A [lsort -integer $A]
set B {}
set x 0
set y [lindex $A $x]
while {$x < [llength $A]} {
set i [lindex $A $x]
while {$y < $i} {
lappend B $y
incr y
}
incr x
incr y
}
puts $B
Output:
2 4 6 7 8 10 11 12 14
paddy's answer looks pretty good. This is a bit shorter, assumes the list is already sorted.
package require Tcl 8.5
set A {1 3 5 9 13 15}
set result [list]
for {set i [lindex $A 0]; incr i} {$i < [lindex $A end]} {incr i} {
if {$i ni $A} {
lappend result $i
}
}
See http://tcl.tk/man/tcl8.5/TclCmd/expr.htm#M15 for the "ni" operator.
I have an array: A B AB BAB ABBAB BABABBAB ... The number of each term of the array is base on the Fibonacci number.Put the n-th string and the n+1-th string together, then producing the n+2-th string,eg.BABABBAB = BAB + ABBAB.
Then is the 10^16-th letter is A or B?
Let f[n] be the nth fibonacci number.
Assume we want to find the value at position x in the string obtained by concatenating f[1], f[2], ..., f[n].
Find the lowest k such that f[1] + f[2] + ... + f[k] >= x. So position x belongs to word that has f[k] characters (at least in the concatenation it does. But since all words are made up from a and b, we'll try to reduce the problem to just those two).
To find the position corresponding to x in the term f[k], subtract f[1] + ... + f[k - 1] from x.
if k = 1 print a, if k = 2 print b, else go to step 4.
if f[k - 2] < x, then the position we're looking for is in the word corresponding to (with length) f[k - 1]. Subtract 1 from k and f[k - 2] from x and go to step 3.
Else, the position we're looking for is in the word corresponding to f[k - 2]. Subtract 2 from k, leave x unchanged and go to step 3.
This doesn't require generating the actual words, just their lengths, which are the basic fibonacci numbers.
Worked example
- note that I'm only using the actual words for illustration purposes, they are not needed.
n f[n] corresponding word
1 1 a
2 1 b
3 2 ab
4 3 bab
5 5 abbab
6 8 bababbab
Concatenating all these we get: ababbababbabbababbab. Let's ask ourselves what's at position 10 (it's b).
1. f[1] + f[2] + f[3] + f[4] + f[5] >= 10, so k = 5
2. x = 10, f[1] + f[2] + f[3] + f[4] = 7, so subtract 7 from x, giving x = 3
3'. k isn't 1 or 2, skip this.
4'. f[k - 2 = 3] = 2 < x. k = 4, x = 1
3''. still ignoring this.
4'' f[k - 2 = 2] = 1 >= x. k = 2, x = 1
3'''. k = 2, print 'b'.
please don't take this answer too serious:
i never was good and math and this sounds like this task should be too heavy to calculate without a freaky algorithm, so my solution would be to simply have a guess. to choose between A and B, i would write a very simple programm like this in php to print out the first 15 or 20 "lines":
<?php
$var1 = "B";
$var2 = "A";
for($i=3;$i<=15;$i++){
$tmp = $var2;
$var2 = $var1;
$var1 = $tmp.$var1;
echo $i." ".$var1."<br>";
}
echo strlen(implode('',explode('B',$var1)));
echo "<br>";
echo strlen(implode('',explode('A',$var1)));
?>
the result shows there are always less As (38%) than Bs (62%) - so the chance to be right when guessing B aren't that bad.