ฉันจะใช้บางอย่างเช่นตารางการประดิษฐ์ของ Minecraft ได้อย่างไร


55

ระบบงานหัตถกรรมใน Minecraftใช้ 2x2 หรือ 3x3 ตาราง คุณวางส่วนผสมลงในตารางและถ้าคุณใส่ส่วนผสมที่ถูกต้องในรูปแบบที่ถูกต้องมันจะเปิดใช้งานสูตร

บางประเด็นที่น่าสนใจเกี่ยวกับการออกแบบ:

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

ฉันอาจจะคิดมาก แต่ดูเหมือนว่าปัญหาการค้นหา / การตั้งค่าการลดที่น่าสนใจ ดังนั้นงานนี้หรือพูดได้อย่างไร


6
คำถามยอดเยี่ยม! ฉันสนใจมาก! ฉันมีความคิดบางอย่างอยู่แล้ว แต่และฉันจะแบ่งปันทันทีที่กลับถึงบ้าน
jcora

ที่จริงฉันกำลังพยายามเขียนสำเนา Minecraft "ใกล้ที่สุดเท่าที่จะเป็นไปได้" ฉันเขียนสิ่งที่ผู้จัดการสินค้าคงคลังและสูตรทั้งหมดแล้วและฉันต้องบอกว่ามันทำงานได้ดีมาก ฉันพอใจกับรหัสสะอาด อย่างไรก็ตามมันไม่ง่ายที่จะเขียน ฉันเขียนประมาณ 10 คลาสเพื่อให้มันทำงานได้อย่างดีทั้งสูตรกริดสินค้าคงคลัง ฯลฯ เมื่อฉันหาเวลาฉันจะเขียนคำตอบ
Martijn Courteaux

คุณควรดูว่า minecraft ให้รหัสสูตรการคราฟของพวกเขาอย่างไร
Bradman175

คำตอบ:


14

อีกวิธีคือใช้ต้นไม้ที่ค่อนข้างซับซ้อน โหนดสาขาในต้นไม้ของคุณจะถูกสร้างขึ้นโดยวนซ้ำสูตร (ใช้อีกครั้งfor (y) { for (x) }); นี่คือโครงสร้างต้นไม้แบบ by-the-book ของคุณ โหนดสุดท้ายของคุณจะมีโครงสร้างเพิ่มเติม ( Dictionary/ HashMap) ที่แมปมิติกับสูตรอาหาร

สิ่งสำคัญที่คุณจะทำคือ:

สูตรต้นไม้

โหนดสีดำเป็นสาขาของคุณที่ระบุประเภทรายการ - ส่วนสีแดงคือใบของคุณ (เทอร์มิเนเตอร์) ซึ่งช่วยให้คุณแยกขนาด / การวางแนวได้

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

เพียงแค่เตะฉันไปและดำเนินการนี้ - ซึ่งอาจจะชี้แจงคำตอบของฉัน อีกทั้งฉันตระหนักว่านี่เป็นคำตอบที่แตกต่าง - และโดยชอบธรรม: มันเป็นทางออกที่แตกต่าง


ตรงไปตรงมามาก ฉันชอบมัน.
David Eyk

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

23

คุณต้องจำไว้ว่า Minecraft ใช้ชุดของสูตรที่เป็นไปได้เพียงเล็กน้อยดังนั้นไม่จำเป็นต้องมีอะไรที่ฉลาด

ที่กล่าวว่าสิ่งที่ฉันจะทำคือการหาตารางที่เล็กที่สุดที่เหมาะสม (เช่นละเว้นแถวและคอลัมน์ที่ว่างเปล่าเพื่อดูว่ามันเป็น 2x2 หรือ 3x3 หรือ 2x3 (ประตู)) จากนั้นวนรอบรายการสูตรอาหารที่มีขนาดนั้นเพียงแค่ตรวจสอบว่าประเภทรายการนั้นเหมือนกัน (เช่นที่การเปรียบเทียบจำนวนเต็ม 9 จำนวนที่แย่ที่สุดใน minecraft เพราะใช้รหัสประเภทจำนวนเต็มสำหรับรายการและบล็อก) และหยุดเมื่อคุณพบคู่ที่ตรงกัน

วิธีนี้ยังทำให้ตำแหน่งสัมพัทธ์ของรายการที่ไม่เกี่ยวข้อง (คุณสามารถวางไฟฉายไว้ที่ใดก็ได้บนตารางการประดิษฐ์และมันจะทำงานได้เพราะมันเห็นว่าเป็นกล่อง 1x2 ไม่ใช่กล่อง 3x3 ซึ่งส่วนใหญ่จะว่างเปล่า)

หากคุณมีสูตรจำนวนมากเพื่อให้การค้นหาเชิงเส้นผ่านการจับคู่ที่เป็นไปได้ใช้เวลานานมันจะเป็นไปได้ที่จะเรียงลำดับรายการและทำการค้นหาแบบไบนารี (O (log (N)) vs O (N) สิ่งนี้จะทำให้มีงานพิเศษในการสร้างรายการ แต่สามารถทำได้เมื่อเริ่มต้นเพียงครั้งเดียวและเก็บไว้ในหน่วยความจำหลังจากนั้น

อีกสิ่งหนึ่งที่สุดท้ายเพื่อให้การพลิกสูตรในแนวนอนที่ง่ายที่สุดคือเพียงเพิ่มเวอร์ชันที่มิเรอร์ในรายการ

หากคุณต้องการทำโดยไม่เพิ่มสูตรที่สองคุณสามารถตรวจสอบว่าสูตรการป้อนมีรายการใน [0,0] ที่มี id สูงกว่าใน [0,2] (หรือ [0,1] สำหรับ 2x2 ไม่จำเป็นต้องตรวจสอบ สำหรับ 1x2 และหากเป็นเช่นนั้นให้มิร์เรอร์ถ้าไม่ตรวจสอบแถวถัดไปจนกว่าจะถึงจุดสิ้นสุดการใช้สิ่งนี้คุณต้องตรวจสอบให้แน่ใจว่าได้เพิ่มสูตรในการหมุนที่ถูกต้อง


1
ฉันสงสัยว่าสูตรอาหารจำนวนเล็กน้อยใน Minecraft อาจไม่สามารถกู้ตัวเองให้ค้นหาเชิงเส้นได้
David Eyk

1
มันเป็นและเป็นสิ่งที่ฉันเขียนไว้ด้านบน (ด้วยการปรับให้เหมาะสมที่สุดของการค้นหาแบบไบนารี) อย่างไรก็ตามมีตัวเลือกไม่กี่ตัวสำหรับการสร้างคบเพลิงซึ่งคุณสามารถใส่ได้ทุกที่ ในการเริ่มต้นรับขนาดของสูตรคุณไม่จำเป็นต้องเพิ่ม 6 สูตรสำหรับไฟฉายและคุณ จำกัด การค้นหาเฉพาะขนาดที่ถูกต้องในขั้นตอนเดียว - ดังนั้นโดยทั่วไปตัวเลือกสำหรับจุดที่ 2 ของคุณคือจัดกลุ่มตามขนาดย้ายสูตรไปที่มุมหรือเพิ่มสูตรที่ซ้ำกันเพิ่มเติม
Elva

15

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

ขั้นตอนที่ 1) เข้ารหัสตารางเป็นสตริง

เพียงให้รหัสตัวอักษรกับเซลล์แต่ละประเภทและเชื่อมทุกอย่างเข้าด้วยกันตามลำดับนี้:

123
456 => 123456789
789

และเป็นตัวอย่างที่เป็นรูปธรรมมากขึ้นพิจารณาสูตรไม้ที่ W หมายถึงไม้และ E เป็นเซลล์ว่าง (คุณสามารถใช้ถ่านที่ว่างเปล่า '):

EEE
WEE => EEEWEEWEE
WEE

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

ต่อจากตัวอย่างด้านบนแม้ว่าเราจะย้ายขบวนไปมารอบ ๆ แต่ก็ยังมีรูปแบบในสายอักขระ (WE เบาะด้วย E ทั้งสองด้าน):

EEW
EEW => EEWEEWEEE
EEE

ดังนั้นไม่ว่าคุณจะขยับคันโยกไปรอบ ๆ ที่ใดมันจะยังคงตรงกับนิพจน์ทั่วไปต่อไปนี้: /^E*WEEWE*$/

นิพจน์ทั่วไปยังช่วยให้คุณสามารถดำเนินการตามเงื่อนไขที่คุณกล่าวถึง ตัวอย่างเช่น (สูตรที่ทำขึ้น) หากคุณต้องการ pickaxe ที่ทำจากเหล็กหรือหินเพื่อให้ผลลัพธ์เดียวกันเช่น:

III    SSS
EWE or EWE
EWE    EWE

คุณสามารถรวมทั้งสองอย่างเข้ากับนิพจน์ทั่วไป: /^(III)|(SSS)EWEEWE$/

นอกจากนี้ยังสามารถเพิ่มการพลิกในแนวนอนได้เช่นกัน (โดยใช้ตัวดำเนินการ | ด้วย)

แก้ไข: อย่างไรก็ตามส่วน regex ไม่จำเป็นอย่างเคร่งครัด มันเป็นวิธีเดียวในการสรุปปัญหาในนิพจน์เดียว แต่สำหรับปัญหาตำแหน่งตัวแปรคุณสามารถตัดทอนกริดสตริงของช่องว่างภายในช่องว่างใด ๆ (หรือ E ในตัวอย่างนี้) และทำ String.Contains () และสำหรับปัญหาส่วนผสมหลายอย่างหรือสูตรอาหารที่ทำมิเรอร์คุณสามารถจัดการได้ทั้งหมดเป็นสูตรหลาย ๆ สูตร (เช่นแยกต่างหาก) ด้วยผลลัพธ์เดียวกัน

ขั้นตอนที่ 3) เร่งการค้นหา

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

  1. คุณสามารถกำหนด "ความยาว" ของสูตรอาหารว่าเป็นระยะห่างระหว่างอักขระที่ไม่ว่างตัวแรกและอักขระที่ไม่ว่างเปล่าตัวสุดท้าย ง่ายๆTrim().Length()จะให้ข้อมูลนี้กับคุณ ตำรับอาหารสามารถจัดกลุ่มตามความยาวและเก็บไว้ในพจนานุกรม

    หรือ

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

  2. หากจุดที่ 1 ไม่เพียงพอสูตรอาหารอาจถูกจัดกลุ่มตามประเภทของส่วนผสมแรกที่ปรากฏในสูตร นี่จะง่ายเหมือนการทำTrim().CharAt(0)(และการป้องกันการตัดทำให้สตริงว่าง)

ตัวอย่างเช่นคุณจะเก็บสูตรไว้ใน:

Dictionary<int, Dictionary<char, List<string>>> _recipes;

และทำการค้นหาตามที่ต้องการ:

// A string encode of your current grid configuration 
string grid;

// Get length and first char in our grid
string trim = grid.Trim();
int length = trim.Length();
char firstChar = length==0 ? ' ' : trim[0];

foreach(string recipe in _recipes[length][firstChar])
{
    // Check for a match with the recipe
    if(Regex.Match(grid, recipe))
    {
        // We found a matching recipe, do something with it
    }
}

3
นี่คือ ... ฉลาดมาก ๆ
Raveline

18
คุณมีปัญหาและต้องการแก้ไขโดยใช้นิพจน์ทั่วไปหรือไม่ ตอนนี้คุณมีปัญหา 2 ข้อ :)
Kromster

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

2
@DavidGouveia นั่นเป็นเพียงวลีสำหรับคนที่ไม่สบายใจกับ Regex หากพวกเขาตัดสินใจที่จะแก้ปัญหาด้วย regex ตอนนี้พวกเขามีสองปัญหา: (1) ปัญหาจริงที่พวกเขาต้องการแก้ (2) การเขียนรูปแบบ regex เพื่อแก้ปัญหานั้น
iamserious

2
กลับไปที่ 'ตอนนี้คุณมีปัญหาสองข้อ' - Regex จะมีปัญหาทันทีที่คุณมีรายการมากกว่าช่วงที่พิมพ์ได้ของ ASCII เว้นแต่ว่าตัวประมวลผล regex ของคุณรองรับยูนิโค้ดและคุณสามารถรับประกันได้ว่าชุดค่าผสมบางอย่างจะไม่เดินทาง regex NFA ขึ้น คุณสามารถรวม DFA ของคุณเอง (ค่อนข้างง่าย) เข้าด้วยกันเพื่อจับคู่รูปแบบ แต่ regex จะเป็นวิธีที่ดีที่สุดในการสร้างต้นแบบ
Jonathan Dickinson

3

ฉันไม่สามารถบอกคุณได้ว่า Minecraft ทำงานอย่างไร - แม้ว่าฉันจะแน่ใจว่าถ้าคุณดู MCP (ถ้าคุณมีสำเนา Minecraft ที่ถูกกฎหมาย) คุณก็จะพบ

ฉันจะใช้สิ่งนี้ดังนี้:

  1. มีพจนานุกรม / hashmap บนดิสก์ ( B + Tree / SQL-Light ) - ค่าจะเป็น ID รายการของผลลัพธ์สูตร
  2. เมื่อผู้ใช้งานหัตถกรรมบางสิ่งบางอย่างเพียงแค่คุณหาแถวแรก / คอลัมน์ที่มีรายการที่เป็นอิสระ ; รวมสิ่งเหล่านั้นเข้าด้วยกัน
  3. ค้นหาแถว / คอลัมน์สุดท้ายด้วยรายการอีกครั้งอย่างอิสระ
  4. คำนวณความกว้างและความสูงจากรายการและเพิ่มไปยังคีย์
  5. วนรอบช่วงของกล่องขอบเขตที่คุณเพิ่งคำนวณและผนวก ID ของแต่ละรายการ (ใช้ของคุณตามปกติfor (y) { for (x) })
  6. ค้นหาคีย์ในฐานข้อมูล

ตัวอย่างเช่นสมมติว่าเรามีสองส่วนผสม; X และ Y และช่องว่างเป็น * ใช้สูตรต่อไปนี้:

**X
**Y
**Y

ก่อนอื่นเราหาช่อง จำกัด ให้(2,0)-(2,2)ได้ ดังนั้นกุญแจของเราจะเป็นแบบนี้[1][3](1 ความกว้าง 3 ความสูง) ต่อไปเราจะวนแต่ละรายการในกล่อง bounding และผนวกรหัสดังนั้นคีย์กลายเป็น[1][3][X][Y][Y]- จากนั้นคุณค้นหาในพจนานุกรม / DB ของคุณและคุณจะได้รับผลลัพธ์ของสูตรนั้น

เพื่ออธิบายความเป็นอิสระในขั้นตอนที่ 2 ให้ชัดเจนยิ่งขึ้นให้พิจารณาสูตรต่อไปนี้:

*XX
XXX
XX*

ด้านบน / ซ้ายชัดเจนที่ 0,0 - อย่างไรก็ตามรายการแรกที่คุณจะพบมักจะเป็น 0,1 หรือ 1,0 (ขึ้นอยู่กับวงของคุณ) อย่างไรก็ตามหากพบคอลัมน์ที่ไม่ว่างแรกเช่นเดียวกับแถวที่ไม่ว่างแรกและรวมพิกัดเหล่านั้นคุณจะได้รับ 0,0 - เงินต้นเดียวกันนี้ใช้กับด้านล่าง / ขวาของกล่องขอบเขต


ที่เก็บข้อมูล Bukkit ไม่มีรหัส Minecraft ใด ๆ คุณต้องใช้MCP (และสำเนา Minecraft)
BlueRaja - Danny Pflughoeft

นี่ไม่ใช่แค่คำตอบที่ตรงกันข้ามของคุณใช่ไหม
David Eyk

@DavidEyk (นี่เป็นคำตอบแรกของฉัน) ไม่ใช่จริงๆมันขึ้นอยู่กับโครงสร้าง hashmap (ไม่ว่าจะเป็น bigtable-like หรือ in-memory) เหตุผลที่ฉันตอบอีกครั้งเพราะฉันกังวลเกี่ยวกับการชนของแฮชที่นำไปสู่ประสิทธิภาพที่ต่ำ - อย่างน้อยในแฮชแมปในหน่วยความจำ คำตอบอื่น ๆ ของฉันจะทำงานได้ดีขึ้นสำหรับรายการเพิ่มเติมและโครงสร้างในหน่วยความจำ - ซึ่งจะทำงานได้ดีขึ้นถ้าเป็นใน SQL / etc
Jonathan Dickinson

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