āĻœāĻžāĻ­āĻžāĻ¤ā§‡ "āĻŸā§āĻ¯āĻžāĻ—" - āĻ•ā§€āĻ­āĻžāĻŦā§‡ āĻāĻ•āĻŸāĻŋ āĻĒā§‚āĻ°ā§āĻŖāĻžāĻ™ā§āĻ— āĻ—ā§‡āĻŽ āĻŦāĻŋāĻ•āĻžāĻļ āĻ•āĻ°āĻž āĻ¯āĻžāĻ¯āĻŧ

āĻœāĻžāĻ­āĻžāĻ¤ā§‡ "āĻŸā§āĻ¯āĻžāĻ—" - āĻ•ā§€āĻ­āĻžāĻŦā§‡ āĻāĻ•āĻŸāĻŋ āĻĒā§‚āĻ°ā§āĻŖāĻžāĻ™ā§āĻ— āĻ—ā§‡āĻŽ āĻŦāĻŋāĻ•āĻžāĻļ āĻ•āĻ°āĻž āĻ¯āĻžāĻ¯āĻŧ

"āĻĒāĻ¨ā§‡āĻ°ā§‹" āĻŦāĻž "āĻĒāĻ¨ā§‡āĻ°ā§‹" āĻāĻ•āĻŸāĻŋ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ āĻ˛āĻœāĻŋāĻ• āĻ—ā§‡āĻŽā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻšāĻŽā§ŽāĻ•āĻžāĻ° āĻ‰āĻĻāĻžāĻšāĻ°āĻŖ āĻ¯āĻž āĻ¸āĻžāĻ°āĻž āĻŦāĻŋāĻļā§āĻŦā§‡ āĻœāĻ¨āĻĒā§āĻ°āĻŋāĻ¯āĻŧāĨ¤ āĻ§āĻžāĻāĻ§āĻžāĻŸāĻŋ āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯, āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ›ā§‹āĻŸ āĻĨā§‡āĻ•ā§‡ āĻŦāĻĄāĻŧ āĻĒāĻ°ā§āĻ¯āĻ¨ā§āĻ¤ āĻ•ā§āĻ°āĻŽāĻžāĻ¨ā§āĻ¸āĻžāĻ°ā§‡ āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž āĻ¸āĻš āĻŦāĻ°ā§āĻ—āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°āĻ—ā§āĻ˛āĻŋ āĻ¸āĻžāĻœāĻžāĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻāĻŸāĻž āĻ¸āĻšāĻœ āĻ¨āĻ¯āĻŧ, āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻāĻŸāĻž āĻ†āĻ•āĻ°ā§āĻˇāĻŖā§€āĻ¯āĻŧ.

āĻ†āĻœāĻ•ā§‡āĻ° āĻŸāĻŋāĻ‰āĻŸā§‹āĻ°āĻŋāĻ¯āĻŧāĻžāĻ˛ā§‡ āĻ†āĻŽāĻ°āĻž āĻĻā§‡āĻ–āĻžāĻŦ āĻ•āĻŋāĻ­āĻžāĻŦā§‡ Eclipse āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ Java 8-āĻ Fifteen āĻĄā§‡āĻ­ā§‡āĻ˛āĻĒ āĻ•āĻ°āĻž āĻ¯āĻžāĻ¯āĻŧāĨ¤ UI āĻĄā§‡āĻ­ā§‡āĻ˛āĻĒ āĻ•āĻ°āĻ¤ā§‡ āĻ†āĻŽāĻ°āĻž Swing API āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦāĨ¤

āĻ†āĻŽāĻ°āĻž āĻŽāĻ¨ā§‡ āĻ•āĻ°āĻŋāĻ¯āĻŧā§‡ āĻĻāĻŋāĻšā§āĻ›āĻŋ: "Habr"-āĻāĻ° āĻ¸āĻ•āĻ˛ āĻĒāĻžāĻ āĻ•āĻĻā§‡āĻ° āĻœāĻ¨ā§āĻ¯ - "Habr" āĻĒā§āĻ°āĻšāĻžāĻ°āĻŽā§‚āĻ˛āĻ• āĻ•ā§‹āĻĄ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻ¯ā§‡āĻ•ā§‹āĻ¨ā§‹ Skillbox āĻ•ā§‹āĻ°ā§āĻ¸ā§‡ āĻ¨āĻĨāĻŋāĻ­ā§āĻ•ā§āĻ¤ āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ 10 āĻ°ā§āĻŦā§‡āĻ˛ āĻ›āĻžāĻĄāĻŧāĨ¤

Skillbox āĻ¸ā§āĻĒāĻžāĻ°āĻŋāĻļ āĻ•āĻ°ā§‡: āĻļāĻŋāĻ•ā§āĻˇāĻžāĻ—āĻ¤ āĻ…āĻ¨āĻ˛āĻžāĻ‡āĻ¨ āĻ•ā§‹āĻ°ā§āĻ¸ "āĻĒā§‡āĻļāĻž āĻœāĻžāĻ­āĻž āĻŦāĻŋāĻ•āĻžāĻļāĻ•āĻžāĻ°ā§€".

āĻ–ā§‡āĻ˛āĻžāĻ° āĻ¨āĻ•āĻļāĻž

āĻāĻ‡ āĻĒāĻ°ā§āĻ¯āĻžāĻ¯āĻŧā§‡ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻŦā§ˆāĻļāĻŋāĻˇā§āĻŸā§āĻ¯āĻ—ā§āĻ˛āĻŋ āĻ¸āĻ‚āĻœā§āĻžāĻžāĻ¯āĻŧāĻŋāĻ¤ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡:

  • āĻ†āĻ•āĻžāĻ° - āĻ–ā§‡āĻ˛āĻžāĻ° āĻŽāĻžāĻ ā§‡āĻ° āĻ†āĻ•āĻžāĻ°;
  • nbTiles — āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡āĻ° āĻŸā§āĻ¯āĻžāĻ—ā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĨ¤ nbTiles = āĻ†āĻ•āĻžāĻ° * āĻ†āĻ•āĻžāĻ° - 1;
  • āĻŸāĻžāĻ‡āĻ˛āĻ¸ āĻšāĻ˛ āĻāĻ•āĻŸāĻŋ āĻŸā§āĻ¯āĻžāĻ— āĻ¯āĻž āĻĒā§‚āĻ°ā§āĻŖāĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĻ° āĻāĻ•-āĻŽāĻžāĻ¤ā§āĻ°āĻŋāĻ• āĻ…ā§āĻ¯āĻžāĻ°ā§‡āĨ¤ āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻŸā§āĻ¯āĻžāĻ— āĻĒāĻ°āĻŋāĻ¸āĻ°ā§‡ āĻāĻ•āĻŸāĻŋ āĻ…āĻ¨āĻ¨ā§āĻ¯ āĻŽāĻžāĻ¨ āĻĒāĻžāĻŦā§‡ [0, nbTiles]āĨ¤ āĻļā§‚āĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻ–āĻžāĻ˛āĻŋ āĻŦāĻ°ā§āĻ— āĻ¨āĻŋāĻ°ā§āĻĻā§‡āĻļ āĻ•āĻ°ā§‡;
  • blankPos — āĻ–āĻžāĻ˛āĻŋ āĻŦāĻ°ā§āĻ—āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡āĻ° āĻ…āĻŦāĻ¸ā§āĻĨāĻžāĻ¨āĨ¤

āĻ–ā§‡āĻ˛āĻž āĻ¯ā§āĻ•ā§āĻ¤āĻŋ

āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻ—ā§‡āĻŽ āĻĒāĻœāĻŋāĻļāĻ¨ āĻļā§āĻ°ā§ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻŦā§āĻ¯āĻŦāĻšā§ƒāĻ¤ āĻāĻ•āĻŸāĻŋ āĻ°āĻŋāĻ¸ā§‡āĻŸ āĻĒāĻĻā§āĻ§āĻ¤āĻŋ āĻ¸āĻ‚āĻœā§āĻžāĻžāĻ¯āĻŧāĻŋāĻ¤ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻāĻ‡āĻ­āĻžāĻŦā§‡ āĻ†āĻŽāĻ°āĻž āĻŸā§āĻ¯āĻžāĻ— āĻ…ā§āĻ¯āĻžāĻ°ā§‡āĻ° āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻ‰āĻĒāĻžāĻĻāĻžāĻ¨ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻŽāĻžāĻ¨ āĻ¸ā§‡āĻŸ āĻ•āĻ°āĻŋāĨ¤ āĻ†āĻšā§āĻ›āĻž, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻ†āĻŽāĻ°āĻž āĻ…ā§āĻ¯āĻžāĻ°ā§‡āĻ° āĻļā§‡āĻˇ āĻ…āĻŦāĻ¸ā§āĻĨāĻžāĻ¨ā§‡ blankPos āĻ°āĻžāĻ–āĻŋāĨ¤

āĻŸā§āĻ¯āĻžāĻ—āĻ—ā§āĻ˛āĻŋāĻ° āĻ…ā§āĻ¯āĻžāĻ°ā§‡ āĻāĻ˛ā§‹āĻŽā§‡āĻ˛ā§‹ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻļāĻžāĻĢā§‡āĻ˛ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ°āĻ“ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨āĨ¤ āĻ†āĻŽāĻ°āĻž āĻ–āĻžāĻ˛āĻŋ āĻŸā§āĻ¯āĻžāĻ—āĻŸāĻŋāĻ•ā§‡ āĻāĻ•āĻ‡ āĻ…āĻŦāĻ¸ā§āĻĨāĻžāĻ¨ā§‡ āĻ°āĻžāĻ–āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻļāĻžāĻĢāĻ˛āĻŋāĻ‚ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ¤ā§‡ āĻ…āĻ¨ā§āĻ¤āĻ°ā§āĻ­ā§āĻ•ā§āĻ¤ āĻ•āĻ°āĻŋ āĻ¨āĻžāĨ¤

āĻ¯ā§‡āĻšā§‡āĻ¤ā§ āĻ§āĻžāĻāĻ§āĻžāĻŸāĻŋāĻ° āĻ¸āĻŽā§āĻ­āĻžāĻŦā§āĻ¯ āĻĒā§āĻ°āĻžāĻ°āĻŽā§āĻ­āĻŋāĻ• āĻ…āĻŦāĻ¸ā§āĻĨāĻžāĻ¨ā§‡āĻ° āĻŽāĻžāĻ¤ā§āĻ° āĻ…āĻ°ā§āĻ§ā§‡āĻ•āĻŸāĻŋāĻ° āĻāĻ•āĻŸāĻŋ āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡, āĻ¤āĻžāĻ‡ āĻŦāĻ°ā§āĻ¤āĻŽāĻžāĻ¨ āĻ˛ā§‡āĻ†āĻ‰āĻŸāĻŸāĻŋ āĻāĻŽāĻ¨āĻ•āĻŋ āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨āĻ¯ā§‹āĻ—ā§āĻ¯ āĻ•āĻŋāĻ¨āĻž āĻ¤āĻž āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻ•āĻ°āĻ¤ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻĢāĻ˛āĻžāĻĢāĻ˛ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ā§‡āĻ° āĻĢāĻ˛āĻžāĻĢāĻ˛ āĻĒāĻ°ā§€āĻ•ā§āĻˇāĻž āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻāĻŸāĻŋ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯, āĻ†āĻŽāĻ°āĻž isSolvable āĻĒāĻĻā§āĻ§āĻ¤āĻŋ āĻ¸āĻ‚āĻœā§āĻžāĻžāĻ¯āĻŧāĻŋāĻ¤ āĻ•āĻ°āĻŋāĨ¤

āĻ¯āĻĻāĻŋ āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻŸā§āĻ¯āĻžāĻ—ā§‡āĻ° āĻ†āĻ—ā§‡ āĻāĻ•āĻŸāĻŋ āĻ‰āĻšā§āĻš āĻŽāĻžāĻ¨ā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻŸā§āĻ¯āĻžāĻ— āĻĨāĻžāĻ•ā§‡ āĻ¤āĻŦā§‡ āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻŦāĻŋāĻŦā§‡āĻšāĻŋāĻ¤ āĻšāĻ¯āĻŧāĨ¤ āĻ¯āĻ–āĻ¨ āĻ–āĻžāĻ˛āĻŋ āĻ¸ā§āĻĨāĻžāĻ¨āĻŸāĻŋ āĻĨāĻžāĻ•ā§‡, āĻ¤āĻ–āĻ¨ āĻ§āĻžāĻāĻ§āĻžāĻŸāĻŋ āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨āĻ¯ā§‹āĻ—ā§āĻ¯ āĻšāĻ“āĻ¯āĻŧāĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž āĻ…āĻŦāĻļā§āĻ¯āĻ‡ āĻ¸āĻŽāĻžāĻ¨ āĻšāĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻ¤āĻžāĻ‡ āĻ†āĻŽāĻ°āĻž āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž āĻ—āĻŖāĻ¨āĻž āĻ•āĻ°āĻŋ āĻāĻŦāĻ‚ āĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĻŸāĻŋ āĻœā§‹āĻĄāĻŧ āĻšāĻ˛ā§‡ āĻ¸āĻ¤ā§āĻ¯ āĻĢā§‡āĻ°āĻ¤ āĻĻāĻŋāĻ‡āĨ¤

āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ—ā§‡āĻŽ āĻ…āĻĢ āĻĢāĻŋāĻĢāĻŸāĻŋāĻ¨ āĻ˛ā§‡āĻ†āĻ‰āĻŸāĻŸāĻŋ āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡ āĻ•āĻŋāĻ¨āĻž āĻ¤āĻž āĻĒāĻ°ā§€āĻ•ā§āĻˇāĻž āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ isSolved āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻŸāĻŋ āĻ¸āĻ‚āĻœā§āĻžāĻžāĻ¯āĻŧāĻŋāĻ¤ āĻ•āĻ°āĻž āĻ—ā§āĻ°ā§āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖāĨ¤ āĻĒā§āĻ°āĻĨāĻŽā§‡ āĻ†āĻŽāĻ°āĻž āĻĻā§‡āĻ–āĻŋ āĻ–āĻžāĻ˛āĻŋ āĻœāĻžāĻ¯āĻŧāĻ—āĻžāĻŸāĻž āĻ•ā§‹āĻĨāĻžāĻ¯āĻŧāĨ¤ āĻ¯āĻĻāĻŋ āĻĒā§āĻ°āĻžāĻĨāĻŽāĻŋāĻ• āĻ…āĻŦāĻ¸ā§āĻĨāĻžāĻ¨ā§‡ āĻĨāĻžāĻ•ā§‡, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻŦāĻ°ā§āĻ¤āĻŽāĻžāĻ¨ āĻĒā§āĻ°āĻžāĻ¨ā§āĻ¤āĻŋāĻ•āĻ•āĻ°āĻŖāĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨, āĻĒā§‚āĻ°ā§āĻŦā§‡ āĻ¸āĻŋāĻĻā§āĻ§āĻžāĻ¨ā§āĻ¤ āĻ¨ā§‡āĻ“āĻ¯āĻŧāĻž āĻšāĻ¯āĻŧāĻ¨āĻŋāĨ¤ āĻ¤āĻžāĻ°āĻĒāĻ°ā§‡ āĻ†āĻŽāĻ°āĻž āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ āĻ•ā§āĻ°āĻŽā§‡ āĻŸāĻžāĻ‡āĻ˛āĻ¸ā§‡āĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻĒā§āĻ¨āĻ°āĻžāĻŦā§ƒāĻ¤ā§āĻ¤āĻŋ āĻ•āĻ°āĻŋ āĻāĻŦāĻ‚ āĻ¯āĻĻāĻŋ āĻŸā§āĻ¯āĻžāĻ—ā§‡āĻ° āĻŽāĻžāĻ¨ āĻ¸āĻ‚āĻļā§āĻ˛āĻŋāĻˇā§āĻŸ āĻ¸ā§‚āĻšāĻ• +1 āĻĨā§‡āĻ•ā§‡ āĻ­āĻŋāĻ¨ā§āĻ¨ āĻšāĻ¯āĻŧ, āĻ†āĻŽāĻ°āĻž āĻŽāĻŋāĻĨā§āĻ¯āĻž āĻĢā§‡āĻ°āĻ¤ āĻĻāĻŋāĻ‡āĨ¤ āĻ…āĻ¨ā§āĻ¯āĻĨāĻžāĻ¯āĻŧ, āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ° āĻļā§‡āĻˇā§‡ āĻāĻŸāĻŋ āĻ¸āĻ¤ā§āĻ¯ āĻĢāĻŋāĻ°ā§‡ āĻ†āĻ¸āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ•āĻžāĻ°āĻŖ āĻ§āĻžāĻāĻ§āĻžāĻŸāĻŋ āĻ‡āĻ¤āĻŋāĻŽāĻ§ā§āĻ¯ā§‡ āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤

āĻ†āĻ°ā§‡āĻ•āĻŸāĻŋ āĻĒāĻĻā§āĻ§āĻ¤āĻŋ āĻ¯āĻž āĻ¸āĻ‚āĻœā§āĻžāĻžāĻ¯āĻŧāĻŋāĻ¤ āĻ•āĻ°āĻž āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ āĻ¤āĻž āĻšāĻ˛ 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;

āĻ†āĻŽāĻ°āĻž āĻ¸ā§āĻ‡āĻ‚ API āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ UI āĻŦāĻŋāĻ•āĻžāĻļ āĻ•āĻ°āĻŋ

āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻĢā§‡āĻ¸ā§‡ āĻ•āĻžāĻœ āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻāĻ¸ā§‡āĻ›ā§‡āĨ¤ āĻĒā§āĻ°āĻĨāĻŽā§‡ āĻ†āĻŽāĻ°āĻž Jpanel āĻ•ā§āĻ˛āĻžāĻ¸ āĻ¨āĻŋāĻ‡āĨ¤ āĻ¤āĻžāĻ°āĻĒāĻ°ā§‡ āĻ†āĻŽāĻ°āĻž āĻŽāĻžāĻ ā§‡ āĻŸā§āĻ¯āĻžāĻ— āĻ†āĻāĻ•āĻŋ - āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋāĻ° āĻ†āĻ•āĻžāĻ° āĻ—āĻŖāĻ¨āĻž āĻ•āĻ°āĻ¤ā§‡, āĻ†āĻŽāĻ°āĻž āĻ—ā§‡āĻŽ āĻ•āĻ¨āĻ¸ā§āĻŸā§āĻ°āĻžāĻ•ā§āĻŸāĻ° āĻĒā§āĻ¯āĻžāĻ°āĻžāĻŽāĻŋāĻŸāĻžāĻ°ā§‡ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻĄā§‡āĻŸāĻž āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦ:

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

āĻŽāĻžāĻ°ā§āĻœāĻŋāĻ¨ āĻšāĻ˛ āĻ—ā§‡āĻŽ āĻ•āĻ¨āĻ¸ā§āĻŸā§āĻ°āĻžāĻ•ā§āĻŸāĻ°ā§‡ āĻāĻ•āĻŸāĻŋ āĻĒā§āĻ¯āĻžāĻ°āĻžāĻŽāĻŋāĻŸāĻžāĻ° āĻ¸ā§‡āĻŸāĨ¤

āĻāĻ–āĻ¨ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻ¨ā§‡ āĻ—ā§āĻ°āĻŋāĻĄ āĻāĻŦāĻ‚ āĻĻāĻžāĻ— āĻ†āĻāĻ•āĻžāĻ° āĻœāĻ¨ā§āĻ¯ 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);
  }
}

āĻ…āĻŦāĻļā§‡āĻˇā§‡, āĻĒā§‡āĻ‡āĻ¨ā§āĻŸ āĻ•āĻŽā§āĻĒā§‹āĻ¨ā§‡āĻ¨ā§āĻŸ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ•ā§‡ āĻ“āĻ­āĻžāĻ°āĻ°āĻžāĻ‡āĻĄ āĻ•āĻ°āĻž āĻ¯āĻžāĻ•, āĻ¯āĻž JPane āĻ•ā§āĻ˛āĻžāĻ¸ āĻĨā§‡āĻ•ā§‡ āĻ‰āĻĻā§āĻ­ā§‚āĻ¤āĨ¤ āĻ¤āĻžāĻ°āĻĒāĻ°ā§‡ āĻ†āĻŽāĻ°āĻž āĻĄā§āĻ°āĻ—ā§āĻ°āĻŋāĻĄ āĻĒāĻĻā§āĻ§āĻ¤āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŋ, āĻ¤āĻžāĻ°āĻĒāĻ°ā§‡ āĻĄā§āĻ°āĻ¸ā§āĻŸāĻžāĻ°ā§āĻŸ āĻŽā§‡āĻ¸ā§‡āĻœ āĻĒāĻĻā§āĻ§āĻ¤āĻŋ āĻ…āĻ¨ā§āĻ¸āĻ°āĻŖ āĻ•āĻ°ā§‡ āĻāĻ•āĻŸāĻŋ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ āĻ•āĻ°āĻŋ āĻ¯āĻž āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ—ā§‡āĻŽ āĻļā§āĻ°ā§ āĻ•āĻ°āĻ¤ā§‡ āĻ•ā§āĻ˛āĻŋāĻ• āĻ•āĻ°āĻ¤ā§‡ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ•āĻ°ā§‡:

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-āĻ¤ā§‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ—ā§āĻ˛āĻŋ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻ•āĻ°āĻž āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§ˇ āĻāĻŸāĻŋ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯, Jpanel-āĻ MouseListener āĻāĻ° āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ āĻāĻŦāĻ‚ āĻŽā§āĻ­āĻŋāĻ‚ āĻ¸ā§āĻĒāĻŸāĻ—ā§āĻ˛āĻŋāĻ° āĻœāĻ¨ā§āĻ¯ āĻ•ā§‹āĻĄ āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨, āĻ‡āĻ¤āĻŋāĻŽāĻ§ā§āĻ¯ā§‡ āĻ‰āĻĒāĻ°ā§‡ āĻĻā§‡āĻ–āĻžāĻ¨ā§‹ āĻšāĻ¯āĻŧā§‡āĻ›ā§‡:

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();
  }
});

āĻ†āĻŽāĻ°āĻž GameOfFifteen āĻ•ā§āĻ˛āĻžāĻ¸ā§‡āĻ° āĻ•āĻ¨āĻ¸ā§āĻŸā§āĻ°āĻžāĻ•ā§āĻŸāĻ°ā§‡ āĻ•ā§‹āĻĄāĻŸāĻŋ āĻ°āĻžāĻ–āĻŋāĨ¤ āĻāĻ•ā§‡āĻŦāĻžāĻ°ā§‡ āĻļā§‡āĻˇā§‡, āĻ†āĻŽāĻ°āĻž āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻ—ā§‡āĻŽ āĻļā§āĻ°ā§ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ 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

āĻāĻ•āĻŸāĻŋ āĻŽāĻ¨ā§āĻ¤āĻŦā§āĻ¯ āĻœā§āĻĄāĻŧā§āĻ¨