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

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

51byteになった。

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

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

同じコードを短縮してみました。 iostream.h使うとstd::省略とか、i?1:0の代わりにi==0とか、関数のvoid削除とか。 意外とコンパイル出来るもんですね。 改行あわせて132バイト。

1
2
3
4
5
#include <iostream.h>
int n;
g(int i){while(i--)cout<<"*\n"[i==0];}
f(int i){g(i);if(i!=n+1)f(i+1),g(i);}
main(){cin>>n;f(2);}
g++ 3.4.5 (mingw) や 4.1.2 、Sun C++ 5.8 で試してみましたが、
3行目4行目(関数の返値型省略)がerrorになってコンパイルできませんでしたよー

#7583の匿名さんではありませんが、 IBM XL/C++では(ワーニングがでますが)コンパイル&実行可能です。

とはいえ、環境依存のようですからその旨を書いておいたほうがよさそうですね。

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

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

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

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

↑括弧が削れる。

1
(n=v gt).w(-n){|i|s ?*.*n-i.a}
先頭と最後に空白行がはいるのはok?

お題のRubyのGroovy移植です。

1
2
def b = System.in.newReader().readLine().toInteger()*2
b.times { println "*"*(it<b/2 ?it:b-it) }
コマンドライン引数から取れば短くできますね。
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}

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

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

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

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

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

さらに1byte縮んで36byte。

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

同じようなアルゴリズムをRubyで書いてみましたが、イマイチ・・・to_i, to_i, to_s, to_i ...

1
2
3
(('1' * gets.to_i).to_i ** 2).to_s.scan(/./) do |i|
    puts "#{'*' * i.to_i}\n"
end

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

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

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

実行するには、以下のようにコマンド入力します。
コマンドの引数として数値を与えています。
一応、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)))))

書式パクらせてもらいました。 これは知らなかった…

1
(do*((e(read))(i(- e)(1+ i)))((= i e))(format t"~,,V,'*A~%"(- e(abs i))""))

do でカウンタを使う場合は終了判定で incf/decf すると一文字減ります。

1
2
(do*((e(read))(i(- e)))((=(incf i)e))(format t"~V@{*~}
"(- e(abs i))t))
68B。
1
for(i=n=readline();--i>-n;print(o))for(o='',j=i<0?-i:i;j++<n;)o+='*'

ちょっと毛色を変えてクロージャ定義で。 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)))