คุณสามารถดูระบบของคุณราวกับว่ามันประกอบด้วยชุดของรัฐและฟังก์ชั่นที่ฟังก์ชั่นที่f[j]
มีการป้อนข้อมูลx[j]
เปลี่ยนสถานะของระบบs[j]
เข้าสู่สถานะs[j+1]
เช่น:
s[j+1] = f[j](s[j], x[j])
สถานะคือคำอธิบายของโลกทั้งใบของคุณ ตำแหน่งของผู้เล่นตำแหน่งของศัตรูคะแนนกระสุนที่เหลือ ฯลฯ ทุกสิ่งที่คุณต้องการในการวาดเฟรมเกมของคุณ
ฟังก์ชั่นคือทุกสิ่งที่อาจส่งผลกระทบต่อโลก การเปลี่ยนเฟรม, ปุ่มกด, แพ็กเก็ตเครือข่าย
อินพุตคือข้อมูลที่ฟังก์ชั่นใช้งาน การเปลี่ยนเฟรมอาจใช้เวลานานนับตั้งแต่เฟรมสุดท้ายผ่านไปการกดปุ่มอาจรวมถึงการกดปุ่มจริงรวมถึงการกดปุ่ม Shift หรือไม่
เพื่อประโยชน์ในการอธิบายนี้ฉันจะทำให้สมมติฐานต่อไปนี้:
ข้อสันนิษฐาน 1:
จำนวนรัฐสำหรับการวิ่งของเกมนั้นมีขนาดใหญ่กว่าจำนวนฟังก์ชั่น คุณอาจมีสถานะเป็นแสน แต่มีฟังก์ชั่นหลายโหลเท่านั้น (การเปลี่ยนเฟรม, ปุ่มกด, แพ็คเก็ตเครือข่าย ฯลฯ ) แน่นอนปริมาณของอินพุตจะต้องเท่ากับจำนวนของรัฐลบหนึ่ง
ข้อสมมติฐาน 2:
ราคาพิเศษ (หน่วยความจำ, ดิสก์) ของการจัดเก็บในสถานะเดียวจะยิ่งใหญ่กว่าการจัดเก็บฟังก์ชั่นและอินพุตของมัน
ข้อสันนิษฐาน 3:
ค่าใช้จ่ายชั่วคราว (เวลา) ของการนำเสนอรัฐจะคล้ายกันหรือเพียงหนึ่งหรือสองคำสั่งของขนาดยาวกว่าการคำนวณฟังก์ชั่นมากกว่ารัฐ
ขึ้นอยู่กับข้อกำหนดของระบบการเล่นซ้ำของคุณมีหลายวิธีในการนำระบบการเล่นซ้ำมาใช้ดังนั้นเราจึงสามารถเริ่มต้นด้วยวิธีที่ง่ายที่สุดได้ ฉันจะทำตัวอย่างเล็ก ๆ โดยใช้เกมหมากรุกบันทึกไว้ในแผ่นกระดาษ
วิธีที่ 1:
s[0]...s[n]
ร้านค้า ง่ายมากตรงไปตรงมามาก เนื่องจากข้อสันนิษฐานที่ 2 ทำให้ราคาพิเศษของสิ่งนี้ค่อนข้างสูง
สำหรับหมากรุกสิ่งนี้จะสำเร็จได้โดยการวาดกระดานทั้งหมดสำหรับแต่ละท่า
วิธีที่ 2:
หากคุณต้องการเล่นซ้ำไปข้างหน้าคุณสามารถจัดเก็บs[0]
แล้วเก็บf[0]...f[n-1]
(จำไว้ว่านี่เป็นเพียงชื่อของฟังก์ชั่น id) และx[0]...x[n-1]
(สิ่งที่ป้อนเข้าสำหรับแต่ละฟังก์ชั่นเหล่านี้) ในการเล่นซ้ำคุณเพียงเริ่มต้นด้วยs[0]
และคำนวณ
s[1] = f[0](s[0], x[0])
s[2] = f[1](s[1], x[1])
และอื่น ๆ ...
ฉันต้องการทำคำอธิบายประกอบขนาดเล็กที่นี่ ผู้วิจารณ์คนอื่นกล่าวว่าเกมนี้ "ต้องกำหนดขึ้นแน่นอน" ทุกคนที่บอกว่าจำเป็นต้องใช้วิทยาการคอมพิวเตอร์ 101 อีกครั้งเพราะถ้าหากเกมของคุณไม่ได้ทำงานบนคอมพิวเตอร์ควอนตัมโปรแกรมคอมพิวเตอร์ทั้งหมดจะถูกกำหนดไว้ล่วงหน้า นั่นคือสิ่งที่ทำให้คอมพิวเตอร์ยอดเยี่ยมมาก
อย่างไรก็ตามเนื่องจากโปรแกรมของคุณส่วนใหญ่ขึ้นอยู่กับโปรแกรมภายนอกตั้งแต่ไลบรารีไปจนถึงการใช้งานจริงของ CPU ทำให้แน่ใจว่าฟังก์ชั่นของคุณทำงานเหมือนกันระหว่างแพลตฟอร์มอาจจะค่อนข้างยาก
หากคุณใช้ตัวเลขสุ่มหลอกคุณสามารถเก็บหมายเลขที่สร้างขึ้นเป็นส่วนหนึ่งของการป้อนข้อมูลของคุณx
หรือเก็บสถานะของฟังก์ชั่น PRNG เป็นส่วนหนึ่งของรัฐของคุณและการดำเนินการในฐานะที่เป็นส่วนหนึ่งของฟังก์ชั่นs
f
สำหรับหมากรุกสิ่งนี้จะสำเร็จได้โดยการวาดกระดานเริ่มต้น (ซึ่งเป็นที่รู้จัก) แล้วอธิบายแต่ละท่าว่าชิ้นส่วนไหนไปไหน นี่คือวิธีที่พวกเขาทำได้จริงโดยวิธี
วิธีที่ 3:
ตอนนี้คุณน่าจะต้องการค้นหาการเล่นซ้ำของคุณอีกครั้ง นั่นคือการคำนวณการโดยพลการs[n]
n
โดยใช้วิธีที่ 2 คุณจะต้องคำนวณs[0]...s[n-1]
ก่อนจึงจะสามารถคำนวณs[n]
ซึ่งตามสมมติฐานที่ 2 อาจช้า
ในการดำเนินการนี้วิธีที่ 3 เป็นลักษณะทั่วไปของวิธีการที่ 1 และที่ 2: การจัดเก็บf[0]...f[n-1]
และx[0]...x[n-1]
เช่นเดียวกับวิธีที่ 2 แต่ยังร้านค้าs[j]
สำหรับทุกสำหรับให้คงที่j % Q == 0
กล่าวง่ายๆคือQ
คุณเก็บที่คั่นหนังสือไว้ที่ทุกQ
รัฐ ตัวอย่างเช่นสำหรับQ == 100
คุณจัดเก็บs[0], s[100], s[200]...
ในการคำนวณs[n]
สำหรับพลn
แรกคุณโหลดเก็บไว้ก่อนหน้าs[floor(n/Q)]
แล้วคำนวณฟังก์ชั่นทั้งหมดจากการfloor(n/Q)
n
อย่างมากคุณจะคำนวณQ
ฟังก์ชัน ค่าที่น้อยกว่าของQ
การคำนวณได้เร็วขึ้น แต่ใช้พื้นที่มากขึ้นในขณะที่ค่าที่มากขึ้นของการQ
ใช้พื้นที่น้อยลง แต่ใช้เวลาในการคำนวณนานกว่า
วิธีที่ 3 ด้วยQ==1
จะเหมือนกับวิธีที่ 1 ในขณะที่วิธีที่ 3 ด้วยQ==inf
จะเหมือนกับวิธีที่ 2
สำหรับหมากรุกสิ่งนี้จะสำเร็จได้โดยการวาดทุกการเคลื่อนไหวและหนึ่งในทุก ๆ 10 บอร์ด (สำหรับQ==10
)
วิธีที่ 4:
หากคุณต้องการที่จะกลับ replay คุณสามารถทำให้การเปลี่ยนแปลงเล็ก ๆ ของวิธีที่ 3 สมมติQ==100
และคุณต้องการที่จะคำนวณs[150]
ผ่านs[90]
ในสิ่งที่ตรงกันข้าม ด้วยวิธีที่ไม่มีการแก้ไข 3 คุณจะต้องทำการคำนวณ 50 ครั้งเพื่อรับs[150]
และอีก 49 การคำนวณเพื่อให้ได้รับs[149]
และต่อไป แต่เนื่องจากคุณคำนวณแล้วว่าs[149]
จะได้รับs[150]
คุณสามารถสร้างแคชs[100]...s[150]
เมื่อคุณคำนวณs[150]
เป็นครั้งแรกและจากนั้นคุณก็อยู่s[149]
ในแคชเมื่อคุณต้องการที่จะแสดง
คุณจำเป็นที่จะงอกใหม่แคชทุกครั้งที่คุณจำเป็นต้องคำนวณs[j]
สำหรับสำหรับการใดก็ตามj==(k*Q)-1
k
เวลานี้การเพิ่มQ
จะส่งผลให้มีขนาดเล็กลง (สำหรับแคชเท่านั้น) แต่เวลาจะนานขึ้น (สำหรับการสร้างแคชใหม่) Q
สามารถคำนวณค่าที่เหมาะสมที่สุดได้หากคุณทราบขนาดและเวลาที่ต้องใช้ในการคำนวณสถานะและฟังก์ชัน
สำหรับหมากรุกสิ่งนี้จะสำเร็จได้โดยการวาดทุกการเคลื่อนไหวรวมถึงหนึ่งในทุก ๆ 10 บอร์ด (สำหรับQ==10
) แต่ก็ต้องวาดในกระดาษอีกแผ่นหนึ่งซึ่งเป็นกระดาน 10 อันดับสุดท้ายที่คุณคำนวณ
วิธีที่ 5:
หากสถานะนั้นใช้พื้นที่มากเกินไปหรือฟังก์ชั่นใช้เวลามากเกินไปคุณสามารถสร้างโซลูชันที่ใช้การเล่นซ้ำแบบย้อนกลับ (ไม่ใช่ของปลอม) ในการทำสิ่งนี้คุณต้องสร้างฟังก์ชั่นย้อนกลับสำหรับแต่ละฟังก์ชั่นที่คุณมี อย่างไรก็ตามสิ่งนี้ต้องการให้แต่ละฟังก์ชั่นของคุณเป็นการฉีด หากสิ่งนี้เป็นไปได้ดังนั้นสำหรับการf'
แสดงการกลับกันของฟังก์ชันการf
คำนวณs[j-1]
นั้นง่ายมาก
s[j-1] = f'[j-1](s[j], x[j-1])
โปรดทราบว่าในที่นี่ฟังก์ชั่นและใส่ทั้งสองไม่ได้j-1
j
ฟังก์ชันและอินพุตเดียวกันนี้จะเป็นฟังก์ชันที่คุณจะใช้หากคุณกำลังคำนวณ
s[j] = f[j-1](s[j-1], x[j-1])
การสร้างส่วนกลับของฟังก์ชันเหล่านี้เป็นส่วนที่ยุ่งยาก อย่างไรก็ตามคุณมักจะไม่สามารถทำได้เนื่องจากข้อมูลสถานะบางอย่างจะหายไปหลังจากแต่ละฟังก์ชั่นในเกม
วิธีนี้ตามที่เป็นอยู่สามารถย้อนกลับคำนวณแต่ถ้าคุณมีs[j-1]
s[j]
ซึ่งหมายความว่าคุณสามารถดูการเล่นซ้ำย้อนหลังได้โดยเริ่มจากจุดที่คุณตัดสินใจเล่นซ้ำย้อนหลัง หากคุณต้องการเล่นซ้ำย้อนหลังจากจุดที่กำหนดคุณต้องผสมสิ่งนี้กับวิธีที่ 4
สำหรับหมากรุกสิ่งนี้ไม่สามารถนำไปใช้ได้เนื่องจากมีบอร์ดที่กำหนดและการย้ายครั้งก่อนคุณสามารถทราบได้ว่าชิ้นส่วนใดถูกย้าย แต่ไม่ใช่ตำแหน่งที่ย้ายมา
วิธีที่ 6:
สุดท้ายถ้าคุณไม่สามารถรับประกันได้ว่าการทำงานทั้งหมดของคุณเป็นการฉีดคุณสามารถทำเคล็ดลับเล็ก ๆ ได้ แทนที่จะให้แต่ละฟังก์ชั่นคืนค่าสถานะใหม่คุณยังสามารถให้คืนค่าข้อมูลที่ถูกทิ้งเช่น:
s[j+1], r[j] = f[j](s[j], x[j])
r[j]
ข้อมูลที่ถูกทิ้งอยู่ที่ไหน จากนั้นสร้างฟังก์ชันผกผันของคุณเพื่อให้พวกเขานำข้อมูลที่ถูกทิ้งไปเช่น:
s[j] = f'[j](s[j+1], x[j], r[j])
นอกจากนี้f[j]
และx[j]
คุณยังต้องจัดเก็บr[j]
สำหรับแต่ละฟังก์ชั่น อีกครั้งหากคุณต้องการที่จะหาคุณจะต้องเก็บที่คั่นหนังสือเช่นด้วยวิธีที่ 4
สำหรับหมากรุกสิ่งนี้จะเหมือนกับวิธีที่ 2 แต่ต่างจากวิธีที่ 2 ซึ่งบอกได้ว่าชิ้นส่วนไหนจะไปที่ไหนคุณต้องเก็บว่าแต่ละชิ้นมาจากไหน
การดำเนินงาน:
เนื่องจากวิธีนี้ใช้ได้กับทุกรัฐด้วยฟังก์ชั่นทุกชนิดสำหรับเกมเฉพาะคุณสามารถตั้งสมมติฐานได้หลายอย่างซึ่งจะทำให้ง่ายต่อการใช้งาน ที่จริงแล้วถ้าคุณใช้วิธีที่ 6 กับสถานะเกมทั้งหมดไม่เพียง แต่คุณจะสามารถเล่นซ้ำข้อมูล แต่ยังย้อนเวลากลับไปและเล่นต่อจากช่วงเวลาที่กำหนด นั่นคงเป็นสิ่งที่ยอดเยี่ยมมาก
แทนที่จะเก็บสถานะเกมทั้งหมดคุณสามารถเก็บขั้นต่ำเปล่าที่คุณต้องการวาดสถานะที่กำหนดและจัดลำดับข้อมูลนี้เป็นระยะเวลาคงที่ สถานะของคุณจะเป็นอนุกรมเหล่านี้และการป้อนข้อมูลของคุณจะแตกต่างระหว่างสองอนุกรม สิ่งสำคัญสำหรับการทำงานนี้คือการทำให้เป็นอันดับควรเปลี่ยนเพียงเล็กน้อยหากรัฐโลกเปลี่ยนไปเล็กน้อยเช่นกัน ความแตกต่างนี้สามารถเปลี่ยนแปลงได้อย่างสมบูรณ์ดังนั้นการใช้วิธีที่ 5 กับบุ๊กมาร์กจึงเป็นไปได้มาก
ฉันได้เห็นสิ่งนี้ถูกนำไปใช้ในเกมสำคัญบางเกมซึ่งส่วนใหญ่ใช้สำหรับเล่นซ้ำข้อมูลล่าสุดเมื่อมีเหตุการณ์ (เกิดขึ้นในเฟรมต่อวินาทีหรือมีคะแนนในเกมกีฬา)
ฉันหวังว่าคำอธิบายนี้จะไม่น่าเบื่อเกินไป
¹นี่ไม่ได้หมายความว่าบางโปรแกรมทำหน้าที่เหมือนไม่ได้กำหนดไว้ (เช่น MS Windows ^^) ตอนนี้อย่างจริงจังหากคุณสามารถสร้างโปรแกรมที่ไม่ได้กำหนดค่าไว้ในคอมพิวเตอร์ที่กำหนดขึ้นมาได้คุณมั่นใจได้เลยว่าคุณจะได้รับรางวัลเหรียญฟิลด์รางวัลทัวริงและอาจเป็นรางวัลออสการ์และแกรมมี่สำหรับทุกสิ่งที่คุ้มค่า