challenge LL Golf Hole 8 - 横向きのピラミッドを作る

与えられた自然数 n について、横向きで n 段のピラミッドを作ってください。 たとえば、 n に 4 が与えられた場合は以下のようなピラミッドを作ります。

4
*
**
***
****
***
**
*

与える自然数についてはリテラルで与える、標準入力で与える、引数で与えるなどは自由とします。

余力のあるものはこのプログラムを短くしてください。

※LL Future実行委員の高野光弘です。この出題は LL Future公式の出題であり、優れたものについてはLL Golfのセッションでご紹介させていただくかもしれません。ご理解の上、ご投稿ください。また、チケットは現在も発売中のほか、当日券もございます。よろしければ、メインイベントの方にもぜひご参加ください。

1
n=gets.to_i*2;n.times{|i|puts"*"*(i<n/2 ?i:n-i)}

Posted feedbacks - Flatten

Nested Hidden
バッチです。

  e.g.
    C:\>pyramid 4
    *
    **
    ***
    ****
    ***
    **
    *
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
:: pyramid.bat
@echo off
  setlocal enabledelayedexpansion
    for /l %%i in (1,1,%1) do (
      set t=!t!*
      echo !t!
    )
    for /l %%i in (%1,-1,2) do (
      set t=!t:~1,%%i!
      echo !t!
    )
  endlocal
goto :EOF

for expression を使ってみる。
451bytes, 実質444bytes
1
2
3
4
5
6
7
8
<transform version="2.0" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:y="y">
<output method="text"/><param name="n"/>
<template match="/"><value-of separator="&#xA;" select="y:f(1)"/></template>
<function name="y:f"><param name="i"/>
<sequence select="(y:g($i),if($i=$n)then()else(y:f($i+1),y:g($i)))"/>
</function><function name="y:g"><param name="i"/>
<sequence select="string-join((for$x in(1 to$i)return('*')),'')"/>
</function></transform>

55 真っ当なコードしか書けない。

1
print'*'x$_."\n"for(1..$ARGV[0]),reverse(1..$ARGV[0]-1)


	
1
p=print;(function f(n, s){if(!n)return p(s);p(s);f(n-1, s + "*");p(s)})(4,"");

改行をどうするかちょっと悩んだけど、まぁ何とか。
151bytes。実質148bytes
1
2
3
4
5
#include <iostream>
int n;
void g(int i){while(i--)std::cout<<"*\n"[i?0:1];}
void f(int i){g(i);if(i!=n+1)f(i+1),g(i);}
main(){std::cin>>n;f(2);}

51byteになった。

1
print'*'x$_."\n"for(1..($z=(pop))),reverse(1..$z-1)

#7386を元にして、入力を標準入力にして 47 
1
$n=<>;print'*'x$_."\n"for 1..$n,reverse 1..$n-1

#7389 からヒントをいただいて 1byte 削り。 46
1
print'*'x$_."\n"for 1..($n=<>),reverse 1..$n-1

余分な括弧を削った。コードゴルフって括弧を削るのも肝なのね。
47バイト。とりあえずこの方式だと一段落
1
print'*'x$_."\n"for 1..($z=pop),reverse 1..$z-1

44byte。自分の限界の気がする。

1
(-n=gets.to_i).upto(n){|i|puts"*"*(n-i.abs)}

お題のRubyのGroovy移植です。

1
2
def b = System.in.newReader().readLine().toInteger()*2
b.times { println "*"*(it<b/2 ?it:b-it) }

rubyはgets.to_iで9byteも食う。。。 perlだと43byte。

1
print"*"x($n-abs($_))."\n"for -($n=<>)..$n

65バイト

1
main=mapM_(\n->putStrLn.take n$repeat '*')$[1..4]++reverse[1..3]

がんばって53Byte
1
main=mapM(\x->putStrLn$replicate(4-abs x)'*')[-3..3]

引数で。
関数名含めて82Byte。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <stdio.h>

void pira(int n){
    int i=n*2-1,m=1;
    for(;i;m=--i<n?i:n*2-i)
        while(m+1)
            putchar(--m?'*':'\n');
}
/*
pira(int n){int i=n*2,m=1;for(;i;m=--i<n?i:n*2-i)for(;m+1;)putchar(m--?'*':'\n');}
*/
main(){
    pira(4);
}

あれ?いろいろ間違った。

ついでに見直したら79Byteになった。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <stdio.h>

void pira(int n){
    int i=n*2,m;
    while(m=--i<n?i:n*2-i)
        while(m+1)
            putchar(m--?'*':'\n');
}

//pira(int n){int i=n*2,m;while(m=--i<n?i:n*2-i)while(m+1)putchar(m--?'*':'\n');}

main(){
    pira(4);
}

データは引数で。
>jconsole LL8.ijs 4
*
**
***
****
***
**
*
1
exit wd/.'*'$~,~".>2{ARGV

スマートだ、すごい。
デフォルトの記述を省略して、37バイトまでもっていける。
1
print"*"x($n-abs)."\n"for-($n=<>)..$n

桁あふれしてしまうので0~8までしか指定できませんが39byte。stdinで指定します。

1
print'*'x$_."\n"for split//,('1'x<>)**2

もうちょっとだけ縮みました。37byte。

1
print"*"x$_."\n"for('1'x<>)**2=~/\d/g

ワンライン 縮むと思いますが一応

1
main=getLine>>=pmd.read where pmd n=mapM_(\x->putStrLn.take x$cycle"*")(nums++[n]++reverse nums)where nums=take(n-1)$iterate(+1)1

1
2
$n=4;
for($i=1-$n;$i<$n;$i++)printf("%'*".($n-abs($i))."s\n",'');

矢張り先のは長過ぎましたw 84byte

1
main=interact(\s->concat$(\x->x++(tail$reverse x))$take(read s)$iterate("*"++)"*\n")

1
2
3
4
(use srfi-42)

(do-ec (: i (index j) (* (read) 2) 0 -1)
  (print (make-string (min i j) #\*)))

1桁限定で72B。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
s/^/\n/
:a
y/987654321/876543210/
s/^/*/
P
/0/!ba
s/\n0//
:b
s/.//
p
tb

簡単そうに見えて難しかった。 結局この程度。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class H8 {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        for(int i=1; i<=Integer.parseInt(args[0]); i++) {
            for(int j=1; j<=i; j++) sb.append("*");
            sb.append("\n");
        }
        System.out.print(sb);
        System.out.println(sb.reverse().delete(0,target+2) );
    }
}

実行するには、以下のようにコマンド入力します。
コマンドの引数として数値を与えています。
一応、0のケースも入れておきました。

erlc スクリプトファイル名
erl -noshell -s pyramid main 自然数 -s init stop

実行例
$ erl -noshell -s pyramid main 0 -s init stop

$ erl -noshell -s pyramid main 1 -s init stop
*

$ erl -noshell -s pyramid main 3 -s init stop
*
**
***
**
*
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
-module(pyramid).
-export([main/1]).

main([N])-> push(list_to_integer(atom_to_list(N)),[]).

push(0,_)->0;
push(1,L)->io:format("~s~n",[L ++ "*"]), pop(L ++ "*");
push(N,L)->io:format("~s~n",[L ++ "*"]), push(N - 1, L ++ "*").

pop("*")-> 0;
pop([_|L])-> io:format("~s~n",[L]), pop(L).

#7419で投稿しましたが、push, popという関数名がそぐわない感じがしたので、
別のスタイルで書いてみました。
改行を含む文字列を前後両側に伸ばしていく感じです。
実行方法は#7419同様です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
-module(pyramid).
-export([main/1]).

main([N])->
        Len=list_to_integer(atom_to_list(N)),
        s(Len,p(Len)).

s(0,_)->0;
s(1,S)->io:format("~s", [S]);
s(N,S)->s(N - 1, p(N - 1) ++ S ++ p(N - 1)).

p(0)-> [$\n];
p(N)-> "*" ++ p(N - 1).

パディング文字で描いたらいい感じかなと思ったんですが、全然短くできませんでした…。
1
2
3
4
5
(format t "~{~,,V,'*A~%~}"
    (do ((i 1 (1+ i))
         (r () `("" ,i ,@r))
         (a () `(,i "" ,@a)))
        ((< 4 i) `(,@(nreverse r) ,@(cddr a)))))

68B。
1
for(i=n=readline();--i>-n;print(o))for(o='',j=i<0?-i:i;j++<n;)o+='*'

コマンドライン引数から取れば短くできますね。
1
b=args[0].toInteger()*2;b.times {println"*"*(it<b/2?it:b-it)}

52B。
1
[1..<(n=0.decode(args[0])),n..1]*.any{println'*'*it}

ちょっと毛色を変えてクロージャ定義で。 nを受け取ってピラミッドを返すクロージャです。

1
{n->n>1?"*¥n${call(n-1).replaceAll('¥n','*¥n')}*¥n":"*¥n"}

76B。
1
2
(do[(i(-(set! *(read))))]((=(inc! i)*))(format #t"~v,,,'*a
"(- *(abs i))""))

Squeak Smalltalk で。

1
2
3
4
5
6
| n |
n := 4.

World findATranscript: nil.
1 to: n*2-1 do: [:m |
    Transcript cr; show: (String new: {m. n*2-m} min withAll: $*)]

SWI-Prologで

1
p(N):-L is-N,between(L,N,X),K is N-abs(X),writef('%r\n',[*,K]),X=N.

あんまりひねりはないです(^^;

1
val n=readLine.toInt;for(i<- -n+1 until n) println("*" *(n-Math.abs(i)))

もうちょっと工夫してみました。短くなってません。

1
val n=readLine.toInt;for(i<-(1 to n)++(n to 1 by -1)) println("*" *i)

正攻法で文字列処理をすると長くなってしまうので、

少し変則的に文字列処理をしない方向で書いてみました。

1
2
n <- 4+1
l=rep("*",n^2);l[cumsum(n-abs(-n:n))]="\n";cat(l)

ちょっと間違ってましたorz。

1
val n=readLine.toInt;for(i<-(1 to n)++(n-1 to 1 by -1)) println("*" *i)

↑括弧が削れる。

1
(n=v gt).w(-n){|i|s ?*.*n-i.a}

あーargs使えるのか。scala h84.scala 4 とかやります。

1
val n=args(0).toInt;for(i<-(1 to n)++(n-1 to 1 by-1)) println("*"*i)

短くならないものですね。
1
2
3
4
5
6
(define (pyra n)
  (if (= n 0) 
    '() 
    (cons (make-string n #\*)(pyra (- n 1)))))
(let ((l (pyra (read))))
  (map print (append (reverse (cdr l)) l)))

target が定義されていないので、コンパイルできないようですよ?


色々と駆使して短くしてみました。 改行・Tabを除いて 168B

1
2
3
4
5
6
7
8
class Sample203{
    public static void main(String[]s){
        int n=Integer.parseInt(s[0]);
        for(int l=1;l<n*2;l++)
            for(int i=(l<n?l:n*2-l);i>=0;i--)
                System.out.print(i>0?"*":"\n");
    }
}

ワンライナーで。半角空白を除くと 110バイトになります。

# 先頭に 'javascript:'という文字列を追加して、ブラウザのアドレスバーに貼り付けて
# ください。
1
(function (n) { var i = n, s = t = ''; for ( ; i--; ) s += '*'; for (i = -n; i < n; i++) t += s.substr(0, n - Math.abs(i)) + '\n'; alert(t); })(4)

タブと改行を除くと148B
1
2
3
4
5
6
7
8
class P{
    static void Main(string[] a){
        int n=int.Parse(a[0]);
        for(int m=-n;m<=n;m++)
            for(int k=m>0?n-m:n+m;k>=0;)
                System.Console.Write(k-->0?"*":"\n");
    }
}

ちょっと短くなったので再投稿。 改行とTabを除いて158B

1
2
3
4
5
6
7
8
class L{
    public static void main(String[]s){
        int n=Integer.parseInt(s[0]);
        for(int i=1;i>0;n--,i+=n>0?1:-1)
            for(int j=i;j>=0;j--)
                System.out.print(j>0?"*":"\n");
    }
}

宣言をまとめると4バイト縮みます。

1
2
3
4
5
6
7
8