"แƒขแƒ”แƒ’แƒ˜" แƒฏแƒแƒ•แƒแƒจแƒ˜ - แƒ แƒแƒ’แƒแƒ  แƒ’แƒแƒœแƒ•แƒแƒ•แƒ˜แƒ—แƒแƒ แƒแƒ— แƒกแƒ แƒฃแƒšแƒคแƒแƒกแƒแƒ•แƒแƒœแƒ˜ แƒ—แƒแƒ›แƒแƒจแƒ˜

"แƒขแƒ”แƒ’แƒ˜" แƒฏแƒแƒ•แƒแƒจแƒ˜ - แƒ แƒแƒ’แƒแƒ  แƒ’แƒแƒœแƒ•แƒแƒ•แƒ˜แƒ—แƒแƒ แƒแƒ— แƒกแƒ แƒฃแƒšแƒคแƒแƒกแƒแƒ•แƒแƒœแƒ˜ แƒ—แƒแƒ›แƒแƒจแƒ˜

"แƒ—แƒฎแƒฃแƒ—แƒ›แƒ”แƒขแƒ˜" แƒแƒœ "แƒ—แƒฎแƒฃแƒ—แƒ›แƒ”แƒขแƒ˜" แƒแƒ แƒ˜แƒก แƒ›แƒแƒ แƒขแƒ˜แƒ•แƒ˜ แƒšแƒแƒ’แƒ˜แƒ™แƒฃแƒ แƒ˜ แƒ—แƒแƒ›แƒแƒจแƒ˜แƒก แƒจแƒ”แƒกแƒแƒœแƒ˜แƒจแƒœแƒแƒ•แƒ˜ แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒžแƒแƒžแƒฃแƒšแƒแƒ แƒฃแƒšแƒ˜แƒ แƒ›แƒ—แƒ”แƒš แƒ›แƒกแƒแƒคแƒšแƒ˜แƒแƒจแƒ˜. แƒ—แƒแƒ•แƒกแƒแƒขแƒ”แƒฎแƒ˜แƒก แƒ’แƒแƒ“แƒแƒกแƒแƒญแƒ แƒ”แƒšแƒแƒ“, แƒ—แƒฅแƒ•แƒ”แƒœ แƒฃแƒœแƒ“แƒ แƒ›แƒแƒแƒฌแƒงแƒแƒ— แƒ™แƒ•แƒแƒ“แƒ แƒแƒขแƒ”แƒ‘แƒ˜ แƒ แƒ˜แƒชแƒฎแƒ•แƒ”แƒ‘แƒ˜แƒ—, แƒฃแƒ›แƒชแƒ˜แƒ แƒ”แƒกแƒ˜แƒ“แƒแƒœ แƒ“แƒ˜แƒ“แƒแƒ›แƒ“แƒ”. แƒแƒ“แƒ•แƒ˜แƒšแƒ˜ แƒแƒ  แƒแƒ แƒ˜แƒก, แƒ›แƒแƒ’แƒ แƒแƒ› แƒกแƒแƒ˜แƒœแƒขแƒ”แƒ แƒ”แƒกแƒแƒ.

แƒ“แƒฆแƒ”แƒ•แƒแƒœแƒ“แƒ”แƒš แƒ’แƒแƒ™แƒ•แƒ”แƒ—แƒ˜แƒšแƒจแƒ˜ แƒฉแƒ•แƒ”แƒœ แƒ’แƒแƒฉแƒ•แƒ”แƒœแƒ”แƒ‘แƒ—, แƒ—แƒฃ แƒ แƒแƒ’แƒแƒ  แƒฃแƒœแƒ“แƒ แƒ’แƒแƒœแƒแƒ•แƒ˜แƒ—แƒแƒ แƒแƒ— Fifteen Java 8-แƒจแƒ˜ Eclipse-แƒ˜แƒ—. แƒ˜แƒœแƒขแƒ”แƒ แƒคแƒ”แƒ˜แƒกแƒ˜แƒก แƒ’แƒแƒกแƒแƒ•แƒ˜แƒ—แƒแƒ แƒ”แƒ‘แƒšแƒแƒ“ แƒฉแƒ•แƒ”แƒœ แƒ’แƒแƒ›แƒแƒ•แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒ— Swing API-แƒก.

แƒจแƒ”แƒ’แƒแƒฎแƒกแƒ”แƒœแƒ”แƒ‘แƒ—: "Habr"-แƒ˜แƒก แƒงแƒ•แƒ”แƒšแƒ แƒ›แƒ™แƒ˜แƒ—แƒฎแƒ•แƒ”แƒšแƒ˜แƒกแƒ—แƒ•แƒ˜แƒก - แƒคแƒแƒกแƒ“แƒแƒ™แƒšแƒ”แƒ‘แƒ 10 แƒ แƒฃแƒ‘แƒšแƒ˜แƒ“แƒแƒœ Skillbox-แƒ˜แƒก แƒœแƒ”แƒ‘แƒ˜แƒกแƒ›แƒ˜แƒ”แƒ  แƒ™แƒฃแƒ แƒกแƒ–แƒ” แƒฉแƒแƒ แƒ˜แƒชแƒฎแƒ•แƒ˜แƒกแƒแƒก "Habr" แƒกแƒแƒ แƒ”แƒ™แƒšแƒแƒ›แƒ แƒ™แƒแƒ“แƒ˜แƒก แƒ’แƒแƒ›แƒแƒงแƒ”แƒœแƒ”แƒ‘แƒ˜แƒ—.

Skillbox แƒ’แƒ˜แƒ แƒฉแƒ”แƒ•แƒ—: แƒกแƒแƒ’แƒแƒœแƒ›แƒแƒœแƒแƒ—แƒšแƒ”แƒ‘แƒšแƒ แƒแƒœแƒšแƒแƒ˜แƒœ แƒ™แƒฃแƒ แƒกแƒ˜ "แƒžแƒ แƒแƒคแƒ”แƒกแƒ˜แƒ Java Developer".

แƒ—แƒแƒ›แƒแƒจแƒ˜แƒก แƒ“แƒ˜แƒ–แƒแƒ˜แƒœแƒ˜

แƒแƒ› แƒ”แƒขแƒแƒžแƒ–แƒ” แƒ—แƒฅแƒ•แƒ”แƒœ แƒฃแƒœแƒ“แƒ แƒ’แƒแƒœแƒกแƒแƒ–แƒฆแƒ•แƒ แƒแƒ— แƒ—แƒ•แƒ˜แƒกแƒ”แƒ‘แƒ”แƒ‘แƒ˜:

  • แƒ–แƒแƒ›แƒ - แƒกแƒแƒ—แƒแƒ›แƒแƒจแƒ แƒ›แƒแƒ”แƒ“แƒœแƒ˜แƒก แƒ–แƒแƒ›แƒ;
  • nbTiles โ€” แƒ•แƒ”แƒšแƒจแƒ˜ แƒขแƒ”แƒ’แƒ”แƒ‘แƒ˜แƒก แƒ แƒแƒแƒ“แƒ”แƒœแƒแƒ‘แƒ. nbTiles = แƒ–แƒแƒ›แƒ * แƒ–แƒแƒ›แƒ - 1;
  • Tiles แƒแƒ แƒ˜แƒก แƒขแƒ”แƒ’แƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒแƒ แƒ˜แƒก แƒ›แƒ—แƒ”แƒšแƒ˜ แƒ แƒ˜แƒชแƒฎแƒ•แƒ”แƒ‘แƒ˜แƒก แƒ”แƒ แƒ—แƒ’แƒแƒœแƒ–แƒแƒ›แƒ˜แƒšแƒ”แƒ‘แƒ˜แƒแƒœแƒ˜ แƒ›แƒแƒกแƒ˜แƒ•แƒ˜. แƒ—แƒ˜แƒ—แƒแƒ”แƒฃแƒšแƒ˜ แƒขแƒ”แƒ’แƒ˜ แƒ›แƒ˜แƒ˜แƒฆแƒ”แƒ‘แƒก แƒฃแƒœแƒ˜แƒ™แƒแƒšแƒฃแƒ  แƒ›แƒœแƒ˜แƒจแƒ•แƒœแƒ”แƒšแƒแƒ‘แƒแƒก แƒ“แƒ˜แƒแƒžแƒแƒ–แƒแƒœแƒจแƒ˜ [0, nbTiles]. แƒœแƒฃแƒšแƒ˜ แƒ›แƒ˜แƒฃแƒ—แƒ˜แƒ—แƒ”แƒ‘แƒก แƒชแƒแƒ แƒ˜แƒ”แƒš แƒ™แƒ•แƒแƒ“แƒ แƒแƒขแƒ–แƒ”;
  • blankPos - แƒชแƒแƒ แƒ˜แƒ”แƒšแƒ˜ แƒ™แƒ•แƒแƒ“แƒ แƒแƒขแƒ˜แƒก แƒžแƒแƒ–แƒ˜แƒชแƒ˜แƒ.

แƒ—แƒแƒ›แƒแƒจแƒ˜แƒก แƒšแƒแƒ’แƒ˜แƒ™แƒ

แƒฉแƒ•แƒ”แƒœ แƒฃแƒœแƒ“แƒ แƒ’แƒแƒœแƒ•แƒกแƒแƒ–แƒฆแƒ•แƒ แƒแƒ— แƒ’แƒแƒ“แƒแƒขแƒ•แƒ˜แƒ แƒ—แƒ•แƒ˜แƒก แƒ›แƒ”แƒ—แƒแƒ“แƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒ’แƒแƒ›แƒแƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒ แƒแƒฎแƒแƒšแƒ˜ แƒ—แƒแƒ›แƒแƒจแƒ˜แƒก แƒžแƒแƒ–แƒ˜แƒชแƒ˜แƒ˜แƒก แƒ˜แƒœแƒ˜แƒชแƒ˜แƒแƒšแƒ˜แƒ–แƒแƒชแƒ˜แƒ˜แƒกแƒ—แƒ•แƒ˜แƒก. แƒแƒ› แƒ’แƒ–แƒ˜แƒ— แƒฉแƒ•แƒ”แƒœ แƒ•แƒแƒงแƒ”แƒœแƒ”แƒ‘แƒ— แƒ›แƒœแƒ˜แƒจแƒ•แƒœแƒ”แƒšแƒแƒ‘แƒแƒก แƒขแƒ”แƒ’แƒ”แƒ‘แƒ˜แƒก แƒ›แƒแƒกแƒ˜แƒ•แƒ˜แƒก แƒ—แƒ˜แƒ—แƒแƒ”แƒฃแƒšแƒ˜ แƒ”แƒšแƒ”แƒ›แƒ”แƒœแƒขแƒ˜แƒกแƒ—แƒ•แƒ˜แƒก. แƒ™แƒแƒ แƒ’แƒแƒ“, แƒ›แƒแƒจแƒ˜แƒœ แƒ•แƒแƒ—แƒแƒ•แƒกแƒ”แƒ‘แƒ— blankPos-แƒก แƒ›แƒแƒกแƒ˜แƒ•แƒ˜แƒก แƒ‘แƒแƒšแƒ แƒžแƒแƒ–แƒ˜แƒชแƒ˜แƒแƒ–แƒ”.

แƒฉแƒ•แƒ”แƒœ แƒแƒกแƒ”แƒ•แƒ” แƒ’แƒ•แƒญแƒ˜แƒ แƒ“แƒ”แƒ‘แƒ แƒจแƒ”แƒ แƒฌแƒงแƒ›แƒ˜แƒก แƒ›แƒ”แƒ—แƒแƒ“แƒ˜ แƒขแƒ”แƒ’แƒ”แƒ‘แƒ˜แƒก แƒ›แƒแƒกแƒ˜แƒ•แƒ˜แƒก แƒจแƒ”แƒกแƒแƒ แƒ”แƒ•แƒแƒ“. แƒฉแƒ•แƒ”แƒœ แƒแƒ  แƒฉแƒแƒ•แƒ แƒ—แƒแƒ•แƒ— แƒชแƒแƒ แƒ˜แƒ”แƒš แƒขแƒ”แƒ’แƒก แƒ’แƒแƒ“แƒแƒ แƒ”แƒ•แƒ˜แƒก แƒžแƒ แƒแƒชแƒ”แƒกแƒจแƒ˜, แƒ แƒแƒ—แƒ แƒ˜แƒก แƒ˜แƒ›แƒแƒ•แƒ” แƒ›แƒ“แƒ’แƒแƒ›แƒแƒ แƒ”แƒแƒ‘แƒแƒจแƒ˜ แƒ“แƒแƒ•แƒขแƒแƒ•แƒแƒ—.

แƒ•แƒ˜แƒœแƒแƒ˜แƒ“แƒแƒœ แƒ—แƒแƒ•แƒกแƒแƒขแƒ”แƒฎแƒ˜แƒก แƒจแƒ”แƒกแƒแƒซแƒšแƒ แƒกแƒแƒฌแƒงแƒ˜แƒกแƒ˜ แƒžแƒแƒ–แƒ˜แƒชแƒ˜แƒ”แƒ‘แƒ˜แƒก แƒ›แƒฎแƒแƒšแƒแƒ“ แƒœแƒแƒฎแƒ”แƒ•แƒแƒ แƒก แƒแƒฅแƒ•แƒก แƒ’แƒแƒ›แƒแƒกแƒแƒ•แƒแƒšแƒ˜, แƒ—แƒฅแƒ•แƒ”แƒœ แƒฃแƒœแƒ“แƒ แƒจแƒ”แƒแƒ›แƒแƒฌแƒ›แƒแƒ— แƒจแƒ”แƒ“แƒ”แƒ’แƒแƒ“ แƒ›แƒ˜แƒฆแƒ”แƒ‘แƒฃแƒšแƒ˜ แƒจแƒ”แƒ แƒฌแƒงแƒ›แƒ˜แƒก แƒจแƒ”แƒ“แƒ”แƒ’แƒ˜, แƒ แƒแƒ—แƒ แƒ“แƒแƒ แƒฌแƒ›แƒฃแƒœแƒ“แƒ”แƒ—, แƒ แƒแƒ› แƒ›แƒ˜แƒ›แƒ“แƒ˜แƒœแƒแƒ แƒ” แƒ’แƒแƒœแƒšแƒแƒ’แƒ”แƒ‘แƒ แƒ—แƒแƒœแƒแƒ‘แƒ แƒแƒ“ แƒแƒ›แƒแƒกแƒแƒฎแƒกแƒœแƒ”แƒšแƒ˜แƒ. แƒแƒ›แƒ˜แƒกแƒแƒ—แƒ•แƒ˜แƒก แƒฉแƒ•แƒ”แƒœ แƒ’แƒแƒœแƒ•แƒกแƒแƒ–แƒฆแƒ•แƒ แƒแƒ•แƒ— isSolvable แƒ›แƒ”แƒ—แƒแƒ“แƒก.

แƒ—แƒฃ แƒ™แƒแƒœแƒ™แƒ แƒ”แƒขแƒฃแƒš แƒขแƒ”แƒ’แƒก แƒฌแƒ˜แƒœ แƒฃแƒซแƒฆแƒ•แƒ˜แƒก แƒฃแƒคแƒ แƒ แƒ›แƒแƒฆแƒแƒšแƒ˜ แƒ›แƒœแƒ˜แƒจแƒ•แƒœแƒ”แƒšแƒแƒ‘แƒ˜แƒก แƒ›แƒฅแƒแƒœแƒ” แƒขแƒ”แƒ’แƒ˜, แƒ˜แƒ’แƒ˜ แƒ˜แƒ—แƒ•แƒšแƒ”แƒ‘แƒ แƒ˜แƒœแƒ•แƒ”แƒ แƒกแƒ˜แƒแƒ“. แƒ แƒแƒ“แƒ”แƒกแƒแƒช แƒชแƒแƒ แƒ˜แƒ”แƒšแƒ˜ แƒแƒ“แƒ’แƒ˜แƒšแƒ˜ แƒแƒ“แƒ’แƒ˜แƒšแƒ–แƒ”แƒ, แƒ˜แƒœแƒ•แƒ”แƒ แƒกแƒ˜แƒ”แƒ‘แƒ˜แƒก แƒ แƒแƒแƒ“แƒ”แƒœแƒแƒ‘แƒ แƒฃแƒœแƒ“แƒ แƒ˜แƒงแƒแƒก แƒ—แƒแƒœแƒแƒ‘แƒแƒ แƒ˜, แƒ แƒแƒ—แƒ แƒ—แƒแƒ•แƒกแƒแƒขแƒ”แƒฎแƒ˜ แƒแƒ›แƒแƒฎแƒกแƒœแƒแƒ“แƒ˜ แƒ˜แƒงแƒแƒก. แƒแƒกแƒ” แƒ แƒแƒ›, แƒฉแƒ•แƒ”แƒœ แƒ•แƒ˜แƒ—แƒ•แƒšแƒ˜แƒ— แƒ˜แƒœแƒ•แƒ”แƒ แƒกแƒ˜แƒ”แƒ‘แƒ˜แƒก แƒ แƒแƒแƒ“แƒ”แƒœแƒแƒ‘แƒแƒก แƒ“แƒ แƒ•แƒแƒ‘แƒ แƒฃแƒœแƒ”แƒ‘แƒ— true แƒ—แƒฃ แƒ แƒ˜แƒชแƒฎแƒ•แƒ˜ แƒšแƒฃแƒฌแƒ˜แƒ.

แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒ›แƒœแƒ˜แƒจแƒ•แƒœแƒ”แƒšแƒแƒ•แƒแƒœแƒ˜แƒ แƒ’แƒแƒœแƒ•แƒกแƒแƒ–แƒฆแƒ•แƒ แƒแƒ— isSolved แƒ›แƒ”แƒ—แƒแƒ“แƒ˜, แƒ แƒแƒ—แƒ แƒจแƒ”แƒแƒ›แƒแƒฌแƒ›แƒแƒ— แƒแƒ แƒ˜แƒก แƒ—แƒฃ แƒแƒ แƒ แƒฉแƒ•แƒ”แƒœแƒ˜ Game Of Fifteen แƒ’แƒแƒœแƒšแƒแƒ’แƒ”แƒ‘แƒ แƒ›แƒแƒ’แƒ•แƒแƒ แƒ”แƒ‘แƒฃแƒšแƒ˜. แƒฏแƒ”แƒ  แƒ•แƒแƒ—แƒ•แƒแƒšแƒ˜แƒ”แƒ แƒ”แƒ‘แƒ— แƒกแƒแƒ“ แƒแƒ แƒ˜แƒก แƒชแƒแƒ แƒ˜แƒ”แƒšแƒ˜ แƒแƒ“แƒ’แƒ˜แƒšแƒ˜. แƒ—แƒฃ แƒกแƒแƒฌแƒงแƒ˜แƒก แƒžแƒแƒ–แƒ˜แƒชแƒ˜แƒแƒ–แƒ”แƒ, แƒ›แƒแƒจแƒ˜แƒœ แƒ›แƒ˜แƒ›แƒ“แƒ˜แƒœแƒแƒ แƒ” แƒ’แƒแƒกแƒฌแƒแƒ แƒ”แƒ‘แƒ แƒแƒฎแƒแƒšแƒ˜แƒ, แƒแƒ“แƒ แƒ” แƒ’แƒแƒ“แƒแƒฌแƒงแƒ•แƒ”แƒขแƒ˜แƒšแƒ˜ แƒแƒ  แƒแƒ แƒ˜แƒก. แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒฉแƒ•แƒ”แƒœ แƒ•แƒ˜แƒ›แƒ”แƒแƒ แƒ”แƒ‘แƒ— แƒคแƒ˜แƒšแƒ”แƒ‘แƒก แƒกแƒแƒžแƒ˜แƒ แƒ˜แƒกแƒžแƒ˜แƒ แƒ แƒ—แƒแƒœแƒ›แƒ˜แƒ›แƒ“แƒ”แƒ•แƒ แƒแƒ‘แƒ˜แƒ— แƒ“แƒ แƒ—แƒฃ แƒขแƒ”แƒ’แƒ˜แƒก แƒ›แƒœแƒ˜แƒจแƒ•แƒœแƒ”แƒšแƒแƒ‘แƒ แƒ’แƒแƒœแƒกแƒฎแƒ•แƒแƒ•แƒ“แƒ”แƒ‘แƒ แƒจแƒ”แƒกแƒแƒ‘แƒแƒ›แƒ˜แƒกแƒ˜ แƒ˜แƒœแƒ“แƒ”แƒฅแƒกแƒ˜แƒกแƒ’แƒแƒœ +1, แƒฉแƒ•แƒ”แƒœ แƒ•แƒแƒ‘แƒ แƒฃแƒœแƒ”แƒ‘แƒ— false-แƒก. แƒฌแƒ˜แƒœแƒแƒแƒฆแƒ›แƒ“แƒ”แƒ’ แƒจแƒ”แƒ›แƒ—แƒฎแƒ•แƒ”แƒ•แƒแƒจแƒ˜, แƒ›แƒ”แƒ—แƒแƒ“แƒ˜แƒก แƒ‘แƒแƒšแƒแƒก แƒ“แƒ แƒแƒ แƒ“แƒแƒ•แƒฃแƒ‘แƒ แƒฃแƒœแƒ“แƒ”แƒ— แƒกแƒ˜แƒ›แƒแƒ แƒ—แƒšแƒ”แƒก, แƒ แƒแƒ“แƒ’แƒแƒœ แƒ—แƒแƒ•แƒกแƒแƒขแƒ”แƒฎแƒ˜ แƒฃแƒ™แƒ•แƒ” แƒ›แƒแƒ’แƒ•แƒแƒ แƒ”แƒ‘แƒฃแƒšแƒ˜แƒ.

แƒ™แƒ˜แƒ“แƒ”แƒ• แƒ”แƒ แƒ—แƒ˜ แƒ›แƒ”แƒ—แƒแƒ“แƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒฃแƒœแƒ“แƒ แƒ’แƒแƒœแƒ˜แƒกแƒแƒ–แƒฆแƒ•แƒ แƒแƒก แƒแƒ แƒ˜แƒก newGame. แƒกแƒแƒญแƒ˜แƒ แƒแƒ แƒ—แƒแƒ›แƒแƒจแƒ˜แƒก แƒแƒฎแƒแƒšแƒ˜ แƒ˜แƒœแƒกแƒขแƒแƒœแƒชแƒ˜แƒ˜แƒก แƒจแƒ”แƒฅแƒ›แƒœแƒ. แƒแƒ›แƒ˜แƒกแƒแƒ—แƒ•แƒ˜แƒก แƒฉแƒ•แƒ”แƒœ แƒ’แƒแƒ“แƒแƒ•แƒแƒงแƒ”แƒœแƒ”แƒ‘แƒ— แƒกแƒแƒ—แƒแƒ›แƒแƒจแƒ แƒ›แƒแƒ”แƒ“แƒแƒœแƒก, แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒแƒฃแƒ แƒ˜แƒ”แƒ— แƒ“แƒ แƒ•แƒแƒ’แƒ แƒซแƒ”แƒšแƒ”แƒ‘แƒ— แƒกแƒแƒ—แƒแƒ›แƒแƒจแƒ แƒžแƒแƒ–แƒ˜แƒชแƒ˜แƒ˜แƒก แƒ’แƒแƒ“แƒแƒญแƒ แƒแƒก.

แƒแƒฅ แƒแƒ แƒ˜แƒก แƒ™แƒแƒ“แƒ˜แƒก แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒ˜ แƒขแƒ”แƒ’แƒ˜แƒก แƒกแƒแƒ™แƒ•แƒแƒœแƒซแƒ แƒšแƒแƒ’แƒ˜แƒ™แƒ˜แƒ—:

private void newGame() {
  do {
    reset(); // reset in initial state
    shuffle(); // shuffle
  } while(!isSolvable()); // make it until grid be solvable
 
  gameOver = false;
}
 
private void reset() {
  for (int i = 0; i < tiles.length; i++) {
    tiles[i] = (i + 1) % tiles.length;
  }
 
  // we set blank cell at the last
  blankPos = tiles.length - 1;
}
 
private void shuffle() {
  // don't include the blank tile in the shuffle, leave in the solved position
  int n = nbTiles;
 
  while (n > 1) {
    int r = RANDOM.nextInt(n--);
    int tmp = tiles[r];
    tiles[r] = tiles[n];
    tiles[n] = tmp;
  }
}
 
// Only half permutations of the puzzle are solvable/
// Whenever a tile is preceded by a tile with higher value it counts
// as an inversion. In our case, with the blank tile in the solved position,
// the number of inversions must be even for the puzzle to be solvable
private boolean isSolvable() {
  int countInversions = 0;
 
  for (int i = 0; i < nbTiles; i++) {
    for (int j = 0; j < i; j++) {
      if (tiles[j] > tiles[i])
        countInversions++;
    }
  }
 
  return countInversions % 2 == 0;
}
 
private boolean isSolved() {
  if (tiles[tiles.length - 1] != 0) // if blank tile is not in the solved position ==> not solved
    return false;
 
  for (int i = nbTiles - 1; i >= 0; i--) {
    if (tiles[i] != i + 1)
      return false;
  }
 
  return true;
}

แƒ“แƒ แƒ‘แƒแƒšแƒแƒก, แƒ—แƒฅแƒ•แƒ”แƒœ แƒฃแƒœแƒ“แƒ แƒ“แƒแƒแƒžแƒ แƒแƒ’แƒ แƒแƒ›แƒแƒ— แƒขแƒ”แƒ’แƒ”แƒ‘แƒ˜แƒก แƒ›แƒแƒซแƒ แƒแƒแƒ‘แƒ แƒ›แƒแƒกแƒ˜แƒ•แƒจแƒ˜. แƒแƒ› แƒ™แƒแƒ“แƒก แƒ›แƒแƒ’แƒ•แƒ˜แƒแƒœแƒ”แƒ‘แƒ˜แƒ— แƒ’แƒแƒ›แƒแƒ˜แƒซแƒแƒฎแƒ”แƒ‘แƒ”แƒœ แƒ™แƒฃแƒ แƒกแƒแƒ แƒ˜แƒก แƒ›แƒแƒซแƒ แƒแƒแƒ‘แƒแƒ–แƒ” แƒžแƒแƒกแƒฃแƒฎแƒ˜แƒก แƒ’แƒแƒกแƒแƒชแƒ”แƒ›แƒแƒ“. แƒฉแƒ•แƒ”แƒœแƒ˜ แƒ—แƒแƒ›แƒแƒจแƒ˜ แƒ›แƒฎแƒแƒ แƒก แƒ“แƒแƒฃแƒญแƒ”แƒ แƒก แƒ แƒแƒ›แƒ“แƒ”แƒœแƒ˜แƒ›แƒ” แƒคแƒ˜แƒšแƒ”แƒ‘แƒ˜แƒก แƒ›แƒแƒซแƒ แƒแƒแƒ‘แƒแƒก แƒ”แƒ แƒ—แƒ“แƒ แƒแƒฃแƒšแƒแƒ“. แƒแƒ›แƒ’แƒ•แƒแƒ แƒแƒ“, แƒ›แƒแƒก แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒ แƒแƒช แƒ”แƒ™แƒ แƒแƒœแƒ–แƒ” แƒ“แƒแƒญแƒ”แƒ แƒ˜แƒšแƒ˜ แƒžแƒแƒ–แƒ˜แƒชแƒ˜แƒ แƒขแƒ”แƒ’แƒแƒ“ แƒ’แƒแƒ“แƒแƒ•แƒ˜แƒงแƒ•แƒแƒœแƒ”แƒ—, แƒ•แƒ˜แƒฆแƒ”แƒ‘แƒ— แƒชแƒแƒ แƒ˜แƒ”แƒšแƒ˜ แƒขแƒ”แƒ’แƒ˜แƒก แƒžแƒแƒ–แƒ˜แƒชแƒ˜แƒแƒก แƒ“แƒ แƒ•แƒ”แƒซแƒ”แƒ‘แƒ— แƒ›แƒแƒซแƒ แƒแƒแƒ‘แƒ˜แƒก แƒ›แƒ˜แƒ›แƒแƒ แƒ—แƒฃแƒšแƒ”แƒ‘แƒแƒก, แƒ แƒแƒ› แƒฎแƒ”แƒšแƒ˜ แƒจแƒ”แƒฃแƒฌแƒงแƒแƒก แƒ›แƒ˜แƒก แƒ แƒแƒ›แƒ“แƒ”แƒœแƒ˜แƒ›แƒ” แƒ›แƒแƒซแƒ แƒแƒแƒ‘แƒแƒก แƒ”แƒ แƒ—แƒ“แƒ แƒแƒฃแƒšแƒแƒ“.

แƒแƒ˜ แƒ™แƒแƒ“แƒ˜แƒก แƒ›แƒแƒ’แƒแƒšแƒ˜แƒ—แƒ˜:

// get position of the click
int ex = e.getX() - margin;
int ey = e.getY() - margin;
 
// click in the grid ?
if (ex < 0 || ex > gridSize  || ey < 0  || ey > gridSize)
  return;
 
// get position in the grid
int c1 = ex / tileSize;
int r1 = ey / tileSize;
 
// get position of the blank cell
int c2 = blankPos % size;
int r2 = blankPos / size;
 
// we convert in the 1D coord
int clickPos = r1 * size + c1;
 
int dir = 0;
 
// we search direction for multiple tile moves at once
if (c1 == c2  &&  Math.abs(r1 - r2) > 0)
  dir = (r1 - r2) > 0 ? size : -size;
else if (r1 == r2 && Math.abs(c1 - c2) > 0)
  dir = (c1 - c2) > 0 ? 1 : -1;
 
if (dir != 0) {
  // we move tiles in the direction
  do {
    int newBlankPos = blankPos + dir;
    tiles[blankPos] = tiles[newBlankPos];
    blankPos = newBlankPos;
  } while(blankPos != clickPos);
 
tiles[blankPos] = 0;

แƒฉแƒ•แƒ”แƒœ แƒ•แƒแƒ•แƒ˜แƒ—แƒแƒ แƒ”แƒ‘แƒ— UI-แƒก Swing API-แƒก แƒ’แƒแƒ›แƒแƒงแƒ”แƒœแƒ”แƒ‘แƒ˜แƒ—

แƒ“แƒ แƒแƒ แƒ•แƒ˜แƒ›แƒฃแƒจแƒแƒแƒ— แƒ˜แƒœแƒขแƒ”แƒ แƒคแƒ”แƒ˜แƒกแƒ–แƒ”. แƒฏแƒ”แƒ  แƒ•แƒ˜แƒฆแƒ”แƒ‘แƒ— Jpanel แƒ™แƒšแƒแƒกแƒก. แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒ•แƒ”แƒšแƒ–แƒ” แƒ•แƒฎแƒแƒขแƒแƒ•แƒ— แƒขแƒ”แƒ’แƒ”แƒ‘แƒก - แƒ—แƒ˜แƒ—แƒแƒ”แƒฃแƒšแƒ˜แƒก แƒ–แƒแƒ›แƒ˜แƒก แƒ’แƒแƒ›แƒแƒกแƒแƒ—แƒ•แƒšแƒ”แƒšแƒแƒ“ แƒ’แƒแƒ›แƒแƒ•แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒ— แƒ—แƒแƒ›แƒแƒจแƒ˜แƒก แƒ™แƒแƒœแƒกแƒขแƒ แƒฃแƒฅแƒขแƒแƒ แƒ˜แƒก แƒžแƒแƒ แƒแƒ›แƒ”แƒขแƒ แƒจแƒ˜ แƒ›แƒ˜แƒ—แƒ˜แƒ—แƒ”แƒ‘แƒฃแƒš แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ”แƒ‘แƒก:

gridSize = (dimโ€Š - โ€Š2 * margin);
tileSize = gridSize / size;

Margin แƒแƒกแƒ”แƒ•แƒ” แƒแƒ แƒ˜แƒก แƒžแƒแƒ แƒแƒ›แƒ”แƒขแƒ แƒ˜ แƒ›แƒ˜แƒ—แƒ˜แƒ—แƒ”แƒ‘แƒฃแƒšแƒ˜ แƒ—แƒแƒ›แƒแƒจแƒ˜แƒก แƒ™แƒแƒœแƒกแƒขแƒ แƒฃแƒฅแƒขแƒแƒ แƒจแƒ˜.

แƒแƒฎแƒšแƒ แƒฉแƒ•แƒ”แƒœ แƒฃแƒœแƒ“แƒ แƒ’แƒแƒœแƒ•แƒกแƒแƒ–แƒฆแƒ•แƒ แƒแƒ— drawGrid แƒ›แƒ”แƒ—แƒแƒ“แƒ˜, แƒ แƒแƒ—แƒ แƒ“แƒแƒ•แƒฎแƒแƒขแƒแƒ— แƒ‘แƒแƒ“แƒ” แƒ“แƒ แƒšแƒแƒฅแƒ”แƒ‘แƒ˜ แƒ”แƒ™แƒ แƒแƒœแƒ–แƒ”. แƒฉแƒ•แƒ”แƒœ แƒ•แƒแƒแƒœแƒแƒšแƒ˜แƒ–แƒ”แƒ‘แƒ— แƒขแƒ”แƒ’แƒ”แƒ‘แƒ˜แƒก แƒ›แƒแƒกแƒ˜แƒ•แƒก แƒ“แƒ แƒ•แƒแƒฅแƒชแƒ”แƒ•แƒ— แƒ™แƒแƒแƒ แƒ“แƒ˜แƒœแƒแƒขแƒ”แƒ‘แƒก แƒ›แƒแƒ›แƒฎแƒ›แƒแƒ แƒ”แƒ‘แƒšแƒ˜แƒก แƒ˜แƒœแƒขแƒ”แƒ แƒคแƒ”แƒ˜แƒกแƒ˜แƒก แƒ™แƒแƒแƒ แƒ“แƒ˜แƒœแƒแƒขแƒ”แƒ‘แƒแƒ“. แƒจแƒ”แƒ›แƒ“แƒ”แƒ’ แƒ“แƒแƒฎแƒแƒ–แƒ”แƒ— แƒ—แƒ˜แƒ—แƒแƒ”แƒฃแƒšแƒ˜ แƒแƒ“แƒ’แƒ˜แƒšแƒ˜ แƒจแƒ”แƒกแƒแƒ‘แƒแƒ›แƒ˜แƒกแƒ˜ แƒœแƒแƒ›แƒ แƒ˜แƒ— แƒชแƒ”แƒœแƒขแƒ แƒจแƒ˜:

private void drawGrid(Graphics2D g) {
  for (int i = 0; i < tiles.length; i++) {
    // we convert 1D coords to 2D coords given the size of the 2D Array
    int r = i / size;
    int c = i % size;
    // we convert in coords on the UI
    int x = margin + c * tileSize;
    int y = margin + r * tileSize;
 
    // check special case for blank tile
    if(tiles[i] == 0) {
      if (gameOver) {
        g.setColor(FOREGROUND_COLOR);
        drawCenteredString(g, "u2713", x, y);
      }
 
      continue;
    }
 
    // for other tiles
    g.setColor(getForeground());
    g.fillRoundRect(x, y, tileSize, tileSize, 25, 25);
    g.setColor(Color.BLACK);
    g.drawRoundRect(x, y, tileSize, tileSize, 25, 25);
    g.setColor(Color.WHITE);
 
    drawCenteredString(g, String.valueOf(tiles[i]), x , y);
  }
}

แƒ“แƒแƒ‘แƒแƒšแƒแƒก, แƒ’แƒแƒ“แƒแƒ•แƒฃแƒกแƒ•แƒแƒ— paintComponent แƒ›แƒ”แƒ—แƒแƒ“แƒ˜, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒ’แƒแƒ›แƒแƒ›แƒ“แƒ˜แƒœแƒแƒ แƒ”แƒแƒ‘แƒก JPane แƒ™แƒšแƒแƒกแƒ˜แƒ“แƒแƒœ. แƒฉแƒ•แƒ”แƒœ แƒ•แƒ˜แƒงแƒ”แƒœแƒ”แƒ‘แƒ— drawGrid แƒ›แƒ”แƒ—แƒแƒ“แƒก, แƒ แƒแƒกแƒแƒช แƒ›แƒแƒฐแƒงแƒ•แƒ”แƒ‘แƒ drawStartMessage แƒ›แƒ”แƒ—แƒแƒ“แƒ˜, แƒ แƒแƒ—แƒ แƒ’แƒแƒ›แƒแƒ•แƒแƒฉแƒ˜แƒœแƒแƒ— แƒจแƒ”แƒขแƒงแƒแƒ‘แƒ˜แƒœแƒ”แƒ‘แƒ, แƒ แƒแƒ›แƒ”แƒšแƒ˜แƒช แƒ›แƒแƒ’แƒ•แƒ—แƒฎแƒแƒ•แƒก แƒ“แƒแƒ•แƒแƒญแƒ˜แƒ แƒแƒ— แƒ—แƒแƒ›แƒแƒจแƒ˜แƒก แƒ“แƒแƒกแƒแƒฌแƒงแƒ”แƒ‘แƒแƒ“:

private void drawStartMessage(Graphics2D g) {
  if (gameOver) {
    g.setFont(getFont().deriveFont(Font.BOLD, 18));
    g.setColor(FOREGROUND_COLOR);
    String s = "Click to start new game";
    g.drawString(s, (getWidth() - g.getFontMetrics().stringWidth(s)) / 2,
        getHeight() - margin);
  }
}
 
private void drawCenteredString(Graphics2D g, String s, int x, int y) {
  // center string s for the given tile (x,y)
  FontMetrics fm = g.getFontMetrics();
  int asc = fm.getAscent();
  int desc = fm.getDescent();
  g.drawString(s,  x + (tileSize - fm.stringWidth(s)) / 2,
      y + (asc + (tileSize - (asc + desc)) / 2));
}
 
@Override
protected void paintComponent(Graphics g) {
  super.paintComponent(g);
  Graphics2D g2D = (Graphics2D) g;
  g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  drawGrid(g2D);
  drawStartMessage(g2D);
}

แƒ›แƒแƒ›แƒฎแƒ›แƒแƒ แƒ”แƒ‘แƒšแƒ˜แƒก แƒ›แƒแƒฅแƒ›แƒ”แƒ“แƒ”แƒ‘แƒ”แƒ‘แƒ–แƒ” แƒ แƒ”แƒแƒ’แƒ˜แƒ แƒ”แƒ‘แƒ UI-แƒจแƒ˜

แƒ˜แƒ›แƒ˜แƒกแƒแƒ—แƒ•แƒ˜แƒก, แƒ แƒแƒ› แƒ—แƒแƒ›แƒแƒจแƒ›แƒ แƒ’แƒแƒ˜แƒแƒ แƒแƒก แƒ—แƒแƒ•แƒ˜แƒกแƒ˜ แƒ™แƒฃแƒ แƒกแƒ˜, แƒแƒฃแƒชแƒ˜แƒšแƒ”แƒ‘แƒ”แƒšแƒ˜แƒ แƒ›แƒแƒ›แƒฎแƒ›แƒแƒ แƒ”แƒ‘แƒšแƒ˜แƒก แƒฅแƒ›แƒ”แƒ“แƒ”แƒ‘แƒ”แƒ‘แƒ˜แƒก แƒ“แƒแƒ›แƒฃแƒจแƒแƒ•แƒ”แƒ‘แƒ UI-แƒจแƒ˜. แƒแƒ›แƒ˜แƒกแƒแƒ—แƒ•แƒ˜แƒก แƒ“แƒแƒแƒ›แƒแƒขแƒ”แƒ— MouseListener-แƒ˜แƒก แƒ’แƒแƒœแƒฎแƒแƒ แƒชแƒ˜แƒ”แƒšแƒ”แƒ‘แƒ Jpanel-แƒ–แƒ” แƒ“แƒ แƒ–แƒ”แƒ›แƒแƒ— แƒฃแƒ™แƒ•แƒ” แƒœแƒแƒฉแƒ•แƒ”แƒœแƒ”แƒ‘แƒ˜ แƒšแƒแƒฅแƒ”แƒ‘แƒ˜แƒก แƒ’แƒแƒ“แƒแƒแƒ“แƒ’แƒ˜แƒšแƒ”แƒ‘แƒ˜แƒก แƒ™แƒแƒ“แƒ˜:

addMouseListener(new MouseAdapter() {
  @Override
  public void mousePressed(MouseEvent e) {
    // used to let users to interact on the grid by clicking
    // it's time to implement interaction with users to move tiles to solve the game !
    if (gameOver) {
      newGame();
    } else {
      // get position of the click
      int ex = e.getX() - margin;
      int ey = e.getY() - margin;
 
      // click in the grid ?
      if (ex < 0 || ex > gridSize  || ey < 0  || ey > gridSize)
        return;
 
      // get position in the grid
      int c1 = ex / tileSize;
      int r1 = ey / tileSize;
 
      // get position of the blank cell
      int c2 = blankPos % size;
      int r2 = blankPos / size;
 
      // we convert in the 1D coord
      int clickPos = r1 * size + c1;
 
      int dir = 0;
 
      // we search direction for multiple tile moves at once
      if (c1 == c2  &&  Math.abs(r1 - r2) > 0)
        dir = (r1 - r2) > 0 ? size : -size;
      else if (r1 == r2 && Math.abs(c1 - c2) > 0)
        dir = (c1 - c2) > 0 ? 1 : -1;
 
      if (dir != 0) {
        // we move tiles in the direction
        do {
          int newBlankPos = blankPos + dir;
          tiles[blankPos] = tiles[newBlankPos];
          blankPos = newBlankPos;
        } while(blankPos != clickPos);
 
        tiles[blankPos] = 0;
      }
 
      // we check if game is solved
      gameOver = isSolved();
    }
 
    // we repaint panel
    repaint();
  }
});

แƒฉแƒ•แƒ”แƒœ แƒ•แƒแƒ—แƒแƒ•แƒกแƒ”แƒ‘แƒ— แƒ™แƒแƒ“แƒก GameOffFifteen แƒ™แƒšแƒแƒกแƒ˜แƒก แƒ™แƒแƒœแƒกแƒขแƒ แƒฃแƒฅแƒขแƒแƒ แƒจแƒ˜. แƒ“แƒแƒกแƒแƒกแƒ แƒฃแƒšแƒก แƒฉแƒ•แƒ”แƒœ แƒ•แƒฃแƒฌแƒแƒ“แƒ”แƒ‘แƒ— newGame แƒ›แƒ”แƒ—แƒแƒ“แƒก แƒแƒฎแƒแƒšแƒ˜ แƒ—แƒแƒ›แƒแƒจแƒ˜แƒก แƒ“แƒแƒกแƒแƒฌแƒงแƒ”แƒ‘แƒแƒ“.

แƒ—แƒแƒ›แƒแƒจแƒ˜แƒก แƒกแƒ แƒฃแƒšแƒ˜ แƒ™แƒแƒ“แƒ˜

แƒ—แƒแƒ›แƒแƒจแƒ˜แƒก แƒ›แƒแƒฅแƒ›แƒ”แƒ“แƒ”แƒ‘แƒแƒจแƒ˜ แƒœแƒแƒฎแƒ•แƒแƒ›แƒ“แƒ” แƒ‘แƒแƒšแƒ แƒœแƒแƒ‘แƒ˜แƒฏแƒ˜ แƒแƒ แƒ˜แƒก แƒ™แƒแƒ“แƒ˜แƒก แƒงแƒ•แƒ”แƒšแƒ แƒ”แƒšแƒ”แƒ›แƒ”แƒœแƒขแƒ˜แƒก แƒ”แƒ แƒ—แƒแƒ“ แƒจแƒ”แƒ™แƒ แƒ”แƒ‘แƒ. แƒแƒ˜ แƒ แƒ แƒฎแƒ“แƒ”แƒ‘แƒ:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
 
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
 
// We are going to create a Game of 15 Puzzle with Java 8 and Swing
// If you have some questions, feel free to read comments ;)
public class GameOfFifteen extends JPanel { // our grid will be drawn in a dedicated Panel
 
  // Size of our Game of Fifteen instance
  private int size;
  // Number of tiles
  private int nbTiles;
  // Grid UI Dimension
  private int dimension;
  // Foreground Color
  private static final Color FOREGROUND_COLOR = new Color(239, 83, 80); // we use arbitrary color
  // Random object to shuffle tiles
  private static final Random RANDOM = new Random();
  // Storing the tiles in a 1D Array of integers
  private int[] tiles;
  // Size of tile on UI
  private int tileSize;
  // Position of the blank tile
  private int blankPos;
  // Margin for the grid on the frame
  private int margin;
  // Grid UI Size
  private int gridSize;
  private boolean gameOver; // true if game over, false otherwise
 
  public GameOfFifteen(int size, int dim, int mar) {
    this.size = size;
    dimension = dim;
    margin = mar;
    
    // init tiles
    nbTiles = size * size - 1; // -1 because we don't count blank tile
    tiles = new int[size * size];
    
    // calculate grid size and tile size
    gridSize = (dim - 2 * margin);
    tileSize = gridSize / size;
    
    setPreferredSize(new Dimension(dimension, dimension + margin));
    setBackground(Color.WHITE);
    setForeground(FOREGROUND_COLOR);
    setFont(new Font("SansSerif", Font.BOLD, 60));
    
    gameOver = true;
    
    addMouseListener(new MouseAdapter() {
      @Override
      public void mousePressed(MouseEvent e) {
        // used to let users to interact on the grid by clicking
        // it's time to implement interaction with users to move tiles to solve the game !
        if (gameOver) {
          newGame();
        } else {
          // get position of the click
          int ex = e.getX() - margin;
          int ey = e.getY() - margin;
          
          // click in the grid ?
          if (ex < 0 || ex > gridSize  || ey < 0  || ey > gridSize)
            return;
          
          // get position in the grid
          int c1 = ex / tileSize;
          int r1 = ey / tileSize;
          
          // get position of the blank cell
          int c2 = blankPos % size;
          int r2 = blankPos / size;
          
          // we convert in the 1D coord
          int clickPos = r1 * size + c1;
          
          int dir = 0;
          
          // we search direction for multiple tile moves at once
          if (c1 == c2  &&  Math.abs(r1 - r2) > 0)
            dir = (r1 - r2) > 0 ? size : -size;
          else if (r1 == r2 && Math.abs(c1 - c2) > 0)
            dir = (c1 - c2) > 0 ? 1 : -1;
            
          if (dir != 0) {
            // we move tiles in the direction
            do {
              int newBlankPos = blankPos + dir;
              tiles[blankPos] = tiles[newBlankPos];
              blankPos = newBlankPos;
            } while(blankPos != clickPos);
            
            tiles[blankPos] = 0;
          }
          
          // we check if game is solved
          gameOver = isSolved();
        }
        
        // we repaint panel
        repaint();
      }
    });
    
    newGame();
  }
 
  private void newGame() {
    do {
      reset(); // reset in intial state
      shuffle(); // shuffle
    } while(!isSolvable()); // make it until grid be solvable
    
    gameOver = false;
  }
 
  private void reset() {
    for (int i = 0; i < tiles.length; i++) {
      tiles[i] = (i + 1) % tiles.length;
    }
    
    // we set blank cell at the last
    blankPos = tiles.length - 1;
  }
 
  private void shuffle() {
    // don't include the blank tile in the shuffle, leave in the solved position
    int n = nbTiles;
    
    while (n > 1) {
      int r = RANDOM.nextInt(n--);
      int tmp = tiles[r];
      tiles[r] = tiles[n];
      tiles[n] = tmp;
    }
  }
 
  // Only half permutations of the puzzle are solvable.
  // Whenever a tile is preceded by a tile with higher value it counts
  // as an inversion. In our case, with the blank tile in the solved position,
  // the number of inversions must be even for the puzzle to be solvable
  private boolean isSolvable() {
    int countInversions = 0;
    
    for (int i = 0; i < nbTiles; i++) {
      for (int j = 0; j < i; j++) {
        if (tiles[j] > tiles[i])
          countInversions++;
      }
    }
    
    return countInversions % 2 == 0;
  }
 
  private boolean isSolved() {
    if (tiles[tiles.length - 1] != 0) // if blank tile is not in the solved position ==> not solved
      return false;
    
    for (int i = nbTiles - 1; i >= 0; i--) {
      if (tiles[i] != i + 1)
        return false;      
    }
    
    return true;
  }
 
  private void drawGrid(Graphics2D g) {
    for (int i = 0; i < tiles.length; i++) {
      // we convert 1D coords to 2D coords given the size of the 2D Array
      int r = i / size;
      int c = i % size;
      // we convert in coords on the UI
      int x = margin + c * tileSize;
      int y = margin + r * tileSize;
      
      // check special case for blank tile
      if(tiles[i] == 0) {
        if (gameOver) {
          g.setColor(FOREGROUND_COLOR);
          drawCenteredString(g, "u2713", x, y);
        }
        
        continue;
      }
      
      // for other tiles
      g.setColor(getForeground());
      g.fillRoundRect(x, y, tileSize, tileSize, 25, 25);
      g.setColor(Color.BLACK);
      g.drawRoundRect(x, y, tileSize, tileSize, 25, 25);
      g.setColor(Color.WHITE);
      
      drawCenteredString(g, String.valueOf(tiles[i]), x , y);
    }
  }
 
  private void drawStartMessage(Graphics2D g) {
    if (gameOver) {
      g.setFont(getFont().deriveFont(Font.BOLD, 18));
      g.setColor(FOREGROUND_COLOR);
      String s = "Click to start new game";
      g.drawString(s, (getWidth() - g.getFontMetrics().stringWidth(s)) / 2,
          getHeight() - margin);
    }
  }
 
  private void drawCenteredString(Graphics2D g, String s, int x, int y) {
    // center string s for the given tile (x,y)
    FontMetrics fm = g.getFontMetrics();
    int asc = fm.getAscent();
    int desc = fm.getDescent();
    g.drawString(s,  x + (tileSize - fm.stringWidth(s)) / 2,
        y + (asc + (tileSize - (asc + desc)) / 2));
  }
 
  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2D = (Graphics2D) g;
    g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    drawGrid(g2D);
    drawStartMessage(g2D);
  }
 
  public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {
      JFrame frame = new JFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setTitle("Game of Fifteen");
      frame.setResizable(false);
      frame.add(new GameOfFifteen(4, 550, 30), BorderLayout.CENTER);
      frame.pack();
      // center on the screen
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
    });
  }
 
 
}

แƒ‘แƒแƒšแƒแƒก แƒ“แƒ แƒ‘แƒแƒšแƒแƒก, แƒ›แƒแƒ“แƒ˜แƒ— แƒ•แƒ˜แƒ—แƒแƒ›แƒแƒจแƒแƒ—!

แƒ“แƒ แƒแƒ แƒ“แƒแƒ˜แƒฌแƒงแƒแƒก แƒ—แƒแƒ›แƒแƒจแƒ˜ แƒ“แƒ แƒ’แƒแƒ›แƒแƒกแƒชแƒแƒ“แƒแƒ— แƒ˜แƒก แƒ›แƒแƒฅแƒ›แƒ”แƒ“แƒ”แƒ‘แƒแƒจแƒ˜. แƒ•แƒ”แƒšแƒ˜ แƒแƒกแƒ” แƒฃแƒœแƒ“แƒ แƒ’แƒแƒ›แƒแƒ˜แƒงแƒฃแƒ แƒ”แƒ‘แƒแƒ“แƒ”แƒก:

"แƒขแƒ”แƒ’แƒ˜" แƒฏแƒแƒ•แƒแƒจแƒ˜ - แƒ แƒแƒ’แƒแƒ  แƒ’แƒแƒœแƒ•แƒแƒ•แƒ˜แƒ—แƒแƒ แƒแƒ— แƒกแƒ แƒฃแƒšแƒคแƒแƒกแƒแƒ•แƒแƒœแƒ˜ แƒ—แƒแƒ›แƒแƒจแƒ˜

แƒจแƒ”แƒ•แƒ”แƒชแƒแƒ“แƒแƒ— แƒแƒ›แƒแƒฎแƒกแƒœแƒแƒ— แƒ—แƒแƒ•แƒกแƒแƒขแƒ”แƒฎแƒ˜. แƒ—แƒฃ แƒงแƒ•แƒ”แƒšแƒแƒคแƒ”แƒ แƒ˜ แƒ™แƒแƒ แƒ’แƒแƒ“ แƒฌแƒแƒ•แƒ˜แƒ“แƒ, แƒ›แƒ˜แƒ•แƒ˜แƒฆแƒ”แƒ‘แƒ— แƒจแƒ”แƒ›แƒ“แƒ”แƒ’แƒก:

"แƒขแƒ”แƒ’แƒ˜" แƒฏแƒแƒ•แƒแƒจแƒ˜ - แƒ แƒแƒ’แƒแƒ  แƒ’แƒแƒœแƒ•แƒแƒ•แƒ˜แƒ—แƒแƒ แƒแƒ— แƒกแƒ แƒฃแƒšแƒคแƒแƒกแƒแƒ•แƒแƒœแƒ˜ แƒ—แƒแƒ›แƒแƒจแƒ˜

แฒกแƒฃแƒš แƒ”แƒก แƒแƒ แƒ˜แƒก. แƒ›แƒ”แƒขแƒก แƒ”แƒšแƒแƒ“แƒ˜? ๐Ÿ™‚

Skillbox แƒ’แƒ˜แƒ แƒฉแƒ”แƒ•แƒ—:

แƒฌแƒงแƒแƒ แƒ: www.habr.com

แƒแƒฎแƒแƒšแƒ˜ แƒ™แƒแƒ›แƒ”แƒœแƒขแƒแƒ แƒ˜แƒก แƒ“แƒแƒ›แƒแƒขแƒ”แƒ‘แƒ