จะรู้ได้อย่างไรว่าสถานะ FEN นั้นถูกกฎหมาย?


19

ฉันกำลังทำโครงการส่วนบุคคลซึ่งเมื่อถึงจุดหนึ่งที่ฉันต้องตรวจสอบตำแหน่ง FEN ฉันเริ่มต้นด้วยการตรวจสอบพื้นฐานบางอย่างเช่นตรวจสอบว่ามีกษัตริย์และทำให้แน่ใจว่าไม่มีแถวหรือคอลัมน์พิเศษใด ๆ สิ่ง

แต่ฉันควรตรวจสอบอื่น ๆ อย่างไรเพื่อให้แน่ใจว่า FEN นั้นถูกกฎหมาย?

คำตอบ:


18

นี่คือรายการที่จัดระเบียบอย่างดีซึ่งควรตรวจสอบความถูกต้อง 99.99% + ของตำแหน่งทั่วไป:

คณะกรรมการ:

  • มี 8 cols อย่างแน่นอน
  • ผลรวมของสี่เหลี่ยมจัตุรัสที่ว่างและชิ้นเพิ่มเป็น 8 สำหรับแต่ละอันดับ (แถว)
  • ไม่มีหมายเลขติดต่อกันสำหรับช่องว่างสี่เหลี่ยม

กษัตริย์:

  • ดูว่ามีหนึ่ง w_king และ b_king หนึ่งรายการหรือไม่
  • ตรวจสอบให้แน่ใจว่าแยกกษัตริย์ออกจากกัน 1 ช่อง

การตรวจสอบ:

  • ไม่มีการใช้งานสีที่ไม่ได้อยู่ในการตรวจสอบ
  • มีการตรวจสอบสีที่ใช้งานน้อยกว่า 3 ครั้ง (ไม่สามารถตรวจสอบสามครั้ง) ในกรณีที่ 2 ไม่เคยจำนำ + (จำนำอธิการอัศวิน) บิชอป + อธิการอัศวิน + อัศวิน

เบี้ย:

  • มีไม่เกิน 8 เบี้ยจากแต่ละสี
  • ไม่มีเบี้ยในลำดับแรกหรือแถวสุดท้ายเนื่องจากพวกเขาอยู่ในตำแหน่งเริ่มต้นผิดหรือควรได้รับการเลื่อนตำแหน่ง
  • ในกรณีของจัตุรัส en passant; ดูว่ามันถูกสร้างขึ้นอย่างถูกกฎหมาย (เช่นมันจะต้องอยู่ในx3หรือx6อันดับจะต้องมีจำนำ (จากสีที่ถูกต้อง) ในด้านหน้าของมันและจัตุรัส en passant และด้านหลังมันว่างเปล่า)
  • ป้องกันการมีชิ้นส่วนที่ได้รับการเลื่อนตำแหน่งมากกว่าเบี้ยที่ขาดหายไป (เช่นextra_pieces = Math.max(0, num_queens-1) + Math.max(0, num_rooks-2)...จากนั้นextra_pieces <= (8-num_pawns)) คุณควรทำการคำนวณพิเศษสำหรับอธิการถ้าคุณมีบิชอปสอง (หรือมากกว่า) จากสีสี่เหลี่ยมเดียวกันสามารถสร้างได้จากการเลื่อนจำนำเท่านั้น ข้อมูลนี้ไปยังสูตรด้านบนอย่างใด
  • การสร้างจำนำเป็นไปได้ที่จะไปถึง (เช่นในกรณีที่จำนำหลาย ๆ ตัวในคอลเดียวจะต้องมีชิ้นส่วนศัตรูที่ขาดหายไปเพียงพอที่จะสร้างรูปแบบนั้น) นี่เป็นกฎที่มีประโยชน์:
    1. เป็นไปไม่ได้ที่จะมีมากกว่า 6 เบี้ยในไฟล์เดียว (คอลัมน์) (เนื่องจากเบี้ยไม่สามารถอยู่ในอันดับแรกและอันดับสุดท้าย)
    2. จำนวนที่น้อยที่สุดของชิ้นส่วนที่หายไปของศัตรูเพื่อให้ได้จำนำหลายตัวในคอลัมน์เดียวB to G 2=1, 3=2, 4=4, 5=6, 6=9 ___ A and H 2=1, 3=3, 4=6, 5=10, 6=15ตัวอย่างเช่นหากคุณเห็นเบี้ย 5 ตัวใน A หรือ H ผู้เล่นคนอื่นจะต้องหายไปอย่างน้อย 10 ชิ้นจาก 15 ชิ้นที่จับได้ของเขา
    3. หากมีการจำนำสีขาวใน a2 และ a3 จะไม่มีทางกฎหมายหนึ่งใน b2 และความคิดนี้สามารถขยายเพิ่มเติมเพื่อครอบคลุมความเป็นไปได้มากขึ้น

ใช้เรือ:

  • หากกษัตริย์หรือ rooks ไม่ได้อยู่ในตำแหน่งเริ่มต้นของพวกเขา ความสามารถในการเหวี่ยงของฝ่ายนั้นจะหายไป (ในกรณีของราชาทั้งคู่แพ้)

บาทหลวง:

  • ค้นหาบิชอปในแถวแรกและแถวสุดท้ายที่ติดกับเบี้ยที่ไม่ได้ย้ายตัวอย่างเช่น
    1. บิชอป (สีใด ๆ ) ติดอยู่ด้านหลัง 3 เบี้ย
    2. อธิการที่ติดอยู่ด้านหลังเบี้ยที่ไม่ใช่ศัตรู 2 ตัว (ไม่ใช่โดยเบี้ยของศัตรูเพราะเราสามารถไปถึงตำแหน่งนั้นได้โดยการสนับสนุนการจำนำต่ำกว่าอย่างไรก็ตามหากเราตรวจสอบจำนวนเบี้ยและextra_piecesเราสามารถตัดสินได้ว่ากรณีนี้เป็นไปได้หรือไม่)

Non-จัมเปอร์:

  • (หลีกเลี่ยงสิ่งนี้หากคุณต้องการตรวจสอบ Fisher's Chess960) หากมีชิ้นส่วนที่ไม่ใช่จัมเปอร์ของศัตรูระหว่างกษัตริย์และโกงและยังมีเบี้ยจำนำบางส่วนโดยไม่มีการเคลื่อนไหว ตรวจสอบว่าชิ้นส่วนศัตรูเหล่านี้อาจมีอากาศถูกต้องตามกฎหมายในที่นั่น ถามตัวเองด้วย: ราชาหรือนักเล่นแร่แปรธาตุจำเป็นต้องย้ายเพื่อสร้างตำแหน่งนั้นหรือไม่? (ถ้าใช่เราต้องตรวจสอบให้แน่ใจว่าความสามารถในการ castling สะท้อนให้เห็นถึงนี้)
  • หากผู้จำนำทั้ง 8 คนยังคงอยู่ในตำแหน่งเริ่มต้นผู้ที่ไม่ใช่ผู้จั๊มเปอร์ทุกคนจะต้องไม่ออกจากตำแหน่งเริ่มต้น (เช่นผู้ที่ไม่ใช่นักจัมเปอร์ศัตรูไม่สามารถเข้ามาได้อย่างถูกกฎหมาย) มีแนวคิดอื่นที่คล้ายคลึงกันเช่นสีขาว - จำนำจะย้ายครั้งเดียว, ROOKs ควรจะยังคงติดอยู่ในรูปแบบการจำนำ ฯลฯ

นาฬิกาครึ่งหนึ่ง / เต็มเคลื่อนไหว:

  • ในกรณีที่ช่อง en passant นาฬิกาครึ่งเวลาต้องมีค่าเท่ากับ 0
  • HalfMoves <= ((FullMoves-1)*2)+(if BlackToMove 1 else 0)+1 หรือ +0 ขึ้นอยู่กับด้านที่จะย้าย
  • HalfMoves จะต้องเป็นx >= 0และ FullMovesx >= 1

อื่น ๆ :

  • ตรวจสอบให้แน่ใจว่า FEN มีชิ้นส่วนทั้งหมดที่ต้องการ (เช่นสีที่ใช้งาน, ความสามารถในการหล่อ, en passant square, ฯลฯ )

หมายเหตุ:ไม่จำเป็นต้องทำการตรวจสอบ'ผู้เล่นไม่ควรมีมากกว่า 16 ชิ้นเพราะคะแนน' ไม่เกิน 8 เบี้ย ' + ' ป้องกันชิ้นส่วนที่ได้รับการส่งเสริมเป็นพิเศษ ' + ' ราชาองค์เดียว 'ควรครอบคลุมประเด็นนี้แล้ว

หมายเหตุ 2:กฎเหล่านี้มีวัตถุประสงค์เพื่อตรวจสอบตำแหน่งที่เกิดขึ้นจากตำแหน่งเริ่มต้นของหมากรุกปกติกฎบางข้อจะทำให้บางตำแหน่งใช้งานไม่ได้จากChess960 (ยกเว้นถ้าเริ่มจากการจัดเรียงNº518) และสร้างจิ๊กซอร์เพื่อหลีกเลี่ยง


1
คุณยังสามารถตรวจสอบโครงสร้างเบี้ยเช่นจำนำสีขาวไม่สามารถอยู่บน a2, a3 และ b2; ไม่มีทางที่จะจำนำได้ทั้งบน a3 และ b2
Akavall

นั่นคือการบอกว่าตำแหน่ง FEN ควรทำได้จากตำแหน่งเริ่มต้นเท่านั้น? ถ้าฉันต้องการให้ไขปริศนาแสดงโดย FEN ล่ะ? บางครั้งพวกเขาจะถูกสร้างขึ้นในทางที่เป็นไปไม่ได้ที่จะไปถึงในเกมที่เกิดขึ้นจริง ...
tbischel

@tbischel ฉันทำตามกฎเหล่านี้จากปกติมุมมองหมากรุก (ไม่ได้มีไว้สำหรับหมากรุก 960 หรือตำแหน่งอื่น ๆ ที่เกิด) ขอบคุณฉันอาจจะชี้อยู่ที่ไหนสักแห่งนี้จะทำให้มันชัดเจน
ajax333221

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

1
@ ajax333221: หน้านี้จะช่วยให้เกมทางกฎหมายในการที่สีขาวได้รับเกินกว่า 5 เบี้ยบนaไฟล์

10
\s*([rnbqkpRNBQKP1-8]+\/){7}([rnbqkpRNBQKP1-8]+)\s[bw-]\s(([a-hkqA-HKQ]{1,4})|(-))\s(([a-h][36])|(-))\s\d+\s\d+\s*

นี่เป็นนิพจน์ทั่วไปที่ฉันใช้เพื่อให้แน่ใจว่าสตริง FEN นั้นใช้ได้จริง มันไม่ได้ทำการทดสอบใด ๆ สำหรับตำแหน่งทางกฎหมาย / ผิดกฎหมาย แต่มันเป็นจุดเริ่มต้นที่ดี


ฉันคิดว่าสีที่ใช้งานเป็นสิ่งจำเป็น (คุณอนุญาต-) และบางครั้งครึ่งนาฬิกาเต็ม / เป็นตัวเลือกฉันคิดว่า นอกจากนี้ฉันไม่เข้าใจa-hส่วนที่เกี่ยวกับความสามารถในการ/^\s*([rnbqkpRNBQKP1-8]+\/){7}([rnbqkpRNBQKP1-8]+)\s[bw]\s(-|K?Q?k?q?)\s(-|[a-h][36])/
เหวี่ยง

ฉันเพิ่งสังเกตเห็นว่าเราสามารถทำแบบทดสอบ "ไม่มีเบี้ยในการส่งเสริมการขาย" กับสิ่งที่เริ่มต้นเช่น([rnbqkRNBQK1-8]+\/)([rnbqkpRNBQKP1-8]+\/){6}([rnbqkRNBQK1-8]+) ....
ajax333221

สำหรับนาฬิกาสิ่งนี้อาจจะดี(0|[1-9][0-9]*)\s([1-9][0-9]*)เพราะการเคลื่อนไหวไม่มีศูนย์นำหน้าและการเดินเต็มไม่สามารถเป็นหรือเริ่มต้นด้วย 0, (รหัสเครดิต)
ajax333221

5

สำหรับคนอื่น ๆ มีฟังก์ชั่นง่าย ๆ ในเครื่องยนต์ Stockfish ที่ตรวจสอบความถูกต้องของสตริง FEN

bool Position::is_valid_fen(const std::string &fen) {
   std::istringstream iss(fen);
   std::string board, side, castleRights, ep;

   if (!iss) return false;

   iss >> board;

   if (!iss) return false;

   iss >> side;

   if (!iss) {
      castleRights = "-";
      ep = "-";
   } else {
      iss >> castleRights;
      if (iss)
         iss >> ep;
      else
         ep = "-";
   }

   // Let's check that all components of the supposed FEN are OK.
   if (side != "w" && side != "b") return false;
   if (castleRights != "-" && castleRights != "K" && castleRights != "Kk"
       && castleRights != "Kkq" && castleRights != "Kq" && castleRights !="KQ"
       && castleRights != "KQk" && castleRights != "KQq" && castleRights != "KQkq"
       && castleRights != "k" && castleRights != "q" && castleRights != "kq"
       && castleRights != "Q" && castleRights != "Qk" && castleRights != "Qq"
       && castleRights != "Qkq")
      return false;
   if (ep != "-") {
      if (ep.length() != 2) return false;
      if (!(ep[0] >= 'a' && ep[0] <= 'h')) return false;
      if (!((side == "w" && ep[1] == '6') || (side == "b" && ep[1] == '3')))
         return false;
   }

   // The tricky part: The board.
   // Seven slashes?
   if (std::count(board.begin(), board.end(), '/') != 7) return false;
   // Only legal characters?
   for (int i = 0; i < board.length(); i++)
      if (!(board[i] == '/' || (board[i] >= '1' && board[i] <= '8')
            || piece_type_is_ok(piece_type_from_char(board[i]))))
         return false;
   // Exactly one king per side?
   if (std::count(board.begin(), board.end(), 'K') != 1) return false;
   if (std::count(board.begin(), board.end(), 'k') != 1) return false;
   // Other piece counts reasonable?
   size_t wp = std::count(board.begin(), board.end(), 'P'),
      bp = std::count(board.begin(), board.end(), 'p'),
      wn = std::count(board.begin(), board.end(), 'N'),
      bn = std::count(board.begin(), board.end(), 'n'),
      wb = std::count(board.begin(), board.end(), 'B'),
      bb = std::count(board.begin(), board.end(), 'b'),
      wr = std::count(board.begin(), board.end(), 'R'),
      br = std::count(board.begin(), board.end(), 'r'),
      wq = std::count(board.begin(), board.end(), 'Q'),
      bq = std::count(board.begin(), board.end(), 'q');
   if (wp > 8 || bp > 8 || wn > 10 || bn > 10 || wb > 10 || bb > 10
       || wr > 10 || br > 10 || wq > 9 || bq > 10
       || wp + wn + wb + wr + wq > 15 || bp + bn + bb + br + bq > 15)
      return false;

   // OK, looks close enough to a legal position. Let's try to parse
   // the FEN and see!
   Position p;
   p.from_fen(board + " " + side + " " + castleRights + " " + ep);
   return p.is_ok(true);
}

1
ดูเหมือนว่าการตรวจสอบตามจริงทั้งหมดเสร็จสิ้นposition.is_okay()แล้ว รหัสที่นี่ก็ไม่คู่ของการตรวจสอบขั้นพื้นฐานที่จะทำให้แน่ใจว่ามันรูปแบบถูกต้องและว่ามันเป็นมูลค่าการทำการตรวจสอบจริง (เช่นไม่เห็นได้ชัดว่าผิดกฎหมาย)
undergroundmonorail

4

นี่คืออัลกอริทึมการย้อนรอยอย่างง่ายโดยมีเงื่อนไขว่าคุณมีฟังก์ชั่นที่สามารถตรวจสอบการเคลื่อนไหวทางกฎหมายย้อนกลับในทุกสถานะของบอร์ด (หรือที่เรียกว่าตำแหน่ง):

function is_legal_state(state,move)

   //Terminate if a starting state was found. This immediately implies there
   //was a legal game that generated this state, in fact the backtracking
   //can tell you precisely such a game       
   if (state in starting board state)
     return true

   //Apply some move to get to a new state, state is a persistent object
   apply_reverse_move(state,move)

   //Generate all legal "reverse" moves, that is, moves that could have
   //been performed to get to the current state from another position,
   //provided the previous position was valid. You do not have to check the
   //validness of the previous state, you just have to make sure the
   //transitioning move was valid
   legalmoves = enumerate_all_reverse_moves( state )

   for local_move in legalmoves:
     return is_legal_state(state,local_move)

   //Reverse the move that was previously applied so backtracking can
   //work properly 
   reverse_reverse_move(state,move)

   return false

1

ไม่มีสิ่งใดในข้อกำหนด FEN ที่บอกว่าตำแหน่งที่แสดงต้องสามารถเข้าถึงได้จากอาร์เรย์เริ่มต้น การพิสูจน์ว่าตำแหน่งที่กำหนดสามารถเข้าถึงได้จากอาร์เรย์เริ่มต้นเป็นปัญหาที่ยังไม่ได้แก้ไข

ในสตริง FEN ที่ถูกต้องจำนวนการย้ายครึ่งจะต้องสอดคล้องกับตารางเป้าหมาย en passant หากจตุรัสเป้าหมายมีอยู่การนับการย้ายครึ่งหนึ่งต้องเป็นศูนย์ จำนวนการย้ายครึ่งหนึ่งต้องสอดคล้องกับจำนวนการย้ายเต็ม เช่นการย้ายครึ่งนับเป็นสิบไม่เข้ากันกับการย้ายเต็มจำนวนสาม


1

มางานเลี้ยงสาย

ไม่สามารถตรวจสอบได้ 100% ว่าตำแหน่งนั้นถูกกฎหมาย แต่ทำไมการตรวจสอบจึงมีความสำคัญ เราสามารถเล่นหมากรุกไม่ว่าตำแหน่งจะเกิดขึ้นจากตำแหน่งเริ่มต้น (หรือที่เรียกว่า“ เกมอาเรย์”) อาจมีตำแหน่งที่น่าสนใจในการวิเคราะห์ แต่มันก็เกิดขึ้นว่ามันผิดกฎหมาย

ดังนั้นฉันจะตรวจสอบเพียง:

  • มีกษัตริย์ 1 องค์จากแต่ละด้านอย่างแน่นอนหรือไม่?
  • ไม่มีเบี้ยในตำแหน่งที่หนึ่งหรือแปดหรือไม่?
  • ด้านที่จะย้ายไม่ให้การตรวจสอบอยู่แล้ว?

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

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