Programmēšana

Dambrete, kāds?

Pirms vairākiem mēnešiem man tika lūgts izveidot nelielu Java bibliotēku, kurai var piekļūt lietojumprogramma, lai padarītu grafisko lietotāja saskarni (GUI) Dambretes spēlei. Līdztekus dambretes un dambretes renderēšanai GUI jāļauj pārbaudītāju vilkt no viena laukuma uz otru. Arī pārbaudītājam jābūt centrētam uz laukumu, un to nedrīkst piešķirt laukumam, kuru aizņem cits pārbaudītājs. Šajā ierakstā es iepazīstinu ar savu bibliotēku.

Dāmu GUI bibliotēkas projektēšana

Kādus sabiedriskos veidus bibliotēkai vajadzētu atbalstīt? Dambretē katrs no diviem spēlētājiem pārmaiņus pārvieto vienu no saviem parastajiem (ārpus karaļa) dambretēm pāri bortam tikai uz priekšu un, iespējams, pārlec otra spēlētāja (-u) pārbaudītāju (-us). Kad pārbaudītājs nonāk otrā pusē, tas tiek paaugstināts par karali, kurš var pārvietoties arī atpakaļ. No šī apraksta mēs varam secināt šādus veidus:

  • Valde
  • Pārbaudītājs
  • CheckerType
  • Spēlētājs

A Valde objekts identificē dambreti. Tas kalpo kā trauks Pārbaudītājs objekti, kas aizņem dažādus laukumus. Tā var piesaistīt sevi un pieprasīt, lai katrs no tiem tiktu ietverts Pārbaudītājs objektu izdarīt pats.

A Pārbaudītājs objekts identificē pārbaudītāju. Tam ir krāsa un norāde, vai tas ir parasts pārbaudītājs vai karalis pārbaudītājs. Tas var izdarīt pats un padara tā lielumu pieejamu Valde, kuras lielumu ietekmē Pārbaudītājs Izmērs.

CheckerType ir uzskaitījums, kas nosaka pārbaudītāja krāsu un veidu, izmantojot četras konstantes: BLACK_KING, BLACK_REGULAR, RED_KING, un RED_REGULAR.

A Spēlētājs object ir kontrolieris pārbaudītāja pārvietošanai ar izvēles lēcieniem. Tā kā esmu izvēlējies šo spēli ieviest Swing, Spēlētājs nav nepieciešams. Tā vietā esmu pagriezies Valde šūpoles komponentā, kura konstruktors reģistrē peles un peles kustības klausītājus, kuri cilvēka atskaņotāja vārdā apstrādā pārbaudītāja kustību. Nākotnē es varētu ieviest datora atskaņotāju, izmantojot citu pavedienu, sinhronizatoru un citu Valde metode (piemēram, pārvietot()).

Ko dara publiskās API Valde un Pārbaudītājs dot ieguldījumu? Pēc nelielām pārdomām es nācu klajā ar šādu sabiedrību Valde API:

  • Dēlis (): Konstruēt a Valde objekts. Konstruktors veic dažādus inicializācijas uzdevumus, piemēram, klausītāja reģistrāciju.
  • void add (Pārbaudītāja pārbaudītājs, int rinda, int kolonna): Pievienot pārbaudītājs uz Valde pozīcijā, kuru identificējis rinda un kolonna. Rindas un kolonnas ir vērtības, kuru pamatā ir 1, nevis vērtības 0 (sk. 1. attēlu). The pievienot () metieni java.lang.IllegalArgumentException kad tā rindas vai kolonnas arguments ir mazāks par 1 vai lielāks par 8. Turklāt tas iemet nepārbaudīto AlreadyOccupiedException kad mēģināt pievienot a Pārbaudītājs uz aizņemtu laukumu.
  • Dimensija getPreferredSize (): Atgrieziet Valde komponenta vēlamais izmērs izkārtojuma vajadzībām.

1. attēls. Rūtis augšējā kreisajā stūrī atrodas (1, 1)

Es arī izstrādāju šādu sabiedrību Pārbaudītājs API:

  • Pārbaudītājs (CheckerType checkerType): Konstruēt a Pārbaudītājs norādītā objekta checkerType (BLACK_KING, BLACK_REGULAR, RED_KINGvai RED_REGULAR).
  • void draw (grafika g, int cx, int cy): Zīmējiet a Pārbaudītājs izmantojot norādīto grafikas kontekstu g ar pārbaudītāja centru, kas atrodas (cx, cy). Šo metodi paredzēts izsaukt no Valde tikai.
  • Boolean satur (int x, int y, int cx, int cy): A statisks palīga metode izsaukta no Valde kas nosaka, vai peles koordinātas (x, y) atrodas pārbaudītājā, kuras centra koordinātas norāda (cx, cy) un kuru dimensija ir norādīta citur Pārbaudītājs klasē.
  • int getDimension (): A statisks palīga metode izsaukta no Valde kas nosaka pārbaudītāja izmēru, lai dēlis varētu atbilstoši izmērīt kvadrātu un kopējo izmēru.

Tas diezgan lielā mērā aptver visu dambretes GUI bibliotēku, ņemot vērā tā veidus un publiskās API. Tagad mēs pievērsīsimies tam, kā es ieviesu šo bibliotēku.

Dambretes GUI bibliotēkas ieviešana

Dambretes GUI bibliotēka sastāv no četriem publiskiem veidiem, kas atrodas tā paša nosauktajos avota failos: AlreadyOccupiedException, Valde, Pārbaudītājs, un CheckerType. Uzskaitot 1 dāvanas AlreadyOccupiedExceptionavota kods.

Saraksts 1. JauOccupiedException.java

publiskā klase AlreadyOccupiedException paplašina RuntimeException {public AlreadyOccupiedException (virkne msg) {super (msg); }}

AlreadyOccupiedException pagarina java.lang.RuntimeException, kas padara AlreadyOccupiedException nepārbaudīts izņēmums (tas nav jānoķer vai jādeklarē metieni klauzula). Ja es gribētu uztaisīt AlreadyOccupiedException pārbaudīts, es būtu pagarinājis java.lang. Izņēmums. Es izvēlējos padarīt šo veidu nepārbaudītu, jo tas darbojas līdzīgi kā nepārbaudīts NelegālsArgumentException.

AlreadyOccupiedException paziņo konstruktors, kurš ņem virknes argumentu, aprakstot izņēmuma iemeslu. Šis arguments tiek nosūtīts RuntimeException superklase.

Sarakstā 2 dāvanas Valde.

2. saraksts. Board.java

importēt java.awt.Color; importēt java.awt.Dimension; importēt java.awt.Grafika; importēt java.awt.Graphics2D; importēt java.awt.RenderingHints; importēt java.awt.event.MouseEvent; importēt java.awt.event.MouseAdapter; importēt java.awt.event.MouseMotionAdapter; importēt java.util.ArrayList; importēt java.util.List; importēt javax.swing.JComponent; publiskās klases dēlis paplašina JComponent {// dambretes kvadrāta izmēru (par 25% lielāks nekā pārbaudītājs) privātā galīgā statiskā int SQUAREDIM = (int) (Checker.getDimension () * 1,25); // dambretes izmērs (8 kvadrātu platums) privātais fināls int BOARDDIM = 8 * SQUAREDIM; // vēlamais Board komponentes privātā Dimension dimPrefSize izmērs; // vilkšanas karodziņš - iestatīts uz true, kad lietotājs nospiež peles pogu virs pārbaudītāja // un tiek notīrīts uz false, kad lietotājs atbrīvo peles pogas privāto boolean inDrag = false; // nobīde starp vilkšanas sākuma koordinātām un pārbaudītāja centra koordinātām private int deltax, deltay; // atsauce uz novietoto pārbaudītāju vilkšanas privātā PosCheck posCheck sākumā; // pārbaudītāja centrālā atrašanās vieta vilkšanas sākumā private int oldcx, oldcy; // Checker objektu un to sākotnējo pozīciju saraksts private List posChecks; publiskā padome () {posChecks = new ArrayList (); dimPrefSize = jauna dimensija (BOARDDIM, BOARDDIM); addMouseListener (new MouseAdapter () {@Orride public void mousePressed (MouseEvent me) {// Iegūstiet peles koordinātas nospiešanas laikā. int x = me.getX (); int y = me.getY (); // Atrodiet novietoto pārbaudītāju zem peles nospiešanas. (PosCheck posCheck: posChecks), ja (Checker.contains (x, y, posCheck.cx, posCheck.cy)) {Board.this.posCheck = posCheck; oldcx = posCheck.cx; oldcy = posCheck.cy ; deltax = x - posCheck.cx; deltay = y - posCheck.cy; inDrag = true; return;}} @Override public void mouseReleased (MouseEvent me) {// Kad pele ir atlaista, notīriet inDrag (to // norāda, ka nav vilkšanas notiek), ja inDrag ir // jau iestatīts. if (inDrag) inDrag = false; else return; // Ievietojiet pārbaudītāju kvadrāta centrā. int x = me.getX (); int y = me.getY (); posCheck .cx = (x - deltax) / SQUAREDIM * SQUAREDIM + SQUAREDIM / 2; posCheck.cy = (y - delta) / SQUAREDIM * SQUAREDIM + SQUAREDIM / 2; // Nepārvietojiet pārbaudītāju uz aizņemta laukuma. Par (PosCheck posCheck : posChecks) if (posCheck! = Board.this.posCheck && posC heck.cx == Board.this.posCheck.cx && posCheck.cy == Board.this.posCheck.cy) {Board.this.posCheck.cx = oldcx; Board.this.posCheck.cy = vecais; } posCheck = null; pārkrāsot (); }}); // Pievienojiet sīklietotnei peles kustības klausītāju. Šis klausītājs klausās // peles vilkšanas notikumus. addMouseMotionListener (jauns MouseMotionAdapter () {@Override public void mouseDragged (MouseEvent me) {if (inDrag) {// Atjaunināt pārbaudītāja centra atrašanās vietu. posCheck.cx = me.getX () - deltax; posCheck.cy = me.getY ( ) - delta; pārkrāsot ();}}}); } public void add (Pārbaudītāja pārbaudītājs, int rinda, int kol) {if (8. rinda) mest jaunu IllegalArgumentException ("rinda ārpus diapazona:" + rinda); ja (8. sleja) mest jaunu IllegalArgumentException ("kolonna ārpus diapazona:" + kol); PosCheck posCheck = new PosCheck (); posCheck.checker = pārbaudītājs; posCheck.cx = (kolonna - 1) * SQUAREDIM + SQUAREDIM / 2; posCheck.cy = (1. rinda) * SQUAREDIM + SQUAREDIM / 2; for (PosCheck _posCheck: posChecks) ja (posCheck.cx == _posCheck.cx && posCheck.cy == _posCheck.cy) mest jaunu AlreadyOccupiedException ("kvadrāts pie (" + rinda + "," + col + ") ir aizņemts" ); posChecks.add (posCheck); } @Orride public Dimension getPreferredSize () {return dimPrefSize; } @ Pārvarēt aizsargāto tukšo paintComponent (grafika g) {paintCheckerBoard (g); par (PosCheck posCheck: posChecks) if (posCheck! = Board.this.posCheck) posCheck.checker.draw (g, posCheck.cx, posCheck.cy); // Velciet pārbaudītāju pēdējam, lai tas tiktu parādīts virs jebkura pārbaudītāja //. if (posCheck! = null) posCheck.checker.draw (g, posCheck.cx, posCheck.cy); } private void paintCheckerBoard (Graphics g) {((Graphics2D) g) .setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Krāsu dambrete. par (int rinda = 0; rinda <8; rinda ++) {g.setColor ((((1. rinda)! = 0)? Krāsa.BLACK: Krāsa.WHITE); for (int col = 0; col <8; col ++) {g.fillRect (col * SQUAREDIM, rinda * SQUAREDIM, SQUAREDIM, SQUAREDIM); g.setColor ((g.getColor () == Color.BLACK)? Color.WHITE: Color.BLACK); }}} // novietota pārbaudītāja palīgs klases privātā klase PosCheck {publiskā pārbaudītāja pārbaudītājs; public int cx; publiska int cija; }}

Valde pagarina javax.swing.JKomponents, kas padara Valde a šūpoles sastāvdaļa. Kā tādu jūs varat tieši pievienot a Valde komponentu Swing lietojumprogrammas satura rūtī.

Valde paziņo SQUAREDIM un BOARDDIM konstantes, kas identificē kvadrāta un izvēles rūtiņas pikseļu izmērus. Inicializējot SQUAREDIM, Es piesaucu Checker.getDimension () tā vietā, lai piekļūtu līdzvērtīgai publikai Pārbaudītājs nemainīgs. Džošua Bloks atbild, kāpēc es to daru 30. pozīcijā (izmantojiet enums nevis int konstantes) viņa grāmatas otrajā izdevumā, Efektīva Java: "Programmas, kurās tiek izmantots int enum raksts ir trausls. Tā kā int enums ir kompilēšanas laika konstantes, tās tiek apkopotas klientos, kuri tās izmanto. Ja int kas saistīts ar uzskaites konstanti, tā klienti ir jākompilē. Ja tā nav, viņi joprojām darbosies, taču viņu uzvedība būs nedefinēta. "

Plašo komentāru dēļ man nav daudz ko vairāk teikt Valde. Tomēr ņemiet vērā ligzdoto PosCheck klase, kurā aprakstīts novietots pārbaudītājs, saglabājot a Pārbaudītājs atskaite un tās centra koordinātas, kas ir attiecībā pret augšējo kreiso stūri Valde komponents. Pievienojot Pārbaudītājs iebilst pret Valde, tas tiek glabāts jaunā PosCheck objekts kopā ar pārbaudītāja centra stāvokli, kas tiek aprēķināts no norādītās rindas un kolonnas.

Uzskaitot 3 dāvanas Pārbaudītājs.