I made a Hex map with Python

I am making a game with the python library "pygame" as part of my school studies. Since it is a simulation game, I tried to make a common hex map, but the code that can be used does not hit easily. After all, I decided to make it from scratch. It was ... but I asked Qiita user shiracamus to rewrite the childish code! Thank you very much.

Referenced site http://www.redblobgames.com/grids/hexagons/ http://qiita.com/kapipara-games/items/7978a7b51a47df8ace38

environment

code

my_hexmap.py


#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import pygame
from pygame.locals import *

# colors (Red, Green, Blue)
BLACK = (0, 0, 0)
ORANGE = (255, 120, 0)
YELLOW = (255, 255, 0)
CYAN = (0, 255, 255)


class Hexagon:
    """
    Hexagon index/pixel coordinate converter
    There is no limit to the number of hexagon.

       x: 0/4 1/4 3/4 4/4
      y:    |  |   |  |
    0/2--   v0 _____ v1
              /     \
    1/2--    /       \
          v5 \       / v2
    2/2--     \_____/
             v4       v3
    """

    VERTEXES = (1, 0), (3, 0), (4, 1), (3, 2), (1, 2), (0, 1)

    def __init__(self, size):
        self.SIZE = size
        self.HALF = size * 1 // 2
        self.QUARTER = size * 1 // 4
        self.WIDTH = size * 3 // 4
        self.HEIGHT = size

    def index_at(self, pixel_x, pixel_y):
        """get the index coordinae at the pixel coordinate"""
        x = pixel_x // self.WIDTH
        x0 = pixel_x % self.WIDTH
        if x0 < self.QUARTER:  # overlap area
            y0 = (pixel_y - (x % 2) * self.HALF) % self.HEIGHT
            if y0 >= self.HALF:  # lower half
                y0 = self.SIZE - y0
            is_leftarea = x0 < self.QUARTER - y0 * self.QUARTER // self.HALF
            if is_leftarea:
                x -= 1
        y = (pixel_y - (x % 2) * self.HALF) // self.HEIGHT
        return x, y

    def origin_of(self, x, y):
        return x * self.WIDTH, y * self.HEIGHT + (x % 2) * self.HALF

    def vertexes_of(self, x, y):
        """get vertex coodinates of the index coordinate"""
        origin_x, origin_y = self.origin_of(x, y)
        return [(origin_x + vx * self.QUARTER, origin_y + vy * self.HALF)
                for vx, vy in self.VERTEXES]


class HexMap:
    """
    Hexagon map
     ___ x,y ___
    /0,0\___/2,0\
    \___/1,0\___/
    /0,1\___/2,1\
    \___/1,1\___/
    /0,2\___/2,2\
    \___/   \___/
    """

    def __init__(self, columns, rows, hexagon_size):
        self.COLUMNS = columns
        self.ROWS = rows
        self.hexagon = Hexagon(hexagon_size)
        width, height = self.hexagon.origin_of(self.COLUMNS, self.ROWS)
        width += self.hexagon.QUARTER
        self.size = width + 1, height + 1
        self.clear_clicked()

    def clear_clicked(self):
        self.clicked = [[False] * self.ROWS for x in range(self.COLUMNS)]

    def click_at(self, pixel_x, pixel_y):
        x, y = self.hexagon.index_at(pixel_x, pixel_y)
        if 0 <= x < self.COLUMNS and 0 <= y < self.ROWS:
            self.clicked[x][y] = not self.clicked[x][y]

    def is_clicked_on(self, x, y):
        return (0 <= x < self.COLUMNS and 0 <= y < self.ROWS and
                self.clicked[x][y])

    def hexagons(self):
        for x in range(self.COLUMNS):
            for y in range(self.ROWS - (x % 2)):
                yield self.hexagon, x, y


class HexCanvas:
    LINE_WIDTH = 1
    CURSOR_SIZE = 5

    def __init__(self, hexmap):
        self.hexmap = hexmap
        self.canvas = pygame.display.set_mode(hexmap.size)
        self.font = pygame.font.SysFont(None, 17)
        self.cursor = None

    def cursor_at(self, pixel_x, pixel_y):
        self.cursor = pixel_x, pixel_y

    def draw(self):
        canvas = self.canvas
        canvas.fill(BLACK)
        hexmap = self.hexmap
        for hexagon, x, y in hexmap.hexagons():
            vertexes = hexagon.vertexes_of(x, y)
            #Hexagon fill
            color = ORANGE if hexmap.is_clicked_on(x, y) else YELLOW
            pygame.draw.polygon(canvas, color, vertexes)
            #Hexagon border drawing
            for v1, v2 in zip(vertexes, vertexes[1:] + vertexes[:1]):
                pygame.draw.line(canvas, BLACK, v1, v2, self.LINE_WIDTH)
            #Coordinate tag drawing
            tag = "{0}, {1}".format(x, y)
            text = self.font.render(tag, True, CYAN)
            origin_x, origin_y = hexagon.origin_of(x, y)
            text_area = text.get_rect(center=(origin_x + hexagon.HALF,
                                                  origin_y + hexagon.HALF))
            canvas.blit(text, text_area)
        #Cursor drawing
        if self.cursor:
            pygame.draw.circle(canvas, BLACK, self.cursor, self.CURSOR_SIZE, 0)


def main():
    pygame.init()
    FPSCLOCK = pygame.time.Clock()

    hexmap = HexMap(columns=20, rows=15, hexagon_size=50)
    canvas = HexCanvas(hexmap)

    while True:
        for event in pygame.event.get():
            if event.type == QUIT or event.type == KEYDOWN and event.key == K_q:
                pygame.quit()
                return
            if event.type == MOUSEMOTION:
                x, y = pygame.mouse.get_pos()
                canvas.cursor_at(x, y)
            elif event.type == MOUSEBUTTONDOWN:
                x, y = pygame.mouse.get_pos()
                hexmap.click_at(x, y)

        canvas.draw()
        pygame.display.update()
        FPSCLOCK.tick(30)

if __name__ == '__main__':
    main()

Commentary

Image of running the following on ubuntu hexview.png

Recommended Posts

I made a Hex map with Python
I made a fortune with Python.
I made a daemon with Python
I made a character counter with Python
I made a roguelike game with Python
I made a simple blackjack with Python
I made a configuration file with Python
I made a neuron simulator with Python
I made a competitive programming glossary with Python
I made a weather forecast bot-like with Python.
I made blackjack with python!
I made a python text
I made blackjack with Python.
I made wordcloud with Python.
I made a bin picking game with Python
I made a Mattermost bot with Python (+ Flask)
I made a Twitter BOT with GAE (python) (with a reference)
I made a Christmas tree lighting game with Python
I made a Python3 environment on Ubuntu with direnv.
I made a LINE BOT with Python and Heroku
I made a simple typing game with tkinter in Python
I made a puzzle game (like) with Tkinter in Python
I made a payroll program in Python!
I drew a heatmap with seaborn [Python]
Map rent information on a map with python
I tried a functional language with Python
What I did with a Python array
I made a life game with Numpy
I made a stamp generator with GAN
Try drawing a map with python + cartopy 0.18.0
After studying Python3, I made a Slackbot
I made a WEB application with Django
I made a simple circuit with Python (AND, OR, NOR, etc.)
I made a package that can compare morphological analyzers with Python
I made a Nyanko tweet form with Python, Flask and Heroku
I made a lot of files for RDP connection with Python
[Python] I made an image viewer with a simple sorting function.
I made a shuffle that can be reset (reverted) with Python
I made a poker game server chat-holdem using websocket with python
I made a segment tree with python, so I will introduce it
〇✕ I made a game
I made a stamp substitute bot with line
I made a python dictionary file for Neocomplete
I want to make a game with Python
Procedure for creating a LineBot made with Python
Folium: Visualize data on a map with Python
I made a simple Bitcoin wallet with pycoin
I made a random number graph with Numpy
I want to write to a file with Python
Visualize grib2 on a map with python (matplotlib)
I made a Caesar cryptographic program in Python.
I made a Python Qiita API wrapper "qiipy"
I made a QR code image with CuteR
I made a tool to automatically browse multiple sites with Selenium (Python)
I made a plug-in "EZPrinter" that easily outputs map PDF with QGIS.
I tried to discriminate a 6-digit number with a number discrimination application made with python
[Python, ObsPy] I drew a beach ball on the map with Cartopy + ObsPy.
I made a tool that makes decompression a little easier with CLI (Python3)
I made a module PyNanaco that can charge nanaco credit with python
[AWS] I made a reminder BOT with LINE WORKS
I tried fp-growth with python