challenge 逆順になるあみだくじ

nを2以上の整数とします。 上と下で順番が完全に逆転するような縦線がn本のあみだくじを書くプログラムを作ってください。

たとえばnが3の場合は下のように出力してください。

0 1 2
|_| |
| |_|
|_| |
| | |
2 1 0
nはプログラムを書き換えずに指定できるようにしてください。

このお題はoceanさんの投稿を元に作成しました。ご投稿ありがとうございます。

Posted feedbacks - Flatten

Nested Hidden
この問題はかなりおもしろかったです。

とりあえず無理矢理版
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
$n=max(2,(int)$argv[1]);

$h=$n*2-2;

for($i=0;$i<$n;++$i)
	echo " $i";
echo "\n";

for($i=0;$i<$h;++$i)
{	echo " |";
	for($j=1;$j<$n;++$j)
	{	$f=abs($i-($n-2))-($n-$j);
		echo ($f<0 && ($f&1))?"_|":" |";
	}
	echo "\n";
}
for($i=$n;--$i>=0;)
	echo " $i";
echo "\n";

?>

nが2桁以上でも動くように頑張りました。
 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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int  n;       /* あみだの数 */
    int  keta;    /* 数字の桁数 */
    int  *amida;  /* あみだ */
    int  i, j, k; /* ループカウンタ */
    int  tmp;     /* スワップ用 */
    char *under;  /* 移動線 */

    /* nを決定する */
    if (argc < 2) {
        fprintf(stderr, "usage: %s n\n", argv[0]);
        return 1;
    }
    n = atoi(argv[1]);
    if (n < 2) {
        n = 2;
    }
    keta = 1;
    for (tmp = n+1; tmp >= 10; tmp /= 10) {
        keta++;
    }

    /* あみだの初期化、一番上の数字の表示 */
    amida = malloc(n * sizeof(*amida));
    for (i = 0; i < n; i++) {
        amida[i] = i;
    }
    under = malloc(keta * sizeof(*under));
    for (i = 0; i < keta; i++) {
        under[i] = '_';
    }
    for (i = 0; i < n; i++) {
        printf("%d%*c", amida[i], keta, ' ');
    }
    printf("\n");

    /* バブルソート */
    for (i = 0; i < n-1; i++) {
        for (j = 0; j < n-1; j++) {
            if (amida[j] < amida[j+1]) {
                /* 交換があるときに交換の表示をする */
                tmp        = amida[j];
                amida[j]   = amida[j+1];
                amida[j+1] = tmp;
                for (k = 0; k < n; k++) {
                    if (k == j) {
                        printf("|%s", under);
                    }
                    else {
                        printf("|%*c", keta, ' ');
                    }
                }
                printf("\n");
            }
        }
    }

    /* 最後の線と数字の表示 */
    for (i = 0; i < n; i++) {
        printf("|%*c", keta, ' ');
    }
    printf("\n");
    for (i = 0; i < n; i++) {
        printf("%-*d ", keta, amida[i]);
    }
    printf("\n");

    free(amida);
    free(under);
    return 0;
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
def amida (n)
	w = Math.log10(n - 1).to_i + 1
	puts (0...n).to_a.map {|it| it.to_s.ljust(w + 1) } .join
	((n - 1) * 2).times do
		|lv|
		r = (n - 2) - (lv - (n - 2)).abs
		(0...n).to_a.map do 
			|t|
			s = (t <= r and lv.odd? == t.odd?) ? '_' : ' '
			print "|#{s * w}"
		end
		puts
	end
	puts (0...n).to_a.map {|it| it.to_s.ljust(w + 1) } .join
end


amida(ARGV.first.to_i)

amidaの最後(14行目)が反対だ!
1
puts (0...n).to_a.reverse.map {|it| it.to_s.ljust(w + 1) } .join

 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
def dan(n, d)
  ary = []
  0.upto(d - 2) {|i|
    s = "| " * n
    s[-1] = ""
    s[(d - i) * 2 - 3] = "_"
    ary << s.dup
  }
  ary
end

n = ARGV[0].to_i
a = []
s = ""
1.upto(n) {|m|
  s << "#{m} "
}
a << s
1.upto(n) {|m|
  a << dan(n, m)
}
s = "| " * n
s[-1] = ""
a << s
s = ""
n.downto(1) {|m|
  s << "#{m} "
}
a << s
a.each{|line|
  puts line
}

odd? 追加したのを忘れていました。 すみません。すみません。 (一番はじめにいれてやれば動きます)
1
2
3
4
5
class Fixnum
	def odd?
		self % 2 == 1
	end
end

もうちょっとちゃんと考えた版
 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
<?php
$n=max(2,(int)$argv[1]);

$ladder=array();

for($i=0;$i<$n;++$i)
{	$ladder[$i]=$i;
	printf("%2d",$i);
}
echo "\n";

do{	$c=0;
	echo " |";
	for($j=0;$j<$n-1;++$j)
	{	if($ladder[$j]<$ladder[$j+1])
		{	$t=$ladder[$j];
			$ladder[$j]=$ladder[$j+1];
			$ladder[$j+1]=$t;
			echo "_|";
			if(++$j<$n-1)
				echo " |";
			++$c;
		}
		else
			echo " |";
	}
	echo "\n";
}while($c);

for($i=0;$i<$n;++$i)
	printf("%2d",$ladder[$i]);
echo "\n";

?>

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function amida(n) {
    var $ = [ '|', '_', '|', ' ', '|' ];
    var result = numbers() + '\n';

    for (var i = 0; i < n; i++) {
        for (var j = 0, w = n * 2 - 1; j < w; j++) {
            result += $[j % 4];
        }
        $.reverse();
        result += '\n';
    }
    for (var i = 0; i < n; i++) {
      result += '| ';
    }
    result += '\n';
    return result + numbers().split('').reverse().join('') + '\n';

    function numbers() {
        for (var i = 0, line = ''; i < n; i++) line += i + ' ';
        return line.substring(0, line.length - 1);
    }
}
amida(5);

n > 11 だと表示が崩れるな…

…とかいってココサブさんの#740のパクリですすみません。
ひねりは加えてみた。

2桁の場合は無視してます。
 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
Number.prototype.amida = function()
{
    var n = this;
    var s = ["|","_","|"," "];
    var tmp = "";

    for (var i=0; i<n; i++)
        tmp += (i+1).toString() + " ";
    tmp += "\n";

    for (var j=0; j<n; j++)
    {
        for (var i=0; i<n*2-1; i++)
        {
            tmp += s[(i+j*2)%4];
        }
        tmp += "\n";
    }

    for (var i=0; i<n*2-1; i++)
        tmp += s[(i%2)+2];
    tmp += "\n";

    for (var i=n; i>0; i--)
        tmp += (i).toString() + " ";

    return tmp;
}

var n = 9;
alert(n.amida());

バブルソートの可視化の問題ですね。
これって、縦方向の量って圧縮できるんでしょうか。

ばれちゃいましたか。 わかる人はわかったようですね。 最初は「縦方向がもっとも圧縮されたものを表示してください」という お題にしようかと思っていたのですけども、 あえて書かないことにしたのでした。 ネタバレついでに僕が試しに書いたコードのうち読みにくい方を投稿~。
1
(lambda w:(lambda n,f:[w("%s "%i)for i in range(n)]and w("\n")or[f((i+x)%2 for x in range(n-1))for i in range(n)]and f([0]*(n-1))or[w("%s "%i)for i in reversed(range(n))]and w("\n"))(input("n=? >>>"),lambda b:w("|"+"|".join(" _"[c]for c in b)+"|"+"\n")))(__import__("sys").stdout.write)

なるほど、上下の数字の部分がずれるわけですね。
そこは今回のお題の肝ではないので、まぁいいのではないでしょうか。

おもしろい。というわけで勝手に拡張して、
「任意の列に対して、それをソートした結果になるあみだくじを生成」。
3項演算子使えばいいところに使ってないのは 
Zaurus で組んだから(ruby1.8.0 しか入れてなかったー)

> amida 10
10 9  8  7  6  5  4  3  2  1
|__|  |__|  |__|  |__|  |__|
  (略)
|  |__|  |__|  |__|  |__|  |
1  2  3  4  5  6  7  8  9  10

> amidalist ["Tiger", "Zebra", "Cat", "Fox", "Dog"]
Tiger Zebra Cat   Fox   Dog
|     |_____|     |_____|
|_____|     |_____|     |
|     |_____|     |_____|
|     |     |_____|     |
Cat   Dog   Fox   Tiger Zebra
 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
def output(list, space)
  puts list.inject(""){|buf,x|buf+="#{x}     "[0,space+1]}
end
def amidalist(list)
  space = list.inject(0){|m,x|n="#{x}".length;if m>n then m else n end}
  output list, space
  while true
    flag = true, idx = 0, buf = "|"
    while idx < list.length - 1
      if list[idx] > list[idx+1]
        list[idx], list[idx+1] = list[idx+1], list[idx]
        buf += "_"*space + "|"
        idx += 2
        buf += " "*space + "|" if idx < list.length
        flag = false
      else
        buf += " "*space + "|"
        idx += 1
      end
    end
    break if flag
    puts buf
  end
  output list, space
end
def amida(n)
  amidalist (1..n).to_a.reverse
end

縦方向にもっとも圧縮されたものに挑戦。
もっとも圧縮でn回になりそうですね。
 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
61
62
63
64
65
66
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int  n;      /* あみだの数 */
    int  keta;   /* 数字の桁数 */
    int  i, j;   /* ループカウンタ */
    char *under; /* 移動線 */

    /* nを決定する */
    if (argc < 2) {
        fprintf(stderr, "usage: %s n\n", argv[0]);
        return 1;
    }
    n = atoi(argv[1]);
    if (n < 2) {
        n = 2;
    }
    keta = 1;
    for (i = n+1; i >= 10; i /= 10) {
        keta++;
    }

    /* 初期化、一番上の数字の表示 */
    under = malloc((keta+1) * sizeof(*under));
    memset(under, '_', keta);
    under[keta] = '\0';
    for (i = 0; i < n; i++) {
        printf("%d%*c", i, keta, ' ');
    }
    printf("\n");

    /* あみだ作成 */
    for (i = 0; i < n; i++) {
        if ((i % 2) == 0) {
            j = 0;
        }
        else {
            j = 1;
            printf("|%*c", keta, ' ');
        }
        /* 実際に移動線がでるとこ */
        for (; j+1 < n; j+=2) {
            printf("|%s|%*c", under, keta, ' ');
        }
        if (j+1 <= n) {
            printf("|%*c", keta, ' ');
        }
        printf("\n");
    }

    /* 最後の縦線と数字の表示 */
    for (i = 0; i < n; i++) {
        printf("|%*c", keta, ' ');
    }
    printf("\n");
    for (i = 0; i < n; i++) {
        printf("%-*d ", keta, n-i-1);
    }
    printf("\n");

    free(under);
    return 0;
}

rubyist率高いね

ITER> (amida 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
(require :iterate)
(in-package :iter)

(defun %bars (n)
  "横棒の座標のリストを求める"
  (labels ((limit (i j) (<= (+ i j) (* 2 (1- n)))))
    (iter outer
          (for i from 1 to (* 2 (1- n)))
          (appending
           (if (oddp i)
               (iter (for j from 1 to i by 2)
                     (when (limit i j) (collect (cons i j))))
               (iter (for j from 2 to i by 2)
                     (when (limit i j) (collect (cons i j)))))))))

(defun %draw (n bars)
  "横棒の座標リストからアミダを描く"
  (labels ((empty ()
             (iter (for i from 1 to n) (format t "| "))
             (terpri)))
    (empty)
    (iter (for i from 1 to (* 2 (1- n)))
          (iter (for j from 1 to n)
                (format t "|~a" (if (member (cons i j) bars :test #'equal)
                                    "-" " ")))
          (terpri))))

(defun amida (n)
  (%draw n (%bars n)))

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using System;
class Program
{
  static void Main()
  {
    int n = 6;
    for (int i = 0; i < n; ++i) Console.Write("{0} ", i);
    Console.WriteLine();
    for (int i = 1; i < 2 * n - 1; ++i)
    {
      int k = i < n ? i + 1 : 2 * n - 1 - i;
      for (int j = 1; j < n; ++j)
        Console.Write("|{0}", j <= k && (k - j) % 2 == 1 ? "_" : " ");
      Console.WriteLine("|");
    }
    for (int i = n - 1; i >= 0; --i) Console.Write("{0} ", i);
    Console.WriteLine();
  }
}

M-x amida
 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
(require 'cl)

(defun %bars (n)
  "横棒の座標のリストを求める"
  (labels ((limit (i j) (<= (+ i j) (* 2 (1- n)))))
    (loop for i from 1 to (* 2 (1- n)) appending
          (if (oddp i)
              (loop for j from 1 to i by 2
                    when (limit i j)
                    collect (cons i j))
            (loop for j from 2 to i by 2
                  when (limit i j) collect (cons i j))))))
;; (%bars 5)
(defun %draw (n bars)
  "横棒の座標リストからアミダを描く"
  (with-output-to-temp-buffer "*amida*"
    (labels ((empty ()
                    (loop for i from 1 to n do (princ "| "))
                    (terpri)))
      (empty)
      (loop for i from 1 to (* 2 (1- n)) do
            (loop for j from 1 to n do
                  (princ "|")
                  (princ (if (member (cons i j) bars) "-" " ")))
            (terpri)))))

(defun amida (n)
  (interactive "sN: ")
  (setq n (string-to-number n))
  (%draw n (%bars n)))

Squeak Smalltalk で n が 10 以下で(^_^;)。あと「n はプログラムを書き換えずに指定できるように」が「n を引数に取る関数として and/or 起動時オプションとして指定できるように書け」という意味なら、そのようにはしていないのでごめんなさい。(GUI な Squeak Smalltalk 環境ではそうするメリットが少ない←関数 and/or そもそもできない←起動時オプション なので…)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
| n labels numOfVBarsPair m last |
n := 10.
World findATranscript: nil.
numOfVBarsPair := {m := (n alignedTo: 2) / 2. m - (n \\ 2)}.
Transcript cr; show: (labels := String streamContents: [:ss |
   (1 to: n) do: [:i | ss print: i - 1] separatedBy: [ss space]]).
1 to: (last := numOfVBarsPair first * 2 + (n - 1 \\ 2)) do: [:row |
   Transcript cr; show: '|'.
   1 to: n - 1 do: [:i |
      | vBarOrSp |
      vBarOrSp := row < last ifTrue: [' _' atWrap: i + row] ifFalse: [$ ].
      Transcript nextPut: vBarOrSp; nextPut: $|]].
Transcript cr; show: labels reversed

難しかったです。結果として「任意の列に対して、それをソートした結果になるあみだくじを生成」版になってると思います。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
let rec make_ladder = function
| [] -> print_newline (); []
| [x] -> print_endline "| "; [x]
| x::y::xs when x < y -> print_string "|_| "; (y::x::make_ladder xs)
| x::y::xs -> print_string "| "; (x::make_ladder (y::xs))

let rec amida l =
  let rec complete = function
  | [x] -> true
  | x::y::xs -> x > y && complete (y::xs)
  in
  if (complete l) then make_ladder l
  else (amida (make_ladder l))
;;

すみませんっ!

    * 無加工(text)
    * 整形済み(pre)

の意味が分かっていませんでした。orz

可能でしたら上のコメントの修正お願いします。m(__)m

んー、D言語にはネスト関数があるから書き易い~
 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
61
62
module doukaku;
private import std.stdio;
struct Bar {
    int i;
    int j;
}

Bar[] bars(int n) {
    Bar[] bars;
    int limit(int i, int j) { return (i+j) <= 2*(n-1); }
    int i,j;
    void append(int i, int j) {
        if (limit(i, j)) {
                Bar bar;
                bar.i = i;
                bar.j = j;
                bars ~= bar;
            }
    }
    for (i=1; i<=2*(n-1); i++) {
        if (i%2 == 1) {
            for (j=1; j<=i; j+=2)  append(i, j); 
        } else {
            for (j=2; j<=i; j+=2)  append(i, j);
        }
    }
    return bars;
}

int member(int i, int j, Bar[] bars) {
    foreach (bar; bars) {
        if (i==bar.i && j==bar.j) return 1;
    }
    return 0;
}

void draw(int n, Bar[] bars) {
    int i,j;
    void empty() {
        for (int i=1; i<=n; i++) writef("| ");
        writefln("");
    }
    empty();
    for (i=1; i<=2*(n-1); i++) {
        for (j=1; j<=n; j++) {
            writef("|");
            if (member(i, j, bars))
                writef("-");
            else
                writef(" ");
        }
        writefln("");
    }
}

void amida(int n) {
    draw(n, bars(n));
}

void main() {
    amida(10);
}

再帰つらい…orz
 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
(define (bars n)
  (define (limit i j) (<= (+ i j) (* 2 (- n 1))))
  (define (oddp n) (= (remainder n 2) 1))
  (define (append0 i j result)
    (if (limit i j)
      (cons (cons i j) result)
      result))
        
  (define (rec i j result)
    (cond ((<= i (* 2 (- n 1)))
           (if (<= j i)
             (rec i (+ j 2) (append0 i j result))
             (rec (+ i 1) (if (oddp (+ i 1)) 1 2) result)))
          (else
           result)))
  (rec 1 1 ()))

(define (draw n bars)
  (define (empty i)
    (cond ((<= i n)
           (display "| ")
           (empty (+ i 1)))
          (else
           (display "\n"))))
  (define (rec i j)
    (cond ((<= j n)
           (cond ((<= i (* 2 (- n 1)))
                  (display "|")
                  (display (if (member (cons i j) bars) "-" " "))
                  (rec i