# World Cup group stage

**World Cup group stage**

You are encouraged to solve this task according to the task description, using any language you may know.

Generate all possible outcome combinations for the six group stage games. With three possible outcomes for each game there should be 3^{6} = 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[edit]

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

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);

}

- 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.

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");

}

}

- 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

## Elixir[edit]

defmodule World_Cup do

def group_stage do

results = [[3,0],[1,1],[0,3]]

teams = [0,1,2,3]

allresults = combos(2,teams) |> combinations(results)

allpoints = for list <- allresults, do: (for {l1,l2} <- list, do: Enum.zip(l1,l2)) |> List.flatten

totalpoints = for list <- allpoints, do: (for t <- teams, do: {t, Enum.sum(for {t_,points} <- list, t_==t, do: points)} )

sortedtotalpoints = for list <- totalpoints, do: Enum.sort(list,fn({_,a},{_,b}) -> a > b end)

pointsposition = for n <- teams, do: (for list <- sortedtotalpoints, do: elem(Enum.at(list,n),1))

for n <- teams do

for points <- 0..9 do

Enum.at(pointsposition,n) |> Enum.filter(&(&1 == points)) |> length

end

end

end

defp combos(1, list), do: (for x <- list, do: [x])

defp combos(k, list) when k == length(list), do: [list]

defp combos(k, [h|t]) do

(for subcombos <- combos(k-1, t), do: [h | subcombos]) ++ (combos(k, t))

end

defp combinations([h],list2), do: (for item <- list2, do: [{h,item}])

defp combinations([h|t],list2) do

for item <- list2, comb <- combinations(t,list2), do: [{h,item} | comb]

end

end

format = String.duplicate("~4w", 10) <> "~n"

:io.format(format, Enum.to_list(0..9))

IO.puts String.duplicate(" ---", 10)

Enum.each(World_Cup.group_stage, fn x -> :io.format(format, x) end)

- Output:

0 1 2 3 4 5 6 7 8 9 --- --- --- --- --- --- --- --- --- --- 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[edit]

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

-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)].

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]]

## J[edit]

There might be a more elegant way of expressing this.

require'stats'

outcome=: 3 0,1 1,:0 3

pairs=: (i.4) e."1(2 comb 4)

standings=: +/@:>&>,{<"1<"1((i.4) e."1 pairs)#inv"1/ outcome

Here, standings represents all the possible outcomes:

$standings

729 4

Of course, not all of them are distinct:

$~.standings

556 4

With only 556 distinct outcomes, there must be some repeats. Looking at this more closely (gathering the outcomes in identical groups, counting how many members are in each group, and then considering the unique list of group sizes):

~.#/.~standings

1 2 3 4 6

Some standings can be attained two different ways, some three different ways, some four different ways, and some six different ways. Let's look at the one with six different possibilities:

(I.6=#/.~standings){{./.~standings

4 4 4 4

That's where every team gets 4 standing.

How about outcomes which can be achieved four different ways?

(I.4=#/.~standings){{./.~standings

6 6 3 3

6 3 3 6

6 3 6 3

3 6 6 3

3 6 3 6

3 3 6 6

Ok, that's simple. So how about a histogram. Actually, it's not clear what a histogram should represent. There are four different teams, and possible standings range from 0 through 9, so we could show the outcomes for each team:

+/standings =/ i.10

27 81 81 108 162 81 81 81 0 27

27 81 81 108 162 81 81 81 0 27

27 81 81 108 162 81 81 81 0 27

27 81 81 108 162 81 81 81 0 27

Each team has the same possible outcomes. So instead, let's order the results so that instead of seeing each team as a distinct entity we are seeing the first place, second place, third place and fourth place team (and where there's a tie, such as 4 4 4 4, we just arbitrarily say that one of the tied teams gets in each of the tied places...):

+/(\:"1~ standings)=/"1 i.10

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

Here, the first row represents whichever team came in first in each outcome, the second row represents the second place team and so on.

Meanwhile, the leftmost column represents the number of outcomes where that team would have zero standing, the second column represents the number of outcomes where that team would have one standing and so on. (The rightmost column represents the number of outcomes where that team would have 9 standing.)

## Java[edit]

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.

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]));

}

}

- 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[edit]

constant scoring = 0, 1, 3;

my @histo = [0 xx 10] xx 4;

for [X] ^3 xx 6 -> @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;

- 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[edit]

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

- 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[edit]

#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)

- 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[edit]

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)}

# The Array#repeated_permutation method generates the 3^6 different

# 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]}

- 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[edit]

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}] {, }]"

}

- 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[edit]

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()) }

- 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