challenge ビンゴの結果を整形表示

重複無し乱数」の続編です。

「重複無し乱数」で作ったbingo関数の結果を下のように「何番目の乱数か」とセットにして10個ずつ折り返して表示するコードを書いてください。

>>> bingo(30)
  1  2  3  4  5  6  7  8  9 10
 29 14 16 13 30 15 22 11 25  9

 11 12 13 14 15 16 17 18 19 20
 23  4 18  5 28 17  8 12 21 20

 21 22 23 24 25 26 27 28 29 30
 26  6  2 19  1  7 10 27  3 24

>>> bingo(35)
  1  2  3  4  5  6  7  8  9 10
  7 15  3 32  1 16 17 28  6 29

 11 12 13 14 15 16 17 18 19 20
 19 23 30 26 20  5 12  2 25 31

 21 22 23 24 25 26 27 28 29 30
 35 13 24 18 11  8 10 34 22 21

 31 32 33 34 35
  9  4 27 33 14

Posted feedbacks - Nested

Flatten Hidden
enumeratorで
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def bingo(num)
	(1..num).to_a.sort_by{ rand }
end

require 'enumerator'
bingo(35).enum_slice(10).each_with_index{ |e,index|
	num=index * 10 + 1
	tmpl=(["%02s"] * e.size).join(' ')

	puts tmpl % (num .. num + e.size).to_a
	puts tmpl % e
	puts ""
}
リストを選んだ意味があまりなくなってしまいましたが、前のお題にそのまま出力機能を加えました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.util.*;

public class Sample2 {
    public static List<Integer> bingo(int num) {
        Integer[] deck = new Integer[num];
        for (int i = 0; i < num; i++) {
            deck[i] = i + 1;
        }
        List<Integer> nums = (List<Integer>) Arrays.asList(deck);
        Collections.shuffle(nums);
        return nums;
    }

    public static void printBingo(int num) {
        List<Integer> nums = bingo(num);
        for (int j = 0; j < num; j += 10) {
            for (int i = j; i < j + 10 && i < num; i++) {
                System.out.printf("%3d", i + 1);
            }
            System.out.println();
            for (int i = j; i < j + 10 && i < num; i++) {
                System.out.printf("%3d", nums.get(i));
            }
            System.out.printf("%n%n");
        }
    }

    public static void main(String[] args) {
        printBingo(Integer.parseInt(args[0]));
    }
}
showBingoがビンゴの整数リストを文字列に変換する
関数。第一引数は数字の最大桁数
shuffle は前回と同じだけど再掲
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
module Main (main) where

import Data.List
import System.Environment
import System.Random
import Text.Printf

shuffle :: [a] -> StdGen -> Int -> [a] -> [a]
shuffle acc _ 0 _  = acc
shuffle acc g n xs = case randomR (0,n-1) g of
 (i,g') -> case splitAt i xs of
             (ys,z:zs) -> shuffle (z:acc) g' (n-1) (ys++zs)

main :: IO ()
main = do { x:_ <- getArgs
          ; g0  <- getStdGen
          ; let n = read x
          ; putStr $ showBingo (length x)
          $ shuffle [] g0 n [1..n]
          }

showBingo :: Int -> [Int] -> String
showBingo w = unlines . map (showLines w) . map unzip . slice 10 . zip [1..]

slice :: Int -> [a] -> [[a]]
slice n = unfoldr phi
  where phi [] = Nothing
        phi xs = Just $ splitAt n xs

showLines :: Int -> ([Int],[Int]) -> String
showLines n (xs,ys) = unlines [ unwords $ map (pr n) xs
                              , unwords $ map (pr n) ys]

pr :: Int -> Int -> String
pr w = printf $ "%"++show w++"d"

{-
% ./bingo 30
 1  2  3  4  5  6  7  8  9 10
19 26  2  6 11 17 23  8  7  5

11 12 13 14 15 16 17 18 19 20
18 13 16 12 22 24  4 21  1 25

21 22 23 24 25 26 27 28 29 30
 3 29 10 27 15  9 28 14 20 30

% ./bingo 35
 1  2  3  4  5  6  7  8  9 10
20 32 18  3 29 13 33  1 24 21

11 12 13 14 15 16 17 18 19 20
17 12 34  4 25  8 31 30 14 35

21 22 23 24 25 26 27 28 29 30
10 11  7 16 19 15 23 27  9 22

31 32 33 34 35
 2 28  5  6 26
-}
showBingo に (length x) を渡したけど、
(length (show n))を渡す方がよいかもです。
bingo(100)でも動作するようにしたつもり。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import random
import itertools

division = 10

def bingo(count):
    a = [i + 1 for i in xrange(count)]
    random.shuffle(a)
    width = len(str(count)) + 1
    it = ((i + 1, n) for (i, n) in enumerate(a))
    while 1:
        b = list(itertools.islice(it, division))
        if not b:
            break
        for i in xrange(2):
            print "".join(str(c[i]).rjust(width) for c in b)
        print

def main():
    bingo(30)
    bingo(35)

if __name__ == '__main__':
    main()
表示方法のみの変更なので show() 関数だけ変更
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
BEGIN {
	srand
}

{
	n = $1

	bingo(n,ar)
	show(n,ar)
}

function show(n,ar, i,j,k,s1,s2)
{
	s1 = s2 = ""
	k = length(n)

	for (i=1; i<=n; i++) {
		s1 = s1 sprintf(" %"k"d", i+j)
		s2 = s2 sprintf(" %"k"d", ar[i+j])
		if (i % 10 == 0) {
			print s1
			print s2
			print ""
			s1 = s2 = ""
		}
	}
	if (s1 !~ /^$/) { # n % 10 > 0
		print s1
		print s2
		print ""
	}
}

function rand_between_1_and_n(n, x)
{
	x = 1 + int(rand * n)
	return (x <= n)? x : rand_between_1_and_n(n)
}

function bingo(n,ar,  i,x,y,t)
{
	delete ar;
	for (i=1; i<=n; i++) ar[i] = i

	for (i=n*2; i>0; i--) {
		x = rand_between_1_and_n(n)
		y = rand_between_1_and_n(n)
		if (x == y) continue

		t = ar[x] ; ar[x] = ar[y] ; ar[y] = t
	}
}
出力はこんな感じ
% awk -f bingo2.awk
5
 1 2 3 4 5
 1 4 5 2 3

10
  1  2  3  4  5  6  7  8  9 10
  3  8  2  7  1  5  4  9 10  6

15
  1  2  3  4  5  6  7  8  9 10
  9  5 13  2 15 14  6 11  4 12

 11 12 13 14 15
  8 10  3  1  7

19
  1  2  3  4  5  6  7  8  9 10
  5 11 10  1 12 15  3  7 17  9

 11 12 13 14 15 16 17 18 19
 19 18  8  6  2  4 16 14 13

20
  1  2  3  4  5  6  7  8  9 10
  1  4 10  9 14 20  3  6 18 19

 11 12 13 14 15 16 17 18 19 20
 17 15  8 16 13  5 12  2  7 11

21
  1  2  3  4  5  6  7  8  9 10
  5 16 11  4 10 15 18  2  1  9

 11 12 13 14 15 16 17 18 19 20
 19  7  6  8 13  3 12 14 21 17

 21
 20

30
  1  2  3  4  5  6  7  8  9 10
 21 26  7 24 23  5 17 10 16  9

 11 12 13 14 15 16 17 18 19 20
 11 20 12 30  1 14 18  4 15  6

 21 22 23 24 25 26 27 28 29 30
 22  8  3 25 28 19 27 29 13  2

100
   1   2   3   4   5   6   7   8   9  10
  55  98  44  13  99  81  53  61  56  87

  11  12  13  14  15  16  17  18  19  20
  82  24  52  92  66  51  18  70  19  58

  21  22  23  24  25  26  27  28  29  30
  41  47  39  43  94   8  80  59  42  79

  31  32  33  34  35  36  37  38  39  40
  27  73  36  12  62  37  83   9  54  96

  41  42  43  44  45  46  47  48  49  50
  69  84  45  17  26 100  50  67   6   1

  51  52  53  54  55  56  57  58  59  60
  15  65   4  33  16   5  78  23  74  75

  61  62  63  64  65  66  67  68  69  70
  63  38  40  28  91  89  72  34  77  35

  71  72  73  74  75  76  77  78  79  80
  11   2  21  30  49   3  71  57  25  31

  81  82  83  84  85  86  87  88  89  90
  14  10  93  60  85  90  46  88  48  32

  91  92  93  94  95  96  97  98  99 100
  22  95   7  68  29  20  64  97  86  76
bingo関数自体は#2255からいただきました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from random import shuffle

def bingo(n):
  l = range(1, n+1)
  shuffle(l)
  return l

def bingo_print(l):
  fmt = '%%%sd' % len(str(len(l)))
  a = range(1, len(l)+1)
  for i in range(0, len(l), 10):
    print ' '.join([fmt % j for j in a[i:i+10]])
    print ' '.join([fmt % j for j in l[i:i+10]]) + '\n'

bingo_print(bingo(30))
bingo_print(bingo(35))
出力データをまとめてprintしてみた。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from random import shuffle

def bingo(n):
  l = range(1, n+1)
  shuffle(l)
  return l

def bingo_print(l):
  fmt = '%%%sd' % len(str(len(l)))
  a = [fmt % i for i in range(1, len(l)+1)]
  b = [fmt % i for i in l]
  print '\n'.join(['%s\n%s\n' % (' '.join(a[i:i+10]), ' '.join(b[i:i+10])) for i in range(0, len(l), 10)])

bingo_print(bingo(30))
bingo_print(bingo(35))
僕が出題前に書いたコードはこんな感じですが、
確かに#2324みたいにrangeのstepを使った方がいいですね。
スライシングで添え字の範囲が超えてもエラーにならないので僕のコードの18行目以降みたいな
「1行に満たない残りがあれば表示」というコードがいらなくなるわけですね。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def bingo(n):
	from random import shuffle
	result = range(1, n + 1)
	shuffle(result)
	w = len(str(n))
	format = " %%%dd" % w
	nbuf = []
	rbuf = []
	for i in range(n):
		nbuf.append(format % (i + 1))
		rbuf.append(format % result[i])
		if i % 10 == 9:
			print "".join(nbuf)
			print "".join(rbuf)
			print
			nbuf = []
			rbuf = []
	if nbuf:
		print "".join(nbuf)
		print "".join(rbuf)

	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#light
let rec bingo n = shuffle [1..n]
and  shuffle ls =
    let rnd = new System.Random()
    List.sort (fun x y-> rnd.Next(-1,2)) ls

let printLine ln n =
    let rec len (m:int) = ( m.ToString() ).Length
    and mk (m:int) = (String.make ((len n) - (len m)) ' ') ^ m.ToString()
    and (|SplitAt|) m xs = List.partition (fun (x,i) -> i <= m) xs
    and mkLns c = function
        | [] -> []
        | SplitAt c (head,tail) -> (List.unzip head)::mkLns (c+ln) tail
    and concatMap f xs = String.concat " " <| List.map f xs
    and bs = mkLns ln (List.zip (bingo n) [1..n])
    [for (xs,ids) in bs -> (concatMap mk xs) ^ "\n" ^ (concatMap mk ids)]
    |> String.concat "\n"
    |> printf "%s\n"

let bingoPr = fun n -> printLine 10 n
修正。
|> String.concat "\n"
じゃなくて
|> String.concat "\n\n"
としないとお題のようにならないですね。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import scala.util.Sorting.stableSort

def bingo(n:int) = {
  type PList = List[Pair[int,int]]
  val lst = stableSort[int,double](1 to n,x=>Math.random).zipWithIndex.toList
  val w = lst.size.toString.size+1
  def format(n:int) = String.format("%"+w+"d",Array(n.asInstanceOf[AnyRef]))

  def printline(x:PList) = {
    println(x.map(y=>format(y._2+1)).mkString(""))
    println(x.map(y=>format(y._1)).mkString("")+"\n")
  }

  def show(l:PList):unit = l.splitAt(10) match {
    case (l,Nil) => printline(l)
    case (l,ls) =>  printline(l);show(ls)
  }

  show(lst)
}

bingo(30)
bingo(35)
bingo関数自体が結果を出力していたので出力部分を変更。
リストに何番目かの値もInsertして出力してます。全然短くできず。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Public Sub bingo(ByVal n As Integer)
    Dim list As New List(Of Integer)
    For i As Integer = 1 To n
        list.Add(i)
    Next
    Dim r As New Random
    For i As Integer = 1 To n * 2
        Dim index As Integer = r.Next(0, n)
        list.Add(list(index))
        list.RemoveAt(index)
    Next

    For i As Integer = 0 To n - 1
        list.Insert((i \ 10) * 20 + i Mod 10, i + 1)
    Next

    For i As Integer = 1 To list.Count - 1
        Console.Write(list(i - 1).ToString.PadLeft(n.ToString.Length) & Space(-CInt(CBool(i Mod 10 <> 0))))
        If i Mod 10 = 0 OrElse i = list.Count - n Mod 10 Then
            Console.WriteLine(New String(ControlChars.Lf, -CInt(CBool(i Mod 20 = 0))))
        End If
    Next
    Console.WriteLine(list(list.Count - 1))
End Sub
ちょっとゴチャゴチャしてる。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import Random (randomRIO)
import Data.List ((\\),elemIndex)
import Data.Maybe (fromJust)
import Control.Monad (zipWithM_)

bingo :: Int -> IO [Int]
bingo n = b [1..n] n []
  where b [] n     ret = return ret 
        b xs (n+1) ret = do
          r <- randomRIO (0,n)
          let m = xs !! r in b (xs \\ [m]) n (ret ++ [m])

showBingo :: Int -> IO ()
showBingo n = bingo n >>= \xs -> zipWithM_ printBingo (f idxs) (f (t xs))
  where idxs = [1..n]
        f = map concat . map u . s 
        s xs = if xs == [] then [] else let (h,t) = splitAt 10 xs in h:s t
        t xs = map ((1+) . fromJust . (\x -> x `elemIndex` idxs)) xs
        u xs = let len = length (show n) in map (surpress (len + 1) . show) xs
        surpress n xs = reverse $ take n $ reverse xs ++ cycle " " 
        printBingo x y = putStrLn x >> putStrLn y >> putStrLn ""
Squeak Smalltalk で。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
| n size bingo streams |
n := 35.
size := n printString size + 1.
bingo := (1 to: n) asArray shuffled readStream.
streams := {String new writeStream. String new writeStream}.
World findATranscript: nil.
1 to: n do: [:idx |
	{idx. bingo next} with: streams do: [:int :strm |
		strm nextPutAll: (int printPaddedWith: $  to: size)].
	((idx isDivisibleBy: 10) or: [idx = n]) ifTrue: [
		Transcript cr.
		streams do: [:strm | Transcript cr; show: strm contents. strm reset]]]
シーケンスのshuffleはライブラリに追加しようかなあ。

今回のお題はshow-bingo関数で実装してます。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
(use srfi-1)
(use srfi-27)
(use srfi-42)
(use gauche.sequence)
(use util.list)

(define (shuffle! seq)
  (do-ec (: n (- (size-of seq) 1) 0 -1)
         (let1 p (random-integer (+ n 1))
           (unless (= p n)
             (let1 tmp (ref seq n)
               (set! (ref seq n) (ref seq p))
               (set! (ref seq p) tmp)))))
  seq)

(define (bingo n)  (shuffle! (iota n 1)))

(define (show-bingo lis)
  (do-ec (: row (slices (zip (iota (length lis) 1) lis) 10))
         (begin
           (do-ec (: p row) (format #t "~3d" (car p))) (newline)
           (do-ec (: p row) (format #t "~3d" (cadr p))) (newline) (newline))))
 ブラウザとCScriptに対応。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Array.prototype.$huffle = function(){
  for(var $, r, i = this.length; i;)
    $ = this[r = Math.random() * i-- | 0], this[r] = this[i], this[i] = $;
  return this;
};
function bingo(n, w){
  if(!w) w = 10;
  for(var a = [], i = 1; i <= n;) a[a.length] = i++;
  var b = a.concat().$huffle(), r = [], l = (' '+ n).length;
  while(a.length) r[r.length] = a.splice(0, w).join(' ') +'\n'+ b.splice(0, w).join(' ');
  r = r.join('\n\n').replace(/ *\d+/g, function($){ while($.length < l) $ = ' '+ $; return $ });
  if(typeof WSH != 'undefined') WSH.stdOut.write(r);
  else document.write('<pre>'+ r +'</pre>');
}
ブックマークレット版: javascript:(function(n,w,a,b,r,l,i,$){for(a=[],l=('_'+n).length,i=0;i<n;a.push(++i));for(b=a.concat();n;$=b[i=Math.random()*n--|0],b[i]=b[n],b[n]=$);for(r=[];a.length;r.push(a.splice(0,w).join(' ')+'\n'+b.splice(0,w).join(' ')));return'<pre>'+r.join('\n\n').replace(/ *\d+/g,function($){while($.length<l)$=' '+$;return $})+'</pre>'})(35,10)

	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;
using System.Text;
class Program
{
  static void Main()
  {
    PrintBingo(35);
  }
  static void PrintBingo(int n)
  {
    Random r = new Random();
    int[] a = new int[n];
    for (int i = 0; i < n; ++i) a[i] = i + 1;
    for (int i = n; i > 1; --i)
    {
      int k = r.Next(i);
      int tmp = a[i - 1];
      a[i - 1] = a[k];
      a[k] = tmp;
    }
    for (int i = 0; i < n; i++)
    {
      if (i % 10 == 0)
      {
        if (i > 0) Console.WriteLine("\n");
        for (int j = i; j < Math.Min(n, i + 10); j++)
          Console.Write("{0,3}", j + 1);
        Console.WriteLine();
      }
      Console.Write("{0,3}", a[i]);
    }
    Console.WriteLine();
  }
}
bingo関数自体#2289から少し変更しました。
(print-bingo (bingo 25))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
(defun bingo (n)
  (let ((*random-state* (make-random-state t)))
    (loop repeat n
          for rand = (loop 
                       (let ((rand (1+ (random n))))
                         (if (not (member rand lst))
                           (return rand))))
          collect rand into lst
          finally (return lst))))

(defun print-bingo (lst)
  (let ((index 0)
        (format-string (concatenate 
                         'string
                         "~{~"
                         (princ-to-string (1+ (length (princ-to-string (length lst)))))
                         "d~}~%" )))
    (loop for elements on lst by #'(lambda (x) (nthcdr 10 x))
          do (loop repeat 10
                   for e in elements
                   collect (incf index) into column-name
                   collect e into column-value
                   finally (format t format-string column-name)
                           (format t format-string column-value)
                           (terpri)))))
出力用の関数を追加。
ちょっとドロくさいかな?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
sub bingo($;)
{
    my $x = shift ;
    my @num = (1 .. $x);
    my $r;
    for( my $n = $x; $n>0; $n --)
    {
        $r = rand; $r *= 1000;
        push(@num, splice(@num, $r % $n, 1) );
    }
    return @num;
}

sub printTable(@)
{
    my @T = @_;
    my $N, $K;

    printf("[%d] => \n", $#T+1);
    for( $N=0; $N<=$#T; $N = $K + 1)
    {
        # 番号
        for( $K=$N; $K<$#T; $K ++ )
        {
            last if ($K-$N) >= 9;
            printf("%2d ", $K+1);
        }
        printf("%2d\n", $K+1);

        # 乱数
        for( $K=$N; $K<$#T; $K ++ )
        {
            last if ($K-$N) >= 9;
            printf("%2d ", $T[$K]);
        }
        printf("%2d\n", $T[$K]);

        printf("\n");
    }
}

my @table;

srand;
@table = bingo(30); ::printTable(@table);
@table = bingo(35); ::printTable(@table);

	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
function bingo($n){
	$a = range(1, $n);
	shuffle($a);
	
	return $a;
}

function show($a){
	$max = strlen(max($a));
	$html = array("<pre>\n");
	
	for($i=0; $i<count($a); $i+=10){
		for($j=$i, $number=$counter=array(); $j<$i+10; $j++){
			if($j>=count($a)) break;
			
			$counter[] = sprintf("% {$max}d", $j+1);
			$number[] = sprintf("% {$max}d", $a[$j]);
		}
		
		$html[] = sprintf("%s\n%s\n\n", join(" ", $counter), join(" ", $number));
	}
	
	$html[] = "</pre>";
	
	return join("", $html);
}

echo show(bingo(30));
echo show(bingo(35));
?>