วิธีการแก้ปัญหาที่สง่างามสำหรับการระบายสีกระเบื้องหมากรุก


19

ฉันกำลังพัฒนาเกมหมากรุกที่ฉันเขียนขึ้นในจาวาอีกครั้งและสงสัยว่ามีอัลกอริทึมที่สง่างามในการระบายสีกระดานหมากรุกบนกระดานหมากรุกที่มีหมายเลขหรือไม่

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


ทำไมคุณถึงต้องการอัลกอริธึมที่หรูหรากว่านี้ในการทำบางสิ่งพื้นฐาน แค่อยากรู้หรือ ...
ssb

5
สุจริตฉันแค่อยากรู้อยากเห็น
Amir Afghanani

คำตอบ:


40

วิธีที่หรูหราที่สุดที่ฉันสามารถนึกได้เมื่อคุณมีrowและcolumnดัชนีมีดังต่อไปนี้:

bool isLight = (row % 2) == (column % 2);

หรือตรงกันข้าม:

bool isDark = (row % 2) != (column % 2);

โดยพื้นฐานแล้วไทล์บนกระดานหมากรุกจะมีแสงในบริเวณที่ทั้งคอลัมน์และแถวคี่หรือคู่กันและจะมืด


4
ทางออกที่ดีมาก แม้ว่าความคิดเห็นของคุณจะทำให้เข้าใจผิด: "ไทล์บนกระดานหมากรุกนั้นมีน้ำหนักเบาไม่ว่าจะอยู่ที่ใดทั้งคอลัมน์และแถว" ไม่เป็นความจริง .. สมมติว่าแถวคือ 3 และคอลัมน์คือ 5 (ทั้งคู่ไม่เท่ากัน ) 3 % 2 == 1และ5 % 2 == 1.. ดังนั้นทั้งคู่จึงไม่สม่ำเสมอ แต่จะมีสี "เบา" ไม่ได้บอกว่าทางออกของคุณผิด (มันดีเพราะมันจะเปลี่ยนรูปแบบ) แต่ความคิดเห็น / คำอธิบายของคุณดูเหมือนผิด
bummzack

อ๊ะขอบคุณที่ให้ @bummzack อัปเดตคำตอบ
kevintodisco

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

34
bool isLight = ((row ^ column) & 1) == 0;

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


5
^ดี แต่+ทำงานได้ดีพอ ๆ กัน :)
Chris Burt-Brown

2
สำหรับเรื่องนั้นได้-ผลเช่นกัน :)
Trevor Powell

2
การดำเนินงานบิต ftw :)
Mike Cluck

3
ชอบคนอื่น ๆ เพราะนี่คือ "อ่านไม่ได้" (ฉันรู้ว่าการดำเนินการบิตไม่ได้หมายความว่ามันสามารถบำรุงรักษาได้)
Matsemann

22

ข้อเสนอแนะอื่นตรงไปตรงมามาก:

isLight = (row + column) % 2 == 0;

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

แม้แต่จำนวนก้าวก็ให้สีอ่อน
จำนวนก้าวที่ผิดเพี้ยนจะทำให้สีเข้ม


โดยพื้นฐานเหมือนกับคำตอบของนาธานที่เขียนแตกต่างกัน
API-Beast

@ Mr.Beast: & 1จะมีประสิทธิภาพมากกว่า% 2นี้มากเว้นแต่จะปรับปรุงให้ดีขึ้นเป็นพิเศษ แต่โดยทั่วไปฉันเห็นด้วย
LarsH

1
@ LarsH คอมไพเลอร์จะดูแลสิ่งต่าง ๆ เหล่านั้น (หรืออย่างน้อยก็ควร)
neeKo

@ LarsH ฉันตั้งใจอ่านง่ายไม่ใช่ความเร็ว แต่มีไม่มากในนั้น ฉันไม่แน่ใจว่าความเร็วที่แตกต่างระหว่างทั้งสองนั้นสามารถพิจารณาได้ว่า "มาก" เมื่อเรารู้ว่ามันจะถูกเรียกว่า 64 ครั้งเท่านั้นและฉันคิดว่าคอมไพเลอร์สมัยใหม่จะสร้างไบนารีที่เหมือนกันอยู่แล้ว
Chris Burt-Brown

@Chris: ฉันกำลังพูดถึงประสิทธิภาพของการดำเนินงาน% ซึ่งไม่ได้รับผลกระทบจากจำนวนครั้งที่เรียกว่า แต่ฉันเห็นด้วยมันไม่น่าจะสร้างความแตกต่างในทางปฏิบัติของความเร็วของโปรแกรมและฉันก็เห็นด้วยเกี่ยวกับความสำคัญของการอ่านที่เกี่ยวข้องกับการปรับปรุงความเร็วที่อาจเกิดขึ้น
LarsH

4

อันนี้สมมติว่ากำลังสองของเราอยู่ในช่วง [0..63]

bool IsLight(int i)
{
    return 0!=(i>>3^i)&1;
}

การหาสาเหตุว่าทำไมมันจึงใช้งานได้ครึ่งหนึ่งของความสนุก :)


แนวทางที่น่าสนใจ แต่คุณไม่ต้องทำอะไรบางอย่างกับค่าส่งคืนเพื่อให้มันกลายเป็นบูลเช่นreturn (i>>3 ^ i) & 1 != 0? java อนุญาตให้แปลงจำนวนเต็มเป็นบูลีนโดยนัยหรือไม่
LarsH

อาคุณพูดถูก ฉันอ่านตรงไปที่บิต "Java" และเขียนคำตอบที่คิดเกี่ยวกับ C ++ กำลังแก้ไขคำตอบของฉัน
Trevor Powell

นี่คือกระดานที่ดีที่สุดอย่างชัดเจน
Marcks Thomas

1
วิธีการนี้ดึงดูดผมแบบเดียวกับที่ Perl สนใจผม ความเข้าใจที่รวบรัดประเภทนี้สนุกที่จะเขียนเสมอ แก้ปัญหาความสนุกน้อยลง
Trevor Powell

2
  1. หมายเลขกระเบื้อง คุณสามารถหาข้อมูลนี้ได้โดยการคำนวณคอลัมน์ * 8 + หรือสิ่งที่คล้ายกัน

  2. รับโมดูลัส 16 ของหมายเลขกริด (มี 16 ตำแหน่งก่อนที่กระเบื้องจะทำซ้ำ)

  3. สีกระเบื้องขึ้นอยู่กับว่ามันมีเลขคู่หรือคี่ พลิกสีกระเบื้องถ้าผลลัพธ์มากกว่า 7

รหัสสำหรับดัชนี zero-based:

int cellNum = (row*8+column) % 16;
bool isSecondRow = cellNum > 7;
if(cellNum % 2 == 0 ^ isSecondRow){ //XOR operator
    setColor(Color.White);
}else{
    setColor(Color.Charcoal);
}

ทำไมคุณถึงแยกแถวที่สองออกมา? สิ่งนี้ควรใช้กับ 8 แถวทั้งหมด
อาเมียร์อัฟกัน

1
ฉันไม่เข้าใจคำถามของคุณ การmodulus 16ดำเนินการช่วยลดปัญหาให้สองแถว แถวที่สองเป็นไปตามรูปแบบที่แตกต่างจากแถวแรก ifคำสั่งเพียงประเมินจริงถ้าทั้งเป็นแฮคเกอร์กระเบื้องเลขไม่ได้อยู่ในแถวที่สอง หากทั้งสองเป็นจริงมันจะประเมินเป็นเท็จ ตรวจสอบผู้ให้บริการ XOR: msdn.microsoft.com/en-us/library/zkacc7k1.aspx
Jim

1
IsSecondRowควรได้รับการเสนอชื่อIsEvenRowจริงๆ เป็นวิธีที่ค่อนข้างซับซ้อนในการรับบิตของแถวต่ำ: อันดับแรกเปลี่ยนบิตของแถว 3 ตำแหน่งไปทางขวาแล้วละทิ้งทั้งหมดยกเว้น LSB ของแถวจากนั้นตรวจสอบว่ามีการตั้งค่าบิตที่ 4 ของเซลล์
MSalters

ฉันเห็น. +1 สำหรับคำตอบ
อาเมียร์อัฟกานี

บางทีตัวอย่างที่ดีว่าทำไมความสง่างามจึงไม่ใช่ทางออกที่ดีที่สุดเสมอไป ;)
Jim

0

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

ถ้าฉันจะไปให้ไกลที่สุดเท่าที่จะทำได้และทำให้มันง่ายที่จะออกแบบรูปแบบบนกระดานหมากรุกให้มากที่สุดนี่คือสิ่งที่ฉันจะทำ:

1) ฉันจะสร้างไฟล์ที่ระบุสีแต่ละตารางในกระดานหมากรุก

ตัวอย่างเช่นฉันสามารถสร้างไฟล์chess_board_pattern.configที่มีลักษณะดังนี้:

bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb

2) ฉันจะเขียน class / component / อะไรก็ตามที่สามารถอ่านไฟล์นี้และสร้างวัตถุบางชนิดที่แสดงถึงรูปแบบของบอร์ด:

public class BoardPattern {
    private Color[][] pattern;

    public BoardPattern(File patternFile)
    {
        pattern = new Color[8][8];
        //Parse the file and fill in the values of pattern
    }

    public Color[][] getPattern {
        return pattern;
    }
}

3) ฉันจะใช้คลาสนั้นในฟังก์ชั่นที่วาดกระดานจริง

File patternFile = new File("chess_board_pattern.ini");
Color[][] pattern = new BoardPattern(patternFile).getPattern();
ChessBoardDrawable chessBoard = new ChessBoardDrawable();

for(int row = 0; row < 8; row++) {
    for(int column; column < 8; column++) {
        chessBoard.drawSquare(row, column, Color[row][column]);
    }
}

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


8
คุณควรโพสต์นี้เพื่อthedailywtf.com :)
avakar

11
ไม่สามารถป้อนได้เพียงพอต้องการ XML เพิ่มเติม
Maximus Minimus

3
สวัสดีเควิน คุณเขียนThe one-liners used in answers so far would have to be re-written.แต่ยังit's best to come up with generalized solutions like this instead of writing code that's difficult to change later.แต่คุณต้องเข้าใจว่ารหัสนี้ยากมากที่จะฉีกและเขียนใหม่กว่าบรรทัดเดียว ดังนั้นฉันจึงลงคะแนนให้คุณเพราะมันไม่ได้สวยงามหรือแนะนำให้ทำ
Chris Burt-Brown

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

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