Multileval data structures, tie, and indirection

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Da-Breegster

    Multileval data structures, tie, and indirection

    Hi. I'm attempting to write a roguelike (think nethack, crawl, angband,
    tome, adom, and yes, I suppose even rogue) in Perl and I've ran into a
    problem regarding the data structure for the map and handling it easily.
    A map is one 2D level, a simple grid. Each tile on the grid will be a
    hash of data about the grid. The map object itself has other bits of
    data, so that's why I don't just make the object an anonymous array:

    $map->{Map}[$y][$x] = { data about this grid tile }

    So far, so good. I was using methods to access and change tiles, but it
    was extremely awkward. Which looks more convenient?

    $map->tile($y, $x, "Type") = "wall";
    $map->{Map}[$y][$x]{Type} = "wall";

    Well, bad example. But anyway, I seriously despised the first form. The
    syntax itself is extremely awkward and when I generate random dungeons,
    I'd have to use that awkward syntax a lot. So I messed around with
    Tie::Autotie, decided it wasn't up to the task, and cobbled together a
    package that I tied both anonymous arrays (The first representing rows,
    pointing to the second which represented columns. Y, X is easier to deal
    with sometimes.) to. The hash of data describing a tile consists of
    different things, but for the most part, I'd by modifying and accessing
    one key in the hash. Now I'm at the point where I can do this:

    print $map->{Map}[$y][$x]; # $map->{Map}[$y][$x]{Symbol} is printed,
    # through FETCH
    $map->{Map}[$y][$x] = "wall"; # This basically sets
    # $map->{Map}[$y][$x]{Type} to a hashref
    # describing a template of that type.

    Convenient and easy, so far. Then I run into the first problem. What if
    I want to access or change $map->{Map}[$y][$x]{foobar}? The way I tied
    the arrays didn't allow for this. So I hacked together a real messy
    sort of hack, which is shown somewhere below. So far, I'm coping with
    the shortcomings of tie.

    But then I realized that when I assign a tile to "wall", other things
    should happen. Things regarding the $map object itself. Meaning that I
    need a reference to $map, as well as the value of $y. From the 'point of
    view' of $x's tied FETCH routine, I cannot access these.

    I know Perl, each time it encounters a tied variable that's part of a
    multi-level structure, it'll take a temp value and do something with
    that. Step by step. It's impossible to tie an entire data structure to
    where one FETCH routine could know $map, $y, and $x.

    Then I realized something. I was trying to re-implement the Unix
    directory structure, complete with a level of indirection that more or
    less happened to be '..'

    I suppose I could replace the arrays with hashes, and instead do
    $map->{Map}{$y}{$x }. In the $y hash and the $x hash (technically
    inaccurate, but from the point of view of $y/$x) I could have a "back"
    key pointing to the data structure that contains it. This'd solve some
    problems and probably create other unforseen ones. Iterating over the
    hash instead of the array would be no problem with the foreach loops I
    use already.

    I'd still like to avoid method calls to change and access tiles. It *is*
    slower, as I've experimented and tried it. Maps will get quite big,
    sometimes around 300x500 and there are a great number of maps randomly
    generated. And the syntax is just easier.

    Anyway, the thing that started me on all this was convenience. Accessing
    and modifying $map->{Map}[$y][$x] and having all the fancy stuff happen
    behind the scenes. But the way I'm tying stuff down right now is
    probably a bit messy, as it won't let me _cleanly_ manipulate anything
    other than that one key in the hash. Is there an easier way around all
    of this mess?

    If interested, here's the module I ended up writing. Buggy and messy,
    beware.

    ############### #######
    # Roguelike::Tile map #
    ############### #######

    package Roguelike::Tile map;

    use strict;
    use warnings;
    use Roguelike::Util ity;
    use Roguelike::Game ;
    use Roguelike::Tile s;

    our $TILE = load Roguelike::Tile s;
    our $_GET = "Symbol";

    sub TIEARRAY {
    my $class = shift;
    return bless [ @_ ], $class;
    }

    sub FETCH {
    my $self = shift;
    my $index = shift;
    return $self->[$index]{$_GET} if ref $self->[$index] eq
    "HASH";
    return $self->[$index];
    }

    sub STORE {
    elf = shift;
    my $index = shift;
    my $value = shift;
    if ($_GET eq "Symbol") {
    if (ref $value eq "ARRAY") {
    tie my @data, "Roguelike::Til emap", @{$value};
    $value = \@data;
    } else {
    $value = $TILE->{$value};
    }
    }
    $self->[$index] = $value;
    }

    sub FETCHSIZE {
    my $self = shift;
    return @{$self};
    }

    sub STORESIZE {
    my $self = shift;
    my $count = shift;
    if ($count > $self->FETCHSIZE) {
    foreach ($count - $self->FETCHSIZE() .. $count) {
    $self->STORE($_, "");
    }
    } elsif ($count < $self->FETCHSIZE) {
    foreach (0 .. $self->FETCHSIZE() - $count - 2) {
    $self->POP();
    }
    }
    }

    sub EXTEND {
    my $self = shift;
    my $count = shift;
    $self->STORESIZE($cou nt);
    }

    sub EXISTS {
    my $self = shift;
    my $index = shift;
    return defined $self->[$index];
    }

    sub DELETE {
    my $self = shift;
    my $index = shift;
    }

    sub CLEAR {
    my $self = shift;
    return $self = [];
    }

    sub PUSH {
    my $self = shift;
    my @list = @_;
    my $last = $self->FETCHSIZE();
    $self->STORE($last + $_, $list[$_]) foreach 0 .. $#list;
    return $self->FETCHSIZE();
    }

    sub POP {
    my $self = shift;
    return pop @{$self};
    }

    sub SHIFT {
    my $self = shift;
    return shift @{$self};
    }

    sub UNSHIFT {
    my $self = shift;
    my @list = @_;
    my $size = scalar(@list);
    @{$self}[$size .. $#{$self} + $size] = @{$self};
    $self->STORE($_, $list[$_]) foreach 0 .. $#list;
    }

    sub new {
    my $class = shift;
    tie my @map, "Roguelike::Til emap";
    my $width = shift;
    my $height = shift;
    my $tile = shift || " ";
    foreach my $y (0 .. $height - 1) { # starting at 1 blows up
    $map[$y] = [];
    foreach my $x (0 .. $width - 1) { # starting at 1 blows up
    $map[$y][$x] = $tile;
    }
    }
    my $self = bless { Map => \@map, Data => [] }, $class;
    return $self;
    }

    sub get {
    my $self = shift;
    my $y = shift;
    my $x = shift;
    my $attrib = shift;
    my $value = shift;
    $_GET = $attrib;
    $self->{Map}[$y][$x] = $value if defined $value;
    my $data = $self->{Map}[$y][$x];
    $_GET = "Symbol";
    return $data;
    }

    42;


    And a test script, which sort of works.

    #!/usr/bin/perl
    use strict;
    use warnings;
    use lib "/home/dabreegster/tilemap";
    use Roguelike::Tile map;
    use Roguelike::Util ity;

    my $map = new Roguelike::Tile map 2, 5;

    dump $map; # doesn't quite work!

    print "Y" if $map->{Map}[2][0] eq " ";

    print $map->get(2, 0, "Type");
    $map->get(3, 3, "foo" => "bar");
    print $map->get(3, 3, "foo");

    # always give em a width and height. Then go through each one slowly and assign
    # it (these comments won't make sense, don't worry)

    # if the Tile hash contains a ref to another hash, array, whatever, it doesn't
    # work. Ohwell.



    Any tips?

    ~ 'dabreegster' in #perl and #perlcafe on irc.freenode.or g
  • Jim Gibson

    #2
    Re: Multileval data structures, tie, and indirection

    In article <slrndf5fnh.i9e .dabreegster@lo calhost.localdo main>,
    Da-Breegster <dabreegster@gm ail.com> wrote:
    [color=blue]
    > Hi. I'm attempting to write a roguelike (think nethack, crawl, angband,
    > tome, adom, and yes, I suppose even rogue) in Perl and I've ran into a
    > problem regarding the data structure for the map and handling it easily.
    > A map is one 2D level, a simple grid. Each tile on the grid will be a
    > hash of data about the grid. The map object itself has other bits of
    > data, so that's why I don't just make the object an anonymous array:[/color]

    [rest of long post snipped]

    I am afraid you have wasted your time by posting to a defunct
    newsgroup. Try comp.lang.perl. misc in the future.


    ----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
    http://www.newsfeeds.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
    ---= East/West-Coast Server Farms - Total Privacy via Encryption =---

    Comment

    Working...