สร้างไดอะแกรม Voronoi (ตัวแปร ASCII)


24

สมมติว่าคุณได้รับตัวอักษรตัวพิมพ์ใหญ่ที่แตกต่างกันกระจัดกระจายในอาร์เรย์ของเซลล์ที่ว่างเปล่าเป็นรูปสี่เหลี่ยมผืนผ้า แต่ละเซลล์ในอาเรย์เป็นของตัวอักษรที่อยู่ใกล้ที่สุดซึ่งกำหนดเป็นตัวอักษรที่เข้าถึงได้ในจำนวนขั้นตอนแนวนอนและ / หรือแนวตั้งที่น้อยที่สุด - ไม่มีขั้นตอนในแนวทแยง (หากเซลล์มีความยาวเท่ากันจากตัวอักษรที่ใกล้ที่สุดสองตัวขึ้นไปมันจะเป็นตัวอักษรตัวใดตัวหนึ่งตามลำดับตัวอักษรเซลล์ที่มีตัวอักษรตัวพิมพ์ใหญ่อยู่ในนั้นจะเป็นตัวอักษรนั้น) Boundary -cells เป็นแนวนอนหรือแนวตั้ง ติดกับเซลล์อย่างน้อยหนึ่งเซลล์ที่ไม่ได้เป็นของตัวอักษรที่พวกมันเป็นของตัวเอง

เขียนโปรแกรมย่อยของโพรซีเดอร์ที่มีพฤติกรรมดังต่อไปนี้สร้างแผนภาพ Voronoi ...

อินพุต : สตริง ASCII ใด ๆ ที่ประกอบด้วยจุดตัวอักษรตัวพิมพ์ใหญ่และบรรทัดใหม่เท่านั้นเช่นเมื่อพิมพ์จะแสดงอาร์เรย์สี่เหลี่ยมของชนิดที่อธิบายข้างต้นโดยมีจุดที่ทำหน้าที่เป็นช่องว่าง

เอาท์พุท : การพิมพ์ของสตริงการป้อนข้อมูลที่มีแต่ละเซลล์ว่างขอบเขตแทนที่ด้วยรุ่นตัวพิมพ์เล็กของตัวอักษรมันเป็นของ (โปรแกรมย่อยทำการพิมพ์)

ตัวอย่างที่ 1

การป้อนข้อมูล:

......B..
.........
...A.....
.........
.......D.
.........
.C.......
.....E...
.........

เอาท์พุท:

...ab.B..
....ab.bb
...A.abdd
aa...ad..
cca.ad.D.
..caeed..
.C.ce.edd
..ce.E.ee
..ce.....

ร่างที่ไฮไลต์ขอบเขต:

ร่างที่เน้นขอบเขต

ตัวอย่างที่ 2

การป้อนข้อมูล:

............................U...........
......T.................................
........................................
.....................G..................
..R.......S..........F.D.E............I.
.........................H..............
.....YW.Z...............................
......X.................................
........................................
........................................
......MN...........V....................
......PQ................................
........................................
.............L...............J..........
........................................
........................................
....C...........K.......................
........................................
..................................A.....
...........B............................

เอาท์พุท:

..rt.....ts...sg......gduu..U.....ui....
..rt..T..ts...sg......gddeu......ui.....
...rt...ts....sg......gddeeu....ui......
....rttts.....sggggggGgdde.euuuui.......
..R.rywss.S....sfffffFdDdEeeeeeei.....I.
...ryywwzs.....sf....fddhHhhhhhhhi......
..ryyYWwZzs..sssffff.fddh.......hi......
..rxxxXxzzs.sllvvvvvffddh....hhhhi......
rrrxxxxnzzssl.lv....vfddh...hjjjjii.....
mmmmmmmnnnnnl.lv.....vvdh..hj....jai....
mmmmmmMNnnnnl.lv...V...vvhhj.....jaai...
ppppppPQqqql...lv.......vhj......ja.ai..
ppppp.pq.ql....lkv.....vjj.......ja..aii
cccccppqql...L.lkkv...vj.....J...ja...aa
.....cpqqlll..lk..kvvvvj........ja......
......cccbbbllk....kkkkj.......ja.......
....C...cb..bk..K......kj.....ja........
.......cb....bk........kjjjjjja.........
......cb......bk.......kaaaaaa....A.....
.....cb....B...bk......ka...............

การปรับปรุงสี:

การเพิ่มประสิทธิภาพของสี


1
+1; ที่น่าสนใจ; แต่ฉันสังเกตว่าเซลล์ในอินพุตตัวอย่างและเอาต์พุตมีช่องว่างหนึ่งช่องว่างระหว่างอักขระแต่ละตัว นั่นเป็นข้อกำหนดหรือไม่?
Doorknob

@DoorknobofSnow - โอ๊ะฉันทำผิด - ไม่ได้ตั้งใจ ฉันจะแก้ไขเพื่อลบออก
res

เพื่อให้ชัดเจนนี่คือแผนภาพเมตริกของแมนฮัตตันไม่ใช่แบบยุคลิด ไดอะแกรม Voronoi นั้นค่อนข้างเท่ห์ในพื้นที่ของตัวชี้วัดที่ไม่ใช่แบบยุคลิด (ดูที่นี่หรือเพิ่ม Blender หากคุณมีสำเนา; มันมีตัวชี้วัดที่น่าสนใจอยู่ในตัว)
wchargin

@WChargin - เป็นหลักใช่ ที่นี่ "ระยะทาง" ระหว่างเซลล์ทั้งสองเป็นเพียงขั้นตอนจำนวนน้อยที่สุดที่จำเป็นในการเดินจากเซลล์หนึ่งไปยังอีกเซลล์หนึ่งโดยเหยียบเฉพาะระหว่างเซลล์แนวนอนหรือแนวตั้งที่อยู่ติดกันตลอดทาง (มันเป็นจำนวนเต็มไม่ใช่ค่าลบเสมอ) นี่คือเมตริกแท็กซี่ถ้าเราจินตนาการว่าเซลล์เป็นจุดตัดถนนในเมืองที่ถนนมีความกว้างเป็นศูนย์และมีบล็อกเป็นหน่วยสี่เหลี่ยม
res

คำตอบ:


5

GolfScript, 138 144 137 ตัวอักษร

:^n%,,{{^n/1$=2$>1<.'.'={;{@~@+@@+\{^3$?^<n/),\,@-abs@@-abs+99*+}++^'.
'-\$1<{32+}%}++[0..1.0..(.0]2/%..&,(\0='.'if}{@@;;}if}+^n?,%puts}/

อินพุตถูกกำหนดให้กับโปรแกรมย่อยเป็นสตริงเดี่ยวบนสแต็ก น่าเสียดายที่ฉันต้องใช้putsเพราะความต้องการที่รูทีนต้องพิมพ์ผลลัพธ์

คำอธิบายของรหัส

บล็อกด้านนอกจะวนซ้ำไปตามตำแหน่งทั้งหมด (x, y) ตามขนาดของรูปสี่เหลี่ยมผืนผ้าอินพุต ภายในลูปพิกัด x และ y จะถูกทิ้งไว้บนสแต็กในแต่ละครั้ง หลังจากแต่ละบรรทัดเสร็จสมบูรณ์ผลลัพธ์จะถูกพิมพ์ลงในคอนโซล

:^              # save input in variable ^
n%,,{{          # split along newlines, count rows, make list [0..rows-1] 
    ???             # loop code, see below
}+^n?,%puts}/       # ^n?, count columns, make list [0..cols-1], loop and print

รหัสที่ดำเนินการภายในลูปจะใช้อักขระที่สอดคล้องกันของอินพุตก่อน

^n/                 # split input into lines
1$=                 # select the corresponding row
2$>1<               # select the corresponding col

จากนั้นเราก็ตรวจสอบโดยทั่วไปว่าเรามี.หรือไม่ถ้าเรา (อาจจะ) ต้องเปลี่ยนอักขระ

.'.'={              # if the character is '.'
    ;               # throw away the '.'
    ???             # perform more code (see below)
}{                  # else
    @@;;            # remove coordinates, i.e. keep the current character 
                    # (i.e. A, B, ... or \n)
}if                 # end if

อีกครั้งรหัสภายในเริ่มต้นด้วยการวนซ้ำตอนนี้ทุกพิกัด (x, y) (x, y + 1) (x + 1, y) (x, y-1) (x-1, y)

{                   
    @~@+@@+\        # build coordinates x+dx, y+dy
    ???             # loop code
}++                 # push coordinates before executing loop code
[0..1.0..(.0]2/%    # loop over the coordinates [0 0] [0 1] [1 0] [0 -1] [-1 0]

ข้อมูลโค้ดภายในล่าสุดส่งคืนตัวอักษร (ตัวพิมพ์เล็ก) ของจุดที่ใกล้ที่สุดโดยกำหนดพิกัดทั้งสอง

{                   # loop
    ^3$?^<          # find the current letter (A, B, ...) in the input string, 
                    # take anything before
    n/              # split at newlines
    ),              # from the last part take the length (i.e. column in which the letter is)
    \,              # count the number of lines remaining (i.e. row in which the letter is)
    @-abs@@-abs+    # calculate distance to the given coordinate x, y
    99*+            # multiply by 99 and add character value (used for sorting
                    # chars with equal distance)
}++                 # push the coordinates x, y
^'.
'-                  # remove '.' and newline
\$                  # now sort according to the code block above (i.e. by distance to letter)
1<{32+}%            # take the first one and make lowercase

ดังนั้นจากตัวอักษรที่ใกล้ที่สุดห้าตัวสำหรับพิกัด (x, y) (x, y + 1) (x + 1, y) (x, y-1) (x-y, 1) ใช้ตัวแรกถ้าไม่ใช่ทั้งหมด .เท่ากับมิฉะนั้นจะใช้

.                   # copy five letter string
.&,(                # are there distinct letters?
\0=                 # first letter (i.e. nearest for coordinate x,y)
'.'                 # or dot
if                  # if command

รหัสของคุณใช้ได้กับตัวอย่างที่ 1 ดังนั้นฉันจึงประหลาดใจเมื่อบางเซลล์ไม่ถูกต้องในตัวอย่างที่ 2: ในแต่ละสามบรรทัดแรกมันใส่ ".ui" โดยที่ "ui" ควรและในบรรทัดที่สี่จะใส่ "zs" โดยที่ "s" ควรและวาง "ui" โดยที่ "i" ควรเป็นเช่นนั้นเป็นต้น
res

@res พลาดส่วน "equidistant - first ตามลำดับตัวอักษร" น่าเสียดายที่การเรียงลำดับไม่เสถียร เพิ่มตัวอักษรสองสามตัวเพื่อแก้ไขปัญหานั้น
Howard

7

Python 3 - 424 422 417 332 295 ตัวอักษร:

def v(s):
 w=s.find("\n")+1;n=(-1,1,-w,w);r=range(len(s));x=str.replace;s=x(x(s,*".~"),*"\n~")+"~"*w;t=0
 while s!=t:t=s;s=[min(s[i+j]for j in n).lower()if"~"==s[i]and(i+1)%w else s[i]for i in r]+["~"]*w
 print(x("".join(s[i]if any(s[i]!=s[i+j].lower()!="~"for j in n)else"."for i in r),*"~\n"))

มีสามส่วนแต่ละส่วนจะต้องอยู่ในบรรทัดของตัวเองเนื่องจากไวยากรณ์ของงูใหญ่:

  1. บรรทัดแรกตั้งค่าตัวแปร wคือความกว้างของแถวของบอร์ด (รวมถึงบรรทัดใหม่ในตอนท้ายซึ่งจะถูกรีไซเคิลเป็นคอลัมน์เสริมภายใน) rเป็นวัตถุที่ดัชนีทุกตัวละครในrange คือ tuple ของ index offsets เพื่อไปที่เพื่อนบ้านของตัวละคร (ดังนั้นหากคุณต้องการให้ตัวอักษรกระจายออกในแนวทแยงมุมคุณจะต้องเพิ่มไปยัง tuple) เป็นชื่อสั้น ๆ ของวิธีการซึ่งจะถูกใช้หลายครั้งในโค้ดในภายหลัง (การโทรจะดูแปลก ๆ เนื่องจากฉันใช้เพื่อบันทึกอักขระแทนที่จะเป็นแบบธรรมดา) สตริงพารามิเตอร์ที่มีการแก้ไขเล็กน้อยที่จุดนี้เช่นกันกับตัวละครและการขึ้นบรรทัดใหม่ถูกแทนที่ด้วยsn-w-1,-w+1,w-1,w+1xstr.replacex(s,*"xy")s.replace("x", "y")s.~ตัวอักษร (เพราะเรียงตามตัวอักษรทั้งหมด) ~นอกจากนี้ยังมีการเพิ่มอักขระpadding ในแถวด้วยเช่นกัน tจะถูกใช้เป็นข้อมูลอ้างอิงถึงเวอร์ชัน "เก่า" ของsแต่จะต้องเริ่มต้นกับบางสิ่งที่ไม่เท่ากับsตอนเริ่มต้นและศูนย์ใช้อักขระเพียงตัวเดียว (ค่า Pythonic มากกว่าจะเป็นNoneแต่นั่นคืออักขระพิเศษสามตัว) .
  2. บรรทัดที่สองมีการวนซ้ำที่ปรับปรุงซ้ำsโดยใช้รายการความเข้าใจ ในฐานะที่เป็นความเข้าใจ iterates กว่าดัชนีของs, ~ตัวละครจะถูกแทนที่โดยminของเพื่อนบ้านของพวกเขา หาก~ตัวละครถูกล้อมรอบไปด้วยตัวละครอื่น ๆ~สิ่งนี้จะไม่ทำอะไร หากอยู่ถัดจากตัวอักษรหนึ่งตัวขึ้นไปมันจะกลายเป็นตัวอักษรที่เล็กที่สุด (นิยม"a"มากกว่า"b"ฯลฯ ) บรรทัดใหม่ที่ถูกเปลี่ยนเป็น~อักขระจะถูกรักษาไว้โดยการตรวจจับดัชนีของพวกเขาด้วยตัวดำเนินการโมดูลัส แถว padding ที่ท้ายไม่ได้รับการอัปเดตในรายการความเข้าใจ (เนื่องจากช่วงของดัชนีrถูกคำนวณก่อนที่จะถูกเพิ่มเข้าไปs) แต่เป็นแถวใหม่ของ~ตัวละครจะถูกเพิ่มหลังจากเสร็จสิ้นความเข้าใจ โปรดทราบว่าsกลายเป็นรายการของตัวละครมากกว่าสตริงหลังจากผ่านครั้งแรกของการวนรอบ (แต่เนื่องจาก Python มีความยืดหยุ่นเกี่ยวกับประเภทเรายังสามารถทำดัชนีเพื่อให้ได้ตัวอักษรในลักษณะเดียวกัน)
  3. บรรทัดสุดท้ายกลวงเข้าไปด้านในของไดอะแกรมและสร้างอักขระใหม่เป็นสตริงที่จะพิมพ์ ครั้งแรกที่ตัวอักษรใด ๆ ที่ถูกล้อมรอบโดยเฉพาะเล่มอื่น ๆ ของตัวเอง (หรือ~ตัวละครจากช่องว่างภายใน) .ได้รับการแทนที่ด้วย จากนั้นอักขระทั้งหมดจะถูกต่อกันเป็นสตริงเดียว ในที่สุด~ตัวอักขระpadding จะถูกแปลงกลับไปเป็นบรรทัดใหม่และสตริงจะถูกพิมพ์

น่าจะเป็นr=rangeควรจะเป็นภายในร่างกายของฟังก์ชั่นที่จะได้เป็นส่วนหนึ่งของการพิจารณาขั้นตอนการ callable r=range;s=[l.replaceแต่คุณสามารถบันทึกตัวอักษรโดยการเขียน นอกจากนี้คุณยังสามารถบีบตัวอักษรได้มากขึ้นโดยการเขียนif"~"==s[y][x]elseและif"~"==s[y][x]elseรวมเป็น 422 (Btw สิ่งนี้วิ่งมาหาฉันกับ Python 2.7)
res

@res: ขอบคุณสำหรับคำแนะนำเหล่านั้น ฉันใส่r=rangeท้ายบรรทัดแรกของฟังก์ชั่น (ที่ฉันตั้งค่าตัวแปรอื่น ๆ ) และโกนช่องว่างสองสามอันที่ฉันพลาดไปก่อนหน้านี้ ฉันไม่แน่ใจว่าฉันได้ทั้งสองอย่างที่คุณอ้างถึงหรือไม่เพราะคุณดูเหมือนจะพูดถึงสิ่งเดียวกันสองครั้ง และใน Python 2.7 อาจมีความยาวไม่เกินสองตัวอักษรเนื่องจากคุณไม่จำเป็นต้องใส่วงเล็บหลังprint(โดยปกติแล้วจะบันทึกได้เพียง 1 ตัวเท่านั้น แต่print"\n".join(...)ใช้ได้)
Blckknght

อุ๊ปส์ฉันวางผิดที่หนึ่งที่สอง มันควรจะเป็นs[y][x]for(ลบพื้นที่) แต่คุณดูเหมือนจะได้พบมันต่อไป
res

ใช่นั่นคืออีกหนึ่งฉันได้รับ ฉันเพิ่งตัดสินใจที่จะลองการเปลี่ยนแปลงที่ยิ่งใหญ่กว่าและไปที่รายการ 1d แทนที่จะเป็น 2d ซึ่งกลายเป็นการบันทึกอักขระจำนวนมาก!
Blckknght

3

Python 229 226 ตัวอักษร

def F(s):
 e,f,b='~.\n';N=s.index(b)+1;s=s.replace(f,e)
 for i in 2*N*e:s=''.join(min([x[0]]+[[y.lower()for y in x if y>b],all(y.lower()in f+b+x[0]for y in x)*[f]][x[0]!=e])for x in zip(s,s[1:]+b,s[N:]+b*N,b+s,b*N+s))
 print s

F("""......B..
.........
...A.....
.........
.......D.
.........
.C.......
.....E...
.........
""")

น้ำท่วมเติมเพื่อคำนวณผลลัพธ์หรือไม่ การติดตามfor/ zipคำสั่งผสมสร้างอาร์เรย์xสำหรับแต่ละเซลล์ที่มีค่าในเซลล์นั้นและสี่ประเทศเพื่อนบ้าน จากนั้นเราใช้เคล็ดลับของ Blckknght และminความเป็นไปได้มากมายสำหรับแต่ละเซลล์ สิ่งเหล่านี้เป็นคุณค่าของเซลล์ดั้งเดิมเพื่อนบ้านใด ๆ หากยังไม่ได้เข้าชมเซลล์หรือ.ถ้ามันได้รับการเยี่ยมชมและเพื่อนบ้านทั้งหมดมี.หรือเท่ากับเซลล์นั้นเอง


เนื่องจากโปรแกรมย่อยควรจะทำพิมพ์, คุณก็สามารถเปลี่ยนไปreturn s print sนอกจากนี้ไม่y!=bสามารถเปลี่ยนเป็นy>b? ฉันคิดว่าจะเป็น 226 ตัวอักษร
res

3

นี่มันคือ นี่เป็นโปรแกรม F # แรกของฉัน หากฉันพลาดคุณสมบัติของภาษาโปรดแจ้งเตือนฉันเมื่อฉันยังเรียนรู้อยู่

นี่คือตัวอย่างอินพุตของฉัน

 . . . . . . . . . . . . . . . . . . . . . . . . .
 . . . . . . . . . . . . B . . . . . . . . . . . .
 . . . . . . . . . . . . . . . . . . . . . . . . .
 . . . . . . . . A . . . . . . . . . . . . . . . .
 . . . . . . . . . . . . . . . . . . . . . . . . .
 . . . . . . . . . . . . . . . . C . . . . . . . .
 . . . . . . . . . . . . . . . . . . . . . . . . .
 . . . . . . . . . . . . . . . . . . . G . . . . .
 . . . . . . . D . . . . . . . . . . . . . . . . .
 . . . . . . . . F . . . . . . . . . . . . . . . .
 . . . . . . . E . . . . . . . . . . . . . . . . .
 . . . . . . . . . . . . . . . . . . . . . . . . .
 . . . . . . . . . . . . . . . . . . . . . . . . .
 . . . . . . . . . . . . . . . . . . . . . . . . .

นี่คือผลลัพธ์

 . . . . . . . . . a b . . . . . . . b g . . . . .
 . . . . . . . . . a b . B . . . b b b g . . . . .
 . . . . . . . . . . a b . . . b c c c g . . . . .
 . . . . . . . . A . . a b . b c . . c g . . . . .
 . . . . . . . . . . . a b b c . . . c g . . . . .
 a a a a a a a a . . . a b c . . C . c g . . . . .
 d d d d d d d d a a a a b c . . . c g . . . . . .
 . . . . . . . . d d d d b c . . c g . G . . . . .
 . . . . . . . D d d d d d c . . c g . . . . . . .
 d d d d d d d d f f f f f f c . c g . . . . . . .
 e e e e e e e e e e e e e e c . c g . . . . . . .
 . . . . . . . . . . . . . e c . c g . . . . . . .
 . . . . . . . . . . . . . e c . c g . . . . . . .
 . . . . . . . . . . . . . e c . c g . . . . . . .

นี่คือรหัส สนุก.

// The first thing that we need is some data. 
let originalData = [
     "........................."
     "............B............" 
     "........................." 
     "........A................" 
     "........................." 
     "................C........"          
     "........................." 
     "...................G....." 
     ".......D................." 
     "........F................"           
     ".......E................."          
     "........................."
     "........................."
     "........................."
     ]

ตอนนี้เราจำเป็นต้องแปลงข้อมูลนั้นเป็นอาร์เรย์สองมิติเพื่อให้เราสามารถเข้าถึงได้ผ่านตัวสร้างดัชนี

let dataMatrix = 
    originalData
    |> List.map (fun st -> st.ToCharArray())
    |> List.toArray

// We are going to need a concept of ownership for each
// cell. 
type Owned = 
    | Unclaimed
    | Owner of char
    | Claimed of char
    | Boundary of char

ให้เราสร้างเมทริกซ์ที่แสดงถึงความเป็นเจ้าของของแต่ละเซลล์

let claims =
    dataMatrix
    |> Array.map (fun row ->
        row
        |> Array.map (function
            | '.' -> Owned.Unclaimed
            | ch -> Owned.Owner(ch))
        )

ให้เรามีวิธีอรรถประโยชน์เพื่อดูสิ่งที่เกิดขึ้น

let printIt () =
    printfn ""
    claims
    |> Array.iter (fun row ->
        row |> Array.iter (function
            | Owned.Claimed(ch) -> printf " ." 
            | Owned.Owner(ch) -> printf " %c" ch
            | Owned.Boundary(ch) -> printf " %c" ch
            | _ -> printf " ." )
        printfn "")            

ให้เราสร้างบันทึกเพื่อแสดงว่าตัวอักษรตัวใหญ่อยู่ที่ไหน

type CapitalLocation = { X:int; Y:int; Letter:char }

ตอนนี้เราต้องการค้นหาตัวพิมพ์ใหญ่ทั้งหมด

let capitals = 
    dataMatrix
    |> Array.mapi (fun y row -> 
        row 
        |> Array.mapi (fun x item -> 
            match item with
            | '.' -> None
            | _ -> Some({ X=x; Y=y; Letter=item }))
        |> Array.choose id
        |> Array.toList
        )
    |> Array.fold (fun acc item -> item @ acc) List.empty<CapitalLocation>
    |> List.sortBy (fun item -> item.Letter)

ขณะที่เราเคลื่อนที่เราต้องการแนวคิดเกี่ยวกับทิศทาง

type Direction =
    | Left = 0
    | Up = 1
    | Right = 2
    | Down = 3   

// Function gets the coordinates of the adjacent cell. 
let getCoordinates (x, y) direction =
    match direction with
    | Direction.Left -> x-1, y
    | Direction.Up -> x, y-1
    | Direction.Right -> x+1, y
    | Direction.Down -> x, y+1
    | _ -> (-1,-1) // TODO: Figure out how to best throw an error here. 

ขณะที่เราเคลื่อนที่เราจะต้องรู้ขนาด สิ่งนี้จะช่วยให้เราตรวจสอบว่าเราย้ายออกนอกขอบเขตหรือไม่

type Size = { Width:int; Height: int }    

// Get the size of the matrix. 
let size = {Width=originalData.Head.Length; Height=originalData.Length}

รูปแบบที่ใช้งานอยู่: ตรงกับเกณฑ์ของเซลล์ที่ระบุ

let (|OutOfBounds|UnclaimedCell|Claimed|Boundary|) (x,y) =
    match (x,y) with 
    | _,_ when x < 0 || y < 0 -> OutOfBounds
    | _,_ when x >= size.Width || y >= size.Height -> OutOfBounds
    | _ ->                     
        match claims.[y].[x] with
        | Owned.Unclaimed -> UnclaimedCell(x,y)
        | Owned.Claimed(ch) -> Claimed(x,y,ch)
        | Owned.Boundary(ch) -> Boundary(x,y,ch)
        | Owned.Owner(ch) -> Claimed(x,y,ch)

ตอนนี้เรากำลังลงภาษีทองเหลือง สิ่งนี้อ้างว่าเซลล์!

let claimCell letter (x, y) =         
    // Side effect: Change the value of the cell
    (claims.[y].[x] <- Owned.Claimed (System.Char.ToLower letter)) |> ignore

ใช้รูปแบบที่ใช้งานอยู่รับสิทธิ์เซลล์นี้หากไม่มีการอ้างสิทธิ์และส่งคืนพิกัดของเซลล์ที่อยู่ติดกัน

let claimAndReturnAdjacentCells (letter, coordinates, direction) =
    match coordinates with 
    | UnclaimedCell (x,y) ->         
        // Claim it and return the Owned object.
        claimCell letter coordinates // meaningful side effect
        // use Direction as int to allow math to be performed. 
        let directionInt = int direction;            
        Some(
            // [counter-clockwise; forward; clockwise]
            [(directionInt+3)%4; directionInt; (directionInt+1)%4]                 
            |> List.map enum<Direction>                 
            |> List.map (fun newDirection -> 
                (
                    letter, 
                    getCoordinates coordinates newDirection, 
                    newDirection
                ))
        )
    | Claimed(cx,cy,cch) when cch <> System.Char.ToLower letter-> 
        // If we find a "Claimed" element that is not our letter, we have 
        // hit a boundary. Change "Claimed" to "Boundary" and return the 
        // element that led us to evaluating this element. It is also a 
        // boundary. 
        (claims.[cy].[cx] <- Owned.Boundary (System.Char.ToLower cch)) |> ignore
        let reverseDirection = enum<Direction>(((int direction)+2)%4)
        Some[(
            cch,
            getCoordinates (cx, cy) reverseDirection,
            reverseDirection
        )]
    | _ -> None

เรากำลังเริ่มสร้างรายการของถุงข้อมูลนี้ให้เราสร้างประเภทเพื่อทำให้สิ่งต่าง ๆ ชัดเจนยิ่งขึ้น

type CellClaimCriteria = (char * (int * int) * Direction)

รับรายการเกณฑ์สำหรับการอ้างสิทธิ์เซลล์เราจะวนซ้ำรายการที่ส่งคืนเซลล์ถัดไปเพื่ออ้างสิทธิ์และรับเงินคืนในรายการนั้น

let rec claimCells (items:CellClaimCriteria list) =
    items
    |> List.fold (fun acc item ->
        let results = claimAndReturnAdjacentCells item 
        if Option.isSome(results) 
        then (acc @ Option.get results) 
        else acc
        ) List.empty<CellClaimCriteria> 
    |> (fun l ->            
        match l with
        | [] -> []
        | _ -> claimCells l)

สำหรับแต่ละทุนสร้างเกณฑ์การอ้างสิทธิ์ในแต่ละทิศทางจากนั้นเรียกร้องเซลล์เหล่านั้นซ้ำ ๆ

let claimCellsFromCapitalsOut ()=
    capitals
    |> List.fold (fun acc capital ->
        let getCoordinates = getCoordinates (capital.X, capital.Y)
        [Direction.Left; Direction.Up; Direction.Right; Direction.Down]
        |> List.map (fun direction ->                
            (
                capital.Letter, 
                getCoordinates direction, 
                direction
            ))
        |> (fun items -> acc @ items)) List.empty<CellClaimCriteria>
    |> claimCells

ทุกโปรแกรมต้องการหลัก

[<EntryPoint>]
let main args = 
    printIt()
    claimCellsFromCapitalsOut()
    printIt()
    0

ทำได้ดีมากสำหรับการแก้ปัญหาการทำงานในภาษาที่คุณไม่คุ้นเคย อย่างไรก็ตามคุณพลาดขั้นตอนสุดท้าย: นี่คือโค้ดกอล์ฟซึ่งหมายความว่าเป้าหมายคือการเขียนโปรแกรมที่สั้นที่สุดที่เป็นไปได้: ตัวระบุอักขระเดียวเท่านั้นช่องว่างที่จำเป็นต้องรวบรวมอย่างเคร่งครัดเป็นต้น
Peter Taylor

3
PeterTaylor คุณพูดถูก ฉันคิดถึงสิ่งนั้น ไซต์นี้ต้องการ "ปริศนาการเขียนโปรแกรม" มากกว่าและน้อยกว่า "รหัสกอล์ฟ"
ฟิลลิปก็อตต์ Givens
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.