"αžŠαž”αŸ‹αž”αŸ’αžšαžΆαŸ†" αž“αŸ…αž€αŸ’αž“αž»αž„ Java - αžšαž”αŸ€αž”αž”αž„αŸ’αž€αžΎαžαž αŸ’αž‚αŸαž˜αž–αŸαž‰αž›αž€αŸ’αžαžŽαŸˆ

"αžŠαž”αŸ‹αž”αŸ’αžšαžΆαŸ†" αž“αŸ…αž€αŸ’αž“αž»αž„ Java - αžšαž”αŸ€αž”αž”αž„αŸ’αž€αžΎαžαž αŸ’αž‚αŸαž˜αž–αŸαž‰αž›αž€αŸ’αžαžŽαŸˆ

"αžŠαž”αŸ‹αž”αŸ’αžšαžΆαŸ†" ឬ "αžŠαž”αŸ‹αž”αŸ’αžšαžΆαŸ†" αž‚αžΊαž‡αžΆαž§αž‘αžΆαž αžšαžŽαŸαžŠαŸαž’αžŸαŸ’αž…αžΆαžšαŸ’αž™αž“αŸƒαž αŸ’αž‚αŸαž˜αžαž€αŸ’αž€αžœαž·αž‡αŸ’αž‡αžΆαžŠαŸαžŸαžΆαž˜αž‰αŸ’αž‰αž˜αž½αž™ αžŠαŸ‚αž›αž–αŸαž‰αž“αž·αž™αž˜αž‘αžΌαž‘αžΆαŸ†αž„αž–αž·αž—αž–αž›αŸ„αž€αŸ” αžŠαžΎαž˜αŸ’αž”αžΈαžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž›αŸ’αž”αŸ‚αž„αž•αŸ’αž‚αž»αŸ†αžšαžΌαž” αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαžšαŸ€αž”αž…αŸ†αž€αžΆαžšαŸ‰αŸαžŠαŸ‚αž›αž˜αžΆαž“αž›αŸαžαžαžΆαž˜αž›αŸ†αžŠαžΆαž”αŸ‹αž›αŸ†αžŠαŸ„αž™ αž–αžΈαžαžΌαž…αž”αŸ†αž•αž»αžαž‘αŸ…αž’αŸ†αŸ” αžœαžΆαž˜αž·αž“αž„αžΆαž™αžŸαŸ’αžšαž½αž›αž‘αŸ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž‚αž½αžšαž±αŸ’αž™αž…αžΆαž”αŸ‹αž’αžΆαžšαž˜αŸ’αž˜αžŽαŸαŸ”

αž“αŸ…αž€αŸ’αž“αž»αž„αž˜αŸαžšαŸ€αž“αžαŸ’αž„αŸƒαž“αŸαŸ‡ αž™αžΎαž„αž”αž„αŸ’αž αžΆαž‰αž’αŸ’αž“αž€αž–αžΈαžšαž”αŸ€αž”αž’αž—αž·αžœαžŒαŸ’αž Fifteen αž€αŸ’αž“αž»αž„ Java 8 αž‡αžΆαž˜αž½αž™ EclipseαŸ” αžŠαžΎαž˜αŸ’αž”αžΈαž’αž—αž·αžœαžŒαŸ’αž UI αž™αžΎαž„αž“αžΉαž„αž”αŸ’αžšαžΎ Swing APIαŸ”

αž™αžΎαž„αžšαŸ†αž›αžΉαž€αŸ– αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αž“αž€αž’αžΆαž“αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αŸƒ "Habr" - αž€αžΆαžšαž”αž‰αŸ’αž…αž»αŸ‡αžαž˜αŸ’αž›αŸƒ 10 rubles αž“αŸ…αž–αŸαž›αž…αž»αŸ‡αžˆαŸ’αž˜αŸ„αŸ‡αž€αŸ’αž“αž»αž„αžœαž‚αŸ’αž‚αžŸαž·αž€αŸ’αžŸαžΆ Skillbox αžŽαžΆαž˜αž½αž™αžŠαŸ„αž™αž”αŸ’αžšαžΎαž›αŸαžαž€αžΌαžŠαž•αŸ’αžŸαž–αŸ’αžœαž•αŸ’αžŸαžΆαž™ "Habr" αŸ”

Skillbox αžŽαŸ‚αž“αžΆαŸ†αŸ– αžœαž‚αŸ’αž‚αžŸαž·αž€αŸ’αžŸαžΆαžαžΆαž˜αž’αŸŠαžΈαž“αž’αžΊαžŽαž·αž "Profession Java Developer".

αž€αžΆαžšαžšαž…αž“αžΆαž αŸ’αž‚αŸαž˜

αž“αŸ…αžŠαŸ†αžŽαžΆαž€αŸ‹αž€αžΆαž›αž“αŸαŸ‡ αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž€αŸ†αžŽαžαŸ‹αž›αž€αŸ’αžαžŽαŸˆαžŸαž˜αŸ’αž”αžαŸ’αžαž·αŸ–

  • αž‘αŸ†αž αŸ† - αž‘αŸ†αž αŸ†αž“αŸƒαž‘αžΈαž›αžΆαž“αž›αŸαž„;
  • nbTiles - αž…αŸ†αž“αž½αž“αžŸαŸ’αž›αžΆαž€αž“αŸ…αž€αŸ’αž“αž»αž„αžœαžΆαž›αŸ” nbTiles = αž‘αŸ†αž αŸ† * αž‘αŸ†αž αŸ† - 1;
  • αž€αŸ’αžšαž‘αžΆαž€αŸ’αž”αžΏαž„αž‚αžΊαž‡αžΆαžŸαŸ’αž›αžΆαž€αž˜αž½αž™ αžŠαŸ‚αž›αž‡αžΆαž’αžΆαžšαŸαž˜αž½αž™αžœαž·αž˜αžΆαžαŸ’αžšαž“αŸƒαž…αŸ†αž“αž½αž“αž‚αžαŸ‹αŸ” αžŸαŸ’αž›αžΆαž€αž“αžΈαž˜αž½αž™αŸ—αž“αžΉαž„αž‘αž‘αž½αž›αž”αžΆαž“αžαž˜αŸ’αž›αŸƒαžαŸ‚αž˜αž½αž™αž‚αžαŸ‹αž“αŸ…αž€αŸ’αž“αž»αž„αž‡αž½αžš [0, nbTiles] αŸ” αžŸαžΌαž“αŸ’αž™αžαŸ†αžŽαžΆαž„αž±αŸ’αž™αž€αžΆαžšαŸ‰αŸαž‘αž‘αŸ;
  • blankPos - αž‘αžΈαžαžΆαŸ†αž„αž“αŸƒαž€αžΆαžšαŸ‰αŸαž‘αž‘αŸαŸ”

αžαž€αŸ’αž€αžœαž·αž‡αŸ’αž‡αžΆαž αŸ’αž‚αŸαž˜

αž™αžΎαž„αžαŸ’αžšαžΌαžœαž€αŸ†αžŽαžαŸ‹αžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžšαŸ’αžαž€αŸ†αžŽαžαŸ‹αž‘αžΎαž„αžœαž·αž‰αžŠαŸ‚αž›αž”αŸ’αžšαžΎαžŠαžΎαž˜αŸ’αž”αžΈαž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž‘αžΈαžαžΆαŸ†αž„αž αŸ’αž‚αŸαž˜αžαŸ’αž˜αžΈαŸ” αž“αŸαŸ‡αž‡αžΆαžšαž”αŸ€αž”αžŠαŸ‚αž›αž™αžΎαž„αž€αŸ†αžŽαžαŸ‹αžαž˜αŸ’αž›αŸƒαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αžΆαžαž»αž“αžΈαž˜αž½αž™αŸ—αž“αŸƒαž’αžΆαžšαŸαžŸαŸ’αž›αžΆαž€αŸ” αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αž™αžΎαž„αžŠαžΆαž€αŸ‹ blankPos αž“αŸ…αž‘αžΈαžαžΆαŸ†αž„αž…αž»αž„αž€αŸ’αžšαŸ„αž™αž“αŸƒαž’αžΆαžšαŸαŸ”

αž™αžΎαž„αž€αŸαžαŸ’αžšαžΌαžœαž€αžΆαžšαžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžšαŸ’αžαžŸαžΆαž”αŸ‹αžŠαžΎαž˜αŸ’αž”αžΈαžŸαžΆαž”αŸ‹αž’αžΆαžšαŸαž“αŸƒαžŸαŸ’αž›αžΆαž€αŸ” αž™αžΎαž„αž˜αž·αž“αžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αžŸαŸ’αž›αžΆαž€αž‘αž‘αŸαž“αŸ…αž€αŸ’αž“αž»αž„αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžŸαžΆαž”αŸ‹αžŠαžΎαž˜αŸ’αž”αžΈαž‘αž»αž€αžœαžΆαž“αŸ…αž‘αžΈαžαžΆαŸ†αž„αžŠαžΎαž˜αžšαž”αžŸαŸ‹αžœαžΆαž“αŸ„αŸ‡αž‘αŸαŸ”

αžŠαŸ„αž™αžŸαžΆαžšβ€‹αžαŸ‚β€‹αž–αžΆαž€αŸ‹αž€αžŽαŸ’αžαžΆαž›β€‹αž“αŸƒβ€‹αž‘αžΈαžαžΆαŸ†αž„β€‹αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜β€‹αžŠαŸ‚αž›β€‹αž’αžΆαž…β€‹αž’αŸ’αžœαžΎβ€‹αž”αžΆαž“β€‹αž“αŸƒβ€‹αž›αŸ’αž”αŸ‚αž„αž•αŸ’αž‚αž»αŸ†αžšαžΌαž”β€‹αž˜αžΆαž“β€‹αžŠαŸ†αžŽαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™ αž›αž‘αŸ’αž’αž•αž›β€‹αž“αŸƒβ€‹αž€αžΆαžšβ€‹αžŸαžΆαž”αŸ‹β€‹αžαŸ’αžšαžΌαžœαžαŸ‚β€‹αž–αž·αž“αž·αžαŸ’αž™β€‹αžŠαžΎαž˜αŸ’αž”αžΈβ€‹αž”αŸ’αžšαžΆαž€αžŠαžαžΆβ€‹αž”αŸ’αž›αž„αŸ‹β€‹αž”αž…αŸ’αž…αž»αž”αŸ’αž”αž“αŸ’αž“β€‹αž’αžΆαž…β€‹αžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™β€‹αž”αžΆαž“β€‹αž‡αžΆαž‘αžΌαž‘αŸ…αŸ” αžŠαžΎαž˜αŸ’αž”αžΈαž’αŸ’αžœαžΎαžŠαžΌαž…αž“αŸαŸ‡αž™αžΎαž„αž€αŸ†αžŽαžαŸ‹αžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžšαŸ’αž isSovable αŸ”

αž”αŸ’αžšαžŸαž·αž“αž”αžΎ speck αž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹αž˜αž½αž™αž“αžΆαŸ†αž˜αž»αžαžŠαŸ„αž™ speck αžŠαŸ‚αž›αž˜αžΆαž“αžαž˜αŸ’αž›αŸƒαžαŸ’αž–αžŸαŸ‹αž‡αžΆαž„αž“αŸαŸ‡ αžœαžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αžΆαžαŸ‹αž‘αž»αž€αžαžΆαž‡αžΆαž€αžΆαžšαž”αž‰αŸ’αž…αŸ’αžšαžΆαžŸαŸ” αž“αŸ…β€‹αž–αŸαž›β€‹αžŸαŸ’αž›αžΆαž€β€‹αž‘αž‘αŸβ€‹αž“αŸ…β€‹αž“αžΉαž„β€‹αž€αž“αŸ’αž›αŸ‚αž„ αž…αŸ†αž“αž½αž“β€‹αž“αŸƒβ€‹αž€αžΆαžšβ€‹αž”αž‰αŸ’αž…αŸ’αžšαžΆαžŸβ€‹αžαŸ’αžšαžΌαžœβ€‹αžαŸ‚β€‹αž˜αžΆαž“β€‹αžŸαžΌαž˜αŸ’αž”αžΈβ€‹αžαŸ‚β€‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹β€‹αž•αŸ’αžŠαž»αŸ†β€‹αžšαžΌαž”β€‹αžŠαŸ‚αž›β€‹αž’αžΆαž…β€‹αžŠαŸ„αŸ‡β€‹αžŸαŸ’αžšαžΆαž™β€‹αž”αžΆαž“αŸ” αžŠαžΌαž…αŸ’αž“αŸαŸ‡β€‹αž™αžΎαž„β€‹αžšαžΆαž”αŸ‹β€‹αž…αŸ†αž“αž½αž“β€‹αž”αž‰αŸ’αž…αŸ’αžšαžΆαžŸ αž αžΎαž™β€‹αžαŸ’αžšαž‘αž”αŸ‹β€‹αž–αž·αžβ€‹αžœαž·αž‰ αž”αŸ’αžšαžŸαž·αž“αž”αžΎβ€‹αž…αŸ†αž“αž½αž“β€‹αžŸαŸ’αž˜αžΎαŸ”

αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αž‘αŸ€αž αžœαžΆαž‡αžΆαžšαžΏαž„αžŸαŸ†αžαžΆαž“αŸ‹αž€αŸ’αž“αž»αž„αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžαŸ’αžš isSolved αžŠαžΎαž˜αŸ’αž”αžΈαž–αž·αž“αž·αžαŸ’αž™αž˜αžΎαž›αžαžΆαžαžΎ Game Ofteen hand αžšαž”αžŸαŸ‹αž™αžΎαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž¬αž’αžαŸ‹αŸ” αžŠαŸ†αž”αžΌαž„αž™αžΎαž„αž–αž·αž“αž·αžαŸ’αž™αž˜αžΎαž›αž€αž“αŸ’αž›αŸ‚αž„αžŠαŸ‚αž›αžŸαŸ’αž›αžΆαž€αž‘αž‘αŸαžŸαŸ’αžαž·αžαž“αŸ…αŸ” αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž“αŸ…αž€αŸ’αž“αž»αž„αž‘αžΈαžαžΆαŸ†αž„αžŠαŸ†αž”αžΌαž„ αž“αŸ„αŸ‡αž”αŸ’αž›αž„αŸ‹αž”αž…αŸ’αž…αž»αž”αŸ’αž”αž“αŸ’αž“αž‚αžΊαžαŸ’αž˜αžΈ αž˜αž·αž“αžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž–αžΈαž˜αž»αž“αž‘αŸαŸ” αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αž™αžΎαž„αž’αŸ’αžœαžΎαžšαž„αŸ’αžœαž·αž›αž‡αž»αŸ†αžαžΆαž˜αž€αŸ’αžšαž‘αžΆαž€αŸ’αž“αž»αž„αž›αŸ†αžŠαžΆαž”αŸ‹αž”αž‰αŸ’αž…αŸ’αžšαžΆαžŸ αž αžΎαž™αž”αŸ’αžšαžŸαž·αž“αž”αžΎαžαž˜αŸ’αž›αŸƒαžŸαŸ’αž›αžΆαž€αžαž»αžŸαž–αžΈαžŸαž“αŸ’αž‘αžŸαŸ’αžŸαž“αŸ +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;

αž€αŸ†αž–αž»αž„αž’αž—αž·αžœαžŒαŸ’αž UI αž‡αžΆαž˜αž½αž™ Swing API

αžœαžΆαžŠαž›αŸ‹αž–αŸαž›αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž…αŸ†αžŽαž»αž…αž”αŸ’αžšαž‘αžΆαž€αŸ‹αŸ” αžŠαŸ†αž”αžΌαž„αž™αžΎαž„αž™αž€αžαŸ’αž“αžΆαž€αŸ‹ 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);
  }
}

αž‡αžΆαž…αž»αž„αž€αŸ’αžšαŸ„αž™ αž™αžΎαž„αž“αžΉαž„αž”αžŠαž·αžŸαŸαž’αžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžαŸ’αžš 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();
  }
});

αž€αžΌαžŠαžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαžΆαž€αŸ‹αž“αŸ…αž€αŸ’αž“αž»αž„αž’αŸ’αž“αž€αž”αž„αŸ’αž€αžΎαžαž“αŸƒαžαŸ’αž“αžΆαž€αŸ‹ GameOfFifteen αŸ” αž“αŸ…αž…αž»αž„αž”αž‰αŸ’αž…αž”αŸ‹ αž™αžΎαž„αž αŸ…αžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžαŸ’αžšαž αŸ’αž‚αŸαž˜αžαŸ’αž˜αžΈ αžŠαžΎαž˜αŸ’αž”αžΈαž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž αŸ’αž‚αŸαž˜αžαŸ’αž˜αžΈαŸ”

αž€αžΌαžŠαž αŸ’αž‚αŸαž˜αž–αŸαž‰

αž‡αŸ†αž αžΆαž“αž…αž»αž„αž€αŸ’αžšαŸ„αž™αž˜αž»αž“αž“αžΉαž„αžƒαžΎαž‰αž αŸ’αž‚αŸαž˜αž€αŸ†αž–αž»αž„αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž‚αžΊαžαŸ’αžšαžΌαžœαžŠαžΆαž€αŸ‹αž€αžΌαžŠαž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž”αž‰αŸ’αž…αžΌαž›αž‚αŸ’αž“αžΆαŸ” αž“αŸαŸ‡αž‡αžΆαž’αŸ’αžœαžΈαžŠαŸ‚αž›αž€αžΎαžαž‘αžΎαž„αŸ–

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

αž…αž»αž„αž€αŸ’αžšαŸ„αž™ αžαŸ„αŸ‡αž›αŸαž„!

αžœαžΆαžŠαž›αŸ‹αž–αŸαž›αž αžΎαž™αžŠαžΎαž˜αŸ’αž”αžΈαž”αžΎαž€αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž αŸ’αž‚αŸαž˜ αž αžΎαž™αžŸαžΆαž€αž›αŸ’αž”αž„αžœαžΆαž“αŸ…αž€αŸ’αž“αž»αž„αžŸαž€αž˜αŸ’αž˜αž—αžΆαž–αŸ” αžœαžΆαž›αž‚αž½αžšαžαŸ‚αž˜αžΎαž›αž‘αŸ…αžŠαžΌαž…αž“αŸαŸ‡αŸ–

"αžŠαž”αŸ‹αž”αŸ’αžšαžΆαŸ†" αž“αŸ…αž€αŸ’αž“αž»αž„ Java - αžšαž”αŸ€αž”αž”αž„αŸ’αž€αžΎαžαž αŸ’αž‚αŸαž˜αž–αŸαž‰αž›αž€αŸ’αžαžŽαŸˆ

αžαŸ„αŸ‡αž–αŸ’αž™αžΆαž™αžΆαž˜αžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž›αŸ’αž”αŸ‚αž„αž•αŸ’αž‚αž»αŸ†αžšαžΌαž”αŸ” αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αžœαžΈαŸ—αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž›αŸ’αž’ αž™αžΎαž„αž‘αž‘αž½αž›αž”αžΆαž“αŸ–

"αžŠαž”αŸ‹αž”αŸ’αžšαžΆαŸ†" αž“αŸ…αž€αŸ’αž“αž»αž„ Java - αžšαž”αŸ€αž”αž”αž„αŸ’αž€αžΎαžαž αŸ’αž‚αŸαž˜αž–αŸαž‰αž›αž€αŸ’αžαžŽαŸˆ

αž’αžŸαŸ‹αž αžΎαž™αŸ” αžαžΎαž’αŸ’αž“αž€αžšαŸ†αž–αžΉαž„αž…αŸ’αžšαžΎαž“αž‡αžΆαž„αž“αŸαŸ‡αž‘αŸ? πŸ™‚

Skillbox αžŽαŸ‚αž“αžΆαŸ†αŸ–

αž”αŸ’αžšαž—αž–: www.habr.com

αž”αž“αŸ’αžαŸ‚αž˜αž˜αžαž·αž™αŸ„αž”αž›αŸ‹