/ elixirgolf Public

# Elixir Rock, Paper, Scissors#4

Open
opened this issue Dec 11, 2015 · 7 comments
Open

# Elixir Rock, Paper, Scissors #4

opened this issue Dec 11, 2015 · 7 comments

### henrik commented Dec 11, 2015

 (I'll keep editing this one post for my solutions.) 200 characters with some error checking: `import Enum;case IO.gets''do<>->x=for _<-1..3,do: random'rps';s=sum map zip([a,b,c],x),fn{v,v}->0;{?p,?r}->1;{?r,?s}->1;{?s,?p}->1;_->-1end;IO.puts [x,s<0&&"Lose"||s>0&&"Win"||"Draw"];_->end` (Was inspired to give `map` a shot after seeing @hassox's solution – thank you! Also borrowed `-1end` – hadn't realized you could skip the `;` in that one.) This is basically what it does: Get input and run it through a case statement. The case statement does nothing (`_ ->`) if it's not three chars followed by a newline. Otherwise, it sticks those chars into three vars `a, b, c` and… Assigns the computer's three chars to an Erlang string `x` Calculates your score `s` by comparing each pair of your chars and the computer's. Each equal pair (draw) is 0, wins are 1, losses are -1. These three numbers are summed together. If the sum is 0, the match is a draw. If the sum is negative, it's a loss. If positive, you win. Some things to note: I did not seed the randomness but in a "real" thing I believe you should. Maybe Elixir 1.2 does it automatically? `10` is ASCII for a newline. `Enum.random`, `Enum.sum`, `Enum.map` and `Enum.zip` are all used without the module name (thanks to the import). The specification isn't completely clear, so I chose to do some minimal error handling: Only handles input of exactly 3 chars Quietly returns if given any other length of input, but doesn't validate the exact characters 186 chars without error checking: `import Enum;<>=IO.gets'';x=for _<-1..3,do: random'rps';s=sum map zip([a,b,c],x),fn{v,v}->0;{?p,?r}->1;{?r,?s}->1;{?s,?p}->1;_->-1end;IO.puts [x,s<0&&"Lose"||s>0&&"Win"||"Draw"]` Older version, 196 chars, `for` + anonymous function instead of `map`: `import Enum;<>=IO.gets'';x=for _<-1..3,do: random'rps';s=sum for{p,c}<-zip([a,b,c],x),do: fn[v,v]->0;'pr'->1;'rs'->1;'sp'->1;_->-1;end.([p,c]);IO.puts [x,s<0&&"Lose"||s>0&&"Win"||"Draw"]` If we don't care about independent probabilities, we can shorten the randomness a little (my first solution did this until I realized my mistake): `…;x=take_random'rrrpppsss',3;…` Just for fun, this is one way (probably not the shortest one) to add stricter input checking to my solutions above, like @mmrobins brought up: `…<>when a in'rps'and b in 'rps'and c in'rps'->…` You can't use a variable for the `'rps'` here, sadly. Using Erlang strings instead of tuples for the zipping – ended up longer: `…;s=sum map :lists.zipwith(&[&1,&2],[a,b,c],x),fn[v,v]->0;'pr'->1;'rs'->1;'sp'->1;_->-1end;…` @henrik on Twitter.

### hassox commented Dec 11, 2015

 This is my first one of these. Never been a code golfer before. I measured it at 203 characters: `import Enum;import String;case(zip(codepoints(strip(IO.gets"")),take_random(~w(r p s),3))|>map(fn{a,a}->0;{"r","s"}->1;{"p","r"}->1;{"s","p"}->1;_->-1end)|>sum)do 0->"Draw";a when a>0->"Win";_->"Lose"end` This has no error checking. Here's what it does: Get the IO and splits it into a list of codepoints, i.e. `["r", "p", "s"]` Zip this together with a random shuffle of the list `["r", "p", "s"]` (computer move) to produce a list of tuples `[{"r", "p"}, {"p", "r"}, {"s", "s"}]`. The first element is the user move, second is the computer move. Map over the tuples using a guard clause on the function to identify draws `{a, a}` and set those to 0, identify wins r/s, s/p, p/r and set those to 1, all others are -1. Sum these up case on the previous value, 0 == "Draw", > 0 == "Win", otherwise "Lose" @hassox on Twitter

### henrik commented Dec 11, 2015

 @hassox That's a neat solution! This one wasn't easy :) Some thoughts: I think `take_random` won't repeat values, so you could never get "rrr" for example. If I understood the description correctly, you want to also show the computer's choices in the output.

### mmrobins commented Dec 11, 2015

 I'm nowhere close for character count (341), but here's my solution anyway: ``````import String;import Enum;l= ~w{r p s};m=IO.gets "";n=m|>strip|>split("",trim: true);if any?(n,fn(x)->!member?(l,x)end)do;else;f = fn()->random l end;o = [f.(), f.(), f.()];IO.puts o;g=fn(x)->case x do;{x,x}->0;{"r","s"}->1;{"p","r"}->1;{"s","p"}->1;_->-1;end;end;case zip(n,o)|>map(g)|>sum do;0->"Draw";x when x > 0->"Win";_->"Lose";end;end; `````` https://gist.github.com/mmrobins/df54ebe7cf28f58c2a00 easier to read version One thing I noticed from the other solutions up to this point is they don't seem to exit if you give bad input, like "abc" Twitter: @mmrobins

### markolson commented Dec 11, 2015

 This 355'er has a bunch of inefficiencies I probably can't get rid of easily given how I trial-and-error'd my way through writing it, but it does have some checks to make sure that the input is only 'r', 'p', or 's'. ``````import Enum;t='rps';c=fn(s)->into(s,HashSet.new)end;s=(IO.gets"")|>String.strip|>String.to_char_list;case count(Set.difference(c.(s),c.(t)))do 0 when length(s)==3->e=for x<-s,do: {x,random(t)};IO.puts map(e,&(elem(&1,1)));x=sum(map(e,fn(x)->case x do {x,x}->0;{?r,?s}->1;{?p,?r}->1;{?s,?p}->1;_->-1end end));IO.puts(x<0&&"Lose"||x>0&&"Win"||"Draw");_->end `````` Reads the user input, strips it and converts it to a character list Checks if all the characters are in the set of 'r', 'p', 's', and uses a cond to bail out if not. Generates a list of {user,system} guesses Scores 1 if the user wins, 0 if a draw, and -1 if the system won Outputs the system guesses Sums the win/loss records Outputs the result https://gist.github.com/markolson/420d59d8a6f665254a5e for the gist, @mark_olson for twitter.

### f-lombardo commented Dec 17, 2015

 I don't know if it could be acceptable :-) , but this is 193 chars: `case IO.gets''do<>->{f, n}=Enum.random([{fn ?r->?p;?p->?s;?s->?r;_->:ko;end,"Lose"},{fn ?p->?r;?s->?p;?r->?s;_->:ko;end,"Win"},{&(&1),"Draw"}]);IO.puts <><>n;_->end` Twitter: @f_lombardo

### emson commented Dec 18, 2015

 @f-lombardo great solution thanks. Yes it is acceptable - also I made a typo: `Loose -> Lose` therefore could you update your solution which is now `193` chars! Well done.