World Cup group stage: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added Erlang)
Line 72: Line 72:
0 18 136 273 290 4 8 0 0 0
0 18 136 273 290 4 8 0 0 0
108 306 184 125 6 0 0 0 0 0 </pre>
108 306 184 125 6 0 0 0 0 0 </pre>

=={{header|Erlang}}==
This solution take advantage of the expressiveness power of the list comprehensions expressions. Function ''combos'' is copied from [http://panduwana.wordpress.com/2010/04/21/combination-in-erlang/ panduwana blog].

<lang erlang>
-module(world_cup).

-export([group_stage/0]).

group_stage() ->
Results = [[3,0],[1,1],[0,3]],
Teams = [1,2,3,4],
Matches = combos(2,Teams),
AllResults =
combinations(Matches,Results),
AllPoints =
[lists:flatten([lists:zip(L1,L2) || {L1,L2} <- L]) || L <- AllResults],
TotalPoints =
[ [ {T,lists:sum([Points || {T_,Points} <- L, T_ == T])} || T <- Teams] || L <- AllPoints],
SortedTotalPoints =
[ lists:sort(fun({_,A},{_,B}) -> A > B end,L) || L <- TotalPoints],
PointsPosition =
[ [element(2,lists:nth(N, L))|| L <- SortedTotalPoints ] || N <- Teams],
[ [length(lists:filter(fun(Points_) -> Points_ == Points end,lists:nth(N, PointsPosition) ))
|| Points <- lists:seq(0,9)] || N <- Teams].

combos(1, L) ->
[[X] || X <- L];
combos(K, L) when K == length(L) ->
[L];
combos(K, [H|T]) ->
[[H | Subcombos] || Subcombos <- combos(K-1, T)]
++ (combos(K, T)).

combinations([H],List2) ->
[[{H,Item}] || Item <- List2];
combinations([H|T],List2) ->
[ [{H,Item} | Comb] || Item <- List2, Comb <- combinations(T,List2)].
</lang>

Output:
<pre>
[[0,0,0,1,14,148,152,306,0,108],
[0,0,4,33,338,172,164,18,0,0],
[0,18,136,273,290,4,8,0,0,0],
[108,306,184,125,6,0,0,0,0,0]]
</pre>


=={{header|Java}}==
=={{header|Java}}==

Revision as of 16:34, 27 December 2014

Task
World Cup group stage
You are encouraged to solve this task according to the task description, using any language you may know.

It's World Cup season (or at least it was when this page was created)! The World Cup is an international football/soccer tournament that happens every 4 years. Countries put their international teams together in the years between tournaments and qualify for the tournament based on their performance in other international games. Once a team has qualified they are put into a group with 3 other teams. For the first part of the World Cup tournament the teams play in "group stage" games where each of the four teams in a group plays all three other teams once. The results of these games determine which teams will move on to the "knockout stage" which is a standard single-elimination tournament. The two teams from each group with the most standings points move on to the knockout stage. Each game can result in a win for one team and a loss for the other team or it can result in a draw/tie for each team. A win is worth three points in the standings. A draw/tie is worth one point. A loss is not worth any points.

Generate all possible outcome combinations for the six group stage games. With three possible outcomes for each game there should be 36 = 729 of them. Calculate the standings points for each team with each combination of outcomes. Show a histogram (graphical, ASCII art, or straight counts--whichever is easiest/most fun) of the standings points for all four teams over all possible outcomes.

Don't worry about tiebreakers as they can get complicated. We are basically looking to answer the question "if a team gets x standings points, where can they expect to end up in the group standings?".

Hint: there should be no possible way to end up in second place with less than two points as well as no way to end up in first with less than three. Oddly enough, there is no way to get 8 points at all.

D

This imports the module of the third D solution of the Combinations Task.

Translation of: Python

<lang d>void main() {

   import std.stdio, std.range, std.array, std.algorithm, combinations3;
   immutable scoring = [0, 1, 3];
   /*immutable*/ auto r3 = [0, 1, 2];
   immutable combs = 4.iota.array.combinations(2).array;
   uint[10][4] histo;
   foreach (immutable results; cartesianProduct(r3, r3, r3, r3, r3, r3)) {
       int[4] s;
       foreach (immutable r, const g; [results[]].zip(combs)) {
           s[g[0]] += scoring[r];
           s[g[1]] += scoring[2 - r];
       }
       foreach (immutable i, immutable v; s[].sort().release)
           histo[i][v]++;
   }
   writefln("%(%s\n%)", histo[].retro);

}</lang>

Output:
[0, 0, 0, 1, 14, 148, 152, 306, 0, 108]
[0, 0, 4, 33, 338, 172, 164, 18, 0, 0]
[0, 18, 136, 273, 290, 4, 8, 0, 0, 0]
[108, 306, 184, 125, 6, 0, 0, 0, 0, 0]

This alternative version is not fully idiomatic D, it shows what to currently do to tag the main function of the precedent version as @nogc. <lang d>import core.stdc.stdio, std.range, std.array, std.algorithm, combinations3;

immutable uint[2][6] combs = 4u.iota.array.combinations(2).array;

void main() nothrow @nogc {

   immutable uint[3] scoring = [0, 1, 3];
   uint[10][4] histo;
   foreach (immutable r0; 0 .. 3)
    foreach (immutable r1; 0 .. 3)
     foreach (immutable r2; 0 .. 3)
      foreach (immutable r3; 0 .. 3)
       foreach (immutable r4; 0 .. 3)
        foreach (immutable r5; 0 .. 3) {
           uint[4] s;
           foreach (immutable i, immutable r; [r0, r1, r2, r3, r4, r5]) {
               s[combs[i][0]] += scoring[r];
               s[combs[i][1]] += scoring[2 - r];
           }
           foreach (immutable i, immutable v; s[].sort().release)
               histo[i][v]++;
        }
   foreach_reverse (const ref h; histo) {
       foreach (immutable x; h)
           printf("%u ", x);
       printf("\n");
   }

}</lang>

Output:
0 0 0 1 14 148 152 306 0 108 
0 0 4 33 338 172 164 18 0 0 
0 18 136 273 290 4 8 0 0 0 
108 306 184 125 6 0 0 0 0 0 

Erlang

This solution take advantage of the expressiveness power of the list comprehensions expressions. Function combos is copied from panduwana blog.

<lang erlang> -module(world_cup).

-export([group_stage/0]).

group_stage() -> Results = [[3,0],[1,1],[0,3]], Teams = [1,2,3,4], Matches = combos(2,Teams), AllResults = combinations(Matches,Results), AllPoints = [lists:flatten([lists:zip(L1,L2) || {L1,L2} <- L]) || L <- AllResults], TotalPoints = [ [ {T,lists:sum([Points || {T_,Points} <- L, T_ == T])} || T <- Teams] || L <- AllPoints], SortedTotalPoints = [ lists:sort(fun({_,A},{_,B}) -> A > B end,L) || L <- TotalPoints], PointsPosition = [ [element(2,lists:nth(N, L))|| L <- SortedTotalPoints ] || N <- Teams], [ [length(lists:filter(fun(Points_) -> Points_ == Points end,lists:nth(N, PointsPosition) )) || Points <- lists:seq(0,9)] || N <- Teams].

combos(1, L) -> [[X] || X <- L]; combos(K, L) when K == length(L) -> [L]; combos(K, [H|T]) ->

   [[H | Subcombos] || Subcombos <- combos(K-1, T)]
   ++ (combos(K, T)).

combinations([H],List2) -> [[{H,Item}] || Item <- List2]; combinations([H|T],List2) -> [ [{H,Item} | Comb] || Item <- List2, Comb <- combinations(T,List2)]. </lang>

Output:

[[0,0,0,1,14,148,152,306,0,108],
 [0,0,4,33,338,172,164,18,0,0],
 [0,18,136,273,290,4,8,0,0,0],
 [108,306,184,125,6,0,0,0,0,0]]

Java

Works with: Java version 1.5+

This example codes results as a 6-digit number in base 3. Each digit is a game. A 2 is a win for the team on the left, a 1 is a draw, and a 0 is a loss for the team on the left. <lang java5>import java.util.Arrays;

public class GroupStage{

   //team left digit vs team right digit
   static String[] games = {"12", "13", "14", "23", "24", "34"};
   static String results = "000000";//start with left teams all losing
   private static boolean nextResult(){
       if(results.equals("222222")) return false;
       int res = Integer.parseInt(results, 3) + 1;
       results = Integer.toString(res, 3);
       while(results.length() < 6) results = "0" + results;	//left pad with 0s
       return true;
   }
   public static void main(String[] args){
       int[][] points = new int[4][10]; 		//playing 3 games, points range from 0 to 9
       do{
           int[] records = {0,0,0,0};
           for(int i = 0; i < 6; i++){
               switch(results.charAt(i)){
                   case '2': records[games[i].charAt(0) - '1'] += 3; break;    //win for left team
                   case '1':                                                   //draw
                       records[games[i].charAt(0) - '1']++;
                       records[games[i].charAt(1) - '1']++;
                       break;
                   case '0': records[games[i].charAt(1) - '1'] += 3; break;    //win for right team
               }
           }
           Arrays.sort(records);	//sort ascending, first place team on the right
           points[0][records[0]]++;
           points[1][records[1]]++;
           points[2][records[2]]++;
           points[3][records[3]]++;
       }while(nextResult());
       System.out.println("First place: " + Arrays.toString(points[3]));
       System.out.println("Second place: " + Arrays.toString(points[2]));
       System.out.println("Third place: " + Arrays.toString(points[1]));
       System.out.println("Fourth place: " + Arrays.toString(points[0]));
   }

}</lang>

Output:
First place: [0, 0, 0, 1, 14, 148, 152, 306, 0, 108]
Second place: [0, 0, 4, 33, 338, 172, 164, 18, 0, 0]
Third place: [0, 18, 136, 273, 290, 4, 8, 0, 0, 0]
Fourth place: [108, 306, 184, 125, 6, 0, 0, 0, 0, 0]

Perl 6

Translation of: Python

<lang perl6>constant scoring = 0, 1, 3; constant r = 0..2; my @histo = [0 xx 10] xx 4;

for ([X] r,r,r,r,r,r).tree -> @results {

   my @s;
   for @results Z (^4).combinations(2)
    -> $r,        @g {
       @s[@g[0]] += scoring[$r];
       @s[@g[1]] += scoring[2 - $r];
   }
   for @histo Z @s.sort
    -> @h,      $v {
       ++@h[$v];
   }

}

say .fmt('%3d',' ') for @histo.reverse;</lang>

Output:
  0   0   0   1  14 148 152 306   0 108
  0   0   4  33 338 172 164  18   0   0
  0  18 136 273 290   4   8   0   0   0
108 306 184 125   6   0   0   0   0   0

Python

<lang python>from itertools import product, combinations, izip

scoring = [0, 1, 3] histo = [[0] * 10 for _ in xrange(4)]

for results in product(range(3), repeat=6):

   s = [0] * 4
   for r, g in izip(results, combinations(range(4), 2)):
       s[g[0]] += scoring[r]
       s[g[1]] += scoring[2 - r]
   for h, v in izip(histo, sorted(s)):
       h[v] += 1

for x in reversed(histo):

   print x</lang>
Output:
[0, 0, 0, 1, 14, 148, 152, 306, 0, 108]
[0, 0, 4, 33, 338, 172, 164, 18, 0, 0]
[0, 18, 136, 273, 290, 4, 8, 0, 0, 0]
[108, 306, 184, 125, 6, 0, 0, 0, 0, 0]

Racket

<lang racket>#lang racket

Tim Brown 2014-09-15

(define (sort-standing stndg#)

 (sort (hash->list stndg#) > #:key cdr))

(define (hash-update^2 hsh key key2 updater2 dflt2)

 (hash-update hsh key (λ (hsh2) (hash-update hsh2 key2 updater2 dflt2)) hash))

(define all-standings

 (let ((G '((a b) (a c) (a d) (b c) (b d) (c d)))
       (R '((3 0) (1 1) (0 3))))
   (map
    sort-standing
    (for*/list ((r1 R) (r2 R) (r3 R) (r4 R) (r5 R) (r6 R))
      (foldr (λ (gm rslt h)
               (hash-update
                (hash-update h (second gm) (λ (n) (+ n (second rslt))) 0)
                (first gm) (curry + (first rslt)) 0))
             (hash) G (list r1 r2 r3 r4 r5 r6))))))

(define histogram

 (for*/fold ((rv (hash)))
   ((stndng (in-list all-standings)) (psn (in-range 0 4)))
   (hash-update^2 rv (add1 psn) (cdr (list-ref stndng psn)) add1 0)))
Generalised histogram printing functions...

(define (show-histogram hstgrm# captions)

 (define (min* a b)
   (if (and a b) (min a b) (or a b)))
 (define-values (position-mn position-mx points-mn points-mx)
   (for*/fold ((mn-psn #f) (mx-psn 0) (mn-pts #f) (mx-pts 0))
     (((psn rw) (in-hash hstgrm#)))
     (define-values (min-pts max-pts)
       (for*/fold ((mn mn-pts) (mx mx-pts)) ((pts (in-hash-keys rw)))
         (values (min* pts mn) (max pts mx))))
     (values (min* mn-psn psn) (max mx-psn psn) min-pts max-pts)))
 
 (define H
   (let ((lbls-row# (for/hash ((i (in-range points-mn (add1 points-mx)))) (values i i))))
     (hash-set hstgrm# 'thead lbls-row#)))
 
 (define cap-col-width (for/fold ((m 0)) ((v (in-hash-values captions))) (max m (string-length v))))
 
 (for ((plc (in-sequences
             (in-value 'thead)
             (in-range position-mn (add1 position-mx)))))
   (define cnts (for/list ((pts (in-range points-mn (add1 points-mx))))
                  (~a #:align 'center #:width 3 (hash-ref (hash-ref H plc) pts 0))))
   (printf "~a ~a~%"
           (~a (hash-ref captions plc (curry format "#~a:")) #:width cap-col-width)
           (string-join cnts "  "))))

(define captions

 (hash 'thead "POINTS:" 
       1 "1st Place:"
       2 "2nd Place:"
       3 "Sack the manager:"
       4 "Sack the team!"))

(show-histogram histogram captions)</lang>

Output:
POINTS:            0    1    2    3    4    5    6    7    8    9 
1st Place:         0    0    0    1   14   148  152  306   0   108
2nd Place:         0    0    4   33   338  172  164  18    0    0 
Sack the manager:  0   18   136  273  290   4    8    0    0    0 
Sack the team!    108  306  184  125   6    0    0    0    0    0 

Ruby

<lang ruby>teams = [:a, :b, :c, :d] matches = teams.combination(2).to_a outcomes = [:win, :draw, :loss] gains = {win:[3,0], draw:[1,1], loss:[0,3]} places_histogram = Array.new(4) {Array.new(10,0)}

  1. The Array#repeated_permutation method generates the 3^6 different
  2. possible outcomes

outcomes.repeated_permutation(6).each do |outcome|

 results = Hash.new(0)
 
 # combine this outcomes with the matches, and generate the points table
 outcome.zip(matches).each do |decision, (team1, team2)|
   results[team1] += gains[decision][0]
   results[team2] += gains[decision][1]
 end 
 
 # accumulate the results
 results.values.sort.reverse.each_with_index do |points, place|
   places_histogram[place][points] += 1
 end

end

fmt = "%s :" + "%4s"*10 puts fmt % [" ", *0..9] puts fmt % ["-", *["---"]*10] places_histogram.each.with_index(1) {|hist,place| puts fmt % [place, *hist]}</lang>

Output:
  :   0   1   2   3   4   5   6   7   8   9
- : --- --- --- --- --- --- --- --- --- ---
1 :   0   0   0   1  14 148 152 306   0 108
2 :   0   0   4  33 338 172 164  18   0   0
3 :   0  18 136 273 290   4   8   0   0   0
4 : 108 306 184 125   6   0   0   0   0   0

Tcl

Translation of: Java
Works with: Tcl version 8.6

<lang tcl>package require Tcl 8.6 proc groupStage {} {

   foreach n {0 1 2 3} {

set points($n) {0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0}

   }
   set results 0
   set games {0 1 0 2 0 3 1 2 1 3 2 3}
   while true {

set R {0 0 1 0 2 0 3 0} foreach r [split [format %06d $results] ""] {A B} $games { switch $r { 2 {dict incr R $A 3} 1 {dict incr R $A; dict incr R $B} 0 {dict incr R $B 3} } } foreach n {0 1 2 3} r [lsort -integer [dict values $R]] { dict incr points($n) $r }

if {$results eq "222222"} break while {[regexp {[^012]} [incr results]]} continue

   }
   return [lmap n {3 2 1 0} {dict values $points($n)}]

}

foreach nth {First Second Third Fourth} nums [groupStage] {

   puts "$nth place:\t[join [lmap n $nums {format %3s $n}] {, }]"

}</lang>

Output:
First place:	  0,   0,   0,   1,  14, 148, 152, 306,   0, 108
Second place:	  0,   0,   4,  33, 338, 172, 164,  18,   0,   0
Third place:	  0,  18, 136, 273, 290,   4,   8,   0,   0,   0
Fourth place:	108, 306, 184, 125,   6,   0,   0,   0,   0,   0

zkl

Translation of: D
Translation of: Python

<lang zkl>combos :=Utils.Helpers.pickNFrom(2,T(0,1,2,3)); // ( (0,1),(0,2) ... ) scoring:=T(0,1,3); histo  :=(0).pump(4,List().write,(0).pump(10,List().write,0).copy); //[4][10] of zeros

foreach r0,r1,r2,r3,r4,r5 in ([0..2],[0..2],[0..2],[0..2],[0..2],[0..2]){

  s:=L(0,0,0,0);
  foreach i,r in (T(r0,r1,r2,r3,r4,r5).enumerate()){
     g:=combos[i];
     s[g[0]]+=scoring[r];
     s[g[1]]+=scoring[2 - r];
  }
  foreach h,v in (histo.zip(s.sort())){ h[v]+=1; }

} foreach h in (histo.reverse()){ println(h.apply("%3d ".fmt).concat()) }</lang>

Output:
  0   0   0   1  14 148 152 306   0 108 
  0   0   4  33 338 172 164  18   0   0 
  0  18 136 273 290   4   8   0   0   0 
108 306 184 125   6   0   0   0   0   0