สร้างภาษาการเขียนโปรแกรมที่ดูเหมือนจะใช้ไม่ได้


85

หัวข้อความท้าทายโจรอยู่ที่นี่

ความท้าทายของตำรวจ: ออกแบบภาษาการเขียนโปรแกรมที่ดูเหมือนจะใช้ไม่ได้กับการเขียนโปรแกรม แต่ยอมรับการคำนวณ (หรืออย่างน้อยก็ทำภารกิจให้สำเร็จ) ผ่านกลไกที่ไม่ชัดเจน

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

นี่คือการประกวดความนิยม เป้าหมายของตำรวจคือการได้รับคะแนนเสียงมากที่สุดเท่าที่จะเป็นไปได้ในขณะที่อยู่รอดได้ 8 วันหลังจากโพสต์ล่ามโดยไม่แตก ด้วยเหตุนี้แนวทางปฏิบัติดังต่อไปนี้ควรช่วย:

  • อธิบายความหมายของภาษาของคุณอย่างแม่นยำ
  • การเขียนโค้ดที่อ่านได้

กลวิธีต่อไปนี้เป็นกำลังใจอย่างยิ่ง:

  • การใช้การเข้ารหัสแฮชหรือวิธีการเข้ารหัสอื่น ๆ หากคุณเห็นภาษาที่ใช้การเข้ารหัส RSA หรือปฏิเสธที่จะรันโปรแกรมเว้นแต่ว่าแฮช SHA-3 นั้นมีค่าเท่ากับ 0x1936206392306 โปรดอย่าลังเลที่จะลงคะแนน

ความท้าทายของโจร: เขียนโปรแกรมที่ค้นหาเลขจำนวนเต็มอันดับสามในอินพุตเมื่อรันในล่ามของตำรวจ

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

กฎ I / O

  • ล่ามควรใช้ชื่อไฟล์บนบรรทัดคำสั่งสำหรับโปรแกรมและใช้อินพุตและเอาต์พุตมาตรฐานเมื่อเรียกใช้
  • การป้อนข้อมูลจะได้รับใน unary และประกอบด้วยอักขระเท่านั้น0และ1(48 และ 49 ใน ASCII) จำนวนNจะถูกเข้ารหัสเป็นN ตามด้วย1s 0มีเพิ่มเติม0ก่อนสิ้นสุดไฟล์ ตัวอย่าง: สำหรับลำดับ (3, 3, 1, 14), 11101110101111111111111100เข้าเป็น
  • อินพุตรับประกันว่ามีอย่างน้อย 3 ตัวเลข ตัวเลขทั้งหมดเป็นจำนวนเต็มบวก
  • ผลลัพธ์จะถูกตัดสินโดยจำนวน1s ที่พิมพ์ก่อนโปรแกรมหยุด อักขระอื่น ๆ จะถูกละเว้น

ในตัวอย่างต่อไปนี้บรรทัดแรกคืออินพุตในรูปแบบทศนิยม อันที่สองคืออินพุตโปรแกรมจริง ตัวอย่างที่สามคือเอาต์พุตตัวอย่าง

1, 1, 3
101011100
1

15, 18, 7, 2, 15, 12, 3, 1, 7, 17, 2, 13, 6, 8, 17, 7, 15, 11, 17, 2
111111111111111011111111111111111101111111011011111111111111101111111111110111010111111101111111111111111101101111111111111011111101111111101111111111111111101111111011111111111111101111111111101111111111111111101100
111111,ir23j11111111111u

247, 367, 863, 773, 808, 614, 2
<omitted>
<contains 773 1's>

กฎที่น่าเบื่อสำหรับคำตอบของตำรวจ:

  • เพื่อป้องกันความปลอดภัยผ่านความสับสนผู้แปลควรเขียนด้วยภาษาใน 100 อันดับแรกของดัชนี TIOBEนี้และมีผู้แปล / ล่ามที่พร้อมใช้งานฟรี
  • ล่ามจะต้องไม่แปลภาษาที่ตีพิมพ์ก่อนการท้าทายนี้
  • ล่ามควรพอดีกับโพสต์ของคุณและไม่ได้โฮสต์ภายนอก
  • ล่ามควรกำหนดไว้ล่วงหน้า
  • ล่ามควรพกพาและปฏิบัติตามมาตรฐานของภาษาของตัวเอง อย่าใช้พฤติกรรมหรือข้อบกพร่องที่ไม่ได้กำหนด
  • หากโปรแกรมโซลูชันยาวเกินไปที่จะตอบคำถามคุณต้องโพสต์โปรแกรมที่สร้างขึ้น
  • โปรแกรมโซลูชันควรประกอบด้วยเฉพาะ ASCII ที่พิมพ์ได้และบรรทัดใหม่
  • คุณต้องรันโปรแกรมโซลูชันของคุณในเวลาน้อยกว่า 1 ชั่วโมงในคอมพิวเตอร์ของคุณสำหรับแต่ละตัวอย่างอินพุตด้านบน
  • โปรแกรมควรทำงานสำหรับจำนวนเต็มใด ๆ ที่น้อยกว่า 10 6และจำนวนเต็มใด ๆ ที่น้อยกว่า 10 6 (ไม่จำเป็นต้องใช้ภายในหนึ่งชั่วโมง) โดยมีเงื่อนไขว่าความยาวอินพุตรวมน้อยกว่า 10 9 9
  • เพื่อความปลอดภัยตำรวจจะต้องแก้ไขโปรแกรมโซลูชันเป็นคำตอบหลังจากผ่านไป 8 วัน

เกณฑ์การให้คะแนน

ตำรวจที่ปลอดภัยด้วยคะแนนสูงสุดและคะแนนบวกชนะคำถามนี้


คุณไม่ได้ระบุอย่างชัดเจน แต่ฉันคิดว่าตำรวจต้องเขียนและโพสต์ล่ามในคำตอบจริง ๆ หรือไม่
บลู

@muddyfish ใช่ล่ามควรเป็นเนื้อหาของคำตอบของตำรวจ
feersum

1
@ kirbyfan64sos เอาต์พุตจะถูกตัดสินโดยจำนวน 1s ที่พิมพ์ก่อนที่โปรแกรมจะหยุดทำงาน อักขระอื่น ๆ จะถูกละเว้น
mbomb007


20
ฉันเบื่อหน่ายกับความท้าทายนี้ ฉันสร้างภาษาโปรแกรมและจากนั้นใช้เวลาหลายชั่วโมงในการเขียนโปรแกรมงานเพื่อดูว่าภาษายังสามารถทำงานเพียงเพื่อจะพบว่ามันจริงก็ใช้ไม่ได้
Sanchises

คำตอบ:


24

การเปลี่ยน (ปลอดภัย)

ShapeScript

ShapeScript เป็นภาษาการเขียนโปรแกรมที่เกิดขึ้นตามธรรมชาติ Shape shifters (หรือChangelingsตามที่ต้องการเรียก) สามารถเปลี่ยนเป็นชุดคำสั่งที่อนุญาตให้ประมวลผลข้อมูล

ShapeScript เป็นภาษาสแต็กที่มีไวยากรณ์ค่อนข้างง่าย ไม่น่าแปลกใจที่ส่วนใหญ่ของมันสร้างการจัดการกับการเปลี่ยนแปลงรูปร่างของสตริง มันถูกตีความตัวละครโดยตัวละครดังต่อไปนี้:

  • 'และ"เริ่มต้นตัวอักษรสตริง

    จนกว่าจะพบคำพูดที่ตรงกันในซอร์สโค้ดตัวละครทั้งหมดระหว่างคำพูดที่ตรงกันเหล่านี้จะถูกรวบรวมในสตริงซึ่งจะถูกผลักลงบนสแต็ก

  • 0เพื่อ9กดจำนวนเต็ม0ถึง9บนสแต็ก โปรดทราบว่า10ผลักจำนวนเต็มสองจำนวน

  • ! ดึงสตริงออกจากสแต็กและพยายามประเมินเป็น ShapeScript

  • ? ดึงเลขจำนวนเต็มจากสแต็กและส่งสำเนาของรายการสแต็กที่ดัชนีนั้น

    ดัชนี 0 สอดคล้องกับรายการสแต็คสูงสุด (LIFO) และดัชนี -1 ถึงล่างสุด

  • _ pops iterable จากสแต็กและเพิ่มความยาว

  • @ ดึงรายการสองรายการออกจากสแต็กและผลักรายการในลำดับที่กลับกัน

  • $จะปรากฏสองสายจากสแต็กและแยกหนึ่งส่วนล่างสุดที่เกิดขึ้นของชั้นบนสุด รายการผลลัพธ์ถูกส่งคืน

  • &ดึงสตริง (บนสุด) และ iterable จากสแต็กและรวม iterable โดยใช้สตริงเป็นตัวคั่น สตริงผลลัพธ์ถูกส่งคืน

  • หาก ShapeScript ถูกนำมาใช้บนโลกของเราตั้งแต่งูเหลือมเป็นภูติญาติสนิทบนโลกตัวละครอื่น ๆ ทั้งหมดc pop สองรายการXและY (บนสุด) x c yจากกองและพยายามที่จะประเมินรหัสหลาม

    ตัวอย่างเช่นลำดับของอักขระ23+จะประเมิน2+3ในขณะที่ลำดับของอักขระ"one"3*จะประเมิน'one'*3และลำดับของอักขระ1''Aจะประเมิน1A''จะประเมิน

    ในกรณีสุดท้ายเนื่องจากผลลัพธ์ไม่ถูกต้อง Python การเปลี่ยนแปลงจะบ่นว่ารูปร่างปัจจุบันของเขาไม่ได้เปิดใช้งาน (ข้อผิดพลาดทางไวยากรณ์) เนื่องจากไม่ใช่ ShapeScript ที่ถูกต้อง

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

รูปร่างขยับ

ในสภาพตามธรรมชาติของพวกเขาสับเปลี่ยนไม่ได้ใช้รูปร่างของ ShapeScript อย่างไรก็ตามบางส่วนสามารถแปลงเป็นซอร์สโค้ดเดียวที่เป็นไปได้

การเปลี่ยนแปลงที่มีสิทธิ์ทั้งหมดมีรูปแบบธรรมชาติดังต่อไปนี้:

  • ทุกบรรทัดต้องมีจำนวนอักขระเท่ากัน

  • บรรทัดทั้งหมดต้องประกอบด้วยอักขระ ASCII ที่พิมพ์ได้แล้วตามด้วยบรรทัดป้อนบรรทัดเดียว

  • จำนวนบรรทัดต้องตรงกับจำนวนอักขระที่พิมพ์ได้ต่อบรรทัด

ตัวอย่างเช่นลำดับไบต์ ab\ncd\nเป็นการเปลี่ยนแปลงที่มีสิทธิ์

ในความพยายามที่จะเปลี่ยนเป็น ShapeScript การสับเปลี่ยนผ่านการแปลงต่อไปนี้:

  • เริ่มแรกไม่มีซอร์สโค้ด

  • สำหรับแต่ละบรรทัดมีสิ่งต่อไปนี้เกิดขึ้น:

    • ตัวสะสมของการเปลี่ยนแปลงตั้งค่าเป็นศูนย์

    • สำหรับอักขระcแต่ละบรรทัด (รวมถึง linefeed ต่อท้าย) จุดโค้ดของcคือ XORed กับตัวสะสมหารด้วย 2 และอักขระ Unicode ที่สอดคล้องกับจุดโค้ดผลลัพธ์จะถูกผนวกเข้ากับซอร์สโค้ด

      หลังจากนั้นความแตกต่างระหว่างจุดรหัสของcและจุดรหัสของช่องว่าง (32) จะถูกเพิ่มเข้าไปในตัวสะสม

หากส่วนใดส่วนหนึ่งข้างต้นล้มเหลวการเปลี่ยนแปลงจะบ่นว่ารูปร่างปัจจุบันไม่เป็นที่พอใจ

หลังจากประมวลผลทุกบรรทัดแล้วการเปลี่ยนแปลงของการเปลี่ยนแปลงเป็น ShapeScript หวังว่าจะเสร็จสมบูรณ์และโค้ดผลลัพธ์จะถูกดำเนินการ

โซลูชัน (ShapeScript)

"0"@"0"$"0"2*&"0"@+0?_'@1?"0"$_8>"1"*+@1?"0"+$""&'*!#

ShapeScript กลายเป็นว่าใช้งานได้จริง ก็ยังสามารถดำเนินการทดสอบ primality ( หลักฐาน ) และเป็นไปตามข้อกำหนดของภาษาโปรแกรม

ฉันได้เผยแพร่ShapeScriptอีกครั้งบน GitHubด้วยไวยากรณ์ที่ปรับเปลี่ยนเล็กน้อยและ I / O ที่ดีขึ้น

รหัสทำสิ่งต่อไปนี้:

"0"@    Push "0" (A) and swap it with the input string (S).
"0"$    Split S at 0's.
"0"2*   Push "00".
&       Join the split S, using "00" as separator.
"0"@+   Prepend "0" to S.
        The input has been transformed into
        "0<run of 1's>000<run of 1's>0...0<run of 1's>0000".
0?_     Push a copy and compute its length (L).
'       Push a string that, when evaluated, does the following:
  @1?     Swap A on top of S, and push a copy of S.
  "0"$    Split the copy of S at 0's.
  _8>     Get the length of the resulting array and compare it with 8.
          If this returns True, there are more than eight chunks, so there are
          more then seven 0's. With two 0's surrounding each run of 1's and
          three extra 0's at the end, this means that there still are three or
          more runs of 1's in the string.
  "1"*    Push "1" if '>' returned True and "" if it returned False.
  +       Append "1" or "" to A.
  @1?     Swap S on top of A, and push a copy of A.
  "0"+    Append "0" to the copy of A.
  $       Split S at occurrences of A+"0".
  ""&     Flatten the resulting array of strings.
'       This removes all occurrences of "010" in the first iteration, all
        occurrences of "0110" in the second, etc., until there are less than
        three runs of 1's left in S. At this point, A is no longer updated,
        and the code inside the string becomes a noop.
*!      Repeat the code string L times and evaluate.
#       Drop S, leaving only A on the stack.

โซลูชัน (เปลี่ยน)

"1+-.......................
""B1.......................
"" 2)+7....................
"" 2)=<....................
""( $86=...................
""B8=......................
""247......................
""]`b......................
""B1.......................
""%D1=.....................
""%500=....................
""%&74?....................
""%&#.2....................
""%[bdG....................
""%D1=.....................
""%<5?.....................
""%:6>.....................
""%&65?....................
""%&-%7>...................
""%D1=.....................
""%500=....................
""%&74?....................
""%&,)5>...................
""%&%,79...................
"" )$?/=...................
""),-9=....................
""# !......................

เช่นเดียวกับโปรแกรมการเปลี่ยนแปลงทั้งหมดรหัสนี้มีการป้อนบรรทัดต่อท้าย

ShapeScript จะมีข้อผิดพลาดทันทีในตัวละครใด ๆ ที่ไม่เข้าใจ แต่เราสามารถกดสตริงตามอำเภอใจเป็นฟิลเลอร์และ pop พวกเขาในภายหลัง นี้ช่วยให้เราสามารถใส่เพียงเล็กน้อยของรหัสในแต่ละบรรทัด (ที่จุดเริ่มต้นที่สะสมที่มีขนาดเล็ก) "ตามด้วยการเปิด หากเราเริ่มต้นบรรทัดถัดไปด้วย"#เราปิดและป๊อปสตริงโดยไม่ส่งผลกระทบต่อโค้ดจริง

นอกจากนี้เราต้องฝ่าฟันอุปสรรคเล็ก ๆ น้อย ๆ สามอย่าง:

  • สตริงยาวในรหัส ShapeScript เป็นโทเค็นเดียวและเราจะไม่สามารถใส่ลงในบรรทัดได้

    เราจะผลักดันสายนี้ในชิ้น ( '@', '1?'ฯลฯ ) ซึ่งเราจะเชื่อมต่อมา

  • จุดรหัสของ_ค่อนข้างสูงและการผลัก'_'จะเป็นปัญหา

    อย่างไรก็ตามเราจะสามารถผลักดัน'_@'ได้อย่างง่ายดายตามด้วยอีกอัน'@'เพื่อยกเลิกการแลกเปลี่ยน

รหัส ShapeScript การเปลี่ยนแปลงของเราจะสร้างหน้าตาแบบนี้1 :

"0""
"#@"
"#"0"$"
"#"0"2"
"#*&"0""
"#@+"
"#0?"
"#_@"
"#@"
"#'@'"
"#'1?'"
"#'"0'"
"#'"$'"
"#'_@'"
"#'@'"
"#'8'"
"#'>'"
"#'"1'"
"#'"*+'"
"#'@'"
"#'1?'"
"#'"0'"
"#'"+$'"
"#'""&'"
"#"+"77"
"#+*!*"
"#!#"

ฉันพบรหัสการเปลี่ยนแปลงโดยการเรียกใช้รหัส ShapeScript ด้านบนผ่านตัวแปลงนี้ 2

ล่าม (Python 3)

#!/usr/bin/env python3

import fileinput

def error(code):
  print("This shape is " + ["unpleasant", "unpurposed", "inadequate"][code - 1] + ".")
  exit(code)

def interpret(code):
  global stack
  stringing = 0
  for char in code:
    quote = (char == "'") + 2 * (char == '"')
    if quote or stringing:
      if not stringing:
        string = ""
        stringing = quote
      elif stringing == quote:
        stack.append(string)
        stringing = 0
      else:
        string += char
    elif char in "0123456789":
      stack.append(int(char))
    else:
      x = stack.pop()
      if char == '!':
        interpret(x)
      else:
        if char == '?':
          y = stack[~x]
        elif char == "_":
          y = len(x)
        else:
          y = stack.pop()
          if char == '@':
            stack.append(x)
          elif char == '$':
            y = y.split(x)
          elif char == '&':
            y = x.join(map(str, y))
          else:
            try:
              y = eval(repr(y) + char + repr(x))
            except SyntaxError:
              error(2)
        stack.append(y)

source = ""
lengths = []

for line in fileinput.input():
  if not line or sorted(line)[:2][-1] < " " or max(line) > "~":
    error(1)
  lengths.append(len(line))
  accumulator = 0
  for char in line:
    value = ord(char)
    try:
      source += chr(value ^ (accumulator >> 1))
    except:
      error(1)
    accumulator += value - 32

lengths.append(len(lengths) + 1)

if min(lengths) != max(lengths):
  error(1)

stack = ""

for line in fileinput.input("-"):
  stack += line

stack = [stack]

try:
  interpret(source)
except:
  error(3)

print("".join(map(str, stack)))

1 แต่ละบรรทัดจะถูกเติมเต็มด้วยขยะแบบสุ่มตามจำนวนบรรทัดและบรรทัดฟีดไม่ได้มีอยู่จริง
2 ตัวเลขที่ด้านล่างแสดงถึงจุดรหัสต่ำสุดและสูงสุดในรหัสการเปลี่ยนแปลงซึ่งจะต้องอยู่ระหว่าง 32 ถึง 126


1
-1 สำหรับการใช้งานของ xor / transformations การแปลงการเปลี่ยนเป็น ShapeScript ดูเหมือนจะเป็นการเข้ารหัสสำหรับฉัน
MegaTom

10
@ MegaTom คุณสามารถลงคะแนนได้ตามที่เห็นสมควร แต่คำถามที่ขมวดคิ้วจากการเข้ารหัสเพราะใช้คีย์ซึ่งเป็นค่าคงที่รู้จักเฉพาะตำรวจที่ทำให้โจรเสียเปรียบอย่างมาก การแปลงเป็นunkeyedเปลี่ยนแปลง
เดนนิส

1
ShapeScript 67 0"#002?'+'&'0'$'0?2?-@2?>*+00'&!++'1'*'0'+@1?$0?''&@_2-2?*@+@"3*!@#ไบต์: แม้ว่าฉันจะยอมแพ้ในการตามหาการเปลี่ยนแปลงก็ตาม แม้จะสลับกับข้อความที่ไร้ประโยชน์ส่วนใหญ่ฉันก็ยังไม่สามารถรับมากกว่า 20 ไบต์ได้
โม่

2
@ MegaTom จริง ๆ แล้วฉันผิดหวังโดยวิธีแก้ปัญหาที่กำหนด ฉันคาดหวังสิ่งที่ฉลาดกว่ารหัสไร้ประโยชน์ 92.9%
โม่

2
@primo มันต้องใช้เวลาอีกเล็กน้อย แต่ฉันพบว่าการเปลี่ยนแปลงนี้ทำงานร่วมกับ Python 2 ได้เช่นกัน ผมไม่ทราบว่าวิธีการที่ชาญฉลาดคำตอบของฉันมี แต่แผนของฉันโพสต์ของตำรวจที่มีช่องโหว่ที่ได้มีการพบการแตกมันดูเหมือนว่าจะได้ทำงาน
เดนนิส

30

สุ่ม (เขียนด้วย C ++) แตก!โดย Martin

แก้ไข Martin แตกออก เพื่อดูวิธีการแก้ปัญหาของเขาคลิกที่ลิงค์ เพิ่มโซลูชันของฉันแล้ว

แก้ไข คำสั่งคงที่print-dเพื่อให้สามารถจัดการกับทั้งรีจิสเตอร์และสแต็ก เนื่องจากนี่เป็นคำสั่งการดีบักที่ไม่ได้รับอนุญาตในการแก้ปัญหาจึงไม่ควรส่งผลกระทบต่อทุกคนที่ใช้ล่ามรุ่นก่อนหน้า

ฉันยังใหม่กับสิ่งนี้ดังนั้นหากมีสิ่งผิดปกติกับคำตอบหรือล่ามของฉันโปรดแจ้งให้เราทราบ โปรดขอคำอธิบายหากสิ่งที่ไม่ชัดเจน

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

-> พื้นฐาน:

มี 24 stack1, ... stack24กองมีเราเรียกพวกเขา สแต็คเหล่านี้อาศัยอยู่ในรายการ ที่จุดเริ่มต้นของโปรแกรมใด ๆ สแต็คเหล่านี้มีศูนย์ผลักและพวกเขาเริ่มในสถานที่ที่เหมาะสมของพวกเขาคือสแต็คฉันในตำแหน่งที่ithในรายการ (โปรดทราบว่าเราจะจัดทำดัชนีเริ่มต้นจาก 1 ซึ่งแตกต่างจาก C ++) ในระหว่างหลักสูตรของโปรแกรมคำสั่งของสแต็คภายในรายการจะเปลี่ยน นี่เป็นสิ่งสำคัญสำหรับเหตุผลที่จะอธิบายเมื่อฉันพูดถึงคำสั่ง

มีการลงทะเบียน 5 รายการสำหรับการใช้งาน พวกเขาจะถูกตั้งชื่อAlberto, Gertrude, Hans, ,Leopold ShabbySamแต่ละสิ่งเหล่านี้ถูกตั้งค่าเป็นศูนย์ที่จุดเริ่มต้นของโปรแกรม

ดังนั้นเมื่อเริ่มโปรแกรมใด ๆ มี 24 กองแต่ละคนมีหมายเลขที่ตรงกับดัชนีในรายการสแต็ก สแต็คทุกอันจะมีหนึ่งศูนย์อยู่ด้านบน การลงทะเบียนทั้งห้ารายการจะเริ่มต้นเป็นศูนย์

-> คำสั่งและไวยากรณ์ :

มี 13 คำสั่ง (คำสั่งการดีบัก +1) ที่มีอยู่ใน Shuffle พวกเขามีดังนี้

  • cinpushคำสั่งนี้ไม่มีข้อโต้แย้ง มันรออินพุตบรรทัดคำสั่งในรูปแบบที่อธิบายไว้ในคำถาม (อินพุตอื่นจะนำไปสู่ผลลัพธ์ที่ไม่ระบุ / ไม่ได้กำหนด) จากนั้นจะแยกสายป้อนเข้าไปในจำนวนเต็มเช่น->101011100 1,1,3สำหรับแต่ละอินพุตที่ได้รับจะทำสิ่งต่อไปนี้: (1)อนุญาตรายการของสแต็คตามค่า ให้ค่าจำนวนเต็มในคำถามจะเรียกว่า หากน้อยกว่า 10 มันไม่เปลี่ยนแปลงยู หากคือระหว่างวันที่ 9 และ 30 (noninclusive) มันไม่เปลี่ยนแปลงd มิฉะนั้นจะไม่เปลี่ยนแปลงR (2)จากนั้นกดaบนสแต็กซึ่งเป็นอันดับแรกในรายการ โปรดทราบว่าฉันไม่ได้หมายถึงstack1(แม้ว่ามันอาจเป็นกรณีstack1แรกในรายการ) การเรียงสับเปลี่ยนมีการกำหนดไว้ด้านล่าง เนื่องจากcinpushเป็นวิธีเดียวในการรับอินพุตของผู้ใช้จึงต้องปรากฏในโซลูชันใด ๆ
  • mov value registermovคำสั่งเป็นพื้นการกำหนดตัวแปร ก็จะระบุไปvalue สามารถมีหลายรูปแบบ: มันสามารถ(1)จำนวนเต็มเช่น(2)ชื่อของการลงทะเบียนที่แตกต่างกันเช่น(3)ดัชนีของสแต็กตามด้วย 's' เช่นregistervalue47 Hans 4sเช่น โปรดทราบว่านี่เป็นดัชนีในรายการไม่ใช่จำนวนของสแต็ก ด้วยเหตุนี้จำนวนไม่ควรเกิน 24

    movตัวอย่างบางส่วน:

    mov 4s Hans 
    mov Hans ShabbySam
    mov 9999 Gertrude
    
  • movfs index registerย่อมาจาก 'ย้ายจากสแต็ค' มันคล้ายกับmovคำสั่ง มีอยู่เพื่อให้คุณสามารถเข้าถึงสแต็กที่จัดทำดัชนีโดยการลงทะเบียน ตัวอย่างเช่นถ้าก่อนหน้านี้คุณฮันส์ตั้งเท่ากับ 4 ( mov 4 Hans) จากนั้นคุณอาจจะใช้movfs Hans Gertrudeการตั้งเกอร์ทรูดเท่ากับด้านบนของสแต็ค 4. movประเภทของพฤติกรรมนี้ไม่สามารถเข้าถึงได้เพียงแค่ใช้

  • inc register เพิ่มค่าลงทะเบียน 1
  • dec register ลดค่าลงทะเบียน 1
  • compg value value registerสิ่งนี้หมายถึง 'เปรียบเทียบมากขึ้น' มันตั้งค่าการลงทะเบียนเท่ากับค่าที่มากกว่าของสองค่าvalueสามารถเป็นจำนวนเต็มการลงทะเบียนหรือดัชนีสแต็กตามด้วย 's' ดังที่ได้กล่าวมาแล้ว
  • compl value value register 'เปรียบเทียบน้อยลง' เหมือนกับด้านบนยกเว้นใช้ค่าน้อยลง
  • gte value1 value2 registerตรวจสอบว่าvalue1 >= value2วางค่าบูลีน (เป็น 1 หรือ 0) ลงในนั้นหรือไม่registerนั้นหรือไม่
  • POP!! indexป็อปปิดด้านบนของสแต็กที่จัดทำดัชนีโดยindexในรายการสแต็ก
  • jmp labellabelกระโดดโดยไม่มีเงื่อนไขให้กับต้นสังกัด เป็นเวลาที่ดีที่จะพูดคุยเกี่ยวกับฉลาก ป้ายกำกับคือคำตามด้วย ':' ล่ามล่วงหน้าจะแยกวิเคราะห์ฉลากดังนั้นคุณจะสามารถข้ามไปข้างหน้าไปยังป้ายกำกับและย้อนกลับได้
  • jz value labelข้ามไปlabelถ้าvalueเป็นศูนย์
  • jnz value labelข้ามไปlabelถ้าvalueไม่ใช่ศูนย์

    ตัวอย่างของฉลากและการกระโดด:

    this_is_my_label:
         jmp this_is_my_label
    
    mov 10 Hans
    jnz Hans infinite_loop
    
    infinite_loop:
         jmp infinite_loop
    
  • "shuffle" permutationนี่คือคำสั่ง shuffle สิ่งนี้อนุญาตให้คุณเปลี่ยนแปลงรายการของสแต็ค มีสามพีชคณิตที่ถูกต้องที่สามารถนำมาใช้เป็นข้อโต้แย้งที่มีl, และfb

  • print registerวิธีนี้จะตรวจสอบว่าสแต็กทั้งหมดอยู่ในตำแหน่งเริ่มต้นหรือไม่เช่นสแต็คiอยู่ที่ดัชนีiในรายการสแต็ก หากเป็นกรณีนี้มันจะพิมพ์ค่าเป็นregisterunary มิฉะนั้นจะพิมพ์ข้อผิดพลาดที่น่ารังเกียจ อย่างที่คุณเห็นเพื่อเอาท์พุทอะไรกองทั้งหมดจะต้องอยู่ในตำแหน่งที่ถูกต้อง
  • done!สิ่งนี้บอกให้โปรแกรมเลิกโดยไม่มีข้อผิดพลาด หากโปรแกรมสิ้นสุดโดยไม่มีโปรแกรมdone!จะพิมพ์หมายเลขคอนโซลไปที่ด้านบนของแต่ละสแต็กตามด้วยหมายเลขของสแต็ก ลำดับที่สแต็กถูกพิมพ์คือลำดับที่ปรากฏในรายการสแต็ก หากสแต็กว่างเปล่ามันจะถูกละเว้น ลักษณะการทำงานนี้มีวัตถุประสงค์เพื่อการตรวจแก้จุดบกพร่องและอาจไม่สามารถใช้ในการแก้ปัญหา
  • print-d valueสิ่งนี้จะพิมพ์ค่าของสแต็กลงทะเบียนหรือจำนวนเต็มที่กำหนด (เพื่อเข้าถึงสแต็คiส่งผ่านisเป็นอาร์กิวเมนต์ตามที่อธิบายไว้ข้างต้น) นี่เป็นเครื่องมือแก้ไขข้อบกพร่องและไม่ได้เป็นส่วนหนึ่งของภาษาเนื่องจากไม่อนุญาตให้ใช้ในการแก้ปัญหา

-> นี่คือรหัสล่าม

การแยกวิเคราะห์ทั้งหมดเกิดขึ้นในฟังก์ชั่นหลัก ที่นี่คุณจะพบว่ามันแยกวิเคราะห์สำหรับคำสั่งเฉพาะ

#include<fstream>
#include<iostream>
#include<string>
#include<stack>
#include<cmath>

using namespace std;

class superStack: public stack<long> {
    private:
        int m_place;
    public:
        static int s_index;


        superStack() {
            m_place = s_index;
            s_index++;
        }

        int place() {
            return m_place;
        }
};
int superStack::s_index=1;

superStack  stack1,stack2,stack3,stack4,stack5,stack6,stack7,stack8,stack9,stack10,stack11, \
            stack12,stack13,stack14,stack15,stack16,stack17,stack18,stack19,stack20,stack21,stack22,stack23,stack24;


superStack* stackptrs[]=    { \
                        &stack1,&stack2,&stack3,&stack4,&stack5,&stack6,&stack7,&stack8,&stack9,&stack10,&stack11, \
                        &stack12,&stack13,&stack14,&stack15,&stack16,&stack17,&stack18,&stack19,&stack20,&stack21,&stack22,&stack23,&stack24 \
                        };


long Gertrude=0;
long Hans=0;
long Alberto=0;
long ShabbySam=0;
long Leopold=0;


void SWAP( int i, int j) {    // 0 < i,j < 25

    i--;
    j--;


    superStack* tempptr = stackptrs[i];
    stackptrs[i]=stackptrs[j];
    stackptrs[j] = tempptr;



}

void u() {
    int list[3][4] = {
                        {1,9,6,13},
                        {2,10,5,14},
                        {17,19,20,18},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void d() {
    int list[3][4] = {
                        {3,11,8,15},
                        {4,12,7,16},
                        {22,24,23,21},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void r() {
    int list[3][4] = {
                        {2,17,8,24},
                        {4,18,6,23},
                        {9,10,12,11},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void l() {
    int list[3][4] = {
                        {1,19,7,22},
                        {3,20,5,21},
                        {14,13,15,16},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void f() {
    int list[3][4] = {
                        {20,9,24,16},
                        {18,11,22,14},
                        {1,2,4,3},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}
void b() {
    int list[3][4] = {
                        {19,10,23,15},
                        {17,12,21,13},
                        {5,6,8,7},
                    };

    for(int i=0;i<3;i++) {
        for(int j=1;j<4;j++) {
            SWAP( list[i][0], list[i][j] );         
        }
    }
}

void splitpush(string input) {
    long value=0;

    for(long i=0;i<input.size();i++) {

        if(input[i]=='1'){
            value++;
        }
        else if(input[i]=='0' && value!=0 ) {
            if(value<10) {
                u();
            }
            else if (value<30) {
                d();

            }
            else {
                r();
            }
            (*stackptrs[0]).push(value);
            value=0;

        }
        else {
            break;
        }

    }

}

long strToInt(string str) { // IF STRING HAS NON DIGITS, YOU WILL GET GARBAGE, BUT NO ERROR
    long j=str.size()-1;
    long value = 0;
    for(long i=0;i<str.size();i++) {
        long x = str[i]-48;

        value+=x*floor( pow(10,j) );
        j--;
    }
    return value;
}

bool isEmpty(superStack stk) {
    if( stk.size()>0){return false; }
    else {return true;}

}    

long getValue(string str) {
    if(str=="ShabbySam") {
        return ShabbySam;
    }
    else if(str=="Hans") {
        return Hans;
    }
    else if(str=="Gertrude") {
        return Gertrude;
    }
    else if(str=="Alberto") {
        return Alberto;
    }   
    else if(str=="Leopold") {
        return Leopold;
    }
    else if(str[ str.size()-1 ]=='s'){
        str.pop_back();

        long index = strToInt(str)-1;

        if( !isEmpty( (*stackptrs[index]) ) ) {
            return (*stackptrs[index]).top();
        }
        else {
            cerr<<"Bad Expression or Empty Stack";


        }   
    }
    else {
        return strToInt(str);
    }

}

void printUnary(long i) {
    while(i>0) {
        cout<<1;
        i--;
    }
}

int main(int argc, char**argv) {

    if(argc<2){std::cerr<<"No input file given"; return 1;}
    ifstream inf(argv[1]);
    if(!inf){std::cerr<<"File open failed";return 1;}

    for(int i=0;i<24;i++) { 
        (*stackptrs[i]).push(0);         // Pre push a zero on every stack
    }

    string labels[20];
    unsigned labelPoints[20];
    int index=0;



    string str;
    while(inf) { //  parse for labels
        inf>>str;
        //cout<<inf.tellg()<<" ";
        if(inf) {
            if(str[str.size()-1]==':') {
                str.pop_back();
                bool alreadyExists = false;
                for(int i=0; i<index;i++){
                    if(labels[i] == str ) { alreadyExists=true;}
                }
                if(!alreadyExists) {
                    labels[index]=str;
                    labelPoints[index]= inf.tellg();
                    index++;
                }
            }

        }

    }
    inf.clear();
    inf.seekg(0,inf.beg);

    while(inf) { // parse for other commands 
        inf>>str;

        if(inf) {


            if(str=="cinpush") {
                string input;
                cin>>input;
                splitpush(input);
            }

            else if(str=="mov") {
                inf>>str;
                long value = getValue(str);

                inf>>str;
                if(str=="Gertrude"){Gertrude=value;}
                else if(str=="Hans"){Hans=value;}
                else if(str=="ShabbySam"){ShabbySam=value;}
                else if(str=="Alberto"){Alberto=value;}
                else if(str=="Leopold"){Leopold=value;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="movfs") {
                inf>>str;
                long index = getValue(str);
                if(!isEmpty( *stackptrs[index-1] )) {
                    inf>>str;
                    long value = (*stackptrs[index-1]).top();
                    if(str=="Gertrude"){Gertrude=value;}
                    else if(str=="Hans"){Hans=value;}
                    else if(str=="ShabbySam"){ShabbySam=value;}
                    else if(str=="Alberto"){Alberto=value;}
                    else if(str=="Leopold"){Leopold=value;}
                    else {cerr<<"Bad register name.";}
                }
                else {
                    cerr<<"Empty Stack";
                }



            }

            else if(str=="inc") {
                inf>>str;
                if(str=="Gertrude"){Gertrude++;}
                else if(str=="Hans"){Hans++;}
                else if(str=="ShabbySam"){ShabbySam++;}
                else if(str=="Alberto"){Alberto++;}
                else if(str=="Leopold"){Leopold++;}
                else {cerr<<"Bad register name. ";}
            }
            else if(str=="dec") {
                inf>>str;
                if(str=="Gertrude"){Gertrude--;}
                else if(str=="Hans"){Hans--;}
                else if(str=="ShabbySam"){ShabbySam--;}
                else if(str=="Alberto"){Alberto--;}
                else if(str=="Leopold"){Leopold--;}
                else {cerr<<"Bad register name. ";}
            }


            else if(str=="compg") {
                inf>>str;
                long value1 = getValue(str);
                inf>>str;
                long value2 = getValue(str);
                inf>>str;
                long larger;
                if(value1>value2){larger = value1;}
                else {larger = value2;}

                if(str=="Gertrude"){Gertrude=larger;}
                else if(str=="Hans"){Hans=larger;}
                else if(str=="ShabbySam"){ShabbySam=larger;}
                else if(str=="Alberto"){Alberto=larger;}
                else if(str=="Leopold"){Leopold=larger;}
                else {cerr<<"Bad register name. ";}

            }
            else if(str=="compl") {
                inf>>str;
                long value1 = getValue(str);
                inf>>str;
                long value2 = getValue(str);
                inf>>str;
                long larger; //LARGER IS REALLY SMALLER HERE
                if(value1>value2){larger = value2;}
                else {larger = value1;}

                if(str=="Gertrude"){Gertrude=larger;}
                else if(str=="Hans"){Hans=larger;}
                else if(str=="ShabbySam"){ShabbySam=larger;}
                else if(str=="Alberto"){Alberto=larger;}
                else if(str=="Leopold"){Leopold=larger;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="gte") {
                inf>>str;
                long value1= getValue(str);
                inf>>str;
                long value2= getValue(str);
                inf>>str;
                bool torf = value1 >= value2;

                if(str=="Gertrude"){Gertrude=torf;}
                else if(str=="Hans"){Hans=torf;}
                else if(str=="ShabbySam"){ShabbySam=torf;}
                else if(str=="Alberto"){Alberto=torf;}
                else if(str=="Leopold"){Leopold=torf;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="lte") {
                inf>>str;
                long value1= getValue(str);
                inf>>str;
                long value2= getValue(str);
                inf>>str;
                bool torf = value1 <= value2;

                if(str=="Gertrude"){Gertrude=torf;}
                else if(str=="Hans"){Hans=torf;}
                else if(str=="ShabbySam"){ShabbySam=torf;}
                else if(str=="Alberto"){Alberto=torf;}
                else if(str=="Leopold"){Leopold=torf;}
                else {cerr<<"Bad register name. ";}

            }

            else if(str=="POP!!") {
                inf>>str;
                long index = getValue(str);
                index--; //because we (C++ and this interpreter) index differently
                if(!isEmpty( *stackptrs[index] )) {
                    (*stackptrs[index]).pop();
                }
                else {cerr<<"Can't POP!! from empty stack";}

            }

            else if(str=="push"){cerr<<" You can't. ";}

            /*
            else if(str[str.size()-1]==':') {
                str.pop_back();
                bool alreadyExists = false;
                for(int i=0; i<index;i++){
                    if(labels[i] == str ) { alreadyExists=true;}
                }
                if(!alreadyExists) {
                    labels[index]=str;
                    labelPoints[index]= inf.tellg();
                    index++;
                }
            }*/

            else if(str=="jmp") {
                inf>>str;
                for(int i=0;i<index;i++) {
                    if( labels[i]==str) {
                        inf.seekg( labelPoints[i], ios::beg);
                    }
                }
            }
            else if(str=="jz") {
                inf>>str;
                long value = getValue(str);

                if(value==0) {
                    inf>>str;
                    for(int i=0;i<index;i++) {
                        if( labels[i]==str) {
                            inf.seekg( labelPoints[i], ios::beg);
                        }
                    }
                }
            }

            else if(str=="jnz") {
                inf>>str;
                long value = getValue(str);

                if(value!=0) {
                    inf>>str;
                    for(int i=0;i<index;i++) {
                        if( labels[i]==str) {
                            inf.seekg( labelPoints[i], ios::beg);
                        }
                    }
                }
            }

            else if(str== "\"shuffle\"") {
                inf>>str;
                if(str=="l"){ l(); }
                else if(str=="f"){ f(); }
                else if(str=="b"){ b(); }
                else {cerr<<"Bad shuffle parameter";}

            }

            else if(str=="print") {

                for(int i=0;i<24;i++) {

                    if( (i+1) != (*stackptrs[i]).place() ) {
                        cerr<< "Sorry, your stacks are in the wrong place! You can't print unless you put them back! Exiting. ";
                        return 1;
                    }

                }
                inf>>str;
                if(str=="Gertrude"){printUnary(Gertrude);}
                else if(str=="Hans"){printUnary(Hans);}
                else if(str=="ShabbySam"){printUnary(ShabbySam);}
                else if(str=="Alberto"){printUnary(Alberto);}
                else if(str=="Leopold"){printUnary(Leopold);}
                else {cerr<<"Bad register name. ";}


            }

            else if(str=="done!") {return 0;}

            else if(str=="print-d" ){
                inf>>str;
                long value = getValue(str);
                cout<<str;
              }
        }

    }







    /*for(int i=1;i<25;i++) {
        (*(stackptrs[i-1])).push(i);
    }

    u();d();r();l();f();b();
    */

    cout<<"\n";
    for(int i=1;i<25;i++) {
        if( (*(stackptrs[i-1])).size()>0 ) {
            cout<<(*(stackptrs[i-1])).top()<<" "<<(*(stackptrs[i-1])).place()<<"\n";
            (*(stackptrs[i-1])).pop();
        }
    }
    /*
    for (int i=0;i<index;i++) {
        cout<<labels[i]<<": "<<labelPoints[i]<<"\n";
    }*/

    return 1;
}

-> การเรียงสับเปลี่ยน การเรียงสับเปลี่ยนเปลี่ยนรูปแบบองค์ประกอบของรายการสแต็คในรูปแบบต่อไปนี้:

ซึ่งหมายความว่า

(สิ่งเหล่านี้จะปรากฏในรหัสแปลหากมีความคลาดเคลื่อนแสดงว่าล่ามนั้นถูกต้อง)

-> ตัวอย่างง่ายๆ

โปรแกรมง่าย ๆ สองโปรแกรมนี้พิมพ์ตัวเลขจาก 24 ถึง 1 (เป็นเอกภาพ) โดยไม่มีช่องว่าง

mov 24 Hans
start:
    print Hans
    dec Hans
    jnz Hans start
done!

หรือ

mov 24 Hans start: print Hans dec Hans jnz Hans start done!

พวกเขาเป็นโปรแกรมเดียวกัน

คำอธิบายและแนวทางแก้ไข:

มาร์ตินมีคำอธิบายที่ดีในคำตอบของเขาเช่นกัน

เมื่อมาร์ตินเข้าใจภาษานี้จึงได้รับแรงบันดาลใจจากพ็อกเก็ตคิวบ์ (หรือที่เรียกว่า 2x2 Rubik's cube) 24 สแต็คเปรียบเสมือนสี่เหลี่ยมจัตุรัส 24 อันบนลูกบาศก์ การเรียงสับเปลี่ยนเป็นการเคลื่อนไหวพื้นฐานที่ได้รับอนุญาต: ขึ้น, ลง, ขวา, ซ้าย, ด้านหน้า, หลัง

การต่อสู้หลักที่นี่คือเมื่อมีการผลักดันค่าจะใช้การเคลื่อนไหวเพียงสามครั้งเท่านั้นขึ้นลงและขวา อย่างไรก็ตามคุณไม่สามารถเข้าถึงการเคลื่อนไหวเหล่านี้เมื่อ "สับ" กอง คุณมีอีกสามการเคลื่อนไหวเท่านั้น

เมื่อปรากฎว่าทั้งสามชุดของการเคลื่อนไหวทั้งสองครอบคลุมกลุ่มทั้งหมด (เช่นเป็นเครื่องกำเนิดไฟฟ้า) ดังนั้นปัญหาจึงสามารถแก้ไขได้ ซึ่งหมายความว่าคุณสามารถแก้ปัญหาลูกบาศก์ 2x2 Rubik ใด ๆ โดยใช้ 3 การเคลื่อนไหวเท่านั้น

สิ่งที่เหลืออยู่ที่ต้องทำคือหาวิธียกเลิกการเลื่อนขึ้นและลงโดยใช้อีกสามอัน ด้วยเหตุนี้ฉันจึงใช้ระบบพีชคณิตคอมพิวเตอร์ชื่อGAP GAP

หลังจากยกเลิกการเรียงสับเปลี่ยนการค้นหาหมายเลขที่ใหญ่เป็นอันดับสามนั้นค่อนข้างน่าสนใจ

cinpush
main:
    mov 1s ShabbySam
    POP!! 1
    jmp compare
    continue:
        gte 0 ShabbySam Leopold
        jnz Leopold end
        gte ShabbySam 9 Leopold
        jz Leopold uinverse
        gte ShabbySam 29 Leopold
        jz Leopold dinverse
        jnz Leopold rinverse
compare:
    gte ShabbySam Alberto Leopold
    jz Leopold skip
    mov Gertrude Hans
    mov Alberto Gertrude
    mov ShabbySam Alberto
    jmp continue
    skip:
        gte ShabbySam Gertrude Leopold
        jz Leopold skip_2
        mov Gertrude Hans
        mov ShabbySam Gertrude
        jmp continue
    skip_2:
        gte ShabbySam Hans Leopold
        jz Leopold continue
        mov ShabbySam Hans
        jmp continue
uinverse: 
    "shuffle" f
    "shuffle" f
    "shuffle" f
    "shuffle" l
    "shuffle" b
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" l
    "shuffle" l
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" l
    "shuffle" l
    "shuffle" l
    "shuffle" f
    jmp main
dinverse:
    "shuffle" f
    "shuffle" b
    "shuffle" l
    "shuffle" b
    "shuffle" b
    "shuffle" b
    "shuffle" f
    "shuffle" f
    "shuffle" f
    jmp main
rinverse: 
    "shuffle" b "shuffle" l "shuffle" f "shuffle" l "shuffle" b
    "shuffle" f "shuffle" f "shuffle" f "shuffle" b
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" b "shuffle" b "shuffle" b
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" f "shuffle" l "shuffle" f
    "shuffle" l "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l 
    "shuffle" f "shuffle" l "shuffle" l 
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" l "shuffle" l "shuffle" l "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    "shuffle" f "shuffle" f "shuffle" f
    "shuffle" l "shuffle" f "shuffle" l "shuffle" f "shuffle" l "shuffle" f
    "shuffle" l "shuffle" l "shuffle" l
    jmp main
end:
    print Hans
    done!

2
แตกระแหง :) ฉันประทับใจภาษามาก!
Martin Ender

ว้าวเร็วกว่าที่ฉันคาดไว้ ขอบคุณฉันดีใจที่มันเป็นเรื่องสนุกที่จะคิดออกเหมือนที่จะเขียน
เลียม

ฉันอยากรู้อยากเห็นมันจะยากกว่านี้ไหมถ้าฉันเปลี่ยนชื่อของพีชคณิตเป็นบางอย่างที่เห็นได้ชัดเกี่ยวกับลูกบาศก์ของรูบิค?
เลียม

พวกเขาแน่นอนเบาะแส แต่ฉันคิดว่ามันจะไม่ได้มีการดำเนินการที่มากอีกต่อไปถ้าพวกเขามีชื่อที่แตกต่างกัน
Martin Ender

ดูเหมือนว่า GAP จะไม่ฉลาดโดยเฉพาะอย่างยิ่งเกี่ยวกับการย้อนกลับของการเปลี่ยนลำดับการป้อนข้อมูลทั้งสาม ;)
Martin Ender

22

Brian & Chuck , แตกโดย cardboard_box

ตอนนี้ฉันสนใจในความคิดของภาษาการเขียนโปรแกรมที่สองโปรแกรมโต้ตอบกัน (อาจเป็นแรงบันดาลใจจากROCB ) ความท้าทายนี้เป็นแรงจูงใจที่ดีในการแก้ไขปัญหาแนวคิดนี้ในขณะที่พยายามรักษาภาษาให้น้อยที่สุดเท่าที่จะทำได้ เป้าหมายการออกแบบคือการทำให้ภาษาทัวริงสมบูรณ์ในขณะที่แต่ละส่วนแต่ละส่วนจะไม่ทัวริงสมบูรณ์ ยิ่งกว่านั้นทั้งคู่ก็ไม่ควรทัวริงสมบูรณ์โดยไม่ต้องใช้การจัดการซอร์สโค้ด ฉันคิดว่าฉันประสบความสำเร็จ แต่ฉันยังไม่ได้พิสูจน์สิ่งเหล่านั้นอย่างเป็นทางการ ดังนั้นโดยไม่ต้องกังวลใจเพิ่มเติมฉันนำเสนอให้คุณ ...

ตัวละครเอก

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

เนื่องจากซอร์สโค้ดยังเป็นเทปหน่วยความจำคำสั่งจึงถูกกำหนดทางเทคนิคด้วยค่าจำนวนเต็ม แต่จะสัมพันธ์กับอักขระที่เหมาะสม คำสั่งต่อไปนี้มีอยู่:

  • ,( 44): อ่านไบต์จาก STDIN ลงในเซลล์หน่วยความจำปัจจุบัน มีเพียงไบรอันเท่านั้นที่ทำได้ คำสั่งนี้ไม่ใช้สำหรับ Chuck
  • .( 46): เขียนเซลล์หน่วยความจำปัจจุบันโมดูโล 256 เป็นไบต์ไปยัง STDOUT ชัคเท่านั้นที่สามารถทำได้ คำสั่งนี้ไม่ใช้สำหรับ Brian
  • +( 43): เพิ่มเซลล์หน่วยความจำปัจจุบัน
  • -( 45): ลดเซลล์หน่วยความจำปัจจุบัน
  • ?( 63): หากเซลล์หน่วยความจำปัจจุบันเป็นศูนย์นี่คือไม่มีการ op มิฉะนั้นควบคุมมือไปที่โปรแกรมอื่น หัวเทปในโปรแกรมที่ใช้จะยังคงอยู่ใน? ?ส่วนหัวเทปของโปรแกรมอื่นจะย้ายเซลล์หนึ่งไปทางขวาก่อนดำเนินการคำสั่งแรก (ดังนั้นเซลล์ที่ใช้เนื่องจากการทดสอบไม่ได้ดำเนินการเอง)
  • <( 60): เลื่อนหัวเทปหนึ่งเซลล์ไปทางซ้าย นี่คือไม่ต้องเลือกถ้าหัวเทปอยู่ที่ด้านซ้ายสุดของเทปแล้ว
  • >( 62): เลื่อนหัวเทปหนึ่งเซลล์ไปทางขวา
  • {( 123): เลื่อนหัวเทปไปทางซ้ายซ้ำ ๆ จนกว่าเซลล์ปัจจุบันจะเป็นศูนย์หรือถึงปลายด้านซ้ายของเทป
  • }( 125): เลื่อนหัวเทปไปทางขวาซ้ำ ๆ จนกระทั่งเซลล์ปัจจุบันเป็นศูนย์

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

รหัสที่มา

ไฟล์ต้นฉบับถูกประมวลผลดังนี้:

  • หากไฟล์มีสตริง ```ไฟล์จะถูกแบ่งออกเป็นสองส่วนรอบ ๆ เหตุการณ์แรกของสตริงนั้น ช่องว่างนำหน้าและต่อท้ายทั้งหมดถูกถอดออกและส่วนแรกถูกใช้เป็นซอร์สโค้ดสำหรับ Brian และส่วนที่สองสำหรับ Chuck
  • หากไฟล์ไม่มีสตริงนี้บรรทัดแรกของไฟล์จะถูกใช้เป็นแหล่งข้อมูลสำหรับไบรอันและส่วนที่สองสำหรับ Chuck (นอกเหนือจากการขึ้นบรรทัดใหม่ที่กำหนดขอบเขตจะไม่มีการลบช่องว่าง)
  • การเกิดขึ้นของ_ทั้งสองโปรแกรมจะถูกแทนที่ด้วย NULL ไบต์
  • เทปหน่วยความจำสองชุดนั้นเริ่มต้นด้วยรหัสอักขระที่สอดคล้องกับสตริงผลลัพธ์

ตัวอย่างเช่นไฟล์ต้นฉบับต่อไปนี้

  abc
```
0_1
23

จะให้ผลผลิตเทปเริ่มต้นต่อไปนี้:

Brian: [97 98 99 0 0 0 0 ...]
Chuck: [48 0 49 10 50 51 0 0 0 0 ...]

ล่าม

ล่ามเขียนเป็นภาษาทับทิม ใช้แฟล็กบรรทัดคำสั่งสองรายการซึ่งต้องไม่ใช้โดยโซลูชันใด ๆ (เนื่องจากไม่ใช่ส่วนหนึ่งของข้อมูลจำเพาะภาษาจริง):

  • -d: ด้วยการตั้งค่าสถานะนี้ Brian และ Chuck เข้าใจคำสั่งเพิ่มเติมสองคำ !จะพิมพ์การแสดงสตริงของเทปหน่วยความจำทั้งสองโปรแกรมที่ใช้งานอยู่ในรายการก่อน (a^จะทำเครื่องหมายหัวเทปปัจจุบัน) @จะทำเช่นนี้ แต่จะยกเลิกโปรแกรมทันที เพราะฉันขี้เกียจไม่ทำงานหากพวกเขาเป็นคำสั่งสุดท้ายในโปรแกรมดังนั้นหากคุณต้องการใช้พวกเขาที่นั่นให้ทำซ้ำพวกเขาหรือเขียน no-op หลังจากพวกเขา
  • -D: นี่คือโหมดแก้ไขข้อบกพร่องอย่างละเอียด มันจะพิมพ์ข้อมูลการแก้ปัญหาเดียวกัน!หลังจากทุกติ๊กเดียว@ยังใช้งานได้ในโหมดนี้

นี่คือรหัส:

# coding: utf-8

class Instance
    attr_accessor :tape, :code, :ip

    OPERATORS = {
        '+'.ord  => :inc,
        '-'.ord  => :dec,
        '>'.ord  => :right,
        '<'.ord  => :left,
        '}'.ord  => :scan_right,
        '{'.ord  => :scan_left,
        '?'.ord  => :toggle,
        ','.ord  => :input,
        '.'.ord  => :output,
        '!'.ord  => :debug,
        '@'.ord  => :debug_terminate
    }

    OPERATORS.default = :nop

    def initialize(src)
        @code = src.chars.map(&:ord)
        @code = [0] if code.empty?

        @ip = 0
    end

    def tick
        result = :continue
        case OPERATORS[@code[@ip]]
        when :inc
            @tape.set(@tape.get + 1)
        when :dec
            @tape.set(@tape.get - 1)
        when :right
            @tape.move_right
        when :left
            @tape.move_left
        when :scan_right
            @tape.move_right while @tape.get != 0
        when :scan_left
            @tape.move_left while @tape.ip > 0 && @tape.get != 0
        when :toggle
            if @tape.get != 0
                @tape.move_right
                result = :toggle
            end
        when :input
            input
        when :output
            output
        when :debug
            result = :debug
        when :debug_terminate
            result = :debug_terminate
        end

        return :terminate if result != :toggle && @ip == @code.size - 1

        move_right if result != :toggle

        return result
    end

    def move_right
        @ip += 1
        if @ip >= @code.size
            @code << 0
        end
    end

    def move_right
        @ip += 1
        if @ip >= @code.size
            @code << 0
        end
    end

    def move_left
        @ip -= 1 if @ip > 0
    end

    def get
        @code[@ip]
    end

    def set value
        @code[@ip] = value
    end

    def input() end
    def output() end

    def to_s
        str = self.class.name + ": \n"
        ip = @ip
        @code.map{|i|(i%256).chr}.join.lines.map do |l|
            str << l.chomp << $/
            str << ' '*ip << "^\n" if 0 <= ip && ip < l.size
            ip -= l.size
        end
        str
    end
end

class Brian < Instance
    def input
        byte = STDIN.read(1)
        @tape.set(byte ? byte.ord : -1)
    end
end

class Chuck < Instance
    def output
        $> << (@tape.get % 256).chr
    end
end

class BrianChuck

    class ProgramError < Exception; end

    def self.run(src, debug_level=0)
        new(src, debug_level).run
    end

    def initialize(src, debug_level=false)
        @debug_level = debug_level

        src.gsub!('_',"\0")

        if src[/```/]
            brian, chuck = src.split('```', 2).map(&:strip)
        else
            brian, chuck = src.lines.map(&:chomp)
        end

        chuck ||= ""

        brian = Brian.new(brian)
        chuck = Chuck.new(chuck)

        brian.tape = chuck
        chuck.tape = brian

        @instances = [brian, chuck]
    end

    def run
        (puts @instances; puts) if @debug_level > 1

        loop do
            result = current.tick

            toggle if result == :toggle

            (puts @instances; puts) if @debug_level > 1 || @debug_level > 0 && (result == :debug || result == :debug_terminate)

            break if result == :terminate || @debug_level > 0 && result == :debug_terminate
        end
    end

    private

    def current
        @instances[0]
    end

    def toggle
        @instances.reverse!
    end
end

case ARGV[0]
when "-d"
    debug_level = 1
when "-D"
    debug_level = 2
else
    debug_level = 0
end

if debug_level > 0
    ARGV.shift
end

BrianChuck.run(ARGF.read, debug_level)

นี่เป็นวิธีแก้ปัญหาของฉัน (เขียนด้วยลายมือ) ของตัวเอง:

>}>}>
brace left: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace left: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>} Append a bunch of 1s as a dummy list element:
+>+>+>+>+>+>+>+>+>+
Append two 1s and some code to the list; the first is a marker for later; the latter will be the integer
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow right: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_
{<<<<<<<<<{<{    Move back to the start
Read a character and subtract 48 to get actual 0 or 1
,------------------------------------------------
?   If 1 switch to Chuck otherwise continue
>}>}>>>>>>>>>}<<<<<<- Subtract 1 from the result to account for initial 1
?   If integer was positive switch to Chuck
@todo: process end
_
This code is run when reading 1:
}>}>>>>>>>>>}<<<<<<+ Move to the end of Chuck; skip one null cell; move to the end of the list
{<<<<<<<<<{<?   Move back to the code that resets this loop.
_
This code is run after finalising an integer:
change the code after the integer first
<<--<--<--}
Append two 1s and some code to the list; the first is a marker for later; the latter will be the integer
1: +
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1: >+
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow right: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
brace right: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{<<<<<<<+<<{<{    Move back to the start; incrementing the list length
Read a character and subtract 48 to get actual 0 or 1
,------------------------------------------------
?   If 1 switch to Chuck otherwise continue
>}>}>>>>>>>>>}
Leave the resetting code, but remove the rest of the last list element:
<<<--<--<--
1: <-
question mk: <---------------------------------------------------------------
arrow left: <------------------------------------------------------------
brace right: <-----------------------------------------------------------------------------------------------------------------------------
1: <-
<{< Move back to the cell we reserved for the counter
<<<<<<-- decrement list size by two so we don't process the two largest elements
_

<{<<<<<<{<{<{<{<{>}>}>>>>>>> This is the beginning of the loop which decrements all list elements by 1
+ Add 1 to the running total
>>- Set marker of dummy list element to zero
_ Beginning of loop that is run for each list element
<{<<<<<<{<{<{<{<{>}>}>}>}+ set last marker back to 1
>>>>>>>>>> move to next marker
? Skip the next bit if we're not at the end of the list
<? Move back to the beginning of the loop
@ we should never get here
_
This is run when we're not at the end of the list
<<<- Set marker to 0 to remember current position
>>>>- Move to the current value and decrement it
? Move back to loop beginning if value is not zero yet
- Make element negative so it's skipped in the future
{<{<{>- Move to remaining list length and decrement it
? If it's nonzero switch to Chuck
>>>>>>>>->->->->->->->->->- Remove the dummy list to make some space for new code:
>}+ Fill in the marker in the list
{<<<<<<<<< Add some loop resetting code after the result:
brace left: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arrow left: >++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
question mk: >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_
This loop adds a print command to Chuck's code while decrementing the result
>>>>>>>>}>>>>>}>>>>>} Move to the very end of Chuck's code and leave some space to seek the 1
print: ++++++++++++++++++++++++++++++++++++++++++++++
{<<<<<{<<<<<{<<<<<<<{<
- decrement the result
? if nonzero run loop again
At this point we just need to make Chuck seek for the 1 at the end of this code print it often enough
>>}>>>>>>>}>>>>>}
arrow right: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
<?1 Switch to Chuck which moves Brian's tape head onto the 1 and then prints it N times


```

_   Dummy cell to hold input
This code is run when reading a 1:
{<{<{<{ ensure we're at the start
}>}<? Skip 0 handling code and switch to Brian
_ This code is run after a 1 has been processed:
{<{<?

รหัสนี้สามารถรันได้เหมือนเดิมเพราะหมายเหตุทั้งหมดใช้ no-ops และถูกข้ามไป {และ}และ

แนวคิดพื้นฐานคือ:

  1. เพิ่มองค์ประกอบศูนย์ใหม่ให้กับรายการ (ที่ส่วนท้ายของเทปของ Chuck) และเพิ่มความยาวของรายการเป็น 1
  2. ในขณะที่เรากำลังอ่าน1ให้เพิ่มองค์ประกอบนั้น
  3. เมื่อเราอ่านก0ให้ทำความสะอาด หากจำนวนเต็มที่ได้รับมากกว่าศูนย์ให้กลับไปที่ 1

    ตอนนี้เรามีรายการหมายเลขอินพุตที่ท้ายเทปของ Chuck และเราทราบความยาวของรายการ

  4. ลบ 2 จากความยาวของรายการ (ดังนั้นขั้นตอนต่อไปนี้จะไม่สนใจองค์ประกอบที่ใหญ่ที่สุดสองรายการ) เรียกสิ่งนี้Nว่า

  5. ในขณะที่N > 0เพิ่มผลรวมที่กำลังทำงานอยู่แล้วลดองค์ประกอบรายการทั้งหมด Nเมื่อใดก็ตามที่องค์ประกอบรายการเหลือศูนย์พร่อง

    Mในตอนท้ายของเรื่องนี้ที่รวมการทำงานจะประกอบด้วยสามที่ใหญ่ที่สุดจำนวนในการป้อนข้อมูล,

  6. เขียนMสำเนา.ถึงปลายเทปของ Chuck

  7. บนชัคค้นหา1เทปของไบรอันแล้วดำเนินการสิ่งที่สร้างขึ้น.ในตอนท้าย

หลังจากทำสิ่งนี้เสร็จฉันก็ตระหนักว่าฉันสามารถทำให้มันง่ายขึ้นในบางที่ ตัวอย่างเช่นแทนที่จะติดตามตัวนับและเขียน.ลงในเทปของชัคฉันก็สามารถพิมพ์1ทันทีทุกครั้งก่อนที่ฉันจะลดองค์ประกอบรายการทั้งหมด อย่างไรก็ตามการเปลี่ยนแปลงรหัสนี้ค่อนข้างเจ็บปวดเพราะมันแพร่กระจายการเปลี่ยนแปลงอื่น ๆ ทั่วทุกสถานที่ดังนั้นฉันจึงไม่ต้องกังวลกับการเปลี่ยนแปลง

บิตที่น่าสนใจคือวิธีติดตามรายการและวิธีวนซ้ำผ่านรายการ คุณไม่สามารถจัดเก็บตัวเลขแบบ back-to-back บนเทปของ Chuck ได้เพราะถ้าคุณต้องการตรวจสอบเงื่อนไขในองค์ประกอบรายการใดรายการหนึ่งคุณอาจเสี่ยงต่อการดำเนินการส่วนที่เหลือของรายการซึ่งอาจมีรหัสที่ถูกต้อง คุณไม่ทราบว่าจะมีรายการอยู่นานเท่าไหร่ดังนั้นคุณจึงไม่สามารถจองพื้นที่หน้าโค้ดของ Chuck ได้

ปัญหาต่อไปคือเราต้องปล่อยให้รายการลดลงNในขณะที่เรากำลังดำเนินการอยู่และเราต้องกลับไปที่เดิมเหมือนที่เคยเป็นมา แต่{และ}จะข้ามรายการทั้งหมด

ดังนั้นเราต้องเขียนโค้ดแบบไดนามิกลงบน Chuck ในความเป็นจริงองค์ประกอบแต่ละรายการiมีรูปแบบ:

[1 <Code A> i <Code B>]

1เป็นเครื่องหมายซึ่งเราสามารถตั้งค่าเป็นศูนย์เพื่อระบุตำแหน่งที่เราออกจากการประมวลผลรายการ จุดประสงค์ของมันคือการจับ{หรือที่เพิ่งจะผ่านไปรหัสและ} iนอกจากนี้เรายังใช้ค่านี้เพื่อตรวจสอบว่าเราอยู่ท้ายรายการระหว่างการประมวลผลหรือไม่หากไม่เราจะดำเนิน1การตามเงื่อนไขและ?จะเปลี่ยนการควบคุมเป็นชัคCode Aใช้เพื่อจัดการสถานการณ์นั้นและย้าย IP ไปที่ Brian ตามนั้น

ตอนนี้เมื่อเราลดค่าiเราต้องตรวจสอบว่าiมันมีค่าเป็นศูนย์หรือไม่ ในขณะที่มันไม่ได้?จะเปลี่ยนการควบคุมอีกครั้งดังนั้นจึงCode Bมีการจัดการที่



@cardboard_box ดีมาก!
mbomb007

15

HPR เขียนด้วย Python 3 ( ถอดรหัสโดย TheNumberOne )

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

ข้อกำหนดภาษา

โปรแกรม HPR นั้นทำงานในสภาพแวดล้อมซึ่งเป็นชุดของจำนวนเต็มที่ไม่ใช่ค่าลบที่ไม่ได้เรียงลำดับและรายการของจำนวนเต็มที่ไม่ใช่ค่าลบ ในขั้นต้นสภาพแวดล้อมจะมีเพียงรายการอินพุต (ตัวแปลจะแยกวิเคราะห์ให้คุณ) มีสามคำสั่งและตัวดำเนินการ "control flow" สองตัวที่ปรับเปลี่ยนสภาพแวดล้อม:

  • *ลบองค์ประกอบแรกของทุกรายการที่ไม่ว่างในสภาพแวดล้อมและวางไว้ในสภาพแวดล้อม รายการที่ว่างเปล่าจะไม่ได้รับผลกระทบ ตัวอย่างเช่นมันแปลง

    {4,1,[0,2],[1,3],[]} -> {4,1,0,[2],[3],[]}
    
  • -ลดจำนวนทั้งหมดในสภาพแวดล้อมแล้วลบองค์ประกอบที่เป็นลบ ตัวอย่างเช่นมันแปลง

    {4,2,0,[0,2],[4,4,4]} -> {3,1,[0,2],[4,4,4]}
    
  • $หมุนทุกรายการในสภาพแวดล้อมหนึ่งก้าวไปทางซ้าย ตัวอย่างเช่นมันแปลง

    {4,1,[0,2],[3,4,1]} -> {4,1,[2,0],[4,1,3]}
    
  • !(A)(B)โปรแกรมAและที่ไหนBเป็นพื้นwhileวง จะดำเนินการ "การกระทำ" Aจนกว่า "การทดสอบ" Bจะส่งผลให้สภาพแวดล้อมที่ว่างเปล่า นี่อาจทำให้เกิดการวนซ้ำไม่สิ้นสุด
  • #(A)(B)ใช้โปรแกรมที่ไหนAและที่ไหนBAและBเข้ากับสภาพแวดล้อมในปัจจุบันและใช้เวลาแตกต่างสมมาตรของผล

คำสั่งจะถูกดำเนินการจากซ้ายไปขวา ในตอนท้ายขนาดของสภาพแวดล้อมจะพิมพ์ออกมาพร้อมกัน

ล่าม

ล่ามนี้มีคำสั่ง debug ?ซึ่งจะพิมพ์สภาพแวดล้อมโดยไม่ต้องแก้ไข ไม่ควรปรากฏในโซลูชันใด ๆ สำหรับงาน อักขระใด ๆ ยกเว้น*-$!#()?จะถูกละเว้นเพียงเพื่อให้คุณสามารถเขียนความคิดเห็นโดยตรงในรหัส ในที่สุดล่ามจะรับรู้สำนวน!(A)(#(A)())ว่า "ดำเนินการAจนกว่าผลลัพธ์จะไม่เปลี่ยนแปลง" และปรับให้เหมาะสมสำหรับความเร็วพิเศษ (ฉันต้องการให้โซลูชันของฉันเสร็จภายในหนึ่งชั่วโมงในกรณีทดสอบครั้งสุดท้าย)

import sys

def parse(prog):
    "Parse a prefix of a string into an AST. Return it and the remaining input."
    ret = []
    while prog:
        if prog[0] in "#!":
            sub1, prog1 = parse(prog[2:])
            sub2, prog2 = parse(prog1[1:])
            ret += [prog[0],sub1,sub2]
            prog = prog2
        elif prog[0] == ')':
            prog = prog[1:]
            break
        else:
            ret += [prog[0]]
            prog = prog[1:]
    return ret, prog

def intp(ast, L_env, N_env):
    "Interpret the AST on an environment, return the resulting environment."
    ptr = 0
    while ptr < len(ast):
        cmd = ast[ptr]
        if cmd == '*':
            N_env = N_env | set(L[0] for L in L_env if L)
            L_env = set(L[1:] for L in L_env)
            ptr += 1
        elif cmd == '-':
            N_env = set(N-1 for N in N_env if N>0)
            ptr += 1
        elif cmd == '$':
            L_env = set(L[1:]+L[:1] for L in L_env)
            ptr += 1
        elif cmd == '!':
            # Speed optimization
            cond = ast[ptr+2]
            if cond == ['#', ast[ptr+1], []]:
                L_next, N_next = intp(ast[ptr+1], L_env, N_env)
                while L_next != L_env or N_next != N_env:
                    L_env, N_env = L_next, N_next
                    L_next, N_next = intp(ast[ptr+1], L_env, N_env)
            else:
                while True:
                    L_test, N_test = intp(cond, L_env, N_env)
                    if not L_test and not N_test:
                        break
                    L_env, N_env = intp(ast[ptr+1], L_env, N_env)
            ptr += 3
        elif cmd == '#':
            L_env1, N_env1 = intp(ast[ptr+1], L_env, N_env)
            L_env2, N_env2 = intp(ast[ptr+2], L_env, N_env)
            L_env = L_env1 ^ L_env2
            N_env = N_env1 ^ N_env2
            ptr += 3
        elif cmd == '?':
            print(L_env | N_env)
            ptr += 1
        else:
            ptr += 1
    return L_env, N_env

def main(p, L):
    "Run the program on the input, return the output."
    # Parse the input list
    L = ''.join(c for c in L if c in "01")
    while "00" in L:
        L = L.replace("00","0")
    L = [-2] + [i for i in range(len(L)-1) if L[i:i+2] == "10"]
    L = tuple(b-a-1 for (a,b) in zip(L, L[1:]))
    # Parse the program
    ast = parse(p)[0]
    L_env, N_env = intp(ast, set([L]), set())
    return '1'*(len(L_env) + len(N_env))

if __name__ == "__main__":
    filename = sys.argv[1]
    f = open(filename, 'r')
    prog = f.read()
    f.close()
    L = input()
    print(main(prog, L))

ทางออกของฉัน

โซลูชันอ้างอิงของฉันมีความยาว 484 ไบต์จึงค่อนข้างสั้นเมื่อเทียบกับโปรแกรม 3271- ไบต์ของ TheNumberOne สิ่งนี้น่าจะเป็นเพราะระบบมาโครที่ซับซ้อนและยอดเยี่ยม TheNumberOne พัฒนาขึ้นสำหรับการเขียนโปรแกรมใน HPR แนวคิดหลักในทั้งสองโปรแกรมของเราคล้ายกัน:

  1. ค้นหาวิธีการสร้างองค์ประกอบสูงสุดของรายการ
  2. หากต้องการลบองค์ประกอบสูงสุดให้หมุนรายการจนกว่าองค์ประกอบแรกจะเท่ากับจำนวนสูงสุดจากนั้นเปิดขึ้นมา
  3. ลบสูงสุดสองครั้งจากนั้นพิมพ์องค์ประกอบสูงสุดใหม่

อย่างไรก็ตามเท่าที่ฉันสามารถบอกได้รายละเอียดการใช้งานที่แน่นอนนั้นแตกต่างกันมาก นี่คือทางออกของฉัน:

!($)(!(-)(#(-)())#(!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())#(-)(#(!(-)(#(-)()))()))(*)#(!(-)(#(-)()))())*!(-)(#(-)())!($)(!(-)(#(-)())#(!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())#(-)(#(!(-)(#(-)()))()))(*)#(!(-)(#(-)()))())*!(-)(#(-)())!(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))(#(-#(!(*)(#(*)())#(!(-)(#(-)()))())(!(-)(#(-)())))())-#(!(-)(#(-)()))()

และนี่คือโปรแกรม Python ที่ได้รับการคอมเม้นต์ที่สร้างขึ้นมา (ไม่มีอะไรแฟนซีที่นี่เพียงแค่การจัดการสตริงพื้นฐานเพื่อกำจัดการทำซ้ำทั้งหมด):

# No numbers in the environment
no_nums = "#(-)()"
# No non-empty lists in the environment
no_lists = "#(*)()"
# Remove all numbers from the environment
del_nums = "!(-)(" + no_nums + ")"
# Remove all lists from the environment
del_lists = "#(" + del_nums + ")()"
# Splat the list to the environment:
#  pop the list until it's empty and delete the empty list,
#  then take symmetric difference with all numbers removed
splat = "#(!(*)(" + no_lists + ")" + del_lists + ")(" + del_nums + ")"
# Put into the environment all numbers up to list maximum:
#  decrement and splat until a fixed point is reached.
#  Without the speed optimization, this is very slow if the list elements are large.
splat_upto = "!(-" + splat + ")(#(-" + splat + ")())"
# Copy maximum element to environment:
#  take all elements up to maximum,
#  then take symmetric difference of decrement and list deletion
copy_max = splat_upto + "#(-)(" + del_lists + ")"
# Delete maximum element from list:
#  rotate until first element is maximal, then pop and delete it
del_max = "!($)(" + del_nums + "#(" + copy_max + ")(*)" + del_lists + ")*" + del_nums
# Full program:
#  remove the maximum twice, then produce all numbers up to maximum,
#  then decrement and remove lists. The environment will contain exactly
#  the integers from 0 to third largest - 1, and their number is printed.
main = del_max + del_max + splat_upto + "-" + del_lists
print(main)


@TheNumberOne เพิ่มโซลูชันของฉัน
Zgarb

12

TKDYNS (การฆ่ามังกรคุณต้องการดาบ) - Cracked โดยมาร์ตินBüttner

แก้ไข: ฉันได้เพิ่มการแก้ปัญหาและคำอธิบายของฉันด้านล่างโพสต์หลัก

พื้นหลัง

ในภาษานี้คุณควบคุมนักรบผู้กล้าที่ได้รับมอบหมายให้ฆ่ามังกรที่น่ากลัว มังกรอาศัยอยู่ในเขาวงกตใต้ดินที่เต็มไปด้วยอันตรายและอันตรายและจนถึงขณะนี้ยังไม่มีใครสามารถทำแผนที่ออกมาและอยู่รอดได้ ซึ่งหมายความว่าคุณต้องนำทางไปยังมังกรในความมืดมืดสนิทโดยไม่มีอะไรนอกจากสัญชาตญาณและความกล้าหาญที่จะนำทางคุณ

...

ก็ไม่มาก คุณนำมินเนี่ยนสำรองไปใช้กับคุณได้อย่างไร้ขีด จำกัด และพวกเขายินดีที่จะนำหน้าคุณเพื่อค้นหาเส้นทางที่ปลอดภัย น่าเสียดายที่พวกมันหนากว่าไม้กระดานสั้นสองแผ่นและจะทำในสิ่งที่คุณบอกให้ทำเท่านั้น มันขึ้นอยู่กับคุณที่จะเกิดขึ้นด้วยวิธีที่ชาญฉลาดในการรับรองว่าลูกน้องของคุณจะค้นพบเส้นทางที่ถูกต้อง

รายละเอียดเพิ่มเติมบางส่วน

ถ้ำมังกรใช้รูปแบบของตาราง 10x10 ระหว่างจุดที่อยู่ติดกันในตารางมีทางเดินแคบ ๆ ระหว่างผู้อื่นมีช่องว่างลึกและความตายบางอย่าง ตัวอย่างเค้าโครงสำหรับตาราง 4x4 อาจเป็นดังนี้:

 0---1   2---3
     |   |   |
 4---5---6   7
 |           |
 8   9--10  11
     |       |
12--13--14--15

คุณรู้ว่ามีวิธีที่จะได้รับจากจุดหนึ่งไปยังอีกจุดหนึ่งเสมอ แต่ไม่มากไปกว่าที่ได้รับการเปิดเผยให้คุณ

ในการเอาชนะมังกรให้สำเร็จก่อนอื่นคุณต้องรวบรวมไอเท็มบางอย่างซึ่งคุณจะสามารถรวมเข้าด้วยกันเพื่อสร้างใบมีดสังหารมังกร สะดวกทุกชิ้นสำหรับอาวุธนี้ได้กระจัดกระจายไปรอบ ๆ ถ้ำมังกร คุณเพียงแค่ต้องรวบรวมพวกเขา

การหมุนคือแต่ละชิ้นส่วนของอาวุธถูกขังอยู่ในโรงพยาบาล ทุกครั้งที่มีการรวบรวมเค้าโครงของทางเดินจะเปลี่ยนไป เส้นทางที่ปลอดภัยก่อนหน้านี้อาจนำไปสู่ความตายและในทางกลับกัน

คำสั่ง

มีเพียง 5 คำสั่งที่ใช้ได้

  • < - ก้าวไปทางซ้าย

  • > - ก้าวไปทางขวา

  • ^ - ก้าวขึ้นไป

  • v - ลดขั้นตอนลง

  • c- รวบรวมไอเทมที่กำลังนอนอยู่ที่ตำแหน่งปัจจุบันของคุณ หากมีรายการอยู่เค้าโครงของถ้ำจะเปลี่ยนไป ด้วยตำแหน่งที่เรียงเป็นแถวตามข้างบนใช้โมดูโลตำแหน่งของคุณ 10 มี 10 เลย์เอาท์ฮาร์ดโค้ดลงในล่ามและโครงร่างจะเปลี่ยนเป็นรูปแบบที่เกี่ยวข้อง ตัวอย่างเช่นหากคุณอยู่ที่ตำแหน่งที่ 13 รูปแบบจะเปลี่ยนเป็นlayouts[3]

เลย์เอาต์ที่ปรากฏใน interpeter นั้นถูกเข้ารหัสเป็นจำนวนเต็มด้วยวิธีต่อไปนี้:

  • เลย์เอาต์ที่ว่างเปล่าถูกเข้ารหัสเป็นศูนย์

  • สำหรับแต่ละขอบในเลย์เอาต์ให้xเล็กกว่าของสองตำแหน่งที่มันเข้าร่วม

    • หากขั้นตอนเป็นแนวนอนให้เพิ่ม2^(2*x)การเข้ารหัส (นั่นคือพลังของไม่ใช่ XOR)

    • หากขั้นตอนเป็นแนวตั้งให้เพิ่ม2^(2*x + 1)การเข้ารหัส

การไหลของการดำเนินการ

ล่ามทำงานด้วยชื่อของไฟล์ต้นฉบับเป็นอาร์กิวเมนต์บรรทัดคำสั่ง

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

แต่ละซอร์สโปรแกรมประกอบด้วยหลายบรรทัดแต่ละบรรทัดประกอบด้วยบางลำดับของอักขระที่ใช้ได้ 5 ตัวด้านบน เส้นเหล่านี้แสดงถึงลูกน้องของคุณ คุณนักรบติดตามลำดับของการกระทำที่ทราบว่าปลอดภัย ตอนแรกคุณไม่รู้อะไรเกี่ยวกับถ้ำดังนั้นลำดับนี้จึงว่างเปล่า ทำให้แต่ละ minion กลับมาทำสิ่งต่อไปนี้โดยเริ่มจากตำแหน่ง 0:

  • minion ได้รับคำสั่งให้ดำเนินการแอ็คชันที่ทราบว่าปลอดภัยแล้วตามด้วยการกระทำในบรรทัดโค้ดของตนเอง

    • หาก minion ตายที่จุดใดคุณจะได้รับแจ้งเรื่องนี้และที่ซ่อนจะรีเซ็ตเป็นค่าเริ่มต้น รายการทั้งหมดจะถูกแทนที่และทางเดินกลับสู่ตำแหน่งเริ่มต้นของพวกเขา

    • ถ้ามินเนียนยังมีชีวิตอยู่คุณจะกลายเป็นไอต่อไป - เป็นเพียงมินเนี่ยนเท่านั้น ก่อนหน้านี้สิ่งนี้ทริกเกอร์การรีเซ็ตที่ซ่อนให้อยู่ในสถานะเริ่มต้น แต่คราวนี้คุณผนวกการกระทำจากบรรทัดของรหัส minion ไปยังลำดับของการกระทำที่เป็นที่รู้จัก

เมื่อสมุนทั้งหมดหมดแล้วคุณนักรบดำเนินการทั้งหมดที่รู้ว่าปลอดภัยเริ่มอีกครั้งจากตำแหน่งที่ 0 มีผลลัพธ์ที่เป็นไปได้สองประการ:

  • คุณรวบรวมชิ้นส่วนของอาวุธทั้งหมด - ในกรณีนี้คุณฆ่ามังกรสำเร็จและข้อความชัยชนะที่น่าตื่นเต้นก็ปรากฏขึ้น ข้อความชัยชนะครั้งนี้จะมีในหมู่ตัวละครอื่น ๆnคนที่nเป็นจำนวนสูงสุดที่สามให้เป็นอินพุท

  • คุณล้มเหลวในการรวบรวมชิ้นส่วนของอาวุธ - ในกรณีนี้มังกรอาศัยอยู่และคุณล้มเหลวในการค้นหา

รหัสล่าม (Python 2)

import collections
import copy
import sys

size = 10
layouts = [108705550239329248440770931020110627243913363144548922111951,108386637020100924277694952798729434993885646706222210602969,133885860318189115027934177821170081234850573770998325845482,102397795295522647918061101991513921833376565032742993744791,131948019244359669407266662537098175265242405785636894694611,127512068876349726396523358265982765442984953916545984706958,106817519055019354200334114020150263381328246524221867629943,33472343358375525802921815863230485208221126168622186265959,133909781123963725874096031069972704024813281938330035579187,132244654022332695610020359820518831299843076834682749020986]

class Interpreter(object):

    def __init__(self, source_file):
        self.source_filename = source_file
        self.layout = layouts[0]
        self.position = 0
        self.ingredients = []
        self.quest_items = {}
        self.attempts = collections.deque()

        self.safe_position = 0
        self.safe_ingredients = []
        self.safe_quest_items = {}
        self.safe_layout = layouts[0]

    def get_input(self):
        s = raw_input("Which quest would you like to embark on today?")
        ind = s.find('00')
        s = s[:ind]
        items = map(len, s.split('0'))
        for item in items:
            if item not in self.safe_quest_items:
                self.safe_quest_items[item] = 1
            else:
                self.safe_quest_items[item] += 1

    def parse_attempts(self):
        with open(self.source_filename, 'r') as source:
            for line in source:
                self.attempts.append(line.strip())

    def enc(self, x, y):
        x, y = min(x, y), max(x, y)
        if x < 0:
            return 0
        if y == x + 1:
            return 1 << (2*x)
        elif y == x + size:
            return 1 << (2*x + 1)
        else:
            return 0

    def exec_command(self, char):
        if char == '<':
            if self.enc(self.position, self.position-1) & self.layout:
                self.position -= 1
            else:
                return False
        elif char == '>':
            if self.enc(self.position, self.position+1) & self.layout:
                self.position += 1
            else:
                return False
        elif char == '^':
            if self.enc(self.position, self.position-size) & self.layout:
                self.position -= size
            else:
                return False
        elif char == 'v':
            if self.enc(self.position, self.position+size) & self.layout:
                self.position += size
            else:
                return False
        elif char == 'c':
            for item in xrange(self.position, 10**6, size*size):
                if item in self.quest_items:
                    self.ingredients += ([item] * self.quest_items.pop(item))
                    self.ingredients.sort()
                    self.layout = layouts[self.position % 10]
        else:
            raise ValueError

        return True

    def run_minion(self):
        minion = self.attempts.popleft()
        self.position = self.safe_position
        self.ingredients = copy.copy(self.safe_ingredients)
        self.quest_items = copy.copy(self.safe_quest_items)
        self.layout = self.safe_layout
        dead = False

        for cmd in minion:
            if not self.exec_command(cmd):
                dead = True

        if not dead:
            self.safe_position = self.position
            self.safe_ingredients = copy.copy(self.ingredients)
            self.safe_quest_items = copy.copy(self.quest_items)
            self.safe_layout = self.layout

    def process_minions(self):
        while self.attempts:
            self.run_minion()

    def final_run(self):
        if len(self.safe_quest_items) == 0:
            print "You killed the dragon" + "!!1" * self.safe_ingredients[-3]
        else:
            print "The dragon lives on. Better luck next time..."

    def interpret(self):
        self.get_input()
        self.parse_attempts()
        self.process_minions()
        self.final_run()

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print "Wrong number of arguments"
    else:
        test = Interpreter(sys.argv[1])
        test.interpret()

ขอให้โชคดีนักรบผู้กล้าหาญ

ทางออกและคำอธิบายของฉัน

นี่คือสคริปต์ Python ที่สร้างซอร์สโค้ดเพื่อแก้ปัญหา เพื่อความสนใจซอร์สโค้ดสุดท้ายของ Martin นั้นเล็กกว่าโค้ดที่สคริปต์ของฉันสร้างขึ้นประมาณ 5 เท่า ในทางกลับกันสคริปต์ของฉันในการสร้างรหัสนั้นมีขนาดเล็กกว่าโปรแกรม Mathematica ของ Martin ประมาณ 15 เท่า ...

size = 10
layouts = [108705550239329248440770931020110627243913363144548922111951,108386637020100924277694952798729434993885646706222210602969,133885860318189115027934177821170081234850573770998325845482,102397795295522647918061101991513921833376565032742993744791,131948019244359669407266662537098175265242405785636894694611,127512068876349726396523358265982765442984953916545984706958,106817519055019354200334114020150263381328246524221867629943,33472343358375525802921815863230485208221126168622186265959,133909781123963725874096031069972704024813281938330035579187,132244654022332695610020359820518831299843076834682749020986]

def enc(edge):
    x,y = min(edge), max(edge)
    if x < 0:
        return 0
    if y == x + 1:
        return 1 << (2*x)
    elif y == x + size:
        return 1 << (2*x + 1)

def path(x, y, tree):
    stack = [(x,'')]
    while stack[-1][0] != y:
        vertex, path = stack.pop()
        if (enc((vertex, vertex+1))&tree) and ((not path) or path[-1] != '<'):
            stack.append((vertex+1, path+'>'))
        if (enc((vertex, vertex-1))&tree) and ((not path) or path[-1] != '>'):
            stack.append((vertex-1, path+'<'))
        if (enc((vertex, vertex+size))&tree) and ((not path) or path[-1] != '^'):
            stack.append((vertex+size, path+'v'))
        if (enc((vertex, vertex-size))&tree) and ((not path) or path[-1] != 'v'):
            stack.append((vertex-size, path+'^'))
    return stack[-1][1]

def reverse(path):
    rev = ''
    for i in xrange(len(path)-1, -1 ,-1):
        if path[i] == '<':
            rev += '>'
        if path[i] == '>':
            rev += '<'
        if path[i] == 'v':
            rev += '^'
        if path[i] == '^':
            rev += 'v'
    return rev

def assert_at(x, tree):
    path_ul = path(x, 0, tree)
    path_dr = path(x, size*size - 1, tree)
    return path_ul + reverse(path_ul) + path_dr + reverse(path_dr)

def safe_path(x, y, tree):
    return assert_at(x, tree) + path(x, y, tree)

with open('source.txt', 'w') as f:
    for x in xrange(size*size - 1):
        for tree in layouts:
            f.write(safe_path(x, x+1, tree) + 'c\n')

โครงสร้างพื้นฐาน

สิ่งนี้สร้างซอร์สโค้ด 990 บรรทัดซึ่งมาในกลุ่ม 10 10 บรรทัดแรกมีคำแนะนำที่พยายามย้ายมิเนียนจากตำแหน่งหนึ่ง0ไปยังอีกตำแหน่ง1หนึ่งแล้วรวบรวมรายการ - หนึ่งชุดสำหรับแต่ละโครงร่างที่เป็นไปได้ 10 บรรทัดถัดไปทั้งหมดมีคำแนะนำที่พยายามย้ายสมุนจากตำแหน่งหนึ่ง1ไปยังอีกตำแหน่ง2หนึ่งแล้วรวบรวมรายการ และอื่น ๆ ... เส้นทางเหล่านี้คำนวณโดยใช้pathฟังก์ชันในสคริปต์ - ทำการค้นหาในเชิงลึกอย่างง่าย ๆ เท่านั้น

หากเราสามารถมั่นใจได้ว่าในแต่ละกลุ่ม 10 กลุ่มมินเนี่ยนจะประสบความสำเร็จอย่างแม่นยำในแต่ละกลุ่มเราจะแก้ปัญหาได้

ปัญหากับแนวทาง

อาจไม่ใช่ทุกกรณีที่มินเนี่ยนหนึ่งกลุ่มจาก 10 กลุ่มประสบความสำเร็จ - ตัวอย่างเช่นมินเนียนที่ออกแบบมาเพื่อรับจากตำแหน่งหนึ่ง0ไปยังอีกตำแหน่งหนึ่ง1อาจประสบความสำเร็จในการเคลื่อนย้ายจากตำแหน่งหนึ่ง1ไปยังอีกตำแหน่งหนึ่ง2 (เนื่องจากความคล้ายคลึงกันในโครงร่าง) การคำนวณผิดจะเผยแพร่ผ่านอาจทำให้เกิดความล้มเหลว

วิธีแก้ไข

การแก้ไขที่ฉันใช้มีดังนี้:

สำหรับมิเนียนแต่ละอันที่พยายามจะได้จากตำแหน่งหนึ่งnไปn+1ก่อนอื่นให้ทำให้เขาเดินจากตำแหน่งหนึ่งnไปยัง0อีกมุมหนึ่ง (มุมบนซ้าย) และกลับมาอีกครั้งจากนั้นnไปยังอีกตำแหน่งหนึ่ง99(มุมล่างขวา) และกลับมาอีกครั้ง คำแนะนำเหล่านี้สามารถดำเนินการได้อย่างปลอดภัยจากตำแหน่งเท่านั้นตำแหน่งnเริ่มต้นอื่น ๆ และสมุนจะเดินออกจากขอบ

คำแนะนำพิเศษเหล่านี้จึงป้องกันมินเนี่ยนไม่ให้ไปที่อื่นโดยไม่ตั้งใจและเพื่อให้แน่ใจว่ามินเนียนหนึ่งตัวจากแต่ละกลุ่มของ 10 ประสบความสำเร็จ โปรดทราบว่ามันไม่จำเป็นต้องเป็นสมุนที่คุณคาดว่าจะเป็น - อาจเป็นกรณีที่สมุนที่เชื่อว่าเขาอยู่ในเลย์เอาต์ 0 สำเร็จแม้ว่าเราจะอยู่ในเลย์เอาต์ 7 จริง ๆ ก็ตาม แต่ในกรณีใด ๆ ความจริงที่ว่าเรามี ตอนนี้สถานะที่เปลี่ยนไปหมายความว่ามินเนี่ยนอื่น ๆ ทั้งหมดในกลุ่มจะต้องตาย ขั้นตอนพิเศษเหล่านี้คำนวณโดยassert_atฟังก์ชันและsafe_pathฟังก์ชันส่งคืนพา ธ ซึ่งเป็นการต่อเชื่อมของขั้นตอนพิเศษเหล่านี้กับพา ธ ธรรมดา


1
แตกระแหง มันสนุกดี แต่ฉันคิดว่ามันทำให้เกิดปัญหากับกฎ "ภาษาการเขียนโปรแกรมของคุณต้องแก้ปัญหานี้เพียงอย่างเดียว" เนื่องจากการถอดรหัสปริศนาของคุณไม่เกี่ยวข้องกับการแก้ปัญหาการเขียนโปรแกรม ;)
Martin Ender

ฉันสร้างคำตอบนี้เป็นส่วนใหญ่เพราะฉันสังเกตเห็นว่ามีปัญหาอยู่ - และดูเหมือนว่าจะไม่มีอะไรที่จะหยุดยั้งไม่ให้ใครบางคนใช้ปัญหาการคำนวณที่ยากอย่างแท้จริงแทน การห้าม 'no crypto' ดูเหมือนว่าจะแคบลงโดยพล ...
Sam Cappleman-Lynes

จริง ฉันเดาว่านั่นเป็นเหตุผลที่นี่คือการประกวดความนิยม หากปัญหานั้นเป็นเรื่องของการคำนวณมากกว่าและไม่ได้เป็นเรื่องราวที่ดีเท่าที่ควรจะเป็นคะแนนที่ได้รับคำตอบด้วยภาษาที่เหมาะสม (อาจเป็นทัวริงสมบูรณ์) ซึ่งจริงๆแล้วมันยากที่จะใช้
Martin Ender

เพิ่มโซลูชันของฉันเพื่อความสนใจ ที่น่าสนใจก็คือตอนแรกฉันได้ออกแบบจิ๊กซอว์โดยคำนึงถึง 1,000x1000 กริด แต่ในความสนใจที่ไม่มีเลย์เอาต์ที่เข้ารหัสเป็นตัวเลข ~ 600,000 หลักที่ฉันเลือกสำหรับขนาดที่เล็กกว่า
Sam Cappleman-Lynes

8

Firetype แตกโดย Martin Büttner

การผสมผสานที่แปลกประหลาดของ BF และ CJam และใครจะรู้ว่ามีอะไรอีก! ค่อนข้างแน่ใจว่ามันจะง่าย แต่ก็สนุกดี FYI ชื่อนี้อ้างถึง Vermillion ไฟจาก Final Fantasy Type-0

บันทึก : โปรดยกโทษให้ฉันสำหรับความคลุมเครือใด ๆ ในคำอธิบายนี้ ฉันไม่ใช่นักเขียนที่ดีที่สุด ... : O

Martin แตกได้เร็วจริงๆ! นี่เป็นโปรแกรมต้นฉบับของฉันเพื่อแก้ปัญหา:

_
,
^
~
+
|
|
-
%
+
_
+
=











`
~
+
|
%

_
=

\
@
-
-
!
<
>
>
>

_
+
.
<
-
`
~
~
+
|
|
-
#
%

วากยสัมพันธ์

สคริปต์ Firetype นั้นเป็นรายการของเส้น อักขระตัวแรกของแต่ละบรรทัดคือคำสั่งให้รัน เส้นที่ว่างเปล่านั้นเป็น NOP

อรรถศาสตร์

คุณมีอาร์เรย์ของจำนวนเต็มและตัวชี้ (คิดว่า BF) คุณสามารถเลื่อนองค์ประกอบไปทางซ้ายและขวาหรือ "ดัน" ไปยังอาร์เรย์

ใจเร่งเร้า

เมื่อคุณ "ผลักดัน" องค์ประกอบและคุณอยู่ท้ายอาร์เรย์องค์ประกอบเพิ่มเติมจะถูกผนวกเข้ากับท้ายสุด หากคุณไม่ได้อยู่ที่จุดสิ้นสุดองค์ประกอบถัดไปจะถูกแทนที่ ตัวชี้จะเพิ่มขึ้นเสมอ

คำสั่ง

_

กดศูนย์ลงบนอาเรย์

+

เพิ่มองค์ประกอบที่ตัวชี้ปัจจุบัน

-

ลดลงองค์ประกอบที่ตัวชี้ปัจจุบัน

*

องค์ประกอบเป็นสองเท่าที่ตัวชี้ปัจจุบัน

/

ลดองค์ประกอบลงครึ่งหนึ่งที่ตัวชี้ปัจจุบัน

%

ใช้องค์ประกอบที่ตัวชี้ปัจจุบันและข้ามไปข้างหน้าหลายบรรทัดแล้วเลื่อนตัวชี้ไปทางซ้าย หากค่าเป็นลบให้ย้อนกลับแทน

=

ใช้องค์ประกอบที่ชี้ปัจจุบันและข้ามไปยังบรรทัดที่ + 1 ตัวอย่างเช่นถ้าองค์ประกอบปัจจุบันนี้จะข้ามไปยังบรรทัด0 1สิ่งนี้จะย้ายตัวชี้ไปทางซ้ายด้วย

,

อ่านตัวละครจากอินพุตมาตรฐานและผลักดันค่า ASCII

^

ใช้องค์ประกอบที่ตัวชี้ปัจจุบันตีความว่ามันเป็นค่า ASCII สำหรับตัวละครและแปลงเป็นจำนวนเต็ม ตัวอย่างเช่นถ้าค่าปัจจุบันคือ49 (ค่า ASCII ของ1) 1องค์ประกอบที่ชี้ปัจจุบันจะถูกตั้งค่าจำนวนเต็ม

.

เขียนหมายเลขปัจจุบันไปที่หน้าจอ

!

ใช้องค์ประกอบที่ตัวชี้ปัจจุบันและทำซ้ำบรรทัดถัดไปที่หลายต่อหลายครั้ง เลื่อนตัวชี้ไปทางซ้าย

<

เลื่อนตัวชี้ไปทางซ้าย หากคุณเริ่มต้นแล้วข้อผิดพลาดจะถูกโยนทิ้ง

>

เลื่อนตัวชี้ไปทางขวา หากคุณอยู่ในตอนท้ายข้อผิดพลาดจะถูกโยนทิ้ง

~

ถ้าองค์ประกอบปัจจุบันไม่ใช่ศูนย์แทนที่ด้วย0; 1มิฉะนั้นแทนที่ด้วย

|

สแควร์องค์ประกอบปัจจุบัน

@

ตั้งองค์ประกอบปัจจุบันเป็นความยาวของอาร์เรย์

`

ทำซ้ำองค์ประกอบปัจจุบัน

\

จัดเรียงองค์ประกอบที่และก่อนตัวชี้

#

ปฏิเสธองค์ประกอบปัจจุบัน

ล่าม

นอกจากนี้ยังมีที่Github

#!/usr/bin/env python

# The FireType interpreter.
# Runs under Python 2 and 3.
import sys

class Array(object):
    def __init__(self):
        self.array = []
        self.ptr = 0

    def push_zero(self):
        if self.ptr == len(self.array):
            self.array.append(0)
        else:
            self.array[self.ptr] = 0
        self.ptr += 1

    def left(self):
        self.ptr -= 1
        assert self.ptr >= 0 and self.array, 'pointer underflow (at %d)' % i

    def right(self):
        self.ptr += 1
        assert self.ptr <= len(self.array), 'pointer overflow (at %d)' % i

    def sort(self):
        lhs = self.array[:self.ptr-1]
        rhs = self.array[self.ptr-1:]
        lhs.sort()
        lhs.reverse()
        self.array = lhs + rhs

    def __call__(self, *args):
        args = list(args)
        assert self.array, 'out-of-bounds (at %d)' % i
        if not args:
            return self.array[self.ptr-1]
        self.array[self.ptr-1] = args.pop()
        assert not args

    def __len__(self):
        return len(self.array)

    def __str__(self):
        return 'Array(array=%s, ptr=%s)' % (self.array, self.ptr)

    def __repr__(self):
        return 'Array(array=%r, ptr=%r)' % (self.array, self.ptr)

def execute(lines):
    global i, array
    i = 0
    array = Array()
    rep = 0
    while i < len(lines):
        line = lines[i]
        if not line:
            i += 1
            continue
        line = line[0]
        if line == '_':
            array.push_zero()
        elif line == '+':
            array(array() + 1)
        elif line == '-':
            array(array() - 1)
        elif line == '*':
            array(array() * 2)
        elif line == '/':
            array(int(array() / 2))
        elif line == '%':
            i += array()
            array.left()
        elif line == '=':
            i = array()-1
            array.left()
        elif line == ',':
            array.push_zero()
            array(ord(sys.stdin.read(1)))
        elif line == '.':
            sys.stdout.write(str(array()))
        elif line == '!':
            rep = array()
            array.left()
            i += 1
        elif line == '<':
            array.left()
        elif line == '>':
            array.right()
        elif line == '^':
            array(int(chr(array())))
        elif line == '~':
            array(int(not array()))
        elif line == '|':
            array(array() ** 2)
        elif line == '@':
            array(len(array))
        elif line == '`':
            top = array()
            array.push_zero()
            array(top)
        elif line == '\\':
            array.sort()
        elif line == '#':
            array(-array())

        if rep:
            rep -= 1
        else:
            i += 1

def main(args):
    try:
        _, path = args
    except ValueError:
        sys.exit('usage: %s <file to run, - for stdin>')

    if path == '-':
        data = sys.stdin.read()
    else:
        with open(path) as f:
            data = f.read()

    try:
        execute(data.split('\n'))
    except:
        print('ERROR!')
        print('Array was %r' % array)
        print('Re-raising error...')
        raise

if __name__ == '__main__':
    main(sys.argv)

ฉันคิดว่าการยืนยันขอบเขตล่างของอาเรย์นั้นมีค่า เนื่องจากคุณกำลังใช้self.ptr-1สำหรับการเข้าถึงคุณอาจจะตรวจสอบไม่ได้self.ptr>0 >=0(สิ่งนี้ไม่ควรทำให้โปรแกรมที่ถูกต้องใช้ไม่ได้ แต่อาจทำให้บางโปรแกรมทำงานโดยไม่ตั้งใจซึ่งไม่ควรใช้)
Martin Ender

อีกอย่างหนึ่ง: รหัสบอกว่า=ตั้งค่าarray() - 1เป็นเอกสารกล่าว+1?
Martin Ender

แตกระแหง (สมมติว่าล่ามนั้นเป็นบรรทัดฐานไม่ใช่คำอธิบาย)
Martin Ender

@ MartinBüttner Dang นั่นเร็วกว่าที่ฉันคิดไว้! : OI แก้ไขปัญหาเอกสารที่คุณพูดถึง
kirbyfan64sos

7

Acc !! (ปลอดภัย)

มันกลับมา ...

ป้อนคำอธิบายรูปภาพที่นี่

... และหวังว่าจะพิสูจน์ได้อย่างแน่นอนมากขึ้น

ฉันอ่านAcc! ข้อมูลจำเพาะ ACCเป็นอย่างไร!! แตกต่างกันอย่างไร

ในACC !!ตัวแปรลูปออกนอกขอบเขตเมื่อออกจากลูป คุณสามารถใช้ได้ภายในลูปเท่านั้น นอกคุณจะได้รับข้อผิดพลาด "ไม่ได้กำหนดชื่อ" นอกเหนือจากการเปลี่ยนแปลงนี้ภาษาจะเหมือนกัน

งบ

คำสั่งคือการแยกวิเคราะห์ทีละบรรทัด คำสั่งมีสามประเภท:

  1. Count <var> while <cond>

เคานต์<var>เพิ่มขึ้นจาก 0 ตราบเท่าที่<cond>ไม่ใช่ศูนย์เทียบเท่ากับ C for(int <var>=0; <cond>; <var>++)++ ตัวนับลูปอาจเป็นตัวอักษรตัวเล็กก็ได้ เงื่อนไขสามารถเป็นนิพจน์ใด ๆ ไม่จำเป็นต้องเกี่ยวข้องกับตัวแปรลูป ลูปหยุดทำงานเมื่อค่าของเงื่อนไขเป็น 0

ลูปจำเป็นต้องใช้เครื่องมือจัดฟันแบบ K & R (โดยเฉพาะตัวแปร Stroustrup ):

Count i while i-5 {
 ...
}

ดังที่ได้กล่าวมาแล้วตัวแปรลูปใช้ได้เฉพาะในลูปเท่านั้น พยายามอ้างอิงพวกเขาหลังจากนั้นทำให้เกิดข้อผิดพลาด

  1. Write <charcode>

เอาต์พุตอักขระเดี่ยวที่มีค่า ASCII / Unicode ที่กำหนดเป็น stdout รหัสสามารถเป็นนิพจน์ใด ๆ

  1. การแสดงออก

นิพจน์ที่ยืนด้วยตัวเองจะถูกประเมินและกำหนดกลับไปที่ตัวสะสม (ซึ่งสามารถเข้าถึงได้_) ดังนั้นเช่น3เป็นคำสั่งที่ตั้งสะสม 3 _ + 1เพิ่มการสะสม; และ_ * Nอ่านตัวละครและคูณตัวสะสมด้วยรหัสของมัน

หมายเหตุ: แอคคูมูเลเตอร์เป็นตัวแปรเดียวที่สามารถกำหนดให้โดยตรงได้ ตัวแปรลูปและNสามารถใช้ในการคำนวณ แต่ไม่สามารถแก้ไขได้

ตัวสะสมเริ่มต้น 0

การแสดงออก

นิพจน์สามารถรวมตัวอักษรจำนวนเต็มตัวแปรลูป ( a-z) _สำหรับแอคคูเลเตอร์และค่าพิเศษNที่อ่านอักขระและประเมินเป็นรหัสในแต่ละครั้งที่ใช้ หมายเหตุ:นี่หมายความว่าคุณจะได้รับช็อตเดียวเพื่ออ่านตัวละครแต่ละตัว ครั้งต่อไปที่คุณใช้Nคุณจะอ่านอีกครั้ง

ผู้ประกอบการคือ:

  • +, ส่วนที่เพิ่มเข้าไป
  • -การลบ การปฏิเสธเป็นอันขาด
  • *การคูณ
  • /หารด้วยจำนวนเต็ม
  • %, โมดูโล่
  • ^การยกกำลัง

สามารถใช้วงเล็บในการบังคับใช้ลำดับความสำคัญของการดำเนินการ อักขระอื่นใดในนิพจน์คือข้อผิดพลาดทางไวยากรณ์

ช่องว่างและความคิดเห็น

ช่องว่างนำหน้าและต่อท้ายจะถูกละเว้น ช่องว่างในส่วนหัวของลูปจะต้องตรงตามที่แสดงโดยมีช่องว่างเดียวระหว่างส่วนหัวของลูปและการเปิดวงเล็บปีกกาเช่นกัน ช่องว่างภายในนิพจน์เป็นตัวเลือก

# เริ่มความคิดเห็นบรรทัดเดียว

Input / Output

Acc !! คาดว่าอักขระบรรทัดเดียวเป็นอินพุต ตัวท่านแต่ละคนสามารถเรียกดูได้ในลำดับและ charcode Nของประมวลผลโดยใช้ การพยายามอ่านอักขระตัวสุดท้ายของบรรทัดทำให้เกิดข้อผิดพลาด ตัวละครสามารถส่งออกโดยการส่งผ่านรหัสเพื่อWriteคำสั่ง

ล่าม

ล่าม (เขียนใน Python 3) แปลAcc !! รหัสเป็น Python และexecมัน

import re, sys

def main():
    if len(sys.argv) != 2:
        print("Please supply a filename on the command line.", file=sys.stderr)
        return
    codeFile = sys.argv[1]
    with open(codeFile) as f:
        code = f.readlines()
    code = translate(code)
    exec(code, {"inputStream": (ord(char) for char in input())})

def translate(accCode):
    indent = 0
    loopVars = []
    pyCode = ["_ = 0"]
    for lineNum, line in enumerate(accCode):
        if "#" in line:
            # Strip comments
            line = line[:line.index("#")]
        line = line.strip()
        if not line:
            continue
        lineNum += 1
        if line == "}":
            if indent:
                loopVar = loopVars.pop()
                pyCode.append(" "*indent + loopVar + " += 1")
                indent -= 1
                pyCode.append(" "*indent + "del " + loopVar)
            else:
                raise SyntaxError("Line %d: unmatched }" % lineNum)
        else:
            m = re.fullmatch(r"Count ([a-z]) while (.+) \{", line)
            if m:
                expression = validateExpression(m.group(2))
                if expression:
                    loopVar = m.group(1)
                    pyCode.append(" "*indent + loopVar + " = 0")
                    pyCode.append(" "*indent + "while " + expression + ":")
                    indent += 1
                    loopVars.append(loopVar)
                else:
                    raise SyntaxError("Line %d: invalid expression " % lineNum
                                      + m.group(2))
            else:
                m = re.fullmatch(r"Write (.+)", line)
                if m:
                    expression = validateExpression(m.group(1))
                    if expression:
                        pyCode.append(" "*indent
                                      + "print(chr(%s), end='')" % expression)
                    else:
                        raise SyntaxError("Line %d: invalid expression "
                                          % lineNum
                                          + m.group(1))
                else:
                    expression = validateExpression(line)
                    if expression:
                        pyCode.append(" "*indent + "_ = " + expression)
                    else:
                        raise SyntaxError("Line %d: invalid statement "
                                          % lineNum
                                          + line)
    return "\n".join(pyCode)

def validateExpression(expr):
    "Translates expr to Python expression or returns None if invalid."
    expr = expr.strip()
    if re.search(r"[^ 0-9a-z_N()*/%^+-]", expr):
        # Expression contains invalid characters
        return None
    elif re.search(r"[a-zN_]\w+", expr):
        # Expression contains multiple letters or underscores in a row
        return None
    else:
        # Not going to check validity of all identifiers or nesting of parens--
        # let the Python code throw an error if problems arise there
        # Replace short operators with their Python versions
        expr = expr.replace("^", "**")
        expr = expr.replace("/", "//")
        # Replace N with a call to get the next input character
        expr = expr.replace("N", "inputStream.send(None)")
        return expr

if __name__ == "__main__":
    main()

วิธีการแก้

การล่มสลายของAccดั้งเดิม! เป็นตัวแปรลูปที่ยังคงสามารถเข้าถึงได้นอกลูปของพวกเขา สิ่งนี้อนุญาตให้บันทึกสำเนาของตัวสะสมซึ่งทำให้การแก้ปัญหาง่ายเกินไป

ที่นี่โดยไม่มีรูลูปนี้(ขออภัย) เรามีเพียงตัวสะสมเพื่อจัดเก็บข้อมูล อย่างไรก็ตามในการแก้ปัญหาเราจำเป็นต้องเก็บค่าที่มีขนาดใหญ่สี่ค่าโดยพลการ 1การแก้ปัญหา: แทรกบิตของพวกเขาและเก็บหมายเลขชุดผลลัพธ์ในการสะสม ตัวอย่างเช่นค่าตัวสะสม 6437 จะเก็บข้อมูลต่อไปนี้ (โดยใช้บิตลำดับต่ำสุดเป็นแฟล็กบิตเดียว):

1100100100101  Binary representation of accumulator
321032103210F  Key

The flag is 1 and the four numbers are
Number 0: 010 = 2
Number 1: 001 = 1
Number 2: 100 = 4
Number 3: 110 = 6

เราสามารถเข้าถึงบิตใด ๆ ของจำนวนใด ๆ โดยการหารสะสมด้วยอำนาจที่เหมาะสมของ 2, mod 2 นี้ยังช่วยให้การตั้งค่าหรือพลิกแต่ละบิต

ในระดับมาโครอัลกอริธึมจะวนไปที่ตัวเลขที่เป็นเลขยูนารีในอินพุต มันอ่านค่าเป็นตัวเลข 0 จากนั้นทำขั้นตอนวิธีการเรียงลำดับฟองเพื่อวางไว้ในตำแหน่งที่เหมาะสมเมื่อเทียบกับตัวเลขสามตัวอื่น ๆ ในที่สุดมันจะทิ้งค่าที่เหลืออยู่ในหมายเลข 0 เนื่องจากมันมีค่าน้อยที่สุดในสี่ในขณะนี้และจะไม่ใหญ่เป็นอันดับสาม เมื่อลูปจบลงหมายเลข 1 จะใหญ่เป็นอันดับสามดังนั้นเราจะละทิ้งผู้อื่นและส่งออก

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

ฉันสงสัยว่าAcc !! ทัวริงสมบูรณ์ แต่ฉันไม่แน่ใจว่าฉันต้องการไปที่ปัญหาในการพิสูจน์

นี่คือทางออกของฉันด้วยความคิดเห็น:

# Read and process numbers until the double 0

Count y while N-48 {
    # Read unary number and store it (as binary) in number 0
    # The above loop header consumed the first 1, so we need to add 1 to number 0

    _ + 2

    # Increment number 0 for each 1 in input until next 0

    Count z while N-48 {
        # In this context, the flag indicates a need to carry; set it to 1
        _ - _%2 + 1

        # While carry flag is set, increment the next bit in line
        Count i while _%2 {
            # Set carry flag to 1 if i'th bit is 1, 0 if it's 0
            # Set i'th bit to 1 if it was 0, 0 if it was 1
            _ - _%2 + _/2^(i*4+1)%2 + (-1)^(_/2^(i*4+1)%2)*2^(i*4+1)
        }
    }

    # Bubble number 0 upwards

    Count n while n-3 {
        # The flag (rightmost bit of accumulator) needs to become 1 if we want to swap
        # numbers (n) and (n+1) and 0 if we don't
        # Iterate over bit-groups of accumulator, RTL
        Count i while _/2^(i*4+1) {
            # Adjust the flag as follows:
            # _/2^(i*4+n+1)%4 is the current bit of number (n+1) followed by the current
            # bit of number (n), a value between 0 and 3
            # - If this quantity is 1 (01), number (n) is bigger so far; set flag to 1
            # - If this quantity is 2 (10), number (n+1) is bigger so far; set flag to 0
            # - If this quantity is 0 (00) or 3 (11), the two bits are the same; keep
            #   current value of flag
            _ + (_/2^(i*4+n+1)%4%3 + 1)/2*(_/2^(i*4+n+1)%4%3%2 - _%2)
        }

        # Now swap the two if the flag is 1
        Count i while (_%2)*(_/2^(i*4+1)) {
            # _/2^(i*4+n+1)%2 is the current bit of number (n)
            # _/2^(i*4+n+2)%2 is the current bit of number (n+1)
            _ - (_/2^(i*4+n+1)%2)*2^(i*4+n+1) - (_/2^(i*4+n+2)%2)*2^(i*4+n+2) + (_/2^(i*4+n+2)%2)*2^(i*4+n+1) + (_/2^(i*4+n+1)%2)*2^(i*4+n+2)
        }
    }

    # Discard number 0, setting it to all zeros for the next iteration
    Count i while _/2^(i*4+1) {
        _ - _/2^(i*4+1)%2*2^(i*4+1)
    }
}

# Once the loop is over, all input has been read and the result is in number 1
# Divide by 2 to get rid of flag bit

_ / 2

# Zero out numbers 2 and 3

Count i while _/2^(i*4) {
    _ - _/2^(i*4+2)%2*2^(i*4+2)
}

Count i while _/2^(i*4) {
    _ - _/2^(i*4+3)%2*2^(i*4+3)
}

# Move bits of number 1 down to their final locations

Count i while _/2^i {
    _ - _/2^(i*4+1)%2*2^(i*4+1) + _/2^(i*4+1)%2*2^i
}

# _ now contains the correct answer in decimal; to output in unary:

Count z while z-_ {
    Write 49
}

1ตามข้อมูลจำเพาะของคำถามต้องสนับสนุนค่าสูงสุด 1 ล้านเท่านั้น ฉันดีใจที่ไม่มีใครใช้ประโยชน์จากสิ่งนั้นเพื่อการแก้ปัญหาที่ง่ายขึ้น - แม้ว่าฉันจะไม่แน่ใจว่าคุณจะทำการเปรียบเทียบอย่างไร


LOL @ the Bill the Cat รูป
สปาเก็ตตี้

7

Picofuck (ปลอดภัย)

Picofuck คล้ายกับSmallfuck มันทำงานบนเทปไบนารีซึ่งไม่ได้ผูกไว้ทางด้านขวาผูกไว้ทางซ้าย มันมีคำสั่งดังต่อไปนี้:

  • > เลื่อนตัวชี้ไปทางขวา

  • <เลื่อนตัวชี้ไปทางซ้าย หากตัวชี้ตกจากเทปโปรแกรมจะหยุดทำงาน

  • * พลิกบิตที่ตัวชี้

  • (ถ้าบิตที่ตัวชี้เป็น0ข้ามไปยังถัดไป)

  • )ไม่ทำอะไรเลย - วงเล็บใน Picofuck คือifบล็อกไม่ใช่whileลูป

  • .เขียนไป stdout บิตที่ชี้เป็น ASCII หรือ01

  • ,อ่านจาก stdin จนกว่าเราจะพบ0หรือหรือ1เก็บสิ่งนี้ไว้ในบิตที่ตัวชี้

การห่อรหัส Picofuck - เมื่อถึงจุดสิ้นสุดของโปรแกรมมันจะดำเนินต่อไปตั้งแต่ต้น

นอกจากนี้ Picofuck จะปิดวงเล็บที่ซ้อนกัน วงเล็บที่ปรากฏในโปรแกรม Picofuck ต้องสลับกันระหว่าง(และ)เริ่มต้นด้วยและลงท้ายด้วย()

ล่าม

เขียนใน Python 2.7

การใช้งาน: python picofuck.py <source_file>

import sys

def interpret(code):
    # Ensure parentheses match and are not nested.
    in_if_block = False
    for c in code:
        if c == '(':
            if in_if_block:
                print "NESTED IFS DETECTED!!!!!"
                return
            in_if_block = True
        elif c == ')':
            if not in_if_block:
                print "Unmatched parenthesis"
                return
            in_if_block = False
    if in_if_block:
        print "Unmatched parenthesis"
        return


    code_ptr = 0
    array = [0]
    ptr = 0

    while 1:
        command = code[code_ptr]
        if command == '<':
            if ptr == 0:
                break
            ptr -= 1
        elif command == '>':
            ptr += 1
            if ptr == len(array):
                array.append(0)
        elif command == '*':
            array[ptr] = 1-array[ptr]
        elif command == '(':
            if array[ptr] == 0:
                while code[code_ptr] != ')':
                    code_ptr = (code_ptr + 1) % len(code)
        elif command == ',':
            while True:
                c = sys.stdin.read(1)
                if c in ['0','1']:
                    array[ptr] = int(c)
                    break
        elif command == '.':
            sys.stdout.write(str(array[ptr]))
        code_ptr = (code_ptr+1)%len(code)

if __name__ == "__main__":
    with open(sys.argv[1]) as source_file:
        code = source_file.read()
    interpret(code)

วิธีการแก้

โปรแกรม python 2.7 ต่อไปนี้จะแสดงผลลัพธ์ของฉันซึ่งสามารถพบได้ที่นี่

ฉันอาจแก้ไขโพสต์นี้ในภายหลังด้วยคำอธิบายที่ละเอียดยิ่งขึ้นเกี่ยวกับวิธีการทำงานของมัน แต่ปรากฎว่า Picofuck นั้นเสร็จสิ้นในทัวริง

states = {
    "SETUP":(
        "*>",
        "GET_NUMBER",
        "GET_NUMBER"
    ),

    "GET_NUMBER":(
        ",",
        "CHANGE_A",
        "PREPARE_PRINT_C"
    ),

    "GET_DIGIT":(
        ",",
        "CHANGE_A",
        "GOT_DIGIT"
    ),

    "GOT_DIGIT":(
        ">>>>",
        "GO_BACK",
        "GO_BACK"
    ),

    "CHANGE_A":(
        ">",
        "CHANGE_B",
        "SET_A"
    ),

    "SET_A":(
        "*>>>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CHANGE_B":(
        ">",
        "CHANGE_C",
        "SET_B"
    ),

    "SET_B":(
        "*>>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CHANGE_C":(
        ">",
        "CONTINUE_GET_NUMBER",
        "SET_C"
    ),

    "SET_C":(
        "*>>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "CONTINUE_GET_NUMBER":(
        ">>",
        "GET_DIGIT",
        "GET_DIGIT"
    ),

    "GO_BACK":(
        "<<<<<",
        "FINISH_GO_BACK",
        "GO_BACK"
    ),

    "FINISH_GO_BACK":(
        ">",
        "GET_NUMBER",
        "GET_NUMBER"
    ),

    "PREPARE_PRINT_C":(
        ">>>",
        "PRINT_C",
        "PRINT_C"
    ),

    "PRINT_C":(
        ".>>>>>",
        "PRINT_C",
        "TERMINATE"
    ),

    "TERMINATE":(
        "<",
        "TERMINATE",
        "TERMINATE"
    ),
}

def states_to_nanofuck(states,start_state):
    state_list = list(states)
    state_list.remove(start_state)
    state_list.insert(0,start_state)

    states_by_index = []
    for i,state in enumerate(state_list):
        commands, next1, next0 = states[state]
        states_by_index.append((commands,state_list.index(next1),state_list.index(next0)))


    # setup first state
    fragments = ['*(*>>>>>*<<<<<)>>>>>']

    # reset states that don't match
    for index in range(len(states_by_index)):
        for bool in range(2):
            # at state_0_0
            state_dist = index*3 + bool
            # move state to curstate
            fragments.append('>'*state_dist)
            fragments.append('(*')
            fragments.append(  '<'*state_dist)
            fragments.append(  '<<*>>')
            fragments.append(  '>'*state_dist)
            fragments.append(')')
            fragments.append('<'*state_dist)

            # go to arr
            fragments.append('<<<')

            if bool == 0:
                #flip arr
                fragments.append('*')

            # compute match = arr & curstate
            fragments.append('(>)(>*<)<(<)>')

            if bool == 0:
                #flip arr
                fragments.append('*')

            # reset curstate
            fragments.append('>(*)')

            # move match to matchstate, go back to state_0_0
            matchstate_dist = index*3 + 2
            fragments.append('>(*>')
            fragments.append(  '>'*matchstate_dist)
            fragments.append(  '*')
            fragments.append(  '<'*matchstate_dist)
            fragments.append('<)>')

    #fragments.append('|')

    # do the commands of the matching state
    for index,state in enumerate(states_by_index):
        for bool in range(2):
            # at state_0_0
            matchstate_dist = index*3 + 2
            # move matchstate to curstate
            fragments.append('>'*matchstate_dist)
            fragments.append('(*')
            fragments.append(  '<'*matchstate_dist)
            fragments.append(  '<<*>>')
            fragments.append(  '>'*matchstate_dist)
            fragments.append(')')
            fragments.append('<'*matchstate_dist)

            # if curstate, reset curstate
            fragments.append('<<(*')

            # go to arr
            fragments.append('<')

            # do commands
            commands,next1,next0 = state
            for c in commands:
                if c in '<>':
                    fragments.append(c*(3*len(states_by_index)+5))
                else:
                    fragments.append(c)

            # go to state_0_0
            fragments.append('>>>')

            # set next states
            for dist in [next0*3, next1*3+1]:
                fragments.append('>'*dist)
                fragments.append('*')
                fragments.append('<'*dist)

            # go to curstate
            fragments.append('<<')

            # end if
            fragments.append(')')

            # go to state_0_0
            fragments.append('>>')


    # go back to setup and set it
    fragments.append('<<<<<*')

    code = ''.join(fragments)

    return code



print states_to_nanofuck(states, "SETUP")

2
รอเกือบ 2 ปีแล้วหรือยัง?
CalculatorFeline

เพียงแค่ FYI ลิงค์ที่คุณให้ไว้ตอนนี้จะตาย '
Conor O'Brien

ลิงค์ต้องดาวน์โหลดและฉันขี้เกียจเกินไป กรุณาแก้ไข
CalculatorFeline

@CalculatorFeline เป็น 13KB ซึ่งง่ายต่อการจัดการเช่นเดียวกับการดาวน์โหลด
mbomb007

7

PQRS - ปลอดภัย! ให้บริการโซลูชั่น /

ข้อมูลพื้นฐานเกี่ยวกับ

คำแนะนำโดยนัยทั้งหมดมีตัวถูกดำเนินการที่อยู่หน่วยความจำสี่ตัว:

P₀ Q₀ R₀ S₀
P₁ Q₁ R₁ S₁
...
Pᵥ₋₁ Qᵥ₋₁ Rᵥ₋₁ Sᵥ₋₁

ที่ไหนvคือขนาดของหน่วยความจำใน quartets

Pᵢ, Qᵢ, Rᵢ, Sᵢจะมีการเซ็นจำนวนเต็มขนาดพื้นเมืองของเครื่อง (เช่น 16, 32 หรือ 64 บิต) ซึ่งเราจะดูเป็นคำพูด

สำหรับแต่ละวงสี่iการดำเนินการโดยนัยที่มีการ[]บอกทางอ้อมคือ:

if (([Pᵢ] ← [Qᵢ] − [Rᵢ]) ≤ 0) go to Sᵢ else go to Pᵢ₊₁

สังเกตได้ว่า Subleqเป็นส่วนหนึ่งของPQRS

Subleq ได้รับการพิสูจน์แล้วว่าสมบูรณ์ดังนั้น PQRSก็น่าจะเสร็จสมบูรณ์เช่นกัน!

โครงสร้างโปรแกรม

PQRSกำหนดส่วนหัวเริ่มต้นดังนี้:

H₀ H₁ H₂ H₃ H₄ H₅ H₆ H₇

H₀ H₁ H₂ H₃เป็นคำสั่งแรกP₀ Q₀ R₀ S₀เสมอH₀จะH₃ต้องมีการกำหนดที่โหลด

PQRSมีพื้นฐาน I / O แต่เพียงพอสำหรับความท้าทาย

H₄ H₅: เมื่อเริ่มโปรแกรมจะอ่านH₅อักขระ ASCII สูงสุดจากอินพุตมาตรฐานและบันทึกเป็นคำที่ดัชนีH₄เป็นต้นไปH₄และ H₅จำเป็นต้องกำหนดเวลาโหลด หลังจากอ่านแล้วH₅จะถูกตั้งค่าตามจำนวนตัวอักษรที่อ่าน (และคำที่บันทึก)

H₆ H₇: เมื่อสิ้นสุดโปรแกรม, เริ่มต้นที่ดัชนีH₆, มันจะพิมพ์ไบต์ทั้งหมดที่ประกอบไปด้วยH₇คำว่าเอาต์พุตมาตรฐานเป็นอักขระ ASCIIH₆และH₇จำเป็นต้องกำหนดไว้ก่อนที่โปรแกรมจะสิ้นสุด ไบต์ Null '\0'ในเอาต์พุตจะถูกข้ามไป

การสิ้นสุด

การสิ้นสุดทำได้โดยการกำหนดSᵢขอบเขตi < 0หรือi ≥ vหรือ

เล่นกล

quartets Pᵢ Qᵢ Rᵢ Sᵢไม่จำเป็นต้องสอดคล้องหรือลำดับสาขาจะได้รับอนุญาตในช่วงเวลาย่อยสี่

PQRSมีทางอ้อมดังนั้นซึ่งแตกต่างจาก Subleq มีความยืดหยุ่นเพียงพอที่จะใช้รูทีนย่อย

รหัสสามารถแก้ไขได้ด้วยตนเอง!

ล่าม

ล่ามเขียนด้วยภาษา C:

#include <stdlib.h>
#include <stdio.h>

// The "architecture"
enum {P, Q, R, S, START_OF_INPUT, LENGTH_OF_INPUT, START_OF_OUTPUT, LENGTH_OF_OUTPUT};
const int NEXT = S + 1;

// Recommend optimized!
#define OPTIMIZED

#ifdef PER_SPECS
// This may not work on all OSes and architectures - just too much memory needed!
const int K = 1002000200;
#else // OPTIMIZED
// This provides enough space to run the test cases with challenge-optimized.pqrs
const int K = 5200;
#endif

int main(int argc, char *argv[])
{
    int i, *M;
    char *p;
    FILE *program;

    // Allocate enough memory
    M = calloc(K, sizeof(int));

    // Load the program
    for (i = 0, program = fopen(argv[1], "r"); i < K && !feof(program); i++)
        if (!fscanf(program, "%d", M + i))
            break;
    fclose(program);

    // Read in the input
    for (i = 0; i < M[LENGTH_OF_INPUT] && !feof(stdin); i++)
    {
        int c = fgetc(stdin);
        if (c != EOF)
            M[M[START_OF_INPUT] + i] = c;
        else
            break;
    }
    M[LENGTH_OF_INPUT] = i;

    // Execute until terminated
    for (i = 0; i >= 0 && i < K; )
        i = (M[M[P + i]] = M[M[Q + i]] - M[M[R + i]]) <= 0? M[S + i]: i + NEXT;

    // Write the output
    for (i = 0, p = (char *)(M + M[START_OF_OUTPUT]); i < M[LENGTH_OF_OUTPUT] * sizeof(int); i++)
        // Ignore '\0'
        if (p[i])
            fputc(p[i], stdout);

    // Done
    free(M);

    return 0;
}

หากต้องการใช้ให้บันทึกข้างต้นเป็น pqrs.c แล้วคอมไพล์:

gcc -o pqrs pqrs.c

โปรแกรมตัวอย่าง

Echos สามารถป้อนอักขระได้สูงสุด 40 ตัวนำหน้าด้วย 'PQRS-'

8 8 8 -1 14 40 9 45 0 80 81 82 83 45

หากต้องการเรียกใช้ให้บันทึกข้างต้นเป็นecho.pqrsแล้ว:

$ ./prqs echo.pqrs
greetings[enter]
[ctrl-D]
PQRS-greetings

ใช้กรณีทดสอบ:

$ ./pqrs challenge-optimized.pqrs < test-1.txt
1

$ ./pqrs challenge-optimized.pqrs < test-2.txt
11111111111111111

$ ./pqrs challenge-optimized.pqrs < test-3.txt
[lots of ones!]

$ ./pqrs challenge-optimized.pqrs < test-3.txt | wc
0       1     773

กรณีทดสอบทั้งหมดทำงานได้อย่างรวดเร็วเช่น <500 ms

ความท้าทาย

PQRSนั้นถือว่ามีความเสถียรดังนั้นความท้าทายจึงเริ่มต้นขึ้นในระหว่างปี 2558-2553 13:00 น. และสิ้นสุดวันที่ 2015-11-08 13:00, เวลาใน UTC

โชคดี!

วิธีการแก้

ภาษานั้นค่อนข้างคล้ายกับภาษาที่ใช้ใน"Baby"ซึ่งเป็นเครื่องดิจิตอลอิเล็กทรอนิกสเตชั่นเครื่องแรกของโลก ในหน้านั้นเป็นโปรแกรมที่จะค้นหาตัวประกอบจำนวนเต็มสูงสุดในหน่วยความจำน้อยกว่า 32 คำ (CRT!)!

ฉันพบว่าการเขียนโซลูชันเพื่อให้สอดคล้องกับข้อกำหนดไม่เข้ากันกับระบบปฏิบัติการและเครื่องที่ฉันใช้ (อนุพันธ์ Linux Ubuntu บนฮาร์ดแวร์ที่เก่ากว่าเล็กน้อย) มันเป็นเพียงการร้องขอหน่วยความจำมากกว่าที่มีอยู่และการถ่ายโอนข้อมูลหลัก บนระบบปฏิบัติการที่มีการจัดการหน่วยความจำเสมือนขั้นสูงหรือเครื่องที่มีหน่วยความจำอย่างน้อย 8 GB คุณอาจเรียกใช้โซลูชันตามข้อมูลจำเพาะ ฉันได้ให้บริการโซลูชั่นทั้งสอง

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

; ANNOTATED PQRS ASSEMBLER CODE
; MINIMAL SIZED BUFFERS TO RUN THE TEST CASES

;OFFSET   LABEL       P-OP        Q-OP        R-OP        S-OP
0                     TEMP        ZERO        ZERO        L1

; INPUT AND OUTPUT LOCATIONS AND SIZES
4                     INPUT       4000        
6         L0:         OUTPUT      1000        

; GET CURRENT INPUT
8         L1:         TEMP        INPUT       ASCII_ZERO  L2
12                    SUM         SUM         INC         IGNORE
16                    L1+1        L1+1        INC         IGNORE
20                    TEMP        ZERO        ZERO        L1

; CHECK IF END OF NUMBERS
24        L2:         NUMBERS     SUM         ZERO        L3

; ADVANCE TO NEXT NUMBER
28                    L2          L2          INC         IGNORE

; ADVANCE COUNT
32                    COUNT       COUNT       INC         IGNORE
36                    L1+1        L1+1        INC         IGNORE

; CLEAR SUM AND GO BACK
40                    SUM         ZERO        ZERO        L1

; SORT NUMBERS                
44        L3:         P           NUMBERS     ZERO        LA
48        L4:         Q           NUMBERS+1   ZERO        L9

; COMPARE                
52                    TEMP        Q           P           L8

; SWAP IF OUT OF ORDER
56                    L5+1        L3+1        ZERO        IGNORE
60                    L6          L3+1        ZERO        IGNORE
64                    L6+1        L4+1        ZERO        IGNORE
68                    L7          L4+1        ZERO        IGNORE
72        L5:         TEMP        P           ZERO        IGNORE
76        L6:         P           Q           ZERO        IGNORE
80        L7:         Q           TEMP        ZERO        IGNORE

; INCREMENT INNER INDEX
84        L8:         L4+1        L4+1        INC         IGNORE
88                    TEMP        ZERO        ZERO        L3

; INCREMENT OUTER INDEX AND RESET INNER INDEX
92        L9:         L3+1        L3+1        INC         IGNORE
96                    L4+1        L3+1        INC         IGNORE
100                   TEMP        ZERO        ZERO        L3

; OUTPUT THIRD LARGEST NUMBER
104                   L0+1        NUMBERS+2   ZERO        IGNORE
108       LA:         TEMP        NUMBERS+2   ZERO        EXIT
112       LB:         OUTPUT      ASCII_ONE   ZERO        IGNORE
116                   LB          LB          INC         IGNORE
120                   NUMBERS+2   NUMBERS+2   DEC         EXIT
124                   TEMP        ZERO        ZERO        LA

; SAFETY LOOP – JUST IN CASE IGNORE DOESN'T WORK AS PLANNED!
128       IGNORE:     TEMP        ZERO        ZERO        IGNORE

; CONSTANTS
132       ZERO:        0
133       INC:        -1
134       DEC:         1
135       ASCII_ZERO: 48
136       ASCII_ONE:  49

; VARIABLES
137       TEMP:       [1]
138       SUM:        [1]
139       COUNT:      [1]
140       P:          [1]
141       Q:          [1]

; WORKING SPACE
142       NUMBERS:    [10]

; I/O SPACE
152       INPUT:      [4000]
4152      OUTPUT:     [1000]
5152

สิ่งที่มันทำคือการแยกวิเคราะห์อินพุตแปลงยูนารีเป็นไบนารี่จากนั้นเรียงลำดับฟองสบู่บนตัวเลขด้วยค่าในลำดับที่ลดลงจากนั้นก็ส่งออกค่าที่ใหญ่ที่สุดอันดับสามโดยการแปลงไบนารี่กลับเป็นเอก

โปรดทราบว่าINC(เพิ่มขึ้น) เป็นลบและDEC(ลดลง) เป็นบวก! เมื่อมีการใช้L#หรือL#+1เป็นP-หรือQ-OPสิ่งที่เกิดขึ้นคือมันมีการปรับปรุงตัวชี้: การเพิ่มขึ้นลดลงการแลกเปลี่ยน ฯลฯ แอสเซมเบลอร์ได้รวบรวมมือเพื่อPQRSโดยแทนที่ป้ายที่มีการชดเชย ด้านล่างนี้เป็นโซลูชันที่ปรับให้เหมาะสมPQRS :

137 132 132 8
152 4000
4152 1000
137 152 135 24
138 138 133 128
9 9 133 128
137 132 132 8
142 138 132 44
24 24 133 128
139 139 133 128
9 9 133 128
138 132 132 8
140 142 132 108
141 143 132 92
137 141 140 84
73 45 132 128
76 45 132 128
77 49 132 128
80 49 132 128
137 140 132 128
140 141 132 128
141 137 132 128
49 49 133 128
137 132 132 44
45 45 133 128
49 45 133 128
137 132 132 44
7 144 132 128
137 144 132 -1
4152 136 132 128
112 112 133 128
144 144 134 -1
137 132 132 108
137 132 132 128
0
-1
1
48
49

สามารถบันทึกรหัสข้างต้นchallenge-optimized.pqrsเพื่อใช้ในกรณีทดสอบ

เพื่อความสมบูรณ์นี่คือแหล่งที่มาตามรายละเอียด:

; ANNOTATED PQRS ASSEMBLER CODE
; FULL SIZED BUFFERS TO RUN ACCORDING TO SPECS

;OFFSET   LABEL       P-OP        Q-OP        R-OP        S-OP
0                     TEMP        ZERO        ZERO        L1

; INPUT AND OUTPUT LOCATIONS AND SIZES
4                     INPUT       10^9        
6         L0:         OUTPUT      10^6        

; GET CURRENT INPUT
8         L1:         TEMP        INPUT       ASCII_ZERO  L2
12                    SUM         SUM         INC         IGNORE
16                    L1+1        L1+1        INC         IGNORE
20                    TEMP        ZERO        ZERO        L1

; CHECK IF END OF NUMBERS
24        L2:         NUMBERS     SUM         ZERO        L3

; ADVANCE TO NEXT NUMBER
28                    L2          L2          INC         IGNORE

; ADVANCE COUNT
32                    COUNT       COUNT       INC         IGNORE
36                    L1+1        L1+1        INC         IGNORE

; CLEAR SUM AND GO BACK
40                    SUM         ZERO        ZERO        L1

; SORT NUMBERS                
44        L3:         P           NUMBERS     ZERO        LA
48        L4:         Q           NUMBERS+1   ZERO        L9

; COMPARE                
52                    TEMP        Q           P           L8

; SWAP IF OUT OF ORDER
56                    L5+1        L3+1        ZERO        IGNORE
60                    L6          L3+1        ZERO        IGNORE
64                    L6+1        L4+1        ZERO        IGNORE
68                    L7          L4+1        ZERO        IGNORE
72        L5:         TEMP        P           ZERO        IGNORE
76        L6:         P           Q           ZERO        IGNORE
80        L7:         Q           TEMP        ZERO        IGNORE

; INCREMENT INNER INDEX
84        L8:         L4+1        L4+1        INC         IGNORE
88                    TEMP        ZERO        ZERO        L3

; INCREMENT OUTER INDEX AND RESET INNER INDEX
92        L9:         L3+1        L3+1        INC         IGNORE
96                    L4+1        L3+1        INC         IGNORE
100                   TEMP        ZERO        ZERO        L3

; OUTPUT THIRD LARGEST NUMBER
104                   L0+1        NUMBERS+2   ZERO        IGNORE
108       LA:         TEMP        NUMBERS+2   ZERO        EXIT
112       LB:         OUTPUT      ASCII_ONE   ZERO        IGNORE
116                   LB          LB          INC         IGNORE
120                   NUMBERS+2   NUMBERS+2   DEC         EXIT
124                   TEMP        ZERO        ZERO        LA

; SAFETY LOOP – JUST IN CASE IGNORE DOESN'T WORK AS PLANNED!
128       IGNORE:     TEMP        ZERO        ZERO        IGNORE

; CONSTANTS
132       ZERO:        0
133       INC:        -1
134       DEC:         1
135       ASCII_ZERO: 48
136       ASCII_ONE:  49

; VARIABLES
137       TEMP:       [1]
138       SUM:        [1]
139       COUNT:      [1]
140       P:          [1]
141       Q:          [1]

; WORKING SPACE
142       NUMBERS:    [10^6]

; I/O SPACE
1000142   INPUT:      [10^9]
1001000142 OUTPUT:    [10^6]
1002000142

และการแก้ปัญหา:

137 132 132 8
1000142 1000000000
1001000142 1000000
137 1000142 135 24
138 138 133 128
9 9 133 128
137 132 132 8
142 138 132 44
24 24 133 128
139 139 133 128
9 9 133 128
138 132 132 8
140 142 132 108
141 143 132 92
137 141 140 84
73 45 132 128
76 45 132 128
77 49 132 128
80 49 132 128
137 140 132 128
140 141 132 128
141 137 132 128
49 49 133 128
137 132 132 44
45 45 133 128
49 45 133 128
137 132 132 44
7 144 132 128
137 144 132 -1
1001000142 136 132 128
112 112 133 128
144 144 134 -1
137 132 132 108
137 132 132 128
0
-1
1
48
49

ในการเรียกใช้ข้างต้นคุณจะต้องแสดงความคิดเห็น#define OPTIMIZEDและเพิ่ม#define PER_SPECSในpqrs.cและคอมไพล์

นี่เป็นความท้าทายที่ยิ่งใหญ่ - สนุกกับการออกกำลังกายทางจิตจริงๆ! พาฉันกลับไปที่ผู้ประกอบเครื่อง 6502 วัน ...

ถ้าฉันจะใช้PQRSเป็นภาษาการเขียนโปรแกรม "ของจริง" ฉันอาจจะเพิ่มโหมดเพิ่มเติมสำหรับการเข้าถึงโดยตรงและโดยอ้อมสองเท่านอกเหนือจากการเข้าถึงทางอ้อมเช่นเดียวกับตำแหน่งสัมพัทธ์และตำแหน่งที่แน่นอน


3
คุณควรเตรียมวิธีแก้ปัญหาก่อนโพสต์
feersum

1
ใช่การแก้ปัญหาพร้อมแล้ว ฉันเข้าใจว่ามีข้อสงสัยบางอย่างเพราะภาษานั้นใช้งานได้ยากจริงๆสำหรับผู้ที่ต้องการดูตัวอย่างฉันสามารถส่งไปให้คุณได้หากคุณสัญญาว่าจะไม่เปิดเผยก่อนจบการแข่งขัน!

6

สังกะสีแตก! โดย @Zgarb

นอกจากนี้ยังมีที่GitHub

คุณต้องมีโผ 1.12 และผับ เพียงรันpub getเพื่อดาวน์โหลดการพึ่งพาเท่านั้นซึ่งเป็นไลบรารีการแยกวิเคราะห์

นี่คือการหวังว่าจะใช้เวลานานกว่า 30 นาที! โอ้

ภาษา

สังกะสีมุ่งเน้นไปที่การนิยามตัวดำเนินการใหม่ คุณสามารถกำหนดตัวดำเนินการทั้งหมดในภาษาใหม่ได้อย่างง่ายดาย!

โครงสร้างของโปรแกรมสังกะสีทั่วไปดูเหมือนว่า:

let
<operator overrides>
in <expression>

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

การแสดงออก

ต่อไปนี้เป็นนิพจน์ที่ถูกต้องใน Zinc:

ตัวอักษร

สังกะสีสนับสนุนทุกตัวอักษรของจำนวนเต็มปกติเหมือนและ1-2

ตัวแปร

สังกะสีมีตัวแปร (เช่นภาษาส่วนใหญ่) หากต้องการอ้างอิงพวกเขาเพียงใช้ชื่อ ชอบภาษาส่วนใหญ่อีกครั้ง!

อย่างไรก็ตามมีตัวแปรพิเศษที่เรียกSว่าทำงานเหมือนของ Qพีท เมื่อคุณใช้มันครั้งแรกมันจะอ่านในบรรทัดจากอินพุตมาตรฐานและตีความมันเป็นชุดของตัวเลข ยกตัวอย่างเช่นสายการป้อนข้อมูลจะกลายเป็นชุด1234231{1, 2, 3, 4, 3, 2, 1}

โน๊ตสำคัญ!!! ในบางกรณีตัวอักษรที่ส่วนท้ายของการแทนที่โอเปอเรเตอร์จะถูกวิเคราะห์อย่างไม่ถูกต้องดังนั้นคุณต้องล้อมรอบด้วยวงเล็บ

การดำเนินงานไบนารี

สนับสนุนการดำเนินงานไบนารีต่อไปนี้:

  • นอกจากผ่าน:+1+1
  • ลบผ่าน:-1-1
  • การคูณทาง*: 2*2.
  • หารผ่าน/: 4/2.
  • ความเท่าเทียมกับ=: 3=3.

นอกจากนี้ยังสนับสนุนการดำเนินการ unary ต่อไปนี้ด้วย:

  • ความยาว:##x

ลำดับความสำคัญมีความสัมพันธ์ที่เหมาะสมเสมอ คุณสามารถใช้วงเล็บเพื่อแทนที่สิ่งนี้

ความเท่าเทียมกันและความยาวทำงานในชุดเท่านั้น เมื่อคุณพยายามรับความยาวของจำนวนเต็มคุณจะได้จำนวนของตัวเลขในการแทนค่าสตริง

กำหนดความเข้าใจ

เพื่อจัดการกับชุดสังกะสีได้กำหนดความเข้าใจ พวกเขามีลักษณะเช่นนี้:

{<variable>:<set><clause>}

ข้อเป็นทั้งประโยคเมื่อหรือข้อเรียง

ประโยคเมื่อ^<expression>ดูเหมือนว่า การแสดงออกหลังเครื่องหมายรูปหมวกจะต้องส่งผลให้จำนวนเต็ม การใช้คำสั่ง when จะรับเฉพาะองค์ประกอบในชุดซึ่งexpressionไม่ใช่ศูนย์ ภายในนิพจน์ตัวแปร_จะถูกตั้งค่าเป็นดัชนีปัจจุบันในชุด มันเทียบเท่ากับ Python นี้คร่าวๆ:

[<variable> for _, <variable> in enumerate(<set>) when <expression> != 0]

ข้อเรียงลำดับซึ่งมีลักษณะเหมือน$<expression>, <expression>เรียงลำดับจากมากไปน้อยชุดด้วยค่าของ มันเท่ากับ Python นี้:

sorted(<set>, key=lambda <variable>: <expression>)[::-1]

นี่คือตัวอย่างความเข้าใจ:

  • รับเฉพาะองค์ประกอบของเซตsที่เท่ากับ 5:

    {x:s^x=5}
    
  • จัดเรียงชุดsตามค่าหากองค์ประกอบของมันกำลังสอง:

    {x:s$x*x}
    

การแทนที่

การแทนที่โอเปอเรเตอร์ช่วยให้คุณกำหนดผู้ประกอบการใหม่ พวกเขามีลักษณะเช่นนี้:

<operator>=<operator>

หรือ:

<variable><operator><variable>=<expression>

ในกรณีแรกคุณสามารถกำหนดตัวดำเนินการให้เท่ากับตัวดำเนินการอื่น ตัวอย่างเช่นฉันสามารถกำหนด+ให้ลบจริงผ่าน:

+=-

เมื่อคุณทำสิ่งนี้คุณสามารถกำหนดโอเปอเรเตอร์ให้เป็นโอเปอเรเตอร์เวทมนตร์อีกครั้ง มีตัวดำเนินการวิเศษสองอย่าง:

  • joinใช้เวลาชุดและจำนวนเต็มและรวมเนื้อหาของชุด ยกตัวอย่างเช่นการเข้าร่วม{1, 2, 3}ด้วยจะมีผลในจำนวนเต็ม414243

  • cutยังใช้ชุดและจำนวนเต็มและจะแบ่งชุดที่เกิดขึ้นทุกจำนวน ใช้cutบน{1, 3, 9, 4, 3, 2}และ3จะสร้าง{{1}, {9, 4}, {2}}... แต่ใด ๆ {1, {9, 4}, 2}ชุดเดียวองค์ประกอบแบนดังนั้นผลที่ตามมาจะเป็นจริง

นี่คือตัวอย่างที่ให้คำจำกัดความใหม่แก่+โอเปอเรเตอร์join:

+=join

สำหรับกรณีหลังคุณสามารถกำหนดโอเปอเรเตอร์ให้เป็นนิพจน์ที่กำหนดใหม่ ตัวอย่างนี้กำหนดการดำเนินการบวกเพื่อเพิ่มค่าแล้วเพิ่ม 1:

x+y=1+:x+:y

แต่สิ่งที่+:? คุณสามารถต่อท้ายเครื่องหมายจุดคู่:กับตัวดำเนินการเพื่อใช้เวอร์ชันในตัว ตัวอย่างนี้ใช้ builtin +ผ่าน+:เพื่อเพิ่มตัวเลขเข้าด้วยกันจากนั้นเพิ่ม 1 (จำไว้ว่าทุกอย่างเชื่อมโยงกันได้)

การเอาชนะโอเปอเรเตอร์ความยาวจะมีลักษณะดังนี้:

#x=<expression>

โปรดทราบว่าการดำเนินการในตัวเกือบทั้งหมด (ยกเว้นความเท่าเทียมกัน) จะใช้ตัวดำเนินการความยาวนี้เพื่อกำหนดความยาวของชุด หากคุณกำหนดให้เป็น:

#x=1

ทุกส่วนของสังกะสีที่ทำงานในชุดยกเว้น=จะทำงานเฉพาะในองค์ประกอบแรกของชุดที่ได้รับ

การแทนที่หลายรายการ

คุณสามารถลบล้างโอเปอเรเตอร์หลายรายการโดยคั่นด้วยเครื่องหมายจุลภาค:

let
+=-,
*=/
in 1+2*3

การพิมพ์

คุณไม่สามารถพิมพ์สิ่งใดในสังกะสีโดยตรง ผลลัพธ์ของนิพจน์ต่อไปนี้inจะถูกพิมพ์ ค่าของชุดจะถูกต่อกับตัวคั่น ตัวอย่างเช่นใช้สิ่งนี้:

let
...
in expr

ถ้าexprเป็นชุด{1, 3, {2, 4}},1324จะถูกพิมพ์ไปที่หน้าจอทันทีที่โปรแกรมเสร็จสิ้น

วางมันทั้งหมดเข้าด้วยกัน

นี่คือโปรแกรมสังกะสีอย่างง่ายที่ดูเหมือนจะเพิ่ม2+2แต่ทำให้ผลลัพธ์เป็น 5:

let
x+y=1+:x+:y
in 1+2

ล่าม

สิ่งนี้ไปในbin/zinc.dart:

import 'package:parsers/parsers.dart';
import 'dart:io';

// An error.
class Error implements Exception {
  String cause;
  Error(this.cause);
  String toString() => 'error in Zinc script: $cause';
}


// AST.
class Node {
  Obj interpret(ZincInterpreter interp) => null;
}

// Identifier.
class Id extends Node {
  final String id;
  Id(this.id);
  String toString() => 'Id($id)';
  Obj interpret(ZincInterpreter interp) => interp.getv(id);
}

// Integer literal.
class IntLiteral extends Node {
  final int value;
  IntLiteral(this.value);
  String toString() => 'IntLiteral($value)';
  Obj interpret(ZincInterpreter interp) => new IntObj(value);
}

// Any kind of operator.
class Anyop extends Node {
  void set(ZincInterpreter interp, OpFuncType func) {}
}

// Operator.
class Op extends Anyop {
  final String op;
  final bool orig;
  Op(this.op, [this.orig = false]);
  String toString() => 'Op($op, $orig)';
  OpFuncType get(ZincInterpreter interp) =>
    this.orig ? interp.op0[op] : interp.op1[op];
  void set(ZincInterpreter interp, OpFuncType func) { interp.op1[op] = func; }
}

// Unary operator (len).
class Lenop extends Anyop {
  final bool orig;
  Lenop([this.orig = false]);
  String toString() => 'Lenop($orig)';
  OpFuncType get(ZincInterpreter interp) =>
    this.orig ? interp.op0['#'] : interp.op1['#'];
  void set(ZincInterpreter interp, OpFuncType func) { interp.op1['#'] = func; }
}

// Magic operator.
class Magicop extends Anyop {
  final String op;
  Magicop(this.op);
  String toString() => 'Magicop($op)';
  Obj interpret_with(ZincInterpreter interp, Obj x, Obj y) {
    if (op == 'cut') {
      if (y is! IntObj) { throw new Error('cannot cut int with non-int'); }
      if (x is IntObj) {
        return new SetObj(x.value.toString().split(y.value.toString()).map(
          int.parse));
      } else {
        assert(x is SetObj);
        List<List<Obj>> res = [[]];
        for (Obj obj in x.vals(interp)) {
          if (obj == y) { res.add([]); }
          else { res.last.add(obj); }
        }
        return new SetObj(new List.from(res.map((l) =>
          l.length == 1 ? l[0] : new SetObj(l))));
      }
    } else if (op == 'join') {
      if (x is! SetObj) { throw new Error('can only join set'); }
      if (y is! IntObj) { throw new Error('can only join set with int'); }
      String res = '';
      for (Obj obj in x.vals(interp)) {
        if (obj is! IntObj) { throw new Error('joining set must contain ints'); }
        res += obj.value.toString();
      }
      return new IntObj(int.parse(res));
    }
  }
}

// Unary operator (len) expression.
class Len extends Node {
  final Lenop op;
  final Node value;
  Len(this.op, this.value);
  String toString() => 'Len($op, $value)';
  Obj interpret(ZincInterpreter interp) =>
    op.get(interp)(interp, value.interpret(interp), null);
}

// Binary operator expression.
class Binop extends Node {
  final Node lhs, rhs;
  final Op op;
  Binop(this.lhs, this.op, this.rhs);
  String toString() => 'Binop($lhs, $op, $rhs)';
  Obj interpret(ZincInterpreter interp) =>
    op.get(interp)(interp, lhs.interpret(interp), rhs.interpret(interp));
}

// Clause.
enum ClauseKind { Where, Sort }
class Clause extends Node {
  final ClauseKind kind;
  final Node expr;
  Clause(this.kind, this.expr);
  String toString() => 'Clause($kind, $expr)';
  Obj interpret_with(ZincInterpreter interp, SetObj set, Id id) {
    List<Obj> res = [];
    List<Obj> values = set.vals(interp);
    switch (kind) {
    case ClauseKind.Where:
      for (int i=0; i<values.length; i++) {
        Obj obj = values[i];
        interp.push_scope();
        interp.setv(id.id, obj);
        interp.setv('_', new IntObj(i));
        Obj x = expr.interpret(interp);
        interp.pop_scope();
        if (x is IntObj) {
          if (x.value != 0) { res.add(obj); }
        } else { throw new Error('where clause condition must be an integer'); }
      }
      break;
    case ClauseKind.Sort:
      res = values;
      res.sort((x, y) {
        interp.push_scope();
        interp.setv(id.id, x);
        Obj x_by = expr.interpret(interp);
        interp.setv(id.id, y);
        Obj y_by = expr.interpret(interp);
        interp.pop_scope();
        if (x_by is IntObj && y_by is IntObj) {
          return x_by.value.compareTo(y_by.value);
        } else { throw new Error('sort clause result must be an integer'); }
      });
      break;
    }
    return new SetObj(new List.from(res.reversed));
  }
}

// Set comprehension.
class SetComp extends Node {
  final Id id;
  final Node set;
  final Clause clause;
  SetComp(this.id, this.set, this.clause);
  String toString() => 'SetComp($id, $set, $clause)';
  Obj interpret(ZincInterpreter interp) {
    Obj setobj = set.interpret(interp);
    if (setobj is SetObj) {
      return clause.interpret_with(interp, setobj, id);
    } else { throw new Error('set comprehension rhs must be set type'); }
  }
}

// Operator rewrite.
class OpRewrite extends Node {
  final Anyop op;
  final Node value;
  final Id lid, rid; // Can be null!
  OpRewrite(this.op, this.value, [this.lid, this.rid]);
  String toString() => 'OpRewrite($lid, $op, $rid, $value)';
  Obj interpret(ZincInterpreter interp) {
    if (lid != null) {
      // Not bare.
      op.set(interp, (interp,x,y) {
        interp.push_scope();
        interp.setv(lid.id, x);
        if (rid == null) { assert(y == null); }
        else { interp.setv(rid.id, y); }
        Obj res = value.interpret(interp);
        interp.pop_scope();
        return res;
      });
    } else {
      // Bare.
      if (value is Magicop) {
        op.set(interp, (interp,x,y) => value.interpret_with(interp, x, y));
      } else {
        op.set(interp, (interp,x,y) => (value as Anyop).get(interp)(x, y));
      }
    }
    return null;
  }
}

class Program extends Node {
  final List<OpRewrite> rws;
  final Node expr;
  Program(this.rws, this.expr);
  String toString() => 'Program($rws, $expr)';
  Obj interpret(ZincInterpreter interp) {
    rws.forEach((n) => n.interpret(interp));
    return expr.interpret(interp);
  }
}


// Runtime objects.
typedef Obj OpFuncType(ZincInterpreter interp, Obj x, Obj y);

class Obj {}

class IntObj extends Obj {
  final int value;
  IntObj(this.value);
  String toString() => 'IntObj($value)';
  bool operator==(Obj rhs) => rhs is IntObj && value == rhs.value;
  String dump() => value.toString();
}

class SetObj extends Obj {
  final List<Obj> values;
  SetObj(this.values) {
    if (values.length == 0) { throw new Error('set cannot be empty'); }
  }
  String toString() => 'SetObj($values)';
  bool operator==(Obj rhs) => rhs is SetObj && values == rhs.values;
  String dump() => values.map((x) => x.dump()).reduce((x,y) => x+y);
  List<Obj> vals(ZincInterpreter interp) {
    Obj lenobj = interp.op1['#'](interp, this, null);
    int len;
    if (lenobj is! IntObj) { throw new Error('# operator must return an int'); }
    len = lenobj.value;
    if (len < 0) { throw new Error('result of # operator must be positive'); }
    return new List<Obj>.from(values.getRange(0, len));
  }
}


// Parser.
class ZincParser extends LanguageParsers {
  ZincParser(): super(reservedNames: ['let', 'in', 'join', 'cut']);
  get start => prog().between(spaces, eof);
  get comma => char(',') < spaces;
  get lp => symbol('(');
  get rp => symbol(')');
  get lb => symbol('{');
  get rb => symbol('}');
  get colon => symbol(':');
  get plus => symbol('+');
  get minus => symbol('-');
  get star => symbol('*');
  get slash => symbol('/');
  get eq => symbol('=');
  get len => symbol('#');
  get in_ => char(':');
  get where => char('^');
  get sort => char('\$');

  prog() => reserved['let'] + oprw().sepBy(comma) + reserved['in'] + expr() ^
            (_1,o,_2,x) => new Program(o,x);
  oprw() => oprw1() | oprw2() | oprw3();
  oprw1() => (basicop() | lenop()) + eq + (magicop() | op()) ^
             (o,_,r) => new OpRewrite(o,r);
  oprw2() => (id() + op() + id()).list + eq + expr() ^
             (l,_,x) => new OpRewrite(l[1], x, l[0], l[2]);
  oprw3() => lenop() + id() + eq + expr() ^ (o,a,_,x) => new OpRewrite(o, x, a);
  magicop() => (reserved['join'] | reserved['cut']) ^ (s) => new Magicop(s);
  basicop() => (plus | minus | star | slash | eq) ^ (op) => new Op(op);
  op() => (basicop() + colon ^ (op,_) => new Op(op.op, true)) | basicop();
  lenop() => (len + colon ^ (_1,_2) => new Lenop(true)) |
             len ^ (_) => new Lenop();
  expr() => setcomp() | unop() | binop() | prim();
  setcomp() => lb + id() + in_ + rec(expr) + clause() + rb ^
               (_1,i,_2,x,c,_3) => new SetComp(i,x,c);
  clausekind() => (where ^ (_) => ClauseKind.Where) |
                  (sort  ^ (_) => ClauseKind.Sort);
  clause() => clausekind() + rec(expr) ^ (k,x) => new Clause(k,x);
  unop() => lenop() + rec(expr) ^ (o,x) => new Len(o,x);
  binop() => prim() + op() + rec(expr) ^ (l,o,r) => new Binop(l,o,r);
  prim() => id() | intlit() | parens(rec(expr));
  id() => identifier ^ (i) => new Id(i);
  intlit() => intLiteral ^ (i) => new IntLiteral(i);
}


// Interpreter.
class ZincInterpreter {
  Map<String, OpFuncType> op0, op1;
  List<Map<String, Obj>> scopes;
  ZincInterpreter() {
    var beInt = (v) {
      if (v is IntObj) { return v.value; }
      else { throw new Error('argument to binary operator must be integer'); }
    };
    op0 = {
      '+': (_,x,y) => new IntObj(beInt(x)+beInt(y)),
      '-': (_,x,y) => new IntObj(beInt(x)-beInt(y)),
      '*': (_,x,y) => new IntObj(beInt(x)*beInt(y)),
      '/': (_,x,y) => new IntObj(beInt(x)/beInt(y)),
      '=': (_,x,y) => new IntObj(x == y ? 1 : 0),
      '#': (i,x,_2) =>
        new IntObj(x is IntObj ? x.value.toString().length : x.values.length)
    };
    op1 = new Map<String, OpFuncType>.from(op0);
    scopes = [{}];
  }

  void push_scope() { scopes.add({}); }
  void pop_scope() { scopes.removeLast(); }
  void setv(String name, Obj value) { scopes[scopes.length-1][name] = value; }
  Obj getv(String name) {
    for (var scope in scopes.reversed) {
      if (scope[name] != null) { return scope[name]; }
    }
    if (name == 'S') {
      var input = stdin.readLineSync() ?? '';
      var list = new List.from(input.codeUnits.map((c) =>
        new IntObj(int.parse(new String.fromCharCodes([c])))));
      setv('S', new SetObj(list));
      return getv('S');
    } else throw new Error('undefined variable $name');
  }
}


void main(List<String> args) {
  if (args.length != 1) {
    print('usage: ${Platform.script.toFilePath()} <file to run>');
    return;
  }
  var file = new File(args[0]);
  if (!file.existsSync()) {
    print('cannot open ${args[0]}');
    return;
  }
  Program root = new ZincParser().start.parse(file.readAsStringSync());
  ZincInterpreter interp = new ZincInterpreter();
  var res = root.interpret(interp);
  print(res.dump());
}

และนี่ไปในpubspec.yaml:

name: zinc
dependencies:
  parsers: any

แนวทางแก้ไขปัญหา

let
#x=((x=S)*(-2))+#:x,
/=cut
in {y:{x:S/0$#:x}^_=2}

1
ฉันเข้าใจถูกต้องว่ามีการสั่งซื้อชุดและสามารถทำซ้ำได้ดังนั้นจึงเป็นรายการโดยทั่วไป? นอกจากนี้หากฉันjoinมีชุดแบบผสม{1,{3,2}}จะมีข้อผิดพลาดหรือไม่ ฉันไม่สามารถติดตั้ง Dart ได้ในตอนนี้ดังนั้นฉันไม่สามารถตรวจสอบตัวเองได้
Zgarb

@Zarb ใช่ชุดเป็นรายการโดยทั่วไปในกรณีนี้ เข้าร่วมชุดผสมควรเป็นข้อผิดพลาด แต่ล่ามจริงเกิดปัญหาเอทีเอ็ม ...
kirbyfan64sos

ฉันจะเรียกใช้ล่ามได้อย่างไร ถ้าฉันเพียงแค่พยายามที่dart bin/zinc.dart test.zncฉันได้รับข้อผิดพลาดทางไวยากรณ์: 'file:///D:/Development/languages/zinc/bin/zinc.dart': error: line 323 pos 41: unexpected token '?'...var input = stdin.readLineSync() ?? '';
มาร์ตินเอนเดอร์


1
@Zgarb จำได้ว่าเมื่อใดในสเป็คฉันบอกว่าการปฏิบัติการในตัวทั้งหมดยกเว้นความเท่าเทียมกันใช้ตัวดำเนินการความยาว? ฉันลบล้างมันเพื่อกลับไป-2+#:Sเมื่อได้รับSซึ่งตัดเลขศูนย์สองต่อท้าย นั่นคือวิธีที่ฉันหวังว่ามันจะได้รับการแก้ไข และ^ไม่ควรย้อนกลับชุด ... นั่นเป็นข้อผิดพลาด ...
kirbyfan64sos

5

Compass Soup ( แตกโดย cardboard_box )

ล่าม: C ++

Compass Soup เป็นเหมือนเครื่องจักรทัวริงที่มีเทป 2 มิติที่ไม่มีที่สิ้นสุด หลักสำคัญคือหน่วยความจำคำสั่งและหน่วยความจำข้อมูลอยู่ในพื้นที่เดียวกันและผลลัพธ์ของโปรแกรมคือเนื้อหาทั้งหมดของพื้นที่นั้น

ป้อนคำอธิบายรูปภาพที่นี่

มันทำงานอย่างไร

โปรแกรมคือบล็อกข้อความแบบสองมิติ พื้นที่โปรแกรมเริ่มต้นด้วยซอร์สโค้ดทั้งหมดที่วางด้วยอักขระตัวแรกที่ (0,0) ส่วนที่เหลือของพื้นที่โปรแกรมนั้นไม่มีที่สิ้นสุดและเริ่มต้นด้วยอักขระ null (ASCII 0)

มีพอยน์เตอร์สองตัวที่สามารถเคลื่อนที่ไปรอบ ๆ พื้นที่โปรแกรมได้:

  • ตัวชี้การดำเนินการมีที่ตั้งและทิศทาง (เหนือ, ใต้, ตะวันออกหรือตะวันตก) แต่ละเห็บคำสั่งภายใต้ตัวชี้การดำเนินการจะถูกดำเนินการแล้วตัวชี้การดำเนินการย้ายในทิศทางปัจจุบัน ตัวชี้การดำเนินการเริ่มเคลื่อนที่ไปทางทิศตะวันออก (บวก x) ที่ตำแหน่งของ!อักขระหรือที่ (0,0) หากไม่มีอยู่
  • ตัวชี้ข้อมูลมีเพียงที่ตั้ง มันถูกย้ายไปอยู่กับคำแนะนำx, X, และy Yมันเริ่มต้นที่ตำแหน่งของ@ตัวละครหรือที่ (0,0) หากไม่มีอยู่

อินพุต

เนื้อหาของ stdin จะถูกพิมพ์ลงในช่องว่างของโปรแกรมเริ่มต้นที่ตำแหน่งของ>ตัวละครหรือที่ (0,0) หากไม่มีอยู่

เอาท์พุต

โปรแกรมจะหยุดทำงานเมื่อตัวชี้การดำเนินการทำงานออกจากขอบเขตอย่างไม่อาจแก้ไขได้ ผลลัพธ์คือเนื้อหาทั้งหมดของพื้นที่โปรแกรมในขณะนั้น มันถูกส่งไปยัง stdout และ 'result.txt'

คำแนะนำ

  • n - เปลี่ยนเส้นทางตัวชี้การดำเนินการทางทิศเหนือ (ลบ y)
  • e - เปลี่ยนเส้นทางตัวชี้การดำเนินการตะวันออก (บวก x)
  • s - เปลี่ยนเส้นทางตัวชี้การดำเนินการทางทิศใต้ (บวก y)
  • w - เปลี่ยนเส้นทางตัวชี้การดำเนินการทางทิศตะวันตก (ลบ x)
  • y - เลื่อนตัวชี้ข้อมูลไปทางทิศเหนือ (ลบ y)
  • X - ย้ายตัวชี้ข้อมูลไปทางทิศตะวันออก (บวก x)
  • Y - ย้ายตัวชี้ข้อมูลไปทางทิศใต้ (บวก y)
  • x - ย้ายตัวชี้ข้อมูลไปทางตะวันตก (ลบ x)
  • p- เขียนอักขระถัดไปที่พบโดยตัวชี้การดำเนินการที่ตัวชี้ข้อมูล ตัวละครนั้นไม่ได้ถูกดำเนินการตามคำสั่ง
  • j- ตรวจสอบตัวละครตัวต่อไปที่พบโดยตัวชี้การดำเนินการกับตัวละครภายใต้ตัวชี้ข้อมูล ตัวละครนั้นไม่ได้ถูกดำเนินการตามคำสั่ง หากเหมือนกันตัวชี้การดำเนินการจะข้ามไปยังอักขระตัวถัดไป
  • c - เขียนอักขระ null ที่ตัวชี้ข้อมูล
  • * - เบรกพอยต์ - เพียงแค่ทำให้ล่ามหยุด

อักขระอื่นทั้งหมดถูกละเว้นโดยตัวชี้การดำเนินการ

ล่าม

ตัวแปลใช้ไฟล์ต้นฉบับเป็นอาร์กิวเมนต์และอินพุตบน stdin มันมีดีบักเกอร์ที่ใช้ไม่ได้ซึ่งคุณสามารถเรียกใช้ด้วยคำสั่งเบรกพอยต์ในรหัส ( *) เมื่อแตกตัวชี้การดำเนินการจะแสดงเป็น ASCII 178 (บล็อกสีเทาเข้ม) และตัวชี้ข้อมูลจะแสดงเป็น ASCII 177 (บล็อกสีเทาอ่อน)

#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>

// Compass Soup programming language interpreter
// created by Brian MacIntosh (BMacZero)
// for https://codegolf.stackexchange.com/questions/61804/create-a-programming-language-that-only-appears-to-be-unusable
//
// 31 October 2015

struct Point
{
    int x, y;
    Point(int ix, int iy) { x = ix; y = iy; };
    bool operator==(const Point &other) const
    {
        return other.x == x && other.y == y;
    }
    bool operator!=(const Point &other) const
    {
        return other.x != x || other.y != y;
    }
};

struct Bounds
{
    int xMin, xMax, yMin, yMax;
    Bounds(int xmin, int ymin, int xmax, int ymax)
    {
        xMin = xmin; yMin = ymin; xMax = xmax; yMax = ymax;
    }
    bool contains(Point pt)
    {
        return pt.x >= xMin && pt.x <= xMax && pt.y >= yMin && pt.y <= yMax;
    }
    int getWidth() { return xMax - xMin + 1; }
    int getHeight() { return yMax - yMin + 1; }
    bool operator==(const Bounds &other) const
    {
        return other.xMin == xMin && other.xMax == xMax && other.yMin == yMin && other.yMax == yMax;
    }
    bool operator!=(const Bounds &other) const
    {
        return other.xMin != xMin || other.xMax != xMax || other.yMin != yMin || other.yMax != yMax;
    }
};

int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }

Bounds hull(Point a, Bounds b)
{
    return Bounds(min(a.x, b.xMin), min(a.y, b.yMin), max(a.x, b.xMax), max(a.y, b.yMax));
}

Bounds hull(Bounds a, Bounds b)
{
    return Bounds(min(a.xMin, b.xMin), min(a.yMin, b.yMin), max(a.xMax, b.xMax), max(a.yMax, b.yMax));
}

Bounds programBounds(0,0,0,0);
char** programSpace;

Point execPtr(0,0);
Point execPtrDir(1,0);
Point dataPtr(0,0);
Point stdInPos(0,0);

bool breakpointHit = false;
char breakOn = 0;

/// reads the character from the specified position
char read(Point pt)
{
    if (programBounds.contains(pt))
        return programSpace[pt.x - programBounds.xMin][pt.y - programBounds.yMin];
    else
        return 0;
}

/// read the character at the data pointer
char readData()
{
    return read(dataPtr);
}

/// read the character at the execution pointer
char readProgram()
{
    return read(execPtr);
}

/// gets the bounds of the actual content of the program space
Bounds getTightBounds(bool debug)
{
    Bounds tight(0,0,0,0);
    for (int x = programBounds.xMin; x <= programBounds.xMax; x++)
    {
        for (int y = programBounds.yMin; y <= programBounds.yMax; y++)
        {
            if (read(Point(x, y)) != 0)
            {
                tight = hull(Point(x, y), tight);
            }
        }
    }
    if (debug)
    {
        tight = hull(dataPtr, tight);
        tight = hull(execPtr, tight);
    }
    return tight;
}

/// ensure that the program space encompasses the specified rectangle
void fitProgramSpace(Bounds bounds)
{
    Bounds newBounds = hull(bounds, programBounds);

    if (newBounds == programBounds) return;

    // allocate new space
    char** newSpace = new char*[newBounds.getWidth()];

    // copy content
    for (int x = 0; x < newBounds.getWidth(); x++)
    {
        newSpace[x] = new char[newBounds.getHeight()];
        for (int y = 0; y < newBounds.getHeight(); y++)
        {
            Point newWorldPos(x + newBounds.xMin, y + newBounds.yMin);
            newSpace[x][y] = read(newWorldPos);
        }
    }

    // destroy old space
    for (int x = 0; x < programBounds.getWidth(); x++)
    {
        delete[] programSpace[x];
    }
    delete[] programSpace;

    programSpace = newSpace;
    programBounds = newBounds;
}

/// outputs the current program space to a file
void outputToStream(std::ostream &stream, bool debug)
{
    Bounds tight = getTightBounds(debug);
    for (int y = tight.yMin; y <= tight.yMax; y++)
    {
        for (int x = tight.xMin; x <= tight.xMax; x++)
        {
            char at = read(Point(x, y));
            if (debug && x == execPtr.x && y == execPtr.y)
                stream << (char)178;
            else if (debug && x == dataPtr.x && y == dataPtr.y)
                stream << (char)177;
            else if (at == 0)
                stream << ' ';
            else
                stream << at;
        }
        stream << std::endl;
    }
}

/// writes a character at the specified position
void write(Point pt, char ch)
{
    fitProgramSpace(hull(pt, programBounds));
    programSpace[pt.x - programBounds.xMin][pt.y - programBounds.yMin] = ch;
}

/// writes a character at the data pointer
void write(char ch)
{
    write(dataPtr, ch);
}

/// writes a line of text horizontally, starting at the specified position
void writeLine(Point loc, std::string str, bool isSource)
{
    fitProgramSpace(Bounds(loc.x, loc.y, loc.x + str.size(), loc.y));
    for (unsigned int x = 0; x < str.size(); x++)
    {
        programSpace[x + loc.x][loc.y] = str[x];

        // record locations of things
        if (isSource)
        {
            switch (str[x])
            {
            case '>':
                stdInPos = Point(loc.x + x, loc.y);
                break;
            case '!':
                execPtr = Point(loc.x + x, loc.y);
                break;
            case '@':
                dataPtr = Point(loc.x + x, loc.y);
                break;
            }
        }
    }
}

void advanceExecPtr()
{
    execPtr.x += execPtrDir.x;
    execPtr.y += execPtrDir.y;
}

void breakpoint()
{
    breakpointHit = true;
    outputToStream(std::cout, true);
    std::cout << "[Return]: step | [Space+Return]: continue | [<char>+Return]: continue to <char>" << std::endl;
    while (true)
    {
        std::string input;
        std::getline(std::cin, input);
        if (input.size() == 0)
        {
            break;
        }
        else if (input.size() == 1)
        {
            if (input[0] == ' ')
            {
                breakpointHit = false;
                break;
            }
            else
            {
                breakOn = input[0];
                breakpointHit = false;
                break;
            }
        }
    }
}

int main(int argc, char** argv)
{
    if (argc != 2)
    {
        printf("Usage: CompassSoup <source-file>");
        return 1;
    }

    // open source file
    std::ifstream sourceIn(argv[1]);

    if (!sourceIn.is_open())
    {
        printf("Error reading source file.");
        return 1;
    }

    programSpace = new char*[1];
    programSpace[0] = new char[1];
    programSpace[0][0] = 0;

    // read starting configuration
    std::string line;
    int currentLine = 0;
    while (std::getline(sourceIn, line))
    {
        writeLine(Point(0, currentLine), line, true);
        currentLine++;
    }

    sourceIn.close();

    // take stdin
    std::string input;
    std::cout << ">";
    std::cin >> input;
    std::cin.ignore();
    writeLine(stdInPos, input, false);

    // execute
    while (programBounds.contains(execPtr))
    {
        if (execPtrDir.x == 0 && execPtrDir.y == 0)
        {
            printf("Implementation error: execPtr is stuck.");
            break;
        }

        advanceExecPtr();

        char command = readProgram();

        // breakpoint control code
        if (breakpointHit || (breakOn != 0 && command == breakOn))
        {
            breakOn = 0;
            breakpoint();
        }

        switch (command)
        {
        case 'n':
            execPtrDir = Point(0,-1);
            break;
        case 'e':
            execPtrDir = Point(1,0);
            break;
        case 's':
            execPtrDir = Point(0,1);
            break;
        case 'w':
            execPtrDir = Point(-1,0);
            break;
        case 'x':
            dataPtr.x--;
            break;
        case 'X':
            dataPtr.x++;
            break;
        case 'y':
            dataPtr.y--;
            break;
        case 'Y':
            dataPtr.y++;
            break;
        case 'p':
            advanceExecPtr();
            write(readProgram());
            break;
        case 'j':
            advanceExecPtr();
            if (readData() == readProgram())
            {
                advanceExecPtr();
            }
            break;
        case 'c':
            write(0);
            break;
        case '*':
            breakpoint();
            break;
        }
    }

    std::ofstream outputFile("result.txt");
    outputToStream(outputFile, false);
    outputToStream(std::cout, false);
    outputFile.close();
}

ตัวอย่าง

สวัสดีชาวโลก

Hello, World!

แมว

>

พาริตี้: ยอมรับสตริงของอักขระที่ถูกยกเลิกโดยศูนย์ ('0') ขาออกyesในบรรทัดแรกของการส่งออกถ้าจำนวนของ 1s |ในการป้อนข้อมูลที่เป็นเลขคี่มิฉะนั้นเอาท์พุท

|>
!--eXj1s-c-eXj0s-c-exj|s-pyXpeXps
   c   |   c   |   |   |
  cn0j-w---n1j-w   n---w

เคล็ดลับ

คุณควรใช้โปรแกรมแก้ไขข้อความที่ดีและใช้ฟังก์ชั่นของปุ่ม 'Insert' อย่างรอบคอบและใช้ 'Alt-Drag' เพื่อเพิ่มหรือลบข้อความในหลายแถวพร้อมกัน

วิธีการแก้

นี่คือทางออกของฉัน มันไม่ดีเท่า cardboard_box เพราะฉันต้องทำให้ซอร์สโค้ดลบเอง ฉันหวังว่าฉันจะหาวิธีลบรหัสทั้งหมดและทิ้งคำตอบไว้ แต่ฉันทำไม่ได้

วิธีการของฉันคือแยกลำดับที่แตกต่างกันของ1s ลงบนเส้นที่แตกต่างกันแล้วเรียงลำดับพวกเขาโดยให้1"ตกลง" ทั้งหมดจนกว่าพวกเขาจะตีอีกครั้ง1และในที่สุดก็จะลบทุกอย่างยกเว้นบรรทัดที่สามหลังจากอินพุต

  • บล็อกขนาดใหญ่ทางด้านล่างขวาของการ#A#อ่าน1และคัดลอกไปยังบรรทัดสุดท้ายของการแบ่งจนกว่า0จะอ่าน
  • #B#ตรวจสอบหนึ่งวินาที0และไปทางเหนือเพื่อ#D#มีหนึ่ง มิฉะนั้น#C#จะเริ่มต้นสายแยกใหม่โดยใส่หลังจากที่หนึ่งที่ผ่านมาและกลับไป|#A#
  • บล็อกที่ด้านบนและด้านบน#F#เป็นรหัสแรงโน้มถ่วง มันเดินไปที่สุดท้าย1ของแถวแรกและย้ายมันขึ้นมาจนฮิตหรือ1 -หากไม่สามารถทำเช่นนั้นได้จะทำเครื่องหมายแถวว่าเสร็จแล้วโดยใส่+ก่อนหน้า
  • #G#กำลังลบการแยกที่ไม่จำเป็นทั้งหมดออกและ#H#ลบ stdin และรหัสทั้งหมดระหว่างวงเล็บ

รหัส:

 s-----------------------w
 s-c-w  s-c-w  s---w    e+-
 eXj)nc-eXj)nc-exj(ncyj(nn
(n-----------------------------------------w                      ))
(  #H#                             s---w   |                      ))
(                                  exj+ncyxn                      ))
(                                  |                              ))
(                      s---w   s-c-+w                             ))
(                      exj+ncy-eXj1nn                             ))
(                      |                                          ))
(         s---w    s-c-+w    s+pxw                                ))
(         eyj-n-YY-eXj1nn    |  sn1jX--w           e----s         ))
(         |                  Y  x     e+---s e---s ns1jyw         ))
(      ej+n------s           j  |     nn+jYw-n+jxw-Yw   |         ))
(      Y   ec----s      e---s|  |                       1         ))
(      c   ns1jX-wYcYYY-n-jyww  |                       p         ))
(      ns+jxw      #G#       e--s                       Y         ))
(       e---n                   |               s------w|         ))
(                               |               |   ej-nn         ))
(             s--w              e----s   exc----eyj1n---n         ))
(#A#          p e+---s   s---w       |#F#|                        ))
(e----se---s  1 ||   |   exj|n----p+YeXj1ns                       ))
(ns-jXwn-jyw--w-nn1jXw   c #D#       n----w                       ))
( |        |         |   |                                        ))
( |        n---------+---+-------------|pw            s---w s---w ))
( |                  |   |     exp)XYs   |            eyj-nYeXj0ns)
( |         s---ws---+w  n-----+-----+---+------------+----------w))
( |         |   ||   ||  e--yp)n     e---+--s         |           )
( |     e-c-exj|neYj|nn  |     #C#       |  |         p           ))
( |     |                |     s---w s---+w s---w s---+w          ))
( |     |          #B#  e+s    |   | |   || |   | |   ||          ))
(!ep-Yj0n-c----------Xj0nne----exj|n-eYj|nn exj|n-eYj|nn          ))
(-@
 |>


สาปเข้ามาใกล้! ฉันจะแบ่งปันวิธีแก้ปัญหาเมื่อกลับถึงบ้านคืนนี้
BMac

ฉันไม่สามารถรับโปรแกรมความเท่าเทียมกันในการทำงาน ตอนแรกควรมีคำสั่ง debug หรือไม่? ถ้าฉันผ่านมันไปติดอยู่ในวงวนไม่สิ้นสุดความคิดอะไรที่ฉันอาจจะทำผิด?
feersum

ดูเหมือนว่าจะมีcจุดเริ่มต้นพิเศษที่ไม่ควรอยู่ที่นั่น ฉันซ่อมมัน. เพิ่มโซลูชันของฉันให้กับปัญหาด้วย
BMac

4

Acc! , Cracc'dโดย ppperry

ภาษานี้มีโครงสร้างการวนรอบหนึ่งคณิตศาสตร์เลขจำนวนเต็มพื้นฐานอักขระ I / O และตัวสะสม (เช่นชื่อ) เพียงหนึ่งสะสม ดังนั้นชื่อ

งบ

คำสั่งคือการแยกวิเคราะห์ทีละบรรทัด คำสั่งมีสามประเภท:

  1. Count <var> while <cond>

เคานต์<var>เพิ่มขึ้นจาก 0 ตราบเท่าที่<cond>ไม่ใช่ศูนย์เทียบเท่ากับ for(<var>=0; <cond>; <var>++)C-สไตล์ ตัวนับลูปอาจเป็นตัวอักษรตัวเล็กก็ได้ เงื่อนไขสามารถเป็นนิพจน์ใด ๆ ไม่จำเป็นต้องเกี่ยวข้องกับตัวแปรลูป ลูปหยุดทำงานเมื่อค่าของเงื่อนไขเป็น 0

ลูปจำเป็นต้องใช้เครื่องมือจัดฟันแบบ K & R (โดยเฉพาะตัวแปร Stroustrup ):

Count i while i-5 {
 ...
}
  1. Write <charcode>

เอาต์พุตอักขระเดี่ยวที่มีค่า ASCII / Unicode ที่กำหนดเป็น stdout รหัสสามารถเป็นนิพจน์ใด ๆ

  1. การแสดงออก

นิพจน์ที่ยืนด้วยตัวเองจะถูกประเมินและกำหนดกลับไปที่ตัวสะสม (ซึ่งสามารถเข้าถึงได้_) ดังนั้นเช่น3เป็นคำสั่งที่ตั้งสะสม 3 _ + 1เพิ่มการสะสม; และ_ * Nอ่านตัวละครและคูณตัวสะสมด้วยรหัสของมัน

หมายเหตุ: แอคคูมูเลเตอร์เป็นตัวแปรเดียวที่สามารถกำหนดให้โดยตรงได้ ตัวแปรลูปและNสามารถใช้ในการคำนวณ แต่ไม่สามารถแก้ไขได้

ตัวสะสมเริ่มต้น 0

การแสดงออก

นิพจน์สามารถรวมตัวอักษรจำนวนเต็มตัวแปรลูป ( a-z) _สำหรับแอคคูเลเตอร์และค่าพิเศษNที่อ่านอักขระและประเมินเป็นรหัสในแต่ละครั้งที่ใช้ หมายเหตุ:นี่หมายความว่าคุณจะได้รับช็อตเดียวเพื่ออ่านตัวละครแต่ละตัว ครั้งต่อไปที่คุณใช้Nคุณจะอ่านอีกครั้ง

ผู้ประกอบการคือ:

  • +, ส่วนที่เพิ่มเข้าไป
  • -การลบ การปฏิเสธเป็นอันขาด
  • *การคูณ
  • /หารด้วยจำนวนเต็ม
  • %, โมดูโล่
  • ^การยกกำลัง

สามารถใช้วงเล็บในการบังคับใช้ลำดับความสำคัญของการดำเนินการ อักขระอื่นใดในนิพจน์คือข้อผิดพลาดทางไวยากรณ์

ช่องว่างและความคิดเห็น

ช่องว่างนำหน้าและต่อท้ายจะถูกละเว้น ช่องว่างในส่วนหัวของลูปจะต้องตรงตามที่แสดงโดยมีช่องว่างเดียวระหว่างส่วนหัวของลูปและการเปิดวงเล็บปีกกาเช่นกัน ช่องว่างภายในนิพจน์เป็นตัวเลือก

# เริ่มความคิดเห็นบรรทัดเดียว

Input / Output

Acc! คาดว่าอักขระบรรทัดเดียวเป็นอินพุต ตัวท่านแต่ละคนสามารถเรียกดูได้ในลำดับและ charcode Nของประมวลผลโดยใช้ การพยายามอ่านอักขระตัวสุดท้ายของบรรทัดทำให้เกิดข้อผิดพลาด ตัวละครสามารถส่งออกโดยการส่งผ่านรหัสเพื่อWriteคำสั่ง

ล่าม

ล่าม (เขียนใน Python 3) แปลAcc! รหัสเป็น Python และexecมัน

import re, sys

def main():
    if len(sys.argv) != 2:
        print("Please supply a filename on the command line.", file=sys.stderr)
        return
    codeFile = sys.argv[1]
    with open(codeFile) as f:
        code = f.readlines()
    code = translate(code)
    exec(code, {"inputStream": (ord(char) for char in input())})

def translate(accCode):
    indent = 0
    loopVars = []
    pyCode = ["_ = 0"]
    for lineNum, line in enumerate(accCode):
        if "#" in line:
            # Strip comments
            line = line[:line.index("#")]
        line = line.strip()
        if not line:
            continue
        lineNum += 1
        if line == "}":
            if indent:
                loopVar = loopVars.pop()
                if loopVar is not None:
                    pyCode.append(" "*indent + loopVar + " += 1")
                indent -= 1
            else:
                raise SyntaxError("Line %d: unmatched }" % lineNum)
        else:
            m = re.fullmatch(r"Count ([a-z]) while (.+) \{", line)
            if m:
                expression = validateExpression(m.group(2))
                if expression:
                    loopVar = m.group(1)
                    pyCode.append(" "*indent + loopVar + " = 0")
                    pyCode.append(" "*indent + "while " + expression + ":")
                    indent += 1
                    loopVars.append(loopVar)
                else:
                    raise SyntaxError("Line %d: invalid expression " % lineNum
                                      + m.group(2))
            else:
                m = re.fullmatch(r"Write (.+)", line)
                if m:
                    expression = validateExpression(m.group(1))
                    if expression:
                        pyCode.append(" "*indent
                                      + "print(chr(%s), end='')" % expression)
                    else:
                        raise SyntaxError("Line %d: invalid expression "
                                          % lineNum
                                          + m.group(1))
                else:
                    expression = validateExpression(line)
                    if expression:
                        pyCode.append(" "*indent + "_ = " + expression)
                    else:
                        raise SyntaxError("Line %d: invalid statement "
                                          % lineNum
                                          + line)
    return "\n".join(pyCode)

def validateExpression(expr):
    "Translates expr to Python expression or returns None if invalid."
    expr = expr.strip()
    if re.search(r"[^ 0-9a-z_N()*/%^+-]", expr):
        # Expression contains invalid characters
        return None
    elif re.search(r"[a-zN_]\w+", expr):
        # Expression contains multiple letters or underscores in a row
        return None
    else:
        # Not going to check validity of all identifiers or nesting of parens--
        # let the Python code throw an error if problems arise there
        # Replace short operators with their Python versions
        expr = expr.replace("^", "**")
        expr = expr.replace("/", "//")
        # Replace N with a call to get the next input character
        expr = expr.replace("N", "inputStream.send(None)")
        return expr

if __name__ == "__main__":
    main()


3

GoToTape (ปลอดภัย)

(ชื่อเดิมคือ Simp-plex)

ภาษานี้ง่าย การควบคุมการไหลหลักคือ goto รูปแบบการควบคุมที่เป็นธรรมชาติและมีประโยชน์ที่สุด

ข้อกำหนดภาษา

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

  • ตัวอักษร: a- zเป็นคำสั่ง goto, ไปที่A- Z, ตามลำดับ
  • :: ตั้งค่าแอคคิวมูเลเตอร์เป็นค่า ASCII เป็นถ่านจากอินพุต
  • ~: ส่งออกถ่านสำหรับค่า ASCII ในตัวสะสม
  • &: ลบหนึ่งจากการสะสมถ้าเป็น 1 หรือมากกว่ามิฉะนั้นเพิ่มหนึ่ง
  • |: เพิ่มหนึ่งในการสะสม
  • <: ตั้งค่าตัวชี้ข้อมูลเป็น 0
  • +: เพิ่มเซลล์ข้อมูลที่ตัวชี้ข้อมูล; ย้ายตัวชี้ +1
  • -: ลบหนึ่งออกจากเซลล์ข้อมูลที่ตัวชี้ข้อมูลหากเป็นบวก ย้ายตัวชี้ +1
  • [...]: รันโค้ด n ครั้งโดยที่ n คือหมายเลขบนเทปที่ตัวชี้ข้อมูล (ไม่สามารถซ้อนกันได้)
  • /: ข้ามคำสั่งถัดไปถ้าตัวสะสมเป็น 0

ล่าม (C ++)

#include <iostream>
#include <memory.h>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int serch(char* str,char ch){
    for(int i = 0;str[i];i++){
        if(str[i]==ch)
            return i;
    }
    return -1;
}

void runCode(char* code){
    int i = 0;
    char c;
    unsigned int* tape;
    tape = new unsigned int[1000003];
    memset(tape,0,1000003*sizeof(int));
    unsigned int p=0;
    unsigned int a=0;
    unsigned int n;
    unsigned int s;

    while(c=code[i]){
        if('A'<=c && c<='Z');
        if('a'<=c && c<='z')i=serch(code, c+'A'-'a');
        if(':'==c)a=cin.get();
        if('+'==c)tape[p++]++;
        if('-'==c)tape[p++] += tape[p]?-1:0;
        if('|'==c)a++;
        if('&'==c)a=a?a-1:1;
        if('<'==c)p=0;
        if('['==c){if(tape[p]){n=tape[p];s=i;}else i+=serch(code+i,']');};
        if(']'==c)i=--n?i:s;
        if('~'==c)cout<<(char)a;
        if('/'==c)i+=a?0:1;
        if('$'==c)p=a;
        i++;
    }
    delete[](tape);
}

int main(int argc, char* argv[]) {
    if(argc == 2){

        ifstream sorceFile (argv[1]);
        string code(static_cast<stringstream const&>(stringstream() << sorceFile.rdbuf()).str());
        runCode((char*)code.c_str());
    }else
        cout << "Code file must be included as a command-line argument \n";
    return 0;
}

มีความสุข!

วิธีการแก้

A:+&&&&&&&&&&/gbG&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&/a<aB<[|]C[&]-[|]/c<[|]D[&]-[|]/d<[|]+E[&]|||||||||||||||||||||||||||||||||||||||||||||||||~X&/x-[|]/e


2
การเข้ารหัส C ++ ของคุณกำลังฆ่าฉัน! มีเหตุผลที่คุณใช้callocแทน new charเขียนสไตล์ C ในขณะที่วนรอบใช้การจัดการหน่วยความจำแบบ C ทำให้เรารวบรวมไฟล์ C ++ ใหม่ทุกครั้งที่เราเปลี่ยนรหัสและใช้ 20 ifs แทน a switch? ฉันไม่ได้บ่น แต่ดวงตาของฉันมีเลือดออกตอนนี้ ... : O
kirbyfan64sos

3
ฉันได้แก้ไขจุดที่เป็นเนื้อล่าม
MegaTom

@ kirbyfan64sos รหัสไม่ดี ฉันจะรวมมันเข้าด้วยกันอย่างรวดเร็วและอาจไม่ได้ทำอย่างที่ควร ฟังก์ชั่นหลักสามารถเปลี่ยนแปลงได้เพื่อรับรหัสเป็นอินพุต ในความเป็นจริงฉันคิดว่าฉันจะทำอย่างนั้นในตอนนี้ ...
MegaTom

1
คำถามที่บอกว่าล่ามควรใช้ชื่อไฟล์บนบรรทัดคำสั่งสำหรับโปรแกรม
Dennis

นี่คือบางส่วนเป็น วิธีที่สั้นของการอ่านไฟล์ลงในสตริง แล้วโทรที่จะได้รับstr.c_str() char*
feersum

0

นี่เป็นความคิดที่ไม่ดีเนื่องจากภาษาลึกลับเกือบทุกภาษาดูไม่สามารถอ่านได้ (ดูที่ Jelly)
แต่นี่จะไป:

Pylongolf2 beta6

ผลักไปที่กอง

การกดไปที่สแต็กจะทำหน้าที่แตกต่างกันในภาษาอื่น
รหัส78ผลักดัน7และ8เป็นกลุ่ม แต่ใน Pylongolf 78มันดัน
ใน Pylongolf2 นี้อยู่ toggleable Üกับ

คำสั่ง

) Print the stack.
Ü Toggle the method Pylongolf2 uses for pushing to stack.
a The useless command, removes and adds the selected item in the same place.
c Ask for input.
n Convert string to a number.
" Toggle string mode for pushing text to the stack.
s Convert a number to a string. ╨ Encode the selected item (it must be a string).
_ Duplicate the selected item next to itself.
b Swap places between the selected item and the one before.
d Set the selected item to the last one.
m Move the selected item to the end of the stack.
@ Select an item. (Number required after this command as an argument).
w Wait a specified amount of time (the time is taken from the stack).
= Compare the selected item to the one before. (WARNING. THIS DELETES THE 2 ITEMS AND PLACES A true OR A false) (V2 beta)
~ Print the stack nicely. (V2 beta)
² Square a number. (V3 beta)
| Split a string to an array by the character after |. (V4 beta)
♀ Pop the array. (the contents are left in the stack) (V4 beta)
> Begin a while statement. (V5 beta)
< Loop back to the beginning of the while statement. (V5 beta)
! Break out of the while statements. (V5 beta)
? An if statement, does nothing if the selected item is a `true` boolean. (V6 beta)
¿ If an if statement is `false`, the interpreter skips everything to this character. (V6 beta)

การต่อข้อมูลสตริงและการลบรูปแบบ Regex ออกจากสตริง

สัญลักษณ์ + เชื่อมสตริงเข้าด้วยกัน
คุณสามารถใช้สัญลักษณ์ - เพื่อลบอักขระตามรูปแบบ regex จากสตริง:

c╨2"[^a-zA-Z]"-~

[^a-zA-Z]รหัสนี้จะเข้าและลบอักขระที่ไม่ใช่ตัวอักษรทั้งหมดโดยการเอาทุกรูปแบบการจับคู่
รายการที่เลือกจะต้องเป็น regex และรายการก่อนหน้าจะต้องเป็นสตริงที่จะแก้ไข

ถ้างบ

ในการทำเช่นนั้นให้ใส่ a =เพื่อเปรียบเทียบไอเท็มที่เลือกและอันใดอันหนึ่ง
สถานที่แห่งนี้trueหรือfalseในสถานที่
คำสั่ง?ตรวจสอบบูลีนนี้
ถ้าเป็นเช่นtrueนั้นก็ไม่ทำอะไรเลยและล่ามก็ดำเนินต่อไป
หากเป็นเช่นfalseนั้นล่ามจะข้ามไปที่¿อักขระที่อยู่ ใกล้ที่สุด

นำมาจากหน้า Github

ล่ามสำหรับ Pylongolf2 (Java):

package org.midnightas.pylongolf2;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

public class Pylongolf {

    public static final void main(String[] args) throws Exception {
        String content = new String(Files.readAllBytes(Paths.get(new File(args[0]).toURI()))) + " ";
        boolean fullreadMode = true;
        List<Object> stack = new ArrayList<Object>();
        List<Integer> whileStatements = new ArrayList<Integer>();
        HashMap<String, Object> vars = new HashMap<String, Object>();
        int ifStatements = 0;
        Scanner scanner = new Scanner(new UnclosableDecorator(System.in));
        int selectedIndex = 0;
        for (int cl = 0; cl < content.length(); cl++) {
            char c = content.charAt(cl);
            if (isNumber(c)) {
                if (!fullreadMode) {
                    stack.add(Double.parseDouble(c + ""));
                } else {
                    String number = "";
                    for (int cl0 = cl; cl0 < content.length(); cl0++) {
                        if (isNumber(content.charAt(cl0))) {
                            number += content.charAt(cl0);
                        } else {
                            cl = cl0 - 1;
                            stack.add(Double.parseDouble(number));
                            break;
                        }
                    }
                }
            } else if (c == ')') {
                System.out.println(Arrays.toString(stack.toArray()));
            } else if (c == 'Ü') {
                fullreadMode = !fullreadMode;
            } else if (c == '+') {
                if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] obj = (Object[]) stack.remove(selectedIndex);
                    Double dbl = new Double(0d);
                    for (Object o : obj) {
                        dbl += (Double) o;
                    }
                    stack.add(selectedIndex, dbl);
                } else {
                    Object obj0 = stack.remove(selectedIndex);
                    Object obj1 = stack.remove(selectedIndex);
                    if (obj0 instanceof Number && obj1 instanceof Number)
                        stack.add(((Number) obj0).doubleValue() + ((Number) obj1).doubleValue());
                    else if (obj0 instanceof String) {
                        stack.add(obj0.toString() + obj1.toString());
                    }
                }
            } else if (c == '-') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() - ((Number) obj1).doubleValue());
                else if (obj0 instanceof String && obj1 instanceof String) {
                    stack.add(obj0.toString().replaceAll(obj1.toString(), ""));
                }
            } else if (c == '*') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() * ((Number) obj1).doubleValue());
            } else if (c == '/') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                if (obj0 instanceof Number && obj1 instanceof Number)
                    stack.add(((Number) obj0).doubleValue() / ((Number) obj1).doubleValue());
            } else if (c == 'a') {
                stack.add(selectedIndex, stack.remove(selectedIndex));
            } else if (c == 'c') {
                stack.add(scanner.nextLine());
            } else if (c == 'n') {
                if (stack.get(selectedIndex) instanceof String) {
                    stack.add(selectedIndex, Double.parseDouble(stack.remove(selectedIndex).toString()));
                } else if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] oldArray = (Object[]) stack.remove(selectedIndex);
                    Object[] newArray = new Object[oldArray.length];
                    for (int i = 0; i < oldArray.length; i++) {
                        newArray[i] = Double.parseDouble(oldArray[i].toString());
                    }
                    stack.add(selectedIndex, newArray);
                }
            } else if (c == '"') {
                String string = "\"";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    string = string + content.charAt(cl0);
                    if (content.charAt(cl0) == '"') {
                        stack.add(string.substring(1, string.length() - 1));
                        cl = cl0;
                        break;
                    }
                }
            } else if (c == 's') {
                Object obj = stack.remove(selectedIndex);
                if (obj instanceof Double) {
                    Double dbl = (Double) obj;
                    if (dbl.doubleValue() == Math.floor(dbl)) {
                        stack.add(selectedIndex, "" + dbl.intValue() + "");
                    } else {
                        stack.add(selectedIndex, "" + dbl + "");
                    }
                }
            } else if (c == '╨') {
                cl++;
                char editmode = content.charAt(cl);
                if (editmode == '0') {
                    stack.add(selectedIndex, rot13(stack.remove(selectedIndex).toString()));
                } else if (editmode == '1') {
                    stack.add(selectedIndex,
                            new StringBuilder(stack.remove(selectedIndex).toString()).reverse().toString());
                } else if (editmode == '2') {
                    stack.add(selectedIndex, stack.remove(selectedIndex).toString().toLowerCase());
                } else if (editmode == '3') {
                    stack.add(selectedIndex, stack.remove(selectedIndex).toString().toUpperCase());
                }
            } else if (c == '_') {
                stack.add(selectedIndex, stack.get(selectedIndex));
            } else if (c == 'b') {
                stack.add(selectedIndex + 1, stack.remove(selectedIndex));
            } else if (c == 'd') {
                selectedIndex = stack.size() == 0 ? 0 : stack.size() - 1;
            } else if (c == 'm') {
                stack.add(stack.remove(selectedIndex));
            } else if (c == '@') {
                String number = "";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    if (isNumber(content.charAt(cl0)))
                        number += content.charAt(cl0);
                    else {
                        cl = cl0 - 1;
                        selectedIndex = Integer.parseInt(number);
                        break;
                    }
                }
            } else if (c == 'w') {
                String number = "";
                for (int cl0 = cl + 1; cl0 < content.length(); cl0++) {
                    if (isNumber(content.charAt(cl0)))
                        number += content.charAt(cl0);
                    else {
                        cl = cl0 - 1;
                        Thread.sleep(Long.parseLong(number));
                        break;
                    }
                }
            } else if (c == '=') {
                Object obj0 = stack.remove(selectedIndex);
                Object obj1 = stack.remove(selectedIndex);
                stack.add(new Boolean(obj0.equals(obj1)));
            } else if (c == '~') {
                for (Object o : stack)
                    System.out.print(o);
                System.out.println();
            } else if (c == '²') {
                if (stack.get(selectedIndex) instanceof Double) {
                    Double dbl = (Double) stack.remove(selectedIndex);
                    stack.add(selectedIndex, dbl * dbl);
                } else if (stack.get(selectedIndex) instanceof Object[]) {
                    Object[] obj = (Object[]) stack.remove(selectedIndex);
                    Object[] newArray = new Object[obj.length];
                    for (int i = 0; i < obj.length; i++) {
                        newArray[i] = Math.pow((Double) obj[i], 2);
                    }
                    stack.add((Object[]) newArray);
                }
            } else if (c == '|') {
                String string = (String) stack.remove(selectedIndex);
                cl++;
                char splitChar = content.charAt(cl);
                stack.add((Object[]) string.split(splitChar + ""));
            } else if (c == '♀') {
                for (Object obj : (Object[]) stack.remove(selectedIndex)) {
                    stack.add(selectedIndex, obj);
                }
            } else if (c == '>') {
                whileStatements.add(new Integer(cl));
            } else if (c == '<') {
                cl = whileStatements.get(whileStatements.size() - 1);
            } else if (c == '!') {
                whileStatements.remove(whileStatements.size() - 1);
            } else if (c == '?') {
                if (stack.get(selectedIndex) instanceof Boolean) {
                    Boolean bool = (Boolean) stack.remove(selectedIndex);
                    if (bool == false) {
                        ifStatements++;
                        for (int cl0 = cl; cl0 < content.length(); cl0++) {
                            if (content.charAt(cl0) == '¿') {
                                ifStatements--;
                                cl = cl0;
                            }
                        }
                    }
                }
            } else if (c == 't') {
                break;
            } else if (c == '(') {
                stack.remove(selectedIndex);
            } else if (c == ':') {
                cl++;
                char charToVar = content.charAt(cl);
                vars.put(charToVar + "", stack.remove(selectedIndex));
            } else if (c >= 'A' && c <= 'Z') {
                stack.add(vars.get(c + ""));
            } else if (c == 'r') {
                stack.add(selectedIndex,
                        (double) new Random().nextInt(((Double) stack.remove(selectedIndex)).intValue() + 1));
            }
        }
        scanner.close();
    }

    public static String rot13(String input) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            if (c >= 'a' && c <= 'm')
                c += 13;
            else if (c >= 'A' && c <= 'M')
                c += 13;
            else if (c >= 'n' && c <= 'z')
                c -= 13;
            else if (c >= 'N' && c <= 'Z')
                c -= 13;
            sb.append(c);
        }
        return sb.toString();
    }

    public static boolean isNumber(char c) {
        return c >= '0' && c <= '9';
    }

}

มันควรจะใช้ยากไหม : /
CalculatorFeline

0

Rainbow (หมายเหตุ: ล่ามเร็ว ๆ นี้)

ฉันรู้ว่าความท้าทายนี้หมดอายุแล้ว

Rainbow เป็นส่วนผสมของ ... หลายสิ่งหลายอย่าง

Rainbow เป็นภาษาสแต็ก 2D ที่มีสองสแต็ค (Like Brain-Flak) และ 8 ทิศทาง ( N NE E SE S SW W NW) มี 8 คำสั่ง:

  • 1, +, *,"ทำสิ่งที่พวกเขาทำใน 1+
  • ! สลับกองซ้อนที่ใช้งานอยู่
  • > หมุน IP ตามเข็มนาฬิกา
  • , ใส่ตัวอักษรและผลักดันมัน
  • . ป๊อปและออกอักขระ

อย่างไรก็ตามอักขระในซอร์สโค้ดจะไม่ถูกเรียกใช้งานในทันที แทน,[The Character in the source code]^[Top Of Stack]ป้อนเข้าไปในสิ่งที่ Collatz Conjecture และจำนวนขั้นตอนที่ใช้ในการเข้าถึง 1 จะถูกแปลงเป็นอักขระด้วยตาราง ASCII ตัวละครนี้จะถูกดำเนินการแล้ว

  • หากใช้เวลามากกว่า 127 ขั้นตอนในการเข้าถึง 1 จำนวนขั้นตอนทั้งหมดจะถูกหารด้วย 127 ใช้การเตือนความจำจากนั้นเพิ่มการเตือนความจำให้กับความฉลาดทาง

ที่จุดเริ่มต้นของโปรแกรมซอร์สโค้ด (ยกเว้นอักขระตัวสุดท้าย) จะถูกส่งไปยังสแต็ก

เมื่อ IP ถึงขอบของซอร์สโค้ดมันจะสิ้นสุดลง

วันโลกาวินาศล่มสลาย

n และ m คือสองการลงทะเบียน เมื่อ>คำสั่งถูกดำเนินการ m จะเพิ่มขึ้น การเปิดเผยจะเกิดขึ้นก็ต่อเมื่อ m เกิน n เมื่อคติเกิดขึ้นมัน:

  • หมุนทวนเข็มนาฬิกาแทนทวนเข็มนาฬิกา
  • m กลายเป็น 0
  • n กลายเป็นด้านบนของสแต็ก จากนั้นสแตกจะถูกตอก

m เป็นศูนย์เริ่มแรกและ n เป็นอักขระตัวสุดท้ายของรหัสต้นฉบับ

การเข้ารหัสลับ

หลังจากดำเนินการใด ๆ รหัสแหล่งที่มาจะถูกเข้ารหัส ASCII ของอักขระตัวที่หนึ่งเพิ่มขึ้นทีละหนึ่งตัวที่สองจะถูกลดจำนวนลงหนึ่งตัวที่สามจะเพิ่มขึ้นสองตัวอันดับที่ 4 จะลดลงสองตัวเป็นต้น


1
รักแน่ใจว่าคุณต้องการล่ามจะมีนี้เป็นคำตอบที่ถูกต้อง ...
Conor โอไบรอัน

@ ConorO'Brien เมื่อความท้าทายนี้หมดอายุไปแล้วนี่เป็นเรื่องสนุก ฉันจะจัดหาล่ามให้
HighlyRadioactive

@ HighlyRadioactive ... คุณพูดเมื่อเกือบหนึ่งเดือนที่แล้ว
pppery
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.