Constrained random points on a circle
You are encouraged to solve this task according to the task description, using any language you may know.
The task is to generate a stream of 100 uniformly distributed random points (x,y integer pairs) that lie in a circular disc at 10 to 15 units from its center; and then display/plot them to show a fuzzy circle. The actual number plotted may be less than 100, because some will overlap.
There are several possible approaches, depending on your language. One is simply to generate random pairs of integers and filter out those that don't satisfy the equation
Another is to precalculate the set of all possible points (there are 404 of them) and select from this set. Yet another is to use real-valued polar coordinates then snap to integer Cartesian coordinates. I'm sure there are others.
Haskell
Using Knuth Shuffle <lang haskell>import Data.List import Control.Monad import Control.Arrow import Rosetta.Knuthshuffle
task = do
let blanco = replicate (31*31) " " cs = sequence [[-15,-14..15],[-15,-14..15]] :: Int constraint = uncurry(&&).((<= 15*15) &&& (10*10 <=)). sum. map (join (*))
-- select and randomize all circle points
pts <- knuthShuffle $ filter constraint cs
-- 'paint' first 100 randomized circle points on canvas
let canvas = foldl (\cs [x,y] -> replaceAt (31*(x+15)+y+15) "/ " cs ) blanco (take 100 pts)
-- show canvas
mapM_ (putStrLn.concat). takeWhile(not.null). map (take 31) $ iterate (drop 31) canvas</lang>
Output (added a trailing space per 'pixel'
*Main> task / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
J
This version deals 100 coordinates from the set of acceptable coordinates (much like dealing cards from a shuffled deck):
<lang j>gen=: ({~ 100?#)bind((#~ 1=99 225 I.+/"1@:*:),/,"0/~i:15)</lang>
Example use: <lang j> '*' (<"1]15+gen )} 31 31$' '
* * * * * * * * * * * * * * *** ** * * ** * ** * ** * * * * * * ** * ** ** ** * *** * ** * * ** * * ** * ** * * ** * * * * * * * ** * * ** * * * * * * ** * * * * * ** * * * ** * </lang>
PureBasic
<lang PureBasic>Procedure is_inrange(x,y,minlimit.f=10,maxlimit.f=15)
Protected.f z=Sqr(x*x+y*y) If minlimit<=z And z <=maxlimit ProcedureReturn 1 EndIf
EndProcedure
CreateImage(0,31,31) StartDrawing(ImageOutput(0)) For i=1 To 100
Repeat x=Random(30)-15: y=Random(30)-15 Until is_inrange(x,y) Plot(x+15,y+15,$0000FF)
Next StopDrawing()
Title$="PureBasic Plot" Flags=#PB_Window_SystemMenu OpenWindow(0,#PB_Ignore,#PB_Ignore,ImageWidth(0),ImageHeight(0),Title$,Flags) ImageGadget(0,0,0,30,30,ImageID(0)) Repeat: Event=WaitWindowEvent() Until Event=#PB_Event_CloseWindow</lang>
Python
Note that the diagram shows the number of points at any given position (up to a maximum of 9 points). <lang python>>>> from collections import defaultdict >>> from random import choice >>> world = defaultdict(int) >>> possiblepoints = [(x,y) for x in range(-15,16) for y in range(-15,16) if 10 <= abs(x+y*1j) <= 15] >>> for i in range(100): world[choice(possiblepoints)] += 1
>>> for x in range(-15,16): print(.join(str(min([9, world[(x,y)]])) if world[(x,y)] else ' ' for y in range(-15,16)))
1 1 1 1 11 1 1 1 1 111 1 1211 1 2 1 1 11 1 11 21 1 1 11 1 1 2 1 1 1 2 1 1 1 1 1 2 11 1 1 1 1 1 1 2 1 1 1 1 1 2 1 1 3 11 2 11 1 1 1 2 1 1 2 1 1 1 1 1 2 2 1 1 </lang>
If the number of samples is increased to 1100: <lang python>>>> for i in range(1000): world[choice(possiblepoints)] += 1
>>> for x in range(-15,16): print(.join(str(min([9, world[(x,y)]])) if world[(x,y)] else ' ' for y in range(-15,16)))
2 41341421333 5133333131253 1 5231514 14214721 24 326 21222143234122322 54235153132123344125 22 32331432 2422 33 5453135 4144344 132595 323123 4 6353 432224 5 4323 3 5313 23214 41433 42454 33342 332 4 34314 142 1 35 53
124211 53131
22221 152 4 22213 34562 654 4 4 212 24354 52232 544222 283323 411123 453325 251321 124332 2124134 2443226 2 113315 64324334 2412452 324 32121132363 4222434324635 5433 3113333123432112633 2131181233 424 47414232164 4 </lang>
SystemVerilog
<lang SystemVerilog>program main;
bit [39:0] bitmap [40];
class Point; rand bit signed [4:0] x; rand bit signed [4:0] y;
constraint on_circle_edge { (10*10) <= (x*x + y*y); (x*x + y*y) <= (15*15); };
function void do_point(); randomize; bitmap[x+20][y+20] = 1; endfunction endclass
initial begin Point p = new; repeat (100) p.do_point; foreach (bitmap[row]) $display( "%b", bitmap[row]); end
endprogram</lang>
Piping the output through sed to improve the contrast of the output:
% vcs -sverilog -R circle.sv | sed 's/0/ /g' 1 11 1 1 1 1 1 11 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 11 1 11 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 11 1111 1 1 111 1 11 1 111 1 11 1 1 1 1 1 1 1 11 1 1 1 11 1 1
Tcl
<lang tcl>package require Tcl 8.5
- Generate random point at specified distance from the centre
proc getPoint {range from to} {
set r2 [expr {$range / 2}] set f2 [expr {$from ** 2}] set t2 [expr {$to ** 2}] while 1 {
set x [expr {int($range * rand())}] set y [expr {int($range * rand())}] set d2 [expr {($x-$r2)**2 + ($y-$r2)**2}] if {$d2 >= $f2 && $d2 <= $t2} { return [list $y $x] }
}
}
- Make somewhere to store the counters
set ary [lrepeat 31 [lrepeat 31 0]]
- Generate 100 random points
for {set i 0} {$i < 100} {incr i} {
set location [getPoint 31 10 15] # Increment the counter for the point lset ary $location [expr {1 + [lindex $ary $location]}]
}
- Simple renderer
foreach line $ary {
foreach c $line {
puts -nonewline [expr {$c == 0 ? " " : $c > 9 ? "X" : $c}]
} puts ""
}</lang> Example output:
1 1 1 1 1 1 2 1 1 11 1 1 1 11 1 1 1 1 1 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 2 1 2 2 1 1 1 11 1 1 1 1 1 2 1 1 1 1 1 1 1 11 1 2 1 1 11 11 1 1 1 1 2 1 11 121 1 1 1 1 1 1