7
\$\begingroup\$

Statement

Given an input like this 35 15 0 0 10 that matches the following constrains:

  • Width in characters of the grid (5-50)
  • Height in characters of the grid (5-25)
  • Initial X position of the ball (0-(Width-1)
  • Initial Y position of the ball (0-(Height-1)
  • Number of movements to simulate

Generate a grid that shows the trajectory of the ball, knowing it's direction is initially DR (down-right) and that colliding with a wall will reverse the increment being applied to that axis. In other words, if we are going DR and hit the bottom we will now be going UR until we collide again.

The trajectory is not affected by passing twice over the same point since it's not the game snake, it's the trajectory of an object in 2d.

The input will be a string such as the one above and the output should be similar to this, not caring about which characters represent the wall, trajectory or ball, as long as they're consistent.

enter image description here

Points

Your score is the length of your submission, in characters.

Winners by language

var QUESTION_ID=81035,OVERRIDE_USER=19121;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

\$\endgroup\$
16
  • \$\begingroup\$ The border characters are not ASCII \$\endgroup\$
    – Luis Mendo
    May 31, 2016 at 23:13
  • \$\begingroup\$ That's why it's a bonus to have them \$\endgroup\$ May 31, 2016 at 23:14
  • \$\begingroup\$ @JuanCortés I think he means they aren't ascii art then. \$\endgroup\$
    – Riker
    May 31, 2016 at 23:16
  • 1
    \$\begingroup\$ Some languages don't support non-ASCII chars. Can the border be formed with say +-| symbols? \$\endgroup\$
    – Luis Mendo
    May 31, 2016 at 23:18
  • 4
    \$\begingroup\$ Your example figure seems to have 48 movements, not 50. Can you check? \$\endgroup\$
    – Luis Mendo
    May 31, 2016 at 23:54

7 Answers 7

4
\$\begingroup\$

MATL, 35 34 characters

Z"42Gi:qi!+lGqE!/tYo-KM!*|QYoZ}X](

Try it online!

Explanation

This takes care of the reflections using the formulas

nx = 2*(Nx-1)
px = abs(t/nx-round(t/nx))*nx

where t is a time variable that increases in steps of 1, Nx is the maximum size along the x direction and px is the computed x position. Analogous formulas are used for the y coordinate.

A char matrix of spaces is initially created, and then it is filled with character * at the computed x and y positions.

Z"     % Implicitly take [width height]. Push char matrix of spaces with that size
42     % Push 42. ASCII for character `*`
G      % Push first input again, that is, [width height]
i      % Take number of movements, M
:q     % Range [0 1 ... M-1]
i!     % Take initial position [x y]. Transpose into column vector
+      % Add element-wise with broadcast. Gives 2-row vector
lG     % Push first input, [width height]
qE!    % Transform into column vector [2*width-2; 2*height-2]
/      % Divide element-wise with broadcast
tYo    % Duplicate. Round to closest integer
-      % Subtract
KM!    % Push [2*width-2; 2*height-2] again
*      % Multiply element-wise with broadcast
|      % Absolute value
Q      % Add 1
Yo     % Round to closest integer
Z}     % Separate 2-row array into two row arrays. These contain row and column
       % indices, respectively, of the ball positions 
X]     % Convert row and colummn indices to linear index
(      % Assign 42 to those positions of the matrix of spaces
\$\endgroup\$
1
  • \$\begingroup\$ This looks like black magic! \$\endgroup\$
    – Potaito
    Jun 5, 2016 at 19:57
2
\$\begingroup\$

Python 180 172 171 163 145 Bytes

(-2 Bytes with Python3)

def r(m,n,x,y,t):
 s=([' ']*m+['\n'])*n;a=b=1
 for c in'o'*(t-1)+'x':s[x+y*m+y],x,y=c,x+a,y+b;a*=2*(0<x<m-1)-1;b*=2*(0<y<n-1)-1
 print''.join(s)

To save 2 more bytes with Python3 (thanks to shooqie) replace second line with

 s=[*' '*m,'\n']*n

Had to use a list of characters because python does not support string item assignement. The x+y*m+y part is from x+y*(m+1) because of the '\n' add each line end

Edit1: right after posting, saw how to get rid of the overwriting 'x'

Edit2: space after print

Edit3: using < and > instead ==, also tabs for 2nd indentation

Edit4: Replaced the if statements with assignements, daisy-chaining less-than and placing the loop in one line (thanks to RootTwo)

\$\endgroup\$
6
  • \$\begingroup\$ Not sure if it works in Python 2, but you can do s=[*' '*m,'\n']*n instead of s=([' ']*m+['\n'])*n. Also, I believe you can omit the space between print and ''.join(s) as well as the space between x==0 (y==0) and or \$\endgroup\$
    – shooqie
    Jun 1, 2016 at 15:36
  • \$\begingroup\$ Does not work in Python 2 and now I don't want to switch languages, but I'll put your suggestion into the post. The space after print can be omitted, the one before or not \$\endgroup\$
    – Karl Napf
    Jun 1, 2016 at 16:15
  • \$\begingroup\$ Simple statements can be put on one line and separated by ;. This removes the bytes used by the leading indent. For example: ` s=([' ']*m+['\n'])*n;a=b=1` eliminates the ' ' before the a saving one byte (the ';' basically replaces the '\n'). Changing the if statements to assignment statements would let the for i... loop go on a single line and save another 6 bytes. \$\endgroup\$
    – RootTwo
    Jun 3, 2016 at 2:07
  • \$\begingroup\$ @RootTwo Merging the if statements into the assignement did not work for me, since they rely on the updated positions. I also could not find a shorter way of assignement instead of if. \$\endgroup\$
    – Karl Napf
    Jun 5, 2016 at 1:42
  • 1
    \$\begingroup\$ Try 'a*=2*(0<x<m-1)-1' instead of if x<1 or x>m-2:a=-a. Same for y and b. The loop can be for c in 'o'*(t-1)+x:, then 'xo'[i<t-1] becomes c. \$\endgroup\$
    – RootTwo
    Jun 5, 2016 at 7:03
1
\$\begingroup\$

JavaScript, 293 279

Nothing too clever going on here.

EDIT: Saved 14 characters by initialising the 2D array differently.

p=prompt().split(' ')
a=[];for(i=0;i++<p[1];)a.push(new Array(~~p[0]).fill(' '))
x=~~p[2];y=~~p[3]
d=e=1
for(i=0;i++<p[4];){a[y][x]=i==p[4]?'x':'o'
if(x<1&&d<0||x>p[0]-2&&d>0)d*=-1
if(y<1&&e<0||y>p[1]-2&&e>0)e*=-1
x+=d;y+=e}o=''
for(i=0;i++<p[1];)o+=a[i-1].join('')+'\n'
alert(o)

\$\endgroup\$
3
  • \$\begingroup\$ You can initialise a 2d array by doing a=Array(size).map(_=>Array(size).fill' ')(replace '-s with a back tick \$\endgroup\$
    – Bálint
    Jun 1, 2016 at 7:57
  • \$\begingroup\$ You should specify the input format. With 35 15 0 0 10 I don't get the expected result \$\endgroup\$
    – Luis Mendo
    Jun 1, 2016 at 15:29
  • \$\begingroup\$ Array.fill is ES6, in which case you might as well use [..." ".repeat(p[0])] \$\endgroup\$
    – Neil
    Jun 1, 2016 at 19:22
1
\$\begingroup\$

R, 156 bytes/chars

As an unnamed function. It's quite long but I quite like the method. There's probably a better way to do the 1 to w to 1 vector.

function(w,h,x,y,i)cat(c(' ','o')[1:(w*h)%in%(rep(c(c(1:w),c((w-1):2)),i)[x:((i=i-1)+x)+1]+(rep(c(c(1:h),c((h-1):2)),i)*w-w)[y:(i+y)+1])*1+1],fill=w,sep='')

Brief explanation of function internals

cat(                                                 # output to STDOUT
  c(' ','o')                                         # vector of characters
    [1:(w*h)%in%(                                    # number of characters in the board
      rep(c(c(1:w),c((w-1):2)),i)[x:((i=i-1)+x)+1]+  # oscillating vector of x to w to 1 to x
      (rep(c(c(1:h),c((h-1):2)),i)*w-w)[y:(i+y)+1]   # similar to above but in steps of w
    *1+1]                                            # cause a vector of 1 or 2 to pick char
  ,fill=w,sep='')                                    # print width of w, no separator

Like the other current answers this doesn't output the border, but I will add one if required.

\$\endgroup\$
1
\$\begingroup\$

Javascript ES6 202 181 177 chars

(w,h,x,y,s)=>(a=(r=Array)(h).fill().map(_=>r(w).fill` `),eval("for(vx=vy=1;s--;x+=vx,y+=vy,a){a[y][x]=0;if(!x||x==w-1)vx*=-1;if(!y||y==h-1)vy*=-1;}"),a.map(r=>r.join``).join`
`)

Not very golfed, I take a another look at it once I get home.

\$\endgroup\$
4
  • \$\begingroup\$ Score is in chars here. \$\endgroup\$ Jun 1, 2016 at 13:37
  • \$\begingroup\$ @ΈρικΚωνσταντόπουλος The count is the same in chars too \$\endgroup\$
    – Bálint
    Jun 1, 2016 at 13:46
  • \$\begingroup\$ Your header should say "chars"/"char" or "characters"/"character". Not "bytes"/"byte". \$\endgroup\$ Jun 1, 2016 at 13:55
  • \$\begingroup\$ array comps. + Array.keys might save you some bytes \$\endgroup\$
    – Downgoat
    Jun 5, 2016 at 20:42
1
\$\begingroup\$

C++11, 355 Bytes

Takes input string as command line arguments

#include <iostream>
#define A(n,i) int n=atoi(a[i]);
int main(int,char**a) {
A(w,1)A(h,2)A(x,3)A(y,4)A(n,5)
int d=1,r=1;
auto b=new int64_t[h];
while(--n>1){
b[y]|=1<<x;
if(r)x++;else x--;
if(d)y++;else y--;
if(x==0||x==w-1)r=!r;
if(y==0||y==h-1)d=!d;
}
for(int i=0;i<h;++i){
for(int j=0;j<w;++j){
std::cout<<(x==j&&y==i?'x':b[i]&(1<<j)?'o':' ');
}
std::cout<<'\n';
}  
}

Don't worry about the newlines, they are already removed from the count.

Storing the rows as 64-Bit integer is okay since maximum width is 50.

\$\endgroup\$
0
\$\begingroup\$

Q, 94 Bytes (kx.com)

{[w;h;i;j;n]./[(1+h,w)#" ";+{z#y_+\0,-1 1@{x=2*_x%2}'&(-_-(z+y)%x)#x}.'(h,j,n;w,i,n);:;"*"]}.

Defines a lambda with parameters w (width), h (height), i (initial x), j (initial y), and n (number of movements).

Lambda is delimited with {}

Final . (after }) allows to use a sequence as argument. Standard function invocation is f[arg;arg;..;arg], but we can also invoque as f . sequence. An integer sequence is v v .. v, so we can invoque as f . w h i j n. If we define f:{..}. we can invoque as f w h i j n (as required by the question)

Solution uses 'K mode' of Q. K is the functional inner core of Q (Q is more readable, verbose and with a lot of additional libraries, but K is compact). To execute in K mode we must use scripts with k extension (vs q extension for q mode). Interactive interpreter starts in Q mode (-> q) prompt). We can load code from k script, and execute test directly on interactive interpreter (even in q mode, as shown in test). There is also a k mode at interactive interpreter level, but it's not worth in this case.

TEST

NOTE.- to avoid display cluttering, we assume f name associated to lambda (f:{..}.)

q)f 35 15 0 0 49
"*                             *     "
" *                           * *    "
"  *                         *   *   "
"   *                       *     *  "
"    *                     *       * "
"     *                   *         *"
"      *                 *         * "
"       *               *         *  "
"        *             *         *   "
"         *           *         *    "
"          *         *         *     "
"           *       *         *      "
"            *     *   *     *       "
"             *   *     *   *        "
"              * *       * *         "
"               *         *          "
q)f 35 15 4 2 49
"                                *   "
"                               * *  "
"    *                         *   * "
"     *                       *     *"
"      *                     *     * "
"       *                   *     *  "
"        *                 *     *   "
"         *               *     *    "
"          *             *     *     "
"           *           *     *      "
"            *     *   *     *       "
"             *     * *     *        "
"              *     *     *         "
"               *   * *   *          "
"                * *   * *           "
"                 *     *            "

EXPLANATION

We define a lambda for 1D movement that accepts args [max;init;n] (legal positions 0..max-1, initial pos init, n movements) and returns a sequence of positions (after computing rebounds). Later apply that lambda to y and x axes (with args [h;j;n] and [w;i;n] respectively).

  • Initially assume starting at 0 pos. We calculate number of rebounds to accomplish n movements, and generate a sequence with repeated increasing numbers (0 0 ...0; 1 1 .. 1; 2 2 .. 2; ..).

  • Each subsequence has w items, so there are rebounds just between subsequences. For each number determine if is even, and sustitutes even results by 1 and even results by -1. (1 1 .. 1; -1 -1 .. -1; 1 1 .. 1; ..)

  • We join subsequences and calculate accumulated sums starting with 0 -> 0 1 2 3 .. 35 34 33 32 .. 0 1 2 ..

  • finally we drop starting i movements and take exactly n movements

Last, we define a (h x w) char matrix filled with blanks, and for each position (resulting of applying 1D lambda on y and x) we replace character with "*"

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.