ASCIIポリゴンの面積


31

ASCIIアートポリゴンを表す文字列を入力および出力として受け取り、ポリゴンの領域を返すプログラムまたは関数を作成する必要があります。

入力は、文字で構成され、単純な多角形_ / \ L V spacenewline定義する文字列です(つまり、余分なセグメント、セルフタッチ、セルフ交差はありません)。

単一の文字セルの面積は 2

  • _サイズにセルを分割0し、2
  • \サイズにセルを分割1し、1
  • /サイズにセルを分割1し、1
  • Lサイズにセルを分割0し、2
  • Vサイズに細胞を分割1し、1(の双方はV、それらがリストに一緒に処理されるので、常にポリゴンの同じ側にあります。)

すべての文字は、期待する文字セルの2つのコーナーを接続します(例:の場合は左上と右上V)。

面積が7の例(1+2+12行目と1+1+13 行目):

 _
/ \
V\/

入力

  • 入力は長方形を形成します。つまり、改行の間には同じ数の文字があります。
  • 多角形の任意の辺に余分な空白を含めることができます。
  • 末尾の改行はオプションです。

出力

  • 単一の正の整数、ポリゴンの面積。

出力は、入力の最後の行の後です。

  _  
  V  

1

/L
\/

3



    /VV\
    L  /
     L/
14

  ____/\ 
  \    /
/\/   /
\____/

32  

   /V\
  /   \__ 
  \     /
/\/   /V
L____/

45

これはコードゴルフなので、最短のエントリーが勝ちます。


3番目の例は14
オプティマイザー

@Optimizerありがとう、訂正。
randomra

^ 意図的に不足しているのですか?
-RobAu

@RobAuはい、それは十分に見えません。
-randomra

回答:


5

CJam、48 43 29バイト

qN-{i_9%2%U!^:U;J%D%1U2*?}%:+

更新:数学とorlpの答えからのstate * 2トリックを使用してたくさんゴルフをしました。

仕組み(期限切れ、間もなく更新)

入力を改行で分割し、各部分について境界文字の出現のカウンターを維持しL\/ます。このカウンター%2は、2つのパーティションのどちらを選択してすべてのキャラクターを選択するかを示します。次に、文字列内の各文字のインデックスを見つけますL _。配列の最後の要素\/V-1参照します。インデックスを取得した後4558Zb2/、配列を作成[[2 0] [0 2] [0 2] [1 1]]するために使用し、カウンターを使用して正しいカウントを選択します。

qN/0f{                                  }      e# Split the input on newline and for each
      \{                             }/        e# swap the 0 to back and for each char in
                                               e# the line, run this loop
        _"L _"#                                e# Copy the char and get index of it in
                                               e# this string "L _"
               4558Zb                          e# This is basically 4558 3base
                                               e# which comes to be [2 0 0 2 0 2 1 1]
                     2/=                       e# Group into pairs of 2 and choose the
                                               e# correct one.
                        2$=                    e# Based on the counter, choose the correct
                                               e# partition amount
                           @@"\/L"&,+          e# Increment the counter if the char is one
                                               e# of \, / and L
                                       ;       e# Pop the counter after each line loop
                                         :+    e# Sum all the numbers to get area

こちらからオンラインでお試しください


22

Pyth、47 46 45 36 30

FNs.zx=Z}N"\/L"aY|}N"\/V"yZ;sY

説明:

FNs.z            For every character in input, except newlines...
  x=Z}N"\/L"     Swap state if /, \, or L.
  aY|}N"\/V"yZ;  Append 1 if /, \, or V, else 2 times the state to Y.
sY               Sum Y and print.

「ポリゴン内」と「ポリゴン外」の2つの状態があります。以下の文字はそれぞれ、左上から右下に読むときに次のことを行います。

/ \     swap state, add one to area
V                   add one to area
_ space             if in polygon, add two to area
L       swap state, if in polygon, add two to area

「エリアに1つ追加」と「ポリゴンの場合、エリアに2つ追加」は相互に排他的であることに注意してください。


私は本当にどのようにx=機能するかについて混乱しています。これはどこかに文書化されていますか?
ジャクベ

@ジャクベそれは拡張された割り当てです。
orlp

@Jakubeそれのように+=*=または何でも。この場合xはxorとして使用されているので、Pythonのとまったく同じです^=
isaacg

14

網膜、293 + 15 = 308314 385バイト

;`\s
_
;`\\
/
;`.+
o$0iio
;+`(o(?=/.*(i)|L.*(ii)|V.*(io)|_)|i(?=/.*(io)|L.*(o)|_.*(ii)|V.*(i))).
$1$2$3$4$5$6$7$8
;`o
<empty>
;`ii$
#:0123456789
;+`^(?=i)(i*)\1{9}(?=#.*(0)|i#.*(1)|ii#.*(2)|iii#.*(3)|iiii#.*(4)|iiiii#.*(5)|iiiiii#.*(6)|iiiiiii#.*(7)|iiiiiiii#.*(8)|iiiiiiiii#.*(9))
$1#$2$3$4$5$6$7$8$9$10$11
:.*|\D
<empty>

各行は個別のファイルに含まれるため、バイトカウントに13を追加しました。または、すべてを1つのファイルにそのまま入れて、-sフラグを使用することもできます。<empty>実際に空のファイルまたは行の略。

残念ながら、結果を単項から10進数に変換するためだけに187バイトが必要です。近いうちにこれを実際に実装する必要があると思います。

説明

Retinaは正規表現ベースの言語です(正規表現でこのようなことを行えるようにするために正確に記述しました)。ファイル/行の各ペアは置換ステージを定義します。最初の行はパターンで、2行目は置換文字列です。パターンの前に`-delimited構成文字列を付けることができます。この構成文字列には、通常の正規表現修飾子とRetina固有のオプションが含まれる場合があります。上記のプログラムの場合、関連するオプションは;、そのステージの出力を抑制する、および+結果が変化しなくなるまでループ内の置換を適用する、です。

解決策のアイデアは、各行を個別にカウントすることです。なぜなら、ポリゴンの内側にいるか外側にいるかは、すでに遭遇したキャラクターによっていつでも決定できるからです。これは、線の始点と終点が常にポリゴンの外側にあるため、すべてを1本の線に結合できることも意味します。我々はまた、ことに注意することができます_ラインスイープアルゴリズムのために完全に一致している、などとスペース\/。だから、最初のステップとして、私はすべての改行とスペースを交換_し、すべての\ことで/、後にいくつかのコードを簡素化します。

現在の内側/外側の状態を文字ioで追跡し、同時にisを使用して領域を集計します。そのためにo、ポリゴンの外側にいることを示すために、結合された線にを追加することから始めます。またiio、入力の最後にを追加します。これは、新しい文字を生成するためのルックアップとして使用します。

次に、最初の大規模な置換は、単純に1つを次の文字セットに置換するiか、またはo1つを置換するだけ/V_Lで、全体をフラッディングして集計します。置換テーブルは次のようになります。列はその行の最後の文字に対応し、行は次の文字に対応します(場所Sはスペースと<>空の文字列です)。入力のすべての文字を含めて、すでに使用した等価性を示しています。

     i     o

/    io    i
\    io    i
L    o     ii
V    i     io
_    ii    <>
S    ii    <>

最後の文字は、文字の後にポリゴンの内側にあるか外側にあるかを常に示し、is の数はポリゴンに追加する必要がある領域に対応することに注意してください。例として、最後の入力例の最初の4回の繰り返しの結果を示します(これは、実際には各行を個別にフラッディングする古いバージョンによって生成されましたが、原理は同じです)。

o   /V\
o  /   \___
o  L     _/
o/\/   /V
oL__ _/
o   V

o  /V\
o /   \___
o L     _/
oi\/   /V
oii__ _/
o  V

o /V\
o/   \___
oL     _/
oiio/   /V
oiiii_ _/
o V

o/V\
oi   \___
oii     _/
oiioi   /V
oiiiiii _/
oV

oiV\
oiii  \___
oiiii    _/
oiioiii  /V
oiiiiiiii_/
oio

最後に、にo一致するものをすべて削除することで、すべてのsと改行を取り除き[^i]、残りは10進数から1進数への変換であり、かなり退屈です。


4

Perl、65 58バイト

map{map{$b^=2*y,/\\L,,;$a+=y,/\\V,,||$b}split//}<>;print$a
  • / \またはLが表示されたら、$ bを0と2の間で切り替えます。
  • / \またはVが表示されたら、$ aに1を追加します。
  • 他のものを見たら、$ aに$ bを追加します。

素晴らしい解決策、Perlは驚くほどコンパクトです。
orlp

1
入力処理をさらにいくつかのゲインのために簡素化できます$/=\1;$-^=2*y,/\\L,,,$a+=y,/\\V,,||$-for<>;print$a
。– nutki

4

GNU sed、290 + 1

+ 1は-r、sedに渡されるスイッチを考慮します。コメントと追加の空白はスコアにカウントされません。

私は詳細に見ていないが、これはおそらくマーティンの網膜の答えに似ていると思う:

:                      # label to start processing next (or first) line
s/[0-9]//g             # remove the count of colons from previous lines
H                      # append the current line to the hold space
g                      # copy the hold space to the pattern space
y^_\\^ /^              # Replace '_' with ' ' and replace '\' with '/'
s/(\n| +$)//g          # strip newlines and trailing space
:o                     # start of "outside loop"
s/(^|:) *V/\1:/        # replace leading spaces and "V" with ":"
to                     #   if the above matches, stay outside
s/(^|:) *[|/]/\1:/     # replace leading spaces and "|" or "/" with ":"
ti                     #   if the above matches, go inside
s/(^|:) *L/\1::/       # replace leading spaces and "L" with "::"
:i                     # start of "inside" loop
s/: /:::/              # replace space with "::"
ti                     #   if the above matches, stay inside
s/:V/::/               # replace "V" with ":"
ti                     #   if the above matches, stay inside
s/:[|/]/::/            # replace "|" or "/" with ":"
to                     #    if the above matches, go outside
s/:L/:/                # remove "L"
to                     #    if the above matches, go outside
h                      # copy current string of colons to hold buffer
:b                     # start of colon count loop
s/:{10}/</g            # standard sed "arithmetic" to get string length
s/<([0-9]*)$/<0\1/
s/:{9}/9/
s/:{8}/8/
s/:{7}/7/
s/:{6}/6/
s/:{5}/5/
s/::::/4/
s/:::/3/
s/::/2/
s/:/1/
s/</:/g
tb                     # once arithmetic done, pattern buffer contains string length
N                      # append newline and next line to pattern buffer
b                      # loop back to process next line

概要

  • エリアの各ユニットをコロンで置き換えます :
  • コロンの数を数える

ノート

  • sed行指向であるため、一度に複数の行を処理するには多少の作業が必要です。このNコマンドは、現在のパターンスペースに改行を追加してから次の行を追加することでこれを行います。難点Nは、入力ストリームEOFに到達すると、それsed以上の処理を行うオプションなしで完全に終了することです。これを回避するために、次の行を読み込む直前に、各行の最後で現在のコロンのセットをカウントします。

出力:

$ echo '   /V\
  /   \__ 
  \     /
/\/   /V
L____/' |sed -rf polyarea.sed
45
$

3

C、93 96108バイト

編集:コメントの提案を考慮に入れ、whileをループの単一ステートメントに変換し、「i」変数を完全に削除しました。

int s,t;main(c,v)char**v;{for(;c=*v[1]++;t+=s+(c>46^!(c%19)^s))s^=c>13^c%9>4;printf("%d",t);}

元の投稿:

これは、ここでアカウントを作成できるようにするための、楽しくて簡単な問題のように見えました。

main(c,v)char**v;{int i,t,s;i=t=s=0;while(c=v[1][i++]){s^=c>13^c%9>4;t+=s+(c>46^!(c%19)^s);}printf("%d",t);}

ポリゴンテキストは、最初のコマンドライン引数として渡す必要があります。これは、改行や空白を使用してもしなくても機能します。

これは、ポリゴンを一度に1文字ずつ読み取り、sは現在「/」、「L」、または「\」でポリゴンの内外を切り替え、tは「/」、「V」、および「\」、または「L」、「_」、スペースおよび改行で内側の場合は2、外側の場合は0

あらゆる種類の「ゴルフ」(またはC、C ++とは異なる範囲でC)に手を触れるのは今回が初めてなので、批判を歓迎します!


ようこそ、お疲れ様でした!とにかくi=t=s=0;Cがすべてintのsを0に初期化すると思うのをスキップできるかもしれません。また、whileループをループに変換できるかどうかも確認してforください。それはしばしば数バイトを節約します。
Ypnypn

上記のforループのアイデアを使用すると、次のようなことができると思います...int i,t,s;for(i=t=s=0;c=v[1][i++];t+=s+(c>46^!(c%19)^s))s^=c>13^c%9>4;...。4バイト節約できます。1つ、1つ、2つ。
ダイダロス

また、前述のように、明らかにグローバル変数は自動的に0に設定されるため、内部int i,t,v;ではmainなく前に置くと、i=t=s=0さらに7バイトを節約できます。
ダイダロス

3

POSIX sed、245 244

POSIX sed、拡張機能または拡張正規表現なし。入力はsedの最大保持スペースサイズに制限されます-POSIXでは少なくとも8192が義務付けられています。GNUがさらに管理します。このバージョンでは、図形の前後に空白行がないことを前提としています。拡張で示されている余分な10バイトのコードは、それが要件である場合に対応できます(元の質問では指定されていません)。

H
/^\([L\\]_*\/\|V\| \)*$/!d
x
s/[_ ]/  /g
s/^/!/
s/$/!/
:g
s/\([^V]\)V/V\1/
tg
y/V/ /
s/L/!  /g
s,[/\\], ! ,g
s/![^!]*!//g
:d
/ /{
s/     /v/g
s/vv/x/g
/[ v]/!s/\b/0/2
s/  /b/g
s/bb/4/
s/b /3/
s/v /6/
s/vb/7/
s/v3/8/
s/v4/9/
y/ bvx/125 /
td
}

拡張および注釈付き

#!/bin/sed -f

# If leading blank lines may exist, then delete them
# (and add 8 bytes to score)
#/^ *$/d

# Collect input into hold space until we reach the end of the figure
# The end is where all pieces look like \___/ or V
H
/^\([L\\]_*\/\|V\| \)*$/!d

x

# Space and underscore each count as two units
s/[_ ]/  /g

# Add an edge at the beginning and end, so we can delete matching pairs
s/^/!/
s/$/!/
# Move all the V's to the beginning and convert each
# to a single unit of area
:gather
s/\([^V]\)V/V\1/
tgather
y/V/ /

# L is a boundary to left of cell; / and \ in middle
s/L/!  /g
s,[/\\], ! ,g

# Strip out all the bits of outer region
s/![^!]*!//g

# Now, we have a space for each unit of area, and no other characters
# remaining (spaces are convenient because we will use \b to match
# where they end).  To count the spaces, we use roman numerals v and x
# to match five and ten, respectively.  We also match two (and call
# that 'b').  At the end of the loop, tens are turned back into spaces
# again.
:digit
/ /{
s/     /v/g
s/vv/x/g
/[ v]/!s/\b/0/2
s/  /b/g
s/bb/4/
s/b /3/
s/v /6/
s/vb/7/
s/v3/8/
s/v4/9/
y/ bvx/125 /
tdigit
}

# If trailing blank lines may exist, then stop now
# (and add 2 bytes to score)
#q

1

C、84バイト

a;i;f(char*s){for(;*s;a+=strchr("\\/V",*s++)?1:i+i)i^=!strchr("\nV_ ",*s);return a;}

見るたびにサイドを切り替える\/またはL; \\/またはに常に1を追加しVますが、スペース、改行、Lまたはに2(内部の場合)または0(外部の場合)を追加します_

変数aおよびiは、入力時にゼロであると想定されます-関数が複数回呼び出される場合、それらはリセットされなければなりません。

ゴルフをしていない:

int a;                          /* total area */
int i;                          /* which side; 0=outside */
int f(char*s)
{
    while (*s) {
        i ^= !strchr("\nV_ ",*s);
        a += strchr("\\/V",*s++) ? 1 : i+i;
    }
    return a;
}

テストプログラム:

#include <stdio.h>
int main()
{
    char* s;
    s = "  _  \n"
        "  V  \n";
    printf("%s\n%d\n", s, f(s));
    a=i=0;

    s = "/L\n"
        "\\/\n";
    printf("%s\n%d\n", s, f(s));
    a=i=0;


    s = "    /VV\\\n"
        "    L  /\n"
        "     L/";
    printf("%s\n%d\n", s, f(s));
    a=i=0;

    s = "  ____/\\ \n"
        "  \\    /\n"
        "/\\/   /\n"
        "\\____/";
    printf("%s\n%d\n", s, f(s));
    a=i=0;

    s = "   /V\\\n"
        "  /   \\__ \n"
        "  \\     /\n"
        "/\\/   /V\n"
        "L____/";
    printf("%s\n%d\n", s, f(s));
    a=i=0;

    return 0;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.