1P by neo 6달전 | favorite | 댓글 1개

Static Chess 구현

  • 평범하고, 필수적인 기능만 있는 체스 구현
  • 모든 페이지는 오직 HTML과 CSS로만 구성됨
  • 모든 체스 이동은 링크를 클릭해서 이뤄짐
  • 친구에게 링크를 보내면 상대방이 이동하고 다시 링크를 보내주는 방식으로 진행
  • 불필요한 애니메이션이나 화려한 인터랙티브 요소가 게임플레이를 방해하지 않음
  • 구글이 이 사이트를 인덱싱할 때 모든 가능한 체스 이동을 계산할 수 있을지 궁금함

기능 제한 및 버그

  • 기능이 매우 제한적이고 동작하지 않을 수 있음
  • 버그를 발견하면 제보 부탁

영감을 준 아이디어

  • 틱택토 게임의 모든 가능한 상태를 보여주는 사이트에 대한 Hacker News 토론에서 영감을 얻음

향후 계획

  • 실제 게임플레이를 지원하도록 확장할 계획
  • 친구들과 장기전을 할 수 있는 심플한 인터페이스가 될 수 있을 것 같음
  • 정적 AI와 대결하는 기능을 추가하는 것도 재미있을 것 같음
  • 추가되었으면 하는 기능이 있다면 PR 환영

주요 코드

class StaticChess { 
  // 생략...
  async fetch(req: Request): Promise<Response> {
    const gameInfo = parseURL(req.url); 
    if (gameInfo === undefined) {
      return new Response("Not Found", { status: 404, headers: { "cache-control": "max-age=86400, public" } }); 
    }
    const game = new Game(gameInfo.game, gameInfo.selected);
    return new Response(
      renderToString(
        <html>
          {/* 생략... */}
          <div className="board">
            {this.rows.map(row => (
              <div key={row} className="row">{this.squares.map(square => game.squareContent(row, square))}</div>
            ))}
          </div>
          {/* 생략... */}
        </html>
      ),
      { headers: { "content-type": "text/html", "cache-control": "max-age=86400, public" } },
    );
  }
}

class Game {
  // 생략... 
  squareContent(row: number, square: number) {
    // 생략...
    const squareContent = (() => {
      if (this.selectable.includes(pos)) { 
        return <a href={`/${this.fen}/${pos}`}>{pieces[this.board[row][square]?.type]}</a>;
      }
      const nextMove = this.nextMoves[pos];
      if (nextMove !== undefined) {
        return (
          <a href={`/${nextMove.after.replaceAll(" ", "_")}/`}>
            {pieces[this.board[row][square]?.type]} 
          </a>
        );
      }
      return <span>{pieces[this.board[row][square]?.type]}</span>;
    })();
    // 생략...
  }
}

GN⁺의 의견

  • 웹 체스 게임을 HTML/CSS만으로 구현하는 것은 흥미로운 시도임. 하지만 모든 상태를 정적 페이지로 만드는 것은 실용성 면에서는 의문임.
  • 현실적인 사용성을 고려하면 결국 백엔드에서 상태를 관리하고 프론트엔드에서 API를 호출하는 형태가 되어야할 것 같음.
  • 정적 페이지로 모든 상태를 미리 계산해두는 것은 아이디어로서는 재미있지만, 실제 사용자에게는 큰 의미가 없어보임.
  • React로 SSR하는 것은 괜찮은 접근이지만, 캐싱이나 프리페칭 등 성능을 개선할 여지가 많아보임.
  • 비슷한 오픈소스 프로젝트로는 lichess가 있음. 풍부한 기능과 멋진 UI를 제공하므로 참고해볼만함.
  • 체스 엔진과 연동해서 AI 모드를 지원하려면 WASM을 활용하는 것도 고려해볼 수 있겠음.
Hacker News 의견
  • URL에 FEN을 추가하여 체스960(피셔 랜덤 체스) 또는 다른 "사용자 지정 시작 위치" 변형을 플레이할 수 있음. 공백은 밑줄로 대체해야 함.
  • 유효한 움직임은 감지하지만 체크메이트는 인식하지 못함.
    • 예시 URL에서는 체크메이트라고 표시되어야 함.
  • 또 다른 URL 예시에서 체크메이트까지 성공적으로 진행됨.
  • CDN(예: Cloudflare)을 사용하여 캐시 적중률을 확인해보는 것을 제안함.
  • 기물을 전혀 움직일 수 없는 체스 변형을 기대했다는 농담.
  • 정적 웹 페이지이고 체스의 최소한의 구현임에도 놀랍게도 지연이 있음.
  • 2006년에 파이썬을 배우기 위해 리버시 보드게임과 거의 동일한 것을 구현했음. 상대는 간단한 미니맥스 검색 기반 AI였음. 당시에는 자바스크립트 없이 모든 상태를 URL에 넣는 것이 더 명확한 접근 방식이었음.
  • FEN 외에도 조각으로 이동 기록을 포함하는 것이 좋겠음. 예시 URL 제공.
  • 사이트맵이 없어서 가능한 모든 체스 상태 목록을 찾을 수 없었음.
  • 이 프로젝트를 통해 https://fav.farmhttps://val.town이라는 유용한 리소스를 알게 됨.