/**
* OOPrisoner.java
*
* Copyright 2014 the original author or authors.
*
* We licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.niolex.common.prisoner;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Random;
import org.apache.niolex.commons.reflect.MethodFilter;
import org.apache.niolex.commons.reflect.MethodUtil;
/**
* @author <a href="mailto:xiejiyun@foxmail.com">Xie, Jiyun</a>
* @version 1.0.0
* @since 2014-1-9
*/
public class OOPrisoner {
private static final int TOTAL = Prisoner.TOTAL;
private static final int ROUND = 2000;
private static final Prisoner[] prisoners = new Prisoner[TOTAL];
public static void initSimple() {
prisoners[0] = new BaseCollector();
for (int i = 1; i < TOTAL; ++i) {
prisoners[i] = new BasePrisoner();
}
}
public static void initLetK() {
for (int i = 0; i < TOTAL; ++i) {
prisoners[i] = new ElectCollector();
}
}
public static void init7Stages() {
prisoners[0] = new StageCollector();
for (int i = 1; i < TOTAL; ++i) {
prisoners[i] = new StagePrisoner();
}
}
public static void init2Stages() {
prisoners[0] = new FinalCollector();
for (int i = 1; i < 10; ++i) {
prisoners[i] = new FirstLevelCollector();
}
for (int i = 10; i < TOTAL; ++i) {
prisoners[i] = new LevelPrisoner();
}
}
public static int oneRound(Random r) {
LightBulb l = new LightBulb();
boolean[] checks = new boolean[TOTAL];
for (int i = 0; i < TOTAL; ++i) {
checks[i] = false;
}
int days = 0, k;
while (!prisoners[k = r.nextInt(TOTAL)].sure(days, l)) {
checks[k] = true;
++days;
}
for (int i = 0; i < TOTAL; ++i) {
if (!checks[i]) {
throw new RuntimeException("Invalid Algorithm!");
}
}
return days;
}
/**
* @param args
*/
public static void main(String[] args) throws Exception {
final double BASE = 365.0002;
final double BASE_T = BASE * ROUND;
List<Method> list = MethodUtil.getMethods(OOPrisoner.class, MethodFilter.c().includeStatic().p().r(void.class));
for (Method m : list) {
int total = 0, max = 0, min = Integer.MAX_VALUE, k;
Random generator = new Random(32785);
for (int i = 0; i < ROUND; ++i) {
m.invoke(null);
k = oneRound(generator);
total += k;
if (max < k) max = k;
if (min > k) min = k;
}
System.out.printf("%s\t - Avg %.2f, Max %.2f, Min %.2f\n", m.getName().substring(4),
(total / BASE_T), (max / BASE), (min / BASE));
}
}
}
class LightBulb {
private boolean status;
boolean isOn() {
return status;
}
boolean isOff() {
return !status;
}
void setOn() {
status = true;
}
void turnOff() {
status = false;
}
}
interface Prisoner {
int TOTAL = 100;
boolean sure(int day, LightBulb bulb);
}
class BasePrisoner implements Prisoner {
protected int count = 1;
public boolean sure(int day, LightBulb bulb) {
if (bulb.isOff() && count > 0) {
--count;
bulb.setOn();
}
return false;
}
}
class BaseCollector implements Prisoner {
protected int count = 1;
public BaseCollector() {
super();
}
public BaseCollector(int count) {
super();
this.count = count;
}
public boolean sure(int day, LightBulb bulb) {
if (bulb.isOn()) {
++count;
bulb.turnOff();
if (count == TOTAL) {
return true;
}
}
return false;
}
}
class ElectCollector extends BasePrisoner {
private int visit = 0;
private Prisoner deligate;
public boolean sure(int day, LightBulb bulb) {
if (day < 100) {
// The first stage, elect the collector.
if (bulb.isOff()) {
++visit;
if (visit == 2) {
bulb.setOn();
deligate = new BaseCollector(day);
}
}
if (day == 99) {
if (bulb.isOff()) return true;
else bulb.turnOff();
}
return false;
} else {
switch (visit) {
case 0: return super.sure(day, bulb);
case 1: return false;
default: return deligate.sure(day, bulb);
}
}
}
}
class StagePrisoner implements Prisoner {
static final int STAGE_LEN = 450;
protected int count = 1;
protected int coll = 0;
public final boolean sure(int day, LightBulb bulb) {
int rem = day % STAGE_LEN;
int itr = (day / STAGE_LEN) % 7;
boolean endDay = rem == STAGE_LEN - 1;
return sure(itr, endDay, day, bulb);
}
public boolean sure(int itr, boolean endDay, int day, LightBulb bulb) {
int cnt = 1 << itr;
if (bulb.isOn()) {
if ((count & cnt) > 0) {
bulb.turnOff();
count += cnt;
}
} else {
if ((count & cnt) > 0) {
bulb.setOn();
count -= cnt;
}
}
if (endDay && bulb.isOn()) {
bulb.turnOff();
count += cnt;
}
return false;
}
}
class StageCollector extends StagePrisoner {
public boolean sure(int itr, boolean endDay, int day, LightBulb bulb) {
int cnt = 1 << itr;
if (bulb.isOn()) {
bulb.turnOff();
count += cnt;
return count == TOTAL;
}
return false;
}
}
class LevelPrisoner implements Prisoner {
static final int FIRST_LEN = 450;
static final int SECOND_LEN = 450;
static final int TOTAL_LEN = FIRST_LEN + SECOND_LEN;
protected int count = 1;
protected int coll = 0;
public final boolean sure(int day, LightBulb bulb) {
int rem = day % TOTAL_LEN;
int level = rem < FIRST_LEN ? 1 : 2;
boolean endDay = rem == FIRST_LEN - 1 || rem == TOTAL_LEN - 1;
return sure(level, endDay, day, bulb);
}
public boolean sure(int level, boolean endDay, int day, LightBulb bulb) {
if (level == 1) {
if (bulb.isOff() && count > 0) {
--count;
bulb.setOn();
}
} else {
if (bulb.isOff() && coll > 0) {
--coll;
bulb.setOn();
}
}
processEndday(level, endDay, bulb);
return false;
}
protected void processEndday(int level, boolean endDay, LightBulb bulb) {
if (endDay && bulb.isOn()) {
if (level == 1) {
++count;
} else {
++coll;
}
bulb.turnOff();
}
}
}
class FirstLevelCollector extends LevelPrisoner {
static final int FIRST_COLLECT = 10;
protected int role = 1;
public boolean sure(int level, boolean endDay, int day, LightBulb bulb) {
if (role == 1 && level == 1) {
// collector
if (bulb.isOn()) {
bulb.turnOff();
++count;
if (count == FIRST_COLLECT) {
role = 0;
count = 0;
++coll;
}
}
processEndday(level, endDay, bulb);
return false;
} else {
return super.sure(level, endDay, day, bulb);
}
}
}
class FinalCollector extends FirstLevelCollector {
public boolean sure(int level, boolean endDay, int day, LightBulb bulb) {
if (bulb.isOff()) {
if (level == 1 && !endDay && role > 0) {
--role;
bulb.setOn();
}
return false;
}
if (level == 1) {
if (count != 0) {
bulb.turnOff();
++count;
if (count == FIRST_COLLECT) {
count = 0;
++coll;
}
} else if (endDay) {
// We have no way now.
bulb.turnOff();
++role;
}
} else {
bulb.turnOff();
++coll;
}
return coll * 10 == TOTAL;
}
}