001package ball.game.life; 002/*- 003 * ########################################################################## 004 * Game Applications and Utilities 005 * $Id: Automata.java 6118 2020-06-04 19:31:45Z ball $ 006 * $HeadURL: svn+ssh://svn.hcf.dev/var/spool/scm/repository.svn/ball-game/trunk/src/main/java/ball/game/life/Automata.java $ 007 * %% 008 * Copyright (C) 2010 - 2020 Allen D. Ball 009 * %% 010 * Licensed under the Apache License, Version 2.0 (the "License"); 011 * you may not use this file except in compliance with the License. 012 * You may obtain a copy of the License at 013 * 014 * http://www.apache.org/licenses/LICENSE-2.0 015 * 016 * Unless required by applicable law or agreed to in writing, software 017 * distributed under the License is distributed on an "AS IS" BASIS, 018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 019 * See the License for the specific language governing permissions and 020 * limitations under the License. 021 * ########################################################################## 022 */ 023import java.beans.ConstructorProperties; 024import java.math.BigInteger; 025import lombok.ToString; 026 027/** 028 * Life {@link Automata}. 029 * 030 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 031 * @version $Revision: 6118 $ 032 */ 033@ToString 034public class Automata { 035 private final int height; 036 private final int width; 037 038 /** 039 * @param height The extent of the y-axis. 040 * @param width The extent of the x-axis. 041 */ 042 @ConstructorProperties({ "height", "width" }) 043 public Automata(int height, int width) { 044 if (height > 0) { 045 this.height = height; 046 } else { 047 throw new IllegalArgumentException("height=" + height); 048 } 049 050 if (width > 0) { 051 this.width = width; 052 } else { 053 throw new IllegalArgumentException("width=" + width); 054 } 055 } 056 057 /** 058 * Method to get the height of the board. 059 * 060 * @return The height. 061 */ 062 public int getHeight() { return height; } 063 064 /** 065 * Method to get the width of the board. 066 * 067 * @return The width. 068 */ 069 public int getWidth() { return width; } 070 071 /** 072 * Given the current {@code state}, calculate the next {@code state}. 073 * 074 * @param current The current {@code state}. 075 * 076 * @return The next {@code state}. 077 */ 078 public BigInteger next(BigInteger current) { 079 BigInteger next = BigInteger.ZERO; 080 081 for (int y = 0; y < height; y += 1) { 082 for (int x = 0; x < width; x += 1) { 083 int count = 0; 084 085 count += get(current, y - 1, x - 1) ? 1 : 0; 086 count += get(current, y - 1, x) ? 1 : 0; 087 count += get(current, y - 1, x + 1) ? 1 : 0; 088 count += get(current, y, x - 1) ? 1 : 0; 089 count += get(current, y, x + 1) ? 1 : 0; 090 count += get(current, y + 1, x - 1) ? 1 : 0; 091 count += get(current, y + 1, x) ? 1 : 0; 092 count += get(current, y + 1, x + 1) ? 1 : 0; 093 094 if (get(current, y, x)) { 095 switch (count) { 096 case 2: 097 case 3: 098 next = next.setBit(y * width + x); 099 break; 100 101 default: 102 next = next.clearBit(y * width + x); 103 break; 104 } 105 } else { 106 switch (count) { 107 case 3: 108 next = next.setBit(y * width + x); 109 break; 110 111 default: 112 next = next.clearBit(y * width + x); 113 break; 114 } 115 } 116 } 117 } 118 119 return next; 120 } 121 122 /** 123 * Method to get the value of a cell at a specified {@code (y, x)} 124 * coordinate fron the argument {@code state}. 125 * 126 * @param state The {@link Automata} {@code state}. 127 * @param y The {@code y} coordinate. 128 * @param x The {@code x} coordinate. 129 * 130 * @return {@code true} if the {@code (y, x)} coordinate is valid and 131 * if the specified cell is "alive;" {@code false} otherwise. 132 */ 133 public boolean get(BigInteger state, int y, int x) { 134 return ((0 <= y && y < height && 0 <= x && x < width) 135 && state.testBit(y * width + x)); 136 } 137}