Προς το περιεχόμενο

Παιχνίδι 2048 σε C


johnny.tifosi

Προτεινόμενες αναρτήσεις

Αλήθεια, το είχα απορία από τη στιγμή που το "κουτούλησα" το enum στον κώδικα, αλλά το άφηνα για αργότερα.

 

Θα περίμενε κανείς τα sentinels να πηγαίνουν αναλογικά με το dim. Δεν πάει έτσι;

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

  • Απαντ. 272
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Συχνή συμμετοχή στο θέμα

Δημοσιευμένες Εικόνες

Κι εγώ έτσι νόμιζα, αλλά δεν πάει. Τα sentinels που έχω βάλει τα έχω πάρει αυτούσια από τις παραλλαγές που κάνω clone μέσα στο game (αυτές δηλαδή είχαν αυτά τα sentinels... δεν ξέρω με ποια λογική).

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Κι εγώ έτσι νόμιζα, αλλά δεν πάει. Τα sentinels που έχω βάλει τα έχω πάρει αυτούσια από τις παραλλαγές που κάνω clone μέσα στο game (αυτές δηλαδή είχαν αυτά τα sentinels... δεν ξέρω με ποια λογική).

Το 2048game.com τα έχει για κάποιο λόγο όπως τα δίνεις και εσύ. Θα περίμενε κανείς να υπάρχει μεγαλύτερο sentinel σε μεγαλύτερα boards για να κρατείται η δυσκολία σε ένα σταθερό επίπεδο αλλά όχι το 8x8 να έχει 16384 και το 5x5 να έχει 65536.

 

Δεν νομίζω πάντως ότι είναι set in stone κάποια τιμή. Αν γράψεις στο google "2048 5x5" θα δεις ότι ένα 80% των εκδόσεων κρατάνε το 2048 και οι υπόλοιπες έχουν είτε 4096 ή 8192 (που συμβαδίζει με τη λογική "λίγο μεγαλύτερο value για να διατηρώ την ίδια δυσκολία")

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημοσ. (επεξεργασμένο)

Κάνω αυτό το ποστ, για να διευκολύνω τον geomagas και όποιον άλλον θελήσει να φτιάξει αυτόνομο replay viewer (σε οποιαδήποτε γλώσσα, και με οποιοδήποτε tui/gui).

Το παρακάτω είναι ένα replay-file με 8 κινήσεις παιγμένες σε ταμπλό 5x5:

0
8:44 44 0 2 0@5 65536 1 21 0#0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 8 0 0 0 2 16 
7:44 44 0 4 2@5 65536 1 22 0#0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 8 0 0 0 0 16 
6:20 20 0 4 4@5 65536 1 21 1#0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 4 0 0 0 8 8 
5:8 8 0 2 4@5 65536 1 20 0#0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 2 4 0 0 4 8 
4:8 8 0 2 2@5 65536 1 21 0#0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 2 0 0 0 4 8 
3:8 8 0 2 2@5 65536 1 22 0#0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 2 0 0 0 0 8 
2:0 0 0 4 2@5 65536 1 22 1#0 0 0 0 0 0 0 0 0 2 0 0 0 0 4 0 0 0 0 4 0 0 0 0 0 
1:0 0 0 0 4@5 65536 1 23 0#0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 
NULL:
750 8 8
8:0 0 0 0 4@5 65536 1 23 0#0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 
7:0 0 0 4 2@5 65536 1 22 1#0 0 0 0 0 0 0 0 0 2 0 0 0 0 4 0 0 0 0 4 0 0 0 0 0 
6:8 8 0 2 2@5 65536 1 22 0#0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 2 0 0 0 0 8 
5:8 8 0 2 2@5 65536 1 21 0#0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 2 0 0 0 4 8 
4:8 8 0 2 4@5 65536 1 20 0#0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 2 4 0 0 4 8 
3:20 20 0 4 4@5 65536 1 21 1#0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 4 0 0 0 8 8 
2:44 44 0 4 2@5 65536 1 22 0#0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 8 0 0 0 0 16 
1:44 44 0 2 0@5 65536 1 21 0#0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 8 0 0 0 2 16

Επειδή στην πραγματικότητα τα replay-files είναι moves-history-files (για να λειτουργούν και ως load/save game) για απλή αναπαραγωγή του replay δεν χρειάζονται όλα τα περιεχόμενα του αρχείου. Στο συγκεκριμένο παράδειγμα χρειάζονται μονάχα οι γραμμές από την 11 και κάτω (συμπεριλαμβανομένης).

Θα εξηγήσω αναλυτικά και αυτόνομα από τον κώδικα, τι απεικονίζει η κάθε γραμμή από την 11 και κάτω, ώστε να μην χρειάζεται να διαβάζετε μακρινάρια δικού μου κώδικα προκειμένου να φτιάξετε δικό σας replay-viewer.

Πρέπει όπως να πω μερικά έξτρα για το πως να φτάσετε στη γραμμή 11. Θα τα πω περιληπτικά τώρα στην αρχή, να φεύγουν από την μέση.

Ουσιαστικά το κάθε replay-file είναι κάτι σαν log αρχείο όλων των κινήσεων, σε 3 μορφές: undo, redo και replay. Για replay viewer χρειάζoνται μονάχα οι κινήσεις του replay + τα meta-data τους (μια έξτρα γραμμή δηλαδή, ακριβώς πάνω από τις κινήσεις του replay).

Στο παραπάνω παράδειγμα, έχουμε:

  • Γραμμή [1]: έχει κάνει undo ο παίκτης; (0 = όχι)
  • Γραμμές [2-9]: λίστα Undo (8 κινήσεις),
  • Γραμμή [10]: λίστα Redo (δεν υπάρχουν κινήσεις)
  • Γραμμή [11]: Replay meta-data
  • Γραμμές [12-19] λίστα Replay (8 κινήσεις)

Meta-data κρατούνται μονάχα για τις κινήσεις του replay. Για Undo και Redo ΔΕΝ κρατούνται meta-data.

Αν κάποια από τις 3 λίστες είναι κενή, τότε αντί για λίστα γραμμών υπάρχει μια μόνο γραμμή, που λέει "NULL:\r\n" (όπως είναι η λίστα Redo στο παράδειγμα... τον χαρακτήρα ':' τον εξηγώ αργότερα, παρακάτω μαζί με τους '@' και '#').

Όταν μια λίστα δεν είναι κενή, άρα υπάρχει αντίστοιχη λίστα γραμμών στο αρχείο, τότε η 1η γραμμή αυτής της λίστας, έχει στην αρχή της το συνολικό πλήθος των κινήσεων.

Στο παράδειγμα, αυτό το νούμερο είναι το 8, και όπως βλέπουμε εμφανίζεται τόσο στην αρχή της 1ης γραμμής στη λίστα Undo, όσο και στην αρχή της 1ης γραμμής στη λίστα Replay.

Γνωρίζοντας αυτές τις πληροφορίες, ελπίζω να είναι πλέον εύκολο να κάνετε skip όλες τις περιττές γραμμές, μέχρι να φτάσετε στη γραμμή με τα meta-data του replay (δηλαδή στη γραμμή 11 στο παράδειγμα).

Ας δούμε τώρα αναλυτικά όλες τις γραμμές από την 11 και κάτω...

Γραμμή 11:
750 8 8\r\n

Το πρώτο νούμερο (το 750) είναι η καθυστέρηση σε milliseconds από την μια κίνηση στην άλλη αν ο χρήστης βάλει το replay να παίζει αυτόματα.

Το δεύτερο νούμερο (το 8) είναι το καταγεγραμμένο πλήθος κινήσεων μέσα στο replay. Με άλλα λόγια, μπορείτε να το χρησιμοποιήσετε ΚΑΙ ως ένδειξη για το πόσες γραμμές ακόμα χρειάζεται να διαβάσετε από το αρχείο.

Το τρίτο νούμερο (8 επίσης σε αυτό το παράδειγμα) σας είναι άχρηστο. Αγνοήστε το εντελώς (μάλλον κακώς το έχω βάλει να εμφανίζεται στα αρχεία).

Γραμμές 12-19:

Η κάθε μια από αυτές τις γραμμές, απεικονίζει μια παιγμένη κίνηση. Η κάθε κίνηση (κάθε γραμμή δηλαδή) περιέχει 4 ας τις πούμε κατηγορίες πληροφοριών, οι οποίες διαχωρίζονται μέσα στην γραμμή με 3 διαχωριστικούς χαρακτήρες :, @ και #

Ας πάρουμε για παράδειγμα τη γραμμή 12 (όλες οι υπόλοιπες ακολουθούν το ίδιο μοτίβο).
8:0 0 0 0 4@5 65536 1 23 0#0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0\r\n

8: Αυτός είναι ο αύξοντας-αριθμός της συγκεκριμένης κίνησης. Αυτό που χρειάζεται προσοχή εδώ είναι πως οι αύξοντες αριθμοί αφενός είναι 1-base, και κυρίως αφετέρου ότι εμφανίζονται με αντεστραμμένη σειρά συγκριτικά με την χρονολογική σειρά που παίχτηκαν οι κινήσεις από τον παίκτη.. Δηλαδή στην γραμμή 12 εμφανίζεται η 1η κίνηση που έπαιξε ο παίκτης (κι ας λέει 8 ο αύξοντας αριθμός της)..

EDIT: Τα παρακάτω που άλλαξα σε διαγραμμένα, δεν ισχύουν γενικώς, γιατί η λογική επιλογή σε έναν viewer είναι να χρησιμοποιηθεί array και όχι στοίβα για τις κινήσεις, οπότε με array ξέρετε ανά πάσα στιγμή ποια κίνηση προβάλλετε.

Για να τυπώσετε λοιπόν μέσα στον viewer σας τον σωστό αριθμό της εκάστοτε τρέχουσας κίνησης, πρέπει πρώτα να έχετε κρατήσει σε μια μεταβλητή το πλήθος των καταγεγραμμένων κινήσεων, από τη γραμμή 11 (το 2ο νούμερο της γραμμής 11).

Αν έχετε ονομάσει αυτή τη μεταβλητή ας πούμε: nmoves, και τους αύξοντες αριθμούς τους κρατάτε μέσα στο loop των κινήσεων ας πούμε σε μια μεταβλητή: aa, τότε ο αριθμός της εκάστοτε κίνησης υπολογίζεται με απλή αριθμητική: nmoves - aa + 1


(δείτε και το spoiler που ακολουθεί).

Απολογούμαι για αυτή την "ασυνέπεια", αλλά έχει να κάνει με το ότι εγώ τις κινήσεις τις διαχειρίζομαι ως στοίβες, που είναι first-in-last-out, και πως δεν κρατάω μονάχα την στοίβα του replay αλλά και των undo & redo. Και τις διαχειρίζομαι όλες με κοινό interface. Εγώ μάλιστα δεν "τραβάω" το πλήθος των κινήσεων από την γραμμή 11, αλλά απευθείας από την γραμμή 12 (και μετά χρησιμοποιώ κι εκείνο το νούμερο που σας είπα πως σας είναι άχρηστο στη γραμμή 11, προκειμένου να εμφανίζω τον τρέχοντα αριθμό κίνησης... μη σας μπλέκω όμως με άλλο με αυτό).


0 0 0 0 4@ (gamestate meta-data):

Το πρώτο νούμερο (0 εδώ) είναι το σκορ που είχε σε αυτή την κίνηση ο παίκτης.

Το δεύτερο νούμερο (επίσης 0 εδώ) είναι το καλύτερο-σκορ (best-score) του ταμπλό εκείνη τη στιγμή.

Το 3ο νούμερο (επίσης 0 εδώ) είναι boolean και δηλώνει αν σε αυτή την κίνηση ο παίκτης νίκησε (αν έφτασε δηλαδή στο sentinel tile). Λογικά δεν σας ενδιαφέρει αυτή η πληροφορία (εγώ την χρησιμοποιώ ώστε αν έχει νικήσει, και βγει από replay-mode σε normal-mode να μην τον αφήνω να συνεχίσει να παίζει σε αυτό το ταμπλό).

Τα επόμενα δυο νούμερα (0 και 4 εδώ) είναι τα enumerated values που δηλώνουν ποια ήταν η προηγούμενη κίνηση και ποια θα είναι η επόμενη. Όλες οι enumerated τιμές είναι οι εξής:

enum {  /* GameState direction of next & previous moves */
	GS_MVDIR_NONE  = 0,
	GS_MVDIR_UP    = 1,
	GS_MVDIR_DOWN  = 2,
	GS_MVDIR_LEFT  = 3,
	GS_MVDIR_RIGHT = 4
};

Άρα λοιπόν, για τη γραμμή 12 τα νούμερα αυτά μας λένε πως δεν υπήρχε προηγούμενη κίνηση (0) και πως η επόμενη κίνηση ήταν προς τα δεξιά (4).

5 65536 1 23 0# (board-meta-data):

Το πρώτο νούμερο (5) είναι η διάσταση του τετράγωνου ταμπλό. Είχαμε δηλαδή ταμπλό 5x5.

Το δεύτερο νούμερο (65536) είναι το sentinel value της νίκης. Δηλαδή ο παίκτης κερδίζει αν πιάσει tile με τιμή 65536.

Το τρίτο νούμερο (1) είναι το πλήθος των τυχαίων tiles που δημιουργούνται μετά από κάθε επιτυχημένη κίνηση στο ταμπλό (το οποίο είναι διπλάσιο στην αυτόματα παιγμένη από το game 1η κίνηση).

Το τέταρτο νούμερο (23) είναι πόσες κενές θέσεις υπήρχαν στο ταμπλό.

Το πέμπτο νούμερο (0) είναι boolean και δηλώνει αν στο ταμπλό υπήρχαν γειτονικά tiles με ίσες, μη-μηδενικές τιμές.

0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0\r\n (tile values):

Στο τέλος της γραμμής έχουμε τις τιμές των tiles σε όλο το ταμπλό. Υπάρχουν 25 τιμές, μιας και το ταμπλό είναι 5x5. Αν στον viewer δεν θέλετε να χρησιμοποιήσετε μονοκόμματο buffer, αλλά 2Δ, τότε σημειώστε πως οι παραπάνω τιμές είναι serialized με row-major order.

Για να μετατρέψετε τη θέση του εκάστοτε tile (ας την πούμε n) από 1Δ στο αρχείο, σε 2Δ θέση (i,j) για το δικό σας buffer, μπορείτε να χρησιμοποιήσετε τους ακόλουθους τύπους:

i = n / ncols
j = n % ncols 

όπου ncols είναι η μονή διάσταση του τετράγωνου ταμπλό, δηλαδή στο δικό μας παράδειγμα το ncols ισούται με 5.

Για την ανάποδη μετατροπή (αν τη χρειαστείτε) μπορείτε να χρησιμοποιήστε τον τύπο:

n = i * ncols + j

Τέλος, όπως έχουμε αναφέρει και σε άλλα ποστς, ΟΛΕΣ οι γραμμές στα replay-files τελειώνουν ΠΑΝΤΑ σε \r\n

Ελπίζω να μη μου ξέφυγε κάτι, και να μπορείτε πλέον να φτιάξετε αυτόνομους replay-viewers σε οποιαδήποτε γλώσσα και με οποιοδήποτε tui/gui χωρίς να χρειάζεται καν να διαβάσετε τον ήδη υπάρχοντα κώδικα.

@imitheos:

Εγώ στην αρχή είχα σκεφτεί να δίνω στον παίκτη την επιλογή να ορίζει αυτός ποιο θέλει να είναι το sentinel-value (προφανώς μέσα σε κάποια όρια), ώστε να λειτουργεί κάπως σαν επιλογή βαθμού δυσκολίας.

Επειδή όμως όταν ξεκίνησα είχα πάρα πολύ λιγότερο ελεύθερο χρόνο, και το παραπάνω ήθελε έξτρα δουλειά, το πήγα πιο... safe και έκανα clone ακριβώς τη συμπεριφορά των 3 παραλλαγών που ενσωμάτωσα στο game.

Εννοείται πως δεν είμαστε υποχρεωμένοι να το συνεχίσουμε έτσι. Γενικώς μπορούμε να υλοποιήσουμε ότι θεωρούμε καλύτερο. Δεν έχω κανένα πρόβλημα εγώ... το αντίθετο, αυτός ήταν κι ο λόγος που είπαμε να το βάλουμε στο github :)

EDIT:

Btw, υπάρχει κι ένα pending pull-request με διορθωμένα κάποια typos, βελτιωμένο README.md (π.χ. με άλλαξα από "author" σε "initial author" κι έφτιαξα λίγο καλύτερο markdown) κι ελαφρώς τροποποιημένη την άδεια (έβγαλα εκείνο που έλεγε να επικοινωνήσουν μαζί μου αν μπλα-μπλα).

Υποθέτω θα ειδοποιήσει ο geomagas όταν το κάνει merge.

Επεξ/σία από migf1
  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Επειδή όμως όταν ξεκίνησα είχα πάρα πολύ λιγότερο ελεύθερο χρόνο, και το παραπάνω ήθελε έξτρα δουλειά, το πήγα πιο... safe και έκανα clone ακριβώς τη συμπεριφορά των 3 παραλλαγών που ενσωμάτωσα στο game.

 

Εννοείται πως δεν είμαστε υποχρεωμένοι να το συνεχίσουμε έτσι. Γενικώς μπορούμε να υλοποιήσουμε ότι θεωρούμε καλύτερο. Δεν έχω κανένα πρόβλημα εγώ... το αντίθετο, αυτός ήταν κι ο λόγος που είπαμε να το βάλουμε στο github :)

Το ότι πολλοί το έχουν κρατήσει 2048 δεν το ανέφερα επικριτικά με στυλ "κοίτα τι βλακείες έγραψες" απλά σαν γεγονός ότι η επικρατέστερη άποψη είναι ίδιο value ανεξάρτητα από board (το οποίο πολύ πιθανώς είναι λάθος απλά διατηρήθηκε ίδιο από αμέλεια του εκάστοτε developer). Η "επίσημη" υλοποίηση άλλωστε το έχει όπως εσύ. Δεν έχω άποψη για το πως θα ήταν καλύτερο να γίνει.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Κάνω αυτό το ποστ, για να διευκολύνω τον geomagas και όποιον άλλον θελήσει να φτιάξει αυτόνομο replay viewer (σε οποιαδήποτε γλώσσα, και με οποιοδήποτε tui/gui).

 

Χεχε! Σε πρόλαβα! :P

Εντάξει, τα saves είναι αρκετά straightforward αν τα ανοίξει κανείς και τα κοιτάξει. Τα νούμερα μιλούν από μόνα τους. Για μένα, η κρίσιμη διευκρίνηση ήταν αυτή του προηγούμενου post σου, σχετικά με τις stacks που πρέπει να "πετάξεις".

 

Ο replayer που έλεγα έχει αρχίσει να παίρνει σχήμα εδώ, αλλά είναι ακόμα εργοτάξιο, οπότε επιφυλάσσομαι για να ζητήσω σχόλια. Ακόμα κι η διαδικασία που διαβάζει τα saves (php) είναι όσο πιο quick'n'dirty γίνεται:

$sav=array();
foreach(glob(__DIR__.'/replays/*.sav') as $s)
    $sav[basename($s,".sav")]=$s;
    
function skip_stack(&$data)
    {
    if('NULL:'==$data[0])
        array_shift($data);
    else
        {
        list($n,)=explode(':',$data[0]);
        array_splice($data,0,$n);
        }
    }
    
function sav2json($file)
    {
    header('Content-Type: application/json; charset=utf-8');
    global $sav;
    if($data=file($sav[$file],FILE_IGNORE_NEW_LINES))
        {
        array_shift($data); // discard first line
        skip_stack($data); // skip undo stack
        skip_stack($data); // skip redo stack
        $meta=explode(' ',array_shift($data)); // discard metadata?
        $ret=array(
            'states'=>array(),
            );
        foreach($data as $line)
            {
            list(,$payload)=explode('@',$line);
            list($rmeta,$values)=explode('#',$payload);
            $ret['states'][]=explode(' ',$values);
            }
        list($ret['dim'],)=explode(' ',$rmeta);
        echo json_encode($ret);
        }
    else
        header('HTTP/1.0 404 Not Found');
    exit;
    }

Btw, υπάρχει κι ένα pending pull-request με διορθωμένα κάποια typos, βελτιωμένο README.md (π.χ. με άλλαξα από "author" σε "initial author" κι έφτιαξα λίγο καλύτερο markdown) κι ελαφρώς τροποποιημένη την άδεια (έβγαλα εκείνο που έλεγε να επικοινωνήσουν μαζί μου αν μπλα-μπλα).

 

Υποθέτω θα ειδοποιήσει ο geomagas όταν το κάνει merge.

 

Το έκανε, αλλά πουουουου μυαλό να ειδοποιήσει... :-)

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Για εργοτάξιο παρά πάνω από μια χαρά μου φαίνεται εμένα! Ωραίος :)

 

θα μπορούσες όμως να μου εξηγήσεις τι πλεονέκτημα δίνει το 2^n map έναντι του όπως είναι τώρα;

 

Διότι σήμερα που το σκέφτομαι με καθαρό μυαλό, αφενός το x += x έναντι του x = map[x]++ δεν νομίζω πως υστερεί σε ταχύτητα (μάλλον υπερτερεί, αλλά γενικώς δεν νομίζω πως στο συγκεκριμένο game τίθεται θέμα ταχύτητας σε τέτοιο επίπεδο, γιατί είναι πολύ λίγα τα data του board), κι αφετέρου και όπως είναι τώρα μπορούν να γίνουν mapped τα tile values σε κάτι άλλο (image-fnames, γράμματα, κλπ).

 

Τί μου διαφεύγει;

 

@imitheos: Δεν το εξέλεβα ως επικριτικό το ποστ σου ρε συ.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

θα μπορούσες όμως να μου εξηγήσεις τι πλεονέκτημα δίνει το 2^n map έναντι του όπως είναι τώρα;

 

Διότι σήμερα που το σκέφτομαι με καθαρό μυαλό, αφενός το x += x έναντι του x = map[x]++ δεν νομίζω πως υστερεί σε ταχύτητα (μάλλον υπερτερεί, αλλά γενικώς δεν νομίζω πως στο συγκεκριμένο game τίθεται θέμα ταχύτητας σε τέτοιο επίπεδο, γιατί είναι πολύ λίγα τα data του board), κι αφετέρου και όπως είναι τώρα μπορούν να γίνουν mapped τα tile values σε κάτι άλλο (image-fnames, γράμματα, κλπ).

 

Τί μου διαφεύγει;

 

Όπως είπα και πριν, η διαφορά στην ταχύτητα δεν είναι σημαντική, και οπωσδήποτε όχι κατά το gameplay (ίσως μόνο κατά τον υπολογισμό ενός μεγάλου δένδρου καταστάσεων, για το ai). Το όλο concept αφορά το πιθανό normalization των τιμών των tiles σε κάτι πιο "ουδέτερο" από τις δυνάμεις του 2. Το οποίο είναι και πιο εύκολο να χρησιμοποιηθεί σαν index σε πίνακες.

 

Κατά τα άλλα, για τον υπολογισμό της τιμής, δεν τίθεται θέμα σύγκρισης του x+=x  με το x=map[x]++, αλλά πχ του x+=x[i+1] με το x++.

 

Και βέβαια όπως είναι τώρα μπορεί να γίνει map σε οτιδήποτε, αλλά για παράδειγμα στον replayer που είδες, και επειδή στα "themes" αποφάσισα να χρησιμοποιήσω arrays που με βολεύουν καλύτερα, για να το πετύχω με τις τιμές που περιέχουν τα replay files κάνω αυτό:

            value=parseInt(state[i*dim+j]);
            value=value?Math.log(value)/Math.LN2:0; // normalize!

Και βέβαια θα μπορούσα να κάνω τον μετασχηματισμό στον server ώστε να μη χρειάζεται να γίνεται "συνέχεια", και βέβαια θα μπορούσα να μη χρησιμποιήσω arrays κλπ κλπ, απλά θεωρώ ότι μια πιο normalized (έτσι την ονόμασα προβοκατόρικα :P ) εκδοχή θα βόλευε καλύτερα καθώς δίνει την ευκαιρία για απλοποιήσεις στον κώδικα και για εύκολες επεκτάσεις.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Καλημέρα,

 

εξακολουθώ να μην το πιάνω το πλεονέκτημα :(

Ίσα-ίσα που βλέπω ένα extra-step για normalization πριν γίνει mapped η τιμή του tile-value σε κάτι άλλο (image-fname, letter, κλπ).

 

ΥΓ. Μόλις άλλαξα τα x += x[i+1]; σε x += x; στο board.c :P

 

EDIT:

 

Για τα arrays vs stacks στον viewer, δεν το συζητάμε πως τα arrays είναι "the way to go"! Και μάλιστα κακώς λέω στο προηγούμενο ποστ πως για να εμφανιστεί το σωστό move-count πρέπει να χρησιμοποιηθεί nmoves - aa + 1 (παω να το διορθώσω... αν με αφήσει)... αυτό είναι stack specific πράγμα που αναγκάστηκα να κάνω μόνο εγώ στο πλήρες games, επειδή εκεί είναι όλα στοίβες.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Καλημέρα,

 

εξακολουθώ να μην το πιάνω το πλεονέκτημα :(

Ίσα-ίσα που βλέπω ένα extra-step για normalization πριν γίνει mapped η τιμή του tile-value σε κάτι άλλο (image-fname, letter, κλπ).

 

Ε ναι, αυτό λέω, ότι δεν θα χρειαζόταν το extra step αν η λογική ήταν ήδη "normalized"...

Αλλά άστο, ούτως ή άλλως δεν ήταν σημαντικό, και το συζητάμε άλλη στιγμή αν προκύψει.

 

ΥΓ. Μόλις άλλαξα τα x += x[i+1]; σε x += x; στο board.c :P

optimization++

  :D

 

EDIT: Επειδή το πρωί έχω τις πιο "κουλές" ιδέες, δεν το κάνεις x*=2 καλύτερα;

Που ξέρεις, μπορεί ο compiler να είναι αρκετά έξυπνος και να το μεταφράσει τελικά σε καμιά SHL! :P

 

EDIT:

 

Για τα arrays vs stacks στον viewer, δεν το συζητάμε πως τα arrays είναι "the way to go"! Και μάλιστα κακώς λέω στο προηγούμενο ποστ πως για να εμφανιστεί το σωστό move-count πρέπει να χρησιμοποιηθεί nmoves - aa + 1 (παω να το διορθώσω... αν με αφήσει)... αυτό είναι stack specific πράγμα που αναγκάστηκα να κάνω μόνο εγώ στο πλήρες games, επειδή εκεί είναι όλα στοίβες.

 

arrays vs stacks? Χάθηκα λίγο τώρα...

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ε ναι, αυτό λέω, ότι δεν θα χρειαζόταν το extra step αν η λογική ήταν ήδη "normalized"...

Αλλά άστο, ούτως ή άλλως δεν ήταν σημαντικό, και το συζητάμε άλλη στιγμή αν προκύψει.

 

Τότε θα έχουμε το ανάποδο για την πλειοψηφία των περιπτώσεων (όταν δηλαδή προβάλλουμε δυνάμεις 2^n αριθμούς στο ταμπλό). Το extra-step σε αυτές τις περιπτώσεις είναι πως πρέπει να υψώσεις το 2 στη δύναμη που υποδεικνύει η εσωτερικά "normalized" τιμή.

 

Για τις υπόλοιπες, λιγότερες περιπτώσεις (όταν π.χ. θέλουμε να προβάλλουμε εικόνες, γράμματα, κλπ αντί για τα νορμάλ νούμερα) τότε είτε κρατάμε "normalized" τις τιμές είτε όχι, θα κάνουμε την αντιστοίχιση έτσι κι αλλιώς :)

 

optimization++
  :D

 

 

arrays vs stacks? Χάθηκα λίγο τώρα...

 

 

Εννοώ αυτό που έγραψες κι εσύ. Πως δηλαδή στον viewer δεν υπάρχει απολύτως κανένας λόγος να φορτωθούν οι κινήσεις σε στοίβα. Η προφανής και λογική επιλογή είναι να φορτωθούν σε πίνακα. Όπως έχεις ήδη κάνει δηλαδή στον viewer.

 

EDIT: Επειδή το πρωί έχω τις πιο "κουλές" ιδέες, δεν το κάνεις x*=2 καλύτερα;

Που ξέρεις, μπορεί ο compiler να είναι αρκετά έξυπνος και να το μεταφράσει τελικά σε καμιά SHL! :P

 

:lol: Θα μας κλείσουν στο Δρομοκαΐτειο στο τέλος :lol:

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Εννοώ αυτό που έγραψες κι εσύ. Πως δηλαδή στον viewer δεν υπάρχει απολύτως κανένας λόγος να φορτωθούν οι κινήσεις σε στοίβα. Η προφανής και λογική επιλογή είναι να φορτωθούν σε πίνακα. Όπως έχεις ήδη κάνει δηλαδή στον viewer.

 

Δεν θυμάμαι να έγραψα κάτι τέτοιο. Αλλά οκ, κατάλαβα πως το εννοείς.

 

EDIT: Αν αναφερόσουν σε αυτό

...σχετικά με τις stacks που πρέπει να "πετάξεις".

εννοούσα τις redo/undo stacks που πρέπει να αγνοήσεις από την αρχή του .sav.

 

:lol: Θα μας κλείσουν στο Δρομοκαΐτειο στο τέλος :lol:

Γιατί ρε συ; Παιδιά είμαστε και παίζουμε! Που είναι το κακό;

 

baby-dinosaurs-23131708.jpg

 

Άσε που δεν νομίζω να έχει χώρο εκεί μέσα... Κρίνοντας από το "απ' έξω", λογικά "από μέσα" πρέπει να είναι full!

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα

  • Δημιουργία νέου...